diff --git a/sandbox/deployment.sh b/sandbox/deployment.sh new file mode 100644 index 0000000..e3bb0b3 --- /dev/null +++ b/sandbox/deployment.sh @@ -0,0 +1,277 @@ +#!/bin/bash + + +usage() { + cat <&2; exit 1; +} + +COMMAND=$1 +shift + +commands=('deploy','check','run','stop') + +if [[ ! "${commands[@]}" =~ "${COMMAND}" ]]; then + usage +fi + +COMPOSERS=() +NODE_NAME="" +NODE_SETTINGS=() +PRODUCT_SETTINGS=() +SECRET_SETTINGS="" +STACK_NAME="" +DO_UPDATE="no" + +while getopts ":n:N:P:w:s:f:h:u" o; do + case "${o}" in + n) + NODE_NAME="${OPTARG}" + ;; + N) + NODE_SETTINGS+=("${OPTARG}") + ;; + P) + PRODUCT_SETTINGS+=("${OPTARG}") + ;; + s) + SECRET_SETTINGS="${OPTARG}" + ;; + f) + COMPOSERS+=("${OPTARG}") + ;; + w) + STACK_NAME=${OPTARG} + ;; + u) + DO_UPDATE="yes" + ;; + h) + usage + ;; + *) + usage + ;; + esac +done +shift $((OPTIND-1)) + +if [ "${COMMAND}" == "" ] || [ "${COMPOSERS}" == "" ]; then + echo "Required arguments missing" + usage +fi + +# building node settings +if [ -f "$NODE_NAME.env" ]; then + set +a + . "$NODE_NAME.env" + set -a +fi + +for NODE_SETTING in "${NODE_SETTINGS[@]}"; do + . $NODE_SETTING +done + +# building project settings +bash -c "echo ''> .project.tmp.env" +for PRODUCT_SETTING in "${PRODUCT_SETTINGS[@]}"; do + bash -c "cat $PRODUCT_SETTING >> .project.tmp.env" +done + +export PROJECT_SETTINGS=".project.tmp.env" + +grep ^CLIENT_API .project.tmp.env | sed 's/^CLIENT_//' > .project.client.tmp.env +grep ^ADMIN_API .project.tmp.env | sed 's/^ADMIN_//' > .project.admin.tmp.env +grep ^I_CLIENT_API .project.tmp.env | sed 's/^I_CLIENT_//' > .project.i_client.tmp.env +grep ^REPORT_GENERATOR .project.tmp.env | sed 's/^REPORT_GENERATOR_//' > .project.renderer.tmp.env + +# special default variables +export MYSQL_HOST_DIR=${MYSQL_HOST_DIR:-"/home/dockns-root/mysql_data"} +export DOCKER_REGISTRY=${DOCKER_REGISTRY:-"docker-registry.smarthomedevs.work/issuing"} +export REPLICAS=${REPLICAS:-"1"} +export TAG=${TAG:-"latest"} +export PUBLIC_NODE_IP=${PUBLIC_NODE_IP:-"0.0.0.0"} + +# parse secret names from composer +COMPOSER_FILE_ARGS="" +COMPOSER_SWARM_ARGS="" + +for COMPOSER in "${COMPOSERS[@]}"; do + + COMPOSER_FILE_ARGS+=" -f $COMPOSER" + COMPOSER_SWARM_ARGS+=" -c $COMPOSER" + + IFS=$'\n' tag_vars=($(grep "TAG_" $COMPOSER | sed 's/.*\$TAG_/TAG_/')) + for tag_var in "${tag_vars[@]}"; do + if [[ "${!tag_var}" == "" ]]; then + eval "export $tag_var='$TAG'" + fi + done + + IFS=$'\n' secret_vars=($(grep "SV_" $COMPOSER | sed 's/.*\.\$//')) + for secret in "${secret_vars[@]}"; do + if [[ "${!secret}" == "" ]]; then + eval "export $secret='0'" + fi + done +done + +EXIT=0 + +# building secret settings +if [ -f "$SECRET_SETTINGS" ]; then + . $SECRET_SETTINGS +fi + +if [[ "$COMMAND" == "check" ]]; then + bash -c "docker compose $COMPOSER_FILE_ARGS config" + EXIT=$? +fi + +if [[ "$COMMAND" == "deploy" ]]; then + if [ "$STACK_NAME" == "" ]; then + echo "" + echo "STACK_NAME required" + echo "" + usage + fi + if [[ "$DO_UPDATE" == "yes" ]]; then + REGISTRY_AUTH="--with-registry-auth" + else + REGISTRY_AUTH="" + fi + + [[ -f "control.sh" ]] && [[ "$NODE_NAME" != "" ]] && eval $(./control.sh $NODE_NAME) + + if [[ "$FORCE_DEPLOY" != "1" ]]; then + + for cron_part in 'cron' 'schedule'; do + CRON_SERVICE_NAME=$(docker service ls --filter name=${STACK_NAME}_${cron_part} --format '{{.Name}}') + if [[ "$CRON_SERVICE_NAME" != "" ]]; then + break; + fi + done + + TASK_SERVICE_NAME=$(docker service ls --filter name=${STACK_NAME}_task_template --format '{{.Name}}') + + TASK_CONTAINER_ID="" + if [[ "$TASK_CONTAINER_NAME" != "" ]]; then + TASK_CONTAINER_ID=$(docker ps --filter name="$TASK_SERVICE_NAME" --format '{{.ID}}') + fi + + if [[ "$TASK_CONTAINER_ID" != "" ]]; then + docker service scale $CRON_SERVICE_NAME=0 || exit 255 + RUNNUNG_TASKS=$(docker exec -it $TASK_CONTAINER_ID ps axuf | grep nameless) + if [[ "$RUNNING_TASKS" != "" ]]; then + echo "Running tasks found! Can't deploy"; + exit 255; + fi + fi + + + if [[ "$CRON_SERVICE_NAME" != "" ]]; then + docker service scale $CRON_SERVICE_NAME=0 || exit 255 + fi + + if [[ "$TASK_CONTAINER_ID" != "" ]]; then + RUNNUNG_TASKS=$(docker exec -it $TASK_CONTAINER_ID ps axuf | grep nameless) + if [[ "$RUNNING_TASKS" != "" ]]; then + echo "Scheduler is stopped but running tasks found! Can't deploy"; + exit 255; + fi + fi + fi + + + bash -c "docker stack deploy --prune $COMPOSER_SWARM_ARGS $REGISTRY_AUTH $STACK_NAME" + + EXIT=$? + + if [ $EXIT -ne 0 ] + then + echo "Deploy failed" + exit $EXIT + fi + + echo "Waiting for services..." + + while true; do + + IFS=$'\n' services=($(docker service ls | grep $STACK_NAME | awk '{print $2,$4}')); + + if [ $? -ne 0 ] + then + echo "Something went wrong" + exit $? + fi + + is_ready=1 + all_services=0 + bad_services=0 + + for line in "${services[@]}" + do + all_services=$((all_services+1)) + IFS=$' ' service_status=($line) + re="migrate|test_setup" + if ! [[ "${service_status[0]}" =~ $re ]] + then + IFS=$'/' replicas=(${service_status[1]}) + if [ ${replicas[0]} -lt ${replicas[1]} ] + then + is_ready=0 + bad_services=$((bad_services+1)) + fi + fi + done + + if [ $is_ready -eq 1 ] + then + break + fi + + sleep 5; + echo "Services: $all_services, but $bad_services is not ready yet" + done + + echo "Done." +fi + +if [[ "$COMMAND" == "run" ]]; then + bash -c "docker compose $COMPOSER_FILE_ARGS down" + if [[ "$DO_UPDATE" == "yes" ]]; then + bash -c "docker compose $COMPOSER_FILE_ARGS pull" + fi + + bash -c "docker compose $COMPOSER_FILE_ARGS up -d" + EXIT=$? +fi + +if [[ "$COMMAND" == "stop" ]]; then + bash -c "docker compose $COMPOSER_FILE_ARGS down" + EXIT=$? +fi + +rm .project*.tmp.env + +exit $EXIT