Como atualizo o módulo cfn-response do AWS CloudFormation para funções do AWS Lambda em execução no Python 2.7/3.6/3.7?

5 minuto de leitura
0

Quero atualizar o módulo cfn-response do AWS CloudFormation para funções do AWS Lambda em execução no Python 2.7/3.6/3.7.

Resolução

Observação: as etapas a seguir são aplicáveis somente às funções do Lambda em execução no Python 2.7/3.6/3.7. Os comandos a seguir são aplicáveis aos ambientes Linux e macOS. A sintaxe pode variar no Windows PowerShell.

Observação: se você receber erros ao executar comandos da AWS Command Line Interface (AWS CLI), certifique-se de estar usando a versão mais recente da AWS CLI.

1.Para encontrar as pilhas que contêm recursos personalizados, execute o comando a seguir:

aws cloudformation list-stacks --region us-east-1 | grep -oE 'arn:[^"]+' | while read arn; do aws cloudformation list-stack-resources --stack-name $arn --region us-east-1 | grep -E '(Custom::)|(::CustomResource)' | awk '{print $2}' | while read resource; do if [[ -n $resource ]]; then echo $arn; echo $resource; fi; done; done

Você deve ver uma saída semelhante à saída de exemplo a seguir:

arn:aws:cloudformation:us-east-1:123456789012:stack/TestStack/3497b950-55f1-11eb-aad4-124a026c8667
"ResourceType": "AWS::CloudFormation::CustomResource",

2.Para encontrar a função do Lambda associada ao recurso personalizado, execute o comando a seguir para verificar a propriedade ServiceToken do recurso personalizado no modelo da pilha:

aws cloudformation get-template --stack-name TestStack | jq -r .TemplateBody

Observação: o comando na etapa 2 visualiza o modelo da pilha usando a opção jq (do site da jq) para formatar a resposta.

Você deve ver uma saída semelhante à saída de exemplo a seguir:

Resources:
  MyCustomResource:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt MyFunction.Arn
      Name: "John"
  MyFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt MyRole.Arn
      Runtime: python3.7
      Code:
        ZipFile: |
          import cfnresponse
          def handler(event, context):
            responseData = {'Message': 'Hello {}!'.format(event['ResourceProperties']['Name'])}
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
  MyRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
Outputs:
  Result:
    Value: !GetAtt MyCustomResource.Message

Observação: o modelo que você obtém da saída da etapa 2 é um exemplo de modelo mínimo para um recurso personalizado com suporte do Lambda. A propriedade ServiceToken: !GetAtt MyFunction.Arn está na seção MyCustomResource. O valor resolvido pelo**! GetAtt** MyFunction**.Arn** da propriedade ServiceToken é o nome do recurso da Amazon (ARN) do tópico Amazon Simple Notification Service (Amazon SNS) ou a função do Lambda.

3.No modelo da etapa 2, identifique onde sua função do Lambda está definida.

Se sua função do Lambda estiver na mesma pilha do recurso personalizado, vá para a etapa 4. Por exemplo, a função Fn::GetAtt na etapa 2 mostra que a função do Lambda está definida no mesmo modelo do recurso personalizado.

Se a propriedade ServiceToken apontar para um ARN codificado, a função do Lambda poderá estar em outra pilha. Se a propriedade ServiceToken for resolvida por meio de Fn::Import, use a API list-exports no AWS CloudFormation para pesquisar o valor. Por exemplo:

aws cloudformation list-exports --region us-east-1
{
    "Exports": [
        {
            "ExportingStackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/SomeOtherStack/481dc040-b283-11e9-b1bd-12d607a4fd1c",
            "Value": "arn:aws:lambda:us-east-1:123456789012:function:SomeOtherStack-MyFunction-5ZE2CQO8RAA9",
            "Name": "MyExport"
        }
    ]
}

Em seguida, verifique se há tags de função localizadas em uma pilha separada usando list-tags para localizar o ARN da pilha do AWS CloudFormation. Por exemplo:

aws lambda list-tags --resource arn:aws:lambda:us-east-1:123456789012:function:TestStack-MyFunction-5ZE2CQO8RAA9 | grep stack-id

Você recebe uma saída semelhante à seguinte:

"aws:cloudformation:stack-id": "arn:aws:cloudformation:us-east-1:123456789012:stack/TestStack/3497b950-55f1-11eb-aad4-124a026c8667"

Observação: você também pode encontrar tags de função no console do AWS Lambda.

4.Para permitir que o AWS CloudFormation carregue o módulo cfn-response mais recente em sua função do Lambda, atualize o código-fonte embutido da sua função Lambda. Por exemplo:

Code:
        ZipFile: |
          import cfnresponse
          def handler(event, context):
            responseData = {'Message': 'Hello {}!'.format(event['ResourceProperties']['Name'])}
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")

Observação: consulte a etapa 2 para ver um exemplo de modelo que tem uma função do Lambda com código-fonte embutido.

Agora, o exemplo de código do módulo cfn-response a seguir é carregado pelo AWS CloudFormation em sua função do Lambda. Por exemplo:

from botocore.vendored import requests
import json

SUCCESS = "SUCCESS"
FAILED = "FAILED"

def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False):
    responseUrl = event['ResponseURL']

    print(responseUrl)

    responseBody = {}
    responseBody['Status'] = responseStatus
    responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' + context.log_stream_name
    responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name
    responseBody['StackId'] = event['StackId']
    responseBody['RequestId'] = event['RequestId']
    responseBody['LogicalResourceId'] = event['LogicalResourceId']
    responseBody['NoEcho'] = noEcho
    responseBody['Data'] = responseData

Observação: para obter mais informações, consulte os exemplos de código na seção “Código-fonte do módulo” do módulo cfn-response.

O exemplo de código do módulo cfn-responseusa botocore.requests no pacote de implantação da função do Lambda.

Para atualizar o módulo cfn-response para a versão mais recente que usa urllib3, atualize o código embutido da função no modelo do AWS CloudFormation. Faça isso adicionando um comentário ao código da função do Lambda embutida. Por exemplo:

ZipFile: |
           import cfnresponse
           def handler(event, context):
+            # This comment was added to force an update on this function's code
             responseData = {'Message': 'Hello {}!'.format(event['ResourceProperties']['Name'])}
             cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
   MyRole:

5.Salve todas as alterações no modelo que contém sua função do Lambda.

6.Atualize sua pilha.

O módulo cfn-response é modificado após a conclusão da atualização da pilha.

Observação: se o código da função residir em um bucket do Amazon Simple Storage Service (Amazon S3) ou em uma imagem do Amazon Elastic Container Registry (Amazon ECR), você mesmo deverá atualizar o módulo para incluir a versão com urllib3. Para obter o código-fonte da versão mais recente do módulo cfn-response, consulte o módulo cfn-response.

Observação: se um novo runtime de Python ou JavaScript introduzir uma alteração significativa, você deverá atualizar o módulo cfn-response. Em vez de atualizar o ZipFile novamente, você pode anexar automaticamente a versão mais recente do módulo cfn-response sempre que a propriedade Runtime de uma função for atualizada.


AWS OFICIAL
AWS OFICIALAtualizada há 3 anos