2015-09-27 42 views
5

我有用Java编写的AWS Lambda函数,我想用它作为对AWS CloudFormation函数的响应的一部分。亚马逊提供two detailed examples关于如何创建CloudFormation自定义资源,该自定义资源基于Node.js中编写的AWS Lambda函数返回其值,但是我一直难以将Lambda示例转换为Java。我们如何设置我们的AWS Java函数,以便它从CloudFormation中读取作为参数传递给Lambda函数的预签名S3 URL的值,并将我们期望的响应发送回等待的CloudFormation模板?我们如何使用用Java编写的AWS Lambda函数访问和响应CloudFormation自定义资源?

回答

6

经过与AWS的来回对话,以下是我创建的一些代码示例来完成此操作。

首先,假设你想leverage the predefined interfaces for creating Handlers,可以实现RequestsHandler和定义的handleRequest方法,像这样:

public class MyCloudFormationResponder implements RequestHandler<Map<String, Object>, Object>{ 
    public Object handleRequest(Map<String,Object> input, Context context) { 
     ... 
    } 
} 

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); 
    } 

关键的东西在这里指出,超出了在的NodeJS实例的AWS文档中解释的

  • (String)input.get("ResponseURL")是您需要回复的预签名S3 URL(稍后会详细介绍)
  • (Map<String,Object>)input.get("ResourceProperties")返回从CF模板传递到Lambda函数的CloudFormation自定义资源“Properties”的映射。我提供的字符串和ArrayList作为可返回的对象类型的两个例子,虽然其他几个人都是可能的

为了回CloudFormation模板自定义资源实例回应,您需要执行一个HTTP PUT回调到前面提到的ResponseURL,并包含变量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(); 
    } 

尤其值得注意的是节点“数据”上面它引用的附加com.amazonaws.util.json.JSONObject,其中包括我所需要的,我CloudFormation模板中的任何属性。在这种情况下,它会在CF模板被检索的东西,如{ "Fn::GetAtt": [ "MyCustomResource", "CFAttributeRefName" ] }

最后,你可以简单地return null因为没有得到此功能,因为它是实际响应CF调用HTTPUrlConnection返回。

+0

你给了地方,因为我有从自定义资源读取响应回来时,我将它发送到水桶的问题响应发送桶任何权限?我的lambda正确地发送数据,然后CloudFormation挂起,因为它似乎永远不会收到通知。 –

+0

对responseURL的请求很尴尬,因为我找不到一个错误:我们计算的请求签名与您提供的签名不匹配。检查你的密钥和签名方法。 你有没有遇到过这个,你知道它到底是什么意思吗? –

0

Neil,

我真的很感谢你在这里的优秀文档。我会添加一些我认为有用的东西:

input.get(“RequestType”) - 这会返回为“创建”,“删除”等。您可以使用此值确定如何执行堆栈被创建,删除等。

就安全性而言,我上传了Lambda函数并手动设置了VPC,子网和安全组(默认),这样我就可以在多个cloudformationn脚本中重复使用它。这似乎工作正常。

我创建了一个由CF脚本调用的Lambda函数,另一个我可以在第一个失败的情况下手动运行。

这款出色的gradle aws插件可以轻松将Java Lambda函数上传到AWS。

Gradle AWS Plugin

相关问题