#!/bin/sh

# ------------------------------------------------------------
# Company:  Software- und Organisations-Service GmbH
# Date:     2022-12-03
# Purpose:  Create deployment packages from deployment descriptor for JS7 Agent, Controller, JOC Cockpit
# Platform: Linux, MacOS: bash, ksh, zsh, dash
# ------------------------------------------------------------
#
# Example:  ./js7_create_deployment_package.sh --deploy-desc=/home/sos/js7.deploy/desc/agents.descriptor.json --work-dir=/tmp/work --archive-dir=/home/sos/js7.deploy/archive
#
#           performs temporary installation from deployment descriptor and creates tarballs from installed files
#
# Example:  ./js7_create_deployment_package.sh --deploy-desc=/home/sos/js7.deploy/desc/agents.descriptor.json --work-dir=/tmp/work --archive-dir=/home/sos/js7.deploy/archive --agent-id=agent_001 --dry-run --keep-work
#
#           limits processing to the indidcated Agent, does not perform an installation but retains the work directory holding the install scripts

set -e

# ------------------------------
# Initialize variables
# ------------------------------

script_home=$(cd "$(dirname "$0")" > /dev/null && pwd)
dep_home=$(cd "$(dirname "${script_home}")" > /dev/null && pwd)

deploy_desc=
config_dir="${DEP_CONFIG:-${dep_home}/config}"
work_dir="${DEP_WORK:-${dep_home}/work}"
archive_dir="${DEP_ARCHIVE:-${dep_home}/archive}"
script_dir="${DEP_BIN:-${dep_home}/bin}"
release_dir="${DEP_RELEASE:-${dep_home}/release}"
deploy_agent_id=primaryAgent
select_agent_ids=
select_controller_ids=
select_joc_ids=
make_dirs=
keep_work=
dry_run=
workflow_parallelism=100
workflow_timezone="Etc/UTC"
show_logs=
force_sudo=

tmp_dir=
log_dir=
log_file=
hostname=$(hostname)
start_time=$(date +"%Y-%m-%dT%H-%M-%S")
run_file=
job_file=
run_config_dir=
run_work_dir=
run_tarballs=
run_rollouts_file=
exclude_file=


Usage()
{
    >&2 echo ""
    >&2 echo "Usage: $(basename "$0") [Options] [Switches]"
    >&2 echo ""
    >&2 echo "  Options:"
    >&2 echo "    --deploy-desc=<file>               | required: path to a deployment descriptor file"
    >&2 echo "    --config-dir=<directory>           | required: path to configuration directory, default: ${config_dir}"
    >&2 echo "    --work-dir=<directory>             | required: path to working directory, default: ${work_dir}"
    >&2 echo "    --archive-dir=<directory>          | required: path to archive directory, default: ${archive_dir}"
    >&2 echo "    --release-dir=<directory>          | required: path to release directory holding JS7 installation files, default: ${release_dir}"
    >&2 echo "    --script-dir=<directory>           | optional: path to script directory, default: ${script_dir}"
    >&2 echo "    --deploy-agent-id=<identifier>     | optional: Agent ID executing the deployment workflow, default: ${deploy_agent_id}"
    >&2 echo "    --agent-id=<id[,id]>               | optional: list of Agent IDs to which processing will be limited"
    >&2 echo "    --controller-id=<id[,id]>          | optional: list of Controller IDs to which processing will be limited"
    >&2 echo "    --joc-instancee-id=<id[,id]>       | optional: list of JOC Cockpit Instance IDs to which processing will be limited"
    >&2 echo "    --workflow-parallelism=<number>    | optional: max. parallel processes in deployment workflow, default: ${workflow_parallelism}"
    >&2 echo "    --workflow-timezone=<identifier>   | optional: time zone of the deployment workflow, default: ${workflow_timezone}"
    >&2 echo "    --log-dir=<directory>              | optional: log directory for log output of this script"
    >&2 echo ""
    >&2 echo "  Switches:"
    >&2 echo "    -h | --help                        | displays usage"
    >&2 echo "    --force-sudo                       | forces use of sudo for operations on directories"
    >&2 echo "    --dry-run                          | creates install scripts without running the script"
    >&2 echo "    --make-dirs                        | creates the specified directories if they do not exist"
    >&2 echo "    --keep-work                        | keeps temporary installations in work directory"
    >&2 echo "    --show-logs                        | shows log output of the script"
    >&2 echo ""
}

Log()
{
    if [ -n "${log_file}" ] && [ -f "${log_file}" ]
    then
        echo "$@" >> "${log_file}"
    fi

    if [ -z "${show_logs}" ]
    then
        echo "$@"
    fi
}

LogError()
{
    if [ -n "${log_file}" ] && [ -f "${log_file}" ]
    then
        echo "[ERROR]" "$@" >> "${log_file}"
    fi
    
    >&2 echo "[ERROR]" "$@"
}

CreateExcludeFile()
{
    exclude_file="${work_dir}"/tmp/js7_deploy_tarball_exclude_$$.tmp

    if [ -f "${exclude_file}" ]
    then
        rm -f "${exclude_file}"
    fi
    
    touch "${exclude_file}"

    for i in "$@"; do
        if [ -d "${i}" ]
        then
            find "$i" -print >> "${exclude_file}"
        fi
    done
    
    echo "${exclude_file}"
}


AddDeployScriptFunctions()
{
    printf '
Log()
{
    echo "$@"
}

LogError()
{
    >&2 echo "[ERROR]" "$@"
}

MakeService()
{
    use_systemd_service_file=$1

    rc=0
    ("${use_sudo}" systemctl cat -- "${systemd_service_name}" > /dev/null 2>&1) || rc=$?
    if [ "${rc}" -eq 0 ]
    then
        Log ".... updating systemd service: ${systemd_service_name}"
    else
        Log ".... adding systemd service: ${systemd_service_name}"
    fi

    Log ".... copying systemd service file ${use_systemd_service_file} to ${systemd_service_dir}/${systemd_service_name}"
    "${use_sudo}" cp -p "${use_systemd_service_file}" "${systemd_service_dir}"/"${systemd_service_name}"

    Log ".... systemd service command: $use_sudo systemctl enable ${systemd_service_name}"
    rc=0
    ("${use_sudo}" systemctl enable "${systemd_service_name}" > /dev/null 2>&1) || rc=$?

    if [ "${rc}" -eq 0 ]
    then
        Log ".... systemd service enabled: ${systemd_service_name}"

        Log ".... systemd service command: $use_sudo systemctl daemon-reload"
        ("${use_sudo}" systemctl daemon-reload > /dev/null 2>&1) || rc=$?

        if [ "${rc}" -eq 0 ]
        then
            Log ".... systemd service configuration reloaded: ${systemd_service_name}"
        else
            LogError "could not reload systemd daemon configuration for service: ${systemd_service_name}, exit code ${rc}"
            exit 7
        fi
    else
        LogError "could not enable systemd service: ${systemd_service_name}, exit code ${rc}"
        exit 7
    fi
}

StartService()
{
    rc=0
    Log ".... systemd service command: $use_sudo systemctl start ${systemd_service_name}"
    ("${use_sudo}" systemctl start "${systemd_service_name}" > /dev/null 2>&1) || rc=$?

    if [ "${rc}" -eq 0 ]
    then
        Log ".... systemd service started: ${systemd_service_name}"
    else
        LogError "could not start systemd service: ${systemd_service_name}, exit code ${rc}"
        exit 7
    fi
}

StopService()
{
    rc=0
    ("${use_sudo}" systemctl cat -- "${systemd_service_name}" > /dev/null 2>&1) || rc=$?

    if [ "${rc}" -eq 0 ]
    then
        Log ".... systemd service command: $use_sudo systemctl stop ${systemd_service_name}"
        ("${use_sudo}" systemctl stop "${systemd_service_name}" > /dev/null 2>&1) || rc=$?

        if [ "${rc}" -eq 0 ]
        then
            Log ".... systemd service stopped: ${systemd_service_name}"
        else
            LogError "could not stop systemd service: ${systemd_service_name}, exit code ${rc}"
            exit 7
        fi
    fi
}

' >> "$1"
}

# ------------------------------
# Process command line options
# ------------------------------

Arguments()
{
    for option in "$@"
    do
        case "${option}" in
            -h|--help)              Usage
                                    exit
                                    ;;
            # Options
            --deploy-desc=*)        deploy_desc=$(echo "${option}" | sed 's/--deploy-desc=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            --config-dir=*)         config_dir=$(echo "${option}" | sed 's/--config-dir=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            --work-dir=*)           work_dir=$(echo "${option}" | sed 's/--work-dir=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            --archive-dir=*)        archive_dir=$(echo "${option}" | sed 's/--archive-dir=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            --script-dir=*)         script_dir=$(echo "${option}" | sed 's/--script-dir=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            --release-dir=*)        release_dir=$(echo "${option}" | sed 's/--release-dir=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            --log-dir=*)            log_dir=$(echo "${option}" | sed 's/--log-dir=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            --deploy-agent-id=*)    deploy_agent_id=$(echo "${option}" | sed 's/--deploy-agent-id=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            --agent-id=*)           select_agent_ids=$(echo "${option}" | sed 's/--agent-id=//' | sed 's/^"//' | sed 's/"$//')
                                    ;;
            --controller-id=*)      select_controller_ids=$(echo "${option}" | sed 's/--controller-id=//' | sed 's/^"//' | sed 's/"$//')
                                    ;;
            --joc-instance-id=*)    select_joc_ids=$(echo "${option}" | sed 's/--joc-instance-id=//' | sed 's/^"//' | sed 's/"$//')
                                    ;;
            --workflow-parallellism=*)  workflow_parallelism=$(echo "${option}" | sed 's/--workflow-parallelism=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            --workflow-timezone=*)  workflow_timezone=$(echo "${option}" | sed 's/--workflow-timezone=//' | sed 's/^"//' | sed 's/"$//' | sed 's/^\(.*\)\/$/\1/')
                                    ;;
            # Switches
            --force-sudo)           force_sudo=1
                                    ;;
            --dry-run)              dry_run=1
                                    ;;
            --make-dirs)            make_dirs=1
                                    ;;
            --keep-work)            keep_work=1
                                    ;;
            --show-logs)            show_logs=1
                                    ;;
            *)                      >&2 echo "unknown option: ${option}"
                                    Usage
                                    exit 1
                                    ;;
        esac
    done

    if [ -z "${deploy_desc}" ]
    then
        LogError "Deployment Descriptor must be specified: --deploy-desc="
        Usage
        exit 1
    fi

    if [ ! -f "${deploy_desc}" ]
    then
        LogError "Deployment Descriptor not found: --deploy-desc=${deploy_desc}"
        Usage
        exit 1
    fi

    if [ -z "${config_dir}" ]
    then
        LogError "Deployment Configuration Directory must be specified: --config-dir="
        Usage
        exit 1
    fi

    if [ ! -d "${config_dir}" ]
    then
        LogError "Deployment Configuration Directory not found: --config-dir=${config_dir}"
        Usage
        exit 1
    fi

    if [ -z "${work_dir}" ]
    then
        LogError "Deployment Working Directory must be specified: --work-dir="
        Usage
        exit 1
    fi

    if [ ! -d "${work_dir}" ]
    then
        LogError "Deployment Working Directory not found: --work-dir=${work_dir}"
        Usage
        exit 1
    fi

    if [ -z "${release_dir}" ]
    then
        LogError "Release Directory must be specified: --release-dir="
        Usage
        exit 1
    fi

    if [ -n "${release_dir}" ] && [ ! -d "${release_dir}" ]
    then
        LogError "Release Directory not found: --release-dir=${release_dir}"
        Usage
        exit 1
    fi

    if [ -n "${script_dir}" ] && [ ! -d "${script_dir}" ]
    then
        LogError "Script Directory not found: --script-dir=${script_dir}"
        Usage
        exit 1
    fi

    if [ -n "${show_logs}" ] && [ -z "${log_dir}" ]
    then
        LogError "Log directory not specified and --show-logs switch is present: --log-dir="
        Usage
        exit 1
    fi

    if [ -z "${make_dirs}" ] && [ -n "${log_dir}" ] && [ ! -d "${log_dir}" ]
    then
        LogError "Log directory not found and --make-dirs switch not present: --log-dir=${log_dir}"
        Usage
        exit 1
    fi

    # initialize logging
    if [ -n "${log_dir}" ]
    then
        # create log directory if required
        if [ ! -d "${log_dir}" ] && [ -n "${make_dirs}" ]
        then
            mkdir -p "${log_dir}"
        fi
    
        log_file="${log_dir}"/deployment_package.$(basename "${deploy_desc}")."${hostname}"."${start_time}".log
        while [ -f "${log_file}" ]
        do
            sleep 1
            start_time=$(date +"%Y-%m-%dT%H-%M-%S")
            log_file="${log_dir}"/deployment_package.$(basename "${deploy_desc}")."${hostname}"."${start_time}".log
        done
        
        touch "${log_file}"
    fi

    Log "-- begin of log --------------"
    Log "$0" "$@"
    Log "-- begin of output -----------"
}

# ----------------------------------
# Process Agent installation package
# ----------------------------------

CreateAgentPackage()
{
    controllerId=$1
    agentId=$2
    agentJson=$3

    cfg_release=$(echo "${agentJson}" | jq -r ".media.release // empty" | sed 's/^"//' | sed 's/"$//')
    if [ -z "${cfg_release}" ]
    then
        LogError "Deployment Descriptor file misses element .media.release: --deploy-desc=${deploy_desc}"
        exit 1
    fi

    cfg_tarball=$(echo "${agentJson}" | jq -r ".media.tarball // empty" | sed 's/^"//' | sed 's/"$//')
    if [ -z "${cfg_tarball}" ]
    then
        LogError "Deployment Descriptor file misses element .media.tarball: --deploy-desc=${deploy_desc}"
        exit 1
    fi

    Log ".... creating install script: ${run_file}"
    CreateAgentInstallScript "${controllerId}" "${agentId}" "${agentJson}"
    agent_archive_dir="${archive_dir}"/"${cfg_descriptor_id}"/agents/"${agentId}"

    if [ ! -d "${agent_archive_dir}" ]
    then
        mkdir -p "${agent_archive_dir}"
    else
        ${use_sudo} rm -f -r "${agent_archive_dir}"/*
    fi

    if [ -z "${dry_run}" ]
    then
        Log ".... running install script: ${run_file}"
        "${run_file}"
        CreateAgentTarball "${controllerId}" "${agentId}" "${agentJson}"
        CreateAgentJobScript "${controllerId}" "${agentId}" "${agentJson}" "${run_tarballs}" "${agent_archive_dir}"
        CreateAgentImport "${controllerId}" "${agentId}" "${agentJson}"

        cp -p "${run_file}" "${agent_archive_dir}"/run_install_agent.sh
        Log ".... install script for deployment package ready: ${agent_archive_dir}/run_install_agent.sh"

        cp -p "${job_file}" "${agent_archive_dir}"/run_deploy_agent.sh
        Log ".... job script for deployment package ready: ${agent_archive_dir}/run_deploy_agent.sh"

        cp -p "${deploy_file}" "${agent_archive_dir}"/run_rollout_agent.sh
        Log ".... rollout script for deployment package ready: ${agent_archive_dir}/run_rollout_agent.sh"

        if [ -s "${run_rollouts_file}" ]
        then
            printf ',' >> "${run_rollouts_file}"
        fi
        
        printf '%s' "${agent_archive_dir}"/run_rollout_agent.sh >> "${run_rollouts_file}"

        if [ -z "${keep_work}" ] && [ -d "${work_dir}"/agents/"${agentId}" ]
        then
            ${use_sudo} rm -f -r "${work_dir}"/agents/"${agentId}"
        fi
    fi
}

CreateAgentInstallScript()
{
    controllerId=$1
    agentId=$2
    agentJson=$3

    run_config_dir="${config_dir}"
    run_script_dir="${script_dir}"
    run_work_dir="${work_dir}/agents/${agentId}"
    
    if [ -d "${run_work_dir}" ]
    then
        ${use_sudo} rm -f -r "${run_work_dir}"
    fi

    cfg_release=$(echo "${agentJson}" | jq -r ".media.release // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_tarball=$(echo "${agentJson}" | jq -r ".media.tarball // empty" | sed 's/^"//' | sed 's/"$//')

    if [ ! "$(echo "${cfg_tarball}" | cut -c1)" = "/" ] && [ ! "$(echo "${cfg_tarball}" | cut -c1)" = "." ] && [ ! "$(echo "${cfg_tarball}" | cut -c1)" = '$' ]
    then
        cfg_tarball="${release_dir}"/"${cfg_tarball}"
    fi
    
    cfg_home=$(echo "${agentJson}" | jq -r ".installation.home // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data=$(echo "${agentJson}" | jq -r ".installation.data // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_run_user=$(echo "${agentJson}" | jq -r ".installation.runUser // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home_owner=$(echo "${agentJson}" | jq -r ".installation.homeOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data_owner=$(echo "${agentJson}" | jq -r ".installation.dataOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_http_port=$(echo "${agentJson}" | jq -r ".installation.httpPort // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_https_port=$(echo "${agentJson}" | jq -r ".installation.httpsPort // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_java_home=$(echo "${agentJson}" | jq -r ".installation.javaHome // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_java_options=$(echo "${agentJson}" | jq -r ".installation.javaOptions // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_pre=$(echo "${agentJson}" | jq -r ".installation.execPre // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_post=$(echo "${agentJson}" | jq -r ".installation.execPost // empty" | sed 's/^"//' | sed 's/"$//')
    
    cfg_controller_id=$controllerId
    if [ -n "${isControllerPresent}" ]
    then
        cfg_primary_controller_cert=$(< "${deploy_desc}" jq -r ".controllers[] | select(.controllerId=\"${controllerId}\") | .\"primary\".configuration.certificates.cert // empty" | sed 's/^"//' | sed 's/"$//')
        cfg_secondary_controller_cert=$(< "${deploy_desc}" jq -r ".controllers[] | select(.controllerId=\"${controllerId}\") | .\"secondary\".configuration.certificates.cert // empty" | sed 's/^"//' | sed 's/"$//')
    else
        cfg_primary_controller_cert=$(< "${deploy_desc}" jq -r ".certificates.controller.primaryControllerCert // empty" | sed 's/^"//' | sed 's/"$//')
        cfg_secondary_controller_cert=$(< "${deploy_desc}" jq -r ".certificates.controller.secondaryControllerCert // empty" | sed 's/^"//' | sed 's/"$//')        
    fi

    cfg_keystore=$(echo "${agentJson}" | jq -r ".configuration.certificates.keyStore // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_keystore_password=$(echo "${agentJson}" | jq -r ".configuration.certificates.keyStorePassword // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_key_alias=$(echo "${agentJson}" | jq -r ".configuration.certificates.keyAlias // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_truststore=$(echo "${agentJson}" | jq -r ".configuration.certificates.trustStore // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_truststore_password=$(echo "${agentJson}" | jq -r ".configuration.certificates.trustStorePassword // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_service_name=$(echo "${agentJson}" | jq -r ".target.serviceName // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_service_dir=$(echo "${agentJson}" | jq -r ".target.serviceDir // empty" | sed 's/^"//' | sed 's/"$//')

    use_http_port=$(echo "${cfg_http_port}" | cut -d':' -f 2)
    cfg_service_name=${cfg_service_name:-js7_agent_${use_http_port}.service}
    if [ "${cfg_service_name%*.service}" = "${cfg_service_name}" ]
    then
        cfg_service_name="${cfg_service_name}".service
    fi

    if [ -z "${cfg_run_user}" ] && [ -n "${cfg_data_owner}" ]
    then
        cfg_run_user=${cfg_data_owner}
    fi
    cfg_run_user=$(echo "${cfg_run_user}" | cut -d':' -f 1)    

    cfg_config_dir=""
    i=0
    j=$(echo "${agentJson}" | jq -r ".configuration.templates // empty | length")
    if [ -n "$j" ]
    then
        while [ "$i" -lt "$j" ]; do
            if [ -n "${cfg_config_dir}" ]
            then
                cfg_config_dir="${cfg_config_dir},"
            fi
            cfg_config_dir="${cfg_config_dir}\${DEP_CONFIG}/$(echo "${agentJson}" | jq ".configuration.templates[$i] // empty" | sed 's/^"//' | sed 's/"$//')"
            i=$(( i + 1 ))
        done
    fi

    cfg_agent_conf=$(echo "${agentJson}" | jq -r ".configuration.files.agentConf // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_private_conf=$(echo "${agentJson}" | jq -r ".configuration.files.privateConf // empty" | sed 's/^"//' | sed 's/"$//')

    touch "${run_file}"
    chmod u+x "${run_file}"

    printf '#!/bin/sh\n\n'                                                                                           > "${run_file}"
    printf 'set -e\n\n'                                                                                             >> "${run_file}"
    printf 'DEP_BIN="%s"\n' "${run_script_dir}"                                                                     >> "${run_file}"
    printf 'DEP_CONFIG="%s"\n' "${run_config_dir}"                                                                  >> "${run_file}"
    printf 'DEP_WORK_TEMP="%s"\n\n' "${run_work_dir}"                                                               >> "${run_file}"
    printf 'mkdir -p "${DEP_WORK_TEMP}"\n\n'                                                                        >> "${run_file}"
    printf '"${DEP_BIN}"/js7_install_agent.sh \\\n'                                                                 >> "${run_file}"
    printf '    --real-path-prefix="%s" \\\n'  "\${DEP_WORK_TEMP}"                                                  >> "${run_file}"

    if [ -n "${cfg_release}" ]
    then
        printf '    --release="%s" \\\n' "${cfg_release}"                                                           >> "${run_file}"
    fi

    if [ -n "${cfg_tarball}" ]
    then
        printf '    --tarball="%s" \\\n' "${cfg_tarball}"                                                           >> "${run_file}"
    fi

    if [ -n "${cfg_home}" ]
    then
        printf '    --home="%s" \\\n' "\${DEP_WORK_TEMP}${cfg_home}"                                                >> "${run_file}"
    fi

    if [ -n "${cfg_data}" ]
    then
        printf '    --data="%s" \\\n' "\${DEP_WORK_TEMP}${cfg_data}"                                                >> "${run_file}"
    fi

    if [ -n "${cfg_run_user}" ]
    then
        printf '    --user="%s" \\\n' "${cfg_run_user}"                                                             >> "${run_file}"
    fi

    if [ -n "${cfg_home_owner}" ]
    then
        printf '    --home-owner="%s" \\\n' "${cfg_home_owner}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_data_owner}" ]
    then
        printf '    --data-owner="%s" \\\n' "${cfg_data_owner}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_http_port}" ]
    then
        printf '    --http-port="%s" \\\n' "${cfg_http_port}"                                                       >> "${run_file}"
    fi

    if [ -n "${cfg_https_port}" ]
    then
        printf '    --https-port="%s" \\\n' "${cfg_https_port}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_java_home}" ]
    then
        printf '    --java-home="%s" \\\n' "${cfg_java_home}"                                                       >> "${run_file}"
    fi

    if [ -n "${cfg_java_options}" ]
    then
        printf '    --java-options="%s" \\\n' "${cfg_java_options}"                                                 >> "${run_file}"
    fi

    if [ -n "${cfg_exec_post}" ]
    then
        printf '    --exec-start="%s" \\\n' "${cfg_exec_post}"                                                      >> "${run_file}"
    fi

    if [ -n "${cfg_exec_pre}" ]
    then
        printf '    --exec-stop="%s" \\\n' "${cfg_exec_pre}"                                                        >> "${run_file}"
    fi


    if [ -n "${cfg_controller_id}" ]
    then
        printf '    --controller-id="%s" \\\n' "${cfg_controller_id}"                                               >> "${run_file}"
    fi

    if [ -n "${cfg_primary_controller_cert}" ]
    then
        printf '    --controller-primary-cert="%s" \\\n' "\${DEP_CONFIG}/${cfg_primary_controller_cert}"            >> "${run_file}"
    fi

    if [ -n "${cfg_secondary_controller_cert}" ]
    then
        printf '    --controller-secondary-cert="%s" \\\n' "\${DEP_CONFIG}/${cfg_secondary_controller_cert}"        >> "${run_file}"
    fi


    if [ -n "${cfg_keystore}" ]
    then
        printf '    --keystore="%s" \\\n' "\${DEP_CONFIG}/${cfg_keystore}"                                          >> "${run_file}"
    fi

    if [ -n "${cfg_keystore_password}" ]
    then
        printf '    --keystore-password="%s" \\\n' "${cfg_keystore_password}"                                       >> "${run_file}"
    fi

    if [ -n "${cfg_key_alias}" ]
    then
        printf '    --keystore-alias="%s" \\\n' "${cfg_key_alias}"                                                  >> "${run_file}"
    fi

    if [ -n "${cfg_truststore}" ]
    then
        printf '    --truststore="%s" \\\n' "\${DEP_CONFIG}/${cfg_truststore}"                                      >> "${run_file}"
    fi

    if [ -n "${cfg_truststore_password}" ]
    then
        printf '    --truststore-password="%s" \\\n' "${cfg_truststore_password}"                                   >> "${run_file}"
    fi

    if [ -n "${cfg_config_dir}" ]
    then
        printf '    --deploy-dir="%s" \\\n' "${cfg_config_dir}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_agent_conf}" ]
    then
        printf '    --agent-conf="%s" \\\n' "\${DEP_CONFIG}/${cfg_agent_conf}"                                      >> "${run_file}"
    fi

    if [ -n "${cfg_private_conf}" ]
    then
        printf '    --private-conf="%s" \\\n' "\${DEP_CONFIG}/${cfg_private_conf}"                                  >> "${run_file}"
    fi

    if [ -n "${cfg_service_name}" ]
    then
        printf '    --service-name="%s" \\\n' "${cfg_service_name}"                                                 >> "${run_file}"
    fi

    if [ -n "${cfg_service_dir}" ]
    then
        printf '    --service-dir="%s" \\\n' "${cfg_service_dir}"                                                   >> "${run_file}"
    fi

    if [ -n "${show_logs}" ]
    then
        printf '    --show-logs \\\n'                                                                               >> "${run_file}"
    fi

    if [ -n "${log_dir}" ]
    then
        printf '    --log-dir=%s \\\n' "${log_dir}"                                                                 >> "${run_file}"
    fi

    if [ -n "${force_sudo}" ]
    then
        printf '    --force-sudo \\\n'                                                                              >> "${run_file}"
    fi

    printf '    --make-dirs\n'                                                                                      >> "${run_file}"
}

CreateAgentTarball()
{
    controllerId=$1
    agentId=$2
    agentJson=$3

    cfg_release=$(echo "${agentJson}" | jq -r ".media.release // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home=$(echo "${agentJson}" | jq -r ".installation.home // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data=$(echo "${agentJson}" | jq -r ".installation.data // empty" | sed 's/^"//' | sed 's/"$//')

    run_tarballs=
    run_work_dir="${work_dir}"/agents/"${agentId}"        
    agent_archive_dir="${archive_dir}"/"${cfg_descriptor_id}"/agents/"${agentId}"
    mkdir -p "${agent_archive_dir}"

    if [ -n "${cfg_home}" ]
    then
        agent_home_dir="${run_work_dir}""${cfg_home}"
        agent_home_parent_dir=$(dirname "${agent_home_dir}")
        agent_home_basename=$(basename "${agent_home_dir}")
        agent_home_archive_file="${agent_archive_dir}"/js7_deploy_agent_unix."${agentId}"."${cfg_release}".install.tar
    
        exclude_file=$(CreateExcludeFile "${agent_home_dir}"/logs "${agent_home_dir}"/state "${agent_home_dir}"/work)

        if [ -n "${os_compat}" ]
        then
            Log ".... creating installation deployment package file: tar -cpf ${agent_home_archive_file} -C ${agent_home_parent_dir} ${agent_home_basename}"
            tar -X "${exclude_file}" -cpf "${agent_home_archive_file}" -C "${agent_home_parent_dir}" "${agent_home_basename}"
        else
            Log ".... creating installation deployment package file: tar -cpf ${agent_home_archive_file} ${agent_home_basename}"
            (
                cd "${agent_home_parent_dir}" || exit 2
                tar -X "${exclude_file}" -cpf "${agent_home_archive_file}" "${agent_home_basename}"
            )
        fi

        test -e "${agent_home_archive_file}" && gzip -f "${agent_home_archive_file}"
        run_tarballs="${agent_home_archive_file}".gz
        Log ".... installation deployment package ready: ${agent_home_archive_file}.gz"
    fi

    if [ -n "${cfg_data}" ] && [ "${cfg_data#*"${cfg_home}"}" = "${cfg_data}" ]
    then
        agent_data_dir="${run_work_dir}""${cfg_data}"
        agent_data_parent_dir=$(dirname "${agent_data_dir}")
        agent_data_basename=$(basename "${agent_data_dir}")
        agent_data_archive_file="${agent_archive_dir}"/js7_deploy_agent_unix."${agentId}"."${cfg_release}".config.tar
    
        exclude_file=$(CreateExcludeFile "${agent_data_dir}"/logs "${agent_data_dir}"/state "${agent_data_dir}"/work)

        if [ -n "${os_compat}" ]
        then
            Log ".... creating configuration deployment package file: tar -cpf ${agent_data_archive_file} -C ${agent_data_parent_dir} ${agent_data_basename}"
            tar -X "${exclude_file}" -cpf "${agent_data_archive_file}" -C "${agent_data_parent_dir}" "${agent_data_basename}"
        else
            Log ".... creating configuration deployment package file: tar -cpf ${agent_data_archive_file} ${agent_data_basename}"
            (
                cd "${agent_data_parent_dir}" || exit 2
                tar -X "${exclude_file}" -cpf "${agent_data_archive_file}" "${agent_data_basename}"
            )
        fi

        test -e "${agent_data_archive_file}" && gzip -f "${agent_data_archive_file}"
        Log ".... configuration deployment package ready: ${agent_data_archive_file}.gz"

        if [ -n "${run_tarballs}" ]
        then
            run_tarballs="${run_tarballs}",
       fi
        run_tarballs="${run_tarballs}""${agent_data_archive_file}".gz
    fi
}

CreateAgentJobScript()
{
    controllerId=$1
    agentId=$2
    agentJson=$3
    run_tarballs=$4
    agent_archive_dir=$5

    use_tarballs=$(echo "${run_tarballs}" | sed 's/^"//' | sed 's/"$//')

    cfg_force_sudo=$(echo "${agentJson}" | jq -r ".target.forceSudo // empty" | sed 's/^"//' | sed 's/"$//')

    if [ -z "${cfg_force_sudo}" ]
    then
        cfg_force_sudo="${force_sudo}"
    fi
    
    cfg_host=$(echo "${agentJson}" | jq -r ".target.connection.host // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_port=$(echo "${agentJson}" | jq -r ".target.connection.port // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_user=$(echo "${agentJson}" | jq -r ".target.authentication.user // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_keyfile=$(echo "${agentJson}" | jq -r ".target.authentication.keyFile // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_location=$(echo "${agentJson}" | jq -r ".target.packageLocation // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home=$(echo "${agentJson}" | jq -r ".installation.home // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data=$(echo "${agentJson}" | jq -r ".installation.data // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home_owner=$(echo "${agentJson}" | jq -r ".installation.homeOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data_owner=$(echo "${agentJson}" | jq -r ".installation.dataOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_http_port=$(echo "${agentJson}" | jq -r ".installation.httpPort // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_pre_extract=$(echo "${agentJson}" | jq -r ".target.execPre // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_post_extract=$(echo "${agentJson}" | jq -r ".target.execPost // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_make_service=$(echo "${agentJson}" | jq -r ".target.makeService // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_service_name=$(echo "${agentJson}" | jq -r ".target.serviceName // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_service_dir=$(echo "${agentJson}" | jq -r ".target.serviceDir // empty" | sed 's/^"//' | sed 's/"$//')

    use_http_port=$(echo "${cfg_http_port}" | cut -d':' -f 2)
    cfg_service_name=${cfg_service_name:-js7_agent_${use_http_port}.service}
    if [ "${cfg_service_name%*.service}" = "${cfg_service_name}" ]
    then
        cfg_service_name="${cfg_service_name}".service
    fi

    if [ -z "${cfg_service_dir}" ]
    then
        cfg_service_dir=/usr/lib/systemd/system
    fi

    if [ -z "${cfg_location}" ]
    then
        cfg_location="."
    fi

    if [ -n "${use_tarballs}" ] && [ -n "${cfg_host}" ] && [ -n "${cfg_user}" ]
    then
        touch "${deploy_file}"
        chmod u+x "${deploy_file}"

        printf '#!/bin/sh\n\n'                                                                                           > "${deploy_file}"
        printf 'set -e\n\n'                                                                                             >> "${deploy_file}"

        touch "${job_file}"
        chmod u+x "${job_file}"

        printf '#!/bin/sh\n\n'                                                                                           > "${job_file}"
        printf 'set -e\n\n'                                                                                             >> "${job_file}"

        if [ -n "${cfg_force_sudo}" ]
        then
            printf 'force_sudo="1"\n'                                                                                   >> "${job_file}"
        else
            printf 'force_sudo="0"\n'                                                                                   >> "${job_file}"
        fi

        printf 'if [ "$(id -u)" -eq 0 ]\n'                                                                              >> "${job_file}"
        printf 'then\n'                                                                                                 >> "${job_file}"
        printf '    use_sudo=""\n'                                                                                      >> "${job_file}"
        printf 'else\n'                                                                                                 >> "${job_file}"
        printf '    use_sudo="sudo"\n'                                                                                  >> "${job_file}"
        printf 'fi\n\n'                                                                                                 >> "${job_file}"

        printf 'systemd_service_dir="%s"\n' "${cfg_service_dir}"                                                        >> "${job_file}"
        printf 'systemd_service_name="%s"\n' "${cfg_service_name}"                                                      >> "${job_file}"
        AddDeployScriptFunctions "${job_file}"

        tarballIndex=0
        set -- "$(echo "${use_tarballs}" | sed -r 's/[,]+/ /g')"
        for i in $@; do
            if [ ! -f "${i}" ]
            then
                LogError "tarball file not found: $i"
                exit 1
            fi
            
            if [ -n "${cfg_port}" ]
            then
                use_scp_port="-P ${cfg_port}"
                use_ssh_port="-p ${cfg_port}"
            else
                use_scp_port=
                use_ssh_port=
            fi

            printf 'echo "deploying %s to host %s"\n' "${i}" "${cfg_host}"                                                                        >> "${deploy_file}"
            if [ -n "${cfg_keyfile}" ]
            then
                printf 'scp -i "%s" %s "%s" %s@%s:"%s"\n' "${cfg_keyfile}" "${use_scp_port}" "${i}" "${cfg_user}" "${cfg_host}" "${cfg_location}" >> "${deploy_file}"
            else
                printf 'scp %s "%s" %s@%s:"%s"\n' "${i}" "${use_scp_port}" "${cfg_user}" "${cfg_host}" "${cfg_location}"                          >> "${deploy_file}"
            fi

            if [ "${tarballIndex}" -eq 0 ]
            then
                if [ -n "${cfg_exec_pre_extract}" ]
                then
                    printf '%s\n' "Log \".. executing pre-extraction command: ${cfg_exec_pre_extract}\""                >> "${job_file}"
                    printf '%s\n\n' "${cfg_exec_pre_extract}"                                                           >> "${job_file}"
                fi
            fi

            if [ "${tarballIndex}" -eq 0 ]
            then
                if [ -n "${cfg_home}" ]
                then
                    printf 'if [ -d "%s" ]\n' "${cfg_home}"                                                             >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. removing home directory: %s"\n' "${cfg_home}"                                   >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "${cfg_home}"                            >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        rm -f -r "%s"\n' "${cfg_home}"                                                      >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} rm -f -r "%s"\n' "${cfg_home}"                                          >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'if [ ! -d "%s" ]\n' "$(dirname "${cfg_home}")"                                              >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. creating parent home directory: %s"\n' "$(dirname "${cfg_home}")"               >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "$(dirname $(dirname "${cfg_home}"))"    >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        mkdir -p "%s"\n' "$(dirname "${cfg_home}")"                                         >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} mkdir -p "%s"\n' "$(dirname "${cfg_home}")"                             >> "${job_file}"
                    printf '    fi\n\n'                                                                                 >> "${job_file}"

                    printf '    if [ "${force_sudo}" -eq 1 ] || [ ! -w "%s" ]\n' "$(dirname $(dirname "${cfg_home}"))"  >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        Log ".. owning parent home directory to: %s"\n' "${cfg_user}"                       >> "${job_file}"
                    printf '        ${use_sudo} chown %s "%s"\n' "${cfg_user}" "$(dirname "${cfg_home}")"               >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'Log ".. extracting tarball to home directory: %s"\n' "$(dirname "${cfg_home}")"             >> "${job_file}"
                    printf 'cd "%s" > /dev/null\n\n' "$(dirname "${cfg_home}")"                                         >> "${job_file}"
                fi
            else
                if [ -n "${cfg_data}" ]
                then
                    printf 'if [ ! -d "%s" ]\n' "$(dirname "${cfg_data}")"                                              >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. creating parent data directory: %s"\n' "$(dirname "${cfg_data}")"               >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "$(dirname $(dirname "${cfg_data}"))"    >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        mkdir -p "%s"\n' "$(dirname "${cfg_data}")"                                         >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} mkdir -p "%s"\n' "$(dirname "${cfg_data}")"                             >> "${job_file}"
                    printf '    fi\n\n'                                                                                 >> "${job_file}"

                    printf '    if [ "${force_sudo}" -eq 1 ] || [ ! -w "%s" ]\n' "$(dirname $(dirname "${cfg_data}"))"  >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        Log ".. owning parent data directory to: %s"\n' "${cfg_user}"                       >> "${job_file}"
                    printf '        ${use_sudo} chown -R %s "%s"\n' "${cfg_user}" "$(dirname "${cfg_data}")"            >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'else\n'                                                                                     >> "${job_file}"
                    printf '    if [ -d "%s" ]\n' "${cfg_data}"                                                         >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        if [ "${force_sudo}" -eq 1 ] || [ ! -w "%s" ]\n' "${cfg_data}"                      >> "${job_file}"
                    printf '        then\n'                                                                             >> "${job_file}"
                    printf '            Log ".. owning data directory to: %s"\n' "${cfg_user}"                          >> "${job_file}"
                    printf '            ${use_sudo} chown -R %s "%s"\n' "${cfg_user}" "${cfg_data}"                     >> "${job_file}"
                    printf '        fi\n'                                                                               >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'Log ".. extracting tarball to data directory: %s"\n' "$(dirname "${cfg_data}")"             >> "${job_file}"
                    printf 'cd "%s" > /dev/null\n\n' "$(dirname "${cfg_data}")"                                         >> "${job_file}"
                fi
            fi

            printf 'Log ".. extracting tarball: %s"\n' "$(basename ${i})"                                               >> "${job_file}"
            printf 'if [ "${force_sudo}" -eq 1 ]\n'                                                                     >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    test -e "%s" && gzip -c -d < "%s" | ${use_sudo} tar -xpf -\n' "${cfg_location}"/"$(basename ${i})" "${cfg_location}"/"$(basename ${i})" >> "${job_file}"
            printf 'else\n'                                                                                             >> "${job_file}"
            printf '    test -e "%s" && gzip -c -d < "%s" | tar -xpf -\n' "${cfg_location}"/"$(basename ${i})" "${cfg_location}"/"$(basename ${i})" >> "${job_file}"
            printf 'fi\n'                                                                                               >> "${job_file}"
            printf 'rc=$?\n'                                                                                            >> "${job_file}"
            printf 'cd - > /dev/null\n\n'                                                                               >> "${job_file}"

            tarballIndex=$((tarballIndex+1)) 
        done

        if [ -n "${cfg_home}" ] && [ -n "${cfg_home_owner}" ] && [ ! "${cfg_user}" = "${cfg_home_owner}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    Log ".. owning home directory to: %s"\n' "${cfg_home_owner}"                                    >> "${job_file}"
            printf '    ${use_sudo} chown -R %s "%s"\n' "${cfg_home_owner}" "${cfg_home}"                               >> "${job_file}"
            printf '    rc=$?\n'                                                                                        >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_data}" ] && [ -n "${cfg_data_owner}" ] && [ ! "${cfg_user}" = "${cfg_data_owner}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    Log ".. owning data directory to: %s"\n' "${cfg_data_owner}"                                    >> "${job_file}"
            printf '    ${use_sudo} chown -R %s "%s"\n' "${cfg_data_owner}" "${cfg_data}"                               >> "${job_file}"
            printf '    rc=$?\n'                                                                                        >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_make_service}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    Log ".. creating systemd service: %s"\n' "js7_agent_${use_http_port}.service"                   >> "${job_file}"
            printf '    MakeService "%s"\n' "${cfg_home}/bin/agent_${use_http_port}.service"                            >> "${job_file}"
            printf '    rc=$?\n'                                                                                        >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_exec_post_extract}" ]
        then
            printf '%s\n' "Log \".. executing post-extraction command: ${cfg_exec_post_extract}\""                      >> "${job_file}"
            printf '%s\n\n' "${cfg_exec_post_extract}"                                                                  >> "${job_file}"
        fi

        printf 'Log ".. deployment completed, return code: ${rc}"\n'                                                    >> "${job_file}"
        printf 'exit ${rc}\n\n'                                                                                         >> "${job_file}"

        if [ -n "${cfg_keyfile}" ]
        then
            printf 'scp -i "%s" %s "%s" %s@%s:"%s"\n' "${cfg_keyfile}" "${use_scp_port}" "${agent_archive_dir}/run_deploy_agent.sh" "${cfg_user}" "${cfg_host}" "${cfg_location}" >> "${deploy_file}"
            printf 'ssh -i "%s" %s -t -t -o LogLevel=QUIET %s@%s %s\n\n' "${cfg_keyfile}" "${use_ssh_port}" "${cfg_user}" "${cfg_host}" "'chmod u+x ${cfg_location}/run_deploy_agent.sh && ${cfg_location}/run_deploy_agent.sh'" >> "${deploy_file}"
        else
            printf 'scp %s "%s" %s@%s:"%s"\n' "${agent_archive_dir}/run_deploy_agent.sh" "${use_scp_port}" "${cfg_user}" "${cfg_host}" "${cfg_location}" >> "${deploy_file}"
            printf 'ssh %s -t -t -o LogLevel=QUIET %s@%s %s\n\n' "${use_ssh_port}" "${cfg_user}" "${cfg_host}" "'chmod u+x ${cfg_location}/run_deploy_agent.sh && ${cfg_location}/run_deploy_agent.sh'" >> "${deploy_file}"
        fi        
    fi
}

CreateControllerPackage()
{
    controllerId=$1
    controllerInstance=$2
    controllerJson=$3

    Log ".... creating install script: ${run_file}"
    CreateControllerInstallScript "${controllerId}" "${controllerInstance}" "${controllerJson}"
    
    cfg_release=$(echo "${controllerJson}" | jq -r ".media.release // empty" | sed 's/^"//' | sed 's/"$//')
    if [ -z "${cfg_release}" ]
    then
        LogError "Deployment Descriptor file misses element .media.release: --deploy-desc=${deploy_desc}"
        exit 1
    fi

    cfg_tarball=$(echo "${controllerJson}" | jq -r ".media.tarball // empty" | sed 's/^"//' | sed 's/"$//')
    if [ -z "${cfg_tarball}" ]
    then
        LogError "Deployment Descriptor file misses element .media.tarball: --deploy-desc=${deploy_desc}"
        exit 1
    fi

    controller_archive_dir="${archive_dir}"/"${cfg_descriptor_id}"/controllers/"${controllerId}"

    if [ ! -d "${controller_archive_dir}" ]
    then
        mkdir -p "${controller_archive_dir}"
    else
        if [ -d "${controller_archive_dir}/${controllerInstance}" ]
        then
            ${use_sudo} rm -f -r "${controller_archive_dir}/${controllerInstance}"
        fi
    fi

    if [ -z "${dry_run}" ]
    then
        "${run_file}"
        CreateControllerTarball "${controllerId}" "${controllerInstance}" "${controllerJson}"
        CreateControllerJobScript "${controllerId}" "${controllerInstance}" "${controllerJson}" "${run_tarballs}" "${controller_archive_dir}"

        cp -p "${run_file}" "${controller_archive_dir}"/run_install_controller.sh
        Log ".... install script for deployment package ready: ${controller_archive_dir}/run_install_controller.sh"

        cp -p "${job_file}" "${controller_archive_dir}"/run_deploy_controller.sh
        Log ".... job script for deployment package ready: ${controller_archive_dir}/run_deploy_controller.sh"
        
        cp -p "${deploy_file}" "${controller_archive_dir}"/run_rollout_controller.sh
        Log ".... rollout script for deployment package ready: ${controller_archive_dir}/run_rollout_controller.sh"

        if [ -s "${run_rollouts_file}" ]
        then
            printf ',' >> "${run_rollouts_file}"
        fi
        
        printf '%s' "${controller_archive_dir}"/run_rollout_controller.sh >> "${run_rollouts_file}"

        if [ -z "${keep_work}" ] && [ -d "${work_dir}"/controllers/"${controllerId}" ]
        then
            ${use_sudo} rm -f -r "${work_dir}"/controllers/"${controllerId}"
        fi
    fi
}

CreateControllerInstallScript()
{
    controllerId=$1
    controllerInstance=$2
    controllerJson=$3

    run_config_dir="${config_dir}"
    run_script_dir="${script_dir}"
    run_work_dir="${work_dir}/controllers/${controllerId}"
    
    if [ -d "${run_work_dir}" ]
    then
        ${use_sudo} rm -f -r "${run_work_dir}"
    fi

    cfg_license_key=$(< "${deploy_desc}" jq -r ".license.licenseKeyFile // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_license_bin=$(< "${deploy_desc}" jq -r ".license.licenseBinFile // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_release=$(echo "${controllerJson}" | jq -r ".media.release // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_tarball=$(echo "${controllerJson}" | jq -r ".media.tarball // empty" | sed 's/^"//' | sed 's/"$//')

    if [ ! "$(echo "${cfg_tarball}" | cut -c1)" = "/" ] && [ ! "$(echo "${cfg_tarball}" | cut -c1)" = "." ] && [ ! "$(echo "${cfg_tarball}" | cut -c1)" = '$' ]
    then
        cfg_tarball="${release_dir}"/"${cfg_tarball}"
    fi

    cfg_home=$(echo "${controllerJson}" | jq -r ".installation.home // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data=$(echo "${controllerJson}" | jq -r ".installation.data // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_run_user=$(echo "${controllerJson}" | jq -r ".installation.runUser // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home_owner=$(echo "${controllerJson}" | jq -r ".installation.homeOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data_owner=$(echo "${controllerJson}" | jq -r ".installation.dataOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_http_port=$(echo "${controllerJson}" | jq -r ".installation.httpPort // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_https_port=$(echo "${controllerJson}" | jq -r ".installation.httpsPort // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_java_home=$(echo "${controllerJson}" | jq -r ".installation.javaHome // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_java_options=$(echo "${controllerJson}" | jq -r ".installation.javaOptions // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_pre=$(echo "${controllerJson}" | jq -r ".installation.execPre // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_post=$(echo "${controllerJson}" | jq -r ".installation.execPost // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_joc_ref=$(< "${deploy_desc}" jq -r ".controllers[] | select(.controllerId=\"${controllerId}\") | .jocRef // empty" | sed 's/^"//' | sed 's/"$//')
    if [ -n "${cfg_joc_ref}" ] && [ -n "${isJocPresent}" ]
    then
        tmp_instance=$(< "${deploy_desc}" jq -r ".joc[].members | select(.clusterId=\"${cfg_joc_ref}\") | .instances[0] // empty" | sed 's/^"//' | sed 's/"$//')
        if [ -n "${tmp_instance}" ]
        then
            cfg_primary_joc_cert=$(< "${deploy_desc}" jq -r ".joc[].members | select(.clusterId=\"${cfg_joc_ref}\") | .instances[0].configuration.certificates.cert // empty" | sed 's/^"//' | sed 's/"$//')
            tmp_instance=$(< "${deploy_desc}" jq -r ".joc[].members | select(.clusterId=\"${cfg_joc_ref}\") | .instances[1] // empty" | sed 's/^"//' | sed 's/"$//')
            if [ -n "${tmp_instance}" ]
            then
                cfg_secondary_joc_cert=$(< "${deploy_desc}" jq -r ".joc[].members | select(.clusterId=\"${cfg_joc_ref}\") | .instances[1].configuration.certificates.cert // empty" | sed 's/^"//' | sed 's/"$//')
            fi
        fi
    else
        cfg_primary_joc_cert=$(< "${deploy_desc}" jq -r ".certificates.joc.primaryJocCert // empty" | sed 's/^"//' | sed 's/"$//')
        cfg_secondary_joc_cert=$(< "${deploy_desc}" jq -r ".certificates.joc.secondaryJocCert // empty" | sed 's/^"//' | sed 's/"$//')            
    fi

    cfg_controller_id=${controllerId}

    cfg_primary_controller_cert=$(< "${deploy_desc}" jq -r ".controllers[] | select(.controllerId=\"${controllerId}\") | .primary.configuration.certificates.cert // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_secondary_controller_cert=$(< "${deploy_desc}" jq -r ".controllers[] | select(.controllerId=\"${controllerId}\") | .secondary.configuration.certificates.cert // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_keystore=$(echo "${controllerJson}" | jq -r ".configuration.certificates.keyStore // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_keystore_password=$(echo "${controllerJson}" | jq -r ".configuration.certificates.keyStorePassword // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_key_alias=$(echo "${controllerJson}" | jq -r ".configuration.certificates.keyAlias // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_truststore=$(echo "${controllerJson}" | jq -r ".configuration.certificates.trustStore // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_truststore_password=$(echo "${controllerJson}" | jq -r ".configuration.certificates.trustStorePassword // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_service_name=$(echo "${controllerJson}" | jq -r ".target.serviceName // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_service_dir=$(echo "${controllerJson}" | jq -r ".target.serviceDir // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_service_name=${cfg_service_name:-js7_controller_${controllerId}.service}
    if [ "${cfg_service_name%*.service}" = "${cfg_service_name}" ]
    then
        cfg_service_name="${cfg_service_name}".service
    fi

    if [ -z "${cfg_run_user}" ] && [ -n "${cfg_data_owner}" ]
    then
        cfg_run_user=${cfg_data_owner}
    fi
    cfg_run_user=$(echo "${cfg_run_user}" | cut -d':' -f 1)    

    cfg_config_dir=""
    i=0
    j=$(echo "${controllerJson}" | jq -r ".configuration.templates  // empty| select (.!=null) | length")
    if [ -n "$j" ]
    then
        while [ "$i" -lt "$j" ]
        do
            if [ -n "${cfg_config_dir}" ]
            then
                cfg_config_dir="${cfg_config_dir}",
            fi
            cfg_config_dir="${cfg_config_dir}\${DEP_CONFIG}/$(echo "${controllerJson}" | jq ".configuration.templates[$i] // empty" | sed 's/^"//' | sed 's/"$//')"
            i=$(( i + 1 ))
        done
    fi

    cfg_controller_conf=$(echo "${controllerJson}" | jq -r ".configuration.files.controllerConf // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_private_conf=$(echo "${controllerJson}" | jq -r ".configuration.files.privateConf // empty" | sed 's/^"//' | sed 's/"$//')

    touch "${run_file}"
    chmod u+x "${run_file}"

    printf '#!/bin/sh\n\n'                                                                                           > "${run_file}"
    printf 'set -e\n\n'                                                                                             >> "${run_file}"
    printf 'DEP_BIN="%s"\n' "${run_script_dir}"                                                                     >> "${run_file}"
    printf 'DEP_CONFIG="%s"\n' "${run_config_dir}"                                                                  >> "${run_file}"
    printf 'DEP_WORK_TEMP="%s"\n\n' "${run_work_dir}"                                                               >> "${run_file}"
    printf 'mkdir -p "${DEP_WORK_TEMP}"\n\n'                                                                        >> "${run_file}"
    printf '"${DEP_BIN}"/js7_install_controller.sh \\\n'                                                            >> "${run_file}"    
    printf '    --real-path-prefix="%s" \\\n'  "\${DEP_WORK_TEMP}"                                                  >> "${run_file}"

    if [ -n "${cfg_release}" ]
    then
        printf '    --release="%s" \\\n' "${cfg_release}"                                                           >> "${run_file}"
    fi

    if [ -n "${cfg_tarball}" ]
    then
        printf '    --tarball="%s" \\\n' "${cfg_tarball}"                                                           >> "${run_file}"
    fi

    if [ -n "${cfg_home}" ]
    then
        printf '    --home="%s" \\\n' "\${DEP_WORK_TEMP}${cfg_home}"                                                >> "${run_file}"
    fi

    if [ -n "${cfg_data}" ]
    then
        printf '    --data="%s" \\\n' "\${DEP_WORK_TEMP}${cfg_data}"                                                >> "${run_file}"
    fi

    if [ -n "${cfg_run_user}" ]
    then
        printf '    --user="%s" \\\n' "${cfg_run_user}"                                                             >> "${run_file}"
    fi

    if [ -n "${cfg_home_owner}" ]
    then
        printf '    --home-owner="%s" \\\n' "${cfg_home_owner}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_data_owner}" ]
    then
        printf '    --data-owner="%s" \\\n' "${cfg_data_owner}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_http_port}" ]
    then
        printf '    --http-port="%s" \\\n' "${cfg_http_port}"                                                       >> "${run_file}"
    fi

    if [ -n "${cfg_https_port}" ]
    then
        printf '    --https-port="%s" \\\n' "${cfg_https_port}"                                                     >> "${run_file}"
    fi


    if [ -n "${cfg_license_key}" ]
    then
        printf '    --license-key="%s" \\\n' "\${DEP_CONFIG}/${cfg_license_key}"                                    >> "${run_file}"
    fi

    if [ -n "${cfg_license_bin}" ]
    then
        printf '    --license-bin="%s" \\\n' "\${DEP_CONFIG}/${cfg_license_bin}"                                    >> "${run_file}"
    fi


    if [ -n "${cfg_java_home}" ]
    then
        printf '    --java-home="%s" \\\n' "${cfg_java_home}"                                                       >> "${run_file}"
    fi

    if [ -n "${cfg_java_options}" ]
    then
        printf '    --java-options="%s" \\\n' "${cfg_java_options}"                                                 >> "${run_file}"
    fi

    if [ -n "${cfg_exec_post}" ]
    then
        printf '    --exec-start="%s" \\\n' "${cfg_exec_post}"                                                      >> "${run_file}"
    fi

    if [ -n "${cfg_exec_pre}" ]
    then
        printf '    --exec-stop="%s" \\\n' "${cfg_exec_pre}"                                                        >> "${run_file}"
    fi


    if [ -n "${cfg_primary_joc_cert}" ]
    then
        printf '    --joc-primary-cert="%s" \\\n' "\${DEP_CONFIG}/${cfg_primary_joc_cert}"                          >> "${run_file}"
    fi

    if [ -n "${cfg_secondary_joc_cert}" ]
    then
        printf '    --joc-secondary-cert="%s" \\\n' "\${DEP_CONFIG}/${cfg_secondary_joc_cert}"                      >> "${run_file}"
    fi


    if [ -n "${cfg_controller_id}" ]
    then
        printf '    --controller-id="%s" \\\n' "${cfg_controller_id}"                                               >> "${run_file}"
    fi

    if [ "${controllerInstance}" = "secondary" ]
    then
        printf '    --standby \\\n'                                                                                 >> "${run_file}"
    fi

    if [ -n "${cfg_primary_controller_cert}" ]
    then
        printf '    --controller-primary-cert="%s" \\\n' "\${DEP_CONFIG}/${cfg_primary_controller_cert}"            >> "${run_file}"
    fi

    if [ -n "${cfg_secondary_controller_cert}" ]
    then
        printf '    --controller-secondary-cert="%s" \\\n' "\${DEP_CONFIG}/${cfg_secondary_controller_cert}"        >> "${run_file}"
    fi


    if [ -n "${cfg_keystore}" ]
    then
        printf '    --keystore="%s" \\\n' "\${DEP_CONFIG}/${cfg_keystore}"                                          >> "${run_file}"
    fi

    if [ -n "${cfg_keystore_password}" ]
    then
        printf '    --keystore-password="%s" \\\n' "${cfg_keystore_password}"                                       >> "${run_file}"
    fi

    if [ -n "${cfg_key_alias}" ]
    then
        printf '    --keystore-alias="%s" \\\n' "${cfg_key_alias}"                                                  >> "${run_file}"
    fi

    if [ -n "${cfg_truststore}" ]
    then
        printf '    --truststore="%s" \\\n' "\${DEP_CONFIG}/${cfg_truststore}"                                      >> "${run_file}"
    fi

    if [ -n "${cfg_truststore_password}" ]
    then
        printf '    --truststore-password="%s" \\\n' "${cfg_truststore_password}"                                   >> "${run_file}"
    fi

    if [ -n "${cfg_config_dir}" ]
    then
        printf '    --deploy-dir="%s" \\\n' "${cfg_config_dir}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_controller_conf}" ]
    then
         printf '    --controller-conf="%s" \\\n' "\${DEP_CONFIG}/${cfg_controller_conf}"                           >> "${run_file}"
    fi

    if [ -n "${cfg_private_conf}" ]
    then
        printf '    --private-conf="%s" \\\n' "\${DEP_CONFIG}/${cfg_private_conf}"                                  >> "${run_file}"
    fi

    if [ -n "${cfg_service_name}" ]
    then
        printf '    --service-name="%s" \\\n' "\${cfg_service_name}"                                                >> "${run_file}"
    fi

    if [ -n "${cfg_service_dir}" ]
    then
        printf '    --service-dir="%s" \\\n' "\${cfg_service_dir}"                                                  >> "${run_file}"
    fi

    if [ -n "${show_logs}" ]
    then
        printf '    --show-logs \\\n'                                                                               >> "${run_file}"
    fi

    if [ -n "${log_dir}" ]
    then
        printf '    --log-dir=%s \\\n' "${log_dir}"                                                                 >> "${run_file}"
    fi

    if [ -n "${force_sudo}" ]
    then
        printf '    --force-sudo \\\n'                                                                              >> "${run_file}"
    fi

    printf '    --make-dirs\n'                                                                                      >> "${run_file}"
}

CreateControllerTarball()
{
    controllerId=$1
    controllerInstance=$2
    controllerJson=$3

    cfg_release=$(echo "${controllerJson}" | jq -r ".media.release" | sed 's/^"//' | sed 's/"$//')
    cfg_home=$(echo "${controllerJson}" | jq -r ".installation.home" | sed 's/^"//' | sed 's/"$//')
    cfg_data=$(echo "${controllerJson}" | jq -r ".installation.data" | sed 's/^"//' | sed 's/"$//')

    run_tarballs=
    run_work_dir="${work_dir}/controllers/${controllerId}"        
    controller_archive_dir="${archive_dir}"/"${cfg_descriptor_id}"/controllers/"${controllerId}"/"${controllerInstance}"
    mkdir -p "${controller_archive_dir}"

    if [ -n "${cfg_home}" ]
    then
        controller_home_dir="${run_work_dir}""${cfg_home}"
        controller_home_parent_dir=$(dirname "${controller_home_dir}")
        controller_home_basename=$(basename "${controller_home_dir}")
        controller_home_archive_file="${controller_archive_dir}"/js7_deploy_controller_unix."${controllerId}"."${controllerInstance}"."${cfg_release}".install.tar

        exclude_file=$(CreateExcludeFile "${controller_home_dir}")
        
        if [ -n "${os_compat}" ]
        then
            Log ".... creating installation deployment package file: tar -cpf ${controller_home_archive_file} -C ${controller_home_parent_dir} ${controller_home_basename}"
            tar -X "${exclude_file}" -cpf "${controller_home_archive_file}" -C "${controller_home_parent_dir}" "${controller_home_basename}"
        else
            Log ".... creating installation deployment package file: tar -cpf ${controller_home_archive_file} ${controller_home_basename}"
            (
                cd "${controller_home_parent_dir}" || exit 2
                tar -X "${exclude_file}" -cpf "${controller_home_archive_file}" "${controller_home_basename}"
            )
        fi

        test -e "${controller_home_archive_file}" && gzip -f "${controller_home_archive_file}"
        Log ".... installation deployment package ready: ${controller_home_archive_file}.gz"
        run_tarballs="${controller_home_archive_file}".gz
    fi

    if [ -n "${cfg_data}" ] && [ "${cfg_data#*"${cfg_home}"}" = "${cfg_data}" ]
    then
        controller_data_dir="${run_work_dir}""${cfg_data}"
        controller_data_parent_dir=$(dirname "${controller_data_dir}")
        controller_data_basename=$(basename "${controller_data_dir}")
        controller_data_archive_file="${controller_archive_dir}"/js7_deploy_controller_unix."${controllerId}"."${controllerInstance}"."${cfg_release}".config.tar
    
        exclude_file=$(CreateExcludeFile "${controller_data_dir}")

        if [ -n "${os_compat}" ]
        then
            Log ".... creating configuration deployment package file: tar -cpf ${controller_data_archive_file} -C ${controller_data_parent_dir} ${controller_data_basename}"
            tar -X "${exclude_file}" -cpf "${controller_data_archive_file}" -C "${controller_data_parent_dir}" "${controller_data_basename}"
        else
            Log ".... creating configuration deployment package file: tar -cpf ${controller_data_archive_file} ${controller_data_basename}"
            (
                cd "${controller_data_parent_dir}" || exit 2
                tar -X "${exclude_file}" -cpf "${controller_data_archive_file}" "${controller_data_basename}"
            )
        fi
        
        test -e "${controller_data_archive_file}" && gzip -f "${controller_data_archive_file}"
        Log ".... configuration deployment package ready: ${controller_data_archive_file}.gz"

        if [ -n "${run_tarballs}" ]
        then
            run_tarballs="${run_tarballs}",
        fi
        run_tarballs="${run_tarballs}""${controller_data_archive_file}".gz
    fi
}

CreateControllerJobScript()
{
    controllerId=$1
    controllerInstance=$2
    controllerJson=$3
    run_tarballs=$4
    controller_archive_dir=$5

    use_tarballs=$(echo "${run_tarballs}" | sed 's/^"//' | sed 's/"$//')

    cfg_force_sudo=$(echo "${controllerJson}" | jq -r ".target.forceSudo // empty" | sed 's/^"//' | sed 's/"$//')

    if [ -z "${cfg_force_sudo}" ]
    then
        cfg_force_sudo="${force_sudo}"
    fi
    
    cfg_host=$(echo "${controllerJson}" | jq -r ".target.connection.host // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_port=$(echo "${controllerJson}" | jq -r ".target.connection.port // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_user=$(echo "${controllerJson}" | jq -r ".target.authentication.user // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_keyfile=$(echo "${controllerJson}" | jq -r ".target.authentication.keyFile // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_location=$(echo "${controllerJson}" | jq -r ".target.packageLocation // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home=$(echo "${controllerJson}" | jq -r ".installation.home // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data=$(echo "${controllerJson}" | jq -r ".installation.data // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home_owner=$(echo "${controllerJson}" | jq -r ".installation.homeOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data_owner=$(echo "${controllerJson}" | jq -r ".installation.dataOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_pre_extract=$(echo "${controllerJson}" | jq -r ".target.execPre // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_post_extract=$(echo "${controllerJson}" | jq -r ".target.execPost // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_make_service=$(echo "${controllerJson}" | jq -r ".target.makeService // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_service_name=$(echo "${controllerJson}" | jq -r ".target.serviceName // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_service_dir=$(echo "${controllerJson}" | jq -r ".target.serviceDir // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_service_name=${cfg_service_name:-js7_controller_${controllerId}.service}
    if [ "${cfg_service_name%*.service}" = "${cfg_service_name}" ]
    then
        cfg_service_name="${cfg_service_name}".service
    fi

    if [ -z "${cfg_service_dir}" ]
    then
        cfg_service_dir=/usr/lib/systemd/system
    fi

    if [ -z "${cfg_location}" ]
    then
        cfg_location="."
    fi

    if [ -n "${use_tarballs}" ] && [ -n "${cfg_host}" ] && [ -n "${cfg_user}" ]
    then
        touch "${deploy_file}"
        chmod u+x "${deploy_file}"

        printf '#!/bin/sh\n\n'                                                                                           > "${deploy_file}"
        printf 'set -e\n\n'                                                                                             >> "${deploy_file}"

        touch "${job_file}"
        chmod u+x "${job_file}"

        printf '#!/bin/sh\n\n'                                                                                           > "${job_file}"
        printf 'set -e\n\n'                                                                                             >> "${job_file}"

        if [ -n "${cfg_force_sudo}" ]
        then
            printf 'force_sudo="1"\n'                                                                                   >> "${job_file}"
        else
            printf 'force_sudo="0"\n'                                                                                   >> "${job_file}"
        fi

        printf 'if [ "$(id -u)" -eq 0 ]\n'                                                                              >> "${job_file}"
        printf 'then\n'                                                                                                 >> "${job_file}"
        printf '    use_sudo=""\n'                                                                                      >> "${job_file}"
        printf 'else\n'                                                                                                 >> "${job_file}"
        printf '    use_sudo="sudo"\n'                                                                                  >> "${job_file}"
        printf 'fi\n\n'                                                                                                 >> "${job_file}"

        printf 'systemd_service_dir="%s"\n' "${cfg_service_dir}"                                                        >> "${job_file}"
        printf 'systemd_service_name="%s"\n' "${cfg_service_name}"                                                      >> "${job_file}"
        AddDeployScriptFunctions "${job_file}"

        tarballIndex=0
        set -- "$(echo "${use_tarballs}" | sed -r 's/[,]+/ /g')"
        for i in $@; do
            if [ ! -f "${i}" ]
            then
                LogError "tarball file not found: $i"
                exit 1
            fi

            if [ -n "${cfg_port}" ]
            then
                use_scp_port="-P ${cfg_port}"
                use_ssh_port="-p ${cfg_port}"
            else
                use_scp_port=
                use_ssh_port=
            fi

            printf 'echo "deploying %s to host %s"\n' "${i}" "${cfg_host}"                                                                        >> "${deploy_file}"
            if [ -n "${cfg_keyfile}" ]
            then
                printf 'scp -i "%s" %s "%s" %s@%s:"%s"\n' "${cfg_keyfile}" "${use_scp_port}" "${i}" "${cfg_user}" "${cfg_host}" "${cfg_location}" >> "${deploy_file}"
            else
                printf 'scp %s "%s" %s@%s:"%s"\n' "${i}" "${use_scp_port}" "${cfg_user}" "${cfg_host}" "${cfg_location}"                          >> "${deploy_file}"
            fi

            if [ "${tarballIndex}" -eq 0 ]
            then
                if [ -n "${cfg_exec_pre_extract}" ]
                then
                    printf '%s\n' "Log \".. executing pre-extraction command: ${cfg_exec_pre_extract}\""                >> "${job_file}"
                    printf '%s\n\n' "${cfg_exec_pre_extract}"                                                           >> "${job_file}"
                fi
            fi
            
            if [ "${tarballIndex}" -eq 0 ]
            then
                if [ -n "${cfg_home}" ]
                then
                    printf 'if [ -d "%s" ]\n' "${cfg_home}"                                                             >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. removing home directory: %s"\n' "${cfg_home}"                                   >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "${cfg_home}"                            >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        rm -f -r "%s"\n' "${cfg_home}"                                                      >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} rm -f -r "%s"\n' "${cfg_home}"                                          >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'if [ ! -d "%s" ]\n' "$(dirname "${cfg_home}")"                                              >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. creating parent home directory: %s"\n' "$(dirname "${cfg_home}")"               >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "$(dirname $(dirname "${cfg_home}"))"    >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        mkdir -p "%s"\n' "$(dirname "${cfg_home}")"                                         >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} mkdir -p "%s"\n' "$(dirname "${cfg_home}")"                             >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'else\n'                                                                                     >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 1 ] || [ ! -w "%s" ]\n' "$(dirname $(dirname "${cfg_home}"))"  >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        Log ".. owning parent home directory to: %s"\n' "${cfg_user}"                       >> "${job_file}"
                    printf '        ${use_sudo} chown %s "%s"\n' "${cfg_user}" "$(dirname "${cfg_home}")"               >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'Log ".. extracting tarball to home directory: %s"\n' "$(dirname "${cfg_home}")"             >> "${job_file}"
                    printf 'cd "%s" > /dev/null\n\n' "$(dirname "${cfg_home}")"                                         >> "${job_file}"
                fi
            else
                if [ -n "${cfg_data}" ]
                then
                    printf 'if [ ! -d "%s" ]\n' "$(dirname "${cfg_data}")"                                              >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. creating parent data directory: %s"\n' "$(dirname "${cfg_data}")"               >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "$(dirname $(dirname "${cfg_data}"))"    >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        mkdir -p "%s"\n' "$(dirname "${cfg_data}")"                                         >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} mkdir -p "%s"\n' "$(dirname "${cfg_data}")"                             >> "${job_file}"
                    printf '    fi\n\n'                                                                                 >> "${job_file}"

                    printf '    if [ "${force_sudo}" -eq 1 ] || [ ! -w "%s" ]\n' "$(dirname $(dirname "${cfg_data}"))"  >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        Log ".. owning parent data directory to: %s"\n' "${cfg_user}"                       >> "${job_file}"
                    printf '        ${use_sudo} chown -R %s "%s"\n' "${cfg_user}" "$(dirname "${cfg_data}")"            >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'else\n'                                                                                     >> "${job_file}"
                    printf '    if [ -d "%s" ]\n' "${cfg_data}"                                                         >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        if [ "${force_sudo}" -eq 1 ] || [ ! -w "%s" ]\n' "${cfg_data}"                      >> "${job_file}"
                    printf '        then\n'                                                                             >> "${job_file}"
                    printf '            Log ".. owning data directory to: %s"\n' "${cfg_user}"                          >> "${job_file}"
                    printf '            ${use_sudo} chown -R %s "%s"\n' "${cfg_user}" "${cfg_data}"                     >> "${job_file}"
                    printf '        fi\n'                                                                               >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'Log ".. extracting tarball to data directory: %s"\n' "$(dirname "${cfg_data}")"             >> "${job_file}"
                    printf 'cd "%s" > /dev/null\n\n' "$(dirname "${cfg_data}")"                                         >> "${job_file}"
                fi
            fi

            printf 'Log ".. extracting tarball: %s"\n' "$(basename ${i})"                                               >> "${job_file}"
            printf 'if [ "${force_sudo}" -eq 1 ]\n'                                                                     >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    test -e "%s" && gzip -c -d < "%s" | ${use_sudo} tar -xpf -\n' "${cfg_location}"/"$(basename ${i})" "${cfg_location}"/"$(basename ${i})" >> "${job_file}"
            printf 'else\n'                                                                                             >> "${job_file}"
            printf '    test -e "%s" && gzip -c -d < "%s" | tar -xpf -\n' "${cfg_location}"/"$(basename ${i})" "${cfg_location}"/"$(basename ${i})" >> "${job_file}"
            printf 'fi\n'                                                                                               >> "${job_file}"
            printf 'rc=$?\n'                                                                                            >> "${job_file}"
            printf 'cd - > /dev/null\n\n'                                                                               >> "${job_file}"
            
            tarballIndex=$((tarballIndex+1)) 
        done

        if [ -n "${cfg_home}" ] && [ -n "${cfg_home_owner}" ] && [ ! "${cfg_user}" = "${cfg_home_owner}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    if [ -d "%s" ]\n' "${cfg_home}"                                                                 >> "${job_file}"
            printf '    then\n'                                                                                         >> "${job_file}"
            printf '        Log ".. owning home directory to: %s"\n' "${cfg_home_owner}"                                >> "${job_file}"
            printf '        ${use_sudo} chown -R %s "%s"\n' "${cfg_home_owner}" "${cfg_home}"                           >> "${job_file}"
            printf '        rc=$?\n'                                                                                    >> "${job_file}"
            printf '    fi\n'                                                                                           >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_data}" ] && [ -n "${cfg_data_owner}" ] && [ ! "${cfg_user}" = "${cfg_data_owner}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    if [ -d "%s" ]\n' "${cfg_data}"                                                                 >> "${job_file}"
            printf '    then\n'                                                                                         >> "${job_file}"
            printf '        Log ".. owning data directory to: %s"\n' "${cfg_data_owner}"                                >> "${job_file}"
            printf '        ${use_sudo} chown -R %s "%s"\n' "${cfg_data_owner}" "${cfg_data}"                           >> "${job_file}"
            printf '        rc=$?\n'                                                                                    >> "${job_file}"
            printf '    fi\n'                                                                                           >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_make_service}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    Log ".. creating systemd service: %s"\n' "js7_controller.service"                               >> "${job_file}"
            printf '    MakeService "%s"\n' "${cfg_home}/bin/controller.service"                                        >> "${job_file}"
            printf '    rc=$?\n'                                                                                        >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_exec_post_extract}" ]
        then
            printf '%s\n' "Log \".. executing post-extraction command: ${cfg_exec_post_extract}\""                      >> "${job_file}"
            printf '%s\n\n' "${cfg_exec_post_extract}"                                                                  >> "${job_file}"
        fi

        printf 'Log ".. deployment completed, return code: ${rc}"\n'                                                    >> "${job_file}"
        printf 'exit ${rc}\n\n'                                                                                         >> "${job_file}"

        if [ -n "${cfg_keyfile}" ]
        then
            printf 'scp -i "%s" %s "%s" %s@%s:"%s"\n' "${cfg_keyfile}" "${use_scp_port}" "${controller_archive_dir}/run_deploy_controller.sh" "${cfg_user}" "${cfg_host}" "${cfg_location}" >> "${deploy_file}"
            printf 'ssh -i "%s" %s -t -t -o LogLevel=QUIET %s@%s %s\n\n' "${cfg_keyfile}" "${use_ssh_port}" "${cfg_user}" "${cfg_host}" "'chmod u+x ${cfg_location}/run_deploy_controller.sh && ${cfg_location}/run_deploy_controller.sh'" >> "${deploy_file}"
        else
            printf 'scp %s "%s" %s@%s:"%s"\n' "${controller_archive_dir}/run_deploy_controller.sh" "${use_scp_port}" "${cfg_user}" "${cfg_host}" "${cfg_location}" >> "${deploy_file}"
            printf 'ssh %s -t -t -o LogLevel=QUIET %s@%s %s\n\n' "${use_ssh_port}" "${cfg_user}" "${cfg_host}" "'chmod u+x ${cfg_location}/run_deploy_controller.sh && ${cfg_location}/run_deploy_controller.sh'" >> "${deploy_file}"
        fi        
    fi
}

CreateJocPackage()
{
    jocId=$1
    jocInstance=$2
    jocJson=$3

    cfg_release=$(echo "${jocJson}" | jq -r ".media.release // empty" | sed 's/^"//' | sed 's/"$//')
    if [ -z "${cfg_release}" ]
    then
        LogError "Deployment Descriptor file misses element .media.release: --deploy-desc=${deploy_desc}"
        exit 1
    fi

    cfg_tarball=$(echo "${jocJson}" | jq -r ".media.tarball // empty" | sed 's/^"//' | sed 's/"$//')
    if [ -z "${cfg_tarball}" ]
    then
        LogError "Deployment Descriptor file misses element .media.tarball: --deploy-desc=${deploy_desc}"
        exit 1
    fi

    Log ".... creating install script: ${run_file}"
    CreateJocInstallScript "${jocId}" "${jocInstance}" "${jocJson}"
    joc_archive_dir="${archive_dir}"/"${cfg_descriptor_id}"/joc/"${jocId}"

    if [ ! -d "${joc_archive_dir}" ]
    then
        mkdir -p "${joc_archive_dir}"
    else
        if [ -d "${joc_archive_dir}/${jocInstance}" ]
        then
            ${use_sudo} rm -f -r "${joc_archive_dir}/${jocInstance}"
        fi
    fi

    if [ -z "${dry_run}" ]
    then
        "${run_file}"
        CreateJocTarball "${jocId}" "${jocInstance}" "${jocJson}"
        CreateJocJobScript "${jocId}" "${jocInstance}" "${jocJson}" "${run_tarballs}" "${joc_archive_dir}"

        cp -p "${run_file}" "${joc_archive_dir}"/run_install_joc.sh
        Log ".... install script for deployment package ready: ${joc_archive_dir}/run_install_joc.sh"

        cp -p "${job_file}" "${joc_archive_dir}"/run_deploy_joc.sh
        Log ".... job script for deployment package ready: ${joc_archive_dir}/run_deploy_joc.sh"

        cp -p "${deploy_file}" "${joc_archive_dir}"/run_rollout_joc.sh
        Log ".... rollout script for deployment package ready: ${joc_archive_dir}/run_rollout_joc.sh"

        if [ -s "${run_rollouts_file}" ]
        then
            printf ',' >> "${run_rollouts_file}"
        fi
        
        printf '%s' "${joc_archive_dir}"/run_rollout_joc.sh >> "${run_rollouts_file}"

        if [ -z "${keep_work}" ] && [ -d "${work_dir}"/joc/"${jocId}" ]
        then
            ${use_sudo} rm -f -r "${work_dir}"/joc/"${jocId}"
        fi
    fi
}

CreateJocInstallScript()
{
    jocId=$1
    jocInstance=$2
    jocJson=$3

    run_config_dir="${config_dir}"
    run_script_dir="${script_dir}"
    run_work_dir="${work_dir}/joc/${jocId}"
    
    if [ -d "${run_work_dir}" ]
    then
        ${use_sudo} rm -f -r "${run_work_dir}"
    fi

    cfg_license_key=$(< "${deploy_desc}" jq -r ".license.licenseKeyFile // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_license_bin=$(< "${deploy_desc}" jq -r ".license.licenseBinFile // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_release=$(echo "${jocJson}" | jq -r ".media.release // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_tarball=$(echo "${jocJson}" | jq -r ".media.tarball // empty" | sed 's/^"//' | sed 's/"$//')
    
    if [ ! "$(echo "${cfg_tarball}" | cut -c1)" = "/" ] && [ ! "$(echo "${cfg_tarball}" | cut -c1)" = "." ] && [ ! "$(echo "${cfg_tarball}" | cut -c1)" = '$' ]
    then
        cfg_tarball="${release_dir}"/"${cfg_tarball}"
    fi

    cfg_setup_dir=$(echo "${jocJson}" | jq -r ".installation.setupDir // empty" | sed 's/^"//' | sed 's/"$//')

    if [ -z "${cfg_setup_dir}" ]
    then
        cfg_setup_dir="${run_work_dir}""${cfg_setup_dir}"
    fi

    cfg_response_dir=$(echo "${jocJson}" | jq -r ".configuration.responseDir // empty" | sed 's/^"//' | sed 's/"$//')

    if [ -n "${cfg_response_dir}" ]
    then
        if [ ! -d "${run_work_dir}"/"${cfg_response_dir}" ]
        then
            mkdir -p "${run_work_dir}"/"${cfg_response_dir}"
        fi

        Log ".... copying response directory ${run_config_dir}/${cfg_response_dir} to ${run_work_dir}/${cfg_response_dir}"
        cp -p -R  "${run_config_dir}"/"${cfg_response_dir}"/* "${run_work_dir}"/"${cfg_response_dir}"
    fi

    cfg_home=$(echo "${jocJson}" | jq -r ".installation.home // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data=$(echo "${jocJson}" | jq -r ".installation.data // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_run_user=$(echo "${jocJson}" | jq -r ".installation.runUser // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home_owner=$(echo "${jocJson}" | jq -r ".installation.homeOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data_owner=$(echo "${jocJson}" | jq -r ".installation.dataOwner // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_title=$(echo "${jocJson}" | jq -r ".installation.title // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_security_level=$(echo "${jocJson}" | jq -r ".installation.securityLevel // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_dbms_config=$(echo "${jocJson}" | jq -r ".installation.dbmsConfig // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_dbms_init=$(echo "${jocJson}" | jq -r ".installation.dbmsInit // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_dbms_driver=$(echo "${jocJson}" | jq -r ".installation.dbmsDriver // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_http_port=$(echo "${jocJson}" | jq -r ".installation.httpPort // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_https_port=$(echo "${jocJson}" | jq -r ".installation.httpsPort // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_is_user=$(echo "${jocJson}" | jq -r ".installation.isUser // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_is_preserve_env=$(echo "${jocJson}" | jq -r ".installation.isPreserveEnv // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_java_home=$(echo "${jocJson}" | jq -r ".installation.javaHome // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_java_options=$(echo "${jocJson}" | jq -r ".installation.javaOptions // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_pre=$(echo "${jocJson}" | jq -r ".installation.execPre // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_post=$(echo "${jocJson}" | jq -r ".installation.execPost // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_keystore=$(echo "${jocJson}" | jq -r ".configuration.certificates.keyStore // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_keystore_password=$(echo "${jocJson}" | jq -r ".configuration.certificates.keyStorePassword // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_key_alias=$(echo "${jocJson}" | jq -r ".configuration.certificates.keyAlias // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_truststore=$(echo "${jocJson}" | jq -r ".configuration.certificates.trustStore // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_truststore_password=$(echo "${jocJson}" | jq -r ".configuration.certificates.trustStorePassword // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_http_ini=$(echo "${jocJson}" | jq -r ".configuration.startFiles.httpIni // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_https_ini=$(echo "${jocJson}" | jq -r ".configuration.startFiles.httpsIni // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_ssl_ini=$(echo "${jocJson}" | jq -r ".configuration.startFiles.sslIni // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_service_name=$(echo "${jocJson}" | jq -r ".target.serviceName // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_service_dir=$(echo "${jocJson}" | jq -r ".target.serviceDir // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_service_name=${cfg_service_name:-js7_joc_${jocId}.service}
    if [ "${cfg_service_name%*.service}" = "${cfg_service_name}" ]
    then
        cfg_service_name="${cfg_service_name}".service
    fi

    if [ -z "${cfg_run_user}" ] && [ -n "${cfg_data_owner}" ]
    then
        cfg_run_user=${cfg_data_owner}
    fi
    cfg_run_user=$(echo "${cfg_run_user}" | cut -d':' -f 1)    

    cfg_ini=
    if [ -n "${cfg_http_ini}" ]
    then
        cfg_ini="${cfg_ini}\${DEP_CONFIG}/${cfg_http_ini},"
    fi
   
    if [ -n "${cfg_https_ini}" ]
    then
        cfg_ini="${cfg_ini}\${DEP_CONFIG}/${cfg_https_ini},"
    fi
   
    if [ -n "${cfg_ssl_ini}" ]
    then
        cfg_ini="${cfg_ini}\${DEP_CONFIG}/${cfg_ssl_ini},"
    fi

    if [ -n "${cfg_ini}" ]
    then
        cfg_ini=${cfg_ini%?}
    fi

    cfg_config_dir=""
    i=0
    j=$(echo "${jocJson}" | jq -r ".configuration.templates  // empty| select (.!=null) | length")
    if [ -n "$j" ]
    then
        while [ "$i" -lt "$j" ]
        do
            if [ -n "${cfg_config_dir}" ]
            then
                cfg_config_dir="${cfg_config_dir},"
            fi
            cfg_config_dir="${cfg_config_dir}\${DEP_CONFIG}/$(echo "${jocJson}" | jq ".configuration.templates[$i] // empty" | sed 's/^"//' | sed 's/"$//')"
            i=$(( i + 1 ))
        done
    fi

    cfg_properties=$(echo "${jocJson}" | jq -r ".configuration.files.jocProperties // empty" | sed 's/^"//' | sed 's/"$//')

    touch "${run_file}"
    chmod u+x "${run_file}"

    printf '#!/bin/sh\n\n'                                                                                           > "${run_file}"
    printf 'set -e\n\n'                                                                                             >> "${run_file}"
    printf 'DEP_BIN="%s"\n' "${run_script_dir}"                                                                     >> "${run_file}"
    printf 'DEP_CONFIG="%s"\n' "${run_config_dir}"                                                                  >> "${run_file}"
    printf 'DEP_WORK_TEMP="%s"\n\n' "${run_work_dir}"                                                               >> "${run_file}"
    printf 'mkdir -p "${DEP_WORK_TEMP}"\n\n'                                                                        >> "${run_file}"
    printf '"${DEP_BIN}"/js7_install_joc.sh \\\n'                                                                   >> "${run_file}"    
    printf '    --real-path-prefix="%s" \\\n'  "\${DEP_WORK_TEMP}"                                                  >> "${run_file}"

    if [ -n "${cfg_release}" ]
    then
        printf '    --release="%s" \\\n' "${cfg_release}"                                                           >> "${run_file}"
    fi

    if [ -n "${cfg_tarball}" ]
    then
        printf '    --tarball="%s" \\\n' "${cfg_tarball}"                                                           >> "${run_file}"
    fi

    if [ -n "${cfg_setup_dir}" ]
    then
        printf '    --setup-dir="%s" \\\n' "\${DEP_WORK_TEMP}${cfg_setup_dir}"                                      >> "${run_file}"
    fi

    if [ -n "${cfg_response_dir}" ]
    then
        printf '    --response-dir="%s" \\\n' "\${DEP_WORK_TEMP}/${cfg_response_dir}"                               >> "${run_file}"
    fi

    if [ -n "${cfg_home}" ]
    then
        printf '    --home="%s" \\\n' "\${DEP_WORK_TEMP}${cfg_home}"                                                >> "${run_file}"
    fi

    if [ -n "${jocId}" ]
    then
        printf '    --cluster-id="%s" \\\n' "${jocId}"                                                              >> "${run_file}"
    fi

    if [ -n "${jocInstance}" ]
    then
        printf '    --instance-id="%s" \\\n' "${jocInstance}"                                                       >> "${run_file}"
    fi

    if [ -n "${cfg_data}" ]
    then
        printf '    --data="%s" \\\n' "\${DEP_WORK_TEMP}${cfg_data}"                                                >> "${run_file}"
    fi

    if [ -n "${cfg_run_user}" ]
    then
        printf '    --user="%s" \\\n' "${cfg_run_user}"                                                             >> "${run_file}"
    fi

    if [ -n "${cfg_home_owner}" ]
    then
        printf '    --home-owner="%s" \\\n' "${cfg_home_owner}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_data_owner}" ]
    then
        printf '    --data-owner="%s" \\\n' "${cfg_data_owner}"                                                     >> "${run_file}"
    fi


    if [ -n "${cfg_title}" ]
    then
        printf '    --title="%s" \\\n' "${cfg_title}"                                                               >> "${run_file}"
    fi

    if [ -n "${cfg_security_level}" ]
    then
        printf '    --security-level="%s" \\\n' "${cfg_security_level}"                                             >> "${run_file}"
    fi

    if [ -n "${cfg_dbms_config}" ]
    then
        printf '    --dbms-config="%s" \\\n' "\${DEP_CONFIG}/${cfg_dbms_config}"                                    >> "${run_file}"
    fi

    if [ -n "${cfg_dbms_init}" ]
    then
        printf '    --dbms-init="%s" \\\n' "${cfg_dbms_init}"                                                       >> "${run_file}"
    fi

    if [ -n "${cfg_dbms_driver}" ]
    then
        printf '    --dbms-driver="%s" \\\n' "\${DEP_CONFIG}/${cfg_dbms_driver}"                                    >> "${run_file}"
    fi


    if [ -n "${cfg_license_key}" ]
    then
        printf '    --license-key="%s" \\\n' "\${DEP_CONFIG}/${cfg_license_key}"                                    >> "${run_file}"
    fi

    if [ -n "${cfg_license_bin}" ]
    then
        printf '    --license-bin="%s" \\\n' "\${DEP_CONFIG}/${cfg_license_bin}"                                    >> "${run_file}"
    fi


    if [ -n "${cfg_http_port}" ]
    then
        printf '    --http-port="%s" \\\n' "${cfg_http_port}"                                                       >> "${run_file}"
    fi

    if [ -n "${cfg_https_port}" ]
    then
        printf '    --https-port="%s" \\\n' "${cfg_https_port}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_java_home}" ]
    then
        printf '    --java-home="%s" \\\n' "${cfg_java_home}"                                                       >> "${run_file}"
    fi

    if [ -n "${cfg_java_options}" ]
    then
        printf '    --java-options="%s" \\\n' "${cfg_java_options}"                                                 >> "${run_file}"
    fi

    if [ -n "${cfg_exec_post}" ]
    then
        printf '    --exec-start="%s" \\\n' "${cfg_exec_post}"                                                      >> "${run_file}"
    fi

    if [ -n "${cfg_exec_pre}" ]
    then
        printf '    --exec-stop="%s" \\\n' "${cfg_exec_pre}"                                                        >> "${run_file}"
    fi


    if [ -n "${cfg_keystore}" ]
    then
        printf '    --keystore="%s" \\\n' "\${DEP_CONFIG}/${cfg_keystore}"                                          >> "${run_file}"
    fi

    if [ -n "${cfg_keystore_password}" ]
    then
        printf '    --keystore-password="%s" \\\n' "${cfg_keystore_password}"                                       >> "${run_file}"
    fi

    if [ -n "${cfg_key_alias}" ]
    then
        printf '    --keystore-alias="%s" \\\n' "${cfg_key_alias}"                                                  >> "${run_file}"
    fi

    if [ -n "${cfg_truststore}" ]
    then
        printf '    --truststore="%s" \\\n' "\${DEP_CONFIG}/${cfg_truststore}"                                      >> "${run_file}"
    fi

    if [ -n "${cfg_truststore_password}" ]
    then
        printf '    --truststore-password="%s" \\\n' "${cfg_truststore_password}"                                   >> "${run_file}"
    fi

    if [ -n "${cfg_config_dir}" ]
    then
        printf '    --deploy-dir="%s" \\\n' "${cfg_config_dir}"                                                     >> "${run_file}"
    fi

    if [ -n "${cfg_ini}" ]
    then
        printf '    --ini="%s" \\\n' "${cfg_ini}"                                                                   >> "${run_file}"
    fi

    if [ -n "${cfg_properties}" ]
    then
         printf '    --properties="%s" \\\n' "\${DEP_CONFIG}/${cfg_properties}"                                     >> "${run_file}"
    fi

    if [ -n "${cfg_is_user}" ]
    then
         printf '    --as-user \\\n'                                                                                >> "${run_file}"
    fi

    if [ -n "${cfg_is_preserve_env}" ]
    then
         printf '    --preserve-env \\\n'                                                                           >> "${run_file}"
    fi

    if [ -n "${cfg_service_name}" ]
    then
        printf '    --service-name="%s" \\\n' "${cfg_service_name}"                                                 >> "${run_file}"
    fi

    if [ -n "${cfg_service_dir}" ]
    then
        printf '    --service-dir="%s" \\\n' "${cfg_service_dir}"                                                   >> "${run_file}"
    fi

    if [ -n "${show_logs}" ]
    then
        printf '    --show-logs \\\n'                                                                               >> "${run_file}"
    fi

    if [ -n "${log_dir}" ]
    then
        printf '    --log-dir=%s \\\n' "${log_dir}"                                                                 >> "${run_file}"
    fi

    if [ -n "${force_sudo}" ]
    then
        printf '    --force-sudo \\\n'                                                                              >> "${run_file}"
    fi

    printf '    --make-dirs\n'                                                                                      >> "${run_file}"
}

CreateJocTarball()
{
    jocId=$1
    jocInstance=$2
    jocJson=$3

    cfg_release=$(echo "${jocJson}" | jq -r ".media.release" | sed 's/^"//' | sed 's/"$//')
    cfg_home=$(echo "${jocJson}" | jq -r ".installation.home" | sed 's/^"//' | sed 's/"$//')
    cfg_data=$(echo "${jocJson}" | jq -r ".installation.data" | sed 's/^"//' | sed 's/"$//')

    run_tarballs=
    run_work_dir="${work_dir}/joc/${jocId}"        
    joc_archive_dir="${archive_dir}"/"${cfg_descriptor_id}"/joc/"${jocId}"/"${jocInstance}"
    mkdir -p "${joc_archive_dir}"

    if [ -n "${cfg_home}" ]
    then
        joc_home_dir="${run_work_dir}""${cfg_home}"
        joc_home_parent_dir=$(dirname "${joc_home_dir}")
        joc_home_basename=$(basename "${joc_home_dir}")
        joc_home_archive_file="${joc_archive_dir}"/js7_deploy_joc_linux."${jocId}"."${jocInstance}"."${cfg_release}".install.tar

        exclude_file=$(CreateExcludeFile "${joc_home_dir}"/logs)
        
        if [ -n "${os_compat}" ]
        then
            Log ".... creating installation deployment package file: tar -cpf ${joc_home_archive_file} -C ${joc_home_parent_dir} ${joc_home_basename}"
            tar -X "${exclude_file}" -cpf "${joc_home_archive_file}" -C "${joc_home_parent_dir}" "${joc_home_basename}"
        else
            Log ".... creating installation deployment package file: tar -cpf ${joc_home_archive_file} ${joc_home_basename}"
            (
                cd "${joc_home_parent_dir}" || exit 2
                tar -X "${exclude_file}" -cpf "${joc_home_archive_file}" "${joc_home_basename}"
            )
        fi

        test -e "${joc_home_archive_file}" && gzip -f "${joc_home_archive_file}"
        Log ".... installation deployment package ready: ${joc_home_archive_file}.gz"
        run_tarballs="${joc_home_archive_file}".gz
    fi

    if [ -n "${cfg_data}" ] && [ "${cfg_data#*"${cfg_home}"}" = "${cfg_data}" ]
    then
        joc_data_dir="${run_work_dir}""${cfg_data}"
        joc_data_parent_dir=$(dirname "${joc_data_dir}")
        joc_data_basename=$(basename "${joc_data_dir}")
        joc_data_archive_file="${joc_archive_dir}"/js7_deploy_joc_linux."${jocId}"."${jocInstance}"."${cfg_release}".config.tar

        exclude_file=$(CreateExcludeFile "${joc_data_dir}"/logs)
        ${use_sudo} rm -f -r "${joc_data_dir}"/logs

        if [ -n "${os_compat}" ]
        then
            Log ".... creating configuration deployment package file: tar -cpf ${joc_data_archive_file} -C ${joc_data_parent_dir} ${joc_data_basename}"
            tar -X "${exclude_file}" -cpf "${joc_data_archive_file}" -C "${joc_data_parent_dir}" "${joc_data_basename}"
        else
            Log ".... creating configuration deployment package file: tar -cpf ${joc_data_archive_file} ${joc_data_basename}"
            (
                cd "${joc_data_parent_dir}" || exit 2
                tar -X "${exclude_file}" -cpf "${joc_data_archive_file}" "${joc_data_basename}"
            )
        fi

        test -e "${joc_data_archive_file}" && gzip -f "${joc_data_archive_file}"
        Log ".... configuration deployment package ready: ${joc_data_archive_file}.gz"

        ${use_sudo} mkdir -p "${joc_data_dir}"/logs

        if [ -n "${run_tarballs}" ]
        then
            run_tarballs="${run_tarballs}",
        fi
        run_tarballs="${run_tarballs}""${joc_data_archive_file}".gz
    fi
}

CreateJocJobScript()
{
    jocId=$1
    jocInstance=$2
    jocJson=$3
    run_tarballs=$4
    joc_archive_dir=$5

    use_tarballs=$(echo "${run_tarballs}" | sed 's/^"//' | sed 's/"$//')

    cfg_host=$(echo "${jocJson}" | jq -r ".target.connection.host // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_port=$(echo "${jocJson}" | jq -r ".target.connection.port // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_user=$(echo "${jocJson}" | jq -r ".target.authentication.user // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_keyfile=$(echo "${jocJson}" | jq -r ".target.authentication.keyFile // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_location=$(echo "${jocJson}" | jq -r ".target.packageLocation // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_force_sudo=$(echo "${jocJson}" | jq -r ".target.forceSudo // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home=$(echo "${jocJson}" | jq -r ".installation.home // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data=$(echo "${jocJson}" | jq -r ".installation.data // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_home_owner=$(echo "${jocJson}" | jq -r ".installation.homeOwner // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_data_owner=$(echo "${jocJson}" | jq -r ".installation.dataOwner // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_exec_pre_extract=$(echo "${jocJson}" | jq -r ".target.execPre // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_exec_post_extract=$(echo "${jocJson}" | jq -r ".target.execPost // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_make_service=$(echo "${jocJson}" | jq -r ".target.makeService // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_service_name=$(echo "${jocJson}" | jq -r ".target.serviceName // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_service_dir=$(echo "${jocJson}" | jq -r ".target.serviceDir // empty" | sed 's/^"//' | sed 's/"$//')

    cfg_service_name=${cfg_service_name:-js7_joc_${jocId}.service}
    if [ "${cfg_service_name%*.service}" = "${cfg_service_name}" ]
    then
        cfg_service_name="${cfg_service_name}".service
    fi

    if [ -z "${cfg_service_dir}" ]
    then
        cfg_service_dir=/usr/lib/systemd/system
    fi

    if [ -z "${cfg_location}" ]
    then
        cfg_location="."
    fi

    if [ -n "${use_tarballs}" ] && [ -n "${cfg_host}" ] && [ -n "${cfg_user}" ]
    then
        touch "${deploy_file}"
        chmod u+x "${deploy_file}"

        printf '#!/bin/sh\n\n'                                                                                           > "${deploy_file}"
        printf 'set -e\n\n'                                                                                             >> "${deploy_file}"

        touch "${job_file}"
        chmod u+x "${job_file}"

        printf '#!/bin/sh\n\n'                                                                                           > "${job_file}"
        printf 'set -e\n\n'                                                                                             >> "${job_file}"

        if [ -n "${cfg_force_sudo}" ]
        then
            printf 'force_sudo="1"\n'                                                                                   >> "${job_file}"
        else
            printf 'force_sudo="0"\n'                                                                                   >> "${job_file}"
        fi

        printf 'if [ "$(id -u)" -eq 0 ]\n'                                                                              >> "${job_file}"
        printf 'then\n'                                                                                                 >> "${job_file}"
        printf '    use_sudo=""\n'                                                                                      >> "${job_file}"
        printf 'else\n'                                                                                                 >> "${job_file}"
        printf '    use_sudo="sudo"\n'                                                                                  >> "${job_file}"
        printf 'fi\n\n'                                                                                                 >> "${job_file}"

        printf 'systemd_service_dir="%s"\n' "${cfg_service_dir}"                                                        >> "${job_file}"
        printf 'systemd_service_name="%s"\n' "${cfg_service_name}"                                                      >> "${job_file}"
        AddDeployScriptFunctions "${job_file}"

        tarballIndex=0
        set -- "$(echo "${use_tarballs}" | sed -r 's/[,]+/ /g')"
        for i in $@; do
            if [ ! -f "${i}" ]
            then
                LogError "tarball file not found: $i"
                exit 1
            fi

            if [ -n "${cfg_port}" ]
            then
                use_scp_port="-P ${cfg_port}"
                use_ssh_port="-p ${cfg_port}"
            else
                use_scp_port=
                use_ssh_port=
            fi

            printf 'echo "deploying %s to host %s"\n' "${i}" "${cfg_host}"                                                                         >> "${deploy_file}"
            if [ -n "${cfg_keyfile}" ]
            then
                printf 'scp -i "%s" %s "%s" %s@%s:"%s"\n' "${cfg_keyfile}" "${use_scp_port}" "${i}" "${cfg_user}" "${cfg_host}" "${cfg_location}"  >> "${deploy_file}"
            else
                printf 'scp %s "%s" %s@%s:"%s"\n' "${i}" "${use_scp_port}" "${cfg_user}" "${cfg_host}" "${cfg_location}"                           >> "${deploy_file}"
            fi

            if [ "${tarballIndex}" -eq 0 ]
            then
                if [ -n "${cfg_exec_pre_extract}" ]
                then
                    printf '%s\n' "Log \".. executing pre-extraction command: ${cfg_exec_pre_extract}\""                >> "${job_file}"
                    printf '%s\n\n' "${cfg_exec_pre_extract}"                                                           >> "${job_file}"
                fi
            fi
            
            if [ "${tarballIndex}" -eq 0 ]
            then
                if [ -n "${cfg_home}" ]
                then
                    printf 'if [ -d "%s" ]\n' "${cfg_home}"                                                             >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. removing home directory: %s"\n' "${cfg_home}"                                   >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "${cfg_home}"                            >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        rm -f -r "%s"\n' "${cfg_home}"                                                      >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} rm -f -r "%s"\n' "${cfg_home}"                                          >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'if [ ! -d "%s" ]\n' "$(dirname "${cfg_home}")"                                              >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. creating parent home directory: %s"\n' "$(dirname "${cfg_home}")"               >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "$(dirname $(dirname "${cfg_home}"))"    >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        mkdir -p "%s"\n' "$(dirname "${cfg_home}")"                                         >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} mkdir -p "%s"\n' "$(dirname "${cfg_home}")"                             >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'else\n'                                                                                     >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 1 ] || [ ! -w "%s" ]\n' "$(dirname "${cfg_home}")"             >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        Log ".. owning parent home directory to: %s"\n' "${cfg_user}"                       >> "${job_file}"
                    printf '        ${use_sudo} chown %s "%s"\n' "${cfg_user}" "$(dirname "${cfg_home}")"               >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'Log ".. extracting tarball to home directory: %s"\n' "$(dirname "${cfg_home}")"             >> "${job_file}"
                    printf 'cd "%s" > /dev/null\n\n' "$(dirname "${cfg_home}")"                                         >> "${job_file}"
                fi
            else
                if [ -n "${cfg_data}" ]
                then
                    printf 'if [ ! -d "%s" ]\n' "$(dirname "${cfg_data}")"                                              >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. creating parent data directory: %s"\n' "$(dirname "${cfg_data}")"               >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "$(dirname $(dirname "${cfg_data}"))"    >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        mkdir -p "%s"\n' "$(dirname "${cfg_data}")"                                         >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} mkdir -p "%s"\n' "$(dirname "${cfg_data}")"                             >> "${job_file}"
                    printf '    fi\n\n'                                                                                 >> "${job_file}"

                    printf '    if [ "${force_sudo}" -eq 1 ] || [ ! -w "%s" ]\n' "$(dirname "${cfg_data}")"             >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        Log ".. owning parent data directory to: %s"\n' "${cfg_user}"                       >> "${job_file}"
                    printf '        ${use_sudo} chown -R %s "%s"\n' "${cfg_user}" "$(dirname "${cfg_data}")"            >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'else\n'                                                                                     >> "${job_file}"
                    printf '    if [ -d "%s" ]\n' "${cfg_data}"                                                         >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        if [ "${force_sudo}" -eq 1 ] || [ ! -w "%s" ]\n' "${cfg_data}"                      >> "${job_file}"
                    printf '        then\n'                                                                             >> "${job_file}"
                    printf '            Log ".. owning data directory to: %s"\n' "${cfg_user}"                          >> "${job_file}"
                    printf '            ${use_sudo} chown -R %s "%s"\n' "${cfg_user}" "${cfg_data}"                     >> "${job_file}"
                    printf '        fi\n'                                                                               >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'if [ -d "%s" ]\n' "${cfg_data}/webapps/joc"                                                 >> "${job_file}"
                    printf 'then\n'                                                                                     >> "${job_file}"
                    printf '    Log ".. removing webapps data directory: %s"\n' "${cfg_data}/webapps/joc"               >> "${job_file}"
                    printf '    if [ "${force_sudo}" -eq 0 ] && [ -w "%s" ]\n' "${cfg_data}/webapps/joc"                >> "${job_file}"
                    printf '    then\n'                                                                                 >> "${job_file}"
                    printf '        rm -r -f "%s"/*\n' "${cfg_data}/webapps/joc"                                        >> "${job_file}"
                    printf '    else\n'                                                                                 >> "${job_file}"
                    printf '        ${use_sudo} rm -r -f "%s"/*\n' "${cfg_data}/webapps/joc"                            >> "${job_file}"
                    printf '    fi\n'                                                                                   >> "${job_file}"
                    printf 'fi\n\n'                                                                                     >> "${job_file}"

                    printf 'Log ".. extracting tarball to data directory: %s"\n' "$(dirname "${cfg_data}")"             >> "${job_file}"
                    printf 'cd "%s" > /dev/null\n\n' "$(dirname "${cfg_data}")"                                         >> "${job_file}"
                fi
            fi

            printf 'Log ".. extracting tarball: %s"\n' "$(basename ${i})"                                               >> "${job_file}"
            printf 'if [ "${force_sudo}" -eq 1 ]\n'                                                                     >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    test -e "%s" && gzip -c -d < "%s" | ${use_sudo} tar -xpf -\n' "${cfg_location}"/"$(basename ${i})" "${cfg_location}"/"$(basename ${i})" >> "${job_file}"
            printf 'else\n'                                                                                             >> "${job_file}"
            printf '    test -e "%s" && gzip -c -d < "%s" | tar -xpf -\n' "${cfg_location}"/"$(basename ${i})" "${cfg_location}"/"$(basename ${i})" >> "${job_file}"
            printf 'fi\n'                                                                                               >> "${job_file}"
            printf 'rc=$?\n'                                                                                            >> "${job_file}"
            printf 'cd - > /dev/null\n\n'                                                                               >> "${job_file}"

            tarballIndex=$((tarballIndex+1)) 
        done

        if [ -n "${cfg_home}" ] 
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf "    ${use_sudo} sed -i \"s/\$(echo %s | sed -e 's@/@\\\\\\\\\/@g')//g\" %s/jetty/bin/jetty.sh\n" "${work_dir}/joc/${jocId}" "${cfg_home}"                       >> "${job_file}"              
            printf "    ${use_sudo} sed -i \"s/\$(echo %s | sed -e 's@/@\\\\\\\\\/@g')//g\" %s/jetty/bin/anonymize-logs.sh\n" "${work_dir}/joc/${jocId}" "${cfg_home}"              >> "${job_file}"              
            printf "    ${use_sudo} sed -i \"s/\$(echo %s | sed -e 's@/@\\\\\\\\\/@g')//g\" %s/install/install_jetty_base.sh\n" "${work_dir}/joc/${jocId}" "${cfg_home}"            >> "${job_file}"              
            printf "    ${use_sudo} sed -i \"s/\$(echo %s | sed -e 's@/@\\\\\\\\\/@g')//g\" %s/install/install_jetty_service.sh\n" "${work_dir}/joc/${jocId}" "${cfg_home}"         >> "${job_file}"              
            printf "    ${use_sudo} sed -i \"s/\$(echo %s | sed -e 's@/@\\\\\\\\\/@g')//g\" %s/install/joc_install_tables.sh\n" "${work_dir}/joc/${jocId}" "${cfg_home}"            >> "${job_file}"              
            printf "    ${use_sudo} sed -i \"s/\$(echo %s | sed -e 's@/@\\\\\\\\\/@g')//g\" %s/install/joc_manage_identity_service.sh\n" "${work_dir}/joc/${jocId}" "${cfg_home}"   >> "${job_file}"              
            printf "    ${use_sudo} sed -i \"s/\$(echo %s | sed -e 's@/@\\\\\\\\\/@g')//g\" %s/install/uninstall_jetty_service.sh\n" "${work_dir}/joc/${jocId}" "${cfg_home}"       >> "${job_file}"              
            printf "    ${use_sudo} sed -i \"s/\$(echo %s | sed -e 's@/@\\\\\\\\\/@g')//g\" %s/install/update_jetty_base.sh\n" "${work_dir}/joc/${jocId}" "${cfg_home}"             >> "${job_file}"              

            printf '    rc=$?\n'                                                                                        >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        # for install tarball link to JETTY_BASE from JOC Cockpit home 
        if [ -n "${cfg_home}" ] && [ -n "${cfg_data}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    Log ".. creating symlink to data directory: %s"\n' "${cfg_data}"                                >> "${job_file}"
            printf '    if [ -L "%s/jetty_base" ]; then\n' "${cfg_home}"                                                >> "${job_file}"
            printf '        if [ "${force_sudo}" -eq 0 ] && [ -w "%s/jetty_base" ]\n' "${cfg_home}"                     >> "${job_file}"
            printf '        then\n'                                                                                     >> "${job_file}"
            printf '            rm -f "%s/jetty_base"\n' "${cfg_home}"                                                  >> "${job_file}"
            printf '        else\n'                                                                                     >> "${job_file}"
            printf '            ${use_sudo} rm -f "%s/jetty_base"\n' "${cfg_home}"                                      >> "${job_file}"
            printf '        fi\n'                                                                                       >> "${job_file}"
            printf '    fi\n\n'                                                                                         >> "${job_file}"

            printf '    if [ "${force_sudo}" -eq 0 ]\n'                                                                 >> "${job_file}"
            printf '    then\n'                                                                                         >> "${job_file}"
            printf '        ln -s "%s" "%s/jetty_base"\n' "${cfg_data}" "${cfg_home}"                                   >> "${job_file}"
            printf '    else\n'                                                                                         >> "${job_file}"
            printf '        ${use_sudo} ln -s "%s" "%s/jetty_base"\n' "${cfg_data}" "${cfg_home}"                       >> "${job_file}"
            printf '    fi\n'                                                                                           >> "${job_file}"
            printf '    rc=$?\n'                                                                                        >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        # for config tarball link to JOC Cockpit home from JETTY_BASE
        if [ -n "${cfg_home}" ] && [ -n "${cfg_data}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    Log ".. creating symlink to home directory: %s"\n' "${cfg_home}"                                >> "${job_file}"
            printf '    if [ -L "%s/joc_home" ]; then\n' "${cfg_data}"                                                  >> "${job_file}"
            printf '        if [ "${force_sudo}" -eq 0 ] && [ -w "%s/jetty_home" ]\n' "${cfg_data}"                     >> "${job_file}"
            printf '        then\n'                                                                                     >> "${job_file}"
            printf '            rm -f "%s/joc_home"\n' "${cfg_data}"                                                    >> "${job_file}"
            printf '        else\n'                                                                                     >> "${job_file}"
            printf '            ${use_sudo} rm -f "%s/joc_home"\n' "${cfg_data}"                                        >> "${job_file}"
            printf '        fi\n'                                                                                       >> "${job_file}"
            printf '    fi\n\n'                                                                                         >> "${job_file}"

            printf '    if [ "${force_sudo}" -eq 0 ]\n'                                                                 >> "${job_file}"
            printf '    then\n'                                                                                         >> "${job_file}"
            printf '        ln -s "%s" "%s/joc_home"\n' "${cfg_home}" "${cfg_data}"                                     >> "${job_file}"
            printf '    else\n'                                                                                         >> "${job_file}"
            printf '        ${use_sudo} ln -s "%s" "%s/joc_home"\n' "${cfg_home}" "${cfg_data}"                         >> "${job_file}"
            printf '    fi\n'                                                                                           >> "${job_file}"
            printf '    rc=$?\n'                                                                                        >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_home}" ] && [ -n "${cfg_home_owner}" ] && [ ! "${cfg_user}" = "${cfg_home_owner}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    Log ".. owning home directory to: %s"\n' "${cfg_home_owner}"                                    >> "${job_file}"
            printf '    ${use_sudo} chown -R %s "%s"\n' "${cfg_home_owner}" "${cfg_home}"                               >> "${job_file}"
            printf '    rc=$?\n'                                                                                        >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_data}" ] && [ -n "${cfg_data_owner}" ] && [ ! "${cfg_user}" = "${cfg_data_owner}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    if [ -d "%s" ]\n' "${cfg_data}"                                                                 >> "${job_file}"
            printf '    then\n'                                                                                         >> "${job_file}"
            printf '        Log ".. owning data directory to: %s"\n' "${cfg_data_owner}"                                >> "${job_file}"
            printf '        ${use_sudo} chown -R %s "%s"\n' "${cfg_data_owner}" "${cfg_data}"                           >> "${job_file}"
            printf '        rc=$?\n'                                                                                    >> "${job_file}"
            printf '    fi\n'                                                                                           >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_make_service}" ]
        then
            printf 'if [ "${rc}" -eq 0 ]\n'                                                                             >> "${job_file}"
            printf 'then\n'                                                                                             >> "${job_file}"
            printf '    Log ".. creating systemd service: %s"\n' "js7_joc.service"                                      >> "${job_file}"
            printf '    MakeService "%s"\n' "${cfg_home}/jetty/bin/joc.service"                                         >> "${job_file}"
            printf '    rc=$?\n'                                                                                        >> "${job_file}"
            printf 'fi\n\n'                                                                                             >> "${job_file}"
        fi

        if [ -n "${cfg_exec_post_extract}" ]
        then
            printf '%s\n' "Log \".. executing post-extraction command: ${cfg_exec_post_extract}\""                      >> "${job_file}"
            printf '%s\n\n' "${cfg_exec_post_extract}"                                                                  >> "${job_file}"
        fi            

        printf 'Log ".. deployment completed, return code: ${rc}"\n'                                                    >> "${job_file}"
        printf 'exit ${rc}\n\n'                                                                                         >> "${job_file}"

        if [ -n "${cfg_keyfile}" ]
        then
            printf 'scp -i "%s" %s "%s" %s@%s:"%s"\n' "${cfg_keyfile}" "${use_scp_port}" "${joc_archive_dir}/run_deploy_joc.sh" "${cfg_user}" "${cfg_host}" "${cfg_location}" >> "${deploy_file}"
            printf 'ssh -i "%s" %s -t -t -o LogLevel=QUIET %s@%s %s\n\n' "${cfg_keyfile}" "${use_ssh_port}" "${cfg_user}" "${cfg_host}" "'chmod u+x ${cfg_location}/run_deploy_joc.sh && ${cfg_location}/run_deploy_joc.sh'" >> "${deploy_file}"
        else
            printf 'scp %s "%s" %s@%s:"%s"\n' "${joc_archive_dir}/run_deploy_joc.sh" "${use_scp_port}" "${cfg_user}" "${cfg_host}" "${cfg_location}" >> "${deploy_file}"
            printf 'ssh %s -t -t -o LogLevel=QUIET %s@%s %s\n\n' "${use_ssh_port}" "${cfg_user}" "${cfg_host}" "'chmod u+x ${cfg_location}/run_deploy_joc.sh && ${cfg_location}/run_deploy_joc.sh'" >> "${deploy_file}"
        fi        
    fi
}

CreateImport()
{
    CreateWorkflowImport
    CreateCalendarImport
    CreateScheduleImport

    import_archive_dir="${archive_dir}"/"${cfg_descriptor_id}"
    import_archive_file="${import_archive_dir}"/js7_import.tar

    Log ".... creating JS7 import file: tar -cpf ${import_archive_file} *"
    (
        cd "$(dirname "${import_dir}")" || exut 2
        tar -cpf "${import_archive_file}" ./*
    )

    gzip -f "${import_archive_file}"    
    Log ".... JS7 import file ready: ${import_archive_file}.gz" 
    
    if [ -z "$keep_work" ] && [ -d "${import_dir}" ]
    then
        rm -f -r "${import_dir}"
    fi
}

CreateWorkflowImport()
{
    workflow_import=$(cat <<EOF
{
  "version": "1.1.0",
  "timeZone": "${workflow_timezone}",
  "orderPreparation": {
    "parameters": {
      "deploy": {
        "type": "List",
        "listParameters": {
          "job": {
            "type": "String"
          }
        }
      }
    },
    "allowUndeclared": false
  },
  "instructions": [
    {
      "TYPE": "ForkList",
      "children": "deploy",
      "childToId": "job",
      "subagentIdVariable": "js7ForkListSubagentId",
      "workflow": {
        "instructions": [
          {
            "TYPE": "Execute.Named",
            "jobName": "deploy",
            "label": "deploy"
          }
        ]
      },
      "joinIfFailed": false
    }
  ],
  "jobs": {
    "deploy": {
      "agentName": "${deploy_agent_id}",
      "withSubagentClusterIdExpr": false,
      "executable": {
        "TYPE": "ShellScriptExecutable",
        "script": "#!/bin/sh\n\n\"\${job}\"",
        "env": {
          "job": "\$job"
        },
        "v1Compatible": false
      },
      "skipIfNoAdmissionForOrderDay": false,
      "parallelism": ${workflow_parallelism},
      "graceTimeout": 15,
      "failOnErrWritten": false,
      "warnOnErrWritten": false
    }
  }
}
EOF
)

    printf '%s' "${workflow_import}" > "${import_dir}"/"${cfg_descriptor_id}".workflow.json

}

CreateCalendarImport()
{
    calendar_import=$(cat <<'EOF'
{
  "version": "1.5.0",
  "type": "WORKINGDAYSCALENDAR",
  "includes": {
    "weekdays": [
      {
        "days": [
          0,
          1,
          2,
          3,
          4,
          5,
          6
        ]
      }
    ]
  }
}
EOF
)

    printf '%s' "${calendar_import}" > "${import_dir}"/"${cfg_descriptor_id}".calendar.json

}

CreateScheduleImport()
{
    schedule_import=$(cat <<EOF
{
  "version": "1.4.0",
  "workflowNames": [
    "${cfg_descriptor_id}"
  ],
  "title": "Deployment Schedule",
  "submitOrderToControllerWhenPlanned": false,
  "planOrderAutomatically": false,
  "calendars": [
    {
      "calendarName": "${cfg_descriptor_id}",
      "timeZone": "Etc/UTC",
      "periods": [
        {
          "singleStart": "00:00:00",
          "whenHoliday": "SUPPRESS"
        }
      ]
    }
  ],
  "orderParameterisations": [
    {
      "orderName": "",
      "variables": {
        "deploy": [
EOF
)

    arrayIndex=1
    use_rollouts=$(< "${run_rollouts_file}" sed 's/^"//' | sed 's/"$//')
    arraySize=$(echo "${use_rollouts}" | tr -cd , | wc -c)
    arraySize=$(($arraySize+1))
    set -- "$(echo "${use_rollouts}" | sed -r 's/[,]+/ /g')"
    for i in $@; do
        schedule_import=$(printf '%s%s' "${schedule_import}" '
          {')
        schedule_import=$(printf '%s%s' "${schedule_import}" "
            \"job\": \"${i}\"")
        schedule_import=$(printf '%s%s' "${schedule_import}" '
          }')
        if [ "${arraySize}" -gt "${arrayIndex}" ]
        then
            schedule_import=$(printf '%s,' "${schedule_import}")
        else
            schedule_import=$(printf '%s'  "${schedule_import}")
        fi
        arrayIndex=$(($arrayIndex+1))
    done

    schedule_import=$(printf '%s%s' "${schedule_import}" '
        ]
      },
      "positions": {}
    }
  ]
}')

    schedule_import=${schedule_import%?}
    printf '%s' "${schedule_import}" > "${import_dir}"/"${cfg_descriptor_id}".schedule.json
}

CreateAgentImport()
{
    controllerId=$1
    agentId=$2
    agentJson=$3

    cfg_agent_controller_id=$controllerId
    cfg_agent_http_port=$(echo "${agentJson}" | jq -r ".installation.httpPort // empty" | sed 's/^"//' | sed 's/"$//')
    cfg_agent_https_port=$(echo "${agentJson}" | jq -r ".installation.httpsPort // empty" | sed 's/^"//' | sed 's/"$//')
    
    agent_port=${cfg_agent_https_port:-${cfg_agent_http_port}}

    if [ "${agent_port#*:}" != "${agent_port}" ]
    then
        agent_host=$(echo "${agent_port}" | cut -d':' -f 1)
        agent_port=$(echo "${agent_port}" | cut -d':' -f 2)
    else
        agent_host=$(echo "${agentJson}" | jq -r ".target.connection.host // empty" | sed 's/^"//' | sed 's/"$//')
    fi
    
    
    if [ -n "${cfg_agent_https_port}" ]
    then
        agent_url=https://${agent_host}:${agent_port}
    else
        agent_url=http://${agent_host}:${agent_port}
    fi
        
    agent_import=$(cat <<EOF
{
  "subagentClusters" : [ ],
  "standaloneAgent" : {
    "controllerId" : "${cfg_agent_controller_id}",
    "agentId" : "${agentId}",
    "agentName" : "${agentId}",
    "agentNameAliases" : [],
    "url" : "${agent_url}",
    "isClusterWatcher" : false,
    "hidden" : false,
    "disabled" : false,
    "deployed" : true,
    "ordering" : 0
  }
}
EOF
)

#   agent_import=${agent_import%?}
    printf '%s' "${agent_import}" > "$(dirname "${import_dir}")"/"${agentId}".agent.json
}

CreateRunRolloutFile()
{
    run_rollout_file="${archive_dir}"/"${cfg_descriptor_id}"/run_rollout.sh

    if [ -f "${run_rollout_file}" ]
    then
        rm -f "${run_rollout_file}"
    fi

    touch "${run_rollout_file}"
    chmod u+x "${run_rollout_file}"

    printf '#!/bin/sh\n\n' > "${run_rollout_file}"

    use_rollouts=$(< "${run_rollouts_file}" sed 's/^"//' | sed 's/"$//')
    set -- "$(echo "${use_rollouts}" | sed -r 's/[,]+/ /g')"
    for i in $@; do
        printf '%s\n' "${i}" >> "${run_rollout_file}"
    done
    
    Log ".. Rollout Script ready: ${run_rollout_file}"
}

# ------------------------------
# Process Deployment Descriptor
# ------------------------------

Process()
{
    os_normal=$(uname -a | tr '[:upper:]' '[:lower:]')

    if [ -n "${os_normal##*sunos*}" ] && [ -n "${os_normal##*solaris*}" ]
    then
        os_compat=1
    else
        os_compat=""
    fi

    cfg_descriptor_id=$(< "${deploy_desc}" jq -r ".descriptor.descriptorId" | sed 's/^"//' | sed 's/"$//')

    if [ -z "${cfg_descriptor_id}" ]
    then
        LogError "Deployment Descriptor ID missing in descriptor file: --deploy-desc=${deploy_desc}"
        exit 1
    fi

    desc_archive_dir="${archive_dir}"/"${cfg_descriptor_id}"

    if [ ! -d "${desc_archive_dir}" ]
    then
        mkdir -p "${desc_archive_dir:?}"
    fi

    tmp_dir="${work_dir}"/tmp

    if [ ! -d "${tmp_dir}" ]
    then
        mkdir -p "${tmp_dir:?}"
    fi

    import_dir="${tmp_dir}"/js7_import_$$/"${cfg_descriptor_id}"
    
    if [ ! -d "${import_dir}" ]
    then
        mkdir -p "${import_dir:?}"
    else
        rm -f -r "${import_dir:?}"/*
    fi
    
    deploy_file="${tmp_dir}"/js7_deploy_package_ssh_$$.sh
    job_file="${tmp_dir}"/js7_deploy_package_job_$$.sh
    run_file="${tmp_dir}"/js7_deploy_package_install_$$.sh
    run_tarballs=
    run_rollouts_file="${tmp_dir}"/js7_run_rollouts_$$.log
    touch "${run_rollouts_file}"

    use_sudo=""
    if [ "$(id -u)" -ne 0 ] && [ -n "${force_sudo}" ]
    then
        use_sudo="sudo"
    fi

    isJocPresent=$(< "${deploy_desc}" jq -r ".joc // empty")
    isControllerPresent=$(< "${deploy_desc}" jq -r ".controllers // empty")

    if [ -z "${select_agent_ids}""${select_controller_ids}" ] || [ -n "${select_joc_ids}" ]
    then
        if [ -n "${isJocPresent}" ]
        then
            jocClusterId=$(< "${deploy_desc}" jq -r ".joc[].members.clusterId // empty")
    
            < "${deploy_desc}" jq -r ".joc[].members | select(.clusterId=\"${jocClusterId}\") | .instances[].instanceId" | while read jocInstanceId; do
                jocInstanceId=$(echo "${jocInstanceId}" | sed 's/^"//' | sed 's/"$//')
    
                match="1"
                set -- "$(echo "${select_joc_ids}" | sed -r 's/[,]+/ /g')"
                for select_joc_instance_id in $@; do
                    match=""

                    if [ -n "${select_joc_instance_id}" ] && [ "${select_joc_instance_id}" = "${jocInstanceId}" ]
                    then
                        match=1
                        break
                    fi
                    
                    if [ -z "${select_joc_instance_id}" ]
                    then
                        match=1
                        break
                    fi
                done
    
                if [ -n "${match}" ]
                then
                    < "${deploy_desc}" jq -r ".joc[].members | select(.clusterId=\"${jocClusterId}\") | .instances[] | select(.instanceId==${jocInstanceId}) | .instanceId" | while read jocInstanceId; do
                        jocInstanceId=$(echo "${jocInstanceId}" | sed 's/^"//' | sed 's/"$//')
                        Log "----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
                        Log ".... creating deployment package for JOC Cockpit Cluster ID: ${jocClusterId}, Instance ID: ${jocInstanceId}"
                        Log "----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
                        CreateJocPackage "${jocClusterId}" "${jocInstanceId}" "$(< "${deploy_desc}" jq -r ".joc[].members | select(.clusterId==\"${jocClusterId}\") | .instances[] | select(.instanceId==${jocInstanceId})")"
                    done
                else
                    Log ".. skipping deployment package for JOC Cockpit Cluster ID: ${jocClusterId}, Instance ID: ${jocInstanceId}"
                fi
            done
        fi
    fi

    if [ -z "${select_joc_ids}""${select_agent_ids}" ] || [ -n "${select_controller_ids}" ]
    then
        if [ -n "${isControllerPresent}" ]
        then
            < "${deploy_desc}" jq -r ".controllers[].controllerId" | while read controllerId; do
                controllerId=$(echo "${controllerId}" | sed 's/^"//' | sed 's/"$//')
    
                match="1"
                set -- "$(echo "${select_controller_ids}" | sed -r 's/[,]+/ /g')"
                for select_controller_id in $@; do
                    match=""
                    if [ -n "${select_controller_id}" ] && [ "${select_controller_id}" = "${controllerId}" ]
                    then
                        match=1
                        break
                    fi
        
                    if [ -z "${select_controller_id}" ]
                    then
                        match=1
                        break
                    fi
                done
                
                if [ -n "${match}" ]
                then
                    < "${deploy_desc}" jq -r ".controllers[] | select(.controllerId == \"${controllerId}\") | keys[] | select(. == \"primary\" or . == \"secondary\")" | while read controllerInstance; do
                        controllerInstance=$(echo "${controllerInstance}" | sed 's/^"//' | sed 's/"$//')
                        Log "----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
                        Log ".. creating deployment package for Controller ID: ${controllerId}, Instance: ${controllerInstance}"
                        Log "----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
                        CreateControllerPackage "${controllerId}" "${controllerInstance}" "$(< "${deploy_desc}" jq -r ".controllers[] | select(.controllerId=\"${controllerId}\") | .\"${controllerInstance}\"")"
                    done
                else
                    Log ".. skipping deployment package for Controller ID: ${controllerId}"
                fi
            done
        fi
    fi

    if [ -z "${select_joc_ids}""${select_controller_ids}" ] || [ -n "${select_agent_ids}" ]
    then
        agentPresent=$(< "${deploy_desc}" jq -r ".agents // empty")
        if [ -n "${agentPresent}" ]
        then
            < "${deploy_desc}" jq -r ".agents.controllerRefs[].controllerId" | while read controllerId; do
                controllerId=$(echo "${controllerId}" | sed 's/^"//' | sed 's/"$//')
                < "${deploy_desc}" jq -r ".agents.controllerRefs[] | select(.controllerId==\"${controllerId}\") | .members[].agentId" | while read agentId; do
                    agentId=$(echo "${agentId}" | sed 's/^"//' | sed 's/"$//')
    
                    match="1"
                    set -- "$(echo "${select_agent_ids}" | sed -r 's/[,]+/ /g')"
                    for select_agent_id in $@; do
                        match=""
    
                        if [ -n "${select_agent_id}" ] && [ "${select_agent_id}" = "${agentId}" ]
                        then
                            match=1
                            break
                        fi
                    
                        if [ -z "${select_agent_id}" ]
                        then
                            match=1
                            break
                        fi
                    done
    
                    if [ -n "${match}" ]
                    then
                        Log "----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
                        Log ".. creating deployment package for Controller ID: ${controllerId}, Agent ID: ${agentId}"
                        Log "----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
                        CreateAgentPackage "${controllerId}" "${agentId}" "$(< "${deploy_desc}" jq -r ".agents.controllerRefs[] | select(.controllerId==\"${controllerId}\") | .members[] | select(.agentId==\"${agentId}\")")"
                    else
                        Log ".. skipping deployment package for Controller ID: ${controllerId}, Agent ID: ${agentId}"
                    fi
                done
            done
        fi
    fi

    if [ -z "${dry_run}" ]
    then
        CreateImport
        CreateRunRolloutFile
    fi
}

# ------------------------------
# Cleanup temporary resources
# ------------------------------

End()
{   
    if [ -f "${run_rollouts_file}" ]
    then
        # Log ".. removing temporary file: ${run_rollouts_file}"
        rm -f "${run_rollouts_file}"
    fi

    if [ -z "${dry_run}" ] && [ -z "${keep_work}" ] && [ -n "${run_file}" ] && [ -f "${run_file}" ]
    then
        # Log ".. removing temporary file: ${run_file}"
        rm -f "${run_file}"
    fi

    if [ -z "${keep_work}" ] && [ -n "${job_file}" ] && [ -f "${job_file}" ]
    then
        # Log ".. removing temporary file: ${job_file}"
        rm -f "${job_file}"
    fi

    if [ -n "${exclude_file}" ] && [ -f "${exclude_file}" ]
    then
        # Log ".. removing temporary file: ${exclude_file}"
        rm -f "${exclude_file}"
    fi

    if [ "$1" = "EXIT" ]
    then
        Log "-- end of log ----------------"

        if [ -n "${show_logs}" ] && [ -f "${log_file}" ]
        then
            cat "${log_file}"
        fi        
    fi

    unset script_home
    unset dep_home
    unset deploy_desc
    unset config_dir
    unset release_dir
    unset work_dir
    unset script_dir
    unset archive_dir
    unset deploy_agent_id
    unset select_agent_ids
    unset select_controller_ids
    unset select_joc_ids
    unset keep_work
    unset dry_run
    unset workflow_parallelism
    unset workflow_timezone
    unset show_logs
    unset make_dirs

    unset tmp_dir
    unset log_dir
    unset log_file
    unset hostname
    unset start_time
    unset run_file
    unset job_file
    unset run_config_dir
    unset run_work_dir
    unset run_tarballs
    unset run_rollouts_file
    unset exclude_file

    set +e
}

# ------------------------------
# Enable trap and start
# ------------------------------

trap 'End EXIT' EXIT
trap 'End SIGTERM' TERM
trap 'End SIGINT' INT

Arguments "$@"
Process
