

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Cree funciones Lambda para evaluar los recursos de Lambda Hooks
<a name="lambda-hooks-create-lambda-function"></a>

CloudFormation Lambda Hooks le permite evaluar CloudFormation y realizar API de control de nube de AWS operaciones con su propio código personalizado. Su Hook puede impedir que se lleve a cabo una operación o emitir una advertencia a la persona que llama y permitir que la operación continúe. Al crear un Hook Lambda, puede configurarlo para interceptar y evaluar las siguientes operaciones: CloudFormation 
+ Operaciones de recursos
+ Operaciones de apilamiento
+ Operaciones del conjunto de cambios

**Topics**
+ [Desarrollo de un gancho Lambda](#lambda-hooks-create-lambda-function-develop)
+ [Evaluación de las operaciones de recursos con Lambda Hooks](#lambda-hooks-create-lambda-function-resource)
+ [Evaluación de las operaciones de apilamiento con Lambda Hooks](#lambda-hooks-create-lambda-function-stack)
+ [Evaluación de las operaciones de los conjuntos de cambios con Lambda Hooks](#lambda-hooks-create-lambda-function-change-set)

## Desarrollo de un gancho Lambda
<a name="lambda-hooks-create-lambda-function-develop"></a>

Cuando Hooks invoque tu Lambda, esperará hasta 30 segundos para que la Lambda evalúe la entrada. La Lambda devolverá una respuesta JSON que indica si el Hook se realizó correctamente o no.

**Topics**
+ [Solicita una entrada](#lambda-hooks-create-lambda-function-request-input)
+ [Entrada de respuesta](#lambda-hooks-create-lambda-function-request-response)
+ [Ejemplos](#lambda-hooks-create-lambda-function-request-example)

### Solicita una entrada
<a name="lambda-hooks-create-lambda-function-request-input"></a>

La entrada que se pasa a la función Lambda depende de la operación de destino de Hook (por ejemplo: pila, recurso o conjunto de cambios). 

### Entrada de respuesta
<a name="lambda-hooks-create-lambda-function-request-response"></a>

Para poder comunicar a Hooks si tu solicitud se ha realizado correctamente o no, tu función Lambda debe devolver una respuesta JSON.

El siguiente es un ejemplo de la forma de la respuesta que espera Hooks:

```
{ 
  "HookStatus": "SUCCESS" or "FAILED" or "IN_PROGRESS", 
  "errorCode": "NonCompliant" or "InternalFailure"
  "message": String, 
  "clientRequestToken": String,
  "CallbackContext": None, 
  "callbackDelaySeconds": Integer,
  "annotations": [
    {
      "annotationName": String,
      "status": "PASSED" or "FAILED" or "SKIPPED",
      "statusMessage": String,
      "remediationMessage": String,
      "remediationLink": String,
      "severityLevel": "INFORMATIONAL" or "LOW" or "MEDIUM" or "HIGH" or "CRITICAL"
    }
  ]
}
```

HookStatus  <a name="lambda-hook-response-hookstatus"></a>
El estado del Hook. Este campo es obligatorio.  
*Valores válidos*: (`SUCCESS`\$1 `FAILED` \$1`IN_PROGRESS`)  
Un Hook puede volver `IN_PROGRESS` 3 veces. Si no se devuelve ningún resultado, el Hook fallará. En el caso de un Lambda Hook, esto significa que la función Lambda se puede invocar hasta 3 veces.

errorCode  <a name="lambda-hook-response-errorcode"></a>
Muestra si la operación se evaluó y se determinó que no era válida, o si se produjeron errores en el Hook que impidieron la evaluación. Este campo es obligatorio si el Hook falla.  
*Valores válidos*: (`NonCompliant`\$1`InternalFailure`)

message  <a name="lambda-hook-response-message"></a>
El mensaje a la persona que llama en el que se indica por qué el Hook tuvo éxito o falló.  
Al evaluar CloudFormation las operaciones, este campo se trunca a 4096 caracteres.  
Al evaluar las operaciones de la API de Cloud Control, este campo se trunca a 1024 caracteres.

clientRequestToken  <a name="lambda-hook-response-clientrequesttoken"></a>
El token de solicitud que se proporcionó como entrada a la solicitud de Hook. Este campo es obligatorio.

CallbackContext  <a name="lambda-hook-response-callbackcontext"></a>
Si lo indica, pasa un contexto adicional que `hookStatus` se `IN_PROGRESS` proporciona como entrada cuando se vuelve a invocar la función Lambda.

callbackDelaySeconds  <a name="lambda-hook-response-callbackdelayseconds"></a>
Cuánto tiempo debe esperar Hooks para volver a invocar este Hook.

annotations  <a name="lambda-hook-response-annotations"></a>
Un conjunto de objetos de anotación que proporcionan más detalles y una guía de corrección.     
Nombre de anotación  
Un identificador de la anotación.  
status  
El estado de invocación de Hook. Esto resulta útil cuando las anotaciones representan una lógica con una evaluación de aprobación o rechazo similar a la de una regla de Guard.   
*Valores válidos*: (\$1 \$1) `PASSED` `FAILED` `SKIPPED`  
statusMessage  
Explicación del estado específico.  
Mensaje de remediación  
Sugerencia para corregir un `FAILED` estado. Por ejemplo, si falta el cifrado de un recurso, puede indicar cómo añadir el cifrado a la configuración del recurso.  
Enlace de remediación  
Una URL HTTP para obtener instrucciones de corrección adicionales.  
severityLevel  
Define el riesgo relativo asociado a cualquier infracción de este tipo. Al asignar niveles de gravedad a los resultados de la invocación de Hook, puedes hacer referencia al [marco de AWS Security Hub CSPM gravedad](https://docs.aws.amazon.com/securityhub/latest/userguide/asff-required-attributes.html#Severity) como ejemplo de cómo estructurar categorías de gravedad significativas.   
*Valores válidos*: (`INFORMATIONAL`\$1 \$1 \$1 `LOW` `MEDIUM` \$1`HIGH`) `CRITICAL`

### Ejemplos
<a name="lambda-hooks-create-lambda-function-request-example"></a>

A continuación se muestra un ejemplo de una respuesta correcta:

```
{ 
  "hookStatus": "SUCCESS",
  "message": "compliant",
  "clientRequestToken": "123avjdjk31"  
}
```

El siguiente es un ejemplo de una respuesta fallida:

```
{ 
  "hookStatus": "FAILED",
  "errorCode": "NonCompliant",
  "message": "S3 Bucket Versioning must be enabled.",
  "clientRequestToken": "123avjdjk31"
 }
```

## Evaluación de las operaciones de recursos con Lambda Hooks
<a name="lambda-hooks-create-lambda-function-resource"></a>

Cada vez que se crea, actualiza o elimina un recurso, se considera una operación de recurso. Por ejemplo, si ejecutas la actualización de una CloudFormation pila que crea un recurso nuevo, habrás completado una operación de recursos. Cuando creas, actualizas o eliminas un recurso mediante la API de Cloud Control, también se considera una operación de recursos. Puede configurar su CloudFormation Lambda Hook para el destino `RESOURCE` y `CLOUD_CONTROL` las operaciones en la configuración de Hook`TargetOperations`.

**nota**  
El controlador `delete` Hook solo se invoca cuando se elimina un recurso mediante un activador de operaciones de la API `delete-resource` de Cloud Control o. CloudFormation `delete-stack`

**Topics**
+ [Sintaxis de entrada de recursos de Lambda Hook](#lambda-hooks-create-lambda-function-resource-input)
+ [Ejemplo de entrada de cambio de recursos de Lambda Hook](#lambda-hooks-create-lambda-function-resource-example)
+ [Ejemplo de función Lambda para operaciones de recursos](#lambda-hooks-create-lambda-function-resource-example-function)

### Sintaxis de entrada de recursos de Lambda Hook
<a name="lambda-hooks-create-lambda-function-resource-input"></a>

Cuando se invoque su Lambda para una operación de recursos, recibirá una entrada JSON que contiene las propiedades del recurso, las propiedades propuestas y el contexto en torno a la invocación de Hook.

A continuación, se muestra un ejemplo de la forma de la entrada JSON:

```
{
    "awsAccountId": String,
    "stackId": String,
    "changeSetId": String,
    "hookTypeName": String,
    "hookTypeVersion": String,
    "hookModel": {
        "LambdaFunction": String
    },
    "actionInvocationPoint": "CREATE_PRE_PROVISION" or "UPDATE_PRE_PROVISION" or "DELETE_PRE_PROVISION"
    "requestData": {
        "targetName": String,
        "targetType": String,
        "targetLogicalId": String,
        "targetModel": {
            "resourceProperties": {...},
            "previousResourceProperties": {...}
        }
    },
    "requestContext": {
        "invocación": 1,
        "CallbackContext": null
    }
}
```

`awsAccountId`  <a name="lambda-hook-resource-awsaccountid"></a>
El ID Cuenta de AWS que contiene el recurso que se está evaluando.

`stackId`  <a name="lambda-hook-resource-stackid"></a>
El ID de pila de la CloudFormation pila de la que forma parte esta operación. Este campo está vacío si la persona que llama es Cloud Control API.

`changeSetId`  <a name="lambda-hook-resource-changesetid"></a>
El ID del conjunto de cambios que inició la invocación de Hook. Este valor está vacío si el cambio de recurso lo inició la API de Cloud Control o `create-stack` las `update-stack` `delete-stack` operaciones u.

`hookTypeName`  <a name="lambda-hook-resource-hooktypename"></a>
El nombre del Hook que se está ejecutando.

`hookTypeVersion`  <a name="lambda-hook-resource-hooktypeversion"></a>
La versión del Hook que se está ejecutando.

`hookModel`  <a name="lambda-hook-resource-hookmodel"></a>  
`LambdaFunction`  <a name="lambda-hook-resource-hookmodel-lambdafunction"></a>
El ARN de Lambda actual invocado por el Hook.

`actionInvocationPoint`  <a name="lambda-hook-resource-actioninvocationpoint"></a>
El punto exacto de la lógica de aprovisionamiento en el que se ejecuta el Hook.  
*Valores válidos*: (`CREATE_PRE_PROVISION`\$1 `UPDATE_PRE_PROVISION` \$1`DELETE_PRE_PROVISION`)

`requestData`  <a name="lambda-hook-resource-requestdata"></a>  
`targetName`  <a name="lambda-hook-resource-requestdata-targetname"></a>
El tipo de objetivo que se está evaluando, por ejemplo,`AWS::S3::Bucket`.  
`targetType`  <a name="lambda-hook-resource-requestdata-targettype"></a>
El tipo de objetivo que se está evaluando, por ejemplo`AWS::S3::Bucket`. En el caso de los recursos aprovisionados con la API de Cloud Control, este valor será`RESOURCE`.  
`targetLogicalId`  <a name="lambda-hook-resource-requestdata-targetlogicalid"></a>
El ID lógico del recurso que se está evaluando. Si el origen de la invocación de Hook es CloudFormation, será el ID de recurso lógico definido en la CloudFormation plantilla. Si el origen de esta invocación de Hook es la API de Cloud Control, será un valor generado.  
`targetModel`  <a name="lambda-hook-resource-requestdata-targetmodel"></a>  
`resourceProperties`  <a name="lambda-hook-resource-requestdata-targetmodel-resourceproperties"></a>
Las propiedades propuestas del recurso que se está modificando. Si se elimina el recurso, este valor estará vacío.   
`previousResourceProperties`  <a name="lambda-hook-resource-requestdata-targetmodel-previousresourceproperties"></a>
Las propiedades que están asociadas actualmente al recurso que se está modificando. Si se está creando el recurso, este valor estará vacío.

`requestContext`  <a name="lambda-hook-resource-requestcontext"></a>  
invocación  <a name="lambda-hook-resource-requestcontext-invocation"></a>
El intento actual de ejecutar el Hook.   
CallbackContext  <a name="lambda-hook-resource-requestcontext-callbackcontext"></a>
Si el Hook se configuró en y `callbackContext` se devolvió`IN_PROGRESS`, estará aquí después de volver a invocarlo.

### Ejemplo de entrada de cambio de recursos de Lambda Hook
<a name="lambda-hooks-create-lambda-function-resource-example"></a>

El siguiente ejemplo de entrada muestra un Hook Lambda que recibirá la definición del `AWS::DynamoDB::Table` recurso que `ProvisionedThroughput` se va a actualizar, donde el valor `ReadCapacityUnits` de cambia de 3 a 10. Estos son los datos de los que dispone Lambda para su evaluación.

```
{
    "awsAccountId": "123456789012",
    "stackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "hookTypeName": "my::lambda::resourcehookfunction",
    "hookTypeVersion": "00000008",
    "hookModel": {
        "LambdaFunction": "arn:aws:lambda:us-west-2:123456789012:function:MyFunction"
    },
    "actionInvocationPoint": "UPDATE_PRE_PROVISION",
    "requestData": {
        "targetName": "AWS::DynamoDB::Table",
        "targetType": "AWS::DynamoDB::Table",
        "targetLogicalId": "DDBTable",
        "targetModel": {
            "resourceProperties": {
                "AttributeDefinitions": [
                    {
                        "AttributeType": "S",
                        "AttributeName": "Album"
                    },
                    {
                        "AttributeType": "S",
                        "AttributeName": "Artist"
                    }
                ],
                "ProvisionedThroughput": {
                    "WriteCapacityUnits": 5,
                    "ReadCapacityUnits": 10
                },
                "KeySchema": [
                    {
                        "KeyType": "HASH",
                        "AttributeName": "Album"
                    },
                    {
                        "KeyType": "RANGE",
                        "AttributeName": "Artist"
                    }
                ]
            },
            "previousResourceProperties": {
                "AttributeDefinitions": [
                    {
                        "AttributeType": "S",
                        "AttributeName": "Album"
                    },
                    {
                        "AttributeType": "S",
                        "AttributeName": "Artist"
                    }
                ],
                "ProvisionedThroughput": {
                    "WriteCapacityUnits": 5,
                    "ReadCapacityUnits": 5
                },
                "KeySchema": [
                    {
                        "KeyType": "HASH",
                        "AttributeName": "Album"
                    },
                    {
                        "KeyType": "RANGE",
                        "AttributeName": "Artist"
                    }
                ]
            }
        }
    },
    "requestContext": {
        "invocation": 1,
        "callbackContext": null
    }    
}
```

Para ver todas las propiedades disponibles para el tipo de recurso, consulte [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-dynamodb-table.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-dynamodb-table.html).

### Ejemplo de función Lambda para operaciones de recursos
<a name="lambda-hooks-create-lambda-function-resource-example-function"></a>

La siguiente es una función sencilla que produce errores en cualquier actualización de recursos de DynamoDB, que intenta establecer `ReadCapacity` el valor `ProvisionedThroughput` de en un valor superior a 10. Si el Hook funciona correctamente, la persona que llama verá el mensaje «ReadCapacity está correctamente configurado». Si la solicitud no pasa la validación, el Hook fallará con el estado «ReadCapacity no puede ser más de 10».

------
#### [ Node.js ]

```
export const handler = async (event, context) => {
    var targetModel = event?.requestData?.targetModel;
    var targetName = event?.requestData?.targetName;
    var response = {
        "hookStatus": "SUCCESS",
        "message": "ReadCapacity is correctly configured.",
        "clientRequestToken": event.clientRequestToken
    };

    if (targetName == "AWS::DynamoDB::Table") {
        var readCapacity = targetModel?.resourceProperties?.ProvisionedThroughput?.ReadCapacityUnits;
        if (readCapacity > 10) {
            response.hookStatus = "FAILED";
            response.errorCode = "NonCompliant";
            response.message = "ReadCapacity must be cannot be more than 10.";
        }
    }
    return response;
};
```

------
#### [ Python ]

```
import json
                            
def lambda_handler(event, context):
    # Using dict.get() for safe access to nested dictionary values
    request_data = event.get('requestData', {})
    target_model = request_data.get('targetModel', {})
    target_name = request_data.get('targetName', '')
    
    response = {
        "hookStatus": "SUCCESS",
        "message": "ReadCapacity is correctly configured.",
        "clientRequestToken": event.get('clientRequestToken')
    }
    
    if target_name == "AWS::DynamoDB::Table":
        # Safely navigate nested dictionary
        resource_properties = target_model.get('resourceProperties', {})
        provisioned_throughput = resource_properties.get('ProvisionedThroughput', {})
        read_capacity = provisioned_throughput.get('ReadCapacityUnits')
        
        if read_capacity and read_capacity > 10:
            response['hookStatus'] = "FAILED"
            response['errorCode'] = "NonCompliant"
            response['message'] = "ReadCapacity must be cannot be more than 10."
    
    return response
```

------

## Evaluación de las operaciones de apilamiento con Lambda Hooks
<a name="lambda-hooks-create-lambda-function-stack"></a>

Cada vez que cree, actualice o elimine una pila con una plantilla nueva, puede configurar su CloudFormation Lambda Hook para que comience por evaluar la nueva plantilla y, potencialmente, bloquear la operación de apilamiento para que no continúe. Puede configurar su CloudFormation Lambda Hook para que se dirija a `STACK` las operaciones en la configuración de Hook`TargetOperations`.

**Topics**
+ [Sintaxis de entrada de la pila Lambda Hook](#lambda-hooks-create-lambda-function-stack-input)
+ [Ejemplo de entrada de cambio de pila de Lambda Hook](#lambda-hooks-create-lambda-function-stack-example)
+ [Ejemplo de función Lambda para operaciones de apilamiento](#lambda-hooks-create-lambda-function-stack-example-function)

### Sintaxis de entrada de la pila Lambda Hook
<a name="lambda-hooks-create-lambda-function-stack-input"></a>

Cuando se invoque su Lambda para una operación de apilamiento, recibirá una solicitud JSON que contiene el contexto de invocación de Hook y el contexto de solicitud. `actionInvocationPoint` Debido al tamaño de las CloudFormation plantillas y al tamaño de entrada limitado que aceptan las funciones de Lambda, las plantillas reales se almacenan en un objeto de Amazon S3. La entrada `requestData` incluye una URL resignada de Amazon S3 a otro objeto, que contiene la versión de la plantilla actual y la anterior.

El siguiente es un ejemplo de la forma de la entrada JSON:

```
{
    "clientRequesttoken": String,
    "awsAccountId": String,
    "stackID": String,
    "changeSetId": String,
    "hookTypeName": String,
    "hookTypeVersion": String,
    "hookModel": {
        "LambdaFunction":String
    },
    "actionInvocationPoint": "CREATE_PRE_PROVISION" or "UPDATE_PRE_PROVISION" or "DELETE_PRE_PROVISION"
    "requestData": {
        "targetName": "STACK",
        "targetType": "STACK",
        "targetLogicalId": String,
        "payload": String (S3 Presigned URL)
    },
    "requestContext": {
        "invocation": Integer,
        "callbackContext": String
    }
}
```

`clientRequesttoken`  <a name="lambda-hook-stack-clientrequesttoken"></a>
El token de solicitud que se proporcionó como entrada a la solicitud de Hook. Este campo es obligatorio.

`awsAccountId`  <a name="lambda-hook-stack-awsaccountid"></a>
El ID del elemento Cuenta de AWS que contiene la pila que se está evaluando.

`stackID`  <a name="lambda-hook-stack-stackid"></a>
El ID de pila de la CloudFormation pila.

`changeSetId`  <a name="lambda-hook-stack-changesetid"></a>
El ID del conjunto de cambios que inició la invocación de Hook. Este valor está vacío si el cambio de pila lo inició la API de Cloud Control o las `delete-stack` operaciones `create-stack``update-stack`, o.

`hookTypeName`  <a name="lambda-hook-stack-hooktypename"></a>
El nombre del Hook que se está ejecutando.

`hookTypeVersion`  <a name="lambda-hook-stack-hooktypeversion"></a>
La versión del Hook que se está ejecutando.

`hookModel`  <a name="lambda-hook-stack-hookmodel"></a>  
`LambdaFunction`  <a name="lambda-hook-stack-hookmodel-lambdafunction"></a>
El ARN de Lambda actual invocado por el Hook.

`actionInvocationPoint`  <a name="lambda-hook-stack-actioninvocationpoint"></a>
El punto exacto de la lógica de aprovisionamiento en el que se ejecuta el Hook.  
*Valores válidos*: (`CREATE_PRE_PROVISION`\$1 `UPDATE_PRE_PROVISION` \$1`DELETE_PRE_PROVISION`)

`requestData`  <a name="lambda-hook-stack-requestdata"></a>  
`targetName`  <a name="lambda-hook-stack-requestdata-targetname"></a>
Este valor será `STACK`.  
`targetType`  <a name="lambda-hook-stack-requestdata-targettype"></a>
Este valor será `STACK`.  
`targetLogicalId`  <a name="lambda-hook-stack-requestdata-targetlogicalid"></a>
El nombre de la pila.  
`payload`  <a name="lambda-hook-stack-requestdata-payload"></a>
La URL prefirmada de Amazon S3 que contiene un objeto JSON con las definiciones de plantilla actuales y anteriores.

`requestContext`  <a name="lambda-hook-stack-requestcontext"></a>
Si se vuelve a invocar el Hook, se establecerá este objeto.    
`invocation`  <a name="lambda-hook-stack-requestcontext-invocation"></a>
El intento actual de ejecutar el Hook.  
`callbackContext`  <a name="lambda-hook-stack-requestcontext-callbackcontext"></a>
Si el Hook estaba activado `IN_PROGRESS` y `callbackContext` se devolvió, estará aquí al volver a invocarlo.

La `payload` propiedad de los datos de la solicitud es una URL que el código debe recuperar. Una vez que haya recibido la URL, obtendrás un objeto con el siguiente esquema:

```
{
    "template": String,
    "previousTemplate": String
}
```

`template`  <a name="lambda-hook-stack-payload-template"></a>
La CloudFormation plantilla completa que se proporcionó a `create-stack` o`update-stack`. Puede ser una cadena JSON o YAML en función de lo que se haya proporcionado a CloudFormation.  
En `delete-stack` las operaciones, este valor estará vacío.

`previousTemplate`  <a name="lambda-hook-stack-payload-previoustemplate"></a>
La CloudFormation plantilla anterior. Puede ser una cadena JSON o YAML en función de lo que se le CloudFormation haya proporcionado.  
En `delete-stack` las operaciones, este valor estará vacío.

### Ejemplo de entrada de cambio de pila de Lambda Hook
<a name="lambda-hooks-create-lambda-function-stack-example"></a>

El siguiente es un ejemplo de entrada de cambio de pila. The Hook está evaluando un cambio que lo actualiza `ObjectLockEnabled` a verdadero y añade una cola de Amazon SQS:

```
{
    "clientRequestToken": "f8da6d11-b23f-48f4-814c-0fb6a667f50e",
    "awsAccountId": "123456789012",
    "stackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "changeSetId": null,
    "hookTypeName": "my::lambda::stackhook",
    "hookTypeVersion": "00000008",
    "hookModel": {
        "LambdaFunction": "arn:aws:lambda:us-west-2:123456789012:function:MyFunction"
    },
    "actionInvocationPoint": "UPDATE_PRE_PROVISION",
    "requestData": {
        "targetName": "STACK",
        "targetType": "STACK",
        "targetLogicalId": "my-cloudformation-stack",
        "payload": "https://s3......"
    },
    "requestContext": {
        "invocation": 1,
        "callbackContext": null
    }
}
```

Este es un ejemplo `payload` de lo siguiente: `requestData`

```
{
    "template": "{\"Resources\":{\"S3Bucket\":{\"Type\":\"AWS::S3::Bucket\",\"Properties\":{\"ObjectLockEnabled\":true}},\"SQSQueue\":{\"Type\":\"AWS::SQS::Queue\",\"Properties\":{\"QueueName\":\"NewQueue\"}}}}",
    "previousTemplate": "{\"Resources\":{\"S3Bucket\":{\"Type\":\"AWS::S3::Bucket\",\"Properties\":{\"ObjectLockEnabled\":false}}}}"
}
```

### Ejemplo de función Lambda para operaciones de apilamiento
<a name="lambda-hooks-create-lambda-function-stack-example-function"></a>

El siguiente ejemplo es una función sencilla que descarga la carga útil de la operación de apilado, analiza el JSON de la plantilla y devuelve la información. `SUCCESS`

------
#### [ Node.js ]

```
export const handler = async (event, context) => {
    var targetType = event?.requestData?.targetType;
    var payloadUrl = event?.requestData?.payload;
    
    var response = {
        "hookStatus": "SUCCESS",
        "message": "Stack update is compliant",
        "clientRequestToken": event.clientRequestToken
    };
    try {
        const templateHookPayloadRequest = await fetch(payloadUrl);
        const templateHookPayload = await templateHookPayloadRequest.json()
        if (templateHookPayload.template)  {
            // Do something with the template templateHookPayload.template
            // JSON or YAML
        }
        if (templateHookPayload.previousTemplate) {
            // Do something with the template templateHookPayload.previousTemplate
            // JSON or YAML        
        }        
    } catch (error) {
        console.log(error);
        response.hookStatus = "FAILED";
        response.message = "Failed to evaluate stack operation.";
        response.errorCode = "InternalFailure";
    }
    return response;
};
```

------
#### [ Python ]

Para usar Python, tendrás que importar la `requests` biblioteca. Para ello, tendrá que incluir la biblioteca en el paquete de despliegue al crear la función Lambda. *Para obtener más información, consulte [Creación de un paquete de despliegue en formato.zip con dependencias](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-create-dependencies) en la AWS Lambda Guía para desarrolladores.*

```
import json
import requests

def lamnbda_handler(event, context):
    # Safely access nested dictionary values
    request_data = event.get('requestData', {})
    target_type = request_data.get('targetType')
    payload_url = request_data.get('payload')
    
    response = {
        "hookStatus": "SUCCESS",
        "message": "Stack update is compliant",
        "clientRequestToken": event.get('clientRequestToken')
    }
    
    try:
        # Fetch the payload
        template_hook_payload_request = requests.get(payload_url)
        template_hook_payload_request.raise_for_status()  # Raise an exception for bad responses
        template_hook_payload = template_hook_payload_request.json()
        
        if 'template' in template_hook_payload:
            # Do something with the template template_hook_payload['template']
            # JSON or YAML
            pass
        
        if 'previousTemplate' in template_hook_payload:
            # Do something with the template template_hook_payload['previousTemplate']
            # JSON or YAML
            pass

    except Exception as error:
        print(error)
        response['hookStatus'] = "FAILED"
        response['message'] = "Failed to evaluate stack operation."
        response['errorCode'] = "InternalFailure"
    
    return response
```

------

## Evaluación de las operaciones de los conjuntos de cambios con Lambda Hooks
<a name="lambda-hooks-create-lambda-function-change-set"></a>

Cada vez que cree un conjunto de cambios, puede configurar su CloudFormation Lambda Hook para que evalúe primero el nuevo conjunto de cambios y, potencialmente, bloquee su ejecución. Puede configurar su CloudFormation Lambda Hook para que se dirija a `CHANGE_SET` las operaciones en la configuración de Hook`TargetOperations`.

**Topics**
+ [Sintaxis de entrada del conjunto de cambios de Lambda Hook](#lambda-hooks-create-lambda-function-change-set-input)
+ [Ejemplo de entrada de cambio de conjunto de cambios de Lambda Hook](#lambda-hooks-create-lambda-function-change-set-example)
+ [Ejemplo de función Lambda para operaciones de conjuntos de cambios](#lambda-hooks-create-lambda-function-change-set-example-function)

### Sintaxis de entrada del conjunto de cambios de Lambda Hook
<a name="lambda-hooks-create-lambda-function-change-set-input"></a>

La entrada para las operaciones del conjunto de cambios es similar a la de las operaciones de apilamiento, pero la carga útil del conjunto de cambios `requestData` también incluye una lista de los cambios de recursos introducidos por el conjunto de cambios.

A continuación se muestra un ejemplo de la forma de la entrada JSON:

```
{
    "clientRequesttoken": String,
    "awsAccountId": String,
    "stackID": String,
    "changeSetId": String,
    "hookTypeName": String,
    "hookTypeVersion": String,
    "hookModel": {
        "LambdaFunction":String
    },
    "requestData": {
        "targetName": "CHANGE_SET",
        "targetType": "CHANGE_SET",
        "targetLogicalId": String,
        "payload": String (S3 Presigned URL)
    },
    "requestContext": {
        "invocation": Integer,
        "callbackContext": String
    }
}
```

`clientRequesttoken`  <a name="lambda-hook-change-set-clientrequesttoken"></a>
El token de solicitud que se proporcionó como entrada a la solicitud de Hook. Este campo es obligatorio.

`awsAccountId`  <a name="lambda-hook-change-set-awsaccountid"></a>
El ID del elemento Cuenta de AWS que contiene la pila que se está evaluando.

`stackID`  <a name="lambda-hook-change-set-stackid"></a>
El ID de pila de la CloudFormation pila.

`changeSetId`  <a name="lambda-hook-change-set-changesetid"></a>
El ID del conjunto de cambios que inició la invocación de Hook.

`hookTypeName`  <a name="lambda-hook-change-set-hooktypename"></a>
El nombre del Hook que se está ejecutando.

`hookTypeVersion`  <a name="lambda-hook-change-set-hooktypeversion"></a>
La versión del Hook que se está ejecutando.

`hookModel`  <a name="lambda-hook-change-set-hookmodel"></a>  
`LambdaFunction`  <a name="lambda-hook-change-set-hookmodel-lambdafunction"></a>
El ARN de Lambda actual invocado por el Hook.

`requestData`  <a name="lambda-hook-change-set-requestdata"></a>  
`targetName`  <a name="lambda-hook-change-set-requestdata-targetname"></a>
Este valor será `CHANGE_SET`.  
`targetType`  <a name="lambda-hook-change-set-requestdata-targettype"></a>
Este valor será `CHANGE_SET`.  
`targetLogicalId`  <a name="lambda-hook-change-set-requestdata-targetlogicalid"></a>
El conjunto de cambios ARN..  
`payload`  <a name="lambda-hook-change-set-requestdata-payload"></a>
La URL prefirmada de Amazon S3 que contiene un objeto JSON con la plantilla actual, así como una lista de los cambios introducidos por este conjunto de cambios.

`requestContext`  <a name="lambda-hook-change-set-requestcontext"></a>
Si se vuelve a invocar el Hook, se establecerá este objeto.    
`invocation`  <a name="lambda-hook-change-set-requestcontext-invocation"></a>
El intento actual de ejecutar el Hook.  
`callbackContext`  <a name="lambda-hook-change-set-requestcontext-callbackcontext"></a>
Si el Hook estaba activado `IN_PROGRESS` y `callbackContext` se devolvió, estará aquí al volver a invocarlo.

La `payload` propiedad de los datos de la solicitud es una URL que el código debe recuperar. Una vez que haya recibido la URL, obtendrás un objeto con el siguiente esquema:

```
{
    "template": String,
    "changedResources": [
        {
            "action": String,
            "beforeContext": JSON String,
            "afterContext": JSON String,
            "lineNumber": Integer,
            "logicalResourceId": String,
            "resourceType": String
        }
    ]
}
```

`template`  <a name="lambda-hook-change-set-payload-template"></a>
La CloudFormation plantilla completa que se proporcionó a `create-stack` o`update-stack`. Puede ser una cadena JSON o YAML en función de lo que se haya proporcionado a CloudFormation.

`changedResources`  <a name="lambda-hook-change-set-payload-changed-resources"></a>
Una lista de los recursos modificados.    
`action`  <a name="lambda-hook-change-set-payload-changed-resources-action"></a>
El tipo de cambio aplicado al recurso.  
*Valores válidos*: (`CREATE`\$1 `UPDATE` \$1`DELETE`)  
`beforeContext`  <a name="lambda-hook-change-set-payload-changed-resources-beforecontext"></a>
Una cadena JSON de las propiedades del recurso antes del cambio. Este valor es nulo cuando se crea el recurso. Todos los valores booleanos y numéricos de esta cadena JSON son CADENAS.  
`afterContext`  <a name="lambda-hook-change-set-payload-changed-resources-aftercontext"></a>
Una cadena JSON de las propiedades de los recursos si se ejecuta este conjunto de cambios. Este valor es nulo cuando se elimina el recurso. Todos los valores booleanos y numéricos de esta cadena JSON son CADENAS.  
`lineNumber`  <a name="lambda-hook-change-set-payload-changed-resources-linenumber"></a>
El número de línea de la plantilla que provocó este cambio. Si la acción es, `DELETE` este valor será nulo.   
`logicalResourceId`  <a name="lambda-hook-change-set-payload-changed-resources-logicalresourceid"></a>
El identificador de recurso lógico del recurso que se va a cambiar.  
`resourceType`  <a name="lambda-hook-change-set-payload-changed-resources-resourcetype"></a>
El tipo de recurso que se va a cambiar.

### Ejemplo de entrada de cambio de conjunto de cambios de Lambda Hook
<a name="lambda-hooks-create-lambda-function-change-set-example"></a>

A continuación se muestra un ejemplo de entrada de cambio de conjunto. En el siguiente ejemplo, puede ver los cambios introducidos por el conjunto de cambios. El primer cambio consiste en eliminar una cola llamada`CoolQueue`. El segundo cambio consiste en añadir una nueva cola llamada. `NewCoolQueue` El último cambio es una actualización de`DynamoDBTable`.

```
{
    "clientRequestToken": "f8da6d11-b23f-48f4-814c-0fb6a667f50e",
    "awsAccountId": "123456789012",
    "stackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/MyStack/1a2345b6-0000-00a0-a123-00abc0abc000",
    "changeSetId": "arn:aws:cloudformation:us-west-2:123456789012:changeSet/SampleChangeSet/1a2345b6-0000-00a0-a123-00abc0abc000",
    "hookTypeName": "my::lambda::changesethook",
    "hookTypeVersion": "00000008",
    "hookModel": {
        "LambdaFunction": "arn:aws:lambda:us-west-2:123456789012:function:MyFunction"
    },
    "actionInvocationPoint": "CREATE_PRE_PROVISION",
    "requestData": {
        "targetName": "CHANGE_SET",
        "targetType": "CHANGE_SET",
        "targetLogicalId": "arn:aws:cloudformation:us-west-2:123456789012:changeSet/SampleChangeSet/1a2345b6-0000-00a0-a123-00abc0abc000",
        "payload": "https://s3......"
    },
    "requestContext": {
        "invocation": 1,
        "callbackContext": null
    }
}
```

Este es un ejemplo `payload` de`requestData.payload`:

```
{
  template: 'Resources:\n' +
    '  DynamoDBTable:\n' +
    '    Type: AWS::DynamoDB::Table\n' +
    '    Properties:\n' +
    '      AttributeDefinitions:\n' +
    '        - AttributeName: "PK"\n' +
    '          AttributeType: "S"\n' +
    '      BillingMode: "PAY_PER_REQUEST"\n' +
    '      KeySchema:\n' +
    '        - AttributeName: "PK"\n' +
    '          KeyType: "HASH"\n' +
    '      PointInTimeRecoverySpecification:\n' +
    '        PointInTimeRecoveryEnabled: false\n' +
    '  NewSQSQueue:\n' +
    '    Type: AWS::SQS::Queue\n' +
    '    Properties:\n' +
    '      QueueName: "NewCoolQueue"',
  changedResources: [
    {
      logicalResourceId: 'SQSQueue',
      resourceType: 'AWS::SQS::Queue',
      action: 'DELETE',
      lineNumber: null,
      beforeContext: '{"Properties":{"QueueName":"CoolQueue"}}',
      afterContext: null
    },
    {
      logicalResourceId: 'NewSQSQueue',
      resourceType: 'AWS::SQS::Queue',
      action: 'CREATE',
      lineNumber: 14,
      beforeContext: null,
      afterContext: '{"Properties":{"QueueName":"NewCoolQueue"}}'
    },
    {
      logicalResourceId: 'DynamoDBTable',
      resourceType: 'AWS::DynamoDB::Table',
      action: 'UPDATE',
      lineNumber: 2,
      beforeContext: '{"Properties":{"BillingMode":"PAY_PER_REQUEST","AttributeDefinitions":[{"AttributeType":"S","AttributeName":"PK"}],"KeySchema":[{"KeyType":"HASH","AttributeName":"PK"}]}}',
      afterContext: '{"Properties":{"BillingMode":"PAY_PER_REQUEST","PointInTimeRecoverySpecification":{"PointInTimeRecoveryEnabled":"false"},"AttributeDefinitions":[{"AttributeType":"S","AttributeName":"PK"}],"KeySchema":[{"KeyType":"HASH","AttributeName":"PK"}]}}'
    }
  ]
}
```

### Ejemplo de función Lambda para operaciones de conjuntos de cambios
<a name="lambda-hooks-create-lambda-function-change-set-example-function"></a>

El siguiente ejemplo es una función sencilla que descarga la carga útil de la operación del conjunto de cambios, recorre cada cambio y, a continuación, imprime las propiedades anteriores y posteriores antes de devolver un. `SUCCESS`

------
#### [ Node.js ]

```
export const handler = async (event, context) => {
    var payloadUrl = event?.requestData?.payload;    
    var response = {
        "hookStatus": "SUCCESS",
        "message": "Change set changes are compliant",
        "clientRequestToken": event.clientRequestToken
    };
    try {
        const changeSetHookPayloadRequest = await fetch(payloadUrl);
        const changeSetHookPayload = await changeSetHookPayloadRequest.json();
        const changes = changeSetHookPayload.changedResources || [];
        for(const change of changes) {
            var beforeContext = {};
            var afterContext = {};
            if(change.beforeContext) {
                beforeContext = JSON.parse(change.beforeContext);
            }
            if(change.afterContext) {
                afterContext = JSON.parse(change.afterContext);
            }
            console.log(beforeContext)
            console.log(afterContext)
            // Evaluate Change here
        }
    } catch (error) {
        console.log(error);
        response.hookStatus = "FAILED";
        response.message = "Failed to evaluate change set operation.";
        response.errorCode = "InternalFailure";
    }
    return response;
};
```

------
#### [ Python ]

Para usar Python, tendrás que importar la `requests` biblioteca. Para ello, tendrá que incluir la biblioteca en el paquete de despliegue al crear la función Lambda. *Para obtener más información, consulte [Creación de un paquete de despliegue en formato.zip con dependencias](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-create-dependencies) en la AWS Lambda Guía para desarrolladores.*

```
import json
import requests

def lambda_handler(event, context):
    payload_url = event.get('requestData', {}).get('payload')
    response = {
        "hookStatus": "SUCCESS",
        "message": "Change set changes are compliant",
        "clientRequestToken": event.get('clientRequestToken')
    }

    try:
        change_set_hook_payload_request = requests.get(payload_url)
        change_set_hook_payload_request.raise_for_status()  # Raises an HTTPError for bad responses
        change_set_hook_payload = change_set_hook_payload_request.json()
        
        changes = change_set_hook_payload.get('changedResources', [])
        
        for change in changes:
            before_context = {}
            after_context = {}
            
            if change.get('beforeContext'):
                before_context = json.loads(change['beforeContext'])
            
            if change.get('afterContext'):
                after_context = json.loads(change['afterContext'])
            
            print(before_context)
            print(after_context)
            # Evaluate Change here

    except requests.RequestException as error:
        print(error)
        response['hookStatus'] = "FAILED"
        response['message'] = "Failed to evaluate change set operation."
        response['errorCode'] = "InternalFailure"
    except json.JSONDecodeError as error:
        print(error)
        response['hookStatus'] = "FAILED"
        response['message'] = "Failed to parse JSON payload."
        response['errorCode'] = "InternalFailure"

    return response
```

------