簡單字串取代巨集範例 - AWS CloudFormation

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

簡單字串取代巨集範例

下列範例會逐步解說使用巨集的程序,從在範本中定義巨集,到為巨集建立 Lambda 函數,然後在範本中使用巨集。

在這個範例中,我們會建立簡單巨集,在處理的範本中插入指定的字串,以取代指定的目標內容。然後,我們會使用它在處理的範本中的指定位置插入空白 WaitHandleCondition

建立巨集

在使用巨集之前,我們必須先完成兩件事:建立執行所需範本處理的 Lambda 函數,然後 CloudFormation 建立巨集定義,將該 Lambda 函數提供給 。

以下範例範本包含範例巨集的定義。若要讓巨集可在特定 中使用 AWS 帳戶,請從 範本建立堆疊。巨集定義會指定巨集名稱、簡短描述,並參考在範本中使用此巨集時 CloudFormation 呼叫ARN的 Lambda 函數的 。(我們尚未包含用於錯誤記錄的 LogGroupNameLogRoleARN 屬性。)

在此範例中,假設從此範本建立的堆疊名為 JavaMacroFunc。由於巨集Name屬性設定為堆疊名稱,因此產生的巨集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'

使用巨集

若要使用我們的巨集,我們使用Fn::Transform內部 函數將其包含在 範本中。

使用下列範本建立堆疊時, 會 CloudFormation 呼叫範例巨集。基礎 Lambda 函數會將一個指定的字串替換成另一個指定的字串。在此案例中,結果是在所處理的範本中插入空白 AWS::CloudFormation::WaitConditionHandle

Parameters: ExampleParameter: Type: String Default: 'SampleMacro' Resources: 2a: Fn::Transform: Name: "JavaMacroFunc" Parameters: replacement: 'AWS::CloudFormation::WaitConditionHandle' target: '$$REPLACEMENT$$' Type: '$$REPLACEMENT$$'
  • 要叫用的巨集會指定為 JavaMacroFunc,這是來自先前的巨集定義範例。

  • 有兩個參數傳遞給巨集:targetreplacement,代表目標字串及其所需的替換值。

  • 巨集可以處理 Type 節點的內容,因為 Type 是參考巨集的 Fn::Transform 函數的同級項目。

  • 產生的 AWS::CloudFormation::WaitConditionHandle 名為 2a

  • 範本還包含巨集也可存取的範本參數:ExampleParameter (但在這個案例中未使用)。

Lambda 輸入資料

在堆疊建立期間 CloudFormation 處理我們的範例範本時,它會將下列事件映射傳遞至JavaMacroFunc巨集定義中參考的 Lambda 函數。

  • 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 包含 ,JSON代表巨集可以處理的範本片段。此片段由 Fn::Transform 函數呼叫的同級項目組成,而不是函數呼叫本身。此外, params包含 JSON 代表巨集參數。在此案例中是 replacement 和 target。同樣地, templateParameterValues包含 JSON 代表為整個範本指定的參數。

Lambda 函數程式碼

以下是JavaMacroFunc範例巨集下 Lambda 函數的實際程式碼。它會逐一查看回應 (不論是字串、清單或映射格式) 包含的範本片段,尋找指定的目標字串。如果找到指定的目標字串,Lambda 函數會以指定的替換字串取代目標字串。如果找不到,該函數會將範本片段保持不變。然後,函數會傳回預期屬性的映射,詳細討論如下 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; } }

Lambda 函數回應

以下是 Lambda 函數傳回 CloudFormation 以進行處理的映射。

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

  • status : SUCCESS

  • fragment :

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

從 傳送的requestId相符項目 CloudFormation,以及 statusSUCCESS表示 Lambda 函數已成功處理包含在請求中的範本片段。在此回應中, fragment包含 JSON 代表要插入處理範本的內容,以取代原始範本程式碼片段。

產生的處理範本

在 從 Lambda 函數 CloudFormation 收到成功回應後,它會將傳回的範本片段插入已處理的範本。

以下是我們的範例產生的處理過範本。參考JavaMacroFunc巨集Fn::Transform的內部函數呼叫不再包含在內。Lambda 函數傳回的範本片段會納入適當的位置中,結果是內容 "Type": "$$REPLACEMENT$$" 已替換成 "Type": "AWS::CloudFormation::WaitConditionHandle"

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