Create VMs on KVM with Ansible

So the Ansible virt module doesn’t have a clone option and the creation of guests is a little limited. Because of this we have to use the shell or command modules and try to make them idempotent. This is a simple example and the dictionary can be expanded to a lot more customization. There is a way to use libvirt as a dynamic inventory and set group and host vars on guests, but I’ll cover that in a different post.

---
- name: create VMs
  hosts: kvm
  become: true
  vars_files:
    - vms.yml

  tasks:
    - name: get VM disks
      command: "ls {{ vm_location }}"
      register: disks
      changed_when: "disks.rc != 0"

    - name: create disk
      command: >
               virt-builder --format qcow2 centos-7.4
               -o {{ vm_location}}/{{ item.key }}.{{ item.value.file_type }}
               --root-password password:{{ root_pass }}
      when: item.key not in disks.stdout
      with_dict: "{{ guests }}"

    - name: get list of VMs
      virt:
        command: "list_vms"
      register: vms 

    - name: create vm
      command: >
                virt-install --import --name {{ item.key }}
                --memory {{ item.value.mem }} --vcpus {{ item.value.cpus }}
                --disk {{ vm_location }}/{{ item.key }}.{{ item.value.file_type }}
                --noautoconsole --os-variant {{ item.value.os_type }}
      when: item.key not in vms.list_vms
      with_dict: "{{ guests }}"

    - name: start vm
      virt:
        name: "{{ item.key }}"
        state: running
      with_dict: "{{ guests }}"

So we do a few checks to make sure the disk isn’t already in the directory and another check to make sure the VM isn’t already created. The dictionary is in the referenced vars_file:

---
vm_location: "/data/VMs"
root_pass: "password"

guests:
  test:
    mem: 512
    cpus: 1
    os_type: rhel7
    file_type: qcow2
  test2:
    mem: 512
    cpus: 1
    os_type: rhel7
    file_type: qcow2

Obviously you wouldn’t put the password in plain text, you’d either use ansible-vault, a vars prompt, or a survey in tower.

And here’s our output. I had already created a system called test so it skips over to give us idempotence.

kvm

IP Address From QEMU Guest Agent

On a KVM host, it’s fairly easy to get a guest’s IP from the internal network to the host.

[jhooks@kvm2 ~]$ sudo virsh domifaddr Tower
 Name       MAC address          Protocol     Address
-------------------------------------------------------------------------------
 vnet0      52:54:00:e7:01:55    ipv4         192.168.122.149/24

However if you you have the guest on a full bridge or macvtap interface you won’t see anything. To get that information you need to add the QEMU guest agent.

On CentOS it’s simply called qemu-guest-agent.

With this installed you can now query the guest’s address by passing --source agent:

[jhooks@kvm2 ~]$ sudo virsh domifaddr Tower --source agent
Name       MAC address          Protocol     Address
------------------------------------------------------------------------------
lo         00:00:00:00:00:00    ipv4         127.0.0.1/8
-          -                    ipv6         ::1/128
eth0       52:54:00:fc:77:18    ipv4         10.1.30.14/24
-          -                    ipv6         fe80::5054:ff:fefc:7718/64
vnet0      52:54:00:e7:01:55    ipv4         192.168.122.149/24