在与 AWS 反复交谈之后,以下是我创建的一些用于完成此任务的代码示例。
首先,假设你想要利用预定义的接口来创建处理程序 http://docs.aws.amazon.com/lambda/latest/dg/java-handler-using-predefined-interfaces.html,您可以实现 RequestsHandler 并定义 HandleRequest 方法,如下所示:
public class MyCloudFormationResponder implements RequestHandler<Map<String, Object>, Object>{
public Object handleRequest(Map<String,Object> input, Context context) {
...
}
}
The Map<String, Object>
是从 CloudFormation 资源发送到 Lambda 函数的值的映射。 CF 资源示例:
"MyCustomResource": {
"Type" : "Custom::String",
"Version" : "1.0",
"Properties": {
"ServiceToken": "arn:aws:lambda:us-east-1:xxxxxxx:function:MyCloudFormationResponderLambdaFunction",
"param1": "my value1",
"param2": ["t1.micro", "m1.small", "m1.large"]
}
}
可以用下面的代码来分析
String responseURL = (String)input.get("ResponseURL");
context.getLogger().log("ResponseURLInput: " + responseURL);
context.getLogger().log("StackId Input: " + input.get("StackId"));
context.getLogger().log("RequestId Input: " + input.get("RequestId"));
context.getLogger().log("LogicalResourceId Context: " + input.get("LogicalResourceId"));
context.getLogger().log("Physical Context: " + context.getLogStreamName());
@SuppressWarnings("unchecked")
Map<String,Object> resourceProps = (Map<String,Object>)input.get("ResourceProperties");
context.getLogger().log("param 1: " + resourceProps.get("param1"));
@SuppressWarnings("unchecked")
List<String> myList = (ArrayList<String>)resourceProps.get("param2");
for(String s : myList){
context.getLogger().log(s);
}
除了 AWS 文档中的 NodeJS 示例中解释的内容之外,这里需要指出的关键事项是
-
(String)input.get("ResponseURL")
是您需要响应的预签名 S3 URL(稍后会详细介绍)
-
(Map<String,Object>)input.get("ResourceProperties")
返回从 CF 模板传递到 Lambda 函数的 CloudFormation 自定义资源“属性”的映射。我提供了 String 和 ArrayList 作为可以返回的对象类型的两个示例,尽管其他几种也是可能的
为了响应 CloudFormation 模板自定义资源实例化,您需要对前面提到的 ResponseURL 执行 HTTP PUT 回调,并在变量中包含以下大部分字段cloudFormationJsonResponse
。下面是我是如何做到这一点的
try {
URL url = new URL(responseURL);
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
JSONObject cloudFormationJsonResponse = new JSONObject();
try {
cloudFormationJsonResponse.put("Status", "SUCCESS");
cloudFormationJsonResponse.put("PhysicalResourceId", context.getLogStreamName());
cloudFormationJsonResponse.put("StackId", input.get("StackId"));
cloudFormationJsonResponse.put("RequestId", input.get("RequestId"));
cloudFormationJsonResponse.put("LogicalResourceId", input.get("LogicalResourceId"));
cloudFormationJsonResponse.put("Data", new JSONObject().put("CFAttributeRefName", "some String value useful in your CloudFormation template"));
} catch (JSONException e) {
e.printStackTrace();
}
out.write(cloudFormationJsonResponse.toString());
out.close();
int responseCode = connection.getResponseCode();
context.getLogger().log("Response Code: " + responseCode);
} catch (IOException e) {
e.printStackTrace();
}
特别值得注意的是上面的节点“Data”,它引用了一个附加的com.amazonaws.util.json.JSONObject
其中我包含了 CloudFormation 模板中所需的所有属性。在这种情况下,它将在 CF 模板中检索,类似于{ "Fn::GetAtt": [ "MyCustomResource", "CFAttributeRefName" ] }
最后,您可以简单地return null
因为该函数不会返回任何内容,因为它是HTTPUrlConnection
实际上响应 CF 调用。