【问题标题】:Passing ARN reference from CloudFormation to Swagger将 ARN 引用从 CloudFormation 传递给 Swagger
【发布时间】:2017-05-07 02:18:17
【问题描述】:

我们正在尝试使用 Amazon CloudFormation 和 Swagger 自动部署 AWS lambda 和 API 网关。为此,我们创建了一个 CloudFormation 模板来创建 APIGateway 所需的 Lambda 和其他资源(包括端点)。我们希望从外部 swagger 文件中导入 API 定义,以便可以将相同的 CloudFormation 模板用于多个 lambda 和 APIGateway。有没有办法我们可以在包含 API 定义的外部 swagger 文件(在同一个 CloudFormation 模板中引用)中引用由 CloudFormation 模板创建的 lambda 的 ARN?

招摇内容:

"x-amazon-apigateway-integration": {
              "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123456789012:function:TestSimpleProxy/invocations",
              "passthroughBehavior": "when_no_match",
              "httpMethod": "POST",
              "type": "aws_proxy"
            }

在上述集成方法中,我需要从云形成模板中动态替换uri的值。

我的成云脚本如下:

"myApi":{
      "Type" : "AWS::ApiGateway::RestApi",
      "Properties" : {
        "BodyS3Location" : S3Location of the swagger definition file,
        ..,
        ..
      }
    }

【问题讨论】:

    标签: amazon-web-services swagger aws-lambda aws-api-gateway amazon-cloudformation


    【解决方案1】:

    "x-amazon-apigateway-integration" 是您的 CloudFormation 模板的一部分吗?

    如果是这样,那么按照https://blog.jayway.com/2016/09/18/introduction-swagger-cloudformation-api-gateway/ 的示例,我认为您可以使用Ref 函数来传递该信息。

    【讨论】:

    • 感谢您的回复。仅当我们使用云形成模板本身对 swagger 定义进行硬编码时,所引用的示例才有效。如果我尝试从外部文件导入它。它抛出了一个无效的 ARN 错误。
    • 您能否分享一个完整的 CloudFormation 模板示例来演示该错误?
    【解决方案2】:

    我刚刚遇到了同样的障碍...这不是一个简单的答案,而是一种解决方法,可以自动解决您想要使用的 Lambda ARN招摇模板;它对我有用。来了……

    1. 在 CF 模板中导出 Lambda ARN,该模板会创建您的 Lambda,并且您希望稍后在 swagger 模板中使用它,例如

      Outputs:
        MyLambdaARN:
          Value: !Ref "LambdaFuncThatIsDefinedInTheTemplate"
          Export:
            Name: !Sub "${AWS::StackName}-LambdaARN"
      
    2. 请参阅 swagger 模板中的 Lambda ARN 导出 - 代替您的 lambda 的 ARN,输入一个可替换令牌,其中包括步骤 1 中的导出名称,例如“MyLambdaStack-LambdaARN”,如果您的步骤 1 中的堆栈创建为“MyLambdaStack”。

      • 对于令牌语法,让我们使用我们希望实际工作的ImportValue function,因此我们的令牌变为!ImportValue(MyLambdaStack-LambdaARN)
      • 在我们的 swagger 模板中,集成扩展使用我们的令牌,如下所示:

        x-amazon-apigateway-integration:
          passthroughBehavior: "when_no_match"
          uri: "!ImportValue(MyLambdaStack-LambdaARN)"
          httpMethod": "POST"
          type: "AWS-PROXY" 
        
    3. 将令牌替换为实际的 Lambda ARN - 我们将使用以下脚本将 !ImportValue(MyLambdaStack-LambdaARN) 令牌替换为我们需要的实际 Lambda ARN。

      #!/bin/bash
      SWAGGER_FILE=$1
      
      REPLACEMENTS=$( \
          aws cloudformation list-exports --query 'Exports[*].[Name,Value]'\
          | awk '{print "s/!ImportValue(" $1 ")/" $2 "/g"}' ORS='; '\
      )
      
      sed "$REPLACEMENTS" "$SWAGGER_FILE"
      

      这就是这个脚本的作用

      1. 使用aws cloudformation list-exports获取堆栈导出列表
      2. 使用--query 'Exports[*].[Name,Value]' 参数过滤到仅导出名称和值
      3. 将导出格式化为 sed 替换字符串,该替换字符串将用 awk '{print "s/!ImportValue(" $1 ")/" $2 "/g"}' ORS='; ' 的实际导出值替换标记值
      4. 最后,使用sed 在作为脚本第一个参数传入的 swagger 文件中进行替换。

      例如,如果您将此脚本创建为resolve-arns.sh,则可以按如下方式调用它:

      ./resolve-arns.sh swagger.yml > resolved-swagger.yml
      
    4. 引用已解决的 Swagger 定义 - 最后,您将在用于创建 API 的 CF 模板中引用 resolved-swagger.yml 文件,例如BodyS3Location: resolved-swagger.yml

    注意事项:

    1. 当然,aws 命令行工具需要可用和配置
    2. 此实现不够复杂,无法处理 AWS 区域参数...但可以为此进行修改
    3. 这是一个 bash 脚本...如果您使用的是不同的操作系统,例如 windows,同样的方法应该可以工作,但实现会有所不同(我可能会从 powershell 开始...)

    【讨论】:

      【解决方案3】:

      还有另一种不太复杂的方法。如果您使用Body 属性而不是AWS::ApiGateway::RestApiBodyS3Location,您可以使用Cloud Formation Instrinsic Functions 在您的swagger 模板中引用或动态构建您想要的ARN。

      ...当然,缺点是您的 swagger 模板嵌入在 CF 脚本中,而不是单独的文件中。

      【讨论】:

        【解决方案4】:

        新解决方案:

        现在可以使用新的AWS::Include Transform 直接从 CloudFormation 模板引用上传的模板:

        Api:
          Type: AWS::ApiGateway::RestApi
          Properties:
            Body:
              Fn::Transform:
                Name: AWS::Include
                Parameters:
                  Location: !Sub s3://${ArtifactsBucket}/swagger.yaml
        

        其中ArtifactsBucket 是指您在创建或更新堆栈之前上传 Swagger 规范的存储桶。然后,在 Swagger 模板本身中,您可以使用内在函数,例如

        x-amazon-apigateway-integration:
          type: aws_proxy
          httpMethod: POST
          uri:
            Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations
        

        在这里,我使用长 Fn::Sub 表示法,而不仅仅是 !Sub,因为 Swagger 本身并不支持后者,还因为 AWS::Include Transform 上的文档说尚不支持速记形式。

        如果你使用SAM,你也可以使用AWS::Serverless::ApiDefinitionBody

        旧的解决方法:

        另一个(有点老套,但很简单)的解决方案是将 Api 列为 CloudFormation 模板中的最后一个资源,并指定一个 empty Body,并在末尾加上 : !Sub |-

        然后,您可以将此模板与实际的 Swagger 文件连接,并使用该文件中的标准 ${} 语法引用任何参数。

        唯一的小麻烦是,当您使用 YAML 时,您必须在连接 Swagger 文件时正确缩进(但这种方法不适用于 JSON 模板;您必须将 Body 替换为 @987654334 之类的东西@如果你使用这些)。

        【讨论】:

        • 您链接到的官方文档至少很难理解。感谢您提供清晰的示例。
        • 很好的答案! 1) 什么是LambdaFunction,是在template.yaml 中为AWS::Serverless::Function 使用的名称吗? 2)AWS::Serverless::Api 也有效吗?
        • 1) 是的,它只是函数的名称; 2) 我认为它应该在AWS::Serverless::Api 中工作,但请验证。
        猜你喜欢
        • 2021-03-27
        • 1970-01-01
        • 2022-11-09
        • 2020-10-22
        • 1970-01-01
        • 2017-11-18
        • 2017-08-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多