CloudFormation is the corner stone to provision infrastructure in AWS with code, however it’s not very DRY, ie. poor modularization, almost static variables and templates. So here comes Ansible.
However at the moment Ansible’s CloudFormation module doesn’t support Jinja2 in templates, like other modules do. Luckily there’s a work-around to get the Ansible-CloudFormation-Jinja2 trio working together.
A simple CloudFormation snippet with Jinja2 variable:
# roles/test-stack/templates/mycf.yaml.j2
...
Parameters:
VpcId:
Type: String
Default: '{{ template_params.vpc_id }}'
...
I don’t put Jinja2 variable directly to replace the !Ref
intrinsic function, because I think this is a softer approach so if there’s any parameter verification in the template it still works.
Then the template can be loaded to Ansible’s cloudformation
module like this:
# roles/test-stack/tasks/main.yaml
- name: create a stack
cloudformation:
stack_name: '{{ stack_names.test_stack }}'
state: present
template_body: "{{ lookup('template', 'templates/mycf.yaml.j2') }}"
tags: '{{ template_tags }}'
...
The inventory may look like this:
# inventory/local
all:
hosts:
dev:
ansible_connection: local
gather_facts: false
All parameters can go into the global variable file group_vars/all
or host variable file host_vars/dev
so later I can create a set of parameters for production.
# group_vars/all
stack_names:
test_stack: test1
...
# host_vars/dev
template_params:
vpc_id: vpc-xxxxxxxxxxxxxxx
template_tags:
app_env: dev
And the playbook can be simple as:
# deploy.yaml
- name: deploy stacks
hosts: dev
tags: dev
roles:
- test-stack
Finally, this CloudFormation stack can be deployed by running:
$ ansible-playbook -i inventory/local deploy.yaml --tags dev
🙂