Ansible is a powerful automation tool that simplifies the management of IT infrastructure. One of its strengths is the ability to work with dynamic inventories, which allow Ansible to discover and manage systems on-the-fly. When working with a KVM (Kernel-based Virtual Machine) environment, leveraging a dynamic inventory can significantly streamline the management of virtual machines (VMs) throughout their lifecycle.
Understanding Dynamic Inventory in Ansible
In Ansible, an inventory is a list of systems that Ansible manages. By default, Ansible uses a static inventory, which is a simple text file containing the hostnames or IP addresses of the systems. However, in dynamic environments where systems are frequently created and destroyed, a static inventory can quickly become outdated and unmanageable.
Dynamic inventories solve this problem by allowing Ansible to query a source (such as a cloud provider, virtualization platform, or database) to generate the list of systems in real-time. This ensures that Ansible always has an up-to-date view of the infrastructure it needs to manage.
Setting Up a Dynamic KVM Inventory
To manage VMs in a KVM environment, we can create a dynamic inventory script that queries the KVM hypervisor for the current list of VMs. This script can be written in Python, Bash, or any other language that can output JSON, as Ansible expects the inventory in JSON format.
Example: A Simple Python Script for KVM Inventory
Here’s an example of a simple Python script (kvm_inventory.py) that uses the libvirt library to query the KVM hypervisor for a list of running VMs:
#!/usr/bin/env python3
import libvirt
import json
def get_vm_info():
conn = libvirt.open('qemu:///system')
if conn is None:
print('Failed to open connection to qemu:///system')
return {}
inventory = {'_meta': {'hostvars': {}}}
for domain_id in conn.listDomainsID():
domain = conn.lookupByID(domain_id)
name = domain.name()
ip_address = None
if domain.hasCurrentSnapshot():
ifaces = domain.interfaceAddresses(libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT, 0)
for (iface_name, iface_info) in ifaces.items():
if iface_info['addrs']:
for addr in iface_info['addrs']:
if addr['type'] == libvirt.VIR_IP_ADDR_TYPE_IPV4:
ip_address = addr['addr']
break
if ip_address:
inventory['g_' + name] = {'hosts': [name]}
inventory['_meta']['hostvars'][name] = {'ansible_host': ip_address}
conn.close()
return inventory
if __name__ == "__main__":
inventory = get_vm_info()
print(json.dumps(inventory, indent=2))
This script connects to the KVM hypervisor, retrieves the list of running VMs, and generates a JSON inventory that Ansible can use.
Using the Dynamic Inventory in Ansible
To use the dynamic inventory with Ansible, you need to specify the script as the inventory source in your Ansible command or playbook:
ansible-playbook -i kvm_inventory.py playbook.yml
Ansible will execute the kvm_inventory.py script, which will return the inventory in JSON format. Ansible will then use this dynamic inventory to determine which hosts to target in the playbook.
Using the Libvirt Inventory Plugin
The Libvirt inventory plugin queries the libvirt daemon to obtain a list of VMs, including their IP addresses, status, and other metadata. Here’s how you can use it:
1. Install the Necessary Dependencies
sudo apt install python3-dev libvirt-dev
Ensure that the libvirt-python package is installed, as it allows Python to interact with the libvirt API.
pip install libvirt-python
You also need the libvirt daemon and KVM installed on your host system.
2. Configure the inventory plugin
Create an inventory configuration file that uses the libvirt inventory plugin. This configuration is usually written in YAML and saved with a .yml or .yaml extension.
Here’s an example configuration (libvirt_inventory.yml):
plugin: community.libvirt.libvirt
uri: qemu:///system
plugin: community.libvirt.libvirt: Specifies the use of the libvirt inventory plugin.uri: qemu:///system: Defines the URI to connect to the KVM hypervisor. The URIqemu:///systemconnects to the system-wide instance of KVM.
This simple configuration will tell Ansible to connect to the KVM hypervisor and gather information about all VMs.
3. Using the Libvirt Inventory Plugin in Ansible
With the configuration in place, you can now use this dynamic inventory in your Ansible commands or playbooks:
ansible-inventory -i libvirt_inventory.yml --list
This command will display the current list of VMs managed by KVM in JSON format.
To run a playbook using this inventory:
ansible-playbook -i libvirt_inventory.yml playbook.yml
Ansible will automatically query the KVM hypervisor for the list of VMs and use it as the inventory for the playbook.
Example Playbook Using Libvirt Inventory Plugin
Here’s a sample playbook that uses the Libvirt inventory to configure VMs:
---
- name: Configure all KVM VMs
hosts: all
tasks:
- name: Install Apache on all VMs
ansible.builtin.yum:
name: httpd
state: present
when: ansible_facts['os_family'] == "RedHat"
- name: Ensure Apache is running
ansible.builtin.service:
name: httpd
state: started
when: ansible_facts['os_family'] == "RedHat"
In this example, the playbook installs and starts Apache on all VMs managed by the KVM hypervisor.
Advantages of Using the Libvirt Inventory Plugin
- Simplicity: No need to write custom scripts to generate inventories.
- Real-time inventory: Always up-to-date with the current state of VMs.
- Integrated with Ansible: Works seamlessly with Ansible’s inventory system.
Managing VM Lifecycle with Ansible
Ansible can also manage the entire lifecycle of VMs, including creation, configuration, and deletion. For example, you can write a playbook to create a new VM, configure its operating system, and install necessary software. Here’s a basic example:
Example: Playbook to Create and Configure a New VM
---
- name: Create and configure a new VM
hosts: localhost
tasks:
- name: Create a new VM
virt:
name: new_vm
state: running
memory: 1024
vcpus: 2
disk:
- size: 10
network:
- bridge: virbr0
os_type: linux
boot:
devices:
- cdrom
- name: Wait for VM to start and obtain an IP
pause:
minutes: 1
- name: Add the new VM to the inventory
add_host:
name: "{{ hostvars['localhost']['new_vm_ip'] }}"
groups: new_vms
- name: Install Nginx on the new VM
ansible.builtin.yum:
name: nginx
state: present
when: ansible_facts['os_family'] == "RedHat"
delegate_to: "{{ item }}"
with_items: "{{ groups['new_vms'] }}"
This playbook creates a new VM using the virt module, waits for it to obtain an IP address, adds the new VM to the inventory, and then installs Nginx on it. The delegate_to and add_host modules are used to dynamically manage the new VM.
Conclusion
Using a dynamic KVM inventory with Ansible is an efficient way to manage the lifecycle and configuration of VMs. By automating the discovery and management of VMs, you can ensure that your infrastructure remains up-to-date and consistent, even in highly dynamic environments. The combination of Ansible’s flexibility and the power of KVM provides a robust solution for managing virtualized infrastructure.
Whether you are spinning up new VMs, configuring existing ones, or tearing down old instances, a dynamic KVM inventory simplifies these tasks, enabling you to focus on higher-level management and automation.