I have a CI process that builds VM images in layers (much like container images are composed of layers).
Each layer is built by creating a snapshot of the parent VM image, creating a new VM from that snapshot, running a playbook against the new VM, and then shutting it down to serve as the base image for the next layer.
Right now, that looks something like:
---
- hosts: all
tasks:
- name: step 1 of VM setup
delegate_to: '{{ vm_server }}'
- name: step 2 of VM setup
delegate_to: '{{ vm_server }}'
- name: run template playbook
import_playbook: site.yml
- hosts: all
tasks:
- name: shutdown new template VM
delegate_to: '{{ vm_server }}'
That playbook is really gross, primarily because when I run it, I limit the run to the new VM, which doesn’t exist yet, which requires some fiddling with dynamic inventory to pretend that it exists before the play begins.
As I see it, I have two directions out of this hole.
First, I could just split this into two playbooks that do the infra setup and tear-down, and change the CI definition to call those and the site.yml individually. That seems idiomatic, but it also makes my CI script 3x larger.
Alternatively, I could change the “run template playbook” step to a command, and invoke ansible-playbook from the ansible playbook. That doesn’t require any changes to the CI definition, and it gets rid of my dynamic inventory problem, but then the inner run of ansible-playbook doesn’t inherit tags or check mode from the outer invocation.
The first option seems obviously better, except that I end up spreading more complexity across two different git repos when I’d rather keep it in just one.
Does anyone have suggestions for a more idiomatic approach, or anything else I should be considering?