docs: split architecture (host + ansible), TTY menu, web UI
This commit is contained in:
@@ -69,47 +69,96 @@ README.md # This file
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Ansible Control Node — QEMU-Bootable (Alpine Linux)
|
## Ansible Control Node — Split Architecture
|
||||||
|
|
||||||
A minimal, portable Ansible control node that boots on QEMU `pc-q35-10.0`.
|
Two independent artifacts. The QEMU VM provides Docker; the Ansible container
|
||||||
Designed to run on Windows hosts, providing Ansible connectivity to Windows,
|
runs the tests. Same container image runs on Docker Swarm or Kubernetes without
|
||||||
Cisco, VMware, MSSQL, and Linux targets. No systemd — OpenRC + BusyBox.
|
the VM layer.
|
||||||
|
|
||||||
|
### The Two Artifacts
|
||||||
|
|
||||||
|
| Artifact | Defined by | Built with | Result |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Alpine Docker Host** | `Dockerfile.alpine-host` | `./scripts/build-qemu.sh` | `output/ansible-node.qcow2` (~470MB) |
|
||||||
|
| **Ansible Control Node** | `Dockerfile.ansible` | `./scripts/build-ansible.sh` | `ansible-node` Docker image (~793MB) |
|
||||||
|
|
||||||
### Build & Launch
|
### Build & Launch
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Prerequisites: Docker, QEMU (qemu-full), passwordless sudo for mount
|
# Prerequisites: Docker, QEMU (qemu-full), passwordless sudo for mount
|
||||||
./scripts/build-qemu.sh # Dockerfile → qcow2 disk (2GB)
|
|
||||||
./scripts/run-qemu.sh # Boot VM (KVM, 1GB RAM, 2 vCPUs)
|
|
||||||
|
|
||||||
# Access the VM (password: ansible)
|
# 1. Build the VM disk
|
||||||
sshpass -p ansible ssh -p 2222 ansible@localhost
|
./scripts/build-qemu.sh # Alpine + Docker + SSH → qcow2
|
||||||
|
|
||||||
|
# 2. Build the Ansible image
|
||||||
|
./scripts/build-ansible.sh # Ansible + 10 collections → Docker image
|
||||||
|
# Or push to a registry:
|
||||||
|
REGISTRY=my-registry ./scripts/build-ansible.sh --push
|
||||||
|
|
||||||
|
# 3. Boot the VM
|
||||||
|
./scripts/run-qemu.sh # QEMU pc-q35-10.0, KVM, 1GB, 2 vCPUs
|
||||||
```
|
```
|
||||||
|
|
||||||
### Architecture
|
### How the User Interacts
|
||||||
|
|
||||||
```
|
```
|
||||||
Dockerfile # Complete rootfs definition
|
QEMU VM boots in ~6 seconds
|
||||||
│
|
│
|
||||||
▼
|
├── ttyS0 (serial console) ──► auto-menu driven
|
||||||
scripts/build-qemu.sh # Docker export → ext4 → qcow2
|
│ ╔══════════════════════════════════════╗
|
||||||
|
│ ║ 1) Run all tests ║
|
||||||
|
│ ║ 2) Run FR1 — Auth ║
|
||||||
|
│ ║ 3) Run FR2 — Use Control ║
|
||||||
|
│ ║ 4) Run FR5 — Data Flow ║
|
||||||
|
│ ║ 5) Download reports (tar.gz) ║
|
||||||
|
│ ║ 6) View latest report ║
|
||||||
|
│ ║ 7) Shell (Ansible container) ║
|
||||||
|
│ ║ 8) Shell (Docker host) ║
|
||||||
|
│ ║ 0) Shutdown ║
|
||||||
|
│ ╚══════════════════════════════════════╝
|
||||||
│
|
│
|
||||||
├── output/ansible-node.qcow2 (bootable disk, ext4)
|
├── :8080 ──► Web UI (browser-based dashboard)
|
||||||
├── output/vmlinuz-virt (kernel, direct -kernel boot)
|
│ • Run buttons for each playbook
|
||||||
└── output/initramfs-virt (initramfs)
|
│ • Output streaming
|
||||||
|
│ • Report downloads (JSON)
|
||||||
│
|
│
|
||||||
▼
|
└── :22 ──► SSH (ansible / ansible)
|
||||||
scripts/run-qemu.sh # QEMU pc-q35-10.0, KVM, virtio
|
```
|
||||||
│
|
|
||||||
▼
|
Every option in the menu and every button in the web UI runs:
|
||||||
┌─────────────────────────────────────────────┐
|
```bash
|
||||||
│ Alpine Linux 3.20 | Kernel 6.6 (virt) │
|
docker run --rm -it \
|
||||||
│ OpenRC | BusyBox | no systemd │
|
-v /ansible/playbooks:/ansible/playbooks:ro \
|
||||||
│ Console: ttyS0 xterm-256color │
|
-v /ansible/reports:/ansible/reports \
|
||||||
│ Keyboard: PS/2 atkbd │
|
-v /ansible/inventory:/ansible/inventory:ro \
|
||||||
│ Docker 26.1 daemon (running) │
|
ansible-node site.yml
|
||||||
│ SSH: ansible@<ip> (password: ansible) │
|
```
|
||||||
└─────────────────────────────────────────────┘
|
|
||||||
|
### Architecture Diagram
|
||||||
|
|
||||||
|
```
|
||||||
|
Dockerfile.alpine-host Dockerfile.ansible
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
┌─────────────────────┐ ┌─────────────────────┐
|
||||||
|
│ Alpine 3.20 │ │ Alpine 3.20 │
|
||||||
|
│ Docker 26.1 daemon │ │ Ansible 2.17 │
|
||||||
|
│ OpenRC (no systemd) │ │ 10 collections │
|
||||||
|
│ tty-menu.sh │ │ pywinrm, pyvmomi, │
|
||||||
|
│ webui.py (:8080) │ │ pymssql, paramiko, │
|
||||||
|
│ sshd (:22) │ │ netmiko, ncclient │
|
||||||
|
│ ~470MB qcow2 │ │ ~793MB Docker image │
|
||||||
|
└─────────────────────┘ └─────────────────────┘
|
||||||
|
│ │
|
||||||
|
│ docker run ansible-node │
|
||||||
|
└───────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────┼───────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌────────┐ ┌──────────┐ ┌─────────┐
|
||||||
|
│Windows │ │ Cisco │ │ VMware │
|
||||||
|
│ WinRM │ │ SSH/CLI │ │ SOAP │
|
||||||
|
└────────┘ └──────────┘ └─────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
### Target Integrations
|
### Target Integrations
|
||||||
@@ -124,15 +173,25 @@ scripts/run-qemu.sh # QEMU pc-q35-10.0, KVM, virtio
|
|||||||
| **MSSQL** | `microsoft.ad` 1.5 | TDS | `pymssql` 2.3 |
|
| **MSSQL** | `microsoft.ad` 1.5 | TDS | `pymssql` 2.3 |
|
||||||
| **Linux** | built-in SSH | SSH | — |
|
| **Linux** | built-in SSH | SSH | — |
|
||||||
|
|
||||||
|
### Deployment Targets for the Ansible Image
|
||||||
|
|
||||||
|
| Environment | How |
|
||||||
|
|---|---|
|
||||||
|
| **QEMU VM on Windows** | `docker run ansible-node` inside the Alpine Docker Host |
|
||||||
|
| **Docker Swarm** | `docker stack deploy` the `ansible-node` image directly |
|
||||||
|
| **Kubernetes** | `kubectl run` a Job or Pod with the `ansible-node` image |
|
||||||
|
|
||||||
### Key Design Decisions
|
### Key Design Decisions
|
||||||
|
|
||||||
| Decision | Rationale |
|
| Decision | Rationale |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Dockerfile as build system | Dependency resolution, layer caching. Same file usable as `docker run` or QEMU boot |
|
| Split: host vs. container | VM provides Docker; Ansible runs in a container. Same image on Swarm/K8s |
|
||||||
| `root=/dev/vda` (not LABEL) | Alpine's `nlplug-findfs` can't resolve labels on virtio-block; device path works |
|
| Dockerfile as build system | Dependency resolution, layer caching. Dockerfile → `docker export` → qcow2 |
|
||||||
|
| `root=/dev/vda` (not LABEL) | Alpine's `nlplug-findfs` can't resolve labels on virtio-block |
|
||||||
| `modules=virtio_blk,ext4` on cmdline | `CONFIG_VIRTIO_BLK=m` — module not auto-detected by initramfs |
|
| `modules=virtio_blk,ext4` on cmdline | `CONFIG_VIRTIO_BLK=m` — module not auto-detected by initramfs |
|
||||||
| No `apk del` purge step | Purging `util-linux-dev` cascades to removing `mount`, `umount`, `blkid` |
|
| TTY menu via `agetty -l` | Auto-launches menu instead of login prompt on serial console |
|
||||||
| Direct `-kernel` boot (no extlinux) | QEMU loads kernel/initrd directly; no bootloader needed in the disk image |
|
| Web UI: Python stdlib only | Zero dependencies; `http.server` + inline HTML + async JS |
|
||||||
|
| Direct `-kernel` boot (no extlinux) | QEMU loads kernel/initrd directly; no bootloader in disk image |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -540,6 +599,55 @@ A hand-crafted example JSON report for testing the renderers without running
|
|||||||
Ansible. Contains 15 results (10 passed, 4 failed, 1 review) across FR1 and FR2.
|
Ansible. Contains 15 results (10 passed, 4 failed, 1 review) across FR1 and FR2.
|
||||||
Useful for CI validation of the report rendering pipeline.
|
Useful for CI validation of the report rendering pipeline.
|
||||||
|
|
||||||
|
### `Dockerfile.alpine-host`
|
||||||
|
|
||||||
|
Alpine Linux 3.20 with Docker daemon, SSH, TTY menu, and web UI. Used as the
|
||||||
|
blueprint for the QEMU-bootable VM disk. Built via `scripts/build-qemu.sh`.
|
||||||
|
Installs: `alpine-base`, `linux-virt`, `docker`, `openssh-server`, `python3`.
|
||||||
|
Provides: serial console menu (`scripts/tty-menu.sh`) and web UI (`webui/app.py`).
|
||||||
|
|
||||||
|
### `Dockerfile.ansible`
|
||||||
|
|
||||||
|
Ansible control node container image. Installs `ansible` + `sshpass` + 10
|
||||||
|
Ansible collections + Python packages for Windows (pywinrm), Cisco (paramiko,
|
||||||
|
netmiko, ncclient), VMware (pyvmomi), and MSSQL (pymssql). Built via
|
||||||
|
`scripts/build-ansible.sh`. Deployable on Docker Swarm, Kubernetes, or inside
|
||||||
|
the Alpine Docker Host VM.
|
||||||
|
|
||||||
|
### `scripts/build-qemu.sh`
|
||||||
|
|
||||||
|
Converts `Dockerfile.alpine-host` into a bootable QEMU disk. Steps: Docker build
|
||||||
|
→ export rootfs → extract kernel + initramfs → create ext4 disk → convert to
|
||||||
|
qcow2. Outputs: `output/ansible-node.qcow2`, `output/vmlinuz-virt`,
|
||||||
|
`output/initramfs-virt`.
|
||||||
|
|
||||||
|
### `scripts/build-ansible.sh`
|
||||||
|
|
||||||
|
Builds the `ansible-node` Docker image from `Dockerfile.ansible`. Reports the
|
||||||
|
image size and layers. With `--push` and `REGISTRY` set, pushes to a container
|
||||||
|
registry for deployment.
|
||||||
|
|
||||||
|
### `scripts/run-qemu.sh`
|
||||||
|
|
||||||
|
Launches the Alpine Docker Host VM on QEMU `pc-q35-10.0`. Uses direct kernel
|
||||||
|
boot (`-kernel` / `-initrd`), virtio devices, user-mode networking with port
|
||||||
|
forwards (SSH on `:2222`, web UI on `:8090`). Supports `--gui`, `--vnc`, and
|
||||||
|
`--debug` modes.
|
||||||
|
|
||||||
|
### `scripts/tty-menu.sh`
|
||||||
|
|
||||||
|
Serial console menu script. Launched automatically by `agetty -l` on `ttyS0`.
|
||||||
|
Options: run individual playbooks, view reports, shell into the Ansible
|
||||||
|
container, shell into the Docker host, shutdown VM. All test options run
|
||||||
|
`docker run ansible-node` with shared volumes.
|
||||||
|
|
||||||
|
### `webui/app.py`
|
||||||
|
|
||||||
|
Minimal web dashboard (Python 3 stdlib only, zero dependencies). Serves on
|
||||||
|
port 8080. Features: dark-themed UI with run buttons per playbook, async output
|
||||||
|
streaming via `fetch`, JSON report downloads. Handles `POST /api/run` to execute
|
||||||
|
playbooks via `docker run` and `GET /reports/<name>` for file downloads.
|
||||||
|
|
||||||
### `inventory.ini`
|
### `inventory.ini`
|
||||||
|
|
||||||
Standard Ansible inventory. Structure:
|
Standard Ansible inventory. Structure:
|
||||||
|
|||||||
Reference in New Issue
Block a user