A shell script to deploy Lambda functions as components of GreengrassV2 to edge devices.

nkmrkzz

kazutaka nakamura

Posted on November 9, 2022

A shell script to deploy Lambda functions as components of GreengrassV2 to edge devices.

I wrote a shell script to deploy Lambda functions as components of GreengrassV2 to edge devices.

I write some programs for edge devices using Lambda functions (Node.js) + GreengrassV2.
Every time I do the test on the edge device, I have to have a lot of manual operations, deploying Lambda functions, creating Greengrass Components, and deploying them to the edge device… , so I wrote a shell script to automate these processes.

Why I wrote a shell script

  • I developed the lambda function using Serverless Framework v2.
  • I created a Greengrass Component using the AWS Console.
  • I have a lot of manual operations, I have to set lambda function's version, topic that I want attach to the function, environment variables and so on.

I know AWS CLI makes it easy to complete the above operations, so I wrote a shell script which contains AWS CLI commands.

How to set up by AWS Console
https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/import-lambda-function-console.html

How to set up by AWS CLI
https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/import-lambda-function-cli.html

Operations Before/After

Before

  • Deploy the Lambda function by Serverless Framework v2
    • sls deploy …
  • Open the AWS Console and move to IoT Core menu
  • Create the Greengrass Component
    • Set the Lambda function's version
    • Update the Component's version
    • Set the topic that I want to attach to the Lambda function
    • Set the environment variables
  • Create the Greengrass Deployment settings
    • Just click some times

After

  • Run the script
    • sh ./scripts/deploy.sh

What I did

I wrote a shell script for the Lambda function's deployment based on the article which I wrote before.

https://zenn.dev/nkmrkz/articles/greengrass-deployment
(Japanese only)

Folder

scripts
|- template
| |- component_template.json
| |- deployment_template.json
|- deployment.sh
Enter fullscreen mode Exit fullscreen mode

The sample lambda function is like that

  • Lambda function can get a message from the MQTT topic and publish a message to the topic.
  • it use some environment variables.

So I need set the following things to Greengrass component.

  • Lambda function's version
  • Component's version
  • Topic that I want to attach to the Lambda function
    • it can have wildcards
  • Environment variables

template/component.json

{
  "lambdaFunction":{
    "lambdaArn": "LambdaFunctionのARN:$LAMBDA_LATEST_VERSION",
    "componentName": "{ComponentName}",
    "componentVersion": "$CUSTOM_COMPONENT_VERSION",
    "componentDependencies": {
      "aws.greengrass.LambdaLauncher": {
        "versionRequirement": ">=2.0.0 <3.0.0",
        "dependencyType": "HARD"
      },
      "aws.greengrass.TokenExchangeService": {
        "versionRequirement": ">=2.0.0 <3.0.0",
        "dependencyType": "HARD"
      },
      "aws.greengrass.LambdaRuntimes": {
        "versionRequirement": ">=2.0.0 <3.0.0",
        "dependencyType": "SOFT"
      }
    },
    "componentLambdaParameters": {
      "eventSources": [
        {
          "topic": "{Topic Name}",
          "type": "IOT_CORE"
        }
      ],
      "maxQueueSize": 1000,
      "maxInstancesCount": 100,
      "maxIdleTimeInSeconds": 60,
      "timeoutInSeconds": 3,
      "statusTimeoutInSeconds": 60,
      "pinned": true,
      "inputPayloadEncodingType": "json",
      "environmentVariables": {
        "STAGE": "$STAGE_NAME",
        "ENV1": "$ENV1",
        "ENV2": "$ENV2"
      },
      "linuxProcessParams": {
        "isolationMode": "NoContainer",
        "containerParams": {}
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

templates/deployment.json

{
  "targetArn": "arn:aws:iot:ap-northeast-1:$ACCOUNT_ID:thinggroup/{TargetGroupForDeployment}",
  "deploymentName": "Deployment Setting Name",
  "components": {
      "aws.greengrass.Cli": {
          "componentVersion": "2.7.0"
      },
      "aws.greengrass.LegacySubscriptionRouter": {
          "componentVersion": "2.1.6",
          "configurationUpdate": {
              "merge": "{\"subscriptions\":{\"{SettingName}\":{\"id\":\"{Identifier}\",\"source\":\"component:{LambdaFunctionName}\",\"subject\":\"#\",\"target\":\"cloud\"}}}"
          },
          "runWith": {}
      },
      "aws.greengrass.Nucleus": {
          "componentVersion": "2.7.0",
          "runWith": {}
      },
      "{ComponentName}": {
          "componentVersion": "$CUSTOM_COMPONENT_VERSION",
          "runWith": {}
      }
  },
  "deploymentPolicies": {
      "failureHandlingPolicy": "DO_NOTHING",
      "componentUpdatePolicy": {
          "timeoutInSeconds": 60,
          "action": "NOTIFY_COMPONENTS"
      },
      "configurationValidationPolicy": {
          "timeoutInSeconds": 60
      }
  },
  "iotJobConfiguration": {}
}
Enter fullscreen mode Exit fullscreen mode

deploy.sh

#!/bin/bash
echo "StageName(dev/stg) : "
read stage_name

echo "start lambda function deployment"

./node_modules/.bin/sls deploy --stage $stage_name --aws-profile {AWS CLI Profile Name}

env1=`grep "ENV1=" ./scripts/.secrets | awk -F "=" '{print$2}'`
env2=`grep "ENV2=" ./scripts/.secrets | awk -F "=" '{print$2}'`
account_id=`aws sts get-caller-identity --profile {AWS CLI Profile Name} --query "Account" |sed -e 's/"//g'`

# component version: $LambdaLtestVersion.0.0
lambda_latest_version=`aws lambda  list-versions-by-function --function-name {Function Name} --query 'Versions[-1].Version' --profile {AWS CLI Profile Name}| sed -e 's/"//g'`
custom_component_version=$lambda_latest_version.0.0

echo "create component.json"
cat ./scripts/templates/component_template.json | sed -e "s/\$ENV1/$env1/g"| sed -e "s/\$ENV2/$env2/g"| sed -e "s/\$CUSTOM_COMPONENT_VERSION/$custom_component_version/g" | sed -e "s/\$LAMBDA_LATEST_VERSION/$lambda_latest_version/g" | sed -e "s/\$STAGE_NAME/$stage_name/g" | sed -e "s/\$ACCOUNT_ID/$account_id/g" > ./scripts/component.json

echo "create deployment.json"
cat ./scripts/templates/deployment_template.json | sed -e "s/\$CUSTOM_COMPONENT_VERSION/$custom_component_version/g" | sed -e "s/\$STAGE_NAME/$stage_name/g" | sed -e "s/\$ACCOUNT_ID/$account_id/g" > ./scripts/deployment.json

echo "start create greengrass component"
aws greengrassv2 create-component-version --cli-input-json fileb://scripts/component.json --profile {AWS CLI Profile Name}

echo "start create greengrass deployment"
aws greengrassv2 create-deployment --cli-input-json fileb://scripts/deployment.json --profile {AWS CLI Profile Name}
Enter fullscreen mode Exit fullscreen mode
  • The script replace the value which is needed to deploy When it runs.
  • I put some values on .secret
  • I put some private values on .secret
    • grep "ENV2=" ./scripts/.secrets | awk -F "=" '{print$2}'
  • By using AWS CLI, The script can get the AWS account ID and latest lambda version deployed in this script.
    • aws sts get-caller-identity - profile {AWS CLI Profile Name} - query "Account" |sed -e 's/"//g'
    • aws lambda list-versions-by-function - function-name {Function Name} - query 'Versions[-1].Version' - profile {AWS CLI Profile Name}| sed -e 's/"//g'
  • The script dose not have any error handling. I will add them later, maybe.

.secrets

ENV1=xxxxx
ENV2=yyyyy
Enter fullscreen mode Exit fullscreen mode

.gitignore(抜粋)

.secrets
component.json
deployment.json
Enter fullscreen mode Exit fullscreen mode

That's all. Keep Playing!

💖 💪 🙅 🚩
nkmrkzz
kazutaka nakamura

Posted on November 9, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related