elway: add mini playbook runner + smoke playbook

`scripts/elway` is a ~600-line Python tool (stdlib + python3-yaml) for
driving one-off ssh commands, ad-hoc file uploads, and YAML playbooks
against a single host. Fills the gap between "single ssh one-liner"
and "reach for Ansible."

Highlights:
  - Three invocation modes: --shell, --upload (LOCAL:REMOTE[:MODE]),
    and --playbook <path>
  - Playbook schema: inline vars, list of steps, optional verify block.
    Template via {{ var }}; CLI --var overrides inline defaults
  - stop_on_fail global (default on), per-step override. Verify phase
    always runs, even after a halt — you see end-state regardless
  - Sudo handled once: probes NOPASSWD; if not, prompts locally via
    getpass, validates up-front, then feeds via `sudo -S` per step.
    Password never written to disk/logs. Upload-with-sudo stages to
    /tmp then sudo-mv + sudo-chmod
  - SSH connection reuse via ControlMaster (60s persist) keeps
    multi-step playbooks responsive (~30ms/step reuse vs ~550ms cold)
  - Live interleaved stdout/stderr with per-step prefix and colored
    pass/fail summary. --dry-run prints the plan without executing
  - Shebang pinned to /usr/bin/python3 to bypass venv-shadowing
    when python3-yaml lives in the system site-packages

Smoke test (playbooks/elway-smoke.yaml) covers vars + upload + verify;
drove out a YAML-scalar-coercion bug before first commit (`shell: false`
parsed to Python bool, crashed the templater — now coerced to string
at load time with a clear error on nulls).
This commit is contained in:
vh
2026-04-24 10:09:16 -07:00
parent 04884742e2
commit dea95bf526
2 changed files with 653 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
# elway's own smoke-test playbook. Exercises: vars (inline + CLI override),
# multi-step flow, upload with mode, stop-on-error semantics, verify phase.
# Target: any Linux host reachable over ssh that has /tmp and curl.
vars:
scratch_dir: /tmp/elway-smoke
greeting: hello from elway
steps:
- name: Clean any prior scratch dir
shell: rm -rf {{ scratch_dir }}
- name: Create scratch dir
shell: mkdir -p {{ scratch_dir }}
- name: Drop a greeting file
shell: echo "{{ greeting }}" > {{ scratch_dir }}/greeting.txt
- name: Upload this playbook into the scratch dir
upload:
src: playbooks/elway-smoke.yaml
dest: "{{ scratch_dir }}/uploaded.yaml"
mode: "0644"
verify:
- name: Greeting file has the expected content
shell: grep -q "{{ greeting }}" {{ scratch_dir }}/greeting.txt
- name: Uploaded file is a non-empty yaml
shell: test -s {{ scratch_dir }}/uploaded.yaml && head -1 {{ scratch_dir }}/uploaded.yaml
- name: Scratch dir exists and is listable
shell: ls -la {{ scratch_dir }}