UNPKG

@geek-fun/serverlessinsight

Version:

Full life cycle cross providers serverless application management for your fast-growing business.

188 lines (169 loc) 5.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.prepareBootstrapStack = void 0; const common_1 = require("../../common"); const getBootstrapTemplate = async (context) => { const stackName = `si-bootstrap-${context.accountId}-${context.region}`; const template = { Description: 'ServerlessInsight Bootstrap Stack', Metadata: { 'ALIYUN::ROS::Interface': { TemplateTags: ['Bootstrap stack created by ServerlessInsight'], }, }, ROSTemplateFormatVersion: '2015-09-01', Resources: { si_auto_artifacts_bucket: { Type: 'ALIYUN::OSS::Bucket', Properties: { BucketName: `${common_1.SI_BOOTSTRAP_BUCKET_PREFIX}-${context.accountId}-${context.region}`, AccessControl: 'private', DeletionForce: false, EnableOssHdfsService: false, RedundancyType: 'LRS', ServerSideEncryptionConfiguration: { SSEAlgorithm: 'KMS', }, }, }, si_auto_bootstrap_api_lambda: { Type: 'ALIYUN::FC3::Function', Properties: { FunctionName: `${common_1.SI_BOOTSTRAP_FC_PREFIX}-${context.accountId}-${context.region}`, Description: 'ServerlessInsight Bootstrap API', Handler: 'index.handler', Runtime: 'nodejs20', Layers: [`acs:fc:${context.region}:1990893136649406:layers/si-bootstrap-sdk/versions/18`], Code: { SourceCode: ` const { bootstrapHandler } = require('@geek-fun/si-bootstrap-sdk'); module.exports.handler = async (rawEvent, context) => { // 处理 Buffer 类型的事件 const event = parseEvent(rawEvent); const commonResponse = { RequestId: event.requestId, LogicalResourceId: event.logicalResourceId, StackId: event.stackId }; try { // 处理业务逻辑 const result = await bootstrapHandler(event); // 构建符合 ROS 要求的响应结构 const rosResponse = { ...commonResponse, Status: result.status, Reason: result.reason, PhysicalResourceId: result.physicalResourceId, Data: result.data || {} // 业务数据 }; // 如果是删除操作,不需要返回数据 if (event.requestType === 'Delete') { delete rosResponse.Data; } // 发送响应到 ROS 服务(如果提供了 ResponseURL) if (event.responseURL) { await sendResponse(event.responseURL, rosResponse); } // 返回成功响应 return { statusCode: 200, body: JSON.stringify({ message: 'Request processed successfully', rosResponse }) }; } catch (error) { console.error('Error:', error); // 构建错误响应 const errorResponse = { ...commonResponse, Status: 'FAILED', Reason: error.message || 'Internal Server Error', PhysicalResourceId: 'error-' + Date.now() }; // 发送错误响应到 ROS 服务 if (event.responseURL) { try { await sendResponse(event.responseURL, errorResponse); } catch (err) { console.error('Failed to send error response:', err); } } // 返回错误响应 return { statusCode: 500, body: JSON.stringify({ error: 'Internal Server Error', details: error.message, rosErrorResponse: errorResponse }) }; } }; // 使用原生 fetch API 发送响应 async function sendResponse(responseUrl, responseBody) { try { const body = JSON.stringify(responseBody); const response = await fetch(responseUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body).toString(), 'Date': new Date().toUTCString() }, body: body }); if (!response.ok) { const errorText = await response.text(); throw new Error(\`Failed to send response. Status: \${response.status}, Body: \${errorText}\`); } console.log('Response sent successfully'); } catch (error) { console.error('Error sending response:', error); throw error; } } const parseEvent = (rawEvent) => { // 处理 Buffer 类型的事件 let event; if (Buffer.isBuffer(rawEvent)) { event = JSON.parse(rawEvent.toString('utf8')); } else if (typeof rawEvent === 'string') { event = JSON.parse(rawEvent); } else { event = rawEvent; } const { credentials, ...resourceProperties } = event.ResourceProperties return { stackId: event.StackId, responseURL: event.ResponseURL, resourceOwnerId: event.ResourceOwnerId, callerId: event.CallerId, resourceProperties, eventType: event.ResourceType, requestType: event.RequestType?.toUpperCase(), resourceType: resourceProperties.resource, regionId: event.RegionId, stackName: event.StackName, requestId: event.RequestId, intranetResponseURL: event.IntranetResponseURL, logicalResourceId: event.LogicalResourceId, physicalResourceId: event.PhysicalResourceId, credentials }; };`, }, MemorySize: 512, Timeout: 900, // 15 minutes }, }, }, }; return { stackName, template }; }; const prepareBootstrapStack = async () => { const context = (0, common_1.getContext)(); const { stackName, template } = await getBootstrapTemplate(context); await (0, common_1.rosStackDeploy)(stackName, template); }; exports.prepareBootstrapStack = prepareBootstrapStack;