本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
簡單字串取代巨集範例
下列範例會逐步解說使用巨集的程序,從在範本中定義巨集,到為巨集建立 Lambda 函數,然後在範本中使用巨集。
在這個範例中,我們會建立簡單巨集,在處理的範本中插入指定的字串,以取代指定的目標內容。然後,我們會使用它在處理的範本中的指定位置插入空白 WaitHandleCondition
。
建立巨集
在使用巨集之前,我們必須先完成兩件事:建立執行所需範本處理的 Lambda 函數,然後 CloudFormation 建立巨集定義,將該 Lambda 函數提供給 。
以下範例範本包含範例巨集的定義。若要讓巨集可在特定 中使用 AWS 帳戶,請從 範本建立堆疊。巨集定義會指定巨集名稱、簡短描述,並參考在範本中使用此巨集時 CloudFormation 呼叫ARN的 Lambda 函數的 。(我們尚未包含用於錯誤記錄的 LogGroupName
或 LogRoleARN
屬性。)
在此範例中,假設從此範本建立的堆疊名為 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
,這是來自先前的巨集定義範例。 -
有兩個參數傳遞給巨集:
target
和replacement
,代表目標字串及其所需的替換值。 -
巨集可以處理
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,以及 status
值SUCCESS
表示 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" } } }