

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Créez des fonctions Lambda pour évaluer les ressources pour les Lambda Hooks
<a name="lambda-hooks-create-lambda-function"></a>

CloudFormation Lambda Hooks vous permet d'évaluer CloudFormation et d'effectuer API de commande du Cloud AWS des opérations par rapport à votre propre code personnalisé. Votre Hook peut bloquer le déroulement d'une opération ou envoyer un avertissement à l'appelant et autoriser le déroulement de l'opération. Lorsque vous créez un Lambda Hook, vous pouvez le configurer pour intercepter et évaluer les opérations suivantes : CloudFormation 
+ Opérations de ressources
+ Opérations de pile
+ Modifier les opérations du set

**Topics**
+ [Développement d'un hook Lambda](#lambda-hooks-create-lambda-function-develop)
+ [Évaluation des opérations sur les ressources avec les Lambda Hooks](#lambda-hooks-create-lambda-function-resource)
+ [Évaluation des opérations de stack avec les Lambda Hooks](#lambda-hooks-create-lambda-function-stack)
+ [Évaluation des opérations relatives aux ensembles de modifications avec les Lambda Hooks](#lambda-hooks-create-lambda-function-change-set)

## Développement d'un hook Lambda
<a name="lambda-hooks-create-lambda-function-develop"></a>

Lorsque les Hooks invoquent votre Lambda, le Lambda attend jusqu'à 30 secondes pour évaluer l'entrée. Le Lambda renverra une réponse JSON indiquant si le Hook a réussi ou échoué.

**Topics**
+ [Demande d'entrée](#lambda-hooks-create-lambda-function-request-input)
+ [Entrée de réponse](#lambda-hooks-create-lambda-function-request-response)
+ [Exemples](#lambda-hooks-create-lambda-function-request-example)

### Demande d'entrée
<a name="lambda-hooks-create-lambda-function-request-input"></a>

L'entrée transmise à votre fonction Lambda dépend de l'opération cible Hook (exemples : stack, resource ou change set). 

### Entrée de réponse
<a name="lambda-hooks-create-lambda-function-request-response"></a>

Afin de communiquer à Hooks si votre demande a réussi ou échoué, votre fonction Lambda doit renvoyer une réponse JSON.

Voici un exemple de forme de la réponse attendue par Hooks :

```
{ 
  "État du crochet": "SUCCESS" or "FAILED" or "IN_PROGRESS", 
  "errorCode": "NonCompliant" or "InternalFailure"
  "message": String, 
  "clientRequestToken": String,
  "Contexte de rappel": 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"
    }
  ]
}
```

État du crochet  <a name="lambda-hook-response-hookstatus"></a>
L'état du Hook. Ce champ est obligatoire.  
*Valeurs valides* : (`SUCCESS`\$1 `FAILED` \$1`IN_PROGRESS`)  
Un Hook peut revenir `IN_PROGRESS` 3 fois. Si aucun résultat n'est renvoyé, le Hook échouera. Pour un Lambda Hook, cela signifie que votre fonction Lambda peut être invoquée jusqu'à 3 fois.

errorCode  <a name="lambda-hook-response-errorcode"></a>
Indique si l'opération a été évaluée et jugée non valide, ou si des erreurs se sont produites dans le Hook, empêchant l'évaluation. Ce champ est obligatoire en cas d'échec du Hook.  
*Valeurs valides* : (`NonCompliant`\$1`InternalFailure`)

message  <a name="lambda-hook-response-message"></a>
Le message envoyé à l'appelant expliquant pourquoi le Hook a réussi ou échoué.  
Lors de l'évaluation CloudFormation des opérations, ce champ est tronqué à 4 096 caractères.  
Lors de l'évaluation des opérations de l'API Cloud Control, ce champ est tronqué à 1024 caractères.

clientRequestToken  <a name="lambda-hook-response-clientrequesttoken"></a>
Le jeton de demande qui a été fourni en entrée de la demande Hook. Ce champ est obligatoire.

Contexte de rappel  <a name="lambda-hook-response-callbackcontext"></a>
Si vous indiquez que `hookStatus` c'est le cas, `IN_PROGRESS` vous transmettez un contexte supplémentaire fourni en entrée lorsque la fonction Lambda est réinvoquée.

callbackDelaySeconds  <a name="lambda-hook-response-callbackdelayseconds"></a>
Combien de temps les Hooks doivent-ils attendre pour invoquer à nouveau ce Hook ?

annotations  <a name="lambda-hook-response-annotations"></a>
Un ensemble d'objets d'annotation qui fournissent des informations supplémentaires et des conseils de correction.     
Nom de l'annotation  
Identifiant de l'annotation.  
status  
Le statut d'invocation de Hook. Cela est utile lorsque les annotations représentent une logique avec une évaluation de réussite ou d'échec similaire à une règle Guard.   
*Valeurs valides* : (`PASSED`\$1 `FAILED` \$1`SKIPPED`)  
statusMessage  
Explication du statut spécifique.  
Message de correction  
Suggestion pour fixer un `FAILED` statut. Par exemple, si le chiffrement d'une ressource n'est pas chiffré, vous pouvez indiquer comment ajouter le chiffrement à la configuration de la ressource.  
Lien vers l'assainissement  
Une URL HTTP pour des conseils de correction supplémentaires.  
severityLevel  
Définit le risque relatif associé à toute violation de ce type. Lorsque vous attribuez des niveaux de gravité aux résultats de votre appel Hook, vous pouvez vous référer au [cadre de AWS Security Hub CSPM gravité](https://docs.aws.amazon.com/securityhub/latest/userguide/asff-required-attributes.html#Severity) comme exemple de la manière de structurer des catégories de gravité significatives.   
*Valeurs valides* : (`INFORMATIONAL`\$1 `LOW` \$1 `MEDIUM` \$1 `HIGH` \$1`CRITICAL`)

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

Voici un exemple de réponse réussie :

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

Voici un exemple d'échec de réponse :

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

## Évaluation des opérations sur les ressources avec les Lambda Hooks
<a name="lambda-hooks-create-lambda-function-resource"></a>

Chaque fois que vous créez, mettez à jour ou supprimez une ressource, cela est considéré comme une opération de ressource. Par exemple, si vous exécutez la mise à jour d'une CloudFormation pile qui crée une nouvelle ressource, vous avez terminé une opération sur la ressource. Lorsque vous créez, mettez à jour ou supprimez une ressource à l'aide de l'API Cloud Control, cela est également considéré comme une opération de ressource. Vous pouvez configurer votre CloudFormation Lambda Hook en fonction du ciblage `RESOURCE` et `CLOUD_CONTROL` des opérations dans la configuration du Hook`TargetOperations`.

**Note**  
Le gestionnaire `delete` Hook n'est invoqué que lorsqu'une ressource est supprimée à l'aide d'un déclencheur d'opération de l'API Cloud Control `delete-resource` ou CloudFormation `delete-stack`.

**Topics**
+ [Syntaxe d'entrée des ressources Lambda Hook](#lambda-hooks-create-lambda-function-resource-input)
+ [Exemple d'entrée de modification de ressource Lambda Hook](#lambda-hooks-create-lambda-function-resource-example)
+ [Exemple de fonction Lambda pour les opérations sur les ressources](#lambda-hooks-create-lambda-function-resource-example-function)

### Syntaxe d'entrée des ressources Lambda Hook
<a name="lambda-hooks-create-lambda-function-resource-input"></a>

Lorsque votre Lambda est invoqué pour une opération sur une ressource, vous recevez une entrée JSON contenant les propriétés de la ressource, les propriétés proposées et le contexte de l'invocation de Hook.

Voici un exemple de forme de l'entrée 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": {
        "invocation": 1,
        "Contexte de rappel": null
    }
}
```

`awsAccountId`  <a name="lambda-hook-resource-awsaccountid"></a>
ID du Compte AWS contenant la ressource en cours d'évaluation.

`stackId`  <a name="lambda-hook-resource-stackid"></a>
L'ID de pile de la CloudFormation pile dont cette opération fait partie. Ce champ est vide si l'appelant est Cloud Control API.

`changeSetId`  <a name="lambda-hook-resource-changesetid"></a>
L'ID de l'ensemble de modifications qui a initié l'invocation de Hook. Cette valeur est vide si le changement de ressource a été initié par l'API Cloud Control ou par les `delete-stack` opérations `create-stack``update-stack`, ou.

`hookTypeName`  <a name="lambda-hook-resource-hooktypename"></a>
Le nom du Hook en cours d'exécution.

`hookTypeVersion`  <a name="lambda-hook-resource-hooktypeversion"></a>
Version du Hook en cours d'exécution.

`hookModel`  <a name="lambda-hook-resource-hookmodel"></a>  
`LambdaFunction`  <a name="lambda-hook-resource-hookmodel-lambdafunction"></a>
L'ARN Lambda actuel invoqué par le Hook.

`actionInvocationPoint`  <a name="lambda-hook-resource-actioninvocationpoint"></a>
Point exact de la logique de provisionnement où le Hook s'exécute.  
*Valeurs valides* : (`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>
Le type de cible évalué, par exemple,`AWS::S3::Bucket`.  
`targetType`  <a name="lambda-hook-resource-requestdata-targettype"></a>
Le type de cible évalué, par exemple`AWS::S3::Bucket`. Pour les ressources fournies avec l'API Cloud Control, cette valeur sera`RESOURCE`.  
`targetLogicalId`  <a name="lambda-hook-resource-requestdata-targetlogicalid"></a>
ID logique de la ressource en cours d'évaluation. Si l'origine de l'invocation de Hook est CloudFormation, il s'agira de l'ID de ressource logique défini dans votre CloudFormation modèle. Si l'origine de cette invocation de Hook est l'API Cloud Control, il s'agira d'une valeur construite.  
`targetModel`  <a name="lambda-hook-resource-requestdata-targetmodel"></a>  
`resourceProperties`  <a name="lambda-hook-resource-requestdata-targetmodel-resourceproperties"></a>
Les propriétés proposées pour la ressource en cours de modification. Si la ressource est supprimée, cette valeur sera vide.   
`previousResourceProperties`  <a name="lambda-hook-resource-requestdata-targetmodel-previousresourceproperties"></a>
Les propriétés actuellement associées à la ressource en cours de modification. Si la ressource est créée, cette valeur sera vide.

`requestContext`  <a name="lambda-hook-resource-requestcontext"></a>  
invocation  <a name="lambda-hook-resource-requestcontext-invocation"></a>
La tentative actuelle d'exécution du Hook.   
Contexte de rappel  <a name="lambda-hook-resource-requestcontext-callbackcontext"></a>
Si le Hook a été réglé sur `IN_PROGRESS` et `callbackContext` a été renvoyé, il sera là après sa révocation.

### Exemple d'entrée de modification de ressource Lambda Hook
<a name="lambda-hooks-create-lambda-function-resource-example"></a>

L'exemple d'entrée suivant montre un Lambda Hook qui recevra la définition de la `AWS::DynamoDB::Table` ressource à mettre à jour, le nombre `ReadCapacityUnits` de `ProvisionedThroughput` passant de 3 à 10. Il s'agit des données dont Lambda dispose pour évaluation.

```
{
    "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
    }    
}
```

Pour voir toutes les propriétés disponibles pour le type de ressource, consultez [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).

### Exemple de fonction Lambda pour les opérations sur les ressources
<a name="lambda-hooks-create-lambda-function-resource-example-function"></a>

Voici une fonction simple qui échoue à toute mise à jour des ressources vers DynamoDB, qui essaie de définir une valeur supérieure à 10 à `ReadCapacity` la valeur `ProvisionedThroughput` de. Si le Hook réussit, le message « ReadCapacity  est correctement configuré » s'affichera pour l'appelant. Si la demande échoue à la validation, le Hook échouera avec le statut « ReadCapacity  ne peut pas être supérieur à 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
```

------

## Évaluation des opérations de stack avec les Lambda Hooks
<a name="lambda-hooks-create-lambda-function-stack"></a>

Chaque fois que vous créez, mettez à jour ou supprimez une pile avec un nouveau modèle, vous pouvez configurer votre CloudFormation Lambda Hook pour commencer par évaluer le nouveau modèle et éventuellement bloquer le déroulement de l'opération de pile. Vous pouvez configurer votre CloudFormation Lambda Hook pour cibler les `STACK` opérations dans la configuration Hook`TargetOperations`.

**Topics**
+ [Syntaxe d'entrée Lambda Hook Stack](#lambda-hooks-create-lambda-function-stack-input)
+ [Exemple d'entrée de modification de la pile Lambda Hook](#lambda-hooks-create-lambda-function-stack-example)
+ [Exemple de fonction Lambda pour les opérations de stack](#lambda-hooks-create-lambda-function-stack-example-function)

### Syntaxe d'entrée Lambda Hook Stack
<a name="lambda-hooks-create-lambda-function-stack-input"></a>

Lorsque votre Lambda est invoqué pour une opération de stack, vous recevez une requête JSON contenant le contexte d'invocation Hook et le contexte de la demande. `actionInvocationPoint` En raison de la taille des CloudFormation modèles et de la taille d'entrée limitée acceptée par les fonctions Lambda, les modèles réels sont stockés dans un objet Amazon S3. La saisie `requestData` inclut une URL abandonnée d'Amazon S3 vers un autre objet, qui contient la version actuelle et précédente du modèle.

Voici un exemple de forme de l'entrée 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>
Le jeton de demande qui a été fourni en entrée de la demande Hook. Ce champ est obligatoire.

`awsAccountId`  <a name="lambda-hook-stack-awsaccountid"></a>
ID du Compte AWS contenant la pile en cours d'évaluation.

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

`changeSetId`  <a name="lambda-hook-stack-changesetid"></a>
L'ID de l'ensemble de modifications qui a initié l'invocation de Hook. Cette valeur est vide si le changement de pile a été initié par l'API Cloud Control ou par les `delete-stack` opérations `create-stack``update-stack`, ou.

`hookTypeName`  <a name="lambda-hook-stack-hooktypename"></a>
Le nom du Hook en cours d'exécution.

`hookTypeVersion`  <a name="lambda-hook-stack-hooktypeversion"></a>
Version du Hook en cours d'exécution.

`hookModel`  <a name="lambda-hook-stack-hookmodel"></a>  
`LambdaFunction`  <a name="lambda-hook-stack-hookmodel-lambdafunction"></a>
L'ARN Lambda actuel invoqué par le Hook.

`actionInvocationPoint`  <a name="lambda-hook-stack-actioninvocationpoint"></a>
Point exact de la logique de provisionnement où le Hook s'exécute.  
*Valeurs valides* : (`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>
Cette valeur sera`STACK`.  
`targetType`  <a name="lambda-hook-stack-requestdata-targettype"></a>
Cette valeur sera`STACK`.  
`targetLogicalId`  <a name="lambda-hook-stack-requestdata-targetlogicalid"></a>
Nom de la pile.  
`payload`  <a name="lambda-hook-stack-requestdata-payload"></a>
URL présignée Amazon S3 contenant un objet JSON avec les définitions de modèles actuelles et précédentes.

`requestContext`  <a name="lambda-hook-stack-requestcontext"></a>
Si le Hook est réinvoqué, cet objet sera défini.    
`invocation`  <a name="lambda-hook-stack-requestcontext-invocation"></a>
La tentative actuelle d'exécution du Hook.  
`callbackContext`  <a name="lambda-hook-stack-requestcontext-callbackcontext"></a>
Si le Hook a été réglé sur `IN_PROGRESS` et `callbackContext` a été renvoyé, il sera présent lors de sa révocation.

La `payload` propriété contenue dans les données de demande est une URL que votre code doit récupérer. Une fois qu'il a reçu l'URL, vous obtenez un objet avec le schéma suivant :

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

`template`  <a name="lambda-hook-stack-payload-template"></a>
Le CloudFormation modèle complet qui a été fourni à `create-stack` ou`update-stack`. Il peut s'agir d'une chaîne JSON ou YAML en fonction de ce qui a été fourni. CloudFormation  
Dans `delete-stack` les opérations, cette valeur sera vide.

`previousTemplate`  <a name="lambda-hook-stack-payload-previoustemplate"></a>
Le CloudFormation modèle précédent. Il peut s'agir d'une chaîne JSON ou YAML en fonction de ce qui a été fourni. CloudFormation  
Dans `delete-stack` les opérations, cette valeur sera vide.

### Exemple d'entrée de modification de la pile Lambda Hook
<a name="lambda-hooks-create-lambda-function-stack-example"></a>

Voici un exemple d'entrée de changement de pile. The Hook évalue une modification qui met le à jour `ObjectLockEnabled` à true et ajoute une file d'attente 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
    }
}
```

Voici un exemple `payload` de `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}}}}"
}
```

### Exemple de fonction Lambda pour les opérations de stack
<a name="lambda-hooks-create-lambda-function-stack-example-function"></a>

L'exemple suivant est une fonction simple qui télécharge la charge utile de l'opération de pile, analyse le modèle JSON et le renvoie. `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 ]

Pour utiliser Python, vous devez importer la `requests` bibliothèque. Pour ce faire, vous devez inclure la bibliothèque dans votre package de déploiement lors de la création de votre fonction Lambda. Pour plus d'informations, consultez la section [Création d'un package de déploiement .zip avec dépendances](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-create-dependencies) dans le *Guide du AWS Lambda développeur*.

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

------

## Évaluation des opérations relatives aux ensembles de modifications avec les Lambda Hooks
<a name="lambda-hooks-create-lambda-function-change-set"></a>

Chaque fois que vous créez un ensemble de modifications, vous pouvez configurer votre CloudFormation Lambda Hook pour d'abord évaluer le nouvel ensemble de modifications et éventuellement bloquer son exécution. Vous pouvez configurer votre CloudFormation Lambda Hook pour cibler les `CHANGE_SET` opérations dans la configuration Hook`TargetOperations`.

**Topics**
+ [Lambda Hook modifie la syntaxe d'entrée du set](#lambda-hooks-create-lambda-function-change-set-input)
+ [Exemple : Lambda Hook change Set, change d'entrée](#lambda-hooks-create-lambda-function-change-set-example)
+ [Exemple de fonction Lambda pour les opérations d'ensemble de modifications](#lambda-hooks-create-lambda-function-change-set-example-function)

### Lambda Hook modifie la syntaxe d'entrée du set
<a name="lambda-hooks-create-lambda-function-change-set-input"></a>

L'entrée pour les opérations d'ensemble de modifications est similaire à celle des opérations de pile, mais la charge utile des opérations inclut `requestData` également une liste des modifications de ressources introduites par l'ensemble de modifications.

Voici un exemple de forme de l'entrée 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>
Le jeton de demande qui a été fourni en entrée de la demande Hook. Ce champ est obligatoire.

`awsAccountId`  <a name="lambda-hook-change-set-awsaccountid"></a>
ID du Compte AWS contenant la pile en cours d'évaluation.

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

`changeSetId`  <a name="lambda-hook-change-set-changesetid"></a>
L'ID de l'ensemble de modifications qui a initié l'invocation de Hook.

`hookTypeName`  <a name="lambda-hook-change-set-hooktypename"></a>
Le nom du Hook en cours d'exécution.

`hookTypeVersion`  <a name="lambda-hook-change-set-hooktypeversion"></a>
Version du Hook en cours d'exécution.

`hookModel`  <a name="lambda-hook-change-set-hookmodel"></a>  
`LambdaFunction`  <a name="lambda-hook-change-set-hookmodel-lambdafunction"></a>
L'ARN Lambda actuel invoqué par le Hook.

`requestData`  <a name="lambda-hook-change-set-requestdata"></a>  
`targetName`  <a name="lambda-hook-change-set-requestdata-targetname"></a>
Cette valeur sera`CHANGE_SET`.  
`targetType`  <a name="lambda-hook-change-set-requestdata-targettype"></a>
Cette valeur sera`CHANGE_SET`.  
`targetLogicalId`  <a name="lambda-hook-change-set-requestdata-targetlogicalid"></a>
La modification a défini l'ARN.  
`payload`  <a name="lambda-hook-change-set-requestdata-payload"></a>
L'URL présignée Amazon S3 contenant un objet JSON avec le modèle actuel, ainsi qu'une liste des modifications apportées par cet ensemble de modifications.

`requestContext`  <a name="lambda-hook-change-set-requestcontext"></a>
Si le Hook est réinvoqué, cet objet sera défini.    
`invocation`  <a name="lambda-hook-change-set-requestcontext-invocation"></a>
La tentative actuelle d'exécution du Hook.  
`callbackContext`  <a name="lambda-hook-change-set-requestcontext-callbackcontext"></a>
Si le Hook a été réglé sur `IN_PROGRESS` et `callbackContext` a été renvoyé, il sera présent lors de sa révocation.

La `payload` propriété contenue dans les données de demande est une URL que votre code doit récupérer. Une fois qu'il a reçu l'URL, vous obtenez un objet avec le schéma suivant :

```
{
    "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>
Le CloudFormation modèle complet qui a été fourni à `create-stack` ou`update-stack`. Il peut s'agir d'une chaîne JSON ou YAML en fonction de ce qui a été fourni. CloudFormation

`changedResources`  <a name="lambda-hook-change-set-payload-changed-resources"></a>
Liste des ressources modifiées.    
`action`  <a name="lambda-hook-change-set-payload-changed-resources-action"></a>
Type de modification appliqué à la ressource.  
*Valeurs valides* : (`CREATE`\$1 `UPDATE` \$1`DELETE`)  
`beforeContext`  <a name="lambda-hook-change-set-payload-changed-resources-beforecontext"></a>
Chaîne JSON contenant les propriétés de la ressource avant la modification. Cette valeur est nulle lors de la création de la ressource. Toutes les valeurs booléennes et numériques de cette chaîne JSON sont des CHAÎNES.  
`afterContext`  <a name="lambda-hook-change-set-payload-changed-resources-aftercontext"></a>
Une chaîne JSON contenant les propriétés des ressources si cet ensemble de modifications est exécuté. Cette valeur est nulle lorsque la ressource est supprimée. Toutes les valeurs booléennes et numériques de cette chaîne JSON sont des CHAÎNES.  
`lineNumber`  <a name="lambda-hook-change-set-payload-changed-resources-linenumber"></a>
Numéro de ligne du modèle à l'origine de cette modification. Si c'est le cas, `DELETE` cette valeur sera nulle.   
`logicalResourceId`  <a name="lambda-hook-change-set-payload-changed-resources-logicalresourceid"></a>
ID de ressource logique de la ressource en cours de modification.  
`resourceType`  <a name="lambda-hook-change-set-payload-changed-resources-resourcetype"></a>
Type de ressource en cours de modification.

### Exemple : Lambda Hook change Set, change d'entrée
<a name="lambda-hooks-create-lambda-function-change-set-example"></a>

Voici un exemple d'entrée de modification d'ensemble de modifications. Dans l'exemple suivant, vous pouvez voir les modifications introduites par l'ensemble de modifications. La première modification consiste à supprimer une file d'attente appelée`CoolQueue`. La deuxième modification consiste à ajouter une nouvelle file d'attente appelée`NewCoolQueue`. La dernière modification est une mise à jour du`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
    }
}
```

Voici un exemple `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"}]}}'
    }
  ]
}
```

### Exemple de fonction Lambda pour les opérations d'ensemble de modifications
<a name="lambda-hooks-create-lambda-function-change-set-example-function"></a>

L'exemple suivant est une fonction simple qui télécharge la charge utile de l'opération d'ensemble de modifications, passe en revue chaque modification, puis imprime les propriétés avant et après avant de renvoyer 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 ]

Pour utiliser Python, vous devez importer la `requests` bibliothèque. Pour ce faire, vous devez inclure la bibliothèque dans votre package de déploiement lors de la création de votre fonction Lambda. Pour plus d'informations, consultez la section [Création d'un package de déploiement .zip avec dépendances](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-create-dependencies) dans le *Guide du AWS Lambda développeur*.

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

------