#!/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