serverless-heaven / serverless-aws-alias

Alias support for Serverless 1.x
MIT License
189 stars 68 forks source link

Creating Main Alias for Stage fails when adding plugin to existing serverless deployment #76

Open mbruning24 opened 7 years ago

mbruning24 commented 7 years ago

First off, great plugin. It's been solving some very tough challenges for me and my team. Great work!

However, I've been trying to add the plugin to some already existing API deployments, and I'm getting an error when deploying the main stage alias. In this case, the API's ${provider.stage} is dev, which means the plugin tries to create a main alias deployment of "dev," which obviously already exists. Here's the --verbose output from the deployment after adding serverless-aws-alias to the plugins array on my serverless.yml:

$ sls deploy --verbose
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Preparing alias ...
Serverless: Processing custom resources
Serverless: Removing resources:
Serverless: Processing functions
Serverless: Processing API
Serverless: Configuring stage
Serverless: Processing SNS Lambda subscriptions
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (13.25 KB)...
Serverless: Uploading CloudFormation alias file to S3...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
CloudFormation - UPDATE_IN_PROGRESS - AWS::CloudFormation::Stack - ens-alias-dev
CloudFormation - UPDATE_IN_PROGRESS - AWS::Lambda::Function - GetLambdaFunction
CloudFormation - UPDATE_COMPLETE - AWS::Lambda::Function - GetLambdaFunction
CloudFormation - UPDATE_COMPLETE_CLEANUP_IN_PROGRESS - AWS::CloudFormation::Stack - ens-alias-dev
CloudFormation - DELETE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - DELETE_COMPLETE - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - UPDATE_COMPLETE - AWS::CloudFormation::Stack - ens-alias-dev
Serverless: Stack update finished...
Serverless: Updating alias stack...
Serverless: Checking Stack update progress...
CloudFormation - UPDATE_IN_PROGRESS - AWS::CloudFormation::Stack - ens-alias-dev-dev
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - GetLambdaVersionlQVnYRFBJjet0buDpEdpz3WEyYblwfMV4ZrjMIklfsI
CloudFormation - CREATE_IN_PROGRESS - AWS::ApiGateway::Deployment - ApiGatewayDeployment1508523706715
CloudFormation - CREATE_IN_PROGRESS - AWS::ApiGateway::Deployment - ApiGatewayDeployment1508523706715
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - GetLambdaVersionlQVnYRFBJjet0buDpEdpz3WEyYblwfMV4ZrjMIklfsI
CloudFormation - CREATE_COMPLETE - AWS::ApiGateway::Deployment - ApiGatewayDeployment1508523706715
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Version - GetLambdaVersionlQVnYRFBJjet0buDpEdpz3WEyYblwfMV4ZrjMIklfsI
CloudFormation - CREATE_IN_PROGRESS - AWS::ApiGateway::Stage - ApiGatewayStage
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Alias - GetAlias
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Alias - GetAlias
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Alias - GetAlias
CloudFormation - CREATE_FAILED - AWS::ApiGateway::Stage - ApiGatewayStage
CloudFormation - UPDATE_ROLLBACK_IN_PROGRESS - AWS::CloudFormation::Stack - ens-alias-dev-dev
CloudFormation - UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS - AWS::CloudFormation::Stack - ens-alias-dev-dev
CloudFormation - DELETE_IN_PROGRESS - AWS::Lambda::Alias - GetAlias
CloudFormation - DELETE_COMPLETE - AWS::ApiGateway::Stage - ApiGatewayStage
CloudFormation - DELETE_COMPLETE - AWS::Lambda::Alias - GetAlias
CloudFormation - DELETE_IN_PROGRESS - AWS::ApiGateway::Deployment - ApiGatewayDeployment1508523706715
CloudFormation - DELETE_IN_PROGRESS - AWS::Lambda::Version - GetLambdaVersionlQVnYRFBJjet0buDpEdpz3WEyYblwfMV4ZrjMIklfsI
CloudFormation - DELETE_COMPLETE - AWS::Lambda::Version - GetLambdaVersionlQVnYRFBJjet0buDpEdpz3WEyYblwfMV4ZrjMIklfsI
CloudFormation - DELETE_COMPLETE - AWS::ApiGateway::Deployment - ApiGatewayDeployment1508523706715
CloudFormation - UPDATE_ROLLBACK_COMPLETE - AWS::CloudFormation::Stack - ens-alias-dev-dev
Serverless: Deployment failed!

  Serverless Error ---------------------------------------

  An error occurred while provisioning your stack: ApiGatewayStage - dev already exists.

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Forums:        forum.serverless.com
     Chat:          gitter.im/serverless/serverless

  Your Environment Information -----------------------------
     OS:                     win32
     Node Version:           6.11.3
     Serverless Version:     1.19.0

When I deploy an API with the plugin already installed, I do not have this problem. Am I missing a step here? Or should the plugin somehow be removing the existing "main stage" deployment before it recreates the new one in the new stack?

Again, super sweet plugin. Love it so far.

mbruning24 commented 7 years ago

FYI, just tested a workaround and it seems to work.

  1. Manually delete the stage deployment from API Gateway
  2. Re-run serverless deploy
  3. Profit

Would love for the plugin to catch and handle this, I think it would make it that much better.

HyperBrain commented 7 years ago

@mbruning24 This is a known issue. The problem here is, that Serverless creates the stage implicitly, i.e. it sets a stage name (string) in the CF deployment resource. That leads to the creation of the stage, but loses the connection to CF. The APIG stage deployed by Serverless is then kind of orphaned.

The alias plugin on the other hand handles its stage resources correctly, i.e. it creates a real stage resource in the CF stack. But that can only succeed if there is no stage there that is not controlled by CF. The correct handling by the plugin also enables nice features like setting the stage configuration from the serverless.yml (see stage in the README - enable APIG logging, etc).

I'm not really sure how the removal of the stage could be done when switching to the plugin for the first time, so that it is somehow automated. An option would be, that the plugin (when it analyzes the Serverless CF output) checks if there is an APIG deployment resource present with a stage name set as string and without a stage resource. In that case the plugin could manually delete the existing stage by using the APIG REST API.

What do you think? We should be sure that the behaviour is intuitive, as it is an automated deletion of the user's resources. Imo we can be quite certain to identify a first-use case in the way proposed above.

mbruning24 commented 7 years ago

@HyperBrain What if you just errored out after analyzing and saw an existing stage already there and said something along the lines of "You have to delete or rename the existing stage to continue"?

If not, I'm not seeing too much wrong with the automatic deletion of the stage deployment resources because in order to remove the plugin, you have to redeploy the package after removing all the aliases, so it's just as intrusive as that imo. Since the action is to replace the old deployment with a "main stage" anyways, it seems to follow that "out with the old, in with the new" is intuitive behavior.

If the plugin didn't hinge on needing another CF stack to manage the individual aliases, I would say try to just keep the existing reference on the main resource stack (with the methods and what not), but after looking through the code, that seems much easier said than done.

HyperBrain commented 7 years ago

What if you just errored out after analyzing and saw an existing stage already there and said something along the lines of "You have to delete or rename the existing stage to continue"?

I think that's the easiest and best solution. The user should immediately know what to do, without having the plugin doing the deletion (in case the user wants to postpone it for whatever reasons).