Esempio di semplice macro di sostituzione di stringhe - AWS CloudFormation

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Esempio di semplice macro di sostituzione di stringhe

L'esempio seguente illustra il processo di utilizzo delle macro, dalla definizione della macro in un modello, alla creazione di una funzione Lambda per la macro e quindi all'utilizzo della macro in un modello.

In questo esempio, creeremo una macro semplice che inserisce la stringa specificata al posto del contenuto di destinazione specificato nel modello elaborato. Quindi la utilizzeremo per inserire un campo WaitHandleCondition vuoto nella posizione specificata nel modello elaborato.

Creazione di una macro

Prima di utilizzare una macro, dobbiamo prima completare due operazioni: creare la funzione Lambda che esegue l'elaborazione del modello desiderata e quindi rendere disponibile tale funzione CloudFormation Lambda creando una definizione di macro.

L'esempio di modello seguente contiene la definizione del nostro esempio di macro. Per rendere disponibile la macro in uno specifico Account AWS, create uno stack dal modello. La definizione della macro specifica il nome della macro, una breve descrizione e fa riferimento alla ARN funzione Lambda CloudFormation che richiama quando questa macro viene utilizzata in un modello. (Non abbiamo incluso una LogRoleARN proprietà LogGroupName or per la registrazione degli errori.)

In questo esempio, supponiamo che lo stack creato da questo modello abbia un nome. JavaMacroFunc Poiché la Name proprietà macro è impostata sul nome dello stack, anche la macro risultante viene JavaMacroFunc denominata.

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'

Utilizzo della macro

Per utilizzare la nostra macro, la includiamo in un modello utilizzando la funzione Fn::Transform intrinseca.

Quando creiamo uno stack utilizzando il modello seguente, CloudFormation richiama la nostra macro di esempio. La funzione Lambda sottostante sostituisce una stringa specificata con un'altra stringa specificata. In questo caso, il risultato è una risorsa AWS::CloudFormation::WaitConditionHandle vuota che viene inserita nel modello elaborato.

Parameters: ExampleParameter: Type: String Default: 'SampleMacro' Resources: 2a: Fn::Transform: Name: "JavaMacroFunc" Parameters: replacement: 'AWS::CloudFormation::WaitConditionHandle' target: '$$REPLACEMENT$$' Type: '$$REPLACEMENT$$'
  • La macro da richiamare è specificata comeJavaMacroFunc, che proviene dal precedente esempio di definizione di macro.

  • Alla macro vengono passati due parametri, target e replacement, che rappresentano la stringa di destinazione e il valore di sostituzione desiderato.

  • La macro può funzionare sul contenuto del nodo Type in quanto Type è un elemento di pari livello della funzione Fn::Transform che fa riferimento alla macro.

  • La risorsa AWS::CloudFormation::WaitConditionHandle risultante è denominata 2a.

  • Il modello contiene inoltre un parametro di modello, ExampleParameter, a cui la macro ha accesso (ma che non utilizza in questo caso).

Dati di input Lambda

Quando CloudFormation elabora il nostro modello di esempio durante la creazione dello stack, passa la seguente mappatura degli eventi alla funzione Lambda a cui si fa riferimento nella definizione della macro. JavaMacroFunc

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

fragmentcontiene la JSON rappresentazione del frammento di modello che la macro può elaborare. Questo frammento comprende elementi di pari livello della chiamata di funzione Fn::Transform, ma non la chiamata stessa. Inoltre, params contiene la JSON rappresentazione dei parametri della macro. In questo caso, sostituzione e destinazione. Analogamente, templateParameterValues contiene la JSON rappresentazione dei parametri specificati per l'intero modello.

Codice funzione Lambda

Di seguito è riportato il codice effettivo per la funzione Lambda alla base della macro di JavaMacroFunc esempio. L'esempio esegue l'iterazione del frammento di modello incluso nella risposta (che sia in un formato di stringa, elenco o mappa), alla ricerca della stringa di destinazione specificata. Se trova la stringa di destinazione specificata, la funzione Lambda sostituisce la stringa di destinazione con la stringa di sostituzione specificata. In caso contrario, la funzione lascia il frammento di modello invariato. Quindi, la funzione restituisce una mappa delle proprietà previste, illustrate in dettaglio di seguito, a 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; } }

Risposta della funzione Lambda

Di seguito è riportata la mappatura a cui torna la funzione Lambda CloudFormation per l'elaborazione.

  • requestId : 5dba79b5-f117-4de0-9ce4-d40363bfb6ab

  • status : SUCCESS

  • fragment :

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

Le requestId corrispondenze inviate da CloudFormation e il status valore di SUCCESS indicano che la funzione Lambda ha elaborato correttamente il frammento di modello incluso nella richiesta. In questa risposta, fragment contiene la JSON rappresentazione del contenuto da inserire nel modello elaborato al posto dello snippet di modello originale.

Modello elaborato risultante

Dopo aver CloudFormation ricevuto una risposta corretta dalla funzione Lambda, inserisce il frammento di modello restituito nel modello elaborato.

Di seguito è riportato il modello elaborato risultante per il nostro esempio. La chiamata alla funzione Fn::Transform intrinseca che faceva riferimento alla macro non è più JavaMacroFunc inclusa. Il frammento di modello restituito dalla funzione Lambda è incluso nella posizione appropriata, con il risultato che il contenuto "Type": "$$REPLACEMENT$$" è stato sostituito con "Type": "AWS::CloudFormation::WaitConditionHandle".

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