【问题标题】:AWS CloudFormation custom lambda function stuck in create stateAWS CloudFormation 自定义 lambda 函数卡在创建状态
【发布时间】:2016-07-17 15:25:22
【问题描述】:

我正在尝试使用从 lambda 函数返回的值。 CloudFormation 自定义资源;但是,当我尝试时,CloudFormation 自定义资源无限陷入等待状态。

以下是我正在尝试的 Lambda 节点代码

exports.handler = function(event, context) {
  var date = new Date();
  var current_hour = date.getHours();
  console.log("START :: " + current_hour);

    console.log("END :: " + current_hour);
    data = {
        "val1" : "val1",
        "val2" : "val2"
    };

    result = {
      "Status" : "SUCCESS",
      "Reason" : "Success Reason",
      "PhysicalResourceId" : "LambdaCustomDelayFunction",
      "StackId" : event.StackId,
      "RequestId" : event.RequestId,
      "LogicalResourceId" : event.LogicalResourceId,
      "Data" : data
    };
    console.log('---Event---');
    console.log(event);
    console.log('---Context---');
    console.log(context);
    console.log('---Result---');
    console.log(result);

    context.done(null, result);
};

在 CloudFormation 脚本之后,我正在尝试使用 lambda

"DelayFunction" : {
      "Type" : "Custom::Delayer",
      "Properties" : {
        "ServiceToken" : "arn:aws:lambda:us-east-1-123456778:function:delayfunction"
      }
      },
"MySG": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription": " Server SG 1",
        "VpcId": {
          "Ref": "VPC"
        },
        "SecurityGroupIngress": [
          {
            "IpProtocol": "-1",
            "CidrIp": "10.0.0.0/16"
          }
        ],
        "SecurityGroupEgress": [
          {
            "IpProtocol": "-1",
            "CidrIp": "0.0.0.0/0"
          }
        ],
        "Tags": [
          {
            "Key": "Name",
            "Value": "SG 1"
          },
          {"Key":"Lambda", "Value":{ "Fn::GetAtt" : ["DelayFunction", "val1"]}} <------ Trying to retrieve the value
        ]
      }
    }

【问题讨论】:

    标签: amazon-web-services amazon-cloudformation aws-lambda


    【解决方案1】:

    您在正确的轨道上,但 CloudFormation API 要求您将 result 对象作为 JSON 编码的主体放入请求事件中提供的预签名 ResponseURL。请参阅Custom Resources 上的文档:

    1. 自定义资源提供程序处理 AWS CloudFormation 请求并向预签名 URL 返回 SUCCESS 或 FAILED 响应。 [...] AWS CloudFormation 等待并侦听预签名 URL 位置中的响应。 [...]
    2. 在获得 SUCCESS 响应后,AWS CloudFormation 继续进行堆栈操作。如果返回 FAILURE 或没有返回响应,则操作失败。

    在您的示例中,您可以将 Lambda 函数中的 context.done(null, result); 行替换为以下内容:

    var responseBody = JSON.stringify(result);
    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
        }
    };
    
    var request = https.request(options, function(response) {
        console.log("Status code: " + response.statusCode);
        console.log("Status message: " + response.statusMessage);
        context.done();
    });
    
    request.on("error", function(error) {
        console.log("send(..) failed executing https.request(..): " + error);
        context.done();
    });
    
    request.write(responseBody);
    request.end();
    

    cfn-response 模块的内容见AWS Lambda Function Code,该模块在一个独立的函数中实现了这个响应逻辑。但是请记住,cfn-response 模块只能在 ZipFile 参数提供内联到 AWS::Lambda::Function 资源的 Javascript 代码时直接引用(并且限制为最多 4096 个字符)。由于您在示例中将 Lambda 函数上传到 CloudFormation 之外,因此将上述代码直接内联到现有函数中可能会更容易。

    【讨论】:

    • 您关于 lambda 中的 cfn-response 的 cmets 令人困惑。他可以按照我的代码将模型包含在他的 lambda 中。复制粘贴有什么意义?
    • 在示例代码中,ServiceToken 属性指向现有的 ARN (arn:aws:lambda:*),这意味着 Lambda 函数不是通过 AWS::Lambda:Function 资源安装的,而是通过其他方式安装的。 cfn-response 模块仅在使用 CloudFormation 资源的 ZipFile 属性时提供(它是 CloudFormation 资源实现的一部分)。由于该模块不是自动可用的,他必须自己提供它,要么将 cfn-response.js 模块源代码添加到他的 zip 中,要么将其直接内联到现有函数中。
    【解决方案2】:

    我在您的代码中看到的只是调用上下文方法以发出完成信号,但您需要专门与 CloudFormation 进行通信(类似于 cfn-signal)

    请在此处查看 cfn 响应部分: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html

    我的函数的基本示例:

    var response = require('cfn-response');
    cloudwatchevents.putTargets(putTargetsParams, function (err, data) {
                        if (err) {
                            console.log(err, err.stack); // an error occurred
                            response.send(event, context, response.FAILED, err.stack);
                        }
                        else {
                            console.log(data);           // successful response
                            response.send(event, context, response.SUCCESS);
                        }
                    });
    

    在内部,response.send() 会为您调用上下文方法。

    【讨论】:

      猜你喜欢
      • 2018-04-21
      • 1970-01-01
      • 2020-02-13
      • 1970-01-01
      • 2020-03-27
      • 1970-01-01
      • 2017-10-14
      • 2021-02-22
      • 2020-07-19
      相关资源
      最近更新 更多