Ansible - MAAS Management
Refreshed June 2026: when I wrote this, there was no first-class Ansible integration for MAAS, so I templated inventory out of the
maasCLI by hand. Canonical now publishes an officialmaas.maascollection with real modules, which is the way to do this today. I have led with that and kept the original homegrown templates below for reference, inlined so they do not disappear with the old gists.
Background
I was working with MAAS and wanted to automate both the deployment and the ongoing management of machines, in my case KVM VMs. The deployment side is covered by my ansible-maas role. For management, the original approach pulled machine state from the maas CLI and templated it into inventory and vars files. That worked, but it was a lot of Jinja to maintain.
The Modern Way: the maas.maas Collection
Canonical maintains an official collection with modules for machines, instances, and more. Install it from Galaxy:
ansible-galaxy collection install maas.maas
With it, querying and managing machines is a module call instead of a CLI scrape. For example, read the current machines and act on them:
---
- hosts: localhost
connection: local
gather_facts: false
vars:
maas_url: http://maas.example.internal:5240/MAAS
maas_api_key: "{{ vault_maas_api_key }}"
tasks:
- name: Get all machines from MAAS
maas.maas.machine_info:
cluster_instance:
host: "{{ maas_url }}"
token_key: "{{ maas_api_key.split(':')[1] }}"
token_secret: "{{ maas_api_key.split(':')[2] }}"
customer_key: "{{ maas_api_key.split(':')[0] }}"
register: maas_machines
- name: Show machines that are ready to deploy
ansible.builtin.debug:
msg: "{{ maas_machines.records | selectattr('status_name', 'equalto', 'Ready') | map(attribute='fqdn') | list }}"
The collection also provides a dynamic inventory and modules to commission, deploy, and release machines, which is exactly the lifecycle the homegrown templates below were reaching for. Check the collection docs for the current module list, since it is actively developed.
The Original Homegrown Approach (For Reference)
Before the collection existed, I generated inventory and vars from the MAAS CLI output. These are kept here for anyone maintaining the old setup.
The inventory template, which split machines into provisioned and non-provisioned groups:
[maas_non_provisioned]
{% for host in (maas_machines['stdout'] | from_json) %}
{% if groups['maas_deployed_machines'] is defined %}
{% if host['fqdn'] not in groups['maas_deployed_machines'] %}
{{ host['fqdn'] }}
{% endif %}
{% else %}
{{ host['fqdn'] }}
{% endif %}
{% endfor %}
The vars template, which captured machine state into lists by status (broken, commissioning, deployed, failed, new, and so on):
---
maas_login_url: '{{ maas_login_url }}'
maas_login_user: '{{ maas_login_user }}'
maas_deployed_machines:
{% for host in groups['maas_deployed_machines'] | default([]) %}
- '{{ host }}'
{% endfor %}
maas_new_machines:
{% for host in groups['maas_new_machines'] | default([]) %}
- '{{ host }}'
{% endfor %}
The original management playbook captured the KVM VMs and their MAC addresses, then drove MAAS from that. If you want the full thing, the historical versions are in the original gists (inventory template, vars template, management playbook). If you are starting fresh, reach for the maas.maas collection instead and skip the templating entirely.
Conclusion
The goal was always to keep MAAS and Ansible in step. In 2017 that meant scraping the CLI. Today the official maas.maas collection does it with proper modules, so most of the Jinja below is now history worth keeping but not worth rebuilding.
Enjoy!
Comments