12. Infrastructure as Code
Tags: aws
Published: 2020-12-29 13:59:14

#Using AWS SAM to deploy the infrastructure.
Previously I had deployed the API Gateway, Lambda function and DynamoDB table by tinkering around in the AWS console. However the real challenge was using SAM to deploy the entire infrastructure using the SAM template for my [bio](http://blog.komlalebu.com/).

#[AWS Serverless Architecture Model](https://aws.amazon.com/serverless/sam/)
AWS Serverless Application Model (SAM) deploys=> DynamoDB + Lambda function + API gateway. 

Git: https://github.com/jicoing/git-komlalebu-sam
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qvtkcx94gm5hu0vhpp48.PNG)

* Step 1 - Prerequisites
The system must have the below installed:


[AWS profile set up](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)
[Python, preferably version > 3.6](https://www.python.org/downloads/)
[AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)
[Docker](http://docs.docker.oeynet.com/toolbox/toolbox_install_windows/)

* Step 2 - Create new AWS SAM project
Using the below command in cmd for windows.
>CMD

                          sam init


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wzr64kyiduxzb75rps44.PNG)

I chose the default project name, with the quick start template for [Hello World](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html) application. This created a directory structure that looks like this.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gcfkg0fd0e19f5767o0x.png)

The application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this sam-app directory. I modified the directory a little bit to remove the default `/hello_world` directory and created my own lambda handler `/komla_function` directory containing my python code.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/s5lc66lyf8zx30onus0t.PNG)

# Tree:
📦sam-app
 ┣ 📂.aws-sam
 ┃ ┣ 📂build
 ┃ ┃ ┣ 📂KomlalebuFunction
 ┃ ┃ ┃ ┣ 📜app.py
 ┃ ┃ ┃ ┗ 📜requirements.txt
 ┃ ┃ ┗ 📜template.yaml
 ┃ ┗ 📜build.toml
 ┣ 📂events
 ┃ ┗ 📜event.json
 ┣ 📂komla_function
 ┃ ┣ 📜app.py
 ┃ ┗ 📜requirements.txt
 ┣ 📂tests
 ┃ ┗ 📂unit
 ┃ ┃ ┣ 📜test_handler.py
 ┃ ┃ ┗ 📜__init__.py
 ┣ 📜.gitignore
 ┣ 📜packaged.yaml
 ┣ 📜README.md
 ┣ 📜SAM.md
 ┗ 📜template.yaml

# template.yaml

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r3ax3ii6bcalqdh1u5fz.png)

We can see the [template.yaml](https://github.com/jicoing/git-komlalebu-sam/blob/master/template.yaml) code below.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qq9f27th79hzzyx3orl4.PNG)

* Step 3 - Python code for lambda handler app.py. Runtime - Python 3.8.
I created a separate folder `komla_function` which contains the `app.py` file. The python script for the lambda function is defined in this file.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/v4g5i4nw9v38fhf3un9r.PNG)

* Step 4 - Modifying the template file.
I defined the below [Globals](https://github.com/aws/serverless-application-model/blob/master/docs/globals.rst), one for extented timeout of the API calls and the second one for [CORS](https://dev.to/lambdastore/enable-cors-for-aws-lambda-function-366a), because my browser was misbehaving.😀

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vx65eiep8omw5xmhs2m4.PNG)

The second change was defining the resources properly for my project requirements. [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html) - Defines the lambda function and its runtime information.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ffesqfx2asi1tryyycq6.PNG)

* Changed 
        
        CodeUri: komla_function/

* Added 

        Policies:
        # Give DynamoDB Full Access to your Lambda Function
        - AmazonDynamoDBFullAccess
To give the lambda function full access to the dynamoDB.

* Modified the API method to do a post.

        KomlalebuAPI:
          Type: Api 
          Properties:
            Path: /
            Method: post
* Finally added template for DynamoDB table creation. The name of my table is `komlalebuTable`. Refer [AWS::Serverless::SimpleTable](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-simpletable.html)

         komlalebuTable:
            Type: AWS::Serverless::SimpleTable
            Properties:
              PrimaryKey:
                 Name: id
                 Type: String
             TableName: komlalebuTable

* Step 5 - Build, package and deploy.
From the /sam-app directory in CMD running the below command compiles the source code along with all the dependencies into /sam-app/.aws-sam/build directory. It also updates template.yml. 
 
>sam build
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dn7zmmqcxslg1lyvb5d6.PNG)

Once the package is built the below command uploads the output-template and build artifacts as a .zip to my S3 bucket ci******evops.

>sam package
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nyuff8wpizfrogtej7ih.PNG)

The package is deployed from SAM CLI, where SAM packages the output-template as `package.yaml` and uploads  to S3 bucket. The name of my stack is `aws-sam-komlalebu`.

>sam deploy
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jll2vsg5y04wwu5x7ur6.PNG)

We can see below the stack created in cloudformation with the output-template file fetched from S3 bucket. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/s034p05kvnnrtqujig02.PNG)

With the events and resources created (API, Lambda function & DynamoDB table.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/74dke12gf0xljy267bqq.PNG)

#Simultaneously
We can verify in the respective AWS services for those resource creation status.

>DynamoDB
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/acr3dhxnp140o9b9lx9u.PNG)

>APIGateway
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/d15io0jyxqm05yehkupw.PNG)

>Lambda
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/aa7tg72cnmbdkdcylojo.PNG)

* Step 6 - Testing.
I went ahead and started testing the API from API gateway console (I am still struggling with Docker setup due to low `C: Drive` space for local testing). I was also consistently getting "message": "Internal server error" (502 Bad Gateway) due to json body to string conversion issue. Finally this [Article](https://stackoverflow.com/questions/57321398/aws-lambda-api-gateway-message-internal-server-error-502-bad-gateway/57321399#57321399?newreg=995dc2442b1544c3b78bde0462bacd22) from stackoverflow saved me. 😀 . The API was working fine.

>API call
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2jqnwdm3yet8mnuvnp2n.PNG)

The values passed to the lambda function by the API are also stored in the DynamoDB table created by SAM. It all came together.




>DynamoDB
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wn148bgmmza6ykov3kzp.PNG)

I went ahead and updated my website code in 'index.html' to hit the API url and it is working as expected i.e storing the visitor count in DynamoDB.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lbalgknzndos1h0iywkh.PNG)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0vobgcej8t0ytnl5d9l4.gif)