Skip to content

ESXi Shell Task Authoring

ESXi Shell Overview

  • ESXi runs BusyBox shell, NOT bash
  • Always use #!/usr/bin/env sh shebang
  • No prelude template available — error handling must be inlined
  • Limited tool availability compared to full Linux
  • Two execution models: native (on ESXi) vs context (remote from Linux host)

Shell Constraints

  • Use POSIX [ ] test syntax preferred (though modern BusyBox supports [[ ]])
  • No bash-specific features: arrays, associative arrays, process substitution
  • Available core tools: grep, awk, sed, cut, sort, uniq, printf, echo, mkdir, mount, cp, chmod, rm
  • ESXi-specific tools: esxcli, localcli, openssl, /sbin/chkconfig, /bin/services.sh
  • No package manager — tools are what's on the ESXi image
  • python3 available on ESXi 7.x and newer

Error Handling

Since there's no prelude, define xiterr() inline at the top of every ESXi task:

Bash
xiterr() { [[ "$1" =~ ^[0-9]+$ ]] && { XIT=$1; shift; } || XIT=1; printf "FATAL: $*\n"; exit $XIT; }
  • Use set -e for basic error trapping
  • Always use explicit exit 0 on success, exit 1 on failure
  • Check command results:
Bash
STATE=$(localcli system maintenanceMode get)
[[ "$STATE" == "Enabled" ]] && xiterr 1 "System still in maintenance mode"

ESXi Management Commands

  • User management: esxcli system account add/set/remove
  • Permissions: esxcli system permission set/remove
  • Maintenance mode: localcli system maintenanceMode set --enable true/false, localcli system maintenanceMode get
  • Networking:
    • vSwitches: localcli network vswitch standard add/remove/uplink
    • Port groups: localcli network vswitch standard portgroup add/remove
    • IP config: localcli network ip interface add, localcli network ip interface ipv4 set
  • Firewall: localcli network firewall ruleset set --enabled true --ruleset-id=name
  • NTP: esxcli system ntp set/get (ESXi 7.x+)
  • Services: /sbin/chkconfig name on/off, /etc/init.d/name start/stop/restart, /bin/services.sh restart
  • System info: esxcli system version get, esxcli system hostname get

File System Paths

  • /tmp/ — Temporary files (cleared on reboot)
  • /opt/rackn/ — Persistent RackN configuration
  • /etc/vmware/ — VMware system configuration
  • /etc/vmware/ssl/ — TLS certificates (rui.crt, rui.key)
  • /etc/ntp.conf — NTP configuration (ESXi 6.x)
  • No standard $HOME — use explicit paths

Context vs Native Execution

Native Tasks

Native tasks run directly ON the ESXi host:

  • Use #!/usr/bin/env sh (BusyBox)
  • No prelude template
  • Direct access to esxcli, localcli
  • Examples: esxi-set-ntp, esxi-manage-users, esxi-exit-maint-mode

Context Tasks

Context tasks run on a Linux host and manage ESXi remotely:

  • Use #!/usr/bin/env bash with {{ template "prelude.tmpl" . }}
  • Access ESXi via SSH/SCP (sshpass + scp) or vSphere API (Python)
  • Task names often prefixed with esxi-no-vib-*
  • Examples: esxi-no-vib-enable-ssh (Python vSphere API), esxi-no-vib-place-config-on-host (SCP)
  • Run in the esxi-agent-runner Docker context (includes govc, pyvmomi, PowerCLI, drpcli)

Using Python on ESXi

python3 is available on ESXi 7.x+. Common pattern: render a Python helper template to /tmp/, then call from sh:

YAML
Templates:
  - Name: "esxi-params.py"
    Path: "/tmp/esxi-params.py"
    ID: "esxi-params.py.tmpl"
  - Name: "my-esxi-task.sh"
    Contents: |
      #!/usr/bin/env sh
      xiterr() { [[ "$1" =~ ^[0-9]+$ ]] && { XIT=$1; shift; } || XIT=1; printf "FATAL: $*\n"; exit $XIT; }
      set -e
      python3 /tmp/esxi-params.py get 'my/param'

Complete Example

YAML
---
Name: "example-esxi-configure"
Description: "Configure an ESXi host setting"
Documentation: |
  Demonstrates a native ESXi task that checks and sets
  maintenance mode status. Uses inline error handling
  since no prelude is available on ESXi.
OptionalParams:
  - rs-debug-enable
Meta:
  icon: "server"
  color: "yellow"
  title: "VMware Content"
  feature-flags: "sane-exit-codes"
Templates:
  - Name: "esxi-params.py"
    Path: "/tmp/esxi-params.py"
    ID: "esxi-params.py.tmpl"
  - Name: "example-esxi-configure.sh"
    Contents: |
      #!/usr/bin/env sh
      # Example ESXi native task

      xiterr() { [[ "$1" =~ ^[0-9]+$ ]] && { XIT=$1; shift; } || XIT=1; printf "FATAL: $*\n"; exit $XIT; }

      {{ if eq (.Param "rs-debug-enable") true }}set -x{{ end }}
      set -e

      # Check current maintenance mode state
      STATE=$(localcli system maintenanceMode get)
      echo "Current maintenance mode: $STATE"

      if [ "$STATE" = "Disabled" ]; then
          echo "Host is not in maintenance mode - no action needed"
          exit 0
      fi

      # Exit maintenance mode
      localcli system maintenanceMode set --enable false
      NEW_STATE=$(localcli system maintenanceMode get)
      [ "$NEW_STATE" = "Disabled" ] || xiterr 1 "Failed to exit maintenance mode"

      # Update DRP parameter
      python3 /tmp/esxi-params.py delete 'esxi/maintenance-mode'

      echo "Successfully exited maintenance mode"
      exit 0