

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.

# Exemple de macro de remplacement de chaîne simple
<a name="macros-example"></a>

L’exemple suivant passe en revue le processus d’utilisation des macros, de la définition de la macro dans un modèle jusqu’à l’utilisation de la macro dans un modèle, en passant par la création d’une fonction Lambda pour la macro.

Dans cet exemple, nous créons une macro simple qui insère la chaîne spécifiée à la place du contenu cible spécifié dans le modèle traité. Ensuite, nous l'utiliserons pour insérer un champ `WaitHandleCondition` vide dans l'emplacement spécifié dans le modèle traité.

## Création d’une macro
<a name="macros-example-definiton"></a>

Avant d'utiliser une macro, nous devons d'abord effectuer deux tâches : créer la fonction Lambda qui exécute le traitement du modèle souhaité, puis rendre cette fonction Lambda accessible CloudFormation en créant une définition de macro.

L'exemple de modèle suivant contient la définition de notre exemple de macro. Pour rendre la macro disponible dans un format spécifique Compte AWS, créez une pile à partir du modèle. La définition de macro spécifie le nom de la macro, une brève description et fait référence à l'ARN de la fonction Lambda qui CloudFormation appelle lorsque cette macro est utilisée dans un modèle. (Nous n’avons pas inclus de propriété `LogGroupName` ou `LogRoleARN` pour la journalisation des erreurs.) 

Dans cet exemple, supposons que la pile créée à partir de ce modèle soit nommée `JavaMacroFunc`. Comme la propriété macro `Name` est définie sur le nom de la pile, la macro résultante est également nommée `JavaMacroFunc`.

```
AWSTemplateFormatVersion: 2010-09-09
  Resources:
    Macro:
      Type: AWS::CloudFormation::Macro
      Properties:
        Name: !Sub '${AWS::StackName}'
        Description: Adds a blank WaitConditionHandle named WaitHandle
        FunctionName: 'arn:aws:lambda:us-east-1:012345678910:function:JavaMacroFunc'
```

## Utilisation de la macro
<a name="macros-example-usage"></a>

Pour utiliser notre macro, nous l’intégrons dans un modèle à l’aide de la fonction intrinsèque `Fn::Transform`.

Lorsque nous créons une pile à l'aide du modèle ci-dessous, CloudFormation appelle notre exemple de macro. La fonction Lambda sous-jacente remplace une chaîne spécifiée par une autre chaîne spécifiée. Dans ce cas, le résultat est qu'un champ `AWS::CloudFormation::WaitConditionHandle` vide est inséré dans le modèle traité.

```
Parameters:
  ExampleParameter:
    Type: String
    Default: 'SampleMacro'

Resources:
  2a:
    Fn::Transform:
      Name: "JavaMacroFunc"
      Parameters:
        replacement: 'AWS::CloudFormation::WaitConditionHandle'
        target: '$$REPLACEMENT$$'
    Type: '$$REPLACEMENT$$'
```
+ La macro à invoquer est spécifiée comme `JavaMacroFunc`, qui provient de l’exemple de définition de macro précédent.
+ Deux paramètres sont transmis à cette macro, `target` et `replacement`, qui représentent la chaîne cible et sa valeur de remplacement souhaitée.
+ La macro peut fonctionner sur le contenu du nœud `Type`, car `Type` est un frère de la fonction `Fn::Transform` référençant la macro.
+ Le champ `AWS::CloudFormation::WaitConditionHandle` obtenu est nommé `2a`.
+ Le modèle contient également un paramètre de modèle, `ExampleParameter`, auquel la macro a également accès (mais n'utilise pas dans ce cas).

## Données d’entrée Lambda
<a name="macros-example-request"></a>

Lors du CloudFormation traitement de notre exemple de modèle lors de la création de la pile, il transmet le mappage d'événements suivant à la fonction Lambda référencée dans la définition de la `JavaMacroFunc` macro.
+ `region` : `us-east-1`
+ `accountId` : `012345678910`
+ `fragment` :

  ```
  {
    "Type": "$$REPLACEMENT$$"
  }
  ```
+ `transformId` : `012345678910::JavaMacroFunc`
+ `params` : 

  ```
  {
      "replacement": "AWS::CloudFormation::WaitConditionHandle",
      "target": "$$REPLACEMENT$$"
  }
  ```
+ `requestId` : `5dba79b5-f117-4de0-9ce4-d40363bfb6ab`
+ `templateParameterValues` :

  ```
  {
      "ExampleParameter": "SampleMacro"
  }
  ```

`fragment` contient du code JSON représentant le fragment de modèle que la macro peut traiter. Ce fragment comprend les frères de l'appel de fonction `Fn::Transform`, mais pas l'appel de fonction lui-même. En outre, `params` contient le code JSON représentant les paramètres de macro. Dans ce cas, replacement et target. De la même façon, `templateParameterValues` contient du code JSON représentant les paramètres spécifiés pour le modèle dans sa totalité.

## Code de la fonction Lambda
<a name="macros-example-function"></a>

Voici le code réel de la fonction Lambda sous-jacente à la macro d’exemple `JavaMacroFunc`. La fonction parcourt le fragment de modèle inclus dans la réponse (qu'elle soit dans un format de chaîne, de liste ou de mappage), à la recherche de la chaîne cible spécifiée. Si elle trouve la chaîne cible spécifiée, la fonction Lambda remplace la chaîne cible par la chaîne de remplacement spécifiée. Sinon, la fonction laisse le fragment de modèle inchangé. La fonction renvoie ensuite une carte des propriétés attendues, décrites en détail ci-dessous, à CloudFormation.

```
package com.macroexample.lambda.demo;

import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class LambdaFunctionHandler implements RequestHandler<Map<String, Object>, Map<String, Object>> {

	private static final String REPLACEMENT = "replacement";
	private static final String TARGET = "target";
	private static final String PARAMS = "params";
	private static final String FRAGMENT = "fragment";
	private static final String REQUESTID = "requestId";
	private static final String STATUS = "status";
	private static final String SUCCESS = "SUCCESS";
	private static final String FAILURE = "FAILURE";
    @Override
    public Map<String, Object> handleRequest(Map<String, Object> event, Context context) {
        // TODO: implement your handler
    	final Map<String, Object> responseMap = new HashMap<String, Object>();
        responseMap.put(REQUESTID, event.get(REQUESTID));
        responseMap.put(STATUS, FAILURE);
    	try {
	        if (!event.containsKey(PARAMS)) {
	        	throw new RuntimeException("Params are required");
	        }
	    	
	        final Map<String, Object> params = (Map<String, Object>) event.get(PARAMS);
	        if (!params.containsKey(REPLACEMENT) || !params.containsKey(TARGET)) {
	        	throw new RuntimeException("replacement or target under Params are required");
	        }
	    	
	    	final String replacement = (String) params.get(REPLACEMENT);
	    	final String target = (String) params.get(TARGET);
	    	final Object fragment = event.getOrDefault(FRAGMENT, new HashMap<String, Object>());
	    	final Object retFragment;
	    	if (fragment instanceof String) {
	    		retFragment = iterateAndReplace(replacement, target, (String) fragment);
	    	} else if (fragment instanceof List) {
	    		retFragment = iterateAndReplace(replacement, target, (List<Object>) fragment);
	    	} else if (fragment instanceof Map) {
	    		retFragment = iterateAndReplace(replacement, target, (Map<String, Object>) fragment);
	    	} else {
	    		retFragment = fragment;
	    	}
	        responseMap.put(STATUS, SUCCESS);
	        responseMap.put(FRAGMENT, retFragment);
	        return responseMap;
    	} catch (Exception e) {
    		e.printStackTrace();
    		context.getLogger().log(e.getMessage());
    		return responseMap;
    	}
    }
    
    private Map<String, Object> iterateAndReplace(final String replacement, final String target, final Map<String, Object> fragment) {
    	final Map<String, Object> retFragment = new HashMap<String, Object>();
    	final List<String> replacementKeys = new ArrayList<>();
    	fragment.forEach((k, v) -> {
    		if (v instanceof String) {
    			retFragment.put(k, iterateAndReplace(replacement, target, (String)v));
    		} else if (v instanceof List) {
    			retFragment.put(k, iterateAndReplace(replacement, target, (List<Object>)v));
    		} else if (v instanceof Map ) {
    			retFragment.put(k, iterateAndReplace(replacement, target, (Map<String, Object>) v));
    		} else {
    			retFragment.put(k, v);
    		}
    	});
    	return retFragment;
    }

    private List<Object> iterateAndReplace(final String replacement, final String target, final List<Object> fragment) {
    	final List<Object> retFragment = new ArrayList<>();
    	fragment.forEach(o -> {
    		if (o instanceof String) {
    			retFragment.add(iterateAndReplace(replacement, target, (String) o));
    		} else if (o instanceof List) {
    			retFragment.add(iterateAndReplace(replacement, target, (List<Object>) o));
    		} else if (o instanceof Map) {
    			retFragment.add(iterateAndReplace(replacement, target, (Map<String, Object>) o));
    		} else {
    			retFragment.add(o);
    		}
    	});
    	return retFragment;
    }
    
    private String iterateAndReplace(final String replacement, final String target, final String fragment) {
    	System.out.println(replacement + " == " + target + " == " + fragment );
    	if (fragment != null AND_AND fragment.equals(target))
    		return replacement;
    	return fragment;
    }
}
```

## Réponse de la fonction Lambda
<a name="macros-example-response"></a>

Voici le mappage auquel la fonction Lambda retourne CloudFormation pour être traitée. 
+ `requestId` : `5dba79b5-f117-4de0-9ce4-d40363bfb6ab`
+ `status` : `SUCCESS`
+ `fragment` :

  ```
  {
    "Type": "AWS::CloudFormation::WaitConditionHandle"
  }
  ```

Les `requestId` correspondances envoyées depuis CloudFormation et une `status` valeur de `SUCCESS` indiquent que la fonction Lambda a traité avec succès le fragment de modèle inclus dans la demande. Dans cette réponse, `fragment` contient le code JSON représentant le contenu à insérer dans le modèle traité à la place de l'extrait de modèle d'origine.

## Modèle traité obtenu
<a name="macros-example-processed"></a>

Après avoir CloudFormation reçu une réponse positive de la part de la fonction Lambda, elle insère le fragment de modèle renvoyé dans le modèle traité.

Vous trouverez ci-dessous le modèle traité obtenu pour notre exemple. L’appel de fonction intrinsèque `Fn::Transform` qui faisait référence à la macro `JavaMacroFunc` n’est plus inclus. Le fragment de modèle renvoyé par la fonction Lambda est inclus dans l'emplacement approprié, de sorte que le contenu `"Type": "$$REPLACEMENT$$"` a été remplacé par `"Type": "AWS::CloudFormation::WaitConditionHandle"`.

```
{
    "Parameters": {
        "ExampleParameter": {
            "Default": "SampleMacro",
            "Type": "String"
        }
    },
    "Resources": {
        "2a": {
            "Type": "AWS::CloudFormation::WaitConditionHandle"
        }
    }
}
```