Automate application deployment
To deploy an application, you use both the AWS Panorama Application CLI and AWS Command Line Interface. After building the application container, you upload it and other assets to an Amazon S3 access point. You then deploy the application with the CreateApplicationInstance API.
For more context and instructions for using the scripts shown, follow the instructions in the sample application README
Sections
Build the container
To build the application container, use the build-container
command. This command builds a Docker
container and saves it as a compressed file system in the assets
folder.
Example 3-build-container.sh
CODE_PACKAGE=SAMPLE_CODE ACCOUNT_ID=$(aws sts get-caller-identity --output text --query 'Account') panorama-cli build-container --container-asset-name code_asset --package-path packages/${ACCOUNT_ID}-${CODE_PACKAGE}-1.0
You can also use command-line completion to fill in the path argument by typing part of the path, and then pressing TAB.
$
panorama-cli build-container --package-path packages/
TAB
Upload the container and register nodes
To upload the application, use the package-application
command. This command uploads assets from
the assets
folder to an Amazon S3 access point that AWS Panorama manages.
Example 4-package-app.sh
panorama-cli package-application
The AWS Panorama Application CLI uploads container and descriptor assets referenced by the package configuration
(package.json
) in each package, and registers the packages as nodes in AWS Panorama. You then refer to
these nodes in your application manifest (graph.json
) to deploy the application.
Deploy the application
To deploy the application, you use the CreateApplicationInstance API. This action takes the following parameters, among others.
-
ManifestPayload
– The application manifest (graph.json
) that defines the application's nodes, packages, edges, and parameters. -
ManifestOverridesPayload
– A second manifest that overrides parameters in the first. The application manifest can be considered as a static resource in the application source, where the override manifest provides deploy-time settings that customize the deployment. -
DefaultRuntimeContextDevice
– The target device. -
RuntimeRoleArn
– The ARN of an IAM role that the application uses to access AWS services and resources. -
ApplicationInstanceIdToReplace
– The ID of an existing application instance to remove from the device.
The manifest and override payloads are JSON documents that must be provided as a string value nested inside of
another document. To do this, the script loads the manifests from a file as a string and uses the jq tool
Example 5-deploy.sh – compose manifests
GRAPH_PATH="graphs/my-app/graph.json" OVERRIDE_PATH="graphs/my-app/override.json" # application manifest GRAPH=$(cat ${GRAPH_PATH} | tr -d '\n' | tr -d '[:blank:]') MANIFEST="$(jq --arg value "${GRAPH}" '.PayloadData="\($value)"' <<< {})" # manifest override OVERRIDE=$(cat ${OVERRIDE_PATH} | tr -d '\n' | tr -d '[:blank:]') MANIFEST_OVERRIDE="$(jq --arg value "${OVERRIDE}" '.PayloadData="\($value)"' <<< {})"
The deploy script uses the ListDevices API to get a list of registered devices in the current Region, and saves the users choice to a local file for subsequent deployments.
Example 5-deploy.sh – find a device
echo "Getting devices..." DEVICES=$(aws panorama list-devices) DEVICE_NAMES=($((echo ${DEVICES} | jq -r '.Devices |=sort_by(.LastUpdatedTime) | [.Devices[].Name] | @sh') | tr -d \'\")) DEVICE_IDS=($((echo ${DEVICES} | jq -r '.Devices |=sort_by(.LastUpdatedTime) | [.Devices[].DeviceId] | @sh') | tr -d \'\")) for (( c=0; c<${#DEVICE_NAMES[@]}; c++ )) do echo "${c}: ${DEVICE_IDS[${c}]} ${DEVICE_NAMES[${c}]}" done echo "Choose a device" read D_INDEX echo "Deploying to device ${DEVICE_IDS[${D_INDEX}]}" echo -n ${DEVICE_IDS[${D_INDEX}]} > device-id.txt DEVICE_ID=$(cat device-id.txt)
The application role is created by another script (1-create-role.sh
Example 5-deploy.sh – role ARN and replacement
arguments
# application role STACK_NAME=panorama-${NAME} ROLE_ARN=$(aws cloudformation describe-stacks --stack-name panorama-${PWD##*/} --query 'Stacks[0].Outputs[?OutputKey==`roleArn`].OutputValue' --output text) ROLE_ARG="--runtime-role-arn=${ROLE_ARN}" # existing application instance id if [ -f "application-id.txt" ]; then EXISTING_APPLICATION=$(cat application-id.txt) REPLACE_ARG="--application-instance-id-to-replace=${EXISTING_APPLICATION}" echo "Replacing application instance ${EXISTING_APPLICATION}" fi
Finally, the script puts all of the pieces together to create an application instance and deploy the application to the device. The service responds with an instance ID which the script stores for later use.
Example 5-deploy.sh – deploy application
APPLICATION_ID=$(aws panorama create-application-instance ${REPLACE_ARG} --manifest-payload="${MANIFEST}" --default-runtime-context-device=${DEVICE_ID} --name=${NAME} --description="command-line deploy" --tags client=sample --manifest-overrides-payload="${MANIFEST_OVERRIDE}" ${ROLE_ARG} --output text) echo "New application instance ${APPLICATION_ID}" echo -n $APPLICATION_ID > application-id.txt
Monitor the deployment
To monitor a deployment, use the ListApplicationInstances API. The monitor script gets the device ID and application instance ID from files in the application directory and uses them to construct a CLI command. It then calls in a loop.
Example 6-monitor-deployment.sh
APPLICATION_ID=$(cat application-id.txt) DEVICE_ID=$(cat device-id.txt) QUERY="ApplicationInstances[?ApplicationInstanceId==\`APPLICATION_ID\`]" QUERY=${QUERY/APPLICATION_ID/$APPLICATION_ID} MONITOR_CMD="aws panorama list-application-instances --device-id ${DEVICE_ID} --query ${QUERY}" MONITOR_CMD=${MONITOR_CMD/QUERY/$QUERY} while true; do $MONITOR_CMD sleep 60 done
When the deployment completes, you can view logs by calling the Amazon CloudWatch Logs API. The view logs script uses the
CloudWatch Logs GetLogEvents
API.
Example view-logs.sh
GROUP="/aws/panorama/devices/MY_DEVICE_ID/applications/MY_APPLICATION_ID" GROUP=${GROUP/MY_DEVICE_ID/$DEVICE_ID} GROUP=${GROUP/MY_APPLICATION_ID/$APPLICATION_ID} echo "Getting logs for group ${GROUP}." #set -x while true do LOGS=$(aws logs get-log-events --log-group-name ${GROUP} --log-stream-name code_node --limit 150) readarray -t ENTRIES < <(echo $LOGS | jq -c '.events[].message') for ENTRY in "${ENTRIES[@]}"; do echo "$ENTRY" | tr -d \" done sleep 20 done