

# Recursos personalizados baseados no Lambda
<a name="template-custom-resources-lambda"></a>

Ao associar uma função do Lambda com um recurso personalizado, a função é invocada sempre que o recurso personalizado é criado, atualizado ou excluído. O CloudFormation chama uma API do Lambda para invocar a função e transferir todos os dados da solicitação (como o tipo de solicitação e as propriedades do recurso) para a função. A capacidade e a personalização das funções do Lambda em associação com o CloudFormation possibilitam uma ampla variedade de cenários, como a pesquisa dinâmica de IDs de AMI durante a criação da pilha ou a implementação e o uso de funções utilitárias, como as funções de reversão de string.

Para obter uma introdução aos recursos personalizados e como eles funcionam, consulte [Como os recursos personalizados funcionam](template-custom-resources.md#how-custom-resources-work).

**Topics**
+ [Instruções passo a passo: criar um mecanismo de atraso com um recurso personalizado apoiado pelo Lambda](walkthrough-lambda-backed-custom-resources.md)
+ [`cfn-response`Módulo](cfn-lambda-function-code-cfnresponsemodule.md)

# Instruções passo a passo: criar um mecanismo de atraso com um recurso personalizado apoiado pelo Lambda
<a name="walkthrough-lambda-backed-custom-resources"></a>

Este passo a passo mostra como configurar e executar um recurso personalizado com suporte do Lambda usando um modelo de exemplo do CloudFormation. Este modelo cria um mecanismo de atraso que pausa as implantações de pilha por um período especificado. Isso pode ser útil quando você precisa introduzir atrasos deliberados durante o provisionamento de recursos, como ao esperar que os recursos se estabilizem antes que os recursos dependentes sejam criados.

**nota**  
Embora os recursos personalizados baseados em Lambda tenham sido recomendados anteriormente para recuperar IDs de AMI, recomendamos utilizar parâmetros do AWS Systems Manager. Essa abordagem torna seus modelos mais reutilizáveis e fáceis de manter. Para obter mais informações, consulte [Obter um valor em texto simples do Systems Manager Parameter Store](dynamic-references-ssm.md). 

**Topics**
+ [Visão geral](#walkthrough-lambda-backed-custom-resources-overview)
+ [Modelo de exemplo](#walkthrough-lambda-backed-custom-resources-sample-template)
+ [Modelo de passo a passo](#walkthrough-lambda-backed-custom-resources-sample-template-walkthrough)
+ [Pré-requisitos](#walkthrough-lambda-backed-custom-resources-prerequisites)
+ [Iniciar a pilha](#walkthrough-lambda-backed-custom-resources-createfunction-createstack)
+ [Limpar os recursos](#walkthrough-lambda-backed-custom-resources-createfunction-cleanup)
+ [Informações relacionadas](#w2aac11c45b9c24b9c23)

## Visão geral
<a name="walkthrough-lambda-backed-custom-resources-overview"></a>

O modelo de pilha de exemplo usado neste passo a passo cria um recurso personalizado baseado no Lambda. Esse recurso personalizado introduz um atraso configurável (60 segundos por padrão) durante a criação da pilha. O atraso ocorre durante as atualizações da pilha somente quando as propriedades do recurso personalizado são modificadas.

Este modelo fornece os seguintes recursos:
+ um recurso personalizado,
+ uma função do Lambda e
+ um perfil do IAM que permite que o Lambda grave logs no CloudWatch.

Ele também define duas saídas:
+ O tempo que a função de fato esperou.
+ Um identificador único gerado durante cada execução da função do Lambda.



**nota**  
O CloudFormation é um serviço gratuito, mas o Lambda cobra com base no número de solicitações para suas funções e no tempo durante o qual seu código é executado. Para obter mais informações sobre preços do Lambda, consulte [Preços do AWS Lambda](https://aws.amazon.com/lambda/pricing/).

## Modelo de exemplo
<a name="walkthrough-lambda-backed-custom-resources-sample-template"></a>

É possível ver o modelo de amostra de recurso personalizado apoiado pelo Lambda com o mecanismo de atraso abaixo:

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-json"></a>

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "LambdaExecutionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [{
            "Effect": "Allow",
            "Principal": { "Service": ["lambda.amazonaws.com"] },
            "Action": ["sts:AssumeRole"]
          }]
        },
        "Path": "/",
        "Policies": [{
          "PolicyName": "AllowLogs",
          "PolicyDocument": {
            "Statement": [{
              "Effect": "Allow",
              "Action": ["logs:*"],
              "Resource": "*"
            }]
          }
        }]
      }
    },
    "CFNWaiter": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Handler": "index.handler",
        "Runtime": "python3.9",
        "Timeout": 900,
        "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] },
        "Code": {
          "ZipFile": { "Fn::Join": ["\n", [
            "from time import sleep",
            "import json",
            "import cfnresponse",
            "import uuid",
            "",
            "def handler(event, context):",
            "  wait_seconds = 0",
            "  id = str(uuid.uuid1())",
            "  if event[\"RequestType\"] in [\"Create\", \"Update\"]:",
            "    wait_seconds = int(event[\"ResourceProperties\"].get(\"ServiceTimeout\", 0))",
            "    sleep(wait_seconds)",
            "  response = {",
            "    \"TimeWaited\": wait_seconds,",
            "    \"Id\": id ",
            "  }",
            "  cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)"
          ]]}
        }
      }
    },
    "CFNWaiterCustomResource": {
      "Type": "AWS::CloudFormation::CustomResource",
      "Properties": {
        "ServiceToken": { "Fn::GetAtt": ["CFNWaiter", "Arn"] },
        "ServiceTimeout": 60
      }
    }
  },
  "Outputs": {
    "TimeWaited": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "TimeWaited"] },
      "Export": { "Name": "TimeWaited" }
    },
    "WaiterId": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "Id"] },
      "Export": { "Name": "WaiterId" }
    }
  }
}
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-yaml"></a>

```
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: "AllowLogs"
          PolicyDocument:
            Statement:
              - Effect: "Allow"
                Action:
                  - "logs:*"
                Resource: "*"
  CFNWaiter:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Runtime: python3.9 
      Timeout: 900
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile:
          !Sub |
          from time import sleep
          import json
          import cfnresponse
          import uuid
​
          def handler(event, context):
            wait_seconds = 0
            id = str(uuid.uuid1())
            if event["RequestType"] in ["Create", "Update"]:
              wait_seconds = int(event["ResourceProperties"].get("ServiceTimeout", 0))
              sleep(wait_seconds)
            response = {
              "TimeWaited": wait_seconds,
              "Id": id 
            }
            cfnresponse.send(event, context, cfnresponse.SUCCESS, response, "Waiter-"+id)
  CFNWaiterCustomResource:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt CFNWaiter.Arn
      ServiceTimeout: 60
Outputs:
  TimeWaited:
    Value: !GetAtt CFNWaiterCustomResource.TimeWaited
    Export:
      Name: TimeWaited
  WaiterId:
    Value: !GetAtt CFNWaiterCustomResource.Id
    Export:
      Name: WaiterId
```

## Modelo de passo a passo
<a name="walkthrough-lambda-backed-custom-resources-sample-template-walkthrough"></a>

Os trechos a seguir explicam partes relevantes do modelo de amostra para ajudá-lo a entender como a função do Lambda está associada a um recurso personalizado e a entender a saída.

`CFNWaiter` do resource [AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html)  
O recurso `AWS::Lambda::Function` especifica o código-fonte, o nome do handler, o ambiente de runtime e o nome do recurso da Amazon (ARN) do perfil de execução da função.  
A propriedade `Handler` é definida como `index.handler`, pois usa um código-fonte do Python. Para mais informações sobre identificadores de manipuladores aceitos ao usar códigos-fonte de funções embutidas, consulte [ AWS::Lambda::Function Code](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-zipfile).  
O `Runtime` é especificado como `python3.9` porque o arquivo de origem é um código do Python.  
O `Timeout` é definido como 900 segundos.  
A propriedade `Role` usa a função `Fn::GetAtt` para obter o ARN do perfil de execução `LambdaExecutionRole` declarado no recurso `AWS::IAM::Role` do modelo.  
A propriedade `Code` define o código da função inline com uma função do Python. A função do Python no modelo de amostra faz o seguinte:  
+ Criar um ID exclusivo utilizando o UUID
+ Verificar se a solicitação é de criação ou atualização
+ Suspender pela duração especificada por `ServiceTimeout` durante solicitações `Create` ou `Update`
+ Retorna o tempo de espera e o ID exclusivo

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-lambda-resource-json"></a>

```
...
    "CFNWaiter": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Handler": "index.handler",
        "Runtime": "python3.9",
        "Timeout": 900,
        "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] },
        "Code": {
          "ZipFile": { "Fn::Join": ["\n", [
            "from time import sleep",
            "import json",
            "import cfnresponse",
            "import uuid",
            "",
            "def handler(event, context):",
            "  wait_seconds = 0",
            "  id = str(uuid.uuid1())",
            "  if event[\"RequestType\"] in [\"Create\", \"Update\"]:",
            "    wait_seconds = int(event[\"ResourceProperties\"].get(\"ServiceTimeout\", 0))",
            "    sleep(wait_seconds)",
            "  response = {",
            "    \"TimeWaited\": wait_seconds,",
            "    \"Id\": id ",
            "  }",
            "  cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)"
          ]]}
        }
      }
    },
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-lambda-resource-yaml"></a>

```
...
  CFNWaiter:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Runtime: python3.9 
      Timeout: 900
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile:
          !Sub |
          from time import sleep
          import json
          import cfnresponse
          import uuid
​
          def handler(event, context):
            wait_seconds = 0
            id = str(uuid.uuid1())
            if event["RequestType"] in ["Create", "Update"]:
              wait_seconds = int(event["ResourceProperties"].get("ServiceTimeout", 0))
              sleep(wait_seconds)
            response = {
              "TimeWaited": wait_seconds,
              "Id": id 
            }
            cfnresponse.send(event, context, cfnresponse.SUCCESS, response, "Waiter-"+id)
...
```

`LambdaExecutionRole` do recurso [AWS::IAM::Role](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html)  
O recurso `AWS::IAM:Role` cria um perfil de execução para a função do Lambda, que inclui uma política de função de suposição que permite que o Lambda a use. Ele também contém uma política que permite o acesso aos logs do CloudWatch.

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-iam-role-json"></a>

```
...
    "LambdaExecutionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [{
            "Effect": "Allow",
            "Principal": { "Service": ["lambda.amazonaws.com"] },
            "Action": ["sts:AssumeRole"]
          }]
        },
        "Path": "/",
        "Policies": [{
          "PolicyName": "AllowLogs",
          "PolicyDocument": {
            "Statement": [{
              "Effect": "Allow",
              "Action": ["logs:*"],
              "Resource": "*"
            }]
          }
        }]
      }
    },
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-iam-role-yaml"></a>

```
...
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: "AllowLogs"
          PolicyDocument:
            Statement:
              - Effect: "Allow"
                Action:
                  - "logs:*"
                Resource: "*"
...
```

Recurso [AWS::CloudFormation::CustomResource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-customresource.html) `CFNWaiterCustomResource`  
O recurso personalizado se vincula à função do Lambda com seu ARN usando `!GetAtt CFNWaiter.Arn`. Ela implementará um tempo de espera de 60 segundos para operações de criação e atualização, conforme definido em `ServiceTimeout`. O recurso somente será chamado para uma operação de atualização se as propriedades forem modificadas.

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-custom-resource-json"></a>

```
...
    "CFNWaiterCustomResource": {
      "Type": "AWS::CloudFormation::CustomResource",
      "Properties": {
        "ServiceToken": { "Fn::GetAtt": ["CFNWaiter", "Arn"] },
        "ServiceTimeout": 60
      }
    }
  },
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-custom-resource-yaml"></a>

```
...
  CFNWaiterCustomResource:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt CFNWaiter.Arn
      ServiceTimeout: 60
...
```

`Outputs`  
As `Outputs` desse modelo são `TimeWaited` e `WaiterId`. O valor `TimeWaited` usa uma função `Fn::GetAtt` para fornecer a quantidade de tempo que o recurso de espera realmente aguardou. `WaiterId` usa uma função `Fn::GetAtt` para fornecer o ID exclusivo que foi gerado e associado à execução.

### JSON
<a name="walkthrough-lambda-backed-custom-resources-sample-template-output-json"></a>

```
...
  "Outputs": {
    "TimeWaited": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "TimeWaited"] },
      "Export": { "Name": "TimeWaited" }
    },
    "WaiterId": {
      "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "Id"] },
      "Export": { "Name": "WaiterId" }
    }
  }
}
...
```

### YAML
<a name="walkthrough-lambda-backed-custom-resources-sample-template-output-yaml"></a>

```
...
Outputs:
  TimeWaited:
    Value: !GetAtt CFNWaiterCustomResource.TimeWaited
    Export:
      Name: TimeWaited
  WaiterId:
    Value: !GetAtt CFNWaiterCustomResource.Id
    Export:
      Name: WaiterId
...
```

## Pré-requisitos
<a name="walkthrough-lambda-backed-custom-resources-prerequisites"></a>

Você deve ter permissões do IAM para usar todos os serviços correspondentes, como o Lambda e o CloudFormation.

## Iniciar a pilha
<a name="walkthrough-lambda-backed-custom-resources-createfunction-createstack"></a>

**Para criar a pilha**

1. Encontre o modelo de sua preferência (YAML ou JSON) na seção [Modelo de exemplo](#walkthrough-lambda-backed-custom-resources-sample-template) e salve-o na máquina com o nome `samplelambdabackedcustomresource.template`.

1. Abra o console do CloudFormation em [https://console.aws.amazon.com/cloudformation/](https://console.aws.amazon.com/cloudformation/).

1. Na página **Pilhas**, escolha **Criar pilha** no canto superior direito e depois **Com novos recursos (padrão)**.

1. Em **Pré-requisito: preparar modelo**, escolha **Escolher um modelo existente**.

1. Para **Especificar modelo**, selecione **Carregar um arquivo de modelo** e depois **Escolher arquivo**.

1. Selecione o arquivo de modelo `samplelambdabackedcustomresource.template` salvou anteriormente.

1. Escolha **Próximo**.

1. Para **Nome da pilha**, digite **SampleCustomResourceStack** e escolha **Próximo**.

1. Para esta demonstração, você não precisa adicionar tags ou especificar configurações avançadas, portanto escolha **Próximo**.

1. Certifique-se de que o nome da pilha esteja correto e escolha **Criar**.

Pode levar alguns minutos para que o CloudFormation crie a pilha. Para monitorar o progresso, visualize os eventos da pilha. Para obter mais informações, consulte [Visualizar informações da pilha no console do CloudFormation](cfn-console-view-stack-data-resources.md).

Se a criação da pilha for bem-sucedida, todos os recursos da pilha, como a função do Lambda e o recurso personalizado, foram criados. Você usou com êxito uma função do Lambda e um recurso personalizado.

Se a função do Lambda retornar um erro, visualize os logs da função no [console](https://console.aws.amazon.com/cloudwatch/home#logs:) do CloudWatch Logs. O nome do stream de logs é o ID físico do recurso personalizado, que pode ser encontrado visualizando os recursos da pilha. Para obter mais informações, consulte [Visualizar dados de log](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html#ViewingLogData), no *Guia do usuário do Amazon CloudWatch*.

## Limpar os recursos
<a name="walkthrough-lambda-backed-custom-resources-createfunction-cleanup"></a>

Exclua a pilha para limpar todos os recursos de pilha criados; assim, você não será cobrado por recursos desnecessários.

**Para excluir a pilha**

1. No console do CloudFormation, escolha a pilha **SampleCustomResourceStack**.

1. Escolha **Ações** e, em seguida, **Excluir pilha**.

1. Na mensagem de confirmação, escolha **Sim, excluir**.

Todos os recursos que você criou serão excluídos.

Agora que você sabe como criar e usar o recurso personalizado apoiado pelo Lambda, pode usar o modelo de amostra e o código deste passo a passo para criar e experimentar outras pilhas e funções.

## Informações relacionadas
<a name="w2aac11c45b9c24b9c23"></a>
+ [Referência de recursos personalizados do CloudFormation](crpg-ref.md)
+ [AWS::CloudFormation::CustomResource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-customresource.html)

# `cfn-response`Módulo
<a name="cfn-lambda-function-code-cfnresponsemodule"></a>

No modelo do CloudFormation, é possível especificar uma função do Lambda como o destino de um recurso personalizado. Ao usar a propriedade `ZipFile` para especificar o código-fonte da [função](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html), você pode carregar o módulo `cfn-response` com a finalidade de enviar respostas da função do Lambda para um recurso personalizado. O módulo `cfn-response` corresponde a uma biblioteca que simplifica o envio de respostas para o recurso personalizado que invocou a função do Lambda. O módulo contém um método `send` que envia um [objeto de resposta](crpg-ref.md#crpg-ref-responses) para um recurso personalizado por meio de um URL do Amazon S3 assinado previamente (o `ResponseURL`).

O módulo `cfn-response` está disponível somente quando você usa a propriedade `ZipFile` para gravar o código-fonte. Ele não está disponível para o código-fonte armazenado nos buckets do Amazon S3. Para código em buckets do , você deve criar suas próprias funções para enviar respostas.

**nota**  
Depois de executar o método `send` a função do Lambda é encerrada, assim qualquer coisa que você grave após esse método é ignorada.

## Carregar o módulo `cfn-response`
<a name="cfn-lambda-function-code-cfnresponsemodule-loading"></a>

Para funções Node.js, use a função `require()` para carregar o módulo `cfn-response`. Para esclarecer, o código de exemplo a seguir cria um objeto `cfn-response` com o nome `response`:

```
var response = require('cfn-response');
```

Para Python, use a instrução `import` para carregar o módulo `cfnresponse`, conforme mostrado no seguinte exemplo:

**nota**  
Use essa exata declaração de importação. Se você usar outras variantes da instrução “import”, o CloudFormation não incluirá o módulo de resposta.

```
import cfnresponse
```

## `send`Parâmetros do método
<a name="cfn-lambda-function-code-cfnresponsemodule-send-parameters"></a>

Você pode usar os seguintes parâmetros com o método `send`.

`event`  
Os campos em uma [solicitação de recurso personalizado](crpg-ref.md#crpg-ref-requesttypes).

`context`  
Um objeto, específico às funções do Lambda que você pode usar para especificar quando a função e qualquer retorno de chamada tiverem concluído a execução ou para acessar informações no ambiente de execução do Lambda. Para obter mais informações, consulte [Construir funções do Lambda com Node.js](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html) no *Guia do desenvolvedor do AWS Lambda*.

`responseStatus`  
Se a função foi concluída com êxito. Use as constantes do módulo `cfnresponse` para especificar o status: `SUCCESS` para execuções bem-sucedidas e `FAILED` para execuções com falha.

`responseData`  
O campo `Data` de um [objeto de resposta](crpg-ref.md#crpg-ref-responses) de um recurso personalizado. Os dados são uma lista de pares de nome-valor.

`physicalResourceId`  
Opcional. O identificador exclusivo do recurso personalizado que invocou a função. Por padrão, o módulo usa o nome do fluxo de log do Amazon CloudWatch Logs que está associado à função do Lambda.  
O valor retornado para um `PhysicalResourceId` pode alterar as operações de atualização de recursos personalizados. Se o valor retornado for o mesmo, a atualização é considerada normal. Se o valor retornado for diferente, o CloudFormation reconhecerá a atualização como uma substituição e enviará uma solicitação de exclusão para o recurso antigo. Para obter mais informações, consulte [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-customresource.html).

`noEcho`  
Opcional. Indica se é necessário mascarar a saída do recurso personalizado quando ela for recuperada usando a função `Fn::GetAtt`. Se definido como `true`, todos os valores retornados serão mascarados com asteriscos (\$1\$1\$1\$1\$1), exceto informações armazenadas nos locais especificados abaixo. Por padrão, esse valor é `false`.  
O uso do atributo `NoEcho` não mascara informações armazenadas no seguinte:  
+ A seção de modelo de `Metadata`. O CloudFormation não transforma, modifica nem edita nenhuma informação incluída na seção `Metadata`. Para obter mais informações, consulte [Metadados](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html).
+ A seção de modelo de `Outputs`. Para obter mais informações, consulte [Saídas](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html).
+ O atributo `Metadata` de uma definição de recurso. Para obter mais informações, consulte o atributo [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-metadata.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-metadata.html).
É altamente recomendável não usar esses mecanismos para incluir informações confidenciais, como senhas ou segredos.
Para obter mais informações sobre como usar `NoEcho` para mascarar informações confidenciais, consulte a prática recomendada [Não incorporar credenciais em seus modelos](security-best-practices.md#creds).

## Exemplos
<a name="cfn-lambda-function-code-cfnresponsemodule-examples"></a>

### Node.js
<a name="cfn-lambda-function-code-zipfile-examplenodejs"></a>

No exemplo Node.js a seguir, a função do Lambda incorporada obtém um valor de entrada e multiplica por 5. As funções em linha são especialmente úteis para funções menores, pois permitem que você especifique o código-fonte diretamente no modelo, em vez de criar um pacote e carregá-lo em um bucket do Amazon S3. A função usa o método `cfn-response` `send` para enviar o resultado de volta para o recurso personalizado que a chamou.

#### JSON
<a name="cfn-lambda-function-code-zipfile-examplenodejs.json"></a>

```
"ZipFile": { "Fn::Join": ["", [
  "var response = require('cfn-response');",
  "exports.handler = function(event, context) {",
  "  var input = parseInt(event.ResourceProperties.Input);",
  "  var responseData = {Value: input * 5};",
  "  response.send(event, context, response.SUCCESS, responseData);",
  "};"
]]}
```

#### YAML
<a name="cfn-lambda-function-code-zipfile-examplenodejs-yaml"></a>

```
ZipFile: >
  var response = require('cfn-response');
  exports.handler = function(event, context) {
    var input = parseInt(event.ResourceProperties.Input);
    var responseData = {Value: input * 5};
    response.send(event, context, response.SUCCESS, responseData);
  };
```

### Python
<a name="cfn-lambda-function-code-zipfile-examplepython"></a>

No exemplo de Python a seguir, a função do Lambda em linha pega um valor inteiro e o multiplica por 5.

#### JSON
<a name="cfn-lambda-function-code-zipfile-examplepython.json"></a>

```
"ZipFile" : { "Fn::Join" : ["\n", [
  "import json",
  "import cfnresponse",
  "def handler(event, context):",
  "   responseValue = int(event['ResourceProperties']['Input']) * 5",
  "   responseData = {}",
  "   responseData['Data'] = responseValue",
  "   cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, \"CustomResourcePhysicalID\")"
]]}
```

#### YAML
<a name="cfn-lambda-function-code-zipfile-examplepython.yaml"></a>

```
ZipFile: |
  import json
  import cfnresponse
  def handler(event, context):
    responseValue = int(event['ResourceProperties']['Input']) * 5
    responseData = {}
    responseData['Data'] = responseValue
    cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
```

## Código-fonte do módulo
<a name="cfn-lambda-function-code-cfnresponsemodule-source"></a>

**Topics**
+ [Código-fonte assíncrono do Node.js](#cfn-lambda-function-code-cfnresponsemodule-source-nodejs-async)
+ [Código fonte do Node.js](#cfn-lambda-function-code-cfnresponsemodule-source-nodejs)
+ [Código-fonte Python](#cfn-lambda-function-code-cfnresponsemodule-source-python)

### Código-fonte assíncrono do Node.js
<a name="cfn-lambda-function-code-cfnresponsemodule-source-nodejs-async"></a>

Veja a seguir o código-fonte do módulo de resposta das funções do Node.js caso o handler seja assíncrono. Analise-o para entender o que o módulo faz e obter ajuda com a implementação de suas próprias funções de resposta.

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0

exports.SUCCESS = "SUCCESS";
exports.FAILED = "FAILED";

exports.send = function(event, context, responseStatus, responseData, physicalResourceId, noEcho) {

    return new Promise((resolve, reject) => {
        var responseBody = JSON.stringify({
            Status: responseStatus,
            Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName,
            PhysicalResourceId: physicalResourceId || context.logStreamName,
            StackId: event.StackId,
            RequestId: event.RequestId,
            LogicalResourceId: event.LogicalResourceId,
            NoEcho: noEcho || false,
            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
            }
        };

        var request = https.request(options, function(response) {
            console.log("Status code: " + parseInt(response.statusCode));
            resolve(context.done());
        });

        request.on("error", function(error) {
            console.log("send(..) failed executing https.request(..): " + maskCredentialsAndSignature(error));
            reject(context.done(error));
        });

        request.write(responseBody);
        request.end();
    })
}
 
function maskCredentialsAndSignature(message) {
    return message.replace(/X-Amz-Credential=[^&\s]+/i, 'X-Amz-Credential=*****')
        .replace(/X-Amz-Signature=[^&\s]+/i, 'X-Amz-Signature=*****');
}
```

### Código fonte do Node.js
<a name="cfn-lambda-function-code-cfnresponsemodule-source-nodejs"></a>

Veja a seguir o código-fonte do módulo de resposta das funções do Node.js caso o handler não seja assíncrono. Analise-o para entender o que o módulo faz e obter ajuda com a implementação de suas próprias funções de resposta.

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0
 
exports.SUCCESS = "SUCCESS";
exports.FAILED = "FAILED";

exports.send = function(event, context, responseStatus, responseData, physicalResourceId, noEcho) {

    var responseBody = JSON.stringify({
        Status: responseStatus,
        Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName,
        PhysicalResourceId: physicalResourceId || context.logStreamName,
        StackId: event.StackId,
        RequestId: event.RequestId,
        LogicalResourceId: event.LogicalResourceId,
        NoEcho: noEcho || false,
        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
        }
    };

    var request = https.request(options, function(response) {
        console.log("Status code: " + parseInt(response.statusCode));
        context.done();
    });

    request.on("error", function(error) {
        console.log("send(..) failed executing https.request(..): " + maskCredentialsAndSignature(error));
        context.done();
    });

    request.write(responseBody);
    request.end();
}
```

### Código-fonte Python
<a name="cfn-lambda-function-code-cfnresponsemodule-source-python"></a>

Veja a seguir o código-fonte do módulo de resposta das funções do Python:

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
 
from __future__ import print_function
import urllib3
import json
import re

SUCCESS = "SUCCESS"
FAILED = "FAILED"

http = urllib3.PoolManager()


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

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

    json_responseBody = json.dumps(responseBody)

    print("Response body:")
    print(json_responseBody)

    headers = {
        'content-type' : '',
        'content-length' : str(len(json_responseBody))
    }

    try:
        response = http.request('PUT', responseUrl, headers=headers, body=json_responseBody)
        print("Status code:", response.status)


    except Exception as e:

        print("send(..) failed executing http.request(..):", mask_credentials_and_signature(e))
 
 
def mask_credentials_and_signature(message):
    message = re.sub(r'X-Amz-Credential=[^&\s]+', 'X-Amz-Credential=*****', message, flags=re.IGNORECASE)
    return re.sub(r'X-Amz-Signature=[^&\s]+', 'X-Amz-Signature=*****', message, flags=re.IGNORECASE)
```