

# Recursos personalizados y respaldados por Lambda
<a name="template-custom-resources-lambda"></a>

Al asociar una función de Lambda con un recurso personalizado, la función se invoca siempre que se crea, actualiza o elimina el recurso personalizado. CloudFormation llama a una API de Lambda para invocar la función y transferir todos los datos de la solicitud (como el tipo de solicitud y las propiedades de recursos) a la función. La potencia y la posibilidad de personalización de funciones de Lambda en combinación con CloudFormation permiten una amplia variedad de situaciones, como, por ejemplo, las búsquedas de ID de AMI de forma dinámica durante la creación de la pila o la implementación y el uso de las funciones de utilidad, tales como las funciones de reversión de cadenas.

Para obtener una introducción a los recursos personalizados y a su funcionamiento, consulte [Cómo funcionan los recursos personalizados](template-custom-resources.md#how-custom-resources-work).

**Topics**
+ [Explicación: cómo crear un mecanismo de retardo mediante un recurso personalizado respaldado por Lambda](walkthrough-lambda-backed-custom-resources.md)
+ [`cfn-response`Módulo de](cfn-lambda-function-code-cfnresponsemodule.md)

# Explicación: cómo crear un mecanismo de retardo mediante un recurso personalizado respaldado por Lambda
<a name="walkthrough-lambda-backed-custom-resources"></a>

En este tutorial, se muestra cómo configurar e inicializar un recurso personalizado respaldado por Lambda mediante una plantilla de muestra de CloudFormation. Esta plantilla crea un mecanismo de retraso que pausa las implementaciones de pilas durante un tiempo específico. Esto puede resultar útil cuando se necesita introducir retrasos deliberados durante el aprovisionamiento de recursos; por ejemplo, cuando se espera a que los recursos se estabilicen antes de que se creen los recursos dependientes.

**nota**  
Si bien anteriormente se recomendaban recursos personalizados respaldados por Lambda para recuperar los ID de AMI, ahora recomendamos usar parámetros AWS Systems Manager. Este enfoque hace que sus plantillas sean más reutilizables y fáciles de mantener. Para obtener más información, consulte [Obtención de un valor de texto sin formato del Almacén de parámetros de Systems Manager](dynamic-references-ssm.md). 

**Topics**
+ [Descripción general](#walkthrough-lambda-backed-custom-resources-overview)
+ [Plantilla de muestra](#walkthrough-lambda-backed-custom-resources-sample-template)
+ [Explicación de la plantilla de ejemplo](#walkthrough-lambda-backed-custom-resources-sample-template-walkthrough)
+ [Requisitos previos](#walkthrough-lambda-backed-custom-resources-prerequisites)
+ [Lanzamiento de la pila](#walkthrough-lambda-backed-custom-resources-createfunction-createstack)
+ [Saneamiento de recursos](#walkthrough-lambda-backed-custom-resources-createfunction-cleanup)
+ [Información relacionada](#w2aac11c45b9c24b9c23)

## Descripción general
<a name="walkthrough-lambda-backed-custom-resources-overview"></a>

La plantilla de pila de ejemplo utilizada en este tutorial crea un recurso personalizado respaldado por Lambda. Este recurso personalizado introduce un retraso configurable (60 segundos por defecto) durante la creación de la pila. El retraso se produce durante las actualizaciones de la pila solo cuando se modifican las propiedades del recurso personalizado.

Esta plantilla proporciona los siguientes recursos:
+ un recurso personalizado,
+ una función de Lambda y
+ un rol de IAM que permite a Lambda escribir registros en CloudWatch.

También define dos salidas:
+ El tiempo real que esperó la función.
+ Un identificador único generado durante cada ejecución de la función de Lambda.



**nota**  
CloudFormation es un servicio gratuito, pero Lambda cobra en función del número de solicitudes de sus funciones y del tiempo de ejecución de su código. Para obtener más información acerca de los precios de Lambda, consulte [Precios de AWS Lambda](https://aws.amazon.com/lambda/pricing/).

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

A continuación, puede ver la plantilla de ejemplo de un recurso personalizado respaldado por Lambda con el mecanismo de retardo:

### 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
```

## Explicación de la plantilla de ejemplo
<a name="walkthrough-lambda-backed-custom-resources-sample-template-walkthrough"></a>

Los siguientes fragmentos explican partes relevantes de la plantilla de ejemplo que ayudan a comprender cómo la función de Lambda se asocia a un recurso personalizado y a entender la salida.

`CFNWaiter` del recurso [AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html)  
El recurso `AWS::Lambda::Function` especifica el código fuente de la función, el nombre del controlador, el entorno del tiempo de ejecución y el nombre de recurso de Amazon (ARN).  
La propiedad `Handler` está establecida en `index.handler`, ya que utiliza un código fuente de Python. Para obtener más información sobre los identificadores de controlador aceptados al usar código fuente de funciones en línea, consulte [AWS::Lambda::Function Code](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-zipfile).  
El `Runtime` se especifica como `python3.9`, ya que el archivo de origen está escrito en Python.  
El `Timeout` se establece en 900 segundos.  
La propiedad `Role` utiliza la función `Fn::GetAtt` para obtener el ARN del rol de ejecución `LambdaExecutionRole` que se declara en el recurso `AWS::IAM::Role` en la plantilla.  
La propiedad `Code` define el código de la función en línea mediante una función de Python. La función de Python en la plantilla de ejemplo hace lo siguiente:  
+ Crear un ID único utilizando el UUID
+ Verifica si se trata de una solicitud de creación o de actualización
+ Duerme durante el tiempo especificado por `ServiceTimeout` durante solicitudes de `Create` o `Update`
+ Devuelve el tiempo de espera y el identificador único

### 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` del recurso [AWS::IAM::Role](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-iam-role.html)  
El recurso `AWS::IAM:Role` crea un rol de ejecución para la función de Lambda, con una política de asunción que autoriza a Lambda a utilizar dicho rol. También contiene una política que permite el acceso a Registros de 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: "*"
...
```

`CFNWaiterCustomResource` de recurso [AWS::CloudFormation::CustomResource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-customresource.html)  
El recurso personalizado se vincula a la función de Lambda con su ARN mediante `!GetAtt CFNWaiter.Arn`. Establecerá un tiempo de espera de 60 segundos para las operaciones de creación y actualización, conforme a lo dispuesto en `ServiceTimeout`. El recurso solo se invocará para una operación de actualización si se modifican las propiedades.

### 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`  
Esta plantilla produce como `Outputs` el `TimeWaited` y el `WaiterId`. El valor `TimeWaited` utiliza una función de `Fn::GetAtt` para indicar la cantidad de tiempo que el recurso de espera realmente esperó. El `WaiterId` utiliza una función de `Fn::GetAtt` para proporcionar el identificador único que se generó y se asoció a la ejecución.

### 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
...
```

## Requisitos previos
<a name="walkthrough-lambda-backed-custom-resources-prerequisites"></a>

Se necesitan permisos de IAM para utilizar todos los servicios correspondientes, como Lambda y CloudFormation.

## Lanzamiento de la pila
<a name="walkthrough-lambda-backed-custom-resources-createfunction-createstack"></a>

**Para crear la pila**

1. Busque la plantilla que prefiera (YAML o JSON) en la sección [Plantilla de muestra](#walkthrough-lambda-backed-custom-resources-sample-template) y guárdela en la máquina con el nombre `samplelambdabackedcustomresource.template`.

1. Abra la consola de CloudFormation en [https://console.aws.amazon.com/cloudformation/](https://console.aws.amazon.com/cloudformation/).

1. En la página **Pilas**, seleccione **Crear pila** en la parte superior derecha y, a continuación, seleccione **Con recursos nuevos (estándar)**.

1. En **Requisito previo: preparar la plantilla**, elija **Seleccione una plantilla existente**.

1. En **Especificar plantilla**, seleccione **Cargar un archivo de plantilla** y, a continuación, elija **Elegir archivo**.

1. Seleccione el archivo de plantilla `samplelambdabackedcustomresource.template` que guardó anteriormente.

1. Elija **Siguiente**.

1. En **Nombre de la pila**, escriba **SampleCustomResourceStack** y, a continuación, elija **Siguiente**.

1. Para este tutorial, no tiene que añadir etiquetas ni especificar una configuración avanzada, así que elija **Next (Siguiente)**.

1. Verifique que el nombre de la pila sea correcto y luego seleccione **Crear**.

CloudFormation puede tardar varios minutos en crear la pila. Para monitorizar el progreso, vea los eventos de la pila. Para obtener más información, consulte [Visualización de la información de la pila desde la consola de CloudFormation](cfn-console-view-stack-data-resources.md).

Si se crea la pila correctamente, se crean todos los recursos de la pila, como la función Lambda y el recurso personalizado. Ha utilizado correctamente una función de Lambda y un recurso personalizado.

Si la función de Lambda devuelve un error, vea los registros de la función en la [consola](https://console.aws.amazon.com/cloudwatch/home#logs:) de Registros de CloudWatch. El nombre de la flujo de registros es el ID físico del recurso personalizado, que puede encontrar al visualizar los recursos de la pila. Para obtener más información, consulte la sección de [Visualización de datos de registro](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html#ViewingLogData) en la *Guía del usuario de Amazon CloudWatch*.

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

Elimine la pila para limpiar todos los recursos de la pila que creó para que no se le cobren los recursos innecesarios.

**Para eliminar la pila**

1. En la consola de CloudFormation, elija la pila **SampleCustomResourceStack**.

1. Elija **Actions (Acciones)** y, a continuación, **Delete Stack (Eliminar pila)**.

1. En el mensaje de confirmación, elija **Yes, Delete (Sí, eliminar)**.

Se eliminan todos los recursos que creó.

Ahora que comprende cómo crear y utilizar un recurso personalizado respaldado por Lambda, puede utilizar la plantilla y el código de ejemplo de esta guía para crear y experimentar con otras pilas y funciones.

## Información relacionada
<a name="w2aac11c45b9c24b9c23"></a>
+ [Referencia de recursos personalizados de CloudFormation](crpg-ref.md)
+ [AWS::CloudFormation::CustomResource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-customresource.html)

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

En su plantilla de CloudFormation puede especificar una función de Lambda como destino de un recurso personalizado. Al utilizar la propiedad `ZipFile` para especificar el código fuente de la [función](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html), puede cargar el módulo `cfn-response` para enviar las respuestas desde su función de Lambda a un recurso personalizado. El módulo `cfn-response` es una biblioteca que simplifica el envío de respuestas al recurso personalizado que invocó la función de Lambda. El módulo tiene un método `send` que envía un [objeto de respuesta](crpg-ref.md#crpg-ref-responses) a un recurso personalizado mediante una URL prefirmada de Amazon S3 (`ResponseURL`).

El módulo `cfn-response` solo está disponible si utiliza la propiedad `ZipFile` para escribir el código fuente. No está disponible para el código fuente que se almacena en buckets de Amazon S3. Para un código de buckets de , debe escribir sus propias funciones para enviar respuestas.

**nota**  
Después de ejecutar el método `send`, la función de Lambda termina, así que todo lo que escriba después de este método se pasa por alto.

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

Para las funciones de Node.js, utilice la función `require()` para cargar el módulo `cfn-response`. Por ejemplo, el siguiente ejemplo de código crea un objeto `cfn-response` con el nombre `response`:

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

Para Python, utilice la declaración `import` para cargar el módulo `cfnresponse`, tal y como se muestra en el ejemplo siguiente:

**nota**  
Utilice esta declaración de importación exacto. Si utiliza otras variantes de la instrucción de importación, CloudFormation no incluirá el módulo de respuesta.

```
import cfnresponse
```

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

Puede utilizar los siguientes parámetros con el método `send`.

`event`  
Los campos de una [solicitud de recurso personalizado](crpg-ref.md#crpg-ref-requesttypes).

`context`  
Un objeto, específico de las funciones de Lambda, que puede utilizar para especificar cuando la función y cualquier devolución de llamada han completado la ejecución o para obtener acceso a información desde el entorno de ejecución de Lambda. Para obtener más información, consulte [Creación de funciones de Lambda con Node.js](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html) en la *Guía para desarrolladores de AWS Lambda*.

`responseStatus`  
Independientemente de que la función se complete con éxito. Utilice las constantes del módulo `cfnresponse` para especificar el estado: `SUCCESS` para las ejecuciones de éxito y `FAILED` para ejecuciones fallidas.

`responseData`  
El campo `Data` de un [objeto de respuesta](crpg-ref.md#crpg-ref-responses) de recursos personalizados. Los datos consisten en una lista de pares de nombre y valor.

`physicalResourceId`  
Opcional. El identificador único del recurso personalizado que invocó la función. De forma predeterminada, el módulo utiliza el nombre de la secuencia de registros de Amazon CloudWatch Logs que se asocia a la función de Lambda.  
El valor devuelto para un `PhysicalResourceId` puede cambiar las operaciones de actualización de recursos personalizadas. Si el valor devuelto es el mismo, se considera una actualización normal. Si el valor devuelto es diferente, CloudFormation reconoce la actualización como un reemplazo y envía una solicitud de eliminación al antiguo recurso. Para obtener más información, 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. Indique si se enmascara la salida del recurso personalizado cuando se recupera con la función `Fn::GetAtt`. Si se establece en `true`, todos los valores devueltos se enmascaran con asteriscos (\$1\$1\$1\$1\$1), excepto la información almacenada en las ubicaciones especificadas a continuación. De forma predeterminada, este valor es `false`.  
El uso del atributo `NoEcho` no enmascara ninguna información almacenada en lo que se muestra a continuación:  
+ La sección de la plantilla `Metadata`. CloudFormation no transforma, modifica ni redacta ninguna información que incluya en la sección `Metadata`. Para obtener más información, consulte [Metadata](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html).
+ La sección de la plantilla `Outputs`. Para obtener más información, consulte [Salidas](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html).
+ El atributo `Metadata` de una definición de recurso. Para obtener más información, consulte [`Metadata` atributo](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-metadata.html).
Recomendamos encarecidamente que no utilice estos mecanismos para incluir información confidencial, como contraseñas o secretos.
Para obtener más información sobre el uso de `NoEcho` para enmascarar información confidencial, consulte la práctica recomendada de [No integre credenciales en sus plantillas](security-best-practices.md#creds).

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

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

En el siguiente ejemplo Node.js, la función de Lambda en línea toma un valor de entrada y lo multiplica por 5. Las funciones en línea son especialmente útiles para las funciones más pequeñas, ya que le permiten especificar el código fuente directamente en la plantilla, en lugar de crear un paquete y cargarlo en un bucket de Amazon S3. La función utiliza el método `cfn-response` `send` para enviar el resultado de vuelta al recurso personalizado que invocó.

#### 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>

En el siguiente ejemplo de Python, la función de Lambda en línea toma un valor de entero y lo 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 fuente del módulo
<a name="cfn-lambda-function-code-cfnresponsemodule-source"></a>

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

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

A continuación, se muestra el código fuente del módulo de respuesta para las funciones de Node.js si el controlador es asíncrono. Revíselo para entender qué hace el módulo y para obtener ayuda con la implementación de sus propias funciones de respuesta.

```
// 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 fuente de Node.js
<a name="cfn-lambda-function-code-cfnresponsemodule-source-nodejs"></a>

A continuación, se muestra el código fuente del módulo de respuesta para las funciones de Node.js si el controlador no es asíncrono. Revíselo para entender qué hace el módulo y para obtener ayuda con la implementación de sus propias funciones de respuesta.

```
// 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 fuente Python
<a name="cfn-lambda-function-code-cfnresponsemodule-source-python"></a>

A continuación, se muestra el código fuente del módulo de respuesta de las funciones de 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)
```