2

我希望我的一些Lambda资源能够使用aws-sdkAWS.IotData({ endpoint: url })函数推送到AWS IOT端点,其中endpoint是必需的参数。如何从CloudFormation模板中获取AWS IOT端点URL?

现在,我通过环境变量将端点URL传递给我的Lambda。但是,当放入SAM/CF模板时,我无法找到检索我的IOT端点URL的方式,以便我可以简单地使用!Ref它。

通过AWS resource type reference浏览我没有找到任何与IOT端点相对应的资源。

好像IOT端点只能手动调配,通过AWS控制台(启用/禁用),如下面的截图:

IOT Endpoint AWS Console

如何过度配置的IOT具有控制权的任何建议端点或至少从SAM/CF模板中读取IOT URL,而无需使用aws-cli编写脚本?

回答

1

恐怕您无法配置IoT端点,因为与物联网端点相关的唯一API调用是DescribeEndpoint

您可以做的是创建一个支持Lambda的CloudFormation自定义资源。 Lambda函数将执行DescribeEndpoint调用(根据Lambda的运行时使用您选择的AWS开发工具包)并返回端点的URL,以便其他CloudFormation资源可以使用它。

下面是Lambda支持的自定义资源的一个很好的示例:http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html

1

对于任何对CloudFormation Custom Resource解决方案感兴趣的人,我写了一个简单的Lambda和一个CF模板,为其他CF堆栈提供IOT端点地址。

template.yaml

AWSTemplateFormatVersion: '2010-09-09' 
Transform: 'AWS::Serverless-2016-10-31' 
Resources: 
    IotEndpointProvider: 
    Type: 'AWS::Serverless::Function' 
    Properties: 
     FunctionName: IotEndpointProvider 
     Handler: iotEndpointProvider.handler 
     Runtime: nodejs6.10 
     CodeUri: . 
     MemorySize: 128 
     Timeout: 3 
     Policies: 
     - Version: '2012-10-17' 
      Statement: 
      - Effect: Allow 
      Action: 
       - iot:DescribeEndpoint 
      Resource: 
       - '*' 
    IotEndpoint: 
    Type: 'Custom::IotEndpoint' 
    Properties: 
     ServiceToken: !GetAtt IotEndpointProvider.Arn 
     Runtime: nodejs6.10 
     CodeUri: . 
     MemorySize: 128 
     Timeout: 3 
Outputs: 
    IotEndpointAddress: 
    Value: !GetAtt IotEndpoint.IotEndpointAddress 
    Export: 
     Name: IotEndpointAddress 

iotEndpointProvider.js

var aws = require("aws-sdk"); 

exports.handler = function(event, context) { 
    console.log("REQUEST RECEIVED:\n" + JSON.stringify(event)); 

    // For Delete requests, immediately send a SUCCESS response. 
    if (event.RequestType == "Delete") { 
     sendResponse(event, context, "SUCCESS"); 
     return; 
    } 

    const iot = new aws.Iot(); 
    iot.describeEndpoint({}, (err, data) => { 
    let responseData, responseStatus; 
     if (err) { 
      responseStatus = "FAILED"; 
      responseData = { Error: "describeEndpoint call failed" }; 
      console.log(responseData.Error + ":\n", err); 
     } else { 
      responseStatus = "SUCCESS"; 
      responseData = { IotEndpointAddress: data.endpointAddress }; 
      console.log('response data: ' + JSON.stringify(responseData)); 
     } 

     sendResponse(event, context, responseStatus, responseData); 
    }); 
}; 

// Send response to the pre-signed S3 URL 
function sendResponse(event, context, responseStatus, responseData) { 

    var responseBody = JSON.stringify({ 
     Status: responseStatus, 
     Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName, 
     PhysicalResourceId: context.logStreamName, 
     StackId: event.StackId, 
     RequestId: event.RequestId, 
     LogicalResourceId: event.LogicalResourceId, 
     Data: responseData 
    }); 

    console.log("RESPONSE BODY:\n", responseBody); 

    var https = require("https"); 
    var url = require("url"); 

    var parsedUrl = url.parse(event.ResponseURL); 
    var options = { 
     hostname: parsedUrl.hostname, 
     port: 443, 
     path: parsedUrl.path, 
     method: "PUT", 
     headers: { 
      "content-type": "", 
      "content-length": responseBody.length 
     } 
    }; 

    console.log("SENDING RESPONSE...\n"); 

    var request = https.request(options, function(response) { 
     console.log("STATUS: " + response.statusCode); 
     console.log("HEADERS: " + JSON.stringify(response.headers)); 
     // Tell AWS Lambda that the function execution is done 
     context.done(); 
    }); 

    request.on("error", function(error) { 
     console.log("sendResponse Error:" + error); 
     // Tell AWS Lambda that the function execution is done 
     context.done(); 
    }); 

    // write data to request body 
    request.write(responseBody); 
    request.end(); 
} 
相关问题