此资源的 CloudFormation 部署方法已存在

问题描述

我有一个创建 APIGateway 的 CloudFormation 模板,但是当我再次部署以添加 APIGateway 方法(运行更新堆栈)时,我得到:

Method already exists for this resource (Service: AmazonApiGateway; Status Code: 409; 
Error Code: ConflictException; Request ID: 7058deed-14e1-46bc-863d-efba23cd668b; Proxy: null)

我尝试向所有资源添加更新/删除策略,但似乎没有奏效:

    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain

我有一种预感,这可能是由于没有正确指定资源造成的,我的资源路径有问题吗?这两个资源是在根资源还是其他地方创建的?

我的最终目标

声明两个单独的资源(带有单独的 URL),例如

https://xxx/post-note

https://xxx/deleteNote

都与 lambda 函数相关

我的模板:

AWstemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
# above two lines necessary to convert SAM template to CloudFormation template
Description: Resource deFinitions for my site
Globals: # any parameters you want available to all your resources
  Api:
    Cors:
      AllowMethods: "'OPTIONS,POST,GET'"
      AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
      AllowOrigin: "'*'"

  Function:
    Runtime: nodejs14.x # language used at runtime
    Timeout: 35 # timeout seconds for a given lambda function execution
    Environment:
      Variables: # these will be important later
        DYNAMO_TABLE: !Ref DynamoNotesTable
        DB_ENDPOINT: http://dynamodb.us-east-1.amazonaws.com
        REGION_NAME: us-east-1

Resources:
  # #############################################################################
  # # BACK END LAMBDAS
  # #############################################################################
  postNote:
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Type: AWS::Serverless::Function
    Properties:
      Handler: backend/dynamo/postNote.postNote
      CodeUri: s3://backend/xxx
      Policies:
        - AmazonDynamoDBFullAccess

  deleteNote:
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Type: AWS::Serverless::Function
    Properties:
      Handler: backend/dynamo/deleteNote.deleteNote
      CodeUri: s3://backend/xxx
      Policies:
        - AmazonDynamoDBFullAccess

  #############################################################################
  # api-gateway (with cognito auth)
  # https://bl.ocks.org/magnetikonline/c314952045eee8e8375b82bc7ec68e88
  #############################################################################
  apiGateway:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Description: API Gateway
      EndpointConfiguration:
        Types:
          - REGIONAL
      Name: my-api

  postNoteGatewayMethod:
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: POST
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Sub
          - arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
          - lambdaArn: !GetAtt postNote.Arn
      ResourceId: !GetAtt apiGateway.RootResourceId
      RestApiId: !Ref apiGateway

  deleteNoteGatewayMethod:
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: POST
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Sub
          - arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
          - lambdaArn: !GetAtt deleteNote.Arn
      ResourceId: !GetAtt apiGateway.RootResourceId
      RestApiId: !Ref apiGateway

  apiGatewayDeployment:
    Type: AWS::ApiGateway::Deployment
    DependsOn:
      - postNoteGatewayMethod
      - deleteNoteGatewayMethod
    Properties:
      RestApiId: !Ref apiGateway
      StageName: Prod

  lambdaApiGatewayInvoke:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt postNote.Arn
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/Prod/POST/PATH_PART

解决方法

两个 cloudformation 资源 AWS::ApiGateway::Method 都指向具有相同 POST 方法的相同 api 网关资源。

我们有两个选择

选项 1:更改其中一种方法的方法名称。

  deleteNoteGatewayMethod:
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: POST   <--- should be DELETE
      AuthorizationType: "NONE"

选项 1:为每种方法使用不同的根资源。因此,如果我们需要两个 POST 端点 /postNote 和 /deleteNote,我们必须有两个独立于根路径的资源,并将这些资源用于 lambda。

例如:

/postNote 以 Parent 作为根资源。

  noteResource:
    Type: AWS::ApiGateway::Resource
    Properties:
      ParentId: !GetAtt apiGateway.RootResourceId
      PathPart: "postNote"
      RestApiId: !Ref apiGateway

和方法 ResourceId 指向 !Ref noteResource

  postNoteGatewayMethod:
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Type: AWS::ApiGateway::Method
    DependsOn:
      - noteResource
    Properties:
      HttpMethod: POST
      AuthorizationType: NONE
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Sub
          - arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
          - lambdaArn: !GetAtt postNote.Arn
      ResourceId: !Ref noteResource
      RestApiId: !Ref apiGateway

同样我们需要添加删除资源。

  deleteResource:
    Type: AWS::ApiGateway::Resource
    Properties:
      ParentId: !GetAtt apiGateway.RootResourceId
      PathPart: "deleteNote"
      RestApiId: !Ref apiGateway

  deleteNoteGatewayMethod:
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Type: AWS::ApiGateway::Method
    DependsOn:
      - deleteResource
    Properties:
      HttpMethod: POST
      AuthorizationType: "NONE"
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Sub
          - arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
          - lambdaArn: !GetAtt deleteNote.Arn
      ResourceId: !Ref deleteResource
      RestApiId: !Ref apiGateway