Joseph Astrahan
Joseph Astrahan

Reputation: 9082

Destroy resources created via Serverless without destroying Lambda endpoints

I have the following resource defined in my serverless.yml file. Its working great to create the resource for all my different stages of development.

resources:
  Resources:
    uploadBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:service}-${self:custom.stage}-uploads
    visitsTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:custom.visitsTable}
        AttributeDefinitions:
          - AttributeName: userId
            AttributeType: S
          - AttributeName: visitId
            AttributeType: S
        KeySchema:
          - AttributeName: userId
            KeyType: HASH
          - AttributeName: visitId
            KeyType: RANGE
        ProvisionedThroughput:
            ReadCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.stage}}
            WriteCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.stage}}

Problem is... if I do sls remove while deleting the database it made it also deletes everything else including the lambda functions and their api gateway endpoints which I need to stay around since I have policies explicitly set for them. How do I tell serverless I want to delete just the database or S3 or whatever it is and not the rest?

Things I've Tried:

I deleted manually on AWS, but if you do this and do sls deploy it does not create the database again! So not sure best way to do this...

Entire Serverless.yml file

service: mydomain-api

# Use serverless-webpack plugin to transpile ES6/ES7
plugins:
  - serverless-webpack
  - serverless-domain-manager

custom:
  webpackIncludeModules: true
  stage: ${opt:stage, self:provider.stage}
  visitsTable: "${self:service}-visits-${self:custom.stage}"
  domains:
    prod: api.mydomain.com
    staging: staging-api.mydomain.com
    dev: dev-api.mydomain.com
  dynamoDbCapacityUnits:
    prod: 5
    staging: 2
    dev: 2
  customDomain:
    basePath: ""
    domainName: ${self:custom.domains.${self:custom.stage}}
    stage: "${self:custom.stage}"
    certificateName: "mydomain.com"
    createRoute53Record: true

provider:
  name: aws
  runtime: nodejs6.10
  stage: prod
  region: us-east-1
  environment:
    VISITS_TABLE: ${self:custom.visitsTable}

  # 'iamRoleStatement' defines the permission policy for the Lambda function.
  # In this case Lambda functions are granted with permissions to access DynamoDB.
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:DescribeTable
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource: "arn:aws:dynamodb:us-east-1:*:*"

functions:
  create:
    handler: src/visits/create.main
    events:
      - http:
          path: visits
          method: post
          cors: true
          authorizer: aws_iam
  get:
    handler: src/visits/get.main
    events:
      - http:
          path: visits/{id}
          method: get
          cors: true
          authorizer: aws_iam
  list:
    handler: src/visits/list.main
    events:
      - http:
          path: visits
          method: get
          cors: true
          authorizer: aws_iam
  update:
    handler: src/visits/update.main
    events:
      - http:
          path: visits/{id}
          method: put
          cors: true
          authorizer: aws_iam
  delete:
    handler: src/visits/delete.main
    events:
      - http:
          path: visits/{id}
          method: delete
          cors: true
          authorizer: aws_iam

resources:
  Resources:
    uploadBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:service}-${self:custom.stage}-uploads
    visitsTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:custom.visitsTable}
        AttributeDefinitions:
          - AttributeName: userId
            AttributeType: S
          - AttributeName: visitId
            AttributeType: S
        KeySchema:
          - AttributeName: userId
            KeyType: HASH
          - AttributeName: visitId
            KeyType: RANGE
        ProvisionedThroughput:
            ReadCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.stage}}
            WriteCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.stage}}

Upvotes: 13

Views: 30057

Answers (3)

Jordan
Jordan

Reputation: 1670

Set DeletionPolicy to "Retain" on the resources you don't want removed upon stack deletion and the rest of them will be removed when you run sls remove.

resources:
  Resources:
    uploadBucket:
      Type: AWS::S3::Bucket
      DeletionPolicy: Retain
      ...

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html

Upvotes: 5

Matt D
Matt D

Reputation: 3496

The Serverless Framework generates a CloudFormation template.

When you run a CloudFormation template for the first time, it creates all of the resources.

When you run it a future time, it compares the new version with the previous version, and generates a plan to make up the difference. That may be adding or removing resources. There are some exceptions to this, normally data resource types, like S3 buckets, which need to be force deleted.

So, to answer your question, you should remove the resources that you don't want anymore from the serverless.yml file, and do a sls deploy again.

Upvotes: 2

dom
dom

Reputation: 11972

The Serverless Framework documentation says the following about sls remove:

The sls remove command will remove the deployed service, defined in your current working directory, from the provider.

So sls remove is not the way to go. Just remove the visitsTable resource from your serverless.yaml and run sls deploy again. The Serverless Framework uses AWS CloudFormation under the hood. So deleting things manually is no good idea. Just keep in mind: Resources created as part of an AWS CloudFormation stack must be managed and modified through stack updates. Maybe this is a good read: https://virtualbonzo.com/2017/12/11/did-you-manually-delete-a-resource-created-by-aws-cloudformation/

Upvotes: 17

Related Questions