amazon-web-services - Cloudformation 自定义资源创建失败

标签 amazon-web-services .net-core aws-lambda aws-cloudformation

我正在尝试创建一个指向 lambda 函数的自定义资源,然后调用它来生成随机优先级或我的 ELB 监听器。

Lambda函数的代码如下。

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace aws_listenser_rule_priority_generator {
    public class Function {
        public async Task<int> FunctionHandler(FunctionParams input, ILambdaContext context) {
            AmazonElasticLoadBalancingV2Client elbV2Client = new AmazonElasticLoadBalancingV2Client(RegionEndpoint.EUWest1);
            var describeRulesResponse = await elbV2Client.DescribeRulesAsync(new DescribeRulesRequest  {
                ListenerArn = input.ListenerArn
            });
            var priority = 0;
            var random = new Random();
            do {
                priority = random.Next(1, 50000);
            }
            while(describeRulesResponse.Rules.Exists(r => r.Priority == priority.ToString()));
            
            return priority;
        }
    }

    public class FunctionParams {
        public string ListenerArn { get; set; }
    }
}

我已使用以下参数在 AWS 控制台上测试了此 lambda,并且它成功返回。

{
  "ListenerArn": "arn:aws:elasticloadbalancing:eu-west-1:706137030892:listener/app/Cumulus/dfcf28e0393cbf77/cdfe928b0285d5f0"
}

但是当我尝试将其与 Cloud Formation 一起使用时。自定义资源卡在创建过程中。

Resources:
  ListenerPriority:
    Type: Custom::Number
    Properties:
      ServiceToken: "arn:aws:lambda:eu-west-1:706137030892:function:GenerateListenerPriority"
      ListenerArn: "arn:aws:elasticloadbalancing:eu-west-1:706137030892:listener/app/Cumulus/dfcf28e0393cbf77/cdfe928b0285d5f0"

最佳答案

先前方法的问题在于数据格式。当我们使用自定义资源时,Cloud Formation 以指定格式发送请求,并期望在指定响应 URL 处异步响应。

我必须对代码进行以下更新:

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace aws_listenser_rule_priority_generator
{
    public class Function
    {
        public async Task FunctionHandler(CustomResourceRequest<CustomResourceRequestProperties> crfRequest, ILambdaContext context)
        {
            var jsonResponse = string.Empty;
            
            if(crfRequest.RequestType.ToUpperInvariant() != "CREATE") {
                jsonResponse = JsonSerializer.Serialize(new CustomResourceResponse<object> {
                    Status = "SUCCESS",
                    Reason = string.Empty,
                    PhysicalResourceId = Guid.NewGuid().ToString(),
                    StackId = crfRequest.StackId,
                    RequestId = crfRequest.RequestId,
                    LogicalResourceId = crfRequest.LogicalResourceId,
                    Data = new {
                        Dummy = "Dummy"
                    }
                });
            }
            else {
                AmazonElasticLoadBalancingV2Client elbV2Client = new AmazonElasticLoadBalancingV2Client(RegionEndpoint.EUWest1);
                var describeRulesResponse = await elbV2Client.DescribeRulesAsync(new DescribeRulesRequest  {
                    ListenerArn = crfRequest.ResourceProperties.ListenerArn
                });
                var priority = 0;
                var random = new Random();
                do {
                    priority = random.Next(1, 50000);
                }
                while(describeRulesResponse.Rules.Exists(r => r.Priority == priority.ToString()));

                jsonResponse = JsonSerializer.Serialize(new CustomResourceResponse<object> {
                    Status = "SUCCESS",
                    Reason = string.Empty,
                    PhysicalResourceId = Guid.NewGuid().ToString(),
                    StackId = crfRequest.StackId,
                    RequestId = crfRequest.RequestId,
                    LogicalResourceId = crfRequest.LogicalResourceId,
                    Data = new {
                        Priority = priority
                    }
                });
            }
            var byteArray = Encoding.UTF8.GetBytes(jsonResponse);
            
            var webRequest = WebRequest.Create(crfRequest.ResponseURL) as HttpWebRequest;
            webRequest.Method = "PUT";
            webRequest.ContentType = string.Empty;
            webRequest.ContentLength = byteArray.Length;
            
            using(Stream datastream = webRequest.GetRequestStream()) {
                await datastream.WriteAsync(byteArray, 0, byteArray.Length);
            }

            await webRequest.GetResponseAsync();
        }
    }
    public class CustomResourceRequest<T> where T : ICustomResourceRequestProperties {
        public string RequestType { get; set; }
        public string ResponseURL { get; set; }
        public string StackId { get; set; }
        public string RequestId { get; set; }
        public string ResourceType { get; set; }
        public string LogicalResourceId{ get; set; }
        public string PhysicalResourceId { get; set; }
        public T ResourceProperties { get; set; }
        public T OldResourceProperties { get; set; }
    }
    public class CustomResourceResponse<T> {
        public string Status { get; set; }
        public string Reason { get; set; }
        public string PhysicalResourceId { get; set; }
        public string StackId { get; set; }
        public string RequestId { get; set; }
        public string LogicalResourceId { get; set; }
        public bool NoEcho { get; set; }
        public T Data { get; set; }
    }
    public interface ICustomResourceRequestProperties {
        public string ServiceToken { get; set; }
    }
    public class CustomResourceRequestProperties : ICustomResourceRequestProperties
    {
        string ICustomResourceRequestProperties.ServiceToken { get; set; }
        public string ListenerArn { get; set; }
    }
}

上面的代码期望一切正常,没有任何问题,并且没有 try catch block 。最佳实践是使用 try catch block 并发送失败响应。

可引用以下网址了解更多详情:

关于amazon-web-services - Cloudformation 自定义资源创建失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65492823/

相关文章:

json - 如何在集成请求 (AWS APIGateway) 中取消转义请求路径

java - AWS 混合云环境的 Hazelcast 配置

c# - 从 C# 服务使用 Graph API 获取日历计划

node.js - AWS Lambda NodeJS 连接到 RDS Postgres 数据库

docker - 如何在Windows docker镜像中安装.pfx证书

.net-core - "Could not find the required ' {组装}.deps.json'。此文件应位于部署包的根目录中

amazon-web-services - 网络接口(interface)与子网 ID 冲突 - Terraform AWS 提供商

amazon-web-services - 如何收集 grep 并在 aws 配置集中使用它

c# - 发布 AWS Lambda .Net Core