Integrate with hosted-app-utils

Strip down this repo and allow the hosted-app-utils `package` script to
auto-generate the package.
This commit is contained in:
2024-07-30 08:48:18 -07:00
parent a47c7b3d98
commit 5222a67855
16 changed files with 47 additions and 438 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "hosted-app-utils"]
path = hosted-app-utils
url = git@gitlab.com:signalytic/client-external/hosted-app-utils.git
+16 -5
View File
@@ -2,12 +2,23 @@
Packaging and installation tools for Streamline's "Streamline EMR" application.
## Building
1. ensure you have docker access to this project's container registry on GitLab
2. run `package.sh` to generate a new application package
3. package will be stored to `build-packages/`
## Setup
1. login to the gitlab docker registry: `docker login registry.gitlab.com`
2. update submodules: `git submodule update --init`
Several defaults can be overridden with command line options or by setting appropriate environment variables. A help prompt can be accessed using `package.sh -h`. For example, `package.sh -t latest -p linux/arm64` will build only the `linux/arm64` platform and use the `latest` tag instead of the current repo version.
## Building
To build, simply run `./package` to generate a new application package.
The `package` script will assign a few variables by default, specifically:
```
CONFIG=${CONFIG:-${LOCATION}/config.json}
COMPOSE=${COMPOSE:-${LOCATION}/docker-compose.yml}
BUILD_DIR=${BUILD_DIR:-${LOCATION}/build-packages}
```
If necessary, each of these may be overridden by running with `VAR=VALUE ./package`.
The `hosted-app-utils` project provides additional customization via command line arguments. This can be used to modify the package name, skip packaging of images, build for only one platform and more. For a list of options, run `./package -h`.
## Installing
1. extract the generated archive file in a temporary folder on the target system
+17
View File
@@ -0,0 +1,17 @@
{
"name": "streamline-emr",
"org": "streamline",
"version": "0.1",
"platforms": [
"linux/arm64",
"linux/amd64"
],
"images": {
"linux/arm64": {
"registry.gitlab.com/signalytic/client-external/streamline/streamline-emr/streamline-emr/arm64:latest": "streamline-emr:latest"
},
"linux/amd64": {
"registry.gitlab.com/signalytic/client-external/streamline/streamline-emr/streamline-emr/amd64:latest": "streamline-emr:latest"
}
}
}
@@ -4,7 +4,7 @@ services:
image: ${APP_IMAGE:-streamline-emr:latest}
container_name: ${APP_CONTAINER:-streamline-emr}
volumes:
- "${DATA_DIR:-/var/signalytic/clientapps/streamline/streamline-emr/data}:/var/lib/mysql"
- "${DATA_DIR:-./data}:/var/lib/mysql"
ports:
- "${APP_PORT:-3000}:80"
dns: 0.0.0.0
+1
Submodule hosted-app-utils added at 6f1a9493c1
-2
View File
@@ -1,2 +0,0 @@
linux/arm64,streamline-emr,registry.gitlab.com/signalytic/client-external/streamline/streamline-emr/streamline-emr/arm64
linux/amd64,streamline-emr,registry.gitlab.com/signalytic/client-external/streamline/streamline-emr/streamline-emr/amd64
1 linux/arm64 streamline-emr registry.gitlab.com/signalytic/client-external/streamline/streamline-emr/streamline-emr/arm64
2 linux/amd64 streamline-emr registry.gitlab.com/signalytic/client-external/streamline/streamline-emr/streamline-emr/amd64
-55
View File
@@ -1,55 +0,0 @@
#!/bin/bash
#
# Copyright (C) Wendepunkt Medical Innovations, Inc - All Rights Reserved.
# Unauthorized copying of this file, via any medium is strictly prohibited.
# Proprietary and confidential
#
# For information: dev@signalytic.ca
#
#
# Install the Streamline "Streamline EMR" application and services
#
# The caller of this script must check the exit value and possibly do a
# roll-back if it is non-zero. If the exit value is non-zero services have not
# been restarted.
LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit 1
fi
# stop any running systemd service if not running in a docker environment
if [ -f /.dockerenv ]; then
echo "Docker environment detected - skipping systemd installation"
else
echo "stopping system service"
systemctl stop streamline-emr
fi
set -e
# copy root files
echo "importing root files"
cp -rfv $LOCATION/root/* /
# import docker images
for f in $(find $LOCATION/images -name "*.img" 2>/dev/null);do
echo "importing docker image: $f"
docker load -i $f
done
for f in $(find $LOCATION/images -name "*.img.xz" 2>/dev/null);do
echo "importing docker image: $f"
xz -d -c $f | docker load
done
# install systemd service unless running in a docker environment
if [ ! -f /.dockerenv ]; then
echo "installing system service"
systemctl daemon-reload
systemctl enable streamline-emr
systemctl start streamline-emr
fi
Executable
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
CONFIG=${CONFIG:-${LOCATION}/config.json}
COMPOSE=${COMPOSE:-${LOCATION}/docker-compose.yml}
BUILD_DIR=${BUILD_DIR:-${LOCATION}/build-packages}
${LOCATION}/hosted-app-utils/package ${CONFIG} ${COMPOSE} output=${BUILD_DIR} $@
-206
View File
@@ -1,206 +0,0 @@
#!/bin/bash
#
# Copyright (C) Wendepunkt Medical Innovations, Inc - All Rights Reserved.
# Unauthorized copying of this file, via any medium is strictly prohibited.
# Proprietary and confidential
#
# For information: dev@signalytic.ca
#
# basic path info
LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
PROJECT_ROOT="$(realpath $LOCATION)"
# determine version name from git
# use ci tag name if available (e.g. "v1.2")
if [ $CI_COMMIT_TAG ]; then
VERSION_NAME="$CI_COMMIT_TAG"
# otherwise if ci, use BRANCH-COMMIT
elif [ $CI_COMMIT_BRANCH ]; then
VERSION_NAME="$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA"
# if not ci, try to use git
elif command -v git &> /dev/null; then
VERSION_NAME=$(git describe --always --tags --abbrev=7 --dirty)
# fallback
else
VERSION_NAME="latest"
fi
# configurable options (override with env vars as needed)
PACKAGE_NAME=${PACKAGE_NAME-"streamline-emr"}
OUTPUT_DIR=${OUTPUT_DIR-"$PROJECT_ROOT/build-packages"}
PACKAGE_IMAGES=${PACKAGE_IMAGES:-1}
COMPRESS_IMAGES=${COMPRESS_IMAGES:-1}
IMAGE_TAG=${IMAGE_TAG:-${VERSION_NAME}}
IMAGES_LIST=${IMAGES_LIST:-${PROJECT_ROOT}/images.csv}
function print_usage {
echo "Streamline EMR packaging utility"
echo
echo "Usage: package.sh [ OPTIONS ]"
echo
echo "Options:"
echo " -h Print this help prompt and exit"
echo " -p PLATFORM Specify a docker platform to target, may be passed multiple"
echo " times. If none specified, all platforms built. Supported"
echo " platforms: 'linux/amd64', 'linux/arm64'"
echo " -t IMAGE_TAG Specify an image tag. It not specified, the tag will be"
echo " inferred from the current git version ('${IMAGE_TAG}')"
echo " -n PACKAGE_NAME Specify the package base name. Default: ${PACKAGE_NAME}"
echo " -o OUTPUT_DIR Specify a directory to save packages. Default: ${OUTPUT_DIR}"
echo " -l IMAGES_LIST Specify a file containing a list of images. Default: ${IMAGES_LIST}"
echo " -I Do not package images"
echo " -C Do not compress images"
echo
}
# collect user args
PLATFORMS=()
while getopts ":p:t:n:o:l:ICh" options; do
case "${options}" in
p)
PLATFORMS+=(${OPTARG})
;;
t)
IMAGE_TAG=${OPTARG}
;;
n)
PACKAGE_NAME=${OPTARG}
;;
o)
OUTPUT_DIR=${OPTARG}
;;
l)
IMAGES_LIST=${OPTARG}
;;
I)
PACKAGE_IMAGES=0
;;
C)
COMPRESS_IMAGES=0
;;
h)
print_usage
exit 0
;;
*)
print_usage
exit 1
;;
esac
done
shift $((OPTIND -1))
# set defaults
if [ ${#PLATFORMS} -eq 0 ]; then
PLATFORMS=("linux/amd64" "linux/arm64")
fi
echo "packaging $PACKAGE_NAME"
echo " output dir: $OUTPUT_DIR"
echo " package images: $PACKAGE_IMAGES"
echo " compress images: $COMPRESS_IMAGES"
echo " image tag: $IMAGE_TAG"
echo " image list: $IMAGES_LIST"
echo " platforms: ${PLATFORMS[@]}"
# work from the project root
pushd $PROJECT_ROOT > /dev/null
# Exit on error:
set -e
trap 'echo "Error: Last command failed with exit code $?."' ERR
# build for each relevant platform
for platform in ${PLATFORMS[@]}; do
echo "preparing package for platform $platform"
if [ "$platform" == "linux/amd64" ];then
pkg_arch="x86_64"
elif [ "$platform" == "linux/arm64" ];then
pkg_arch="aarch64"
else
echo "unexpected platform '$platform'"
exit 1
fi
OUTPUT_NAME="$PACKAGE_NAME-$VERSION_NAME-${pkg_arch}"
OUTPUT_FILE="$OUTPUT_NAME.tar.bz2"
OUTPUT_PATH="$OUTPUT_DIR/$OUTPUT_FILE"
# create a new temp directory to stage files
for i in {1..9999};do
STAGING_DIR="tmp-staging-$i"
if [ ! -d $STAGING_DIR ]; then
break
fi
done
if [ -d $STAGING_DIR ]; then
echo "Failed to generate temp staging dir"
exit 1
fi
# add files
PACKAGE_ROOT=${STAGING_DIR}/${OUTPUT_NAME}
IMAGES_DIR=${PACKAGE_ROOT}/images
mkdir -p ${IMAGES_DIR}
cp ${PROJECT_ROOT}/install.sh ${PACKAGE_ROOT}/
cp -a ${PROJECT_ROOT}/root ${PACKAGE_ROOT}/
echo "${VERSION_NAME}" > ${PACKAGE_ROOT}/root/var/signalytic/clientapps/streamline/streamline-emr/version
if [ "${PACKAGE_IMAGES}" = 1 ]; then
# add images
# read image list from file (e.g. 'images-aarch64')
# images are listed as SAVED_TAG=SOURCE_IMAGE
for image in $(cat ${IMAGES_LIST});do
IFS=, read -r img_platform dest source <<< "${image}"
# package only if the platforms match
if [ "${img_platform}" = "${platform}" ]; then
echo "pulling image '${source}' (${platform})"
docker pull --platform ${platform} ${source}:${IMAGE_TAG}
# re-tag the image with a more generic name
echo "tagging image as '${dest}:latest'"
docker tag ${source}:${IMAGE_TAG} ${dest}:latest
# save the image to file
if [ "${COMPRESS_IMAGES}" = 1 ]; then
path="${IMAGES_DIR}/${dest}.img.xz"
echo "saving to '${path}'"
# if installed, use pv to show progress
if command -v pv &> /dev/null; then
docker save ${dest}:latest | xz -9 - -c | pv -t -r -b -N "saving compressed image..." > ${path}
else
docker save ${dest}:latest | xz -9 - -c > ${path}
fi
else
path="${IMAGES_DIR}/${dest}.img"
echo "saving to '${path}'"
# if installed, use pv to show progress
if command -v pv &> /dev/null; then
docker save ${dest}:latest | pv -t -r -b -N "saving raw image..." > ${path}
else
docker save -o ${path} ${dest}:latest
fi
fi
fi
done
else
echo "skipping image packaging as requested"
fi
# setup output directory and cleanup old files if necessary
mkdir -p $OUTPUT_DIR
rm -rf $OUTPUT_PATH
pushd $STAGING_DIR > /dev/null
tar -cjf $OUTPUT_PATH ${OUTPUT_NAME}
popd > /dev/null
# cleanup staging files
rm -r $STAGING_DIR
echo "output: $OUTPUT_PATH"
done
popd > /dev/null
exit 0
@@ -1,16 +0,0 @@
[Unit]
Description=Run Streamline EMR
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
User=root
WorkingDirectory=/var/signalytic/clientapps/streamline/streamline-emr
ExecStart=/var/signalytic/clientapps/streamline/streamline-emr/start
ExecStop=/var/signalytic/clientapps/streamline/streamline-emr/stop
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
@@ -1,40 +0,0 @@
#!/bin/bash
LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
INTERVAL=${INTERVAL:-60}
# track pid with a file `autoheal.pid`. If a previous instance is still running, exit early.
function cleanup() {
rm -f ${LOCATION}/autoheal.pid
}
trap cleanup EXIT
kill -0 $(cat ${LOCATION}/autoheal.pid 2> /dev/null) 2> /dev/null && echo "autoheal script already running" && exit 1
echo $$ > ${LOCATION}/autoheal.pid
# exit on SIGINT
trap exit INT
# run at fixed interval, checking for and restarting any service marked as 'unhealthy'
pushd $LOCATION > /dev/null
while [ 1 ]; do
# get current state (running or not) and status (healthy, unhealthy, etc)
app_state=$(docker compose ps --format '{{.State}}' streamline-emr)
app_status=$(docker compose ps --format '{{.Status}}' streamline-emr)
# check if app is running and healhty
if [ "${app_state}" = "running" ]; then
if [[ "${app_status}" = *\(unhealthy\) ]]; then
echo "Unhealthy service detected. Restarting 'streamline-emr'"
docker compose restart streamline-emr
fi
# app should be running - restart
else
echo "Container not running. Starting 'streamline-emr'"
docker compose up -d streamline-emr
fi
# wait a little while before checking again
sleep $INTERVAL
done
popd > /dev/null
@@ -1,43 +0,0 @@
#!/bin/bash
LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
SYSTEMLOG=${SYSTEMLOG:-1}
if ! command -v bgsystemlog &> /dev/null; then
SYSTEMLOG=0
fi
# get container info
APP_CONTAINER=${APP_CONTAINER:-streamline-emr}
if grep -q "^APP_CONTAINER=" ${LOCATION}/.env > /dev/null 2>&1; then
APP_CONTAINER=$(sed -n 's/APP_CONTAINER=//p' ${LOCATION}/.env)
fi
pushd $LOCATION > /dev/null
# get process status for each service
echo "checking streamline-emr service status"
for service in $(docker compose ps --services); do
status=$(docker compose ps --format '{"name":"{{.Names}}","created":"{{.CreatedAt}}","elapsed":"{{.RunningFor}}","state":"{{.State}}","status":"{{.Status}}"}' ${service})
if [ "${status}" ]; then
echo $status
if [ "$SYSTEMLOG" -eq 1 ]; then
bgsystemlog -j streamline_emr_status -m ${status}
fi
else
echo "no status results found for service ${service}"
fi
done
# get resource usage
echo "checking streamline-emr resource usage"
status=$(docker stats --no-stream --format '{"name":"{{.Name}}","cpu_p":"{{.CPUPerc}}","mem_p":"{{.MemPerc}}","mem_u":"{{.MemUsage}}","net_io":"{{.NetIO}}","block_io":"{{.BlockIO}}"}' ${APP_CONTAINER})
if [ "${status}" ]; then
echo $status
if [ "$SYSTEMLOG" -eq 1 ]; then
bgsystemlog -j streamline_emr_usage -m ${status}
fi
else
echo "no usage results found for container ${APP_CONTAINER}"
fi
popd > /dev/null
echo "done."
@@ -1,25 +0,0 @@
#!/bin/bash
LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
VERSION_FILE=${LOCATION}/version
version=$(head -n 1 ${VERSION_FILE} 2>/dev/null)
if [ $? -ne 0 ];then
version="unknown version"
fi
echo "Starting Streamline EMR: $version"
# work from the install root
pushd $LOCATION > /dev/null
# make sure we're always working from a clean state
./stop
# start the application
echo "starting services"
docker compose up -d
# start autoheal to restart unhealthy containers
./autoheal &
popd > /dev/null
echo "done."
@@ -1,12 +0,0 @@
#!/bin/bash
LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo "stopping streamline emr"
pushd $LOCATION > /dev/null
if [ -f autoheal.pid ];then
kill $(cat autoheal.pid)
fi
docker compose down
popd > /dev/null
echo "done."
@@ -1,28 +0,0 @@
{
"name": "Streamline EMR",
"dbsync": {
"database": {
"type": "mysql",
"version": "8.0.23",
"name": "main",
"username": "",
"password": "",
"db_path": "/var/lib/mysql",
"logs_path": "/var/lib/mysql/logs",
"log_pattern": "binlog.[0-9]*"
},
"blockgraph": {
"district": "",
"name": "",
"username": "",
"password": ""
},
"instances": {
"streamline-emr": {
"source": "streamline-emr",
"node": "",
"location": "_default"
}
}
}
}
@@ -1,5 +0,0 @@
COMPOSE_PROJECT_NAME=streamline-emr
DATA_DIR=/var/signalytic/clientapps/streamline/streamline-emr/data
APP_IMAGE=streamline-emr:latest
APP_CONTAINER=streamline-emr
APP_PORT=3000