From 7d5b3c1666e372b6481a7c462cc339dc364884ce Mon Sep 17 00:00:00 2001 From: Chris Trowbridge Date: Tue, 1 Mar 2022 13:19:02 -0500 Subject: [PATCH] IGSDK R6.1 Release Fixes to OpenJDK installation Fixes to IG60 firmware update script Add script to update EdgeIQ runtime Add script to update OpenJDK runtime components --- edgeiq/README.md | 15 +- edgeiq/ggv2/README.md | 10 +- .../ggv2_fleet_provisioning_template.conf | 46 ++- .../ig60_ggv2_update_openjdk_components.sh | 72 +++++ .../ggv2/install_ggv2_fleet_provisioning.sh | 235 ++++++++------ edgeiq/ig60_update.sh | 45 +-- edgeiq/update_edge.sh | 298 ++++++++++++++++++ python/igsdk/__init__.py | 2 +- 8 files changed, 584 insertions(+), 139 deletions(-) create mode 100755 edgeiq/ggv2/ig60_ggv2_update_openjdk_components.sh create mode 100644 edgeiq/update_edge.sh diff --git a/edgeiq/README.md b/edgeiq/README.md index c01f00b..0765b7f 100644 --- a/edgeiq/README.md +++ b/edgeiq/README.md @@ -1,9 +1,16 @@ # Laird Connectivity IG60 EdgeIQ Support This folder contains various utilities for supporting the EdgeIQ Device Management service on the Laird Connectivity Sentrius™ IG60. -## Software Update -The script `ig60_update.sh` is used to perform a software update operation via the EdgeIQ cloud: +## Firmware Update +The script `ig60_update.sh` is used to perform a firmware update operation via the EdgeIQ cloud: -1. In the "Software" page in the UI, create a Software Package and attach the update file (.SWU) and the script `ig60_update.sh`. -2. Set the script to be `./ig60_update.sh UPDATE_FILE` where `UPDATE_FILE` is the name of the update .SWU file. +1. In the "Software" page in the UI, create a Software Package and attach the update file (.SWU) and the script `ig60_update.sh` +2. Set the script to be `./ig60_update.sh UPDATE_FILE` where `UPDATE_FILE` is the name of the update .SWU file +3. Apply the update to one or more IG60 devices via the UI + +## Edge Update +The script `update_edge.sh` is used to update the Edge agent to the latest version. + +1. In the "Software" page in the UI, create a Software Package and attach the script `update_edge.sh` +2. Set the script to be `./update_edge.sh /gg /tmp` 3. Apply the update to one or more IG60 devices via the UI diff --git a/edgeiq/ggv2/README.md b/edgeiq/ggv2/README.md index 956e299..58076d4 100644 --- a/edgeiq/ggv2/README.md +++ b/edgeiq/ggv2/README.md @@ -6,4 +6,12 @@ The script [`install_ggv2_fleet_provisioning.sh`](install_ggv2_fleet_provisionin The [`ggv2_fleet_provisioning_template.conf`](ggv2_fleet_provisioning_template.conf) configuration file specifies the parameters passed to the installation script. -For more info, see the Sentrius™ IG60 AWS IoT Greengrass V2 Getting Started Guide. \ No newline at end of file +For more info, see the Sentrius™ IG60 AWS IoT Greengrass V2 Getting Started Guide. + +## Update OpenJDK Dependency Components +The script [`ig60_ggv2_update_openjdk_components.sh`](ig60_ggv2_update_openjdk_components.sh) is used to update the OpenJDK dependency components on an IG60 device via the EdgeIQ cloud. These components **must** be kept in sync with the version of OpenJDK utilized in the installed IG60 firmware version. + +To perform the update: +1. In the "Software" page in the UI, create a Software Package and attach the OpenJDK dependency components tarball file (.tar.gz) provided by Laird Connectivity and the script `ig60_ggv2_update_openjdk_components.sh`. +2. Set the script to be `./ig60_ggv2_update_openjdk_components.sh OPENJDK_TARBALL_FILE` where `OPENJDK_TARBALL_FILE` is the name of the OpenJDK dependency components tarball file. +3. Apply the update to one or more IG60 devices via the UI \ No newline at end of file diff --git a/edgeiq/ggv2/ggv2_fleet_provisioning_template.conf b/edgeiq/ggv2/ggv2_fleet_provisioning_template.conf index 69b5761..ead5afa 100644 --- a/edgeiq/ggv2/ggv2_fleet_provisioning_template.conf +++ b/edgeiq/ggv2/ggv2_fleet_provisioning_template.conf @@ -12,29 +12,41 @@ ###################################################### # URL to Greengrass V2 Core Nucleus zip file -GGV2_CORE_FILE_URL="https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-2.5.2.zip" +# +# Information on the latest available release can be found on the AWS Greengrass GitHub page: +# https://github.com/aws-greengrass/aws-greengrass-nucleus/releases +# +# The latest version can be downloaded from the following location: +# https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-nucleus-latest.zip +# +# Alternatively, you can download a specific version from the following location, replacing +# with the desired version to download: +# https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-.zip +# ** REQUIRED ** +GGV2_CORE_FILE_URL="https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-2.5.6.zip" # Signature for the Greengrass V2 Core Nucelus zip file GGV2_CORE_SIGNATURE="" # Name of the resource tarball file # Default is "resources.tar.gz" -GGV2_RESOURCE_FILE="" +# ** REQUIRED ** +GGV2_RESOURCE_FILE="resources.tar.gz" # URL to root CA certificate (e.g., usually from Amazon) +# ** REQUIRED ** GGV2_ROOT_CA_CERT_URL="https://www.amazontrust.com/repository/AmazonRootCA1.pem" # Launch parameters for the Greengrass V2 Core Nucleus passed to the JVM # Default is "-Xmx128m -XX:+UseSerialGC -XX:TieredStopAtLevel=1" GGV2_NUCLEUS_LAUNCH_PARAMS="-Xmx128m -XX:+UseSerialGC -XX:TieredStopAtLevel=1" -# URL to Laird-provided OpenJDK dependencies tarball file -OPENJDK_FILE_URL="https://igprovdist-s3bucket-15bl34m4svimx.s3.amazonaws.com/lrd-openjdk-0.0.3.tar.gz" - -# Signature for the OpenJDK dependencies tarball file -OPENJDK_SIGNATURE="" +# Name of the OpenJDK dependency components tarball file +# ** REQUIRED ** +OPENJDK_FILE="" # URL to Greengrass V2 Fleet Provisioning plugin +# ** REQUIRED ** FLEET_PROVISIONING_PLUGIN_URL="https://d2s8p88vqu9w66.cloudfront.net/releases/aws-greengrass-FleetProvisioningByClaim/fleetprovisioningbyclaim-latest.jar" # Signature for the Greengrass V2 Fleet Provisioning plugin @@ -46,54 +58,71 @@ FLEET_PROVISIONING_PLUGIN_SIGNATURE="" # Path to device certificate # Default is "/var/media/mmcblk0p1/greengrass/v2/device.pem.crt" +# ** REQUIRED ** SYSTEM_CERTIFICATE_FILE_PATH="/var/media/mmcblk0p1/greengrass/v2/thingCert.crt" # Path to device private key # Default is "/var/media/mmcblk0p1/greengrass/v2/private.pem.key" +# ** REQUIRED ** SYSTEM_PRIVATE_KEY_PATH="/var/media/mmcblk0p1/greengrass/v2/privKey.key" # Path to Amazon Root CA certificate # Default is "/var/media/mmcblk0p1/greengrass/v2/AmazonRootCA1.pem" +# ** REQUIRED ** SYSTEM_ROOT_CA_PATH="/var/media/mmcblk0p1/greengrass/v2/AmazonRootCA1.pem" # Greengrass v2 Core Nucleus root path # Default is "/var/media/mmcblk0p1/greengrass/v2" +# ** REQUIRED ** SYSTEM_ROOT_PATH="/var/media/mmcblk0p1/greengrass/v2" # Greengrass v2 Nucleus version -SERVICES_AWS_GREENGRASS_NUCLEUS_VERSION="" +# This parameter should match the version of the Greengrass v2 Nucleus specified in +# GGV2_CORE_FILE_URL +# ** REQUIRED ** +SERVICES_AWS_GREENGRASS_NUCLEUS_VERSION="2.5.6" # Greengrass v2 root path +# ** REQUIRED ** SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_PATH="/var/media/mmcblk0p1/greengrass/v2" # AWS region +# ** REQUIRED ** SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_AWS_REGION="" # AWS IoT credential endpoint +# ** REQUIRED ** SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_IOT_CRED_ENDPOINT="" # AWS IoT role alias +# ** REQUIRED ** SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_ROLE_ALIAS="" # AWS IoT data endpoint +# ** REQUIRED ** SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_DATA_ENDPOINT="" # AWS IoT credential endpoint +# ** REQUIRED ** SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_CREDENTIAL_ENDPOINT="" # AWS IoT Greengrass V2 provisioning template +# ** REQUIRED ** SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_PROVISIONING_TEMPLATE="" # Path to claim certificate # Default is "/var/media/mmcblk0p1/greengrass/v2/claim-certs/claim.pem.crt" +# ** REQUIRED ** SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PATH="/var/media/mmcblk0p1/greengrass/v2/claim-certs/claim.pem.crt" # Path to claim certificate private key # Default is "/var/media/mmcblk0p1/greengrass/v2/claim-certs/claim.private.pem.key" +# ** REQUIRED ** SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PRIVATE_KEY="/var/media/mmcblk0p1/greengrass/v2/claim-certs/claim.private.pem.key" # Path to Amazon Root CA certificate # Default is "/var/media/mmcblk0p1/greengrass/v2/AmazonRootCA1.pem" +# ** REQUIRED ** SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_CA_PATH="/var/media/mmcblk0p1/greengrass/v2/AmazonRootCA1.pem" # Greengrass v2 Core thing name @@ -101,4 +130,5 @@ SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_CA_PATH="/var/media/ SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_NAME="" # Greengrass v2 Core thing group name +# ** REQUIRED ** SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_GROUP_NAME="" \ No newline at end of file diff --git a/edgeiq/ggv2/ig60_ggv2_update_openjdk_components.sh b/edgeiq/ggv2/ig60_ggv2_update_openjdk_components.sh new file mode 100755 index 0000000..9e9165c --- /dev/null +++ b/edgeiq/ggv2/ig60_ggv2_update_openjdk_components.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# Copyright 2022 Laird Connectivity +# +# IG60 helper script for updating the OpenJDK dependency components to support +# GGv2 which are stored on the SD card +# +# Usage: ig60_ggv2_update_openjdk_components.sh path/to/openjdk.tar.gz +# + +# Make verbose log, fail on uncaught errors +set -xe + +OPENJDK_TARBALL_FILE=$1 + +programname=$(basename $0) + +# +# Helper function to print out the script usage +# +show_usage() { + echo -e "Usage: $programname path/to/openjdk.tar.gz\n" +} + +# +# Helper function to print an error message and exit with a failure code +# +cleanup_and_fail(){ + echo $1 + rm -f ${OPENJDK_TARBALL_FILE} + exit 1 +} + +if [ $# -ne 1 ]; then + show_usage + cleanup_and_fail "Invalid arguments" + exit 1 +fi + +SDCARD_ROOT="/var/media/mmcblk0p1" + +# Link in the FS key +keyctl link @us @s + +# Stop GGv2 +echo "Stopping Greengrass V2" +systemctl stop ggv2runner + +# Since the 'ggv2sdmount' service is configured as 'PartOf' the main +# 'ggv2runner' service, it must be "manually" started here in order to properly +# re-mount the SD card. +echo "Re-mounting SD card" +systemctl start ggv2sdmount + +# Verify the SD card root exists +if [ ! -d "${SDCARD_ROOT}" ]; then cleanup_and_fail "SD card not found"; fi + +# Delete existing OpenJDK files +rm -rf $SDCARD_ROOT/jdk + +# Extract the tarball +echo "Extracting the OpenJDK dependency components tarball" +tar xzf ${OPENJDK_TARBALL_FILE} -C ${SDCARD_ROOT} --no-same-owner +if [ ! $? -eq 0 ]; then cleanup_and_fail "Unable to extract OpenJDK dependency components tarball"; fi + +# Delete the OpenJDK dependency components tarball +rm -f ${OPENJDK_TARBALL_FILE} + +# Restart GGv2 +echo "Restarting Greengrass V2" +systemctl start ggv2runner + +exit 0 diff --git a/edgeiq/ggv2/install_ggv2_fleet_provisioning.sh b/edgeiq/ggv2/install_ggv2_fleet_provisioning.sh index ca43bab..f9d60dd 100644 --- a/edgeiq/ggv2/install_ggv2_fleet_provisioning.sh +++ b/edgeiq/ggv2/install_ggv2_fleet_provisioning.sh @@ -15,18 +15,21 @@ GGV2_NUCLEUS_LAUNCH_PARAMS_DEFAULTS="-Xmx128m -XX:+UseSerialGC -XX:TieredStopAtL ## ---------- FUNCTIONS ---------- ## ------------------------------- -# Print to the systemd journal with a priority of "info" -function print_to_journal_info() { +# Print to standard out and the systemd journal with a priority of "info" +function log_info() { + echo $1 echo $1 | systemd-cat --priority="info" -t ${SCRIPT_IDENTIFIER_NAME} } -# Print to the systemd journal with a priority of "warning" -function print_to_journal_warning() { +# Print to standard out and the systemd journal with a priority of "warning" +function log_warning() { + echo $1 echo $1 | systemd-cat --priority="warning" -t ${SCRIPT_IDENTIFIER_NAME} } -# Print to the systemd journal with a priority of "err" -function print_to_journal_err() { +# Print to standard out and the systemd journal with a priority of "err" +function log_error() { + echo $1 echo $1 | systemd-cat --priority="err" -t ${SCRIPT_IDENTIFIER_NAME} } @@ -43,56 +46,30 @@ function verify_signature() { # Donwload, extract, and then subsequently remove the specified OpenJDk # tarball containing the necessary OpenJDK dependencies for GGv2 function handle_openjdk_dependencies() { - # Download OpenJDK tarball file - print_to_journal_info "Downloading OpenJDK tarball file" - wget -q ${OPENJDK_FILE_URL} -O ${SDCARD_ROOT}/openjdk-file.tar.gz - if [ ! $? -eq 0 ] - then - print_to_journal_err "ERROR: Unable to download OpenJDK tarball file" - error_detected=true - exit 1 - fi - - # Verify OpenJDK tarball file signature - if [ -z "$OPENJDK_SIGNATURE" ] - then - print_to_journal_info "Provided OpenJDK tarball file signature empty, skipping verification" - else - print_to_journal_info "Verifying OpenJDK tarball file signature" - if [ verify_signature ${SDCARD_ROOT}/openjdk-file.tar.gz $OPENJDK_SIGNATURE ] - then - print_to_journal_info "OpenJDK tarball file valid" - else - print_to_journal_err "ERROR: OpenJDK tarball file invalid!" - error_detected=true - exit 1 - fi - fi - # Extract OpenJDK tarball file - print_to_journal_info "Extracting OpenJDK tarball file" - tar xzf ${SDCARD_ROOT}/openjdk-file.tar.gz -C ${SDCARD_ROOT} --no-same-owner + log_info "Extracting OpenJDK tarball file" + tar xzf ./${OPENJDK_FILE} -C ${SDCARD_ROOT} --no-same-owner if [ ! $? -eq 0 ] then - print_to_journal_err "ERROR: Unable to extract OpenJDK tarball file" + log_error "ERROR: Unable to extract OpenJDK tarball file" error_detected=true exit 1 fi # Remove OpenJDK tarball file - print_to_journal_info "Removing OpenJDK tarball file" - rm ${SDCARD_ROOT}/openjdk-file.tar.gz + log_info "Removing OpenJDK tarball file" + rm ./${OPENJDK_FILE} } # Donwload, extract, and then subsequently remove the specified GGv2 Core # Nucleus zip file function handle_ggv2_core_nucleus_zip() { # Download GGv2 Core Nucleus zip file - print_to_journal_info "Downloading GGv2 Core Nucleus zip file" + log_info "Downloading GGv2 Core Nucleus zip file" wget -q ${GGV2_CORE_FILE_URL} -O ${SDCARD_ROOT}/ggv2-core-file.zip if [ ! $? -eq 0 ] then - print_to_journal_err "ERROR: Unable to download GGv2 Core Nucleus zip file" + log_error "ERROR: Unable to download GGv2 Core Nucleus zip file" error_detected=true exit 1 fi @@ -100,42 +77,42 @@ function handle_ggv2_core_nucleus_zip() { # Verify GGv2 Core Nucleus zip file signature if [ -z "$GGV2_CORE_SIGNATURE" ] then - print_to_journal_info "Provided GGv2 Core Nucleus zip file signature empty, skipping verification" + log_info "Provided GGv2 Core Nucleus zip file signature empty, skipping verification" else - print_to_journal_info "Verifying GGv2 Core Nucleus zip file signature" + log_info "Verifying GGv2 Core Nucleus zip file signature" if [ verify_signature ${SDCARD_ROOT}/ggv2-core-file.zip $GGV2_CORE_SIGNATURE ] then - print_to_journal_info "GGv2 Core Nucleus zip file valid" + log_info "GGv2 Core Nucleus zip file valid" else - print_to_journal_err "ERROR: GGv2 Core Nucleus zip file invalid!" + log_error "ERROR: GGv2 Core Nucleus zip file invalid!" error_detected=true exit 1 fi fi # Unzip the GGv2 Core Nucleus zip file - print_to_journal_info "Unzipping GGv2 Core Nucleus zip file" - unzip -q ${SDCARD_ROOT}/ggv2-core-file.zip -o -d ${GREENGRASS_CORE_DIR} + log_info "Unzipping GGv2 Core Nucleus zip file" + unzip -o -q ${SDCARD_ROOT}/ggv2-core-file.zip -d ${GREENGRASS_CORE_DIR} if [ ! $? -eq 0 ] then - print_to_journal_err "ERROR: Unable to unzip GGv2 Core Nucleus zip file" + log_error "ERROR: Unable to unzip GGv2 Core Nucleus zip file" error_detected=true exit 1 fi # Remove the GGv2 Core Nucleus zip file - print_to_journal_info "Removing GGv2 Core Nucleus zip file" + log_info "Removing GGv2 Core Nucleus zip file" rm ${SDCARD_ROOT}/ggv2-core-file.zip } # Donwload the specified root CA cert function handle_root_ca_cert() { # Download Root CA cert - print_to_journal_info "Downloading root CA cert" + log_info "Downloading root CA cert" wget -q ${GGV2_ROOT_CA_CERT_URL} -O ${GREENGRASS_ROOT_DIR}/AmazonRootCA1.pem if [ ! $? -eq 0 ] then - print_to_journal_err "ERROR: Unable to download root CA cert" + log_error "ERROR: Unable to download root CA cert" error_detected=true exit 1 fi @@ -144,11 +121,11 @@ function handle_root_ca_cert() { # Donwload the fleet provisioning plugin (.jar) function handle_fleet_provisioning_plugin() { # Download the GGv2 Fleet Provisioning plugin - print_to_journal_info "Downloading GGv2 Fleet Provisioning plugin" + log_info "Downloading GGv2 Fleet Provisioning plugin" wget -q ${FLEET_PROVISIONING_PLUGIN_URL} -O ${FLEET_PROVISIONING_PLUGIN_PATH} if [ ! $? -eq 0 ] then - print_to_journal_err "ERROR: Unable to download GGv2 Fleet Provisioning plugin" + log_error "ERROR: Unable to download GGv2 Fleet Provisioning plugin" error_detected=true exit 1 fi @@ -156,14 +133,14 @@ function handle_fleet_provisioning_plugin() { # Verify GGv2 Fleet Provisioning plugin signature if [ -z "$FLEET_PROVISIONING_PLUGIN_SIGNATURE" ] then - print_to_journal_info "Provided GGv2 Fleet Provisioning plugin signature empty, skipping verification" + log_info "Provided GGv2 Fleet Provisioning plugin signature empty, skipping verification" else - print_to_journal_info "Verifying GGv2 Fleet Provisioning plugin signature" + log_info "Verifying GGv2 Fleet Provisioning plugin signature" if [ verify_signature ${FLEET_PROVISIONING_PLUGIN_PATH} $FLEET_PROVISIONING_PLUGIN_SIGNATURE ] then - print_to_journal_info "GGv2 Fleet Provisioning plugin valid" + log_info "GGv2 Fleet Provisioning plugin valid" else - print_to_journal_err "ERROR: GGv2 Fleet Provisioning plugin invalid!" + log_error "ERROR: GGv2 Fleet Provisioning plugin invalid!" error_detected=true exit 1 fi @@ -172,7 +149,7 @@ function handle_fleet_provisioning_plugin() { # Generate the config.yaml file that is passed to the GGv2 setup function generate_config_yaml() { - print_to_journal_info "Generating GGv2 initial configuration file" + log_info "Generating GGv2 initial configuration file" CONFIG_YAML=${SDCARD_ROOT}/config.yaml echo -e "---" > ${CONFIG_YAML} @@ -218,7 +195,7 @@ function generate_config_yaml() { # Thing name is blank, so use "IG60_" plus the MAC address instead (without ':' as # AWS GGv2 does not accept them in thing names) THING_NAME=$(cat /sys/class/net/wlan0/address | awk '{ gsub(":",""); print "IG60_" toupper($0) }') - print_to_journal_info "Thing name is blank, using '${THING_NAME}' instead" + log_info "Thing name is blank, using '${THING_NAME}' instead" echo -e " ThingName: \"${THING_NAME}\"" >> ${CONFIG_YAML} else # Thing name isn't blank, so use the provided name @@ -227,11 +204,56 @@ function generate_config_yaml() { echo -e " ThingGroupName: \"${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_GROUP_NAME}\"" >> ${CONFIG_YAML} } +# Verify that required parameters are present +function verify_parameters() { + # Build a sh friendly list of required parameters + required_params="" + required_params="${required_params} GGV2_CORE_FILE_URL" + required_params="${required_params} GGV2_RESOURCE_FILE" + required_params="${required_params} GGV2_ROOT_CA_CERT_URL" + required_params="${required_params} OPENJDK_FILE" + required_params="${required_params} FLEET_PROVISIONING_PLUGIN_URL" + required_params="${required_params} SYSTEM_CERTIFICATE_FILE_PATH" + required_params="${required_params} SYSTEM_PRIVATE_KEY_PATH" + required_params="${required_params} SYSTEM_ROOT_CA_PATH" + required_params="${required_params} SYSTEM_ROOT_PATH" + required_params="${required_params} SERVICES_AWS_GREENGRASS_NUCLEUS_VERSION" + required_params="${required_params} SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_PATH" + required_params="${required_params} SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_AWS_REGION" + required_params="${required_params} SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_IOT_CRED_ENDPOINT" + required_params="${required_params} SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_ROLE_ALIAS" + required_params="${required_params} SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_DATA_ENDPOINT" + required_params="${required_params} SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_CREDENTIAL_ENDPOINT" + required_params="${required_params} SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_PROVISIONING_TEMPLATE" + required_params="${required_params} SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PATH" + required_params="${required_params} SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PRIVATE_KEY" + required_params="${required_params} SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_CA_PATH" + required_params="${required_params} SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_GROUP_NAME" + + param_missing=false + + for param_name in ${required_params}; do + # Retrieve the parameter's value from its name + param_value=$(eval echo "\$$param_name") + + if [ -z "${param_value}" ] + then + log_error "ERROR: ${param_name} is a required parameter" + param_missing=true + fi + done + + if [ "$param_missing" = true ] + then + exit 1 + fi +} + ## ------------------------------- ## --------- MAIN SCRIPT --------- ## ------------------------------- -print_to_journal_info "Beginning GGv2 installation" +log_info "Beginning GGv2 installation" # Link in the FS key keyctl link @us @s @@ -240,7 +262,7 @@ keyctl link @us @s # TODO: Make sure the uSD card is large enough if [ ! -b "/dev/mmcblk0" ] then - print_to_journal_err "ERROR: Could not find SD card" + log_error "ERROR: Could not find SD card" exit 1 fi @@ -253,8 +275,7 @@ SDCARD_ROOT="/var/media/mmcblk0p1" # - GGV2_RESOURCE_FILE # - GGV2_ROOT_CA_CERT_URL # - GGV2_NUCLEUS_LAUNCH_PARAMS -# - OPENJDK_FILE_URL -# - OPENJDK_SIGNATURE +# - OPENJDK_FILE # - FLEET_PROVISIONING_PLUGIN_URL # - FLEET_PROVISIONING_PLUGIN_SIGNATURE # - SYSTEM_CERTIFICATE_FILE_PATH @@ -274,59 +295,65 @@ SDCARD_ROOT="/var/media/mmcblk0p1" # - SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_CA_PATH # - SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_NAME # - SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_GROUP_NAME -print_to_journal_info "Reading in configuration parameters from $1" +log_info "Reading in configuration parameters from $1" source $1 # Print out the configuration parameters we just sourced -print_to_journal_info "GGV2_CORE_FILE_URL: ${GGV2_CORE_FILE_URL}" -print_to_journal_info "GGV2_CORE_SIGNATURE: ${GGV2_CORE_SIGNATURE}" -print_to_journal_info "GGV2_RESOURCE_FILE: ${GGV2_RESOURCE_FILE}" -print_to_journal_info "GGV2_ROOT_CA_CERT_URL: ${GGV2_ROOT_CA_CERT_URL}" -print_to_journal_info "GGV2_NUCLEUS_LAUNCH_PARAMS: ${GGV2_NUCLEUS_LAUNCH_PARAMS}" -print_to_journal_info "OPENJDK_FILE_URL: ${OPENJDK_FILE_URL}" -print_to_journal_info "OPENJDK_SIGNATURE: ${OPENJDK_SIGNATURE}" -print_to_journal_info "FLEET_PROVISIONING_PLUGIN_URL: ${FLEET_PROVISIONING_PLUGIN_URL}" -print_to_journal_info "FLEET_PROVISIONING_PLUGIN_SIGNATURE: ${FLEET_PROVISIONING_PLUGIN_SIGNATURE}" -print_to_journal_info "SYSTEM_CERTIFICATE_FILE_PATH: ${SYSTEM_CERTIFICATE_FILE_PATH}" -print_to_journal_info "SYSTEM_PRIVATE_KEY_PATH: ${SYSTEM_PRIVATE_KEY_PATH}" -print_to_journal_info "SYSTEM_ROOT_CA_PATH: ${SYSTEM_ROOT_CA_PATH}" -print_to_journal_info "SYSTEM_ROOT_PATH: ${SYSTEM_ROOT_PATH}" -print_to_journal_info "SERVICES_AWS_GREENGRASS_NUCLEUS_VERSION: ${SERVICES_AWS_GREENGRASS_NUCLEUS_VERSION}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_PATH: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_PATH}" -print_to_journal_info "SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_AWS_REGION: ${SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_AWS_REGION}" -print_to_journal_info "SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_IOT_CRED_ENDPOINT: ${SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_IOT_CRED_ENDPOINT}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_ROLE_ALIAS: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_ROLE_ALIAS}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_DATA_ENDPOINT: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_DATA_ENDPOINT}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_CREDENTIAL_ENDPOINT: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_CREDENTIAL_ENDPOINT}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_PROVISIONING_TEMPLATE: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_PROVISIONING_TEMPLATE}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PATH: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PATH}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PRIVATE_KEY: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PRIVATE_KEY}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_CA_PATH: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_CA_PATH}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_NAME: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_NAME}" -print_to_journal_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_GROUP_NAME: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_GROUP_NAME}" +log_info "GGV2_CORE_FILE_URL: ${GGV2_CORE_FILE_URL}" +log_info "GGV2_CORE_SIGNATURE: ${GGV2_CORE_SIGNATURE}" +log_info "GGV2_RESOURCE_FILE: ${GGV2_RESOURCE_FILE}" +log_info "GGV2_ROOT_CA_CERT_URL: ${GGV2_ROOT_CA_CERT_URL}" +log_info "GGV2_NUCLEUS_LAUNCH_PARAMS: ${GGV2_NUCLEUS_LAUNCH_PARAMS}" +log_info "OPENJDK_FILE: ${OPENJDK_FILE}" +log_info "FLEET_PROVISIONING_PLUGIN_URL: ${FLEET_PROVISIONING_PLUGIN_URL}" +log_info "FLEET_PROVISIONING_PLUGIN_SIGNATURE: ${FLEET_PROVISIONING_PLUGIN_SIGNATURE}" +log_info "SYSTEM_CERTIFICATE_FILE_PATH: ${SYSTEM_CERTIFICATE_FILE_PATH}" +log_info "SYSTEM_PRIVATE_KEY_PATH: ${SYSTEM_PRIVATE_KEY_PATH}" +log_info "SYSTEM_ROOT_CA_PATH: ${SYSTEM_ROOT_CA_PATH}" +log_info "SYSTEM_ROOT_PATH: ${SYSTEM_ROOT_PATH}" +log_info "SERVICES_AWS_GREENGRASS_NUCLEUS_VERSION: ${SERVICES_AWS_GREENGRASS_NUCLEUS_VERSION}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_PATH: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_PATH}" +log_info "SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_AWS_REGION: ${SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_AWS_REGION}" +log_info "SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_IOT_CRED_ENDPOINT: ${SERVICES_AWS_GREENGRASS_NUCLEUS_CONFIGURATION_IOT_CRED_ENDPOINT}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_ROLE_ALIAS: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_ROLE_ALIAS}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_DATA_ENDPOINT: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_DATA_ENDPOINT}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_CREDENTIAL_ENDPOINT: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_IOT_CREDENTIAL_ENDPOINT}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_PROVISIONING_TEMPLATE: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_PROVISIONING_TEMPLATE}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PATH: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PATH}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PRIVATE_KEY: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_CLAIM_CERTIFICATE_PRIVATE_KEY}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_CA_PATH: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_ROOT_CA_PATH}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_NAME: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_NAME}" +log_info "SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_GROUP_NAME: ${SERVICES_AWS_FLEET_PROVISIONING_BY_CLAIM_CONFIGURATION_TEMPLATE_PARAMETERS_THING_GROUP_NAME}" + +# Verify that required parameters are present +verify_parameters + +# Make sure any previous GGv2 instances are stopped +systemctl stop ggv2runner +systemctl stop ggv2sdmount # Prepare SD card -print_to_journal_info "Preparing SD card" +log_info "Preparing SD card" /usr/bin/ggv2_prepare_sdcard.sh # Extract resource tarball file -print_to_journal_info "Extracting resource tarball file" +log_info "Extracting resource tarball file" tar xzf ./${GGV2_RESOURCE_FILE} -C ${SDCARD_ROOT} --no-same-owner if [ ! $? -eq 0 ] then - print_to_journal_err "ERROR: Unable to extract resource tarball file" + log_error "ERROR: Unable to extract resource tarball file" exit 1 fi # Create the GGv2 Core directory GREENGRASS_CORE_DIR=${SDCARD_ROOT}/GreengrassCore -print_to_journal_info "Creating GGv2 Core directory" +log_info "Creating GGv2 Core directory" mkdir -p ${GREENGRASS_CORE_DIR} FLEET_PROVISIONING_PLUGIN_PATH=${GREENGRASS_CORE_DIR}/aws.greengrass.FleetProvisioningByClaim.jar # Create the GGv2 root directory GREENGRASS_ROOT_DIR=${SDCARD_ROOT}/greengrass/v2 -print_to_journal_info "Creating GGv2 root directory" +log_info "Creating GGv2 root directory" mkdir -p ${GREENGRASS_ROOT_DIR} # Move the claim certs to the GGv2 root directory @@ -367,31 +394,31 @@ fi JAVA_MODULES_PATH=${SDCARD_ROOT}/jdk/lib/modules if [ ! -e "${JAVA_MODULES_PATH}" ] then - print_to_journal_err "ERROR: Could not find OpenJDK dependencies" + log_error "ERROR: Could not find OpenJDK dependencies" exit 1 fi -print_to_journal_info "Found OpenJDK dependencies" +log_info "Found OpenJDK dependencies" # Verify we can run the GGv2 Core jar by printing the version -print_to_journal_info "Checking GGv2 Core Nucleus version" +log_info "Checking GGv2 Core Nucleus version" GREENGRASS_CORE_JAR=${GREENGRASS_CORE_DIR}/lib/Greengrass.jar cd ${SDCARD_ROOT} GGV2_CORE_ACTUAL_VERSION=$(/usr/bin/java -jar ${GREENGRASS_CORE_JAR} --version) if [ -z "$GGV2_CORE_ACTUAL_VERSION" ] then - print_to_journal_err "ERROR: Unable to read GGv2 Core Nucleus version" + log_error "ERROR: Unable to read GGv2 Core Nucleus version" exit 1 fi -print_to_journal_info "GGv2 Core Nucleus version read as: ${GGV2_CORE_ACTUAL_VERSION}" +log_info "GGv2 Core Nucleus version read as: ${GGV2_CORE_ACTUAL_VERSION}" if [ -z "$GGV2_NUCLEUS_LAUNCH_PARAMS" ] then - print_to_journal_info "GGv2 Nucleus launch parameters blank, using defaults (\"$GGV2_NUCLEUS_LAUNCH_PARAMS_DEFAULTS\")" + log_info "GGv2 Nucleus launch parameters blank, using defaults (\"$GGV2_NUCLEUS_LAUNCH_PARAMS_DEFAULTS\")" GGV2_NUCLEUS_LAUNCH_PARAMS="$GGV2_NUCLEUS_LAUNCH_PARAMS_DEFAULTS" fi # Run the GGv2 Core Nucleus setup -print_to_journal_info "Running GGv2 setup" +log_info "Running GGv2 setup" /usr/bin/java -Droot="${GREENGRASS_ROOT_DIR}" -Dlog.store=FILE -Dos.name="Linux" $GGV2_NUCLEUS_LAUNCH_PARAMS -jar ${GREENGRASS_CORE_JAR} \ --init-config ${SDCARD_ROOT}/config.yaml \ --trusted-plugin ${FLEET_PROVISIONING_PLUGIN_PATH} \ @@ -399,7 +426,7 @@ print_to_journal_info "Running GGv2 setup" --start false if [ ! $? -eq 0 ] then - print_to_journal_err "ERROR: Unable to setup GGv2 Core Nucleus" + log_error "ERROR: Unable to setup GGv2 Core Nucleus" exit 1 fi @@ -407,10 +434,10 @@ fi chown -R ggc_user:ggc_group ${GREENGRASS_ROOT_DIR} chown -R ggc_user:ggc_group ${GREENGRASS_CORE_DIR} -print_to_journal_info "GGv2 setup complete" +log_info "GGv2 setup complete" # Start GGv2 service -print_to_journal_info "Starting GGv2 service" +log_info "Starting GGv2 service" systemctl start ggv2runner -print_to_journal_info "GGv2 installation complete!" \ No newline at end of file +log_info "GGv2 installation complete!" \ No newline at end of file diff --git a/edgeiq/ig60_update.sh b/edgeiq/ig60_update.sh index 2509714..fc91806 100644 --- a/edgeiq/ig60_update.sh +++ b/edgeiq/ig60_update.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # IG60 Update Script for EdgeIQ # @@ -15,17 +15,17 @@ KEYFILE=/etc/ssl/misc/dev.crt UPDATEFILE=$1 cleanup_and_fail(){ - echo $1 - umount ${MOUNT_POINT} 2>&1 >/dev/null || true - rm -f ${UPDATEFILE} + echo "$1" + umount ${MOUNT_POINT} >/dev/null 2>&1 || true + rm -f "${UPDATEFILE}" exit 1 } # Read the configured bootside and actual root filesystem partition in use -BOOTSIDE=`fw_printenv -n bootside` || cleanup_and_fail "Cannot read bootside" -CURRENTROOT=`sed -rn 's/.*(ubiblock0_[0-9]).*/\1/p' /proc/cmdline` || cleanup_and_fail "Cannot read current rootfs" +BOOTSIDE=$(fw_printenv -n bootside) || cleanup_and_fail "Cannot read bootside" +CURRENTROOT=$(sed -rn 's/.*(ubiblock0_[0-9]).*/\1/p' /proc/cmdline) || cleanup_and_fail "Cannot read current rootfs" -if [ ${BOOTSIDE} == "a" ]; then +if [ "${BOOTSIDE}" = "a" ]; then UPDATESIDE="b" MIGRATE_DEVICE="/dev/ubi0_5" EXPECTEDROOT="ubiblock0_1" @@ -38,39 +38,42 @@ fi # Sanity check that the mounted rootfs matches the bootside; this # prevents applying an update again before a reboot (which can # lead to an unbootable filesystem!) -if [ ${CURRENTROOT} != ${EXPECTEDROOT} ]; then cleanup_and_fail "Inconsistent boot sides"; fi +if [ "${CURRENTROOT}" != "${EXPECTEDROOT}" ]; then cleanup_and_fail "Inconsistent boot sides"; fi -UPDATETAG=`fw_printenv -n fwkey` || UPDATETAG='stable' +# Set update tag if a different bootloader key was assigned in manufacturing. +# NOTE: Newer versions of fw_printenv return empty strings when variable is undefined +UPDATETAG=$(fw_printenv -n fwkey) || UPDATETAG='stable' +if [ -z "${UPDATETAG}" ]; then UPDATETAG="stable"; fi UPDATESEL="${UPDATETAG},main-${UPDATESIDE}" # Apply update echo "Applying update ${UPDATESEL} from ${UPDATEFILE}" -swupdate -b "2 3" -l 4 -v -i ${UPDATEFILE} -e ${UPDATESEL} -k ${KEYFILE} || cleanup_and_fail "Failed to perform swupdate" +swupdate -b "2 3" -l 4 -v -i "${UPDATEFILE}" -e "${UPDATESEL}" -k "${KEYFILE}" || cleanup_and_fail "Failed to perform swupdate" # Create mount point and mount the data device -mkdir -p ${MOUNT_POINT} || cleanup_and_fail "Failed to create ${MOUNT_POINT}" -mount -o noatime -t ubifs ${MIGRATE_DEVICE} ${MOUNT_POINT} || "Failed to mount ${MIGRATE_DEVICE}" +mkdir -p "${MOUNT_POINT}" || cleanup_and_fail "Failed to create ${MOUNT_POINT}" +mount -o noatime -t ubifs "${MIGRATE_DEVICE}" "${MOUNT_POINT}" || "Failed to mount ${MIGRATE_DEVICE}" # Wipe data patition -rm -rf ${MOUNT_POINT}/* || cleanup_and_fail "Cannot erase ${MOUNT_POINT}" +rm -rf "${MOUNT_POINT:?}"/* || cleanup_and_fail "Cannot erase ${MOUNT_POINT}" # Make sure the encryption key is available keyctl link "@us" "@s" || cleanup_and_fail "Cannot obtain encryption key" # Create encrypted directory and sync encrypted data -mkdir -p ${DATA_SECRET} || cleanup_and_fail "Cannot create ${DATA_SECRET}" -fscryptctl set_policy ${FSCRYPT_KEY} ${DATA_SECRET} || cleanup_and_fail "Cannot enable encryption" -rsync -rlptDW --exclude=.mounted /data/secret/ ${DATA_SECRET} || cleanup_and_fail "Cannot sync to ${DATA_SECRET}" +mkdir -p "${DATA_SECRET}" || cleanup_and_fail "Cannot create ${DATA_SECRET}" +fscryptctl set_policy "${FSCRYPT_KEY}" "${DATA_SECRET}" || cleanup_and_fail "Cannot enable encryption" +rsync -rlptDW --exclude=.mounted /data/secret/ "${DATA_SECRET}" || cleanup_and_fail "Cannot sync to ${DATA_SECRET}" # Migrate public data -mkdir -p ${DATA_PUBLIC} || cleanup_and_fail "Cannot create ${DATA_PUBLIC}" -rsync -rlptDW /data/public/ ${DATA_PUBLIC} || cleanup_and_fail "Cannot sync to ${DATA_PUBLIC}" -umount ${MOUNT_POINT} || cleanup_and_fail "Cannot unmount ${MOUNT_POINT}" +mkdir -p "${DATA_PUBLIC}" || cleanup_and_fail "Cannot create ${DATA_PUBLIC}" +rsync -rlptDW /data/public/ "${DATA_PUBLIC}" || cleanup_and_fail "Cannot sync to ${DATA_PUBLIC}" +umount "${MOUNT_POINT}" || cleanup_and_fail "Cannot unmount ${MOUNT_POINT}" # Change the bootside -fw_setenv bootside ${UPDATESIDE} || cleanup_and_fail "Cannot set bootside" +fw_setenv bootside "${UPDATESIDE}" || cleanup_and_fail "Cannot set bootside" # Delete the update file to save space -rm -f ${UPDATEFILE} +rm -f "${UPDATEFILE}" exit 0 diff --git a/edgeiq/update_edge.sh b/edgeiq/update_edge.sh new file mode 100644 index 0000000..57e47ad --- /dev/null +++ b/edgeiq/update_edge.sh @@ -0,0 +1,298 @@ +#!/bin/bash + +set -e + +# How to use: +# sudo ./update_edge_through_sw_update.sh + +# - create a software package through the edge portal +# - set the following command `sudo ./update_edge_through_sw_update.sh` +# - attach this file +# - run against target device + +# ASSUMPTIONS +# - linux-amd64 +# - systemd enabled +# - standard location /opt/edge/* + +# FLAGS to pass +# - writeable temporary location +WRITEABLE_TMP_LOCATION="/tmp" +# - location for config files +EDGE_PARENT_DIR="/opt" +# (- architecture?) + + +# make it look nice +INFO="INFO: " +TEST="TEST: " +CHECK="CHECK: " +PASSED="PASSED:" +WARN="WARN: " +ERROR="ERROR: " +RUN="RUN: " + +printf "\n==== CHECKING INPUTS ====\n\n" + +if [ ! -z "$1" ] +then + EDGE_PARENT_DIR=$1 + echo "$INFO received custom edge directory $EDGE_PARENT_DIR." +fi +echo "$INFO using edge location $EDGE_LOCATION." +if [ ! -z "$2" ] +then + WRITEABLE_TMP_LOCATION=$2 + echo "$INFO received custom tmp folder $WRITEABLE_TMP_LOCATION." +fi +echo "$INFO using tmp folder $WRITEABLE_TMP_LOCATION." + +# Set edge location +EDGE_LOCATION="$EDGE_PARENT_DIR/edge" + +# Laird specifics +# - architecture armv7 (thumb) - assume edge arm7 / edgectl armhf +# - kernel 4.19, bash, curl, wget available +# - Edge is installed "manually" (not via edgectl, but using the steps described in your documentation for manual installation) +# - There is a systemd unit file present on the device (in place before edge is installed). +# - assume systemctl start edge works ? +# - custom location /gg/edge (writable) +# + +printf "\n==== CHECKING IF CONDITIONS FOR UPDATE ARE MET ====\n\n" + +# config +# http would work too, as long as it only downloads files +STAGING_URL="https://api.stage.machineshop.io/api/v1/platform" +PROD_URL="https://machineshopapi.com/api/v1/platform" +# not used for now +STAGING_URL_NEW="https://api.stage.edgeiq.io/api/v1/platform" +PROD_URL_NEW="https://api.edgeiq.io/api/v1/platform" + +# test if boostrap.json is at the default location +BOOTSTRAP_FILE=$EDGE_LOCATION/conf/bootstrap.json +printf "$TEST check if bootstrap.json is at the specified location ($BOOTSTRAP_FILE).\n" +if [ ! -f $BOOTSTRAP_FILE ]; then + printf "$ERROR bootstrap.json not found, cannot proceed.\n" + exit 1; +else + printf "$PASSED found bootstrap.json.\n" +fi + +# test if systemd is set up in bootstrap.json +printf "$TEST check if bootstrap.json is configured to use systemd\n" + +BOOTSTRAP_CHECK_SYSTEMD="$(cat $BOOTSTRAP_FILE | grep systemd)" || ( printf "$ERROR edge is not configured to use systemd, cannot proceed.\n"; exit 1 ) +if [ -z "$BOOTSTRAP_CHECK_SYSTEMD" ] +then + printf "$ERROR edge is not configured to use systemd, cannot proceed.\n" + exit 1; +else + printf "$PASSED bootstrap.json is configured to use systemd.\n" +fi + +# test if conf.json is at the default location +CONF_FILE=$EDGE_LOCATION/conf/conf.json +printf "$TEST check if conf.json is at the specified location ($CONF_FILE).\n" +if [ ! -f $CONF_FILE ]; then + printf "$ERROR conf.json not found, cannot proceed.\n" + exit 1; +else + printf "$PASSED found conf.json.\n" +fi + +# test if /tmp folder is writable +TEST_FILE="$WRITEABLE_TMP_LOCATION/edgectl-testwrite.txt" +echo "TEST" > $TEST_FILE || ( echo "$ERROR cannot write to tmp location $WRITEABLE_TMP_LOCATION/." ) +rm $TEST_FILE || echo "$WARN cannot delete temporary file: $TEST_FILE." + +# test if there is enough free space (>80 MB) in /tmp +printf "$TEST check if there is enough free space in $WRITEABLE_TMP_LOCATION.\n" +FREE_SPACE=$(df -P "$WRITEABLE_TMP_LOCATION" | awk 'int($4)>81920{print $4}') || echo "$WARN cannot check free space." +if [ -z "$FREE_SPACE" ] +then + printf "$ERROR not enough free space in $WRITEABLE_TMP_LOCATION, cannot proceed.\n" + exit 1; +else + printf "$INFO enough space in $WRITEABLE_TMP_LOCATION: $FREE_SPACE.\n" +fi + +# test if staging or production url is set up in conf.json +printf "$TEST check which environment conf.json is configured to use.\n" + +ENV_DETECTED="" +PLATFORM_URL="" + +# check for staging +ENV_CHECK="$(cat $CONF_FILE | grep $STAGING_URL_NEW)" || echo "$INFO edge is not configured to use staging." +if [ -z "$ENV_CHECK" ] +then + printf "$INFO edge is not configured to use staging.\n" +else + printf "$PASSED conf.json is configured to use staging.\n" + ENV_DETECTED="staging" + PLATFORM_URL="$STAGING_URL_NEW" +fi + +# check for prod +ENV_CHECK="$(cat $CONF_FILE | grep $PROD_URL_NEW)" || echo "$INFO edge is not configured to use production." +if [ -z "$ENV_CHECK" ] +then + printf "$INFO edge is not configured to use production.\n" +else + printf "$PASSED conf.json is configured to use production.\n" + ENV_DETECTED="prod" + PLATFORM_URL="$PROD_URL_NEW" +fi + +# check for old staging +ENV_CHECK="$(cat $CONF_FILE | grep $STAGING_URL)" || echo "$INFO edge is not configured to use staging." +if [ -z "$ENV_CHECK" ] +then + printf "$INFO edge is not configured to use staging.\n" +else + printf "$PASSED conf.json is configured to use staging.\n" + ENV_DETECTED="staging" + PLATFORM_URL="$STAGING_URL_NEW" +fi + +# check for old prod +ENV_CHECK="$(cat $CONF_FILE | grep $PROD_URL)" || echo "$INFO edge is not configured to use production." +if [ -z "$ENV_CHECK" ] +then + printf "$INFO edge is not configured to use production.\n" +else + printf "$PASSED conf.json is configured to use production.\n" + ENV_DETECTED="prod" + PLATFORM_URL="$PROD_URL_NEW" +fi + +# test if env is set up correctly +printf "$TEST check if environment was detected.\n" + +if [ -z $ENV_DETECTED ] +then + printf "$ERROR environment was not detected, cannot proceed.\n" + exit 1; +else + printf "$PASSED environment was detected: $ENV_DETECTED.\n" +fi + +# test if platform URL is set up correctly +printf "$TEST check if platform url was detected.\n" + +if [ -z $PLATFORM_URL ] +then + printf "$ERROR platform URL was not detected, cannot proceed.\n" + exit 1; +else + printf "$PASSED platform URL was detected: $PLATFORM_URL.\n" +fi + +# test if systemd is set up correctly +printf "$TEST check if systemd unit file exists\n" +SYSTEMD_UNIT_FILE="/etc/systemd/system/edge.service" + +if [ ! -f $SYSTEMD_UNIT_FILE ] +then + printf "$ERROR edge systemd unit file is missing, cannot proceed.\n" + exit 1; +else + printf "$PASSED systemd unit file exists ($SYSTEMD_UNIT_FILE).\n" +fi + +# test if edgectl is installed +printf "$CHECK check if edgectl is installed.\n" + +EDGECTL_COMMAND="edgectl" +EDGECTL_DL_URL="" + +if [ -z "$(which edgectl)" ] +then + printf "$INFO edgectl is not installed, needs to be installed.\n" + # TODO install + + # test if architecture is supported + printf "$TEST if architecture is supported.\n" + ARCH=$(uname -m) + if [[ $ARCH == "x86_64" ]] + then + printf "$PASSED architecture is $ARCH / amd64 is supported.\n" + ARCH="amd64" + elif [[ $ARCH == "aarch64" ]] + then + printf "$PASSED architecture is $ARCH is supported.\n" + # set arch to armhf in case of arm7 (edgectl binary is named armhf) + ARCH="arm64" + elif [[ $ARCH == "armv7l" ]] + then + printf "$PASSED architecture is $ARCH is supported.\n" + # set arch to armhf in case of arm7 (edgectl binary is named armhf) + ARCH="armhf" + else + printf "$ERROR architecture $ARCH is not supported.\n" + exit 1 + fi + # download edgectl + wget $PLATFORM_URL/edgectl/latest/edgectl-linux-$ARCH-latest -O $WRITEABLE_TMP_LOCATION/edgectl || ( echo "$ERROR while downloading edgectl."; exit 1 ) + + # set binary executable + chmod +x $WRITEABLE_TMP_LOCATION/edgectl || ( echo "$ERROR while making edgectl executable."; exit 1 ) + EDGECTL_COMMAND="$WRITEABLE_TMP_LOCATION/edgectl" +else + printf "$INFO edgectl is installed.\n" +fi + +printf "$TEST check if edgectl is executable.\n" +$EDGECTL_COMMAND version || ( echo "$ERROR cannot execute edgectl."; exit 1 ) + + +printf "\n==== PROCEEDING WITH UPDATE ====\n\n" + +# modify bootstrap.json to set version to latest +BOOTSTRAP_FILE_TMP="$WRITEABLE_TMP_LOCATION/bootstrap.json" + +echo "COPYING bootstrap.json to $BOOTSTRAP_FILE_TMP" +cp $BOOTSTRAP_FILE $BOOTSTRAP_FILE_TMP + +echo "PRINTING bootstrap.json before changes" +cat $BOOTSTRAP_FILE_TMP + +echo "Replacing version with latest" +sed -i '/version/c\ \"version\" : \"latest\"' $BOOTSTRAP_FILE_TMP + +echo "Inserting install_dir into bootstrap.json if it doesn't exist" +BOOTSTRAP_CHECK_INSTALL_DIR="$(cat $BOOTSTRAP_FILE | grep install_dir)" || echo "$INFO install_dir is not set in bootstrap.json." +if [ -z "$BOOTSTRAP_CHECK_INSTALL_DIR" ] +then + sed -i "4i\ \"install_dir\":\""$EDGE_PARENT_DIR"\"," $BOOTSTRAP_FILE_TMP + printf "$PASSED updated bootstrap.json with install_dir.\n" +else + printf "$PASSED bootstrap.json contains install_dir.\n" +fi + +echo "PRINTING bootstrap.json after changes" +cat $BOOTSTRAP_FILE_TMP + +# call edgectl with update version (for now: just use latest) + +echo "$INFO preparing edgectl install command." + +EDGECTL_FLAGS="" + +echo "$INFO Detected environment is $ENV_DETECTED." +if [[ $ENV_DETECTED == "staging" ]] +then + EDGECTL_FLAGS="${EDGECTL_FLAGS} -s" + echo "$INFO Using staging environment." +else + echo "$INFO Using production environment." +fi + +EGECTL_LOG="$WRITEABLE_TMP_LOCATION/edgectl_install.log" +echo "$INFO command to run is:" +echo "$INFO $EDGECTL_COMMAND install $EDGECTL_FLAGS -b $BOOTSTRAP_FILE_TMP &> $EGECTL_LOG" +echo "$RUN executing edgectl install... will go dark now." + +# need to run this in the background, because edgectl will kill edge and therefore this script, too +nohup $EDGECTL_COMMAND install $EDGECTL_FLAGS -b $BOOTSTRAP_FILE_TMP &> "$EGECTL_LOG" & \ No newline at end of file diff --git a/python/igsdk/__init__.py b/python/igsdk/__init__.py index 148a3eb..833ae3d 100644 --- a/python/igsdk/__init__.py +++ b/python/igsdk/__init__.py @@ -2,4 +2,4 @@ logging.getLogger(__name__).addHandler(logging.NullHandler()) -__version__ = '6.0' +__version__ = '6.1'