Add on-demand ESXi SSH toggle script

Toggles the TSM-SSH service via the vSphere API (govc + .env creds) with
on/off/status/shell subcommands. The shell subcommand restores the prior
service state on exit so it leaves the host as it found it.
This commit is contained in:
Ryan Malloy 2026-06-07 20:39:57 -06:00
parent 0e7942f510
commit c93c97a0de

68
scripts/esxi-ssh.sh Executable file
View File

@ -0,0 +1,68 @@
#!/usr/bin/env bash
# esxi-ssh.sh — on-demand ESXi SSH toggle via the vSphere API (govc + .env creds)
#
# The API account in .env (ESXI_USER, e.g. "claude") can toggle the TSM-SSH
# service but has no interactive host shell, so the `shell` subcommand logs in
# as root by default. Override the shell login with ESXI_SSH_USER.
#
# Usage:
# ./esxi-ssh.sh status # show current TSM-SSH state
# ./esxi-ssh.sh on # enable + start SSH (persists across reboot)
# ./esxi-ssh.sh off # stop + disable SSH (secure default)
# ./esxi-ssh.sh shell [cmd...] # start SSH, log in (root), restore prior state on exit
#
# Env overrides: ENV_FILE (default ../.env), ESXI_SSH_USER (default root)
set -euo pipefail
ENV_FILE="${ENV_FILE:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/.env}"
[[ -r "$ENV_FILE" ]] || { echo "esxi-ssh: env file not readable: $ENV_FILE" >&2; exit 1; }
getenv() { grep -E "^$1=" "$ENV_FILE" | head -1 | cut -d= -f2-; }
HOST="$(getenv ESXI_HOST)"
export GOVC_URL="https://${HOST}"
export GOVC_USERNAME="$(getenv ESXI_USER)"
export GOVC_PASSWORD="$(getenv ESXI_PASS)"
export GOVC_INSECURE=1
SSH_USER="${ESXI_SSH_USER:-root}"
# Prints the TSM-SSH row's "policy status" (e.g. "off Running" / "on Stopped")
ssh_state() { govc host.service.ls 2>/dev/null | awk '/^TSM-SSH[[:space:]]/{print $2, $3}'; }
status() { govc host.service.ls | awk 'NR==1 || /^TSM-SSH[[:space:]]/'; }
on() {
govc host.service enable TSM-SSH >/dev/null 2>&1 || true
govc host.service start TSM-SSH >/dev/null 2>&1 || true
echo "esxi-ssh: SSH enabled on ${HOST}"
status
}
off() {
govc host.service stop TSM-SSH >/dev/null 2>&1 || true
govc host.service disable TSM-SSH >/dev/null 2>&1 || true
echo "esxi-ssh: SSH disabled on ${HOST}"
status
}
shell() {
read -r _ prev_status < <(ssh_state)
echo "esxi-ssh: prior TSM-SSH status=${prev_status:-unknown}"
govc host.service start TSM-SSH >/dev/null 2>&1 || true
# Leave it as we found it: only stop SSH on exit if it was NOT already running
if [[ "${prev_status:-}" != "Running" ]]; then
trap 'echo "esxi-ssh: restoring SSH to stopped"; govc host.service stop TSM-SSH >/dev/null 2>&1 || true' EXIT
fi
echo "esxi-ssh: connecting as ${SSH_USER}@${HOST} ..."
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "${SSH_USER}@${HOST}" "$@"
}
case "${1:-status}" in
on) on ;;
off) off ;;
status) status ;;
shell) shift; shell "$@" ;;
*) echo "usage: $(basename "$0") {on|off|status|shell [cmd...]}" >&2; exit 1 ;;
esac