3
votes

I have a setup where I am using CodeCommit as my repository to store lambda functions and CodePipeline using AWS SAM to deploy and create lambda functions.

I would like to deploy the lambda functions into different environments such as QA, staging, and Prod. I have used the AWS Parameters store to reference my variables.

Below is my template.yaml file that I have set up that creates a lambda function and it uses AWS parameter store to reference the vairables

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Test    

Parameters:
  BucketName:
    Description: 'Required. Bucket Name'
    Type: 'AWS::SSM::Parameter::Value<String>'
    Default: 'MyBucketname' 

  CSVPath:
    Description: 'Required. Configkey Name'
    Type: 'AWS::SSM::Parameter::Value<String>'
    Default: 'MyCSVPath' 

Resources:
    GetOrdersFunction:
        Type: AWS::Serverless::Function 
        Properties:
            CodeUri: ./LambdaCode
            Handler: app.lambda_handler
            FunctionName: app
            Runtime: python3.6
            Description: 'staging'
            Environment: 
                Variables:
                    BucketName: !Ref BucketName
                    CSVPath: !Ref CSVPath
            Events:
              HelloWorld:
                    Type: Api
                    Properties:
                        Path: /orders
                        Method: get  

I am able to define variables in my template.yaml for deployment but I am not sure how I can define it for different environments (prod or qa).

When the pipeline triggers it should deploy to QA environment using QA variables and deploy to prod using prod variables which will be defined in AWS Parameter store

What changes should I make in my template.yaml file to enable deploying to different environments?

3
do you have one code pipeline per environment or at least different stage or action per environment ? you can pass ParameterOverrides from codepipeline to pass right parameter values {"BucketName":"/BUCKETNAME/DEV","CSVPath":"/CSVPATH/DEV"}Balu Vyamajala
yes i have one code pipeline per environmentBilal Yousaf

3 Answers

3
votes

As Meir has mentioned, You can use parameters and condition functionality in cloudformation to do that, for example, you will add a parameter section as follow:

Parameters:
  Stage:
    Type: String
    Default: staging
    Description: Parameter for getting the deployment stage

then a mapping section with a map to hold the environment variables for all your stages

Mappings:
  StagesMap:
    staging:
      CONFIG_BUCKET: staging-bucket-name
      CONFIG_KEY: source-data-key-path
    prod:
      CONFIG_BUCKET: prod-bucket-name
      CONFIG_KEY: source-data-key-path

then your function can use the variables based on which environment you are in:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: CD Demo Lambda
Resources:
  CDDemoLambda:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: lambda_function.lambda_handler
      Runtime: python3.6
      CodeUri: ./LambdaCode
      FunctionName: ApigatewayLambda
      AutoPublishAlias: ApiLambda
      Description: 'Lambda function validation'
      MemorySize: 128
      Timeout: 30
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /getazs
            Method: get
      Environment:
        Variables:
          CONFIG_BUCKET: !FindInMap
            - StagesMap
            - Ref: Stage
            - CONFIG_BUCKET
          CONFIG_KEY: !FindInMap
            - StagesMap
            - Ref: Stage
            - CONFIG_KEY

Now when you are calling your sam to deploy command, you need to define which stage you are deploying to. ex:

sam deploy --parameter-overrides Stage=prod

Your complete cloudformation template should look like this:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: CD Demo Lambda

Parameters:
  Stage:
    Type: String
    Default: staging
    Description: Parameter for getting the deployment stage

Mappings:
  StagesMap:
    staging:
      CONFIG_BUCKET: staging-bucket-name
      CONFIG_KEY: source-data-key-path
    prod:
      CONFIG_BUCKET: prod-bucket-name
      CONFIG_KEY: source-data-key-path


Resources:
  CDDemoLambda:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: lambda_function.lambda_handler
      Runtime: python3.6
      CodeUri: ./LambdaCode
      FunctionName: ApigatewayLambda
      AutoPublishAlias: ApiLambda
      Description: 'Lambda function validation'
      MemorySize: 128
      Timeout: 30
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /getazs
            Method: get
      Environment:
        Variables:
          CONFIG_BUCKET: !FindInMap
            - StagesMap
            - Ref: Stage
            - CONFIG_BUCKET
          CONFIG_KEY: !FindInMap
            - StagesMap
            - Ref: Stage
            - CONFIG_KEY
2
votes

You're looking for the mappings and FindInMap functionality. Take a look at the examples and switch between RegionMap to EnvMap, it will fit perfectly for your use case.

The expectation here is that according to a given argument (Parameter) a set of variables will be taken, this is exactly what mapping does.

2
votes

CloudFormation template default parameters can be overridden from code pipeline by passing parameterOverrides

From Console:

  • Add/Edit Action

  • Action provider Cloudformation

  • Action Mode

  • Create/Update a stack

  • Advanced -> Parameter Overrides

    {"BucketName":"/BUCKETNAME/DEV","CSVPath":"/CSVPATH/DEV"}
    

If codepipeline is created from a Cloudformation template:

                  - Name: DeployMyStack
                    InputArtifacts:
                        - Name: Artifacts
                    ActionTypeId:
                        Category: Deploy
                        Owner: AWS
                        Version: 1
                        Provider: CloudFormation
                    Configuration:
                        ActionMode: 'CREATE_UPDATE'
                        Capabilities: CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND
                        ParameterOverrides: !Sub
                            - '{"BucketName":"/BUCKETNAME/${Env}","CSVPath":"/CSVPATH/${Env}'
                            - {
                                  Env: !Ref Environment,
                              }
                        RoleArn: !Ref CloudFormationServiceRoleArn
                        StackName: !Sub
                            - Gl${ENV}-My-Stack
                            - { ENV: !Ref Environment }
                        TemplatePath: 'Artifacts::MyTemplate.yaml'