Automate Virtual Machine Creation with KVM

This article will cover the process of automating the creation of a CentOS 7 Minimal Virtual Machine using virt-clone, virt-sysprep, and simple BASH scripts.

First, I will cover the creation of a basic template virtual machine that will be used as a target for cloning new VMs. Next I'll create a couple simple BASH scripts while explaining the use of virt-clone and virt-sysprep1 to create and generalize new Virtual Machines.


Create a Virtual Machine Template



Use virt-install2 or virt-manager3 to create a Virtual Machine on your KVM/QEMU Hypervisor, and then install CentOS 7 minimal installation4.

Configuration of my Template VM
  • 1 vCPU
  • 2GB memory
  • 20GB vDisk
  • NIC Network Source using a bridged interface

Once you have a virtual machine created and CentOS 7 installe I recommend adding a channel for the qemu-guest-agent software. To do so, with your newly created VM still powered down, double click on your VM in virt-manager's list and select the information button in the top left corner of the window.

VM Information

Next, click on the "Add Hardware" button at the bottom left of the window. In the Add New Virtual Hardware dialog box select the Channel option, and then org.qemu.guest_agent.0 from the drop down menu. Click "Finish".

Add QEMU Agent Channel

Power on your VM, run updates if you haven't already(sudo yum update), and proceed to install the qemu-guest-agent5. Once the guest agent is installed, power down your VM Template.


Create a BASH script for cloning your Template Virtual Machine



The virt-clone tool allows us to clone our template VM from the command-line. I am now going to show you how create a BASH script that will simplify the process.

NOTE: I prefer to store these scripts in the /usr/local/sbin directory. This ensures the scripts are only accessible to superusers

First, lets look at the virt-clone command that creates the clone of our Template VM:

#!/bin/bash

virt-clone --connect qemu:///system     \  
        --original-xml /etc/libvirt/qemu/centos7_min_template.xml       \
        --name $1       \
        --file /dev/kvm_vm_images/$1

The first line of the command calls virt-clone and tells it to connect to qemu. The second line tells it which virtual machine to reference for the origin of the clone. The third line designates the name for the clone you are about to create. And the last line designates the backing file for the VM's vDisk image. By using the $1 variable, we are referencing the first argument that is passed to the script. So if our script was names create-centos7-min-vm.sh, we would invoke it as follows: /usr/local/sbin/create-centos7-min-vm.sh my-new-vm and it would replace the $1 variable in the script with my-new-vm upon execution.

In it's current state, the script will run and create a cloned VM as expected. However, what happens if you don't supply an argument to name the VM and VM image file? What if you supply multiple arguments by accident? Things will go wrong. Lets add a way to ensure we don't muck up our VM creation by ensuring only a single argument is allowed.

#!/bin/bash

if [[ $# -ne 1 ]]; then  
    printf  "\n\t"
    printf "ERROR:  Illegal number of parameters!!!"
    printf "\n\t"
    printf "Proper usage requires:  $0 new-vm-name"
    printf "\n\n"
    exit 1
fi


virt-clone --connect qemu:///system     \  
        --original-xml /etc/libvirt/qemu/centos7_min_template.xml       \
        --name $1       \
        --file /dev/kvm_vm_images/$1

In the above script I've added an if statement that checks the number of arguments, and if it is not equal to 1, it errors out, notifies the user of an error and proper usage, and immediately exits the script without executing the virt-clone command.

The $# variable refers to the number of arguments that have been passed to the script during execution. The $0 variable refers to the script itself, and inserts the script name into the error message. When used with printf the \n designates a newline, and \t designates a tab.

An additional step that can add a little "polish" to your script is adding color to any text that is output to the console. In the completed example below notice the red and green variables that are declared and initialized at the top of the script. By inserting them in front of the text being printed to the console by printf, we can manipulate the color of the text.

#!/bin/bash

red='\e[1;31m%s\e[0m\n'  
green='\e[1;32m%s\e[0m\n'


if [[ $# -ne 1 ]]; then  
    printf  "\n\t"
    printf "$red" "ERROR:  Illegal number of parameters!!!"
    printf "\n\t"
    printf "$green" "Proper usage requires:  $0 new-vm-name"
    printf "\n\n"
    exit 1
fi


virt-clone --connect qemu:///system     \  
        --original-xml /etc/libvirt/qemu/centos7_min_template.xml       \
        --name $1       \
        --file /dev/kvm_vm_images/$1

printf "\n\n\n\t"  
printf "$green" "Virtual Machine $1 has been created."  
printf "\n\t"  
printf "$green" "Please run the ./virt-sysprep.sh script to generalize your new Virtual Machine"  
printf "\n\n"  

When you're done creating your script make it executable by running the following command: sudo chmod +x /usr/local/sbin/create-centos7-min-vm.sh


Create a BASH script to simplify generalization of your new VM



Let's take a look at the command for generalizing our VM first:

#!/bin/bash

virt-sysprep -d $1 --hostname $2  

This script uses virt-sysprep and accepts two arguments; the VM name used in the previous script, and a second parameter that designates the hostname. The -d flag tells virt-sysprep which VM to target for generalization, and the --hostname flag tells it what value to change the target VM's hostname to.

Like the last script, lets add in some simple logic to ensure we are passing the correct number of parameters as arguments.

#!/bin/bash

if [[ $# -ne 2 ]]; then  
    printf  "\n\t"
    printf "ERROR:  Illegal number of parameters!!!"
    printf "\n\t"
    printf "Proper usage requires:  $0 vm-name new-hostname"
    printf "\n\n"
    exit 1
fi

/usr/bin/virt-sysprep -d $1 --hostname $2



And, if you would like to enhance the readability of the scripts output, add color:

#!/bin/bash

red='\e[1;31m%s\e[0m\n'  
green='\e[1;32m%s\e[0m\n'

if [[ $# -ne 2 ]]; then  
    printf  "\n\t"
    printf "$red" "ERROR:  Illegal number of parameters!!!"
    printf "\n\t"
    printf "$green" "Proper usage requires:  $0 vm-name new-hostname"
    printf "\n\n"
    exit 1
fi

/usr/bin/virt-sysprep -d $1 --hostname $2

And that's it! You should now be able to create a new Virtual Machine by running the two scripts in succession. If you prefer you could also combine both commands into a single script. You could also create several copies of your Template VM's XML configuration file altered to provide varying resource allocations(more memory, vCPUs, etc...).

Research the different options available to virt-clone and virt-sysprep, and further customize your scripts to enhance usability!


Footnotes

RamblingBiped

Read more posts by this author.