MOON
Server: Apache
System: Linux vps.erhabenn.com.br 3.10.0-1160.119.1.el7.tuxcare.els2.x86_64 #1 SMP Mon Jul 15 12:09:18 UTC 2024 x86_64
User: machen (1008)
PHP: 8.2.31
Disabled: NONE
Upload Files
File: //opt/microsoft/omsagent/bin/omsadmin.sh
#!/bin/sh

set -e

VAR_DIR=/var/opt/microsoft/omsagent
ETC_DIR=/etc/opt/microsoft/omsagent

NPM_DIR=$VAR_DIR/npm_state
NPM_CONF_FILE_SUFFIX=conf/omsagent.d/npmd.conf

DF_TMP_DIR=$VAR_DIR/tmp
DF_RUN_DIR=$VAR_DIR/run
DF_STATE_DIR=$VAR_DIR/state
DF_LOG_DIR=$VAR_DIR/log

DF_CERT_DIR=$ETC_DIR/certs
DF_CONF_DIR=$ETC_DIR/conf

TMP_DIR=$DF_TMP_DIR
CERT_DIR=$DF_CERT_DIR
CONF_DIR=$DF_CONF_DIR
SYSCONF_DIR=$ETC_DIR/sysconf

# Optional file with initial onboarding credentials
FILE_ONBOARD=/etc/omsagent-onboard.conf

# Generated conf file containing information for this script
CONF_OMSADMIN=$CONF_DIR/omsadmin.conf

# Omsagent daemon configuration
CONF_OMSAGENT=$CONF_DIR/omsagent.conf

# Omsagent proxy configuration
CONF_PROXY=$ETC_DIR/proxy.conf
PRE_MH_CONF_PROXY=$DF_CONF_DIR/proxy.conf

# File with OS information for telemetry
OS_INFO=/etc/opt/microsoft/scx/conf/scx-release

# Service Control script
SERVICE_CONTROL=/opt/microsoft/omsagent/bin/service_control

# File with information about the agent installed
INSTALL_INFO=/etc/opt/microsoft/omsagent/sysconf/installinfo.txt

# Ruby helpers
RUBY=/opt/microsoft/omsagent/ruby/bin/ruby
AUTH_KEY_SCRIPT=/opt/microsoft/omsagent/bin/auth_key.rb
TOPOLOGY_REQ_SCRIPT=/opt/microsoft/omsagent/plugin/agent_topology_request_script.rb
MAINTENANCE_TASKS_SCRIPT=/opt/microsoft/omsagent/plugin/agent_maintenance_script.rb
# Ruby error codes
AGENT_MAINTENANCE_MISSING_CONFIG_FILE=4
AGENT_MAINTENANCE_MISSING_CONFIG=5
AGENT_MAINTENANCE_ERROR_WRITING_TO_FILE=12

# DSC MetaConfig generation script
if [ -x "$(command -v python2)" ]; then
    METACONFIG_PY=/opt/microsoft/omsconfig/Scripts/OMS_MetaConfigHelper.py
elif [ -x "$(command -v python3)" ]; then
    METACONFIG_PY=/opt/microsoft/omsconfig/Scripts/python3/OMS_MetaConfigHelper.py
else
    # Failure to find python/the correct script path will only break onboarding (just one
    # of omsadmin's numerous functions); exit with failure in the onboard() function instead
    METACONFIG_PY=""
fi

# Certs
FILE_KEY=$CERT_DIR/oms.key
FILE_CRT=$CERT_DIR/oms.crt

# Temporary files
SHARED_KEY_FILE=$TMP_DIR/shared_key
BODY_ONBOARD=$TMP_DIR/body_onboard.xml
RESP_ONBOARD=$TMP_DIR/resp_onboard.xml
ENDPOINT_FILE=$TMP_DIR/endpoints

AGENT_USER=omsagent
AGENT_GROUP=omiusers

# Default settings
URL_TLD=opinsights.azure.com
WORKSPACE_ID=""
AGENT_GUID=""
LOG_FACILITY=local0
CERTIFICATE_UPDATE_ENDPOINT=""
VERBOSE=0
AZURE_RESOURCE_ID=""
OMSCLOUD_ID=""
UUID=""
USER_ID=`id -u`
MULTI_HOMING_MARKER=

DEFAULT_SYSLOG_PORT=25224
DEFAULT_MONITOR_AGENT_PORT=25324

SYSLOG_PORT=$DEFAULT_SYSLOG_PORT
MONITOR_AGENT_PORT=$DEFAULT_MONITOR_AGENT_PORT

# SCOM variables
SCX_SSL_CONFIG=/opt/microsoft/scx/bin/tools/scxsslconfig
OMI_CONF_FILE=/etc/opt/omi/conf/omiserver.conf
OMI_CONF_EDITOR=/opt/omi/bin/omiconfigeditor

# Space seperated list of non oms workspaces
NON_OMS_WS="scom LAD"

# Error codes and categories:

# User configuration/parameters:
INVALID_OPTION_PROVIDED=2
INVALID_CONFIG_PROVIDED=3
INVALID_PROXY=4
# Service-related:
ERROR_ONBOARDING_403=5
ERROR_ONBOARDING_NON_200_HTTP=6
# Network-related:
ERROR_RESOLVING_HOST=7
ERROR_ONBOARDING=8
# Internal errors:
INTERNAL_ERROR=30
RUBY_ERROR_GENERATING_GUID=31
ERROR_GENERATING_CERTS=32
ERROR_GENERATING_METACONFIG=33
ERROR_METACONFIG_PY_NOT_PRESENT=34
# Dependency-related:
INSTALL_PYTHON=60

# curl error codes:
CURL_PROXY_RESOLVE_ERROR=5
CURL_HOST_RESOLVE_ERROR=6
CURL_CONNECT_HOST_ERROR=7

usage()
{
    local basename=`basename $0`
    echo
    echo "Maintenance tool for OMS:"
    echo "Onboarding:"
    echo "$basename -w <workspace id> -s <shared key> [-d <top level domain>]"
    echo
    echo "List Workspaces:"
    echo "$basename -l"
    echo
    echo "Remove Workspace:"
    echo "$basename -x <workspace id>"
    echo
    echo "Remove All Workspaces:"
    echo "$basename -X"
    echo
    echo "Update workspace configuration and folder structure to multi-homing schema:"
    echo "$basename -U"
    echo
    echo "Onboard the workspace with a multi-homing marker. The workspace will be regarded as secondary."
    echo "$basename -m <multi-homing marker>"
    echo
    echo "Define proxy settings ('-u' will prompt for password):"
    echo "$basename [-u user] -p host[:port]"
    echo
    echo "Azure resource ID:"
    echo "$basename -a <Azure resource ID>"
    echo
    echo "Detect if omiserver is listening to SCOM port:"
    echo "$basename -o"
}

set_user_agent()
{
    USER_AGENT=LinuxMonitoringAgent/`head -1 $INSTALL_INFO | awk '{print $1}'`
}

check_user()
{
    if [ "$USER_ID" -ne "0" -a `id -un` != "$AGENT_USER" ]; then
        log_error "This script must be run as root or as the $AGENT_USER user."
        exit 1
    fi
}

chown_omsagent()
{
    # When this script is run as root, we still have to make sure the generated
    # files are owned by omsagent for everything to work properly
    [ "$USER_ID" -eq "0" ] && chown $AGENT_USER:$AGENT_GROUP $@ > /dev/null 2>&1
    return 0
}

save_config()
{
    #Save configuration
    echo WORKSPACE_ID=$WORKSPACE_ID > $CONF_OMSADMIN
    echo AGENT_GUID=$AGENT_GUID >> $CONF_OMSADMIN
    echo LOG_FACILITY=$LOG_FACILITY >> $CONF_OMSADMIN
    echo CERTIFICATE_UPDATE_ENDPOINT=$CERTIFICATE_UPDATE_ENDPOINT >> $CONF_OMSADMIN
    echo URL_TLD=$URL_TLD >> $CONF_OMSADMIN
    echo DSC_ENDPOINT=$DSC_ENDPOINT >> $CONF_OMSADMIN
    echo OMS_ENDPOINT=https://$WORKSPACE_ID.ods.$URL_TLD/OperationalData.svc/PostJsonDataItems >> $CONF_OMSADMIN
    echo AZURE_RESOURCE_ID=$AZURE_RESOURCE_ID >> $CONF_OMSADMIN
    echo OMSCLOUD_ID=$OMSCLOUD_ID | tr -d ' ' >> $CONF_OMSADMIN
    echo UUID=$UUID | tr -d ' ' >> $CONF_OMSADMIN
    chown_omsagent "$CONF_OMSADMIN"
}

update_azure_resource_id()
{
    sed -i "s,\(AZURE_RESOURCE_ID=\)\(.*\),\1$AZURE_RESOURCE_ID," $CONF_OMSADMIN
    echo "Azure Resource ID updated."
}

cleanup()
{
    rm "$BODY_ONBOARD" "$RESP_ONBOARD" "$ENDPOINT_FILE" > /dev/null 2>&1 || true
}

# This helper should only be called in the cases when certs have been created but onboarding failed.
cleanup_certs()
{
    rm "$FILE_CRT" "$FILE_KEY" > /dev/null 2>&1 || true
}

clean_exit()
{
    cleanup
    exit $1
}

log_info()
{
    echo -e "info\t$1"
    logger -i -p "$LOG_FACILITY".info -t omsagent "[INFO] $1"
}

log_warning()
{
    echo -e "warning\t$1"
    logger -i -p "$LOG_FACILITY".warning -t omsagent "[WARNING] $1"
}

log_error()
{
    echo -e "error\t$1"
    logger -i -p "$LOG_FACILITY".err -t omsagent "[ERROR] $1"
}

parse_args()
{
    local OPTIND opt

    while getopts "h?s:w:d:vp:u:a:lx:XUm:oR" opt; do
        case "$opt" in
        h|\?)
            usage
            clean_exit 0
            ;;
        s)
            ONBOARDING=1
            SHARED_KEY=$OPTARG
            ;;
        w)
            ONBOARDING=1
            WORKSPACE_ID=$OPTARG
            ;;
        d)
            ONBOARDING=1
            URL_TLD=$OPTARG
            ;;
        v)
            VERBOSE=1
            CURL_VERBOSE=-v
            ;;
        p)
            PROXY_HOST=$OPTARG
            ;;
        u)
            PROXY_USER=$OPTARG
            ;;
        a)
            AZURE_RESOURCE_ID=$OPTARG
            ;;
        l)
            LIST_WORKSPACES=1
            ;;
        x)
            REMOVE=1
            WORKSPACE_ID=$OPTARG
            ;;
        X)
            REMOVE_ALL=1
            ;;
        U)
            UPDATE_WORKSPACES=1
            ;;
        m)
            MULTI_HOMING_MARKER=$OPTARG
            ;;
        o)
            DETECT_SCOM=1
            ;;
        R)
            RECONSTRUCT_WORKSPACE_STATE=1
            ;;
        esac
    done
    shift $((OPTIND-1))

    if [ "$@ " != " " ]; then
        log_error "Parsing error: '$@' is unparsed"
        usage
        clean_exit $INVALID_OPTION_PROVIDED
    fi

    if [ -n "$PROXY_USER" -a -z "$PROXY_HOST" ]; then
        log_error "Cannot specify the proxy user without specifying the proxy host"
        usage
        clean_exit $INVALID_PROXY
    fi

    if [ -n "$PROXY_HOST" ]; then
        if [ -n "$PROXY_USER" ]; then
            read -s -p "Proxy password for $PROXY_USER: " PROXY_PASS
            echo
            create_proxy_conf "$PROXY_USER:$PROXY_PASS@$PROXY_HOST"
        else
            create_proxy_conf "$PROXY_HOST"
        fi
    fi

    if [ $VERBOSE -eq 0 ]; then
        # Suppress curl output
        CURL_VERBOSE=-s
    fi
}

create_proxy_conf()
{
    local conf_proxy_content=$1
    touch $CONF_PROXY
    chown_omsagent $CONF_PROXY
    chmod 600 $CONF_PROXY
    echo -n $conf_proxy_content > $CONF_PROXY
    log_info "Created proxy configuration: $CONF_PROXY"
}

copy_proxy_conf_from_pre_mh_loc()
{
    # Expected behavior is to use new proxy location first, then fallback to
    # the pre-multi-homing location, then assume no proxy is configured
    # In future: change from cp to mv once all plugins have been updated to use new location
    if [ -f "$PRE_MH_CONF_PROXY" ]; then
        echo "Moving proxy configuration from file $PRE_MH_CONF_PROXY to $CONF_PROXY..."
        cp -pf $PRE_MH_CONF_PROXY $CONF_PROXY
    fi
}

set_proxy_setting()
{
    if [ -n "$PROXY" ]; then
        PROXY_SETTING="--proxy $PROXY"
        create_proxy_conf "$PROXY"
        return
    fi
    local conf_proxy_content=""
    [ -r "$CONF_PROXY" ] && conf_proxy_content=`cat $CONF_PROXY`
    if [ -n "$conf_proxy_content" ]; then
        PROXY_SETTING="--proxy $conf_proxy_content"
        log_info "Using proxy settings from '$CONF_PROXY'"
    fi
}

is_scom_port_open()
{
    $OMI_CONF_EDITOR httpsport -q 1270 < $OMI_CONF_FILE > /dev/null 2>&1
    if [ $? -eq 1 ]; then
        return 1
    fi
    echo "Port 1270 already open"
    return 0
}

onboard_scom()
{
    echo "Onboarding SCOM"
    create_workspace_directories "scom"

    if [ ! -f $CERT_DIR/scom-cert.pem ] || [ ! -f $CERT_DIR/scom-key.pem ]; then
        echo "Generating SCOM certificates..."
        # Generate client auth cert using scxsslconfig tool.
        $SCX_SSL_CONFIG -c -g $CERT_DIR
        if [ $? -ne 0 ]; then
          log_error "Error generating certs"
          clean_exit 1
        fi
        # Rename cert/key to more meaningful name
        mv $CERT_DIR/omi-host-*.pem $CERT_DIR/scom-cert.pem
        mv $CERT_DIR/omikey.pem $CERT_DIR/scom-key.pem
        rm -f $CERT_DIR/omi.pem
        chown_omsagent $CERT_DIR/scom-cert.pem
        chown_omsagent $CERT_DIR/scom-key.pem
    fi

    touch $CONF_DIR/omsagent.conf
    update_path $CONF_DIR/omsagent.conf
    chown_omsagent $CONF_DIR/*
    make_dir $CONF_DIR/omsagent.d
    #Always register SCOM as secondary Workspace
    echo "SCOM Workspace" > $CONF_DIR/.multihoming_marker
    configure_logrotate

    #Open port 1270 if not already open
    is_scom_port_open
    if [ $? -eq 1 ]; then
        echo "Opening port 1270"
        $OMI_CONF_EDITOR httpsport -a 1270 < $OMI_CONF_FILE > /etc/opt/omi/conf/omiserver.conf_temp
        mv /etc/opt/omi/conf/omiserver.conf_temp $OMI_CONF_FILE
        # Restart OMI
        /opt/omi/bin/service_control restart
    fi
}

onboard_lad()
{
    echo "Onboarding LAD"
    create_workspace_directories "LAD"

    touch $CONF_DIR/omsagent.conf
    echo "@include omsagent.d/*" > $CONF_DIR/omsagent.conf
    chown_omsagent $CONF_DIR/*
    make_dir $CONF_DIR/omsagent.d
    #Always register LAD as secondary Workspace
    echo "LAD Workspace" > $CONF_DIR/.multihoming_marker
    save_config
    configure_logrotate
}

onboard()
{
    if [ "$METACONFIG_PY" = "" ]; then
        echo "Error: Python is not installed on this system, onboarding cannot continue." >&2
        echo "Please install either the python2 or python3 package." >&2
        clean_exit $INSTALL_PYTHON
    fi

    if [ $VERBOSE -eq 1 ]; then
        # Mask the shared key
        local shared_key_trunc=`echo "$SHARED_KEY" | cut -c 1-4 2> /dev/null`
        local shared_key_covered=`echo "$SHARED_KEY" | tr "$SHARED_KEY" "*" | cut -c 5- 2> /dev/null`

        echo "Workspace ID:      $WORKSPACE_ID"
        echo "Shared key:        $shared_key_trunc$shared_key_covered"
        echo "Top Level Domain:  $URL_TLD"
    fi

    if [ "$WORKSPACE_ID" = "scom" ]; then
        onboard_scom
        clean_exit $?
    fi

    if [ "$WORKSPACE_ID" = "LAD" ]; then
        onboard_lad
        clean_exit $?
    fi

    local error=0
    if [ -z "$WORKSPACE_ID" -o -z "$SHARED_KEY" ]; then
        log_error "Missing Workspace ID or Shared Key information for onboarding"
        clean_exit $INVALID_CONFIG_PROVIDED
    fi

    if echo "$WORKSPACE_ID" | grep -Eqv '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'; then
        log_error "The Workspace ID is not valid"
        clean_exit $INVALID_CONFIG_PROVIDED
    fi

    if [ ! -z "$AZURE_RESOURCE_ID" ]; then
        update_azure_resource_id
    fi

    # If a test is not in progress then call service_control to check on the workspace status
    if [ -z "$TEST_WORKSPACE_ID" -a -z "$TEST_SHARED_KEY" ]; then
        $SERVICE_CONTROL is-running $WORKSPACE_ID > /dev/null 2>&1
        if [ $? -eq 1 ]; then
            echo "Workspace $WORKSPACE_ID already onboarded and agent is running."
            if [ -z "$MULTI_HOMING_MARKER" -a ! -h $DF_CONF_DIR ]; then
                echo "Symbolic links have not been created; re-onboarding to create them"
            else
                return 0
            fi
        fi
    fi
    create_workspace_directories $WORKSPACE_ID

    # Guard against blank omsadmin.conf
    local omsadmin_contents="`cat $CONF_OMSADMIN 2> /dev/null`"
    if [ -f $FILE_KEY -a -f $FILE_CRT -a -f $CONF_OMSADMIN -a -n "$omsadmin_contents" ]; then
        # Keep the same agent GUID by loading it from the previous conf
        AGENT_GUID=`grep AGENT_GUID $CONF_OMSADMIN | cut -d= -f2`
        log_info "Reusing previous agent GUID $AGENT_GUID"
    else
        AGENT_GUID=`$RUBY -e "require 'securerandom'; print SecureRandom.uuid"`
        if [ $? -ne 0 -o -z "$AGENT_GUID" ]; then
            log_error "Error generating agent GUID"
            clean_exit $RUBY_ERROR_GENERATING_GUID
        fi

        $RUBY $MAINTENANCE_TASKS_SCRIPT -c "$CONF_OMSADMIN" "$FILE_CRT" "$FILE_KEY" "$RUN_DIR/omsagent.pid" "$CONF_PROXY" "$OS_INFO" "$INSTALL_INFO" -w "$WORKSPACE_ID" -a "$AGENT_GUID" $CURL_VERBOSE
        generate_certs_ret=$?
        if [ $generate_certs_ret -eq $AGENT_MAINTENANCE_MISSING_CONFIG ]; then
            log_error "Error generating certs: missing config"
            clean_exit $INTERNAL_ERROR
        elif [ $generate_certs_ret -ne 0 ]; then
            log_error "Error generating certs"
            clean_exit $ERROR_GENERATING_CERTS
        fi
    fi

    if [ -z "$AGENT_GUID" ]; then
        log_error "AGENT_GUID should not be empty"
        return $INTERNAL_ERROR
    else
        log_info "Agent GUID is $AGENT_GUID"
    fi

    if [ "$VERBOSE" = "1" ]; then
        log_info "Private Key stored in:   $FILE_KEY"
        log_info "Public Key stored in:    $FILE_CRT"
        # Public key can be verified with a command like:  openssl x509 -text -in oms.crt
    fi

    # Generate the body first so we can compute a SHA256 on the body

    REQ_DATE=`date +%Y-%m-%dT%T.%N%:z`
    CERT_SERVER=`cat $FILE_CRT | awk 'NR>2 { print line } { line = $0 }'`

    # append telemetry to $BODY_ONBOARD
    `$RUBY $TOPOLOGY_REQ_SCRIPT -t "$BODY_ONBOARD" "$OS_INFO" "$CONF_OMSADMIN" "$AGENT_GUID" "$CERT_SERVER" "$RUN_DIR/omsagent.pid"`
    [ $? -ne 0 ] && log_error "Error appending Telemetry during Onboarding."

    cat /dev/null > "$SHARED_KEY_FILE"
    chmod 600 "$SHARED_KEY_FILE"
    echo -n "$SHARED_KEY" >> "$SHARED_KEY_FILE"
    AUTHS=`$RUBY $AUTH_KEY_SCRIPT $REQ_DATE $BODY_ONBOARD $SHARED_KEY_FILE`
    rm "$SHARED_KEY_FILE"

    CONTENT_HASH=`echo $AUTHS | cut -d" " -f1`
    AUTHORIZATION_KEY=`echo $AUTHS | cut -d" " -f2`

    if [ $VERBOSE -ne 0 ]; then
        # Mask the certificate in the request
        local body_no_newlines="`cat $BODY_ONBOARD | tr -d '\n' 2> /dev/null`"
        local cert_tag="AuthenticationCertificate"
        local hidden_cert="********"
        echo
        echo "Generated request:"
        echo "$body_no_newlines" | sed "s/<$cert_tag>[^<]*<\/$cert_tag>/<$cert_tag>$hidden_cert<\/$cert_tag>/g"
        echo
    fi

    set_proxy_setting

    if [ "`which dmidecode > /dev/null 2>&1; echo $?`" = 0 ]; then
        UUID=`dmidecode | grep UUID | sed -e 's/UUID: //'`
        OMSCLOUD_ID=`dmidecode | grep "Tag: 77" | sed -e 's/Asset Tag: //'`
    elif [ -f /sys/devices/virtual/dmi/id/chassis_asset_tag ]; then
        ASSET_TAG=$(cat /sys/devices/virtual/dmi/id/chassis_asset_tag)
        case "$ASSET_TAG" in
            77*) OMSCLOUD_ID=$ASSET_TAG ;;       # If the asset tag begins with a 77 this is the azure guid
        esac
        PRODUCT_UUID=$(cat /sys/devices/virtual/dmi/id/product_uuid)
        UUID=$(echo $PRODUCT_UUID | tr '[:upper:]' '[:lower:]')
    fi

    #This is a temporary fix for Systems with Curl versions using HTTP\2 as default
    #Since 7.47.0, the curl tool enables HTTP/2 by default for HTTPS connections. This fix runs curl with --http1.1 on systems with version above 7.47.0
    #Curl http2 Docs Link: https://curl.haxx.se/docs/http2.html
    CURL_VERSION_WITH_DEFAULT_HTTP2="7470"
    CURL_VERSION_SYSTEM=`curl --version | head -c11 | awk '{print $2}' | tr --delete .`
    if [ $CURL_VERSION_SYSTEM -gt $CURL_VERSION_WITH_DEFAULT_HTTP2 ]; then
      CURL_HTTP_COMMAND="--http1.1"
    fi

    RET_CODE=`curl --header "x-ms-Date: $REQ_DATE" \
        --header "x-ms-version: August, 2014" \
        --header "x-ms-SHA256_Content: $CONTENT_HASH" \
        --header "Authorization: $WORKSPACE_ID; $AUTHORIZATION_KEY" \
        --header "User-Agent: $USER_AGENT" \
        --header "Accept-Language: en-US" \
        --insecure \
        $CURL_HTTP_COMMAND \
        --data-binary @$BODY_ONBOARD \
        --cert "$FILE_CRT" --key "$FILE_KEY" \
        --output "$RESP_ONBOARD" $CURL_VERBOSE \
        --write-out "%{http_code}\n" $PROXY_SETTING \
        https://${WORKSPACE_ID}.oms.${URL_TLD}/AgentService.svc/LinuxAgentTopologyRequest` || error=$?

    if [ $error -eq $CURL_HOST_RESOLVE_ERROR -a -z "$PROXY_SETTING" ]; then
        log_error "Error resolving host during the onboarding request. Check the correctness of the workspace ID and the internet connectivity, or add a proxy."
        cleanup_certs
        return $ERROR_RESOLVING_HOST
    elif [ $error -eq $CURL_PROXY_RESOLVE_ERROR -a -n "$PROXY_SETTING" ]; then
        log_error "Proxy could not be resolved during the onboarding request. Verify the proxy."
        cleanup_certs
        return $INVALID_PROXY
    elif [ $error -eq $CURL_CONNECT_HOST_ERROR -a -n "$PROXY_SETTING" ]; then
        log_error "Error connecting to OMS service through proxy. Verify the proxy."
        cleanup_certs
        return $INVALID_PROXY
    elif [ $error -ne 0 ]; then
        log_error "Error during the onboarding request: curl returned $error. Check the correctness of the workspace ID and shared key or run omsadmin.sh with '-v'"
        cleanup_certs
        return $ERROR_ONBOARDING
    fi

    if [ "$RET_CODE" = "200" ]; then
        $RUBY $MAINTENANCE_TASKS_SCRIPT --endpoints "$RESP_ONBOARD","$ENDPOINT_FILE" "$CONF_OMSADMIN" "$FILE_CRT" "$FILE_KEY" "$RUN_DIR/omsagent.pid" "$CONF_PROXY" "$OS_INFO" "$INSTALL_INFO" $CURL_VERBOSE
        endpoints_ret=$?
        if [ $endpoints_ret -eq $AGENT_MAINTENANCE_MISSING_CONFIG_FILE ]; then
            log_error "Onboarding response is missing; certificate update and DSC endpoints were not extracted."
        elif [ $endpoints_ret -eq $AGENT_MAINTENANCE_ERROR_WRITING_TO_FILE ]; then
            log_error "Endpoint file could not be written to; certificate update and DSC endpoints were not saved."
        elif [ $endpoints_ret -ne 0 ]; then
            log_warning "During onboarding request, certificate update and DSC endpoints may not have been saved."
        else
            log_info "Onboarding success"
        fi
        # Get CERTIFICATE_UPDATE_ENDPOINT and DSC_ENDPOINT variables from output file
        if [ -e "$ENDPOINT_FILE" ]; then
            CERTIFICATE_UPDATE_ENDPOINT=`sed -n '1p' < $ENDPOINT_FILE`
            DSC_ENDPOINT=`sed -n '2p' < $ENDPOINT_FILE`
        fi
    elif [ "$RET_CODE" = "403" ]; then
        REASON=`cat $RESP_ONBOARD | sed -n 's:.*<Reason>\(.*\)</Reason>.*:\1:p'`
        log_error "Error onboarding. HTTP code 403, Reason: $REASON. Check the Workspace ID, Workspace Key and that the time of the system is correct."
        cleanup_certs
        return $ERROR_ONBOARDING_403
    else
        log_error "Error onboarding. HTTP code $RET_CODE"
        cleanup_certs
        return $ERROR_ONBOARDING_NON_200_HTTP
    fi

    save_config

    copy_omsagent_conf

    if [ -z "$MULTI_HOMING_MARKER" ]; then
        # update the default folders when onboard to a workspace as primary
        # this is the default behavior
        update_symlinks
    else
        # do not update the default folders when onboard the workspace as secondary
        # leave a marker in the etc folder of the workspace to indicate the partner
        echo $MULTI_HOMING_MARKER > $CONF_DIR/.multihoming_marker
    fi

	#Initialize empty syslog daemon conf file with no default collection
    configure_syslog

    configure_monitor_agent

    configure_logrotate

    # If a test is not in progress then register omsagent as a service and start the agent
    if [ -z "$TEST_WORKSPACE_ID" -a -z "$TEST_SHARED_KEY" ]; then
        $SERVICE_CONTROL start $WORKSPACE_ID

        if [ -z "$MULTI_HOMING_MARKER" ]; then
            # Configure omsconfig when the workspace is primary
            # This is a temp solution since the DSC doesn't support multi-homing now
            # Only the primary workspace receives the configuration from the DSC service

            # Set up a cron job to run the OMSConsistencyInvoker every 15 minutes
            # This should be done regardless of MetaConfig creation
            if [ ! -f /etc/cron.d/OMSConsistencyInvoker ]; then
                randomNo=$(od -An -N1 -i /dev/urandom)
                A=$(($randomNo%13+2))
                B=$(($A+15))
                C=$(($B+15))
                D=$(($C+15))
                echo "$A,$B,$C,$D * * * * $AGENT_USER /opt/omi/bin/OMSConsistencyInvoker >/dev/null 2>&1" > /etc/cron.d/OMSConsistencyInvoker
            fi

            if [ ! -f $METACONFIG_PY ]; then
                log_error "MetaConfig generation script not available at $METACONFIG_PY"
                return $ERROR_METACONFIG_PY_NOT_PRESENT
            fi

            if [ "$USER_ID" -eq "0" ]; then
                su - $AGENT_USER -c $METACONFIG_PY > /dev/null || error=$?

                if [ $error -ne 0 ]; then
                    log_info "Retrying configuring omsconfig by calling '$METACONFIG_PY' with 'sudo'"
                    error=0
                    sudo -u $AGENT_USER $METACONFIG_PY > /dev/null || error=$?
                fi
                
            else
                $METACONFIG_PY > /dev/null || error=$?
            fi

            if [ $error -eq 0 ]; then
                log_info "Configured omsconfig"
            else
                log_error "Error configuring omsconfig. Error: $error"
                return $ERROR_GENERATING_METACONFIG
            fi
        fi
    fi

    return 0
}

remove_workspace()
{
    setup_workspace_variables $WORKSPACE_ID

    if [ -d "$CONF_DIR" ]; then
        log_info "Disable workspace: $WORKSPACE_ID"

        $SERVICE_CONTROL disable $WORKSPACE_ID
    else
        log_error "Workspace $WORKSPACE_ID doesn't exist"
    fi

    log_info "Cleanup the folders"

    local port=$DEFAULT_SYSLOG_PORT
    if [ -e "$CONF_DIR/omsagent.d/syslog.conf" ]; then
        port=`grep 'port .*' $CONF_DIR/omsagent.d/syslog.conf | cut -d ' ' -f4`
    fi

    /opt/microsoft/omsagent/bin/configure_syslog.sh unconfigure $WORKSPACE_ID ${port}

    if [ -f "$NPM_CONF_WS" -a -d "$NPM_DIR" ]; then
        log_info "Removing NPM state directory in $WORKSPACE_ID removal"
        rm -rf $NPM_DIR > /dev/null 2>&1
    fi

    rm -rf "$VAR_DIR_WS" "$ETC_DIR_WS" > /dev/null 2>&1

    rm -f /etc/logrotate.d/omsagent-$WORKSPACE_ID > /dev/null 2>&1

    reset_default_workspace
}

reset_default_workspace()
{
    if [ -h $DF_CONF_DIR -a ! -d $DF_CONF_DIR ]; then
        # default conf folder is removed, remove the symlinks
        rm "$DF_TMP_DIR" "$DF_RUN_DIR" "$DF_STATE_DIR" "$DF_LOG_DIR" "$DF_CERT_DIR" "$DF_CONF_DIR" > /dev/null 2>&1
    fi
}

remove_all()
{
    for ws_id in `ls -1 $ETC_DIR | grep -E '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'`
    do
        WORKSPACE_ID=${ws_id}
        remove_workspace
    done

    # Remove non-OMS "workspaces"
    for ws_id in $NON_OMS_WS
    do
       ls -l $ETC_DIR | grep -w "$ws_id" > /dev/null 2>&1
       if [ $? -eq 0 ]; then
           WORKSPACE_ID="$ws_id"
           remove_workspace
       fi
    done
}

show_workspace_status()
{
    local ws_conf_dir=$1
    local ws_id=$2
    local is_primary=$3
    local status='Unknown'

    # 1 if omsagent-ws_id is running, 0 otherwise
    $SERVICE_CONTROL is-running $ws_id
    if [ $? -eq 1 ]; then
        status='Onboarded(OMSAgent Running)'
    elif [ -f ${ws_conf_dir}/.service_registered ]; then
        status='Warning(OMSAgent Registered, Not Running)'
    elif [ -f ${ws_conf_dir}/omsadmin.conf ]; then
        status='Saved(OMSAgent Not Registered, Workspace Configuration Saved)'
    else
        status='Failure(Agent Not Onboarded, No Workspace Configuration Present)'
    fi

    local mh_marker=
    if [ -f ${ws_conf_dir}/.multihoming_marker ]; then
        mh_marker="(`cat ${ws_conf_dir}/.multihoming_marker`)"
    fi

    if [ ${is_primary} -eq 1 ]; then
        echo "Primary Workspace: ${ws_id}    Status: ${status}"
    else
        echo "Workspace${mh_marker}: ${ws_id}    Status: ${status}"
    fi
}

list_scom_workspace()
{
    ls -1 $ETC_DIR | grep -w scom > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        show_workspace_status $ETC_DIR/scom/conf scom 0
        return 1
    fi
    return 0
}

list_workspaces()
{
    local found_ws=0
    local ws_conf_dir=$ETC_DIR/conf

    if [ -h ${ws_conf_dir} ]; then
        # symbolic link - multiple workspace folder structure
        local primary_ws_id=''
        if [ -f ${ws_conf_dir}/omsadmin.conf ]; then
            primary_ws_id=`grep WORKSPACE_ID ${ws_conf_dir}/omsadmin.conf | cut -d= -f2`
        fi

        if [ "${primary_ws_id}" != "" ]; then
            found_ws=1
            show_workspace_status ${ws_conf_dir} ${primary_ws_id} 1
        fi

        for ws_id in `ls -1 $ETC_DIR | grep -E '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'`
        do
            if [ "${primary_ws_id}" != "${ws_id}" ]; then
                found_ws=1
                show_workspace_status $ETC_DIR/${ws_id}/conf ${ws_id} 0
            fi
        done
    elif [ -d ${ws_conf_dir} ]; then
        # directory - single workspace folder structure
        local ws_id=''

        if [ -f ${ws_conf_dir}/omsadmin.conf ]; then
            ws_id=`grep WORKSPACE_ID ${ws_conf_dir}/omsadmin.conf | cut -d= -f2`
        fi

        if [ "${ws_id}" != "" ]; then
            found_ws=1
            show_workspace_status ${ws_conf_dir} ${ws_id} 1
        fi
    else
        # no default conf folder, check all the potential workspace folders
        for ws_id in `ls -1 $ETC_DIR | grep -E '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'`
        do
            found_ws=1
            show_workspace_status $ETC_DIR/${ws_id}/conf ${ws_id} 0
        done
    fi
    # check scom workspace
    list_scom_workspace
    if [ $? -eq 1 ]; then
        found_ws=1
    fi

    if [ $found_ws -eq 0 ]; then
        echo "No Workspace"
    fi

    return 0
}

migrate_pre_mh_workspace()
{
    if [ -d $DF_CONF_DIR -a ! -h $DF_CONF_DIR -a -f $DF_CONF_DIR/omsadmin.conf ]; then
        WORKSPACE_ID=`grep WORKSPACE_ID $DF_CONF_DIR/omsadmin.conf | cut -d= -f2`

        if [ $? -ne 0 -o -z $WORKSPACE_ID ]; then
            echo "WORKSPACE_ID is not found. Skip migration."
            return
        else
            echo "Migrating to multi-homing folder structure..."
        fi

        create_workspace_directories $WORKSPACE_ID

        cp -rpf $DF_TMP_DIR $VAR_DIR_WS
        cp -rpf $DF_STATE_DIR $VAR_DIR_WS
        cp -rpf $DF_RUN_DIR $VAR_DIR_WS
        cp -rpf $DF_LOG_DIR $VAR_DIR_WS

        cp -rpf $DF_CERT_DIR $ETC_DIR_WS
        cp -rpf $DF_CONF_DIR $ETC_DIR_WS

        copy_omsagent_d_conf

        migrate_pre_mh_omsagent_conf

        sed -i s,%SYSLOG_PORT%,$DEFAULT_SYSLOG_PORT,1 $CONF_DIR/omsagent.d/syslog.conf
        sed -i s,%MONITOR_AGENT_PORT%,$DEFAULT_MONITOR_AGENT_PORT,1 $CONF_DIR/omsagent.d/monitor.conf

        update_symlinks
    elif [ -d $DF_CONF_DIR -a ! -h $DF_CONF_DIR ]; then
        # In some upgrade cases, conf and conf/omsagent.d directories are created and are empty
        # Remove these directories if they are empty
        rmdir $DF_CONF_DIR/omsagent.d 2> /dev/null
        rmdir $DF_CONF_DIR 2> /dev/null
    fi
}

migrate_pre_mh_omsagent_conf()
{
    # migrate the omsagent.conf
    cp -pf $CONF_DIR/omsagent.conf $CONF_DIR/omsagent.conf.bak

    # remove the syslog configuration. it has been moved to omsagent.d/syslog.conf
    cat $CONF_DIR/omsagent.conf.bak | sed '/port 25224/,+4 d' | sed '/<filter oms\.syslog\.\*\*>/,+3 d' | tac | sed '/type syslog/,+1 d' | tac > $CONF_DIR/omsagent.conf

    # update the heartbeat configure to use the fake command
    sed -i s,"command /opt/microsoft/omsagent/bin/omsadmin.sh -b > /dev/null","command echo > /dev/null",1 $CONF_DIR/omsagent.conf

    # add the workspace conf, cert and key to the output plugins
    sed -i s,".*buffer_chunk_limit.*","\n  omsadmin_conf_path $CONF_DIR/omsadmin.conf\n  cert_path $CERT_DIR/oms.crt\n  key_path $CERT_DIR/oms.key\n\n&",g $CONF_DIR/omsagent.conf

    # update the workspace state folder
    sed -i s,"/var/opt/microsoft/omsagent/state",$STATE_DIR,g $CONF_DIR/omsagent.conf
}

update_omsagent_d_conf()
{
    # Parameter: Workspace ID for the folder to update
    setup_workspace_variables $1
    WS_OMSAGENT_D_DIR=$CONF_DIR/omsagent.d
    if [ ! -d "$WS_OMSAGENT_D_DIR" ]; then
        echo "$WS_OMSAGENT_D_DIR does not exist; skipping update in this directory."
        return
    fi

    # Note: if syslog.conf, monitor.conf, or other configuration files using a port must be updated
    # during version upgrade, then new functionality will have to be added here
    copy_no_port_omsagent_d_conf $WS_OMSAGENT_D_DIR
    chown_omsagent $WS_OMSAGENT_D_DIR/*
}

# Update configuration and structure for all configured workspaces
update_workspaces()
{
    local error=0
    # Updating from pre-multi-homing version
    migrate_pre_mh_workspace || error=$?

    # Updating from pre-multi-homing structure (somewhat present in versions >1.3)
    copy_proxy_conf_from_pre_mh_loc || error=$?

    # Updating configuration for all onboarded workspaces to latest shipped versions
    for ws_id in `ls -1 $ETC_DIR | grep -E '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'`
    do
        update_omsagent_d_conf $ws_id || error=$?
    done

    if [ $error -ne 0 ]; then
        clean_exit $error
    fi
}

reconstruct_full_workspace_state()
{
    for ws_id in `ls -1 $ETC_DIR | grep -E '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'`
    do
        WORKSPACE_ID=$ws_id
        setup_workspace_variables $WORKSPACE_ID

        if [ -f $CERT_DIR/oms.key -a -f $CERT_DIR/oms.crt -a -f $CONF_DIR/omsadmin.conf ]; then
            local omsadmin_contents="`cat $CONF_DIR/omsadmin.conf 2> /dev/null`"
            if [ -n "$omsadmin_contents" ]; then
                # Create all workspace-specific directories; if they already exist, this is a NOOP
                create_workspace_directories $WORKSPACE_ID

                # If a test is not in progress, then syslog and logrotate can be set up
                if [ -z "$TEST_WORKSPACE_ID" -a -z "$TEST_SHARED_KEY" ]; then
                    # During omsagent removal, log rotate files are removed; set up log rotate like in onboarding
                    configure_logrotate
                    # Note: we could re-configure syslog here, but it will overwrite user settings in some cases
                fi
            else
                log_warning "Workspace $ws_id has an empty configuration file at $CONF_DIR/omsadmin.conf; please onboard to populate this configuration"
            fi
        else
            log_warning "Workspace $ws_id has created a folder $ETC_DIR/$ws_id, but is missing certificates or configuration; please onboard"
        fi
    done
}

setup_workspace_variables()
{
    VAR_DIR_WS=$VAR_DIR/$1
    ETC_DIR_WS=$ETC_DIR/$1

    TMP_DIR=$VAR_DIR_WS/tmp
    STATE_DIR=$VAR_DIR_WS/state
    RUN_DIR=$VAR_DIR_WS/run
    LOG_DIR=$VAR_DIR_WS/log
    CERT_DIR=$ETC_DIR_WS/certs
    CONF_DIR=$ETC_DIR_WS/conf

    NPM_CONF_WS=$ETC_DIR/$1/$NPM_CONF_FILE_SUFFIX
}

create_workspace_directories()
{
    setup_workspace_variables $1

    make_dir $VAR_DIR_WS
    make_dir $ETC_DIR_WS

    make_dir $TMP_DIR
    make_dir $STATE_DIR
    make_dir $RUN_DIR
    make_dir $LOG_DIR
    make_dir $CERT_DIR
    make_dir $CONF_DIR

    chmod 700 $CERT_DIR

    # Generated conf file containing information for this script
    CONF_OMSADMIN=$CONF_DIR/omsadmin.conf

    # Omsagent daemon configuration
    CONF_OMSAGENT=$CONF_DIR/omsagent.conf

    # Certs
    FILE_KEY=$CERT_DIR/oms.key
    FILE_CRT=$CERT_DIR/oms.crt

    # Temporary files
    SHARED_KEY_FILE=$TMP_DIR/shared_key
    BODY_ONBOARD=$TMP_DIR/body_onboard.xml
    RESP_ONBOARD=$TMP_DIR/resp_onboard.xml
    ENDPOINT_FILE=$TMP_DIR/endpoints
}

make_dir()
{
    if [ ! -d $1 ]; then
        mkdir -m 750 $1
    else
        if [ $VERBOSE -eq 1 ]; then
            echo "Directory $1 already exists."
        fi
        chmod 750 $1
    fi

    chown_omsagent $1
}

copy_omsagent_conf()
{
    cp -p $SYSCONF_DIR/omsagent.conf $CONF_DIR

    update_path $CONF_DIR/omsagent.conf

    chown_omsagent $CONF_DIR/*

    copy_omsagent_d_conf
}

copy_omsagent_d_conf()
{
    OMSAGENTD_DIR=$CONF_DIR/omsagent.d
    make_dir $OMSAGENTD_DIR

    cp -p $SYSCONF_DIR/omsagent.d/monitor.conf $OMSAGENTD_DIR
    cp -p $SYSCONF_DIR/omsagent.d/syslog.conf $OMSAGENTD_DIR

    update_path $OMSAGENTD_DIR/monitor.conf

    copy_no_port_omsagent_d_conf $OMSAGENTD_DIR

    chown_omsagent $OMSAGENTD_DIR/*
}

copy_no_port_omsagent_d_conf()
{
    # Copy configuration files from sysconf to a workspace-specific omsagent.d directory
    # which do not depend on a workspace-specific port being set
    # Parameter: workspace-specific omsagent.d directory
    cp -p $SYSCONF_DIR/omsagent.d/heartbeat.conf $1
    cp -p $SYSCONF_DIR/omsagent.d/telemetry.conf $1
    cp -p $SYSCONF_DIR/omsagent.d/operation.conf $1
    cp -p $SYSCONF_DIR/omi_mapping.json $1
    cp -p $SYSCONF_DIR/omsagent.d/container.conf $1 2> /dev/null

    update_path $1/heartbeat.conf
    update_path $1/telemetry.conf
    update_path $1/operation.conf
    if [ -f $1/container.conf ] ; then
        update_path $1/container.conf
    fi
}

update_path()
{
    sed -i s,%CONF_DIR_WS%,$CONF_DIR,1 $1
    sed -i s,%CERT_DIR_WS%,$CERT_DIR,1 $1
    sed -i s,%TMP_DIR_WS%,$TMP_DIR,1 $1
    sed -i s,%RUN_DIR_WS%,$RUN_DIR,1 $1
    sed -i s,%STATE_DIR_WS%,$STATE_DIR,1 $1
    sed -i s,%LOG_DIR_WS%,$LOG_DIR,1 $1
}

update_symlinks()
{
    link_dir $DF_TMP_DIR $TMP_DIR
    link_dir $DF_RUN_DIR $RUN_DIR
    link_dir $DF_STATE_DIR $STATE_DIR
    link_dir $DF_LOG_DIR $LOG_DIR

    link_dir $DF_CERT_DIR $CERT_DIR
    link_dir $DF_CONF_DIR $CONF_DIR
}

link_dir()
{
    if [ -d $1 ]; then
        rm -r $1
    fi

    ln -s $2 $1

    chown_omsagent $1
}

find_available_port()
{
    local port=$1
    local result=$2
    if [ "`which netstat > /dev/null 2>&1; echo $?`" = 0 ]; then
        until [ -z "`netstat -an | grep ${port}`" -a -z "`grep ${port} $ETC_DIR/*/conf/omsagent.d/*.conf`" ]; do
            port=$((port+1))
        done
    else
        log_info "netstat tool is not available. Default port defined in omsadmin.sh will be used."
    fi

    eval $result="${port}"
}

configure_syslog()
{
    echo "Configure syslog..."
    find_available_port $DEFAULT_SYSLOG_PORT SYSLOG_PORT

    sed -i s,%SYSLOG_PORT%,$SYSLOG_PORT,1 $CONF_DIR/omsagent.d/syslog.conf

    /opt/microsoft/omsagent/bin/configure_syslog.sh configure $WORKSPACE_ID $SYSLOG_PORT
}

configure_monitor_agent()
{
    echo "Configure heartbeat monitoring agent..."
    find_available_port $DEFAULT_MONITOR_AGENT_PORT MONITOR_AGENT_PORT

    sed -i s,%MONITOR_AGENT_PORT%,$MONITOR_AGENT_PORT,1 $CONF_DIR/omsagent.d/monitor.conf
}

configure_logrotate()
{
    echo "Configure log rotate for workspace $WORKSPACE_ID..."

    # create the logrotate file for omsagent if workspace is LAD
    if [ "$WORKSPACE_ID" = "LAD" ]; then
        # create the logrotate file for the LAD if it doesn't exist
    	if [ ! -f /etc/logrotate.d/omsagent-$WORKSPACE_ID ]; then
            cp $SYSCONF_DIR/lad-logrotate.conf  /etc/logrotate.d/omsagent-$WORKSPACE_ID
    	fi
    else
    	# create the logrotate file for the workspace if it doesn't exist
    	if [ ! -f /etc/logrotate.d/omsagent-$WORKSPACE_ID ]; then
            cat $SYSCONF_DIR/logrotate.conf | sed "s/%WORKSPACE_ID%/$WORKSPACE_ID/g" > /etc/logrotate.d/omsagent-$WORKSPACE_ID
    	fi
    fi

    # Label omsagent log files according to selinux policy module for logrotate if selinux is present
    SEPKG_DIR_OMSAGENT=/usr/share/selinux/packages/omsagent-logrotate
    if [ -e /usr/sbin/semodule -a -d "$SEPKG_DIR_OMSAGENT" ]; then
        # Label omsagent log file for this $WORKSPACE_ID
        /sbin/restorecon -R $VAR_DIR/*/log > /dev/null 2>&1
    fi
}

main()
{
    check_user
    set_user_agent
    parse_args $@

    if [ $# -eq 0 ] || [ $# -eq 1 -a "$VERBOSE" = "1" ]; then

        # Allow onboarding params to be loaded from a file
        # The file contains at least these two lines :
        # WORKSPACE_ID="[...]"
        # SHARED_KEY="[...]"

        if [ -r "$FILE_ONBOARD" ]; then
            log_info "Reading onboarding params from: $FILE_ONBOARD"
            . "$FILE_ONBOARD"
            ONBOARDING=1
            ONBOARD_FROM_FILE=1
        else
            usage
            clean_exit $INVALID_OPTION_PROVIDED
        fi
    fi

    if [ "$DETECT_SCOM" = "1" ]; then
        is_scom_port_open > /dev/null 2>&1
        clean_exit $?
    fi

    if [ "$ONBOARDING" = "1" ]; then
        onboard || clean_exit $?
    fi

    if [ "$LIST_WORKSPACES" = "1" ]; then
        list_workspaces || clean_exit 1
    fi

    if [ "$UPDATE_WORKSPACES" = "1" ]; then
        update_workspaces || clean_exit $?
    fi

    if [ "$RECONSTRUCT_WORKSPACE_STATE" = "1" ]; then
        reconstruct_full_workspace_state || clean_exit $?
    fi

    if [ "$REMOVE" = "1" ]; then
        remove_workspace || clean_exit 1
    fi

    if [ "$REMOVE_ALL" = "1" ]; then
        remove_all || clean_exit 1
    fi

    # If we reach this point, onboarding was successful, we can remove the
    # onboard conf to prevent accidentally re-onboarding
    [ "$ONBOARD_FROM_FILE" = "1" ] && rm "$FILE_ONBOARD" > /dev/null 2>&1 || true

    clean_exit 0
}

main $@