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
L'exemple suivant explique le processus d'utilisation des macros, de la définition de la macro dans un modèle à la création d'une fonction Lambda pour la macro, puis à l'utilisation de la macro dans un modèle.
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
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 à 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 LogRoleARN
propriété LogGroupName
or pour la journalisation des erreurs.)
Dans cet exemple, supposons que la pile créée à partir de ce modèle est nomméeJavaMacroFunc
. Comme la Name
propriété de la macro est définie sur le nom de la pile, la macro résultante est également JavaMacroFunc
nommé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'
Utilisation de la macro
Pour utiliser notre macro, nous l'incluons dans un modèle à l'aide de la fonction Fn::Transform
intrinsèque.
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 telle
JavaMacroFunc
, comme indiqué dans l'exemple de définition de macro précédent. -
Deux paramètres sont transmis à cette macro,
target
etreplacement
, 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
, carType
est un frère de la fonctionFn::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
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 JSON un élément 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. params
Contient é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.
Code de fonction Lambda
Voici le code réel de la fonction Lambda sous-jacente à l'JavaMacroFunc
exemple 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; } }
Réponse de la fonction Lambda
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 JSON contenu à insérer dans le modèle traité à la place de l'extrait de modèle d'origine.
Modèle traité résultant
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 JavaMacroFunc
macro 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" } } }