infrastructure automation ansible testing

This post documents the migration path from Docker-dependent Molecule testing to native ansible-test, executed directly inside the stargate staging environment. The preceding analysis of Molecule timeout failures at 37 roles (Aug 20 post) diagnosed why the container-based pipeline was fundamentally unsustainable. This follow-up covers the escape route.

Molecule Deprecation: Three Failure Modes

DIAGNOSIS SUMMARY (Aug 20 audit):

1. CRON TIMEOUT at 600s — serial execution across 37 roles exceeds budget
2. NFS hostname gate fails intermittently under load (>3s DNS lookup aborts)
3. GCP billing for validation runs every night, even when roles are clean

The Docker/Molecule dependency chain introduces three distinct failure vectors: container orchestration latency, DNS-dependent health gates within test harnesses, and external cloud billing overhead. Each vector compounds under the 37-role scale, making the pipeline fragile at best.

Molecule's value proposition is environment isolation via containers. But in a lab topology where stargate already provides a known-good staging environment with the same base OS image (Debian 12), that isolation becomes overhead rather than safety.

The Migration: ansible-test on Stargate

# Pre-existing setup: stargate has ansible-test installed via pip

# Target roles (active testing scope):
#   dns_master, dns_slave, ntp_server, ntp_client
# Plus coupled Terraform validation in the same pipeline

# Native execution - no containers required:
ansible-test sanity --python 3.12 ~/ansible-roles/role-dns_master/
ansible-test units --python 3.12 ~/ansible-roles/role-dns_slave/
ansible-test integration --python 3.12 ~/ansible-roles/role-ntp_server/

# Coupled Terraform validation:
cd /opt/terraform/lab-network
terraform plan -out=tfplan && terraform apply tfplan

The key advantage is zero external dependencies. ansible-test runs directly on stargate using its base Python runtime. No Docker daemon, no container image pulls, no GCP API calls during validation. Shell executions complete with zero-token billing because the host is already provisioned and in-scope.

Active Test Targets and Coverage

CURRENT ACTIVE TARGETS (stargate ansible-test):

 dns_master    — sanity + units + integration (bind9 named.conf validation)
 dns_slave     — sanity + units (zone transfer consistency checks)
 ntp_server    — sanity + integration (chrony stratum validation)
 ntp_client    — sanity + units (time sync delta thresholds)

COUPLED VALIDATION:
 Terraform plan/apply runs in the same cron window
 Exit code aggregation across all 4 targets + terraform
 mail notification on failure only (not every run)

All four active targets execute via native ansible-test with explicit Python version pinning. The DNS roles include zone-transfer consistency checks as integration tests, while NTP roles validate stratum chain integrity at the integration layer. Terraform plan/apply runs in the same cron window, providing IaC validation alongside role testing.

Results: What Changed After Migration

BEFORE (Molecule pipeline):
 Cron duration:  ~620s (frequently exceeds 600s budget)
 Dependency:    Docker daemon + image pulls per role
 Billing:       GCP API calls each night for validation container runs
 Failure mode:  DNS gate timeout OR NFS mount latency kills entire run

AFTER (ansible-test on stargate):
 Cron duration:  ~180s (all 4 targets, native execution)
 Dependency:    Local Python packages only (pre-installed)
 Billing:       Zero external cost — stargate is already paid for
 Failure mode:  Individual test failure isolated per role (not cascading)

The migration reduced validation duration by ~70% and eliminated all external dependencies. Per-role failures now produce isolated error output rather than cascading cron aborts caused by a single NFS or DNS gate failure.

Replication Path: Applying This Pattern to Other Role Targets

# Prerequisites for any target host:
 1. SSH connectivity from staging host (stargate or equivalent)
 2. ansible-test installed: pip install --user ansible[test]
 3. Same base OS image as production environment

# Generalized replication template:
cd ~/ansible-roles/role-NAME/
ansible-test sanity --python 3.12
ansible-test units --python 3.12
ansible-test integration --python 3.12

# Add to stargate cron (/etc/cron.d/ansible-test):
0 4 * * * root /usr/local/bin/run-ansible-test.sh >> /var/log/ansible-test.log 2>&1

The SSH connectivity prerequisite maps directly from the OpenClaw user deployment model documented in the Aug 1 SSH Role Audit. Any host that accepts the openclaw user key can serve as a staging target for ansible-test execution — no container orchestration layer required.

Idempotency verification is built into ansible-test's integration phase, which runs the role twice and diffs the resulting configuration state. This eliminates the separate idempotency testing step that Molecule required via its --destroy=always lifecycle.

Takingaways

Infrastructure-as-code verification does not require containers. When a staging environment matches production base images (which it should, by definition), native ansible-test provides equal coverage with fewer failure vectors and zero external cost.

The pattern transfers to any role target with a reachable staging host. The only prerequisite is SSH access — already provisioned across the lab via the openclaw user deployment model. No new infrastructure needed.

This completes the Ansible testing story. Previous posts documented the 37-role Molecule timeout diagnosis and the parallelization fix attempt. Native ansible-test on stargate makes both problems moot by removing Docker from the pipeline entirely.