如何使用 cloudformation 对 AWS 实例中的应用程序进行一系列 API 调用

How to invoke a series of API calls to an application in an AWS instance using cloudformation

有没有办法创建一个 cloudformation 模板,它调用 EC2 实例的 REST API 调用?

用例是在不必使用更新堆栈和用户数据的情况下修改应用程序的配置,因为用户数据更新具有破坏性。

我确实搜索了所有文档,发现这可以通过调用 AWS lambda 来完成。但是,无法获得 CFM 模板和调用属性的正确组合。

添加一个简单的 lambda,它可以独立运行:

from __future__ import print_function
import requests

def handler(event, context):
  r1=requests.get('https://google.com')
  message = r1.text
  return { 
    'message' : message
  }  

这里命名为ltest.py,用requests模块等打包成ltest.zip,然后在CFM模板中调用ltest.zip:

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "Test",

  "Parameters": {
    "ModuleName" : {
      "Description" : "The name of the Python file",
      "Type" : "String",
      "Default" : "ltest"
    },
    "S3Bucket" : {
      "Description" : "The name of the bucket that contains your packaged source",
      "Type" : "String",
      "Default" : "abhinav-temp"
    },
   "S3Key" : {
     "Description" : "The name of the ZIP package",
     "Type" : "String",
     "Default" : "ltest.zip"
   }
},

"Resources" : {

  "AMIInfo": {
    "Type": "Custom::AMIInfo",
      "Properties": {
        "ServiceToken": { "Fn::GetAtt" : ["AMIInfoFunction", "Arn"] }
      }
    },

  "AMIInfoFunction": {
    "Type": "AWS::Lambda::Function",
    "Properties": {
      "Code": {
        "S3Bucket": { "Ref": "S3Bucket" },
        "S3Key": { "Ref": "S3Key" }
      },
      "Handler": { "Fn::Join" : [ "", [{ "Ref": "ModuleName" },".handler"] ]},
      "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] },        
      "Runtime": "python2.7",
      "Timeout": "30"
    }
 },

 "LambdaExecutionRole": {
   "Type": "AWS::IAM::Role",
   "Properties": {
     "AssumeRolePolicyDocument": {
       "Version": "2012-10-17",
       "Statement": [{
          "Effect": "Allow",
          "Principal": {"Service": ["lambda.amazonaws.com"]},
          "Action": ["sts:AssumeRole"]
      }]
    },
    "Path": "/",
    "Policies": [{
      "PolicyName": "root",
      "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [{
            "Effect": "Allow",
            "Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": ["ec2:DescribeImages"],
            "Resource": "*"
        }]
      }
    }]
  }
  }    
},

"Outputs":{ "AMIID":{ "Description": "Result", "Value" : { "Fn::GetAtt": [ "AMIInfo", "message" ] } } }
}

上述结果(使用 Fn::GetAtt 调用的变体)是 Lambda 被实例化,但 AMIInfo 调用卡在 "CREATE_FUNCTION".

堆栈也没有被正确删除。

我会用 Lambda 解决这个问题,但似乎您已经想到了并且可能会忽略它。

有点hack,但是您可以通过源是REST 的元数据将文件添加到实例吗url?

例如

  "Type": "AWS::EC2::Instance",
  "Metadata": {
    "AWS::CloudFormation::Init": {
      "configSets": {
        "CallREST": [ "CallREST" ]
      },
      "CallREST": { "files": 
                    { "c://cfn//junk//rest1output.txt": { "source": "https://myinstance.com/RESTAPI/Rest1/Action1" } } },
    }
  }

要修复您的 lambda,您需要发出成功信号。当 CloudFormation 创建(并运行)Lambda 时,它期望 Lambda 发出成功信号。这就是你卡住的原因 "CREATE_IN_PROGRESS"

http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html 的底部是一个名为 "send" 的函数,可帮助您发出成功信号。

这是我尝试将其集成到您的函数 AS PSUEDOCODE 中而不对其进行测试,但您应该明白了。

from __future__ import print_function
import requests

def handler(event, context):
  r1=requests.get('https://google.com')
  message = r1.text
  # signal complete to CFN
  # send(event, context, responseStatus, responseData, physicalResourceId)
  send(..., ..., SUCCESS, ...)
  return { 
    'message' : message
  }  

Lambda 由事件触发。生命周期挂钩可能会有所帮助。 您可以破解 CloudFormation,但请注意:它不是为此而设计的。