Событие AWS CloudFormation висит в состоянии CREATE_IN_PROGRESS после вызова пользовательского ресурса (лямбда) - PullRequest
1 голос
/ 16 октября 2019

У меня есть лямбда, в которой есть скрипт на python для создания файла application.properties в хранилище параметров. У меня есть шаблон облачной информации, который вызывает эту лямбду для создания application.properties. Мой шаблон облачной информации выглядит следующим образом:

{
   "Description": "Create SSM Parameter",
   "Resources": {
      "primerinvoke": {
         "Type": "AWS::CloudFormation::CustomResource",
         "Properties": {
            "Handler": "lambda_function.lambda_handler",
            "ServiceToken": "arn:aws:lambda:us-east-1:1234:function:test_lambda",
            "FunctionName": "test_lambda"
         }
      }
   }
}

Мой скрипт Python для создания параметра SSM (путь которого: /myapp/dev/test/application.properties):

import boto3
import os

region = os.environ['AWS_REGION']
client = boto3.client('ssm')
def ssm_create():
    response = client.put_parameter(Name='/myapp/'
                                    + os.environ['environment']
                                    + '/test/application.properties',
                                    Description='string',
                                    Value='APPLICATION_NAME=myapp',
                                    Type='SecureString', Overwrite=True)
    return response
def lambda_handler(event, context):
    PutParameterResult = ssm_create()

Iиспользовал import cfnresponse, как предложено в AWS лямбда: нет модуля с именем 'cfnresponse' , однако импорт не работает, и я не знаю, как установить библиотеку cfnresponse внешне на лямбду.

Код выполняется успешно, что означает, что шаблон облачной информации смог вызвать лямбда-код и его сценарий и создать параметр SSM, но он зависает после завершения функции ssm_create() в моем сценарии. Я не знаю, как вернуть статус «УСПЕХ» из моего сценария в стек облачной информации, чтобы он не зависал в состоянии CREATE_IN_PROGRESS.

Любая помощь будет принята с благодарностью! Спасибо.

EDIT1: Я обновил свой код:

responseStatus = 'SUCCESS'
responseBody={}
def sendResponse(event, context, responseStatus):
            responseBody = {'Status': responseStatus,
                            'Reason': 'See the details in CloudWatch Log Stream: ' + context.log_stream_name,
                            'PhysicalResourceId': context.log_stream_name,
                            'StackId': event['StackId'],
                            'RequestId': event['RequestId'],
                            'LogicalResourceId': event['LogicalResourceId'],
                            }
            print 'RESPONSE BODY:n' + json.dumps(responseBody)
def lambda_handler(event, context):
                logger.info(event)
                test_ssm_create()
                try:
                    req = requests.put(event['ResponseURL'], data=json.dumps(sendResponse(event, context, responseStatus)))
                    if req.status_code != 200:
                        print req.text
                        raise Exception('Recieved non 200 response while sending response to CFN.')
                except requests.exceptions.RequestException as e:
                    print e
                    raise
                return
                print("COMPLETE")

req.status_code дает 200, но стек облачной информации снова застревает в CREATE_IN_PROGRESS. Все еще не уверен, как заставить это работать.

1 Ответ

2 голосов
/ 16 октября 2019

Как отмечено в документации CloudFormation, CloudFormation ожидает, что ваша лямбда-функция обратится к ней после завершения своей работы;CloudFormation приостанавливает выполнение до получения этого обратного вызова. Событие, отправленное в вашу функцию Lambda CloudFormation, содержит URL-адрес обратного вызова (ResponseURL), как показано в следующем примере:

{
   "RequestType" : "Create",
   "ResponseURL" : "http://pre-signed-S3-url-for-response",
   "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/stack-name/guid",
   "RequestId" : "unique id for this create request",
   "ResourceType" : "Custom::TestResource",
   "LogicalResourceId" : "MyTestResource",
   "ResourceProperties" : {
      "Name" : "Value",
      "List" : [ "1", "2", "3" ]
   }
}

Если вы не можете импортировать модуль cfnresponse, который выглядит как код python2, выдолжен иметь возможность симулировать то же самое с python3. Попробуйте добавить что-то вроде этого кода в вашу функцию lambda_handler. Обратите внимание, что в ответе есть обязательные ключи, подробно описанные на этой странице документации AWS (т. Е. PhysicalResourceId, StackId, RequestId, LogicalResourceId, которые просто добавить, см. Документацию).

import requests
import json
import uuid

status = {'Status': 'SUCCESS',
          'PhysicalResourceId': 'MyResource_' + str(uuid.uuid1()),
          'StackId': event['StackId'],
          'RequestId': event['RequestId'],
          'LogicalResourceId': event['LogicalResourceId']
         }
r = requests.put(event['ResponseURL'], data=json.dumps(status))

Итак, чтобы отредактировать код в вашем вопросе:

responseStatus = 'SUCCESS'

def getResponse(event, context, responseStatus):
            responseBody = {'Status': responseStatus,
                            'PhysicalResourceId': context.log_stream_name,
                            'StackId': event['StackId'],
                            'RequestId': event['RequestId'],
                            'LogicalResourceId': event['LogicalResourceId'],
                            }
            responseBody = json.dumps(responseBody)
            print 'RESPONSE BODY:n' + responseBody

            return responseBody

def lambda_handler(event, context):
                logger.info(event)
                test_ssm_create()
                try:
                    req = requests.put(event['ResponseURL'], data=getResponse(event, context, responseStatus))
                    if req.status_code != 200:
                        print req.text
                        raise Exception('Received non 200 response while sending response to CFN.')
                except requests.exceptions.RequestException as e:
                    print e
                    raise
                return
                print("COMPLETE")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...