Skip to content
Snippets Groups Projects
Select Git revision
  • eedd0e15aa7df72a80b738fd6941c39b40490c7d
  • master default protected
  • 7771-harden-postgres-backup
  • pgsql-dump-with-snapshots
  • update-colors
  • update-docs-css
  • usb-repair-stick
  • desktop-notification
  • 7000-corrections
  • db-detector
10 results

CHANGELOG.md

Blame
  • director-cli.sh 23.29 KiB
    #!/bin/bash
    # ======================================================================
    #
    # director helper
    #
    #   C
    #   R
    #   U
    #   D
    #     actions for a host, commands, services
    #
    # This script contains specific logic for IML
    #   - UniBe network and group names - see hostCreate()
    #
    # ----------------------------------------------------------------------
    # ah = axel.hahn@unibe.ch
    # 2022-02-16  v0.2  ah  add --cfg param
    # 2022-03-04  v0.3  ah  abort on http 5xx error
    # 2023-01-22  v0.4  ah  fix _bStopOnError; some shellfixes
    # 2023-02-17  v0.5  ah  add hostnamme into CFGSTORAGE
    # 2023-02-17  v0.6  ah  remove invalid line in cleanup
    # 2023-02-17  v0.7  ah  check inc_getconfig.sh exists and hostname -f has a value
    # 2023-10-25  v0.8  ah  generate json with "jo"; optimze http requests on services; parallel service function call
    # ======================================================================
    
    
    _version="0.8"
    
    which curl >/dev/null || exit 1
    which jo   >/dev/null || exit 1
    
    # a custom file to source instead of detecting local data
    loadfile=
    
    
    # MY_NAME=`facter fqdn | cut -f -2 -d ">"`
    # MY_IP=`facter ipaddress | cut -f -2 -d ">"`
    # TODO: test ... maybe uncomment it again
    # MY_NAME=`hostname -f`
    # MY_IP=`_getIpFrontend`
    
    
    typeset cfg_debug=false
    typeset cfg_dryrun=false
    
    export regexPrivateNetworks="^(10\.|172\.1[6-9]\.|172.2[0-9]\.|172\.3[01]\.|192.168\.)"
    
    # json for a host: set group if the system is pingable by Icinga or in a private network
    hostImportReachable="host in network"
    hostImportPrivate="host passive only"
    
    # default groups (jo params)
    hostDefaultgroups="groups[]=iml groups[]=iml-server"
    
    # ======================================================================
    #
    # FUNCTIONS
    #
    # ======================================================================
    
    
      # helper to make http base setup for host actions
      function _initHttp(){
        # see inc_functions
        _initHttpWithConfigfile "${dir_cfg}/api-director.cfg"
        if [ $cfg_debug = true ]; then
          http.setDebug 1
        fi
      }
    
      function _initVars(){
        if [ -z "$loadfile" ]; then
          MY_NAME=$(hostname -f)
          MY_IP=$(_getIpFrontend | head -1)
          MY_ZONE=
        fi
        # ch="`dirname $0`/inc/confighandler.sh"
        ch="./inc/confighandler.sh"
      }
    
      function flushDatadir(){
        if [ -n "${dir_data}" -a -d "${dir_data}" ]; then
          _wd "deleting ${dir_data} ..."
          rm -f ${dir_data}/*.txt
        fi
      }
    
    # ----------------------------------------------------------------------
    # functions for objects
    # ----------------------------------------------------------------------
    
      # ............................................................
      # generate json parameters for jo
      function _generateJsonForHost(){
    
        if [ -z "$loadfile" ]; then
          # --- host infos
          local MY_Platform=$(uname -a | cut -f 1 -d ' ')
          . $(dirname $0)/plugins/inc_pluginfunctions || exit 1
          local MY_OSName=$(ph.getOS)
          local MY_OSMajorVersion=$(ph.getOSMajor)
        fi
    
        local JSONPARAMS="
          object_name=$MY_NAME
          object_type=object 
          address=$MY_IP
          display_name=$MY_NAME
    
          zone=$MY_ZONE
    
          icon_image=/images/os/${MY_OSName}.png
          icon_image_alt="\"${MY_Platform}:\ ${MY_OSName}\ ${MY_OSMajorVersion}\""
    
          vars.platform=${MY_Platform} \
          vars.os=${MY_OSName}${MY_OSMajorVersion}
    
        "
        # ----- set host type
        # check if host is in a private network:
        if echo "$MY_IP" | grep -E "${regexPrivateNetworks}" >/dev/null
        then
          JSONPARAMS+='imports[]="${hostImportPrivate}" '
        else
          JSONPARAMS+='imports[]="${hostImportReachable}" '
        fi
    
        # port checks initiated by icinga server to monitor client
        if [ -n "${host_vars_tcpport}" -a "${host_vars_tcpport}" != "[]" ]; then
          JSONPARAMS+='vars.tcp_port=${host_vars_tcpport} '
        fi
    
        # ----- host groups
        # all host groups must exist in director - otherwise the creation
        # of a host will fail
        JSONPARAMS+="${hostDefaultgroups} "
    
        echo "$JSONPARAMS"
      }
    
      # ............................................................
      # generate json parameters for jo
      # global  int     checkInterval           fetched in check configuration by _parseCheckConfig
      # global  string  IDC_service__obj_name   generated var from check name in _generateVarsByCheckname
      # global  string  IDC_command__obj_name   generated var from check name in _generateVarsByCheckname
      function _generateJsonForServicetemplate(){
        local JSONPARAMS="
          object_name="\"${IDC_service__obj_name}\""
          check_command=\""${IDC_command__obj_name}\""
          object_type=template
    
          enable_active_checks=false
          enable_passive_checks=true
    
          check_interval="\"${checkInterval}s\"" 
    
          # graphite
          enable_perfdata=true 
          vars.check_command=\"${checkName}\"
        "
          if [ ! -z "${checkIcon}" ]; then
            JSONPARAMS+="icon_image=\"${checkIcon}\" icon_image_alt=\"${checkName}\" "
          fi
    
          if [ ! -z "${checkMaxAttempts}" ]; then
            JSONPARAMS+="max_check_attempts=${checkMaxAttempts}"
          fi
        echo "$JSONPARAMS"
      }
    
      # ............................................................
      # generate json parameters for jo
      function _generateJsonForSvclink(){
        local JSONPARAMS="
          object_name="\"${IDC_svcathost__obj_name}\""
          check_type=object
          host=${MY_NAME}
          imports[]="\"${IDC_service__obj_name}\""
        "
        echo "JSONPARAMS"
      }
    
      # ............................................................
      # CRUD actions for an director object: host, service template, linked service
      # examples:
      #   ObjAction create host
      #   ObjAction list svclink
      #
      # param  string  name of action; one of create|read|update|delete|exists|list
      # param  string  name of object; one of host|service|svclink
      # param  string  Dryrun (set any not empty value to show infos without execution)
      function ObjAction(){
    
        local _paramAction=$1
        local _paramObj=$2
        local _paramDryrun=$cfg_dryrun
        test -z "$3" || _paramDryrun=true
    
        local _object_name=         # name of the current object (for ouput only)
    
        local _sMethod=             # http method; GET|POST|PUT|DELETE
        local _sUrl=                # relative url (part behind REST API base url)
        local _jsondata=
    
        local _bNeedsCheck=false    # requires $IDC* vars (a read check config first)
        local _bSendData=false      # true for PUT and POST
    
        local _sUrlList=
        local _sUrlCreate=
        local _sUrlExists=
        local _sUrlRead=
        local _sUrlUpdate=
        local _sUrlDelete=
    
        local _existFilter=
    
        local _bShowResponse=true
        local _bShowFilter=false
        local _bStopOnError=true
        
        # local _sCachefile=
    
        _initHttp
    
        # --- init object based vars
        case "${_paramObj}" in
    
          'host')
            _object_name=$MY_NAME
            _sUrlCreate=director/host
            _sUrlExists=director/host?name=${_object_name}
            _sUrlRead=director/host?name=${_object_name}
            _sUrlUpdate=director/host?name=${_object_name}
            _sUrlDelete=director/host?name=${_object_name}
    
            _existFilter="object_name"
            _jsonparams="$( _generateJsonForHost )"
            ;;
    
          'service')
            _object_name=${IDC_service__obj_name}
            _bNeedsCheck=true
    
            _sUrlList=director/services/templates
            _sUrlCreate=director/service
            _sUrlExists=director/service?name=${_object_name}
            _sUrlRead=director/service?name=${_object_name}
            _sUrlUpdate=director/service?name=${_object_name}
            _sUrlDelete=director/service?name=${_object_name}
    
            _existFilter='"object_name": '
            _jsonparams="$( _generateJsonForServicetemplate )"
            ;;
    
          'svclink')
            _object_name=${IDC_svcathost__obj_name}
            _bNeedsCheck=true
            _sUrlList=director/services?host=$MY_NAME
            _sUrlCreate=director/service
            _sUrlExists="director/service?name=${IDC_svcathost__obj_name}&host=$MY_NAME"
            _sUrlRead="director/service?name=${IDC_svcathost__obj_name}&host=$MY_NAME"
            _sUrlUpdate="director/service?name=${IDC_svcathost__obj_name}&host=$MY_NAME"
            _sUrlDelete="director/service?name=${IDC_svcathost__obj_name}&host=$MY_NAME"
    
            # exists:
            # _existFilter="object_name.*${IDC_svcathost__obj_name}"
            _existFilter='"object_name": '
    
            _jsonparams="$( _generateJsonForSvclink )"
            ;;
    
          *)
            echo "ERROR: object [${_paramObj}] cannot be handled in ${FUNCNAME[0]} (yet?)."
            exit 1
        esac
    
    
        # --- init method based vars
        case "${_paramAction}" in
          'list')
            _sMethod=GET
            _sUrl=$_sUrlList
            _bShowResponse=false
            _bShowFilter=true
    
            _bNeedsCheck=false # 
            ;;
          'exists')
            _sMethod=GET
            _sUrl=$_sUrlExists
            _bShowResponse=false
            _bStopOnError=false
            ;;
          'create')
            _sMethod=PUT
            _sUrl=$_sUrlCreate
            _bSendData=true
            ;;
          'read')
            _sMethod=GET
            _sUrl=$_sUrlRead
            ;;
          'update')
            _sMethod=POST
            _sUrl=$_sUrlUpdate
            _bSendData=true
            ;;
          'delete')
            _sMethod=DELETE
            _sUrl=$_sUrlDelete
            ;;
          *)
            echo "ERROR: method [${_paramAction}] does not exist."
            exit 1
        esac
    
        if [ -z "$_sUrl" ]; then
          echo "SKIP: Action [${_paramAction}] is not supported (yet?) for object type [${_paramObj}]"
          return
        fi
    
        if [ $_bNeedsCheck = true -a -z "${IDC_svcathost__obj_name}" ]; then
          echo "SKIP: you need to load a check before accessing [${_paramObj}]"
          return
        fi
    
        # --- get json data of object
        if [ $_bSendData = true ]; then
          _jsondata=$( eval jo -p -d. $_jsonparams )
        fi
    
        # --- http request
        if [ ${_paramDryrun} = false ]; then
          _wd ">>>>> $_paramAction $_paramObj [${_object_name}] >> $_sMethod $_sUrl $_jsondata"
          http.makeRequest "$_sMethod" "$_sUrl" "$_jsondata"
          if $_bStopOnError && http.isServerError >/dev/null; then
            echo "CRITICAL ERROR: Director API request failed with a server error $_sMethod $_sUrl"
            exit 1
          fi
          if [ $_bShowResponse = true ]; then
            # http.getResponseHeader
            http.getResponse
          fi
    
          http.isOk >/dev/null
        else
          echo "DRYRUN: >>>>> $_paramAction $_paramObj [${_object_name}] >> $_sMethod $_sUrl $_jsondata"
          echo "... _bShowResponse: $_bShowResponse"
          echo "... _bSendData    : $_bSendData"
        fi
    
        # --- on list action: filter response
        if [ "${_paramAction}" = "list" ]; then
          if [ ${_paramDryrun} = false ]; then
            _wd ">>>>> filter response by [object_name]"
            if [ $_bShowFilter = true ]; then
              http.getResponse | grep object_name | cut -f 2- -d ":" | sed 's#^ "##g' | sed 's#",$##'
            else
              http.getResponse | grep object_name | cut -f 2- -d ":" | sed 's#^ "##g' | sed 's#",$##' >/dev/null
            fi
    
          else
    
            echo "DRYRUN: >>>>> filter response by [object_name]"
            echo
          fi
        fi
    
        # --- on exist action: filter response
        if [ "${_paramAction}" = "exists" -a ! -z "${_existFilter}" ]; then
          if [ ${_paramDryrun} = false ]; then
            _wd ">>>>> filter response by [$_existFilter]"
            if [ $_bShowFilter = true ]; then
              http.getResponse | grep $_existFilter
            else
              http.getResponse | grep $_existFilter >/dev/null
            fi
          else
    
            echo "DRYRUN: >>>>> filter response by [$_existFilter]"
            echo
          fi
        fi
      }
    
    # ----------------------------------------------------------------------
    # functions for Host
    # ----------------------------------------------------------------------
    
    
      # ............................................................
      # create a host with PUT on director API
      function hostCreate(){
        _h2 "create host"
    
        ObjAction create host
        if [ -z "$(http.isOk)" ]; then
          echo "ERROR, host was NOT created."
        else
          echo "OK, host was created successfully."
        fi
      }
    
    
      # ............................................................
      # get data of current host from director API
      # and by the way it updates the local host infos too.
      function hostRead(){
        _h2 "read host"
        ObjAction read host
        if [ -z "$(http.isOk)" ]; then
          echo "ERROR, host was NOT found."
        fi
      }
    
    
      # ............................................................
      # update current host
      # param  JSON part starting with ", " and some json data
      function hostUpdate(){
        _h2 "update host - set $1 $2"
    
        ObjAction update host
        if [ -z "$(http.isOk)" ]; then
          case $(http.getStatuscode) in
            "304")
              echo "OK, no update"
              ;;
            *)
              echo "ERROR during update of the host data"
          esac
        else
          echo "OK, host was updated"
        fi
      }
      # ............................................................
      # ensure that a host exists
      function hostCreateOrUpdate(){
        ObjAction exists host
        if [ $? -ne 0 ]; then
          hostCreate
        else
          hostUpdate
        fi
      }
    
    
    
      # ............................................................
      # delete the current host in the director
      function hostDelete(){
        _h2 "delete host"
        ObjAction delete host
        case $(http.getStatuscode) in
          "200")
            echo "OK, host was deleted"
            ;;
          "404")
            echo "ERROR, host does not exist"
            ;;
          *)
            echo "ERROR, unable to delete host"
        esac
        flushDatadir
      }
    
    
    
    # ----------------------------------------------------------------------
    # functions for services
    # director/service
    # ----------------------------------------------------------------------
    
      # ............................................................
      # helper for services: generate variable names for a check
      # vars have prefix IDC for "Icinga Director"
      # uses global var checkName
      function _generateVarsByCheckname(){
        if [ -z "${checkName}" ]; then
          echo ERROR: checkName is empty - I guess _parseCheckConfig was not executed.
          exit 1
        fi
    
        IDC_command__obj_name="${checkName}"
        IDC_service__obj_name="service-template_for_command_${checkName}"
        IDC_svcathost__obj_name="$(_getName4Svcathost ${checkName})"
        IDC_command__cachefile="${dir_data}/command_${checkName}__at-director.txt"
        # set | grep "^IDC"
    
      }
    
    
    
    # ............................................................
      # create a service in Icinga director
      # uses global variables only
      function serviceCreateOrUpdate(){
        # _h2 "${FUNCNAME[0]}()"
        echo ">>> ${FUNCNAME[0]}() - ${IDC_service__obj_name}"
    
        local _action=create
        if ObjAction exists service; then
          _action=update
        fi
    
        if ObjAction $_action service; then
          echo "OK $_action service ${IDC_service__obj_name}"
          return 0
        else
          echo "ERROR :/ $_action service ${IDC_service__obj_name}"
          return 1
        fi
      }
    
    
      # ............................................................
      # create a service in Icinga director
      # param   string  filename of check config
      function serviceCreateByCfgFile(){
          # _h2 "${FUNCNAME[0]}($1) - create single service of given file"
          echo ">>>>>> ${FUNCNAME[0]}($1) - create single service of given file"
          _parseCheckConfig "${1}"
          _generateVarsByCheckname "${checkName}"
    
          # create command if it does not exist
          if serviceCreateOrUpdate >/dev/null ; then
            if ! ObjAction exists svclink; then
              if ObjAction create svclink; then
                echo "OK: linked service ${checkName} on host [$MY_NAME] was created"
              else
                echo "ERROR :-/ unable to create linked service ${checkName} on host [$MY_NAME]"
              fi
            else
              echo "SKIP: linked service on host [${IDC_svcathost__obj_name}] exists"
              # TODO, uncomment -- wenn es sinnvolle Features gibt
              # ObjAction update svclink
            fi
          else
            echo "SKIP: service ${checkName} not ready - unable to create a service link."
          fi
      }
    
      # ............................................................
      # create all functions; this functon is called with cli parameter
      # no params
      function servicesCreateAll(){
        _h2 "${FUNCNAME[0]}() - create all services"
    
        # loop over all services and create
        for mycheckfile in $(getChecks)
        do
          serviceCreateByCfgFile "${mycheckfile}" &
        done
        
        # wait until all background processes are done.
        # 1 line in output is the header and one sub process is the ps command --> check > 2 items
        local _iProcesses=$( getChecks | wc -w )
        while [ $_iProcesses -gt 2 ]; do
          echo "Processes: $_iProcesses"
          sleep 2
          _iProcesses=$( ps --ppid "$$" | wc -l ) 
        done
        echo "Done ${FUNCNAME[0]}"
      }
    
    
      # ............................................................
      # cleanup services - delete unneded links
      function svclinkCleanup(){
        _h2 "Cleanup linked service templates"
        tmpRemote=/tmp/remoteLinks_${MY_NAME}.tmp
        tmpLocal=/tmp/localChecks_${MY_NAME}.tmp
    
    
        # --- perpare I: create file with remote service template links
        ObjAction list svclink | grep -v '>>>' >$tmpRemote
    
        # --- perpare II: create file with local configs and object names for its link
        rm -f $tmpLocal 2>/dev/null
        for mycheckfile in $(getChecks)
        do
          _parseCheckConfig "${mycheckfile}"
          _generateVarsByCheckname "${checkName}"
          echo "$mycheckfile:${IDC_svcathost__obj_name}" >>$tmpLocal
        done
    
        # _h3 "local checks"
        # cat $tmpLocal
        # _h3 "remote linked service templates"
        # ObjAction list svclink
    
        # --- Compare ...
        # _h3 "Compare"
        cat $tmpRemote | while read remoteLink
        do
          if grep "$remoteLink" $tmpLocal >/dev/null
          then
            echo "OK: $remoteLink"
          else
            echo "DELETE: link [$remoteLink] is not used by any local check anymore."
            checkName=$(_getName4Svcathost $remoteLink reverse)
            _generateVarsByCheckname "${checkName}"
            ObjAction delete svclink
          fi
        done
        rm -f $tmpLocal $tmpRemote
        echo --- done.
      }
    
    # ----------------------------------------------------------------------
    # functions for Director
    # ----------------------------------------------------------------------
    
      # ............................................................
      # kick the director to deploy config changes now
      function directorDeploy(){
        _h2 deploy
        _initHttp
    
        _wd POST director/config/deploy
        _APIcall POST director/config/deploy
        if [ -z "$(http.isOk)" ]; then
          echo "ERROR deploy config was not queued."
        else
          echo "OK, deploy was triggered"
        fi
      }
    
    # ..................................................................
    #
    # show a help
    function showHelp(){
    script=$(basename $0)
    cat <<ENDOFHELP
    
    HELP:
    
    Host actions
    
      --hc
      --hostcreate
        Create the host [$MY_NAME] in the icinga director
    
      --hr
      --hostread
        Read the host information of [$MY_NAME] in the icinga director
    
      --hu
      --hostupdate
        Update host in the Icinga director
    
      --he
      --hostensure
        Create host if it does not exist otherwise update it in the
        Icinga director
    
      --hd
      --hostdelete
        Delete [$MY_NAME] in the icinga director
    
    
    Check actions
    
      --listchecks
        list all local config files of known checks for [$MY_NAME]
    
      --linkcleanup
        verify added service templates on [$MY_NAME] with locally
        defined checks and remove unneeded items.
    
      --sca
      --servicescreateall
        Loop over defined checks and add all checks to the host.
        See also:
          --listchecks to get a list of config files.
    
      --sc CFGFILE
      --servicecreate CFGFILE
        create service by naming a config file
        See also:
          --listchecks to get a list of config files.
    
    Cache
    
        --flushcache
          remove files in [$dir_data]
    
    Director actions
    
      --deploy
        icinga update (deploy director data)
    
    Other parameters
    
      --cfg CONFIGFILE
        load a costom config file; default: ./inc_getconfig.sh
        This must be the 1st parameter to be processed.
    
      --debug
        enable debug output.
    
      --nodebug
        disable debug output.
    
      --dryrun
        enable dryrun - it shows actions without execution.
    
    
    EXAMPLES
    
      # $script --dryrun --he
      Show actions and api calls for "--he" parameter (create or update host)
    
    ENDOFHELP
    }
    
    # ------------------------------------------------------------
    #
    # MAIN
    #
    # ------------------------------------------------------------
    
    echo
    echo "##### DIRECTOR HELPER v$_version ##### $MY_NAME $MY_IP"
    echo
    
    if [ "$1" = "--cfg" ] && [ -n "$2" ]; then
      echo "INFO: loading custom config [$2]..."
      . "${2}"
      shift 2
    else
      _cfg="$( dirname $0 )/inc_getconfig.sh"
      if [ ! -f "$_cfg"  ]; then
        echo "ERROR: The configuration file $_cfg was not created yet."
        exit 1
      fi
      . "$_cfg"
    fi
    . $(dirname $0)/inc_functions.sh
    . $(dirname $0)/inc/rest-api-client.sh
    
    
    if [ $# -eq 0 ]; then
      showHelp
      exit 0
    fi
    
    cd $(dirname $0) || exit
    ls ./$(basename $0) >/dev/null || exit 1
    
    _initVars
    if [ -z "$MY_NAME" ]; then
      echo "ERROR: hostname is empty. Ensure that the command 'hostname -f' returns a fqdn."
      exit 1
    fi
    
    # ensure that ./inc_getconfig.sh was loaded
    if [ -z "${dir_cfg}" ]; then
      echo ERROR: Client is not installed/ configured yet on this machine.
      exit 1
    fi
    
    while [ $# -gt 0 ];
    do
      case "$1" in
    
        '--help' | '-h' | '-?')
          showHelp
          exit 0
          ;;
    
        '--debug')
          cfg_debug=true
          ;;
    
        '--nodebug')
          cfg_debug=false
          ;;
    
        '--dryrun')
          cfg_dryrun=true
          ;;
        # ----- override local data with those from a file
        '--load')
          if [ ! -f "$2" ]; then
            echo ERROR: file "$2" is not readable.
            echo Hint: ist must be an absolute path or relative to $( pwd )
            exit 1
          fi
          loadfile="$2"
          . "${loadfile}"
          shift
          echo "loaded ${loadfile}"
          ;;
    
        # ----- host actions
    
        '--he' | '--hostensure')
          hostCreateOrUpdate
          ;;
        '--hc' | '--hostcreate')
          hostCreate
          ;;
        '--hr' | '--hostread')
          hostRead
          ;;
        '--hu' | '--hostupdate')
          hostUpdate
          ;;
        '--hd' | '--hostdelete')
          hostDelete
          ;;
        '--hs' | '--hostshow')
          eval jo -p -d. $( _generateJsonForHost )
          ;;
    
        # ----- check actions
    
        '--listchecks')
          getChecks
          ;;
    
        '--sca' | '--servicescreateall')
          servicesCreateAll
          ;;
    
        '--sc' | '--servicecreate')
          serviceCreateByCfgFile "${2}"
          shift
          ;;
    
        '--linkcleanup')
          svclinkCleanup
          shift
          ;;
    
        '--flushcache')
          flushDatadir
          ;;
    
        # ----- director
    
        '--deploy')
          directorDeploy
          exit 0
          ;;
    
        '--testrun')
          _h1 "svclink - without a config"
          ObjAction "create" "svclink" dry
          ObjAction "exists" "svclink" dry
          ObjAction "read"   "svclink" dry
          ObjAction "update" "svclink" dry
          ObjAction "delete" "svclink" dry
    
          _h1 "svclink - with reading a config"
          _parseCheckConfig "/etc/icinga2-passive-client/checks/CPU-usage"
          _generateVarsByCheckname "${checkName}"
    
          ObjAction "create" "svclink" dry
          ObjAction "exists" "svclink" dry
          ObjAction "read"   "svclink" dry
          ObjAction "update" "svclink" dry
          ObjAction "delete" "svclink" dry
    
          _h1 "host"
          ObjAction "create" "host" dry
          ObjAction "exists" "host" dry
          ObjAction "read"   "host" dry
          ObjAction "update" "host" dry
          ObjAction "delete" "host" dry
    
          ;;
    
        # ---- ab hier TODO
        u)
          shift 1
          hostUpdate "$*"
          exit 0
          ;;
        *)
          echo "ERROR: unknown parameter detected. No idea what to do with [$1]."
          echo "Exiting..."
          exit 2
    
      esac
      shift 1
    done
    
    exit 0
    # ======================================================================