I am building Openstack Servers with the ansible os_server module. One of these fields will accept a very long string (userdata). Typically, I end up with a giant blob of unreadable build script in this field…
Today I learned that I can use this:
---
- name: "Create Server"
os_server:
name: "{{ item.value.name }}"
state: present
availability_zone: "{{ item.value.az.name }}"
flavor: "{{ item.value.flavor }}"
key_name: "{{ item.value.az.keypair }}"
nics: "[{%- for nw in item.value.ports -%}{'port-name': '{{ ProjectPrefix }}{{ item.value.name }}-Port-{{nw.network.name}}'}{%- if not loop.last -%}, {%- endif -%} {%- endfor -%}]" # Ignore this line - it's complicated for a reason
boot_volume: "{{ ProjectPrefix }}{{ item.value.name }}-OS-Volume" # Ignore this line also :)
terminate_volume: yes
volumes: "{%- if item.value.log_size is defined -%}[{{ ProjectPrefix }}{{ item.value.name }}-Log-Volume]{%- else -%}{{ omit }}{%- endif -%}"
userdata: "{% include 'templates/userdata.j2' %}"
auto_ip: no
timeout: 65535
cloud: "{{ cloud }}"
with_dict: "{{ Servers }}"
This file (/path/to/ansible/playbooks/servers.yml) is referenced by my play.yml (/path/to/ansible/play.yml) via an include, so the template reference there is in my templates directory (/path/to/ansible/templates/userdata.j2).
That template can also then reference other template files itself (using {% include 'templates/some_other_file.extension' %}
) so you can have nicely complex userdata fields with loads and loads of detail, and not make the actual play complicated (or at least, no more than it already needs to be!)