Skip to content

Instantly share code, notes, and snippets.

@imrehg
Last active June 16, 2017 12:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imrehg/361405a0e6153470c49bd63b9960924a to your computer and use it in GitHub Desktop.
Save imrehg/361405a0e6153470c49bd63b9960924a to your computer and use it in GitHub Desktop.
#!/bin/bash
set -o pipefail
# Help function
function update-resin-supervisor-help {
cat << EOF
Wrapper to run supervisor agent updates on resin distributions.
$0 <OPTION>
Options:
-h, --help
Display this help and exit.
-i <SUPERVISOR IMAGE>, --supervisor-image <SUPERVISOR IMAGE>
Set supervisor image to update to.
-t <SUPERVISOR TAG>, --supervisor-tag <SUPERVISOR TAG>
Set supervisor tag to update to.
EOF
}
# Parse arguments
while [[ $# > 0 ]]; do
arg="$1"
case $arg in
-h|--help)
update-resin-supervisor-help
exit 0
;;
-i|--supervisor-image)
if [ -z "$2" ]; then
log ERROR "\"$1\" argument needs a value."
fi
UPDATER_SUPERVISOR_IMAGE=$2
shift
;;
-t|--supervisor-tag)
if [ -z "$2" ]; then
log ERROR "\"$1\" argument needs a value."
fi
UPDATER_SUPERVISOR_TAG=$2
shift
;;
--cache)
CACHE=yes
;;
*)
log ERROR "Unrecognized option $1."
;;
esac
shift
done
# Don't souce before parsing args - resin-vars parses args too
source /usr/sbin/resin-vars
# A temporary file used until next reboot
UPDATECONF=/tmp/update-supervisor.conf
if [ -z "$API_ENDPOINT" -o -z "$CONFIG_PATH" ]; then
echo "Environment variables API_ENDPOINT and CONFIG_PATH must be set."
exit 1
fi
# If the user api key exists we use it instead of the deviceApiKey as it means we haven't done the key exchange yet
read DEVICE_API_KEY DEVICE_ID <<<$(jq -r '.apiKey // .deviceApiKey,.deviceId' $CONFIG_PATH)
if [ -z "$DEVICE_API_KEY" -o -z "$DEVICE_ID" ]; then
echo "JSON in config file $CONFIG_PATH must have apiKey or deviceApiKey, and deviceId attributes."
exit 1
fi
function error_handler {
# If docker pull fails, start the old supervisor again and exit
rm -rf $UPDATECONF
systemctl start resin-supervisor
exit 1
}
trap 'error_handler $LINENO' ERR
# Detect containers engine
if which docker &>/dev/null; then
DOCKER=docker
elif which rce &>/dev/null; then
DOCKER=rce
else
error_handler $LINENO "no container engine detected"
fi
# Get target supervisor tag from API.
# The script will exit if curl does not get a valid response.
# Getting data separately before reading it fixes error handling.
echo "Getting image name and tag..."
if data=$(curl --silent --header "User-Agent:" --compressed "$API_ENDPOINT/v1/supervisor_release?\$select=supervisor_version,image_name&\$filter=device/any(d:d/id%20eq%20$DEVICE_ID)&apikey=$DEVICE_API_KEY" | jq -e -r '.d[0].supervisor_version,.d[0].image_name'); then
echo "Supervisor configuration found from API."
if [ -n "$UPDATER_SUPERVISOR_TAG" ] || [ -n "$UPDATER_SUPERVISOR_IMAGE" ]; then
echo "WARN: Ignore image/tag arguments as API overrides them."
fi
read tag image_name <<<$data
# Check that we didn't somehow get an empty tag version.
if [ -z "$tag" ]; then
error_handler $LINENO "no tag received"
fi
else
echo "No supervisor configuration found from API. Using arguments for image and tag."
source /etc/resin-supervisor/supervisor.conf
if [ -z "$UPDATER_SUPERVISOR_TAG" ]; then
# Try to get the tag from supervisor.conf
if [ -n "$SUPERVISOR_TAG" ]; then
UPDATER_SUPERVISOR_TAG=$SUPERVISOR_TAG
else
echo "ERROR: No tag argument provided."
error_handler $LINENO "no tag argument provided"
fi
fi
if [ -z "$UPDATER_SUPERVISOR_IMAGE" ]; then
UPDATER_SUPERVISOR_IMAGE=$SUPERVISOR_IMAGE
fi
echo "Set based on arguments image=$UPDATER_SUPERVISOR_IMAGE and tag=$UPDATER_SUPERVISOR_TAG."
image_name=$UPDATER_SUPERVISOR_IMAGE
tag=$UPDATER_SUPERVISOR_TAG
fi
# Get image id of tag. This will be non-empty only in case it's already downloaded.
echo "Getting image id..."
imageid=$($DOCKER inspect -f '{{.Id}}' "$image_name:$tag") || imageid=""
if [ -n "$imageid" ]; then
echo "Supervisor $image_name:$tag already downloaded."
exit 0
fi
# Try to stop old supervisor to prevent it deleting the intermediate images while downloading the new one
echo "Stop supervisor..."
systemctl stop resin-supervisor
# Pull target version.
echo "Pulling supervisor $image_name:$tag..."
if [ "${CACHE-no}" == "yes" ]; then
SUPERVISOR_CACHE_FILE="/mnt/data/resinhup/cache/resin_supervisor_4_2_4_raspberry_pi.tar.gz"
if [ -f "${SUPERVISOR_CACHE_FILE}" ]; then
echo "==> found cache, loading"
$DOCKER load -i ${SUPERVISOR_CACHE_FILE}
else
echo "No cached supervisor found at ${SUPERVISOR_CACHE_FILE}"
exit 3
fi
else
$DOCKER pull "$image_name:$tag"
fi
$DOCKER rm --force resin_supervisor || true
# Store the tagged image string so resin-supervisor.service can pick it up
echo "SUPERVISOR_IMAGE=$image_name:$tag" > $UPDATECONF
# Run supervisor with the device-type-specific options.
# We give a specific name to the container to guarantee only one running.
echo "Start supervisor..."
systemctl start resin-supervisor
# Mark supervisor as working. This version will run when the device reboots.
echo "Mark pulled tag as latest..."
$DOCKER tag -f "$image_name:$tag" "$image_name:latest"
sed --in-place "s|SUPERVISOR_IMAGE=.*|SUPERVISOR_IMAGE=$image_name|" /etc/resin-supervisor/supervisor.conf
sed --in-place "s|SUPERVISOR_TAG=.*|SUPERVISOR_TAG=$tag|" /etc/resin-supervisor/supervisor.conf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment