]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Salt Stack Script Integration for Linux.
authorJohn Wolfe <jwolfe@vmware.com>
Tue, 21 Dec 2021 20:48:49 +0000 (12:48 -0800)
committerJohn Wolfe <jwolfe@vmware.com>
Tue, 21 Dec 2021 20:48:49 +0000 (12:48 -0800)
Added the "svtminion.sh" script which will be packaged for Linux to
support SaltStack integration and management from the componentMgr plugin.

open-vm-tools/services/plugins/componentMgr/svtminion.sh [new file with mode: 0644]

diff --git a/open-vm-tools/services/plugins/componentMgr/svtminion.sh b/open-vm-tools/services/plugins/componentMgr/svtminion.sh
new file mode 100644 (file)
index 0000000..aa74365
--- /dev/null
@@ -0,0 +1,1867 @@
+#!/usr/bin/env bash
+
+# Copyright (c) 2021 VMware, Inc. All rights reserved.
+
+## Salt VMware Tools Integration script
+##  integration with Component Manager and GuestStore Helper
+
+## set -u
+## set -xT
+set -o functrace
+set -o pipefail
+## set -o errexit
+
+# using bash for now
+# run this script as root, as needed to run salt
+
+readonly SCRIPT_VERSION='SCRIPT_VERSION_REPLACE'
+
+# definitions
+
+CURL_DOWNLOAD_RETRY_COUNT=5
+
+## Repository locations and naming
+readonly default_salt_url_version="3003.3-1"
+readonly salt_name="salt"
+salt_url_version="${default_salt_url_version}"
+readonly base_url="https://repo.saltproject.io/salt/vmware-tools-onedir"
+readonly repo_json_file="repo.json"
+readonly base_url_json_file="${base_url}/${repo_json_file}"
+
+# Salt file and directory locations
+readonly base_salt_location="/opt/saltstack"
+readonly salt_dir="${base_salt_location}/${salt_name}"
+readonly test_exists_file="${salt_dir}/run/run"
+
+readonly salt_conf_dir="/etc/salt"
+readonly salt_minion_conf_name="minion"
+readonly salt_minion_conf_file="${salt_conf_dir}/${salt_minion_conf_name}"
+readonly salt_master_sign_dir="${salt_conf_dir}/pki/${salt_minion_conf_name}"
+
+readonly log_dir="/var/log"
+
+readonly list_file_dirs_to_remove="${base_salt_location}
+/etc/salt
+/var/run/salt
+/var/cache/salt
+/var/log/salt
+/usr/bin/salt-*
+/usr/lib/systemd/system/salt-minion.service
+/etc/systemd/system/salt-minion.service
+"
+## /var/log/vmware-${SCRIPTNAME}-*
+
+readonly salt_dep_file_list="systemctl
+curl
+sha512sum
+vmtoolsd
+grep
+awk
+sed
+cut
+"
+
+readonly allowed_log_file_action_names="status
+depend
+install
+clear
+remove
+default
+"
+
+readonly salt_wrapper_file_list="minion
+call
+"
+
+readonly salt_minion_service_wrapper=\
+"# Copyright (c) 2021 VMware, Inc. All rights reserved.
+
+[Unit]
+Description=The Salt Minion
+Documentation=man:salt-minion(1) file:///usr/share/doc/salt/html/contents.html https://docs.saltproject.io/en/latest/contents.html
+After=network.target
+# After=ConnMgr.service ProcMgr.service sockets.target
+
+[Service]
+KillMode=process
+Type=notify
+NotifyAccess=all
+LimitNOFILE=8192
+MemoryLimit=250M
+Nice=19
+ExecStart=/opt/saltstack/salt/run/run minion
+
+[Install]
+WantedBy=multi-user.target
+"
+
+
+## VMware file and directory locations
+readonly vmtools_base_dir_etc="/etc/vmware-tools"
+readonly vmtools_conf_file="tools.conf"
+readonly vmtools_salt_minion_section_name="salt_minion"
+
+## VMware guestVars file and directory locations
+readonly guestvars_base_dir="guestinfo./vmware.components"
+readonly \
+guestvars_salt_dir="${guestvars_base_dir}.${vmtools_salt_minion_section_name}"
+readonly guestvars_salt_args="${guestvars_salt_dir}.args"
+readonly guestvars_salt_desiredstate="${guestvars_salt_dir}.desiredstate"
+
+
+# Array for minion configuration keys and values
+# allows for updates from number of configuration sources before final
+# write to /etc/salt/minion
+declare -a m_cfg_keys
+declare -a m_cfg_values
+
+
+## Component Manager Installer/Script return/exit status codes
+# return/exit Status codes
+#  100 + 0 => installed
+#  100 + 1 => installing
+#  100 + 2 => notInstalled
+#  100 + 3 => installFailed
+#  100 + 4 => removing
+#  100 + 5 => removeFailed
+#  126 => scriptFailed
+#  130 => scriptTerminated
+declare -A STATUS_CODES_ARY
+STATUS_CODES_ARY[installed]=100
+STATUS_CODES_ARY[installing]=101
+STATUS_CODES_ARY[notInstalled]=102
+STATUS_CODES_ARY[installFailed]=103
+STATUS_CODES_ARY[removing]=104
+STATUS_CODES_ARY[removeFailed]=105
+STATUS_CODES_ARY[scriptFailed]=126
+STATUS_CODES_ARY[scriptTerminated]=130
+
+# log levels available for logging, order sensitive
+readonly LOG_MODES_AVAILABLE=(silent error warning info debug)
+declare -A LOG_LEVELS_ARY
+LOG_LEVELS_ARY[silent]=0
+LOG_LEVELS_ARY[error]=1
+LOG_LEVELS_ARY[warning]=2
+LOG_LEVELS_ARY[info]=3
+LOG_LEVELS_ARY[debug]=4
+
+
+STATUS_CHK=0
+DEPS_CHK=0
+USAGE_HELP=0
+UNINSTALL_FLAG=0
+VERBOSE_FLAG=0
+VERSION_FLAG=0
+
+CLEAR_ID_KEYS_FLAG=0
+CLEAR_ID_KEYS_PARAMS=""
+
+INSTALL_FLAG=0
+INSTALL_PARAMS=""
+
+MINION_VERSION_FLAG=0
+MINION_VERSION_PARAMS=""
+
+LOG_LEVEL_FLAG=0
+LOG_LEVEL_PARAMS=""
+
+#default logging level to errors, similar to Windows script
+LOG_LEVEL=${LOG_LEVELS_ARY[warning]}
+
+# helper functions
+
+_timestamp() {
+    date -u "+%Y-%m-%d %H:%M:%S"
+}
+
+_log() {
+    echo "$(_timestamp) $*" >> \
+        "${log_dir}/vmware-${SCRIPTNAME}-${LOG_ACTION}-${logdate}.log"
+}
+
+_display() {
+    if [[ ${VERBOSE_FLAG} -eq 1 ]]; then echo "$1"; fi
+    _log "$*"
+}
+
+_error_log() {
+    if [[ ${LOG_LEVELS_ARY[error]} -le ${LOG_LEVEL} ]]; then
+        local log_file=""
+        log_file="${log_dir}/vmware-${SCRIPTNAME}-${LOG_ACTION}-${logdate}.log"
+        msg="ERROR: $*"
+        echo "$msg" 1>&2
+        echo "$(_timestamp) $msg" >> "${log_file}"
+        echo "One or more errors found. See ${log_file} for details." 1>&2
+        CURRENT_STATUS=${STATUS_CODES_ARY[scriptFailed]}
+        exit ${STATUS_CODES_ARY[scriptFailed]}
+    fi
+}
+
+_info_log() {
+    if [[ ${LOG_LEVELS_ARY[info]} -le ${LOG_LEVEL} ]]; then
+        msg="INFO: $*"
+        _log "${msg}"
+    fi
+}
+
+_warning_log() {
+    if [[ ${LOG_LEVELS_ARY[error]} -le ${LOG_LEVEL} ]]; then
+        msg="WARNING: $*"
+        _log "${msg}"
+    fi
+}
+
+_debug_log() {
+    if [[ ${LOG_LEVELS_ARY[debug]} -le ${LOG_LEVEL} ]]; then
+        msg="DEBUG: $*"
+        _log "${msg}"
+    fi
+}
+
+_yesno() {
+read -r -p "Continue (y/n)?" choice
+case "$choice" in
+  y|Y ) echo "yes";;
+  n|N ) echo "no";;
+  * ) echo "invalid";;
+esac
+}
+
+
+#
+# _usage
+#
+#   Prints out help text
+#
+
+ _usage() {
+     echo ""
+     echo "usage: ${0}"
+     echo "             [-c|--clear] [-d|--depend] [-h|--help] [-i|--install]"
+     echo "             [-l|--loglevel] [-m|--minionversion] [-r|--remove]"
+     echo "             [-s|--status] [-v|--version]"
+     echo ""
+     echo "  -c, --clear     clear previous minion identifer and keys,"
+     echo "                     and set specified identifer if present"
+     echo "  -d, --depend    check dependencies required to run script exist"
+     echo "  -h, --help      this message"
+     echo "  -i, --install   install and activate salt-minion configuration"
+     echo "                     parameters key=value can also be passed on CLI"
+     echo "  -l, --loglevel  set log level for logging,"
+     echo "                     silent error warning debug info"
+     echo "                     default loglevel is warning"
+     echo "  -m, --minionversion install salt-minion version, default[latest]"
+     echo "  -r, --remove    deactivate and remove the salt-minion"
+     echo "  -s, --status    return status for this script"
+     echo "  -v, --version   version of this script"
+     echo ""
+     echo "  salt-minion vmtools integration script"
+     echo "      example: $0 --status"
+}
+
+
+# work functions
+
+#
+# _cleanup
+#
+#   Cleanups any running process and areas on control-C
+#
+#
+# Results:
+#   Exits with hard-coded value 130
+#
+
+_cleanup() {
+    exit ${STATUS_CODES_ARY[scriptTerminated]}
+}
+
+trap _cleanup INT
+
+
+# cheap trim relying on echo to convert tabs to spaces and
+# all multiple spaces to a single space
+_trim() {
+    echo "$1"
+}
+
+
+#
+# _set_log_level
+#
+#   Set log_level for logging,
+#       log_level 'silent','error','warning','info','debug'
+#       default 'warning'
+#
+# Results:
+#   Returns with exit code
+#
+
+_set_log_level() {
+
+    _info_log "$0:${FUNCNAME[0]} processing setting set log_level for logging"
+
+    local ip_level=""
+    local valid_level=0
+    local old_log_level=${LOG_LEVEL}
+
+    ip_level=$( echo "$1" | cut -d ' ' -f 1)
+    scam=${#LOG_MODES_AVAILABLE[@]}
+    for ((i=0; i<scam; i++)); do
+        name=${LOG_MODES_AVAILABLE[i]}
+        if [[ "${ip_level}" = "${name}" ]]; then
+            valid_level=1
+            break
+        fi
+    done
+    if [[ ${valid_level} -ne 1 ]]; then
+        _warning_log "$0:${FUNCNAME[0]} attempted to set log_level with "\
+            "invalid input, log_level unchanged, currently "\
+            "'${LOG_MODES_AVAILABLE[${LOG_LEVEL}]}'"
+    else
+        LOG_LEVEL=${LOG_LEVELS_ARY[${ip_level}]}
+        _info_log "$0:${FUNCNAME[0]} changed log_level from "\
+            "'${LOG_MODES_AVAILABLE[${old_log_level}]}' to "\
+            "'${LOG_MODES_AVAILABLE[${LOG_LEVEL}]}'"
+    fi
+    return 0
+}
+
+
+#
+# _set_install_minion_version_fn
+#
+#   Set the version of Salt Minion wanted to install
+#       default 'latest'
+#
+#   Note: typically salt version includes the release number in addition to
+#         version number or 'latest' for the most recent release
+#
+#           for example: 3003.3-1
+#
+# Results:
+#   Returns with exit code
+#
+
+_set_install_minion_version_fn() {
+
+    if [[ "$#" -ne 1 ]]; then
+        _error_log "$0:${FUNCNAME[0]} error expected one parameter "\
+            "specifying the version of the salt-minion to install or 'latest'"
+    fi
+
+    _info_log "$0:${FUNCNAME[0]} processing setting salt version for "\
+        "salt-minion to install"
+    local salt_version=""
+
+    salt_version=$(echo "$1" | cut -d ' ' -f 1)
+    if [[ "latest" = "${salt_version}" ]]; then
+        _debug_log "$0:${FUNCNAME[0]} input salt version for salt-minion to"\
+            " install is 'latest', leaving as default "\
+            "'${default_salt_url_version}' for now"
+
+    else
+        _debug_log "$0:${FUNCNAME[0]} input salt version for salt-minion to"\
+            " install is '${salt_version}'"
+
+        salt_url_version="${salt_version}"
+        _debug_log "$0:${FUNCNAME[0]} set salt version for salt-minion to "\
+            "install to '${salt_url_version}'"
+    fi
+
+    return 0
+}
+
+
+#
+# _update_minion_conf_ary
+#
+#   Updates the running minion_conf array with input key and value
+#   updating with the new value if the key is already found
+#
+# Results:
+#   Updated array
+#
+_update_minion_conf_ary() {
+    local cfg_key="$1"
+    local cfg_value="$2"
+    local _retn=0
+
+    if [[ "$#" -ne 2 ]]; then
+        _error_log "$0:${FUNCNAME[0]} error expect two parameters, "\
+            "a key and a value"
+    fi
+
+    # now search m_cfg_keys array to see if new key
+    key_ary_sz=${#m_cfg_keys[@]}
+    if [[ ${key_ary_sz} -ne 0 ]]; then
+        # need to check if array has same key
+        local chk_found=0
+        for ((chk_idx=0; chk_idx<key_ary_sz; chk_idx++))
+        do
+            if [[ "${m_cfg_keys[${chk_idx}]}" = "${cfg_key}" ]]; then
+                m_cfg_values[${chk_idx}]="${cfg_value}"
+                _debug_log "$0:${FUNCNAME[0]} updating minion configuration "\
+                    "array key '${m_cfg_keys[${chk_idx}]}' with "\
+                    "value '${cfg_value}'"
+                chk_found=1
+                break;
+            fi
+        done
+        if [[ ${chk_found} -eq 0 ]]; then
+            # new key for array
+            m_cfg_keys[${key_ary_sz}]="${cfg_key}"
+            m_cfg_values[${key_ary_sz}]="${cfg_value}"
+            _debug_log "$0:${FUNCNAME[0]} adding to minion configuration "\
+                "array new key '${cfg_key}' and value '${cfg_value}'"
+        fi
+    else
+        # initial entry
+        m_cfg_keys[0]="${cfg_key}"
+        m_cfg_values[0]="${cfg_value}"
+        _debug_log "$0:${FUNCNAME[0]} adding initial minion configuration "\
+            "array, key '${cfg_key}' and value '${cfg_value}'"
+    fi
+    return ${_retn}
+}
+
+
+#
+# _fetch_vmtools_salt_minion_conf_tools_conf
+#
+#   Retrieve the configuration for salt-minion from vmtools
+#                                           configuration file tools.conf
+#
+# Results:
+#   Exits with new vmtools configuration file if none found or salt-minion
+#   configuration file updated with configuration read from vmtools
+#   configuration file section for salt_minion
+#
+
+_fetch_vmtools_salt_minion_conf_tools_conf() {
+    # fetch the current configuration for section salt_minion
+    # from vmtoolsd configuration file
+    local _retn=0
+    if [[ ! -f "${vmtools_base_dir_etc}/${vmtools_conf_file}" ]]; then
+        # conf file doesn't exist, create it
+        mkdir -p "${vmtools_base_dir_etc}"
+        echo "[${vmtools_salt_minion_section_name}]" \
+            > "${vmtools_base_dir_etc}/${vmtools_conf_file}"
+        _warning_log "$0:${FUNCNAME[0]} creating empty configuration "\
+            "file ${vmtools_base_dir_etc}/${vmtools_conf_file}"
+    else
+        # need to extract configuration for salt-minion
+        # find section name ${vmtools_salt_minion_section_name}
+        # read configuration till next section, output salt-minion conf file
+
+        local salt_config_flag=0
+        while IFS= read -r line
+        do
+            line_value=$(_trim "${line}")
+            if [[ -n "${line_value}" ]]; then
+                _debug_log "$0:${FUNCNAME[0]} processing tools.conf "\
+                    "line '${line}'"
+                if echo "${line_value}" | grep -q '^\[' ; then
+                    if [[ ${salt_config_flag} -eq 1 ]]; then
+                        # if new section after doing salt config, we are done
+                        break;
+                    fi
+                    if [[ ${line_value} = \
+                        "[${vmtools_salt_minion_section_name}]" ]]; then
+                        # have section, get configuration values, set flag and
+                        #  start fresh salt-minion configuration file
+                        salt_config_flag=1
+                    fi
+                elif [[ ${salt_config_flag} -eq 1 ]]; then
+                    # read config ahead of section check, better logic flow
+                    cfg_key=$(echo "${line}" | cut -d '=' -f 1)
+                    cfg_value=$(echo "${line}" | cut -d '=' -f 2)
+                    _update_minion_conf_ary "${cfg_key}" "${cfg_value}" || {
+                        _error_log "$0:${FUNCNAME[0]} error updating minion "\
+                            "configuration array with key '${cfg_key}' and "\
+                            "value '${cfg_value}', retcode '$?'";
+                    }
+                else
+                    _debug_log "$0:${FUNCNAME[0]} skipping tools.conf "\
+                        "line '${line}'"
+                fi
+            fi
+        done < "${vmtools_base_dir_etc}/${vmtools_conf_file}"
+    fi
+    return ${_retn}
+}
+
+
+#
+# _fetch_vmtools_salt_minion_conf_guestvars
+#
+#   Retrieve the configuration for salt-minion from vmtools guest variables
+#
+# Results:
+#   salt-minion configuration file updated with configuration read
+#                                           from vmtools guest variables
+#   configuration file section for salt_minion
+#
+
+_fetch_vmtools_salt_minion_conf_guestvars() {
+    # fetch the current configuration for section salt_minion
+    # from  guest variables args
+
+    local _retn=0
+    local gvar_args=""
+
+    gvar_args=$(vmtoolsd --cmd "info-get ${guestvars_salt_args}" 2>/dev/null)\
+        || { _warning_log "$0:${FUNCNAME[0]} unable to retrieve arguments "\
+            "from guest variables location ${guestvars_salt_args}, "\
+            "retcode '$?'";
+    }
+
+    if [[ -z "${gvar_args}" ]]; then return ${_retn}; fi
+
+    _debug_log "$0:${FUNCNAME[0]} processing arguments from guest variables "\
+        "location ${guestvars_salt_args}"
+
+    for idx in ${gvar_args}
+    do
+        cfg_key=$(echo "${idx}" | cut -d '=' -f 1)
+        cfg_value=$(echo "${idx}" | cut -d '=' -f 2)
+        _update_minion_conf_ary "${cfg_key}" "${cfg_value}" || {
+            _error_log "$0:${FUNCNAME[0]} error updating minion configuration"\
+                "array with key '${cfg_key}' and value '${cfg_value}', "\
+                "retcode '$?'";
+        }
+    done
+
+    return ${_retn}
+}
+
+
+#
+# _fetch_vmtools_salt_minion_conf_cli_args
+#
+#   Retrieve the configuration for salt-minion from any args '$@' passed
+#                                               on the command line
+#
+# Results:
+#   Exits with new vmtools configuration file if none found
+#   or salt-minion configuration file updated with configuration read
+#   from vmtools configuration file section for salt_minion
+#
+
+_fetch_vmtools_salt_minion_conf_cli_args() {
+    local _retn=0
+    local cli_args=""
+    local cli_no_args=0
+
+    cli_args="$*"
+    cli_no_args=$#
+    if [[ ${cli_no_args} -ne 0 ]]; then
+        _debug_log "$0:${FUNCNAME[0]} processing command line "\
+            "arguments '${cli_args}'"
+        for idx in ${cli_args}
+        do
+            # check for start of next option, idx starts with '-' (covers '--')
+            if [[ "${idx}" = --* ]]; then
+                break
+            fi
+            cfg_key=$(echo "${idx}" | cut -d '=' -f 1)
+            cfg_value=$(echo "${idx}" | cut -d '=' -f 2)
+            _update_minion_conf_ary "${cfg_key}" "${cfg_value}" || {
+                _error_log "$0:${FUNCNAME[0]} error updating minion "\
+                "configuration array with key '${cfg_key}' and "\
+                "value '${cfg_value}', retcode '$?'";
+            }
+        done
+    fi
+    return ${_retn}
+}
+
+
+#
+# _randomize_minion_id
+#
+#   Added 5 digit random number to input minion identifier
+#
+# Input:
+#       String to add random number to
+#       if no input, default string 'minion_' used
+#
+# Results:
+#   exit, return value etc
+#
+
+_randomize_minion_id() {
+
+    local ran_minion=""
+    local ip_string="$1"
+
+    if [[ -z "${ip_string}" ]]; then
+        ran_minion="minion_${RANDOM:0:5}"
+    else
+        #provided input
+        ran_minion="${ip_string}_${RANDOM:0:5}"
+    fi
+    _debug_log "$0:${FUNCNAME[0]} generated randomized minion "\
+            "identifier '${ran_minion}'"
+    echo "${ran_minion}"
+}
+
+
+#
+# _fetch_vmtools_salt_minion_conf
+#
+#   Retrieve the configuration for salt-minion
+#       precendence order: L -> H
+#           from VMware Tools guest Variables
+#           from VMware Tools configuration file tools.conf
+#           from any command line parameters
+#
+# Results:
+#   Exits with new salt-minion configuration file written
+#
+
+_fetch_vmtools_salt_minion_conf() {
+    # fetch the current configuration for section salt_minion
+    # from vmtoolsd configuration file
+
+    _debug_log "$0:${FUNCNAME[0]} retrieving minion configuration parameters"
+    _fetch_vmtools_salt_minion_conf_guestvars || {
+        _error_log "$0:${FUNCNAME[0]} failed to process guest variable "\
+            "arguments, retcode '$?'";
+    }
+    _fetch_vmtools_salt_minion_conf_tools_conf || {
+        _error_log "$0:${FUNCNAME[0]} failed to process tools.conf file, "\
+            "retcode '$?'";
+    }
+    _fetch_vmtools_salt_minion_conf_cli_args "$*" || {
+        _error_log "$0:${FUNCNAME[0]} failed to process command line "\
+            "arguments, retcode '$?'";
+    }
+
+    # now write minion conf array to salt-minion configuration file
+    local mykey_ary_sz=${#m_cfg_keys[@]}
+    local myvalue_ary_sz=${#m_cfg_values[@]}
+    if [[ "${mykey_ary_sz}" -ne "${myvalue_ary_sz}" ]]; then
+        _error_log "$0:${FUNCNAME[0]} key '${mykey_ary_sz}' and "\
+            "value '${myvalue_ary_sz}' array sizes for minion_conf "\
+            "don't match"
+    else
+        mkdir -p "${salt_conf_dir}"
+        echo "# Minion configuration file - created by vmtools salt script"\
+            > "${salt_minion_conf_file}"
+        echo "enable_fqdns_grains: False" >> "${salt_minion_conf_file}"
+        for ((chk_idx=0; chk_idx<mykey_ary_sz; chk_idx++))
+        do
+            # appending to salt-minion configuration file since it
+            # should be new and no configuration set
+
+            # check for special case of signed master's public key
+            # verify_master_pubkey_sign=master_sign.pub
+            if [[ "${m_cfg_keys[${chk_idx}]}" \
+                    = "verify_master_pubkey_sign" ]]; then
+                _debug_log "$0:${FUNCNAME[0]} processing minion "\
+                    "configuration parameters for master public signed key"
+                echo "${m_cfg_keys[${chk_idx}]}: True" \
+                    >> "${salt_minion_conf_file}"
+                mkdir -p "/etc/salt/pki/minion"
+                cp -f "${m_cfg_values[${chk_idx}]}" \
+                    "${salt_master_sign_dir}/"
+            else
+                echo "${m_cfg_keys[${chk_idx}]}: ${m_cfg_values[${chk_idx}]}" \
+                    >> "${salt_minion_conf_file}"
+            fi
+        done
+    fi
+
+    _info_log "$0:${FUNCNAME[0]} successfully retrieved the salt-minion "\
+        "configuration from configuration sources"
+    return 0
+}
+
+
+#
+# _curl_download
+#
+#   Retrieve file from specifed url to specific file
+#
+# Results:
+#   Exits with 0 or error code
+#
+
+_curl_download() {
+    local file_name="$1"
+    local file_url="$2"
+    local download_retry_failed=1       # assume issues
+    local _retn=0
+
+    _info_log "$0:${FUNCNAME[0]} attempting download of file '${file_name}'"
+
+    for ((i=0; i<CURL_DOWNLOAD_RETRY_COUNT; i++))
+    do
+        # ensure minimum version of TLS used is v1.2
+        curl -o "${file_name}" --tlsv1.2 -fsSL "${file_url}"
+        _retn=$?
+        if [[ ${_retn} -ne 0 ]]; then
+            _warning_log "$0:${FUNCNAME[0]} failed to download file "\
+                "'${file_name}' from '${file_url}' on '${i}' attempt, "\
+                "retcode '${_retn}'"
+        else
+            download_retry_failed=0
+            _debug_log "$0:${FUNCNAME[0]} successfully downloaded file "\
+                "'${file_name}' from '${file_url}' after '${i}' attempts"
+            break
+        fi
+    done
+    if [[ ${download_retry_failed} -ne 0 ]]; then
+        _error_log "$0:${FUNCNAME[0]} failed to download file '${file_name}'"\
+            " from '${file_url}' after '${CURL_DOWNLOAD_RETRY_COUNT}' attempts"
+    fi
+
+    _info_log "$0:${FUNCNAME[0]} successfully downloaded file "\
+        "'${file_name}' from '${file_url}'"
+    return 0
+}
+
+
+#
+# _parse_json_latest
+#
+#   Retrieve the salt-minion from Salt repository
+#
+# Results:
+#   Echos string containing colon separated version, name and sha512
+#   from parsed input repo json file
+#   Echos empty '' if 'latest' is not found in repo json file
+#
+ _parse_json_latest() {
+    local file_name="$1"
+    local file_value=""
+    local blk_count=0
+    local latest_blk_count=0
+    local latest_flag=0
+    local found_latest_linux=0
+
+    local var1=""
+    local var2=""
+    declare -A rdict
+
+    _info_log "$0:${FUNCNAME[0]} parsing of repo json file '${file_name}'"
+
+    file_value=$(<"${file_name}")
+
+    # limit 80 cols
+    var1=$(echo "${file_value}" | sed 's/,/,\n/g' | sed 's/{/\n{\n/g')
+    var2=$(echo "${var1}" | sed 's/}/\n}\n/g' | sed 's/,//g' | sed 's/"//g')
+
+    while IFS= read -r line
+    do
+        _debug_log "$0:${FUNCNAME[0]} parsing line '${line}'"
+        if [[ -z "${line}" ]]; then
+            continue
+        fi
+        if [[ "${line}" = "{" ]]; then
+            (( blk_count++ ))
+        elif [[ "${line}" = "}" ]]; then
+            # examine directory just read in
+            if [[  ${latest_flag} -eq 1 ]]; then
+                if [[ "${rdict['os']}" = "linux" ]]; then
+                    # have linux values for latest
+                    _debug_log "$0:${FUNCNAME[0]} parsed following linux for "\
+                    "'latest' from repo json file '${file_name}', os "\
+                    "${rdict['os']}, version ${rdict['version']}, "\
+                    "name ${rdict['name']}, SHA512 "\
+                    "${rdict['SHA512']}"
+                    found_latest_linux=1
+                    break
+                fi
+            fi
+
+            if [[ ${blk_count} -eq ${latest_blk_count} ]]; then
+                latest_flag=0
+                break
+            fi
+            (( blk_count-- ))
+        else
+            line_key=$(echo "${line}" | cut -d ':' -f 1 | xargs)
+            line_value=$(echo "${line}" | cut -d ':' -f 2 | xargs)
+            if [[ "${line_key}" = "latest" ]]; then
+                # note blk_count encountered 'latest' for closing brace check
+                latest_flag=1
+                latest_blk_count=${blk_count}
+                (( latest_blk_count++ ))
+            else
+                rdict["${line_key}"]="${line_value}"
+                _debug_log "$0:${FUNCNAME[0]} updated dictionary with "\
+                "line_key '${line_key}' and line_value '${line_value}'"
+            fi
+        fi
+    done <<< "${var2}"
+
+    if [[ ${found_latest_linux} -eq 1 ]]; then
+        echo "${rdict['version']}:${rdict['name']}:${rdict['SHA512']}"
+    else
+        echo ""
+    fi
+    return 0
+}
+
+
+#
+# _fetch_salt_minion
+#
+#   Retrieve the salt-minion from Salt repository
+#
+# Side Effects:
+#   CURRENT_STATUS updated
+#
+# Results:
+#   Exits with 0 or error code
+#
+
+_fetch_salt_minion() {
+    # fetch the current salt-minion into specified location
+    # could check if already there but by always getting it
+    # ensure we are not using stale versions
+    local _retn=0
+    local calc_sha512sum=1
+    local download_retry_failed=1       # assume issues
+
+    local salt_pkg_name=""
+    local salt_url=""
+    local salt_url_chksum_file=""
+    local salt_url_chksum=""
+    local json_version_name_sha=""
+
+    _debug_log "$0:${FUNCNAME[0]} retrieve the salt-minion and check "\
+        "its validity"
+
+    salt_pkg_name="${salt_name}-${salt_url_version}-linux-amd64.tar.gz"
+    salt_url="${base_url}/${salt_url_version}/${salt_pkg_name}"
+    salt_url_chksum_file="${salt_name}-${salt_url_version}_SHA512"
+    salt_url_chksum="${base_url}/${salt_url_version}/${salt_url_chksum_file}"
+
+    CURRENT_STATUS=${STATUS_CODES_ARY[installFailed]}
+    mkdir -p ${base_salt_location}
+    cd ${base_salt_location} || return $?
+    _curl_download "${repo_json_file}" "${base_url_json_file}"
+    _debug_log "$0:${FUNCNAME[0]} successfully downloaded from "\
+        "'${base_url_json_file}' into file '${repo_json_file}'"
+
+    json_version_name_sha=$(_parse_json_latest "${repo_json_file}")
+    if [[ -n "${json_version_name_sha}" ]]; then
+        # use latest from repo.json file, (version:name:sha512)
+        local salt_json_version=""
+        local salt_json_name=""
+        local salt_json_sha512=""
+        local salt_pkg_sha512=""
+
+        salt_json_version=$(\
+            echo "${json_version_name_sha}" | awk -F":" '{print $1}')
+        salt_json_name=$(\
+            echo "${json_version_name_sha}" | awk -F":" '{print $2}')
+        salt_json_sha512=$(\
+            echo "${json_version_name_sha}" | awk -F":" '{print $3}')
+        _debug_log "$0:${FUNCNAME[0]} using repo.json values version "\
+            "'${salt_json_version}', name '${salt_json_name}, sha512 "\
+            "'${salt_json_sha512}'"
+        salt_pkg_name="${salt_json_name}"
+        salt_url="${base_url}/${salt_json_version}/${salt_pkg_name}"
+        _curl_download "${salt_pkg_name}" "${salt_url}"
+        _debug_log "$0:${FUNCNAME[0]} successfully downloaded from "\
+            "'${salt_url}' into file '${salt_pkg_name}'"
+        salt_pkg_sha512=$(sha512sum "${salt_pkg_name}" |awk -F" " '{print $1}')
+        if [[ "${salt_pkg_sha512}" -ne "${salt_json_sha512}" ]]; then
+            CURRENT_STATUS=${STATUS_CODES_ARY[installFailed]}
+            _error_log "$0:${FUNCNAME[0]} downloaded file '${salt_url}' "\
+                "failed to match checksum in file '${repo_json_file}'"
+        fi
+    else
+        # use defaults
+        _curl_download "${salt_pkg_name}" "${salt_url}"
+        _debug_log "$0:${FUNCNAME[0]} successfully downloaded from "\
+            "'${salt_url}' into file '${salt_pkg_name}'"
+        _curl_download "${salt_url_chksum_file}" "${salt_url_chksum}"
+        _debug_log "$0:${FUNCNAME[0]} successfully downloaded from "\
+            "'${salt_url_chksum}' into file '${salt_url_chksum_file}'"
+        calc_sha512sum=$(grep "${salt_pkg_name}" \
+            "${salt_url_chksum_file}" | sha512sum --check --status)
+        if [[ ${calc_sha512sum} -ne 0 ]]; then
+            CURRENT_STATUS=${STATUS_CODES_ARY[installFailed]}
+            _error_log "$0:${FUNCNAME[0]} downloaded file '${salt_url}' "\
+                "failed to match checksum in file '${salt_url_chksum}'"
+        fi
+    fi
+    _debug_log "$0:${FUNCNAME[0]} sha512sum match was successful"
+
+    tar xzf "${salt_pkg_name}" 1>/dev/null
+    _retn=$?
+    if [[ ${_retn} -ne 0 ]]; then
+        CURRENT_STATUS=${STATUS_CODES_ARY[installFailed]}
+        _error_log "$0:${FUNCNAME[0]} tar xzf expansion of downloaded "\
+            "file '${salt_pkg_name}' failed, return code '${_retn}'"
+    fi
+    if [[ ! -f ${test_exists_file} ]]; then
+        CURRENT_STATUS=${STATUS_CODES_ARY[installFailed]}
+        _error_log "$0:${FUNCNAME[0]} expansion of downloaded file "\
+            "'${salt_url}' failed to provide critical file "\
+            "'${test_exists_file}'"
+    fi
+    CURRENT_STATUS=${STATUS_CODES_ARY[installed]}
+    cd "${CURRDIR}" || return $?
+
+    _info_log "$0:${FUNCNAME[0]} successfully retrieved salt-minion"
+    return 0
+}
+
+
+#
+# _check_multiple_script_running
+#
+#   check if more than one version of the script is running
+#
+# Results:
+#   Echos the number of scripts running, allowing for forks etc
+#   from bash etc, a single instance of the script returns 3
+#
+
+_check_multiple_script_running() {
+    local count=0
+    local procs_found=""
+
+    _info_log "$0:${FUNCNAME[0]} checking how many versions of the "\
+        "script are running"
+
+    procs_found=$(pgrep -f "${SCRIPTNAME}")
+    count=$(echo "${procs_found}" | wc -l)
+
+    _debug_log "$0:${FUNCNAME[0]} checking versions of script are running, "\
+        "bashpid '${BASHPID}', processes found '${procs_found}', "\
+        "and count '${count}'"
+
+    echo "${count}"
+    return 0
+}
+
+
+#
+# _check_std_minion_install
+#
+# Check if standard salt-minion is installed for the OS
+#   for example: install salt-minion from rpm or deb package
+#
+# Results:
+#   0 - No standard install found and empty string output
+#   !0 - Standard install found and Salt version found output
+#
+
+_check_std_minion_install() {
+
+    # checks for /usr/bin, then /usr/local/bin
+    # this catches 80% to 90%  of the reqular cases
+    # if salt-call is there, then so is a salt-minion
+    # as they are installed together
+
+    local _retn=0
+    local max_file_sz=200
+    local list_of_files_check="
+/usr/bin/salt-call
+/usr/local/bin/salt-call
+"
+    _info_log "$0:${FUNCNAME[0]} check if standard salt-minion installed"
+
+    for idx in ${list_of_files_check}
+    do
+        if [[ -f "${idx}" ]]; then
+            #check size of file, if larger than 200, not script wrapper file
+            local file_sz=0
+            file_sz=$(( $(wc -c < "${idx}") ))
+            _debug_log "$0:${FUNCNAME[0]} found file '${idx}', "\
+                "size '${file_sz}'"
+            if [[ ${file_sz} -gt ${max_file_sz} ]]; then
+                # get salt-version
+                local s_ver=""
+                s_ver=$("${idx}" --local test.version |grep -v 'local:' |xargs)
+                _debug_log "$0:${FUNCNAME[0]} found standard salt-minion, "\
+                    "Salt version: '${s_ver}'"
+                echo "${s_ver}"
+                _retn=1
+                break
+            fi
+        fi
+    done
+    echo ""
+    return ${_retn}
+}
+
+
+#
+# _find_salt_pid
+#
+#   finds the pid for the salt process
+#
+# Results:
+#   Echos ${salt_pid} which could be empty '' if salt process not found
+#
+
+_find_salt_pid() {
+    # find the pid for salt-minion if active
+    local salt_pid=0
+    salt_pid=$(pgrep -f "${salt_name}\/run\/run minion" | head -n 1 |
+        awk -F " " '{print $1}')
+    _debug_log "$0:${FUNCNAME[0]} checking for salt-minion process id, "\
+        "found '${salt_pid}'"
+    echo "${salt_pid}"
+}
+
+#
+# _ensure_id_or_fqdn
+#
+#   Ensures that a valid minion identifier has been specified, and if not a
+#   valid Fully Qualified Domain Name exists (not default Unknown.example.org)
+#   else generates a minion id to use.
+#
+# Note: this function should only be run before starting the salt-minion
+#       via systemd after it has been installed
+#
+# Side Effect:
+#   Updates salt-minion configuration file with generated identifer
+#       if no valid FQDN
+#
+# Results:
+#   salt-minion configuration contains a valid identifier or FQDN to use.
+#   Exits with 0
+#
+
+_ensure_id_or_fqdn () {
+    # ensure minion id or fqdn for salt-minion
+
+    local minion_fqdn=""
+
+    # quick check if id specified
+    if grep -q '^id:' < "${salt_minion_conf_file}"; then
+        _debug_log "$0:${FUNCNAME[0]} salt-minion identifier found, no "\
+            "need to check further"
+        return 0
+    fi
+
+    _debug_log "$0:${FUNCNAME[0]} ensuring salt-minion identifier or "\
+        "FQDN is specified for salt-minion configuration"
+    minion_fqdn=$(/usr/bin/salt-call --local grains.get fqdn |
+        grep -v 'local:' | xargs)
+    if [[ -n "${minion_fqdn}" &&
+        "${minion_fqdn}" != "Unknown.example.org" ]]; then
+        _debug_log "$0:${FUNCNAME[0]} non-default salt-minion FQDN "\
+            "'${minion_fqdn}' is specified for salt-minion configuration"
+        return 0
+    fi
+
+    # default FQDN, no id is specified, generate one and update conf file
+    local minion_genid=""
+    minion_genid=$(_generate_minion_id)
+    echo "id: ${minion_genid}" >> "${salt_minion_conf_file}"
+    _debug_log "$0:${FUNCNAME[0]} no salt-minion identifier found, "\
+        "generated identifier '${minion_genid}'"
+
+    return 0
+}
+
+
+#
+# _create_helper_scripts
+#
+#   Create helper scripts for salt-call and salt-minion
+#
+#       Example: _create_helper_scripts
+#
+# Results:
+#   Exits with 0 or error code
+#
+
+_create_helper_scripts() {
+
+    for idx in ${salt_wrapper_file_list}
+    do
+        local abs_filepath=""
+        abs_filepath="/usr/bin/salt-${idx}"
+
+        _debug_log "$0:${FUNCNAME[0]} creating helper file 'salt-${idx}' "\
+            "in directory /usr/bin"
+
+        echo "#!/usr/bin/env bash
+
+# Copyright (c) 2021 VMware, Inc. All rights reserved.
+" > "${abs_filepath}" || {
+            _error_log "$0:${FUNCNAME[0]} failed to create helper file "\
+                "'salt-${idx}' in directory /usr/bin, retcode '$?'";
+        }
+        {
+            echo -n "exec /opt/saltstack/salt/run/run ${idx} ";
+            echo -n "\"$";
+            echo -n "{";
+            echo -n "@";
+            echo -n ":";
+            echo -n "1}";
+            echo -n "\"";
+        } >> "${abs_filepath}" || {
+            _error_log "$0:${FUNCNAME[0]} failed to finish creating helper "\
+                "file 'salt-${idx}' in directory /usr/bin, retcode '$?'";
+        }
+        echo  "" >> "${abs_filepath}"
+
+        # ensure executable
+        chmod 755 "${abs_filepath}" || {
+            _error_log "$0:${FUNCNAME[0]} failed to make helper file "\
+                "'salt-${idx}' executable in directory /usr/bin, retcode '$?'";
+        }
+    done
+
+}
+
+
+#
+# _status_fn
+#
+#   discover and return the current status
+#
+#       0 => installed
+#       1 => installing
+#       2 => notInstalled
+#       3 => installFailed
+#       4 => removing
+#       5 => removeFailed
+#       126 => scriptFailed
+#
+# Side Effects:
+#   CURRENT_STATUS updated
+#
+# Results:
+#   Exits numerical status
+#
+
+_status_fn() {
+    # return status
+    local _retn_status=${STATUS_CODES_ARY[notInstalled]}
+    local script_count=0
+
+    _info_log "$0:${FUNCNAME[0]} checking status for script"
+    script_count=$(_check_multiple_script_running)
+    if [[ ${script_count} -gt 3 ]]; then
+        _error_log "$0:${FUNCNAME[0]} failed to check status, " \
+            "multiple versions of the script are running"
+    fi
+
+    svpid=$(_find_salt_pid)
+    if [[ ! -f "${test_exists_file}" && -z ${svpid} ]]; then
+        # check not installed and no process id
+        CURRENT_STATUS=${STATUS_CODES_ARY[notInstalled]}
+        _retn_status=${STATUS_CODES_ARY[notInstalled]}
+    elif [[ -f "${test_exists_file}" ]]; then
+        # check installed
+        CURRENT_STATUS=${STATUS_CODES_ARY[installed]}
+        _retn_status=${STATUS_CODES_ARY[installed]}
+        # normal case but double-check
+        svpid=$(_find_salt_pid)
+        if [[ -z ${svpid} ]]; then
+            # Note: someone could have stopped the salt-minion,
+            # so installed but not running,
+            # status codes don't allow for that case
+            CURRENT_STATUS=${STATUS_CODES_ARY[installFailed]}
+            _retn_status=${STATUS_CODES_ARY[installFailed]}
+        fi
+    elif [[ -z ${svpid} ]]; then
+        # check no process id and main directory still left, then removeFailed
+        if [[ -f "${test_exists_file}" ]]; then
+            CURRENT_STATUS=${STATUS_CODES_ARY[removeFailed]}
+            _retn_status=${STATUS_CODES_ARY[removeFailed]}
+        fi
+    fi
+
+
+    return ${_retn_status}
+}
+
+
+#
+# _deps_chk_fn
+#
+#   Check dependencies for using salt-minion
+#
+#
+# Side Effects:
+# Results:
+#   Exits with 0 or error code
+#
+_deps_chk_fn() {
+    # return dependency check
+    local error_missing_deps=""
+
+    _info_log "$0:${FUNCNAME[0]} checking script dependencies"
+    for idx in ${salt_dep_file_list}
+    do
+        command -v "${idx}" 1>/dev/null || {
+            if [[ -z "${error_missing_deps}" ]]; then
+                error_missing_deps="${idx}"
+            else
+                error_missing_deps="${error_missing_deps} ${idx}"
+            fi
+        }
+    done
+    if [[ -n "${error_missing_deps}" ]]; then
+        _error_log "$0:${FUNCNAME[0]} failed to find required "\
+            "dependenices '${error_missing_deps}'";
+    fi
+    return 0
+}
+
+
+#
+#  _install_fn
+#
+#   Executes scripts to install Salt from Salt repository
+#       and start the salt-minion using systemd
+#
+# Results:
+#   Exits with 0 or error code
+#
+
+_install_fn () {
+    # execute install of Salt minion
+    local _retn=0
+    local script_count=0
+    local existing_chk=""
+    local found_salt_ver=""
+
+    _info_log "$0:${FUNCNAME[0]} processing script install"
+
+    script_count=$(_check_multiple_script_running)
+    if [[ ${script_count} -gt 3 ]]; then
+        _error_log "$0:${FUNCNAME[0]} failed to install, " \
+            "multiple versions of the script are running"
+    fi
+
+    found_salt_ver=$(_check_std_minion_install)
+    if [[ -n "${found_salt_ver}" ]]; then
+        _error_log "$0:${FUNCNAME[0]} failed to install, " \
+            "existing Standard Salt Installation detected, "\
+            "Salt version: '${found_salt_ver}'"
+    else
+        _debug_log "$0:${FUNCNAME[0]} no standardized install found"
+    fi
+
+    # check if salt-minion or salt-master (salt-cloud etc req master)
+    # and log warning that they will be overwritten
+    existing_chk=$(pgrep -l "salt-minion|salt-master" | cut -d ' ' -f 2 | uniq)
+    if [[ -n  "${existing_chk}" ]]; then
+        for idx in ${existing_chk}
+        do
+            local salt_fn=""
+            salt_fn="$(basename "${idx}")"
+            _warning_log "$0:${FUNCNAME[0]} existing salt functionality "\
+                "${salt_fn} shall be stopped and replaced when new "\
+                "salt-minion is installed"
+        done
+    fi
+
+    # fetch salt-minion form repository
+    _fetch_salt_minion || {
+        _error_log "$0:${FUNCNAME[0]} failed to fetch salt-minion "\
+            "from repository , retcode '$?'";
+    }
+
+    # get configuration for salt-minion
+    _fetch_vmtools_salt_minion_conf "$@" || {
+        _error_log "$0:${FUNCNAME[0]} failed , read configuration for "\
+            "salt-minion, retcode '$?'";
+    }
+
+    if [[ ${_retn} -eq 0 && -f "${test_exists_file}" ]]; then
+        # create helper scripts for /usr/bin to ensure they are present
+        # before attempting to use them in _ensure_id_or_fqdn
+        _debug_log "$0:${FUNCNAME[0]} creating helper files salt-call "\
+            "and salt-minion in directory /usr/bin"
+        _create_helper_scripts || {
+            _error_log "$0:${FUNCNAME[0]} failed to create helper files "\
+                "salt-call or salt-minion in directory /usr/bin, retcode '$?'";
+        }
+    fi
+
+    # ensure minion id or fqdn for salt-minion
+   _ensure_id_or_fqdn
+
+    if [[ ${_retn} -eq 0 && -f "${test_exists_file}" ]]; then
+        if [[ -n  "${existing_chk}" ]]; then
+            # be nice and stop any current salt functionalty found
+            for idx in ${existing_chk}
+            do
+                local salt_fn=""
+                salt_fn="$(basename "${idx}")"
+                _warning_log "$0:${FUNCNAME[0]} stopping salt functionality"\
+                    " ${salt_fn} its replaced with new installed salt-minion"
+                systemctl stop "${salt_fn}" || {
+                    _warning_log "$0:${FUNCNAME[0]} stopping existing salt "\
+                        "functionality ${salt_fn} encountered difficulties "\
+                        "using systemctl, it will be over-written with the "\
+                        "new installed salt-minion regarlessly, retcode '$?'";
+                }
+            done
+        fi
+
+        # install salt-minion systemd service script
+        _debug_log "$0:${FUNCNAME[0]} copying systemd service script "\
+            "'salt-minion.service' to directory /usr/lib/systemd/system"
+        echo "${salt_minion_service_wrapper}" \
+            > /usr/lib/systemd/system/salt-minion.service || {
+            _error_log "$0:${FUNCNAME[0]} failed to copy systemd service "\
+                "file 'salt-minion.service' to directory "\
+                "/usr/lib/systemd/system, retcode '$?'";
+        }
+        cd /etc/systemd/system || return $?
+        rm -f "salt-minion.service"
+        ln -s "/usr/lib/systemd/system/salt-minion.service" \
+            "salt-minion.service" || {
+                _error_log "$0:${FUNCNAME[0]} failed to symbolic link "\
+                    "systemd service file 'salt-minion.service' in "\
+                    "directory /etc/systemd/system, retcode '$?'";
+        }
+        _debug_log "$0:${FUNCNAME[0]} symbolically linked systemd service "\
+            "file 'salt-minion.service' in directory /etc/systemd/system"
+        cd "${CURRDIR}" || return $?
+
+        # start the salt-minion using systemd
+        local name_service="salt-minion.service"
+        systemctl daemon-reload || {
+            _error_log "$0:${FUNCNAME[0]} reloading the systemd daemon "\
+                "failed , retcode '$?'";
+        }
+        _debug_log "$0:${FUNCNAME[0]} successfully executed systemctl "\
+            "daemon-reload"
+        systemctl restart "${name_service}" || {
+            _error_log "$0:${FUNCNAME[0]} starting the salt-minion using "\
+                "systemctl failed , retcode '$?'";
+        }
+        _debug_log "$0:${FUNCNAME[0]} successfully executed systemctl "\
+            "restart '${name_service}'"
+        systemctl enable "${name_service}" || {
+            _error_log "$0:${FUNCNAME[0]} enabling the salt-minion using "\
+                "systemctl failed , retcode '$?'";
+        }
+        _debug_log "$0:${FUNCNAME[0]} successfully executed systemctl "\
+            "enable '${name_service}'"
+    fi
+    return ${_retn}
+}
+
+
+#
+# _generate_minion_id
+#
+#   Searchs salt-minion configuration file for current id, and disables it
+#   and generates a new id based from the existng id found,
+#   or an older commented out id, and provides it with a randomized 5 digit
+#   postpended to it, for example:  myminion_12345
+#
+#   if no previous id found, a generated minion_<random number> is output
+#
+# Side Effects:
+#   Disables any id found in minion configuration file
+#
+# Result:
+#   Outputs randomized minion id for use in a minion configuration file
+#   Exits with 0 or error code
+#
+
+_generate_minion_id () {
+
+    local salt_id_flag=0
+    local minion_id=""
+    local cfg_value=""
+    local ifield=""
+    local tfields=""
+
+    _debug_log "$0:${FUNCNAME[0]} generating a salt-minion identifier"
+
+    # always comment out what was there
+    sed -i 's/^id:/# id:/g' "${salt_minion_conf_file}"
+
+    while IFS= read -r line
+    do
+        line_value=$(_trim "${line}")
+        if [[ -n "${line_value}" ]]; then
+            if echo "${line_value}" | grep -q '^# id:' ; then
+                # get value and write out value_<random>
+                cfg_value=$(echo "${line_value}" | cut -d ' ' -f 3)
+                if [[ -n "${cfg_value}" ]]; then
+                    salt_id_flag=1
+                    minion_id=$(_randomize_minion_id "${cfg_value}")
+                    _debug_log "$0:${FUNCNAME[0]} found previously used id "\
+                        "field, randomizing it"
+                fi
+            elif echo "${line_value}" | grep -q -w 'id:' ; then
+                # might have commented out id, get value and
+                # write out value_<random>
+                tfields=$(echo "${line_value}"|awk -F ':' '{print $2}'|xargs)
+                ifield=$(echo "${tfields}" | cut -d ' ' -f 1)
+                if [[ -n ${ifield} ]]; then
+                    minion_id=$(_randomize_minion_id "${ifield}")
+                    salt_id_flag=1
+                    _debug_log "$0:${FUNCNAME[0]} found previously used "\
+                        "id field, randomizing it"
+                fi
+            else
+                _debug_log "$0:${FUNCNAME[0]} skipping line '${line}'"
+            fi
+        fi
+    done < "${salt_minion_conf_file}"
+
+    if [[ ${salt_id_flag} -eq 0 ]]; then
+        # no id field found, write minion_<random?
+        _debug_log "$0:${FUNCNAME[0]} no previous id field found, "\
+            "generating new identifier"
+        minion_id=$(_randomize_minion_id)
+    fi
+    _debug_log "$0:${FUNCNAME[0]} generated a salt-minion "\
+        "identifier '${minion_id}'"
+    echo "${minion_id}"
+    return 0
+}
+
+
+#
+# _clear_id_key_fn
+#
+#   Executes scripts to clear the minion identifer and keys and
+#   re-generates new identifer, allows for a VM containing a salt-minion,
+#   to be cloned and not have conflicting id and keys
+#   salt-minion is stopped, id and keys cleared, and restarted
+#   if it was previously running
+#
+# Input:
+#   Optional specified input ID to be used, default generate randomized value
+#
+# Note:
+#   Normally a salt-minion if no id is specified will rely on
+#   it's Fully Qualified Domain Name but with VM Cloning, there is no surety
+#   that the FQDN will have been altered, and duplicates can occur.
+#   Also if there is no FQDN, then default 'Unknown.example.org' is used,
+#   again with the issue of duplicates for multiple salt-minions
+#   with no FQDN specified
+#
+# Side Effects:
+#   New minion identifier in configuration file and keys for the salt-minion
+#
+# Results:
+#   Exits with 0 or error code
+#
+
+_clear_id_key_fn () {
+    # execute clearing of Salt minion id and keys
+    local _retn=0
+    local salt_minion_pre_active_flag=0
+    local salt_id_flag=0
+    local minion_id=""
+    local minion_ip_id=""
+    local script_count=0
+
+    _info_log "$0:${FUNCNAME[0]} processing clearing of salt-minion "\
+        "identifier and its keys"
+
+    script_count=$(_check_multiple_script_running)
+    if [[ ${script_count} -gt 3 ]]; then
+        _error_log "$0:${FUNCNAME[0]} failed to clear, " \
+            "multiple versions of the script are running"
+    fi
+
+    if [[ ! -f "${test_exists_file}" ]]; then
+        _debug_log "$0:${FUNCNAME[0]} salt-minion is not installed, "\
+            "nothing to do"
+        return ${_retn}
+    fi
+
+    # get any minion identifier in case specified
+    minion_ip_id=$(echo "$1" | cut -d ' ' -f 1)
+    svpid=$(_find_salt_pid)
+    if [[ -n ${svpid} ]]; then
+        # stop the active salt-minion using systemd
+        # and give it a little time to stop
+        systemctl stop salt-minion || {
+            _error_log "$0:${FUNCNAME[0]} failed to stop salt-minion "\
+                "using systemctl, retcode '$?'";
+        }
+        _debug_log "$0:${FUNCNAME[0]} successfully executed systemctl "\
+            "stop salt-minion"
+        salt_minion_pre_active_flag=1
+    fi
+
+    rm -fR "${salt_conf_dir}/minion_id"
+    rm -fR "${salt_conf_dir}/pki/${salt_minion_conf_name}"
+    # always comment out what was there
+    sed -i 's/^id/# id/g' "${salt_minion_conf_file}"
+    _debug_log "$0:${FUNCNAME[0]} removed '${salt_conf_dir}/minion_id' "\
+        "and '${salt_conf_dir}/pki/${salt_minion_conf_name}', and "\
+        "commented out id in '${salt_minion_conf_file}'"
+
+    if [[ -z "${minion_ip_id}" ]] ;then
+        minion_id=$(_generate_minion_id)
+    else
+        minion_id="${minion_ip_id}"
+    fi
+
+    # add new minion id to bottom of minion configuration file
+    echo "id: ${minion_id}" >> "${salt_minion_conf_file}"
+    _debug_log "$0:${FUNCNAME[0]} updated salt-minion identifer "\
+        "'${minion_id}' in configuration file '${salt_minion_conf_file}'"
+
+    if [[ ${salt_minion_pre_active_flag} -eq 1 ]]; then
+        # restart the stopped salt-minion using systemd
+        systemctl restart salt-minion || {
+            _error_log "$0:${FUNCNAME[0]} failed to restart salt-minion "\
+                "using systemctl, retcode '$?'";
+        }
+
+        _debug_log "$0:${FUNCNAME[0]} successfully executed systemctl "\
+            "restart salt-minion"
+    fi
+
+    return ${_retn}
+}
+
+
+#
+# _remove_installed_files_dirs
+#
+#   Removes all Salt files and directories that may be used
+#
+# Results:
+#   Exits with 0 or error code
+#
+
+_remove_installed_files_dirs() {
+    _debug_log "$0:${FUNCNAME[0]} removing directories and files "\
+        "in '${list_file_dirs_to_remove}'"
+    for idx in ${list_file_dirs_to_remove}
+    do
+        rm -fR "${idx}" || {
+            _error_log "$0:${FUNCNAME[0]} failed to remove file or "\
+                "directory '${idx}' , retcode '$?'";
+        }
+    done
+    return 0
+}
+
+
+#
+#  _uninstall_fn
+#
+#   Executes scripts to uninstall Salt from system
+#       stopping the salt-minion using systemd
+#
+# Side Effects:
+#   CURRENT_STATUS updated
+#
+# Results:
+#   Exits with 0 or error code
+#
+
+_uninstall_fn () {
+    # remove Salt minion
+    local _retn=0
+    local script_count=0
+
+    _info_log "$0:${FUNCNAME[0]} processing script remove"
+
+    script_count=$(_check_multiple_script_running)
+    if [[ ${script_count} -gt 3 ]]; then
+        _error_log "$0:${FUNCNAME[0]} failed to remove, " \
+            "multiple versions of the script are running"
+    fi
+
+    found_salt_ver=$(_check_std_minion_install)
+    if [[ -n "${found_salt_ver}" ]]; then
+        _error_log "$0:${FUNCNAME[0]} failed to remove, " \
+            "existing Standard Salt Installation detected, "\
+            "Salt version: '${found_salt_ver}'"
+    else
+        _debug_log "$0:${FUNCNAME[0]} no standardized install found"
+    fi
+
+    if [[ ! -f "${test_exists_file}" ]]; then
+        CURRENT_STATUS=${STATUS_CODES_ARY[notInstalled]}
+
+        # assumme rest is gone
+        # TBD enhancement, could loop thru and check all of files to remove
+        # and if salt_pid empty but we error out if issues when uninstalling,
+        # so safe for now.
+        _retn=0
+    else
+        CURRENT_STATUS=${STATUS_CODES_ARY[removing]}
+        svpid=$(_find_salt_pid)
+        if [[ -n ${svpid} ]]; then
+            # stop the active salt-minion using systemd
+            # and give it a little time to stop
+            systemctl stop salt-minion || {
+                _error_log "$0:${FUNCNAME[0]} failed to stop salt-minion "\
+                    "using systemctl, retcode '$?'";
+            }
+            _debug_log "$0:${FUNCNAME[0]} successfully executed systemctl "\
+                "stop salt-minion"
+            systemctl disable salt-minion || {
+                _error_log "$0:${FUNCNAME[0]} disabling the salt-minion "\
+                    "using systemctl failed , retcode '$?'";
+            }
+            _debug_log "$0:${FUNCNAME[0]} successfully executed systemctl "\
+                "disable salt-minion"
+        fi
+
+        if [[ ${_retn} -eq 0 ]]; then
+            svpid=$(_find_salt_pid)
+            if [[ -n ${svpid} ]]; then
+                _debug_log "$0:${FUNCNAME[0]} found salt-minion process "\
+                    "id '${salt_pid}', systemctl stop should have "\
+                    "eliminated it, killing it now"
+                kill "${svpid}"
+                ## given it a little time
+                sleep 5
+            fi
+            svpid=$(_find_salt_pid)
+            if [[ -n ${svpid} ]]; then
+                CURRENT_STATUS=${STATUS_CODES_ARY[removeFailed]}
+                _error_log "$0:${FUNCNAME[0]} failed to kill the "\
+                    "salt-minion, pid '${svpid}' during uninstall"
+            else
+                _remove_installed_files_dirs || {
+                    _error_log "$0:${FUNCNAME[0]} failed to remove all "\
+                        "installed salt-minion files and directories, "\
+                        "retcode '$?'";
+                }
+                CURRENT_STATUS=${STATUS_CODES_ARY[notInstalled]}
+            fi
+        fi
+    fi
+
+    _info_log "$0:${FUNCNAME[0]} successfuly removed salt-minion and "\
+        "associated files and directories"
+    return ${_retn}
+}
+
+
+#
+#  _clean_up_log_files
+#
+#   Limits number of log files by removing oldest log files which exceed
+#   limit LOG_FILE_NUMBER
+#
+# Results:
+#   Exits with 0 or error code
+#
+_clean_up_log_files() {
+
+    _info_log "$0:${FUNCNAME[0]} removing and limiting log files"
+    for idx in ${allowed_log_file_action_names}
+    do
+        local count_f=0
+        local found_f=""
+        local -a found_f_ary
+        found_f=$(ls -t "${log_dir}/vmware-${SCRIPTNAME}-${idx}"* 2>/dev/null)
+        count_f=$(echo "${found_f}" | wc | awk -F" " '{print $2}')
+        mapfile -t found_f_ary <<< "${found_f}"
+
+        if [[ ${count_f} -gt ${LOG_FILE_NUMBER} ]]; then
+            # allow for org-0
+            for ((i=count_f-1; i>=LOG_FILE_NUMBER; i--)); do
+                _debug_log "$0:${FUNCNAME[0]} removing log file "\
+                    "'${found_f_ary[i]}', for count '${i}', "\
+                    "limit '${LOG_FILE_NUMBER}'"
+                rm -f "${found_f_ary[i]}" || {
+                    _error_log "$0:${FUNCNAME[0]} failed to remove file "\
+                    "'${found_f_ary[i]}', for count '${i}', "\
+                    "limit '${LOG_FILE_NUMBER}'"
+                }
+            done
+        else
+            _debug_log "$0:${FUNCNAME[0]} found '${count_f}' "\
+                "log files starting with "\
+                "${log_dir}/vmware-${SCRIPTNAME}-${idx}-"\
+                ", limit '${LOG_FILE_NUMBER}'"
+        fi
+    done
+    return 0
+}
+
+################################### MAIN ####################################
+
+# static definitions
+
+CURRDIR=$(pwd)
+
+# default status is notInstalled
+CURRENT_STATUS=${STATUS_CODES_ARY[notInstalled]}
+export CURRENT_STATUS
+
+## build date-time tag used for logging UTC YYYYMMDDhhmmss
+## YearMontDayHourMinuteSecondMicrosecond aka jid
+logdate=$(date -u +%Y%m%d%H%M%S)
+
+# set logging infomation
+LOG_FILE_NUMBER=5
+SCRIPTNAME=$(basename "$0")
+mkdir -p "${log_dir}"
+
+# set to action e.g. 'remove', 'install'
+# default is for any logging not associated with a specific action
+# for example: debug logging and --version
+LOG_ACTION="default"
+
+CLI_ACTION=0
+
+while true; do
+    if [[ -z "$1" ]]; then break; fi
+    case "$1" in
+        -c | --clear )
+            CLEAR_ID_KEYS_FLAG=1;
+            shift;
+            CLEAR_ID_KEYS_PARAMS=$*;
+            ;;
+        -d | --depend )
+            DEPS_CHK=1;
+            shift;
+            ;;
+        -h | --help )
+            USAGE_HELP=1;
+            shift;
+            ;;
+        -i | --install )
+            INSTALL_FLAG=1;
+            shift;
+            INSTALL_PARAMS="$*";
+            ;;
+        -l | --loglevel )
+            LOG_LEVEL_FLAG=1;
+            shift;
+            LOG_LEVEL_PARAMS="$*";
+            ;;
+        -m | --minionversion )
+            MINION_VERSION_FLAG=1;
+            shift;
+            MINION_VERSION_PARAMS="$*";
+            ;;
+        -r | --remove )
+            UNINSTALL_FLAG=1;
+            shift;
+            ;;
+        -s | --status )
+            STATUS_CHK=1;
+            shift;
+            ;;
+        -v | --version )
+            VERSION_FLAG=1;
+            shift;
+            ;;
+        -- )
+            shift;
+            break;
+            ;;
+        * )
+            shift;
+            ;;
+    esac
+done
+
+## check if want help, display usage and exit
+if [[ ${USAGE_HELP} -eq 1 ]]; then
+  _usage
+  exit 0
+fi
+
+
+##  MAIN BODY OF SCRIPT
+
+retn=0
+
+if [[ ${LOG_LEVEL_FLAG} -eq 1 ]]; then
+    # ensure logging level changes are processed before any actions
+    CLI_ACTION=1
+    _set_log_level "${LOG_LEVEL_PARAMS}"
+    retn=$?
+fi
+if [[ ${STATUS_CHK} -eq 1 ]]; then
+    CLI_ACTION=1
+    LOG_ACTION="status"
+    _status_fn
+    retn=$?
+fi
+if [[ ${DEPS_CHK} -eq 1 ]]; then
+    CLI_ACTION=1
+    LOG_ACTION="depend"
+    _deps_chk_fn
+    retn=$?
+fi
+if [[ ${MINION_VERSION_FLAG} -eq 1 ]]; then
+    CLI_ACTION=1
+    # ensure this is processed before install
+    _set_install_minion_version_fn "${MINION_VERSION_PARAMS}"
+    retn=$?
+fi
+if [[ ${INSTALL_FLAG} -eq 1 ]]; then
+    CLI_ACTION=1
+    LOG_ACTION="install"
+    _install_fn "${INSTALL_PARAMS}"
+    retn=$?
+fi
+if [[ ${CLEAR_ID_KEYS_FLAG} -eq 1 ]]; then
+    CLI_ACTION=1
+    LOG_ACTION="clear"
+    _clear_id_key_fn "${CLEAR_ID_KEYS_PARAMS}"
+    retn=$?
+fi
+if [[ ${UNINSTALL_FLAG} -eq 1 ]]; then
+    CLI_ACTION=1
+    LOG_ACTION="remove"
+    _uninstall_fn
+    retn=$?
+fi
+if [[ ${VERSION_FLAG} -eq 1 ]]; then
+    CLI_ACTION=1
+    echo "${SCRIPT_VERSION}"
+    retn=0
+fi
+
+if [[ ${CLI_ACTION} -eq 0 ]]; then
+    # check if guest variables have an action since none from CLI
+    # since none presented on the command line
+    gvar_action=$(vmtoolsd --cmd "info-get ${guestvars_salt_desiredstate}" \
+        2>/dev/null) || {
+            _warning_log "$0 unable to retrieve any action arguments from "\
+                "guest variables ${guestvars_salt_desiredstate}, retcode '$?'";
+    }
+
+    if [[ -n "${gvar_action}" ]]; then
+        case "${gvar_action}" in
+            depend)
+                LOG_ACTION="depend"
+                _deps_chk_fn
+                retn=$?
+                ;;
+            present)
+                LOG_ACTION="install"
+                _install_fn
+                retn=$?
+                ;;
+            absent)
+                LOG_ACTION="remove"
+                _uninstall_fn
+                retn=$?
+                ;;
+            status)
+                LOG_ACTION="status"
+                _status_fn
+                retn=$?
+                ;;
+            *)
+                ;;
+        esac
+    fi
+fi
+
+_clean_up_log_files
+
+exit ${retn}