代码之家  ›  专栏  ›  技术社区  ›  Jiew Meng

CloudFormation自定义资源未完成删除

  •  2
  • Jiew Meng  · 技术社区  · 7 年前

    我已将自定义资源设置为在删除时立即返回

    const aws = require('aws-sdk')
    const util = require('util')
    
    exports.handler = (event, context) => {
      console.log('Event>>>')
      console.log(JSON.stringify(event))
      aws.config.update({ region: event.ResourceProperties.Region })
    
      if (event.RequestType === 'Delete') return ApiMethodCustom.sendResponse(event, context, 'SUCCESS') // HERE!
    
      ApiMethodCustom.setupIntegration(event, context)
    }
    
      static async sendResponse(event, context, responseStatus, responseData = {}) {
        var responseBody = JSON.stringify({
          Status: responseStatus,
          Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName,
          PhysicalResourceId: context.logStreamName,
          StackId: event.StackId,
          RequestId: event.RequestId,
          LogicalResourceId: event.LogicalResourceId,
          Data: responseData
        });
    
        console.log("RESPONSE BODY:\n", responseBody);
    
        var https = require("https");
        var url = require("url");
    
        var parsedUrl = url.parse(event.ResponseURL);
        var options = {
          hostname: parsedUrl.hostname,
          port: 443,
          path: parsedUrl.path,
          method: "PUT",
          headers: {
            "content-type": "",
            "content-length": responseBody.length
          }
        };
    
        console.log("SENDING RESPONSE...\n");
    
        var request = https.request(options, function (response) {
          console.log("STATUS: " + response.statusCode);
          console.log("HEADERS: " + JSON.stringify(response.headers));
          // Tell AWS Lambda that the function execution is done
          context.done();
        });
    
        request.on("error", function (error) {
          console.log("sendResponse Error:" + error);
          // Tell AWS Lambda that the function execution is done
          context.done();
        });
    
        // write data to request body
        request.write(responseBody);
        request.end();
      }
    

    但云的形成似乎被困在 DELETE_IN_PROGRESS

    2018-09-09T01:52:06.913Z    f48808d0-b3d2-11e8-9e84-5b218cad3090
    {
        "RequestType": "Delete",
        "ServiceToken": "arn:aws:lambda:ap-southeast-1:621567429603:function:income2-base-ApiVpcIntegration",
        "ResponseURL": "https://cloudformation-custom-resource-response-apsoutheast1.s3-ap-southeast-1.amazonaws.com/arn%3Aaws%3Acloudformation%3Aap-southeast-1%3A621567429603%3Astack/test/5a34d100-b370-11e8-b89d-503a138dba36%7CApiTestIntegration%7C979b1814-d94c-4a49-b9f7-2fa352ab88f5?AWSAccessKeyId=AKIAIKQZQ3QDXOJPHOPA&Expires=1536465125&Signature=O2O0entoTXHCYp5jbJehghtE9Ck%3D",
        "StackId": "arn:aws:cloudformation:ap-southeast-1:621567429603:stack/test/5a34d100-b370-11e8-b89d-503a138dba36",
        "RequestId": "979b1814-d94c-4a49-b9f7-2fa352ab88f5",
        "LogicalResourceId": "ApiTestIntegration",
        "PhysicalResourceId": "2018/09/08/[$LATEST]b8a3df0fca884fe3b8abdde3ab525ac0",
        "ResourceType": "Custom::ApiVpcIntegration",
        "ResourceProperties": {
            "ServiceToken": "arn:aws:lambda:ap-southeast-1:621567429603:function:income2-base-ApiVpcIntegration",
            "ConnectionId": "24lbti",
            "ResourceId": "x1gjyy",
            "RestApiId": "aaj0q4dbml",
            "Uri": "http://dropletapi-dev.2359media.net:3001/authentication",
            "HttpMethod": "GET"
        }
    }
    
    2018-09-09T01:52:06.914Z    f48808d0-b3d2-11e8-9e84-5b218cad3090    RESPONSE BODY:
    {
        "Status": "SUCCESS",
        "Reason": "See the details in CloudWatch Log Stream: 2018/09/09/[$LATEST]29276598cb9c49c1b1da3672c8707c78",
        "PhysicalResourceId": "2018/09/09/[$LATEST]29276598cb9c49c1b1da3672c8707c78",
        "StackId": "arn:aws:cloudformation:ap-southeast-1:621567429603:stack/test/5a34d100-b370-11e8-b89d-503a138dba36",
        "RequestId": "979b1814-d94c-4a49-b9f7-2fa352ab88f5",
        "LogicalResourceId": "ApiTestIntegration",
        "Data": {}
    }
    
    1 回复  |  直到 7 年前
        1
  •  9
  •   M Jensen    7 年前

    换句话说,在 全部的 here .

    我最终实现了自定义资源,就像 this example on GitHub https://github.com/rosberglinhares (MIT许可证)有两个不同之处;我没有设置单独的lambda来处理sendResponse功能,我减少了定制资源服务器(使用aws cloudformation包和aws cloudformation deploy命令)。

    你的ApiMethodCustom没有定义,所以我很难指导你实现,所以我把我的节点.js8.10代码使用async/await作为参考。

    首先是Cloudformation模板中的自定义资源:

    ---
    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: CustomResource Example Stack
    Resources:
      CustomResource:
        Type: 'AWS::Serverless::Function'
        Properties:
          Runtime: nodejs8.10
          Handler: index.handler
          MemorySize: 128
          Timeout: 15
          Role: !GetAtt CustomResourceRole.Arn
          CodeUri: ./CustomResource/
    
      CustomResourceUser:
        Type: 'Custom::CustomResourceUser'
        Properties:
          ServiceToken: !GetAtt CustomResource.Arn
          ...
    

    注意CodeUri是相对于模板路径的。您需要为CustomResourceRole定义IAM角色和策略。

    'use strict';
    const AWS = require('aws-sdk');
    const axios = require('axios');
    
    exports.handler = async (event, context) => {
      try {
    
        switch (event.RequestType) {
          case 'Create':
            await ApiMethodCustom.create(...);
            break;
          case 'Update':
            await ApiMethodCustom.update(...);
            break;
          case 'Delete':
            await ApiMethodCustom.delete(...);
            break;
        }
        console.info('Success for request type ${event.RequestType}');
        await sendResponse(event, context, 'SUCCESS', { } );
      } catch (error) {
        console.error('Error for request type ${event.RequestType}: ', error);
        await sendResponse(event, context, 'FAILED', { } );
      }
    }
    
    async function sendResponse (event, context, responseStatus, responseData, physicalResourceId) {
    
      var reason = responseStatus == 'FAILED' ? ('See the details in CloudWatch Log Stream: ' + context.logStreamName) : undefined;
    
      var responseBody = JSON.stringify({
        StackId: event.StackId,
        RequestId: event.RequestId,
        Status: responseStatus,
        Reason: reason,
        PhysicalResourceId: physicalResourceId || context.logStreamName,
        LogicalResourceId: event.LogicalResourceId,
        Data: responseData
      });
    
      var responseOptions = {
        headers: {
          'Content-Type': '',
          'Content-Length': responseBody.length
        }
      };
    
      console.info('Response body:\n', responseBody);
    
      try {
        await axios.put(event.ResponseURL, responseBody, responseOptions);
    
        console.info('CloudFormationSendResponse Success');
      } catch (error) {
        console.error('CloudFormationSendResponse Error:');
    
        if (error.response) {
          console.error(error.response.data);
          console.error(error.response.status);
          console.error(error.response.headers);
        } else if (error.request) {
          console.error(error.request);
        } else {
          console.error('Error', error.message);
        }
    
        console.error(error.config);
    
        throw new Error('Could not send CloudFormation response');
      }
    }
    

    有关在AWS Lambda中使用回调与异步的更多信息,请查看 here .

    最后,注意 Axios