AWS

AWS Using Serveless Framework To Create A Lambda Function

What are we talking about this time?

This time we are going to talk about how to expose our AWS lambda function over HTTP, which is exactly the same as what I did in my last AWS article, the thing is I did it all by hand in that article. This time we are going to be talking about the “Serverless Framework”.

Initial setup

If you did not read the very first part of this series of posts, I urge you to go and read that one now as it shows you how to get started with AWS, and create an IAM user : https://sachabarbs.wordpress.com/2018/08/30/aws-initial-setup/

Where is the code

The code for this post can be found here in GitHub : https://github.com/sachabarber/AWS/tree/master/Compute/ServerlessFrameworkLambda

What Is The Serverless Framework?

Picture says a 1000ns words and all that, here is a quick intro picture to the Serverless Framework.

image

At its heart it is an abstraction layer between your code and cloud, where it is cloud agnostic, your code may not be, but serverless itself is, and can be used quite happily against Azure/AWS etc etc

You should be asking yourself just how it does this abstraction over these cloud vendors? That’s a pretty neat trick isn’t it? Why yes, lets see how it works.

Its all mainly down to this rather clever abstraction file called “serverless.yml” which tells the framework what it should provision for you, and how things communicate, and should be setup.

Here is the example one for this demo app which is a simple AWS Lambda exposes as a GET REST API using AWS API Gateway

# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
#    docs.serverless.com
#
# Happy Coding!

service: ServerlessFrameworkLambda # NOTE: update this with your service name

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
  name: aws
  runtime: dotnetcore2.1

# you can overwrite defaults here
#  stage: dev
  region: eu-west-2

# you can add statements to the Lambda function's IAM Role here
#  iamRoleStatements:
#    - Effect: "Allow"
#      Action:
#        - "s3:ListBucket"
#      Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ]  }
#    - Effect: "Allow"
#      Action:
#        - "s3:PutObject"
#      Resource:
#        Fn::Join:
#          - ""
#          - - "arn:aws:s3:::"
#            - "Ref" : "ServerlessDeploymentBucket"
#            - "/*"

# you can define service wide environment variables here
#  environment:
#    variable1: value1

# you can add packaging information here
package:
  artifact: bin/release/netcoreapp2.1/deploy-package.zip
#  exclude:
#    - exclude-me.js
#    - exclude-me-dir/**

functions:
  hello:
    handler: CsharpHandlers::AwsDotnetCsharp.Handler::Hello

#    The following are a few example events you can configure
#    NOTE: Please make sure to change your handler code to work with those events
#    Check the event documentation for details
    events:
      - http:
          path: gettime
          method: get
          cors: true
#      - s3: ${env:BUCKET}
#      - schedule: rate(10 minutes)
#      - sns: greeter-topic
#      - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
#      - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
#      - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
#      - iot:
#          sql: "SELECT * FROM 'some_topic'"
#      - cloudwatchEvent:
#          event:
#            source:
#              - "aws.ec2"
#            detail-type:
#              - "EC2 Instance State-change Notification"
#            detail:
#              state:
#                - pending
#      - cloudwatchLog: '/aws/lambda/hello'
#      - cognitoUserPool:
#          pool: MyUserPool
#          trigger: PreSignUp

#    Define function environment variables here
#    environment:
#      variable2: value2

# you can add CloudFormation resource templates here
#resources:
#  Resources:
#    NewResource:
#      Type: AWS::S3::Bucket
#      Properties:
#        BucketName: my-new-bucket
#  Outputs:
#     NewOutput:
#       Description: "Description for the output"
#       Value: "Some output value"

You can see from the commented lines, how you might configure some of the other functionality you may need, and the docs are pretty decent. You can see more examples here : https://github.com/serverless/examples

But isn’t this quite limited? No not really, for example this is what the AWS offering looks like for serverless functions. This is pretty much exactly what AWS offers without the use of Serverless Framework.

imageAnd just to contrast here is the Azure offering.

image

Now as I say all you care about is the code, and the serverless.yml file, that governs the deployment/update/rollback. Serverless Framework will deal with the cloud provider for you. But just how do you get started with this framework?

The rest of this post will talk you through that.

Installation

The Serverless Framework is a node based command line installation, as such you will need to install node if you don’t already have it, download it from https://nodejs.org/en/download/. Once you have downloaded that, simply open a Node command line window and install the Serverless Framework as follows

npm install -g serverless

Credentials

The next thing you will need to do is associate your cloud provider credentials with the Serverless Framework command line, which you can read about here : https://serverless.com/framework/docs/providers/aws/guide/credentials/

For AWS this would look something like this

serverless config credentials --provider aws --key ANN7EXAMPLE --secret wJalrXUtnFYEXAMPLEKEY

Create A Project

Ok now that you are that far is, you can now create a project. This is easily done as follows, where this one uses a AWS c# template.

serverless create --template aws-csharp --path myService

NOTE : I found that I could not include “.” in the name of my service

Changes I Made At This Point

At this point I updated the serverless.yml file to the one I showed a minute ago, and I then updated the C# function to match almost exactly with the code from my last AWS article

using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;

[assembly:LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace AwsDotnetCsharp
{
    public class Handler
    {
        ITimeProcessor processor = new TimeProcessor();

        public APIGatewayProxyResponse Hello(
           APIGatewayProxyRequest apigProxyEvent, ILambdaContext context)
        {
            LogMessage(context, "Processing request started");
            APIGatewayProxyResponse response;
            try
            {
                var result = processor.CurrentTimeUTC();
                response = CreateResponse(result);

                LogMessage(context, "Processing request succeeded.");
            }
            catch (Exception ex)
            {
                LogMessage(context,
                    string.Format("Processing request failed - {0}", ex.Message));
                response = CreateResponse(null);
            }

            return response;
        }

        APIGatewayProxyResponse CreateResponse(DateTime? result)
        {
            int statusCode = (result != null) ?
                (int)HttpStatusCode.OK :
                (int)HttpStatusCode.InternalServerError;

            string body = (result != null) ?
                JsonConvert.SerializeObject(result) : string.Empty;

            var response = new APIGatewayProxyResponse
            {
                StatusCode = statusCode,
                Body = body,
                Headers = new Dictionary<string, string>
                {
                    { "Content-Type", "application/json" },
                    { "Access-Control-Allow-Origin", "*" }
                }
            };
            return response;
        }

        /// 
<summary>
        /// Logs messages to cloud watch
        /// </summary>

        void LogMessage(ILambdaContext ctx, string msg)
        {
            ctx.Logger.LogLine(
                string.Format("{0}:{1} - {2}",
                    ctx.AwsRequestId,
                    ctx.FunctionName,
                    msg));
        }
    }

  
}

Package A Project

Once you have edited your code, and potentially the serverless.yml file you need to package it, which for a C# project means running the build.cmd command in PowerShell. Internally this runs the AWS dot net command line extensions for Lambda https://github.com/aws/aws-extensions-for-dotnet-cli so you may find you also need to install those too. See my last AWS article on details about how to do that

Deploy The Function

Open the node command prompt at the place where you have your serverless.yml file, and run serverless deploy, and you should see something like this, where it is provisioning the various cloud provider items needed by your serverless.yml fileimageLet’s go and have a look what it created.  imageOk so we see 1 matching AWS function. CoolimageLet’s drill in a bit further, on the matching functionimageWe see the function does indeed have a matching API Gateway (just like in the previous AWS post I did)imageOk so now lets drill into the API GatewayimageSo far so good, we can see the resource created matches what we specified in our serverless.yml fileimageSo lets test the endpoint. Woohoo we see the time, its working, and this was significantly less hassle than the last article were I had to jump into IAM settings, API Gateway configuration, Lambda configuration, publish from Visual Studio/command line wizards. 

We have only really scratched the surface of using the Serverless Framework for Lambda/functions in the cloud, as I say the documentation is pretty good, it really is worth a try if you have not played with it before.


Beware

See ya later, not goodbye

Ok that’s it for now until the next post

 

 



Leave a comment