From c93c97a0de61d6475ad403c6768a4accb4207c68 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Sun, 7 Jun 2026 20:39:57 -0600 Subject: [PATCH] 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. --- scripts/esxi-ssh.sh | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100755 scripts/esxi-ssh.sh diff --git a/scripts/esxi-ssh.sh b/scripts/esxi-ssh.sh new file mode 100755 index 0000000..e6072df --- /dev/null +++ b/scripts/esxi-ssh.sh @@ -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