test(molecule): #75 review follow-ups, and a host-wide lock on the su… #154
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: Molecule | |
| # Containerised converge + idempotence + verify for the decdn_node role. | |
| # Heavy (privileged systemd Docker container) — scoped to ansible/ changes and | |
| # blocking. Mark it a required status check in branch protection once proven. | |
| # This file is in `paths` alongside ansible/ so a change to the job itself (its cache | |
| # wiring, JOBS, the timeout) is exercised by the PR that makes it. cloud-init/ is in | |
| # `paths` because the `cloud-init` scenario boots cloud-init/user-data.yaml and runs | |
| # cloud-init/bootstrap.sh. | |
| on: | |
| pull_request: | |
| paths: ['ansible/**', 'cloud-init/**', '.github/workflows/molecule.yml'] | |
| push: | |
| branches: [main] | |
| paths: ['ansible/**', 'cloud-init/**', '.github/workflows/molecule.yml'] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: molecule-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| molecule: | |
| runs-on: ubuntu-latest # Docker is preinstalled | |
| # ~4m41s at JOBS=3 with 8 scenarios. os-matrix (3 containers) and lifecycle took the | |
| # suite to ~10m at JOBS=3 on a local 16-thread box; re-measure from CI's first run. | |
| # A bound, not a target: without one a wedged privileged systemd container burns | |
| # the 360-minute default, and with cancel-in-progress above, some branch-protection | |
| # setups read the resulting cancelled check as "not failed" rather than as a failure. | |
| timeout-minutes: 45 | |
| defaults: | |
| run: | |
| working-directory: ansible | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| # Keyed on this workflow file: no pip manifest exists, and the workflow is | |
| # where the package list lives. ci.yml's ansible-lint job has the full note. | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.12' | |
| cache: pip | |
| cache-dependency-path: .github/workflows/molecule.yml | |
| - name: Install molecule + Ansible | |
| run: | | |
| python -m pip install --upgrade \ | |
| molecule "molecule-plugins[docker]" ansible ansible-lint docker | |
| # Same key and same rationale as ci.yml's jobs (see ansible-lint there): a warm | |
| # tree makes the install a no-op that never contacts galaxy.ansible.com, and the | |
| # save is gated so a part-way Galaxy failure cannot poison the cache. The key is | |
| # derived wholly from ansible/requirements.yml, so it cannot drift from ci.yml's | |
| # copy the way a duplicated env var would. It wraps | |
| # `make molecule` because the deps install is owned by the Make target here, not | |
| # by a step of its own. | |
| - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| id: galaxy-cache | |
| with: | |
| path: ansible/collections | |
| key: galaxy-${{ runner.os }}-${{ hashFiles('ansible/requirements.yml') }} | |
| - name: molecule test | |
| # `make molecule` runs every scenario under ansible/molecule/ and fans them out | |
| # in parallel; ansible/Makefile documents the set and the fail-loud guards. | |
| # | |
| # There is deliberately no separate `make deps` step: the molecule targets take | |
| # `deps` as a prerequisite, so a standalone one would resolve and install the | |
| # Galaxy requirements a second time every run — a second chance to trip over a | |
| # flaky galaxy.ansible.com, for no added coverage. The cache above wraps that | |
| # Make-owned invocation instead. | |
| # | |
| # JOBS is capped at 3 rather than the default (one job per scenario): every | |
| # scenario is a privileged systemd container, and they share this | |
| # runner's cores and cgroup hierarchy. If this job turns flaky, drop to JOBS=1 | |
| # or swap in `make molecule-serial` — the latter also serialises the output. | |
| run: make molecule JOBS=3 | |
| # A step `if:` without a status-check function implies success(), so this is | |
| # skipped when anything above failed — including a genuinely failing scenario, | |
| # which leaves the cache cold for that run. Conservative on purpose: it is the | |
| # same guard that keeps a part-way Galaxy install out of the cache. | |
| - uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| if: steps.galaxy-cache.outputs.cache-hit != 'true' | |
| with: | |
| path: ansible/collections | |
| key: galaxy-${{ runner.os }}-${{ hashFiles('ansible/requirements.yml') }} |