aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.35k stars 3.77k forks source link

(apigateway): RestApi not redeploying correctly #14660

Open nathan-boulestin opened 3 years ago

nathan-boulestin commented 3 years ago

When I change a resource path in a RestApi the old path is not removed from the api stage. The deploy option of RestApi should update the stage when a change occur in the api.

Reproduction Steps

The initial stack:

    const api: RestApi = new RestApi(this, 'rest-api', {
        deploy: true,
        deployOptions: {
            stageName: 'test-stage'
        }
    })

    const myResource:IResource = api.root.addResource("myResource", {})

    myResource.addMethod("GET", 
        new Integration({
            type:IntegrationType.MOCK,
            integrationHttpMethod:'ANY'
        })
    )

The deployed resources: image The stage: image

If I change the path of the resource: const myResource:IResource = api.root.addResource("myResourceChanged", {}) and redeploy the stack

What did you expect to happen?

The expect deployed resources: image The expect stage: image

What actually happened?

The new deployed resources: image The new stage: image

If I manually redeploy the stage from the console, the /myResource is removed from the stage.

Environment

Other


This is :bug: Bug Report

nija-at commented 3 years ago

Can you look at the produced CloudFormation template and confirm that the old Resource (myResource) is removed after the update?

If so, then this may be an issue with CloudFormation and APIGateway, rather than the CDK.

nathan-boulestin commented 3 years ago

You are right the old resource have been removed from the Cfn template.

So this issue is not about the CDK at all ?

nija-at commented 3 years ago

If the Cfn template is accurate, then the CDK has handled this correctly. You will need to report this issue to the API Gateway service team.

nija-at commented 3 years ago

Actually, the problem is a little more tricky than I originally thought.

In order to cause little or no disruption to running applications during stack updates, CloudFormation ensures that resources are first created and/or updated before any resources are deleted.

CDK automatically creates a default Stage and Deployment whenever a RestApi is created. To ensure that the Deployment is kept in sync with the Rest API definition, the CDK needs to trigger a re-deployment of the Deployment resource. The CDK achieves this by changing the logical id of the Deployment resource which triggers a replacement.

In effect, when a Resource is removed from a RestApi and another added, CloudFormation first creates the new Resource, then creates the new Deployment for the RestApi (that now contains both Resources), then deletes the old Deployment and finally deletes the old Resource. So finally, we end up with a Deployment resource that contains both Resources.

I can't think of an easy way to solve this problem with just the CDK.

adarsh-chauhan commented 1 year ago

any update on this?

openwebsolns commented 1 year ago

@nija-at The CDK way of achieving this also leads to another issue, briefly: a CloudFormation rollback results in the "API Gateway stage" receiving a deployment that does not match the "API Gateway definition". This is due to CDK's creation of a new AWS::ApiGateway::Deployment resource, which it ironically does to "ensure that the Deployment is kept in sync with the Rest API definition". Here's what's happening:

Suppose at the start of a CloudFormation stack update, the RestApi definition is at snapshot defintion-01. Likewise, the API Gateway stage is associated with deployment ID deployment-01. During the stack update:

  1. CloudFormation UPDATEs RestApi definition to definition-02.
  2. CloudFormation CREATEs a new Deployment resource based on this new definition with ID deployment-02.
  3. CloudFormation UPDATEs stage resource to use deployment ID deployment-02.
  4. Rollback is initiated either by hand or automatically through rollback configuration
  5. CloudFormation UPDATEs RestApi definition back, by undoing the changes introduced. This causes a new definition definition-03. Note: this definition is not the same as definition-01 (more on this later)
  6. CloudFormation UPDATEs stage resource to point back to deployment deployment-01. This is because, being a new resource, CloudFormation hasn't yet "deleted" the initial deployment resource. As such, the rollback merely reassigns the old deployment ID property back to the stage.

At the end of this rollback, the REST API definition is definition-03, but the deployed stage is deployment-01, corresponding with definition-01. This may seem safe, but in fact it's a sharp edge because there's inadvertent divergence.


As I write this, I realize this is a "bug" in CloudFormation itself. The correct course of action, in my opinion, is for the AWS::ApiGateway::Deployment resource not to change its logical ID from one deployment to the next (as CDK does today automatically). This forces CloudFormation to UPDATE the Deployment source instead of CREATE/DELETE which leads to the divergence above. Unfortunately, there's no way in the Deployment definition to effectuate this behavior. But a custom resource would!

The custom resource would always create a new API Gateway deployment on every update, and return the deployment ID as its attribute. This would ensure no divergence. Is this something CDK team is open to implementing?

vdefeo-caylent commented 1 year ago

Hi team, any update on it? thanks!

FarrOut commented 3 months ago

https://github.com/aws-cloudformation/cloudformation-coverage-roadmap/issues/623 might help with this issue