Exemple de macro : Création et utilisation d'une macro - AWS CloudFormation

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 : Création et utilisation d'une macro

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é.

Exemple de macro : Modèle de définition de macro

Avant d'utiliser une macro, nous devons d'abord effectuer deux opérations : 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.

Note

Nous examinerons le code de la fonction Lambda plus loin dans cette rubrique.

L'exemple de modèle suivant contient la définition de notre exemple de macro. Pour rendre la macro disponible dans un CloudFormation compte spécifique, nous créons 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 à ARN la fonction Lambda qui est appelée CloudFormation lorsque cette macro est utilisée dans un modèle. (Nous n'avons pas inclus de LogRoleARNpropriété LogGroupNameor pour la journalisation des erreurs.) Pour plus d'informations, consultez AWS: : CloudFormation : :Macro.

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

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'

Exemple de macro : Modèle d'utilisation de macro

Pour utiliser notre macro dans ce cas, nous allons l'inclure 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 vide AWS: CloudFormation : : : WaitConditionHandle est inséré dans le modèle traité.

Notez ce qui suit :

  • La macro à invoquer est spécifiée comme telle JavaMacroFunc, comme indiqué dans 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 résultat AWS: CloudFormation : : WaitConditionHandle 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).

Parameters: ExampleParameter: Type: String Default: 'SampleMacro' Resources: 2a: Fn::Transform: Name: "JavaMacroFunc" Parameters: replacement: 'AWS::CloudFormation::WaitConditionHandle' target: '$$REPLACEMENT$$' Type: '$$REPLACEMENT$$'

Exemple de macro : Demander un mappage d'événement

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 JavaMacroFuncmacro.

fragmentcontient JSON 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. paramsContient également la JSON représentation des paramètres de la macro. Dans ce cas, replacement et target. De même, templateParameterValues contient des éléments JSON représentant les paramètres spécifiés pour le modèle dans son ensemble.

  • 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" }

Exemple de macro : Code de la fonction Lambda

Voici le code réel de la fonction Lambda sous-jacente à l'JavaMacroFuncexemple de macro. 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; } }

Exemple de macro : Réponse de la fonction Lambda

Voici le mappage auquel la fonction Lambda retourne CloudFormation pour être traitée. 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 JSON contenu à insérer dans le modèle traité à la place de l'extrait de modèle d'origine.

  • requestId

    5dba79b5-f117-4de0-9ce4-d40363bfb6ab

  • status

    SUCCESS

  • fragment

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

Exemple de macro : Modèle traité obtenu

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 Fn::Transform intrinsèque qui faisait référence à la JavaMacroFuncmacro 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" } } }

Exemples supplémentaires de macros

Outre cette procédure pas à pas dans ce guide, vous trouverez des exemples de macros, notamment du code source et des modèles, dans notre GitHub référentiel. Ces exemples sont fournis « en l'état » à des fins éducatives.