Cloning Xen VMs With Ansible

In a previous post I explained how to create a VM in XenServer from scratch. Using that method you had to install the CentOS operating system for each new VM. With this method you create new VMs by copying an existing one. Both methods work well. I have started to use the copy method because it is faster. You can also use this method to clone a VM which is useful for integration testing.

The steps are:

  1. Create a new VM and install the OS.
  2. Configure the VM using the Ansible role for your OS.
  3. Remove any reference to a MAC address in the model (in the /etc/sysconfig/network-scripts/ifcfg-eth0 file).
  4. Shutdown the VM.
  5. Record the model VM’s Xen UUID.
  6. Run the Ansible script I provide below to create a new VM based on the model.

The Ansible script is:


- name: Copy VM as full Copy
command: xe vm-copy vm={{ vm_model_uuid }} new-name-label={{ hostname }} sr-uuid={{ primary_sr_uuid }}
register: vm
delegate_to: "{{ pool_master }}"

- name: Find VIF of new copy
command: xe vm-vif-list vm={{ vm.stdout }} params=uuid --minimal
register: vif
delegate_to: "{{ pool_master }}"

- name: Delete model network settings from new copy.
command: xe vif-destroy uuid={{ vif.stdout }}
delegate_to: "{{ pool_master }}"

- name: Adding networks
command: xe vif-create vm-uuid={{ vm.stdout }} network-uuid={{ item.network_uuid }} mac={{ item.mac_address }} device={{ item.device_id }}
delegate_to: "{{ pool_master }}"
with_items: networks

- name: Set the VM RAM limits
command: xe vm-memory-limits-set vm={{ vm.stdout }} static-min={{ ram }} static-max={{ ram }} dynamic-min={{ ram }} dynamic-max={{ ram }}
delegate_to: "{{ pool_master }}"

- name: Set the number of CPUs
command: xe vm-param-set VCPUs-max={{ vcpus }} uuid={{ vm.stdout }}
delegate_to: "{{ pool_master }}"

- name: Launch the VM
command: xe vm-start uuid={{ vm.stdout }}
delegate_to: "{{ pool_master }}"

You can use this script as a replacement for the create_vm.yml script I provided in my guide to automating Xen VM creation.

Most of these variable are explained in my previous guide, some are new and need explanation. pool-master is the FQDN of the XenServer pool master host (stored in group_vars\all). vm_model_uuid is the Xen UUID you recorded in step 5 (stored in (stored in group_vars\all). One VM model is sufficient for me, you may want to create several if you need different classes of VM.

Since writing my previous guide I’ve changed the way I do network configuration to support multi-homed VMs. The new way uses a list of variables stored in the VM’s variable file (host_vars\hostname). During VM copying this information is used by Xen to add networks to the VM. During OS configuration it is used to create the ifcfg-ethX files. Here is an example from one of my VMs.

# Roles: vm, centos, storage, artifactory

hostname: boron
ram: 1GiB
vcpus: 2
- device_id: 0
network_uuid: [Xen Network UUID]
mac_address: [mac]
boot_protocol: dhcp
- device_id: 1xe vm-copy
network_uuid: [Xen Network UUID]
mac_address: [mac]
boot_protocol: dhcp
- device_id: 2
network_uuid: [Xen Network UUID]
mac_address: A[mac]
boot_protocol: static

This script takes a few minutes to run with the slowest part being the copy of the new virtual drive. If you want to quickly create temporary VMs for the purpose of integration testing, for example for use with serverspec, change the first command from xe vm-copy to xe vm-clone. Cloning is very quick. You can use a CI server like Jenkins to quickly spin up a few cloned VMs to run the integration tests on your Ansible script, and then delete them.

Categories: DevOps

Tags: , ,

Share Your Ideas

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: