How To Provision VMs on oVirt / RHEV with Terraform

ComputingPost
9 min readOct 9, 2022

This guide will discuss how you can automate your oVirt / RHEV VM creation with Terraform. It is not just the creation of VMs that you can use terraform for, but provisioning of other resources such as Disk, Network, Snapshots e.t.c. In our previous article, we discussed how you can use Terraform to automate your KVM infrastructure.

For installation of terraform, refer to:

Setup Pre-requisite

You should have installed Terraform provider for oVirt / RHEV using the guide below.

This guide will discuss how you can automate your oVirt / RHEV VM automation with Terraform. It is not just the creation of VMs that you can use terraform for, but provisioning of other resources such as Disk, Network, Snapshots e.t.c. In our previous article, we discussed how you can use Terraform to automate your KVM infrastructure.

VM Template preparation

Ensure your VM template have cloud-init installed.

### CentOS / Rocky Linux ###

sudo yum -y update

sudo yum -y install epel-release

sudo yum install cloud-init cloud-utils-growpart

sudo systemctl enable --now cloud-init





### Debian / Ubuntu ###

sudo apt-get -y update

sudo apt-get -y install cloud-init

Setup Pre-requisite

You should have installed Terraform provider for oVirt / RHEV using the guide below.

Among the resources supported by terraform oVirt provider are:

  • ovirt_cluster
  • ovirt_datacenter
  • ovirt_disk
  • ovirt_disk_attachment
  • ovirt_host
  • ovirt_mac_pool
  • ovirt_network
  • ovirt_snapshot
  • ovirt_storage_domain
  • ovirt_tag
  • ovirt_user
  • ovirt_vm
  • ovirt_vnic
  • ovirt_vnic_profile

The data sources are:

  • ovirt_authzs
  • ovirt_clusters
  • ovirt_datacenters
  • ovirt_disks
  • ovirt_hosts
  • ovirt_mac_pools
  • ovirt_networks
  • ovirt_nics
  • ovirt_storagedomains
  • ovirt_users
  • ovirt_vms
  • ovirt_vnic_profiles

The official documentation for Terraform oVirt provider provides more details on the usage of these resources and data sources. We’ll only cover the most basic and common use cases.

Creating Terraform modules

A module is a container for multiple resources that are used together. Modules can be used to create lightweight abstractions, so that you can describe your infrastructure in terms of its architecture, rather than directly in terms of physical objects.

In terms of structure, most commonly, modules use:

  • Input variables to accept values from the calling module.
  • Output values to return results to the calling module, which it can then use to populate arguments elsewhere.
  • Resources to define one or more infrastructure objects that the module will manage.

We’ll create two modules for ovirt_vm and ovirt_network. Let’s start by creating project folder.

mkdir -p ~/terraform/modules/vms,disk

Create module for VM creation

Create module for ovirt_vm resource which is used to manage VM resource within oVirt.

Create resource:

$ vim ~/terraform/modules/vms/main.tf



resource "ovirt_vm" "vm"

name = "$var.vm_name"

clone = "false"

high_availability = "true"

cluster_id = "$var.cluster_id"

memory = "$var.vm_memory"

template_id = "$var.vm_template_id"

cores = "$var.vm_cpu_cores"

sockets = "$var.vm_cpu_sockets"

threads = "$var.vm_cpu_threads"



initialization

authorized_ssh_key = "$var.vm_authorized_ssh_key"

host_name = "$var.vm_hostname"

timezone = "$var.vm_timezone"

user_name = "$var.vm_user_name"

custom_script = "$var.vm_custom_script"

dns_search = "$var.vm_dns_search"

dns_servers = "$var.vm_dns_servers"



nic_configuration

label = "$var.vm_nic_device"

boot_proto = "$var.vm_nic_boot_proto"

address = "$var.vm_nic_ip_address"

gateway = "$var.vm_nic_gateway"

netmask = "$var.vm_nic_netmask"

on_boot = "$var.vm_nic_on_boot"

Create variables file:

$ vim ~/terraform/modules/vms/vars.tf



# Basic

variable "vm_name"

description = " A unique name for the VM"

default = ""



variable "cluster_id"

description = "The ID of cluster the VM belongs to"

default = ""



variable "vm_template_id"

description = "The ID of template the VM based on"

default = ""



variable "vm_memory"

description = "The amount of memory of the VM (in metabytes)"

default = "4096"



variable "vm_cpu_cores"

description = "The amount of cores"

default = "2"



variable "vm_cpu_sockets"

description = "The amount of sockets"

default = "1"



variable "vm_cpu_threads"

description = " The amount of threads"

default = "1"





# VM initialization



variable "vm_authorized_ssh_key"

description = "The ssh key for the VM"

default = ""



variable "vm_hostname"

description = "The hostname for the VM"

default = ""



variable "vm_timezone"

description = "The timezone for the VM"

default = ""



variable "vm_user_name"

description = "The user name for the VM"

default = ""



variable "vm_custom_script"

description = "Set the custom script for the VM"

default = ""



variable "vm_dns_search"

description = "The dns server for the VM"

default = ""



variable "vm_dns_servers"

description = "The dns server for the VM"

default = ""





# Initialization - Nic Configurations

variable "vm_nic_device"

description = "The vNIC to apply this configuration."

default = ""



variable "vm_nic_boot_proto"

description = "The boot protocol for the vNIC configuration."

default = "static"



variable "vm_nic_ip_address"

description = "The IP address for the vNIC"

default = ""



variable "vm_nic_gateway"

description = "The gateway for the vNIC"

default = ""



variable "vm_nic_netmask"

description = "The netmask for the vNIC"

default = ""



variable "vm_nic_on_boot"

description = "The flag to indicate whether the vNIC will be activated at VM booting"

default = "true"

Outputs file:

$ vim ~/terraform/modules/vms/outputs.tf



output "id"

description = "VM ID"

value = "$ovirt_vm.vm.id"

Create module for Disk management

Here we’ll put the following resources in one module:

  • ovirt_disk — Used to manage a Disk resource within oVirt.
  • ovirt_disk_attachment — For managing Disk attachment resource within oVirt.

Create resources file:

$ vim ~/terraform/modules/disk/main.tf



resource "ovirt_disk" "disk"

name = "$var.name"

alias = "$var.name"

size = "$var.size"

format = "$var.format"

storage_domain_id = "$var.storage_domain_id"

sparse = "$var.sparse"

shareable = "$var.shareable"





resource "ovirt_disk_attachment" "diskattachment"

vm_id = "$var.vm_id"

disk_id = "$ovirt_disk.disk.id"

active = "$var.active"

bootable = "$var.bootable"

interface = "$var.interface"

read_only = "$var.read_only"

use_scsi_reservation = "$var.use_scsi_reservation"

For variables:

$ vim ~/terraform/modules/disk/var.tf



# Disk resource variables

variable "name"

default = ""



variable "size"

default = ""



variable "format"

default = "cow"



variable "storage_domain_id"

default = ""



variable "sparse"

default = "true"



variable "shareable"

default = "false"





# Disk attachment

variable "vm_id"

default = ""



variable "disk_id"

default = ""



variable "active"

default = "true"



variable "bootable"

default = "false"



variable "interface"

default = "virtio_scsi"



variable "pass_discard"

default = ""



variable "read_only"

default = "false"



variable "use_scsi_reservation"

default = "false"

Using Terraform modules

Create the main terraform configuration defining oVirt provider.

$ mkdir  ~/terraform/ovirt

$ cd ~/terraform/ovirt

$ vim main.tf



provider "ovirt"

url = "$var.ovirt_url"

username = "$var.ovirt_username"

password = "$var.ovirt_password"





terraform

backend "local"

path = "ovirt_terraform.tfstate"

Create variables file

$ cd ~/terraform/ovirt

$ vim vars.tf



variable "ovirt_url"

description = "oVirt API URL"

default = "https://ovirthostname/ovirt-engine/api"



variable "ovirt_username"

description = "oVirt Admin user"

default = "admin@internal"



variable "ovirt_password"

description = "oVirt Admin password"

default = "ovirtuserpassword"

Set correct values for access credentials. Once done. you can now create terraform resources using the modules we created.

$ cd ~/terraform/ovirt

$ vim main.tf



# Create VM call temp01

module "temp01"

source = "../modules/vms"

cluster_id = "c5529b5d-1b4e-46e6-9cb1-5d44c28cd65b"

vm_name = "temp01"

vm_hostname = "temp01.example.com"

vm_dns_servers = "8.8.8.8"

vm_dns_search = "example.com"

vm_memory = "2048"

vm_cpu_cores = "2"

vm_timezone = "Africa/Nairobi"

vm_template_id = "fd4b04a9-74b5-4287-adbc-3d5c6711d53f"

vm_nic_device = "eth0"

vm_nic_ip_address = "192.168.10.11"

vm_nic_gateway = "192.168.10.254"

vm_nic_netmask = "255.255.255.0"

Other parameters used in vm module variables can be set. Ensure you set correct variables.

When done, initialize project

$ cd ~/terraform/ovirt

$ terraform init

Initializing modules...

- temp01 in ../modules/vms



Initializing the backend...



Successfully configured the backend "local"! Terraform will automatically

use this backend unless the backend configuration changes.



Initializing provider plugins...



Terraform has been successfully initialized!



You may now begin working with Terraform. Try running "terraform plan" to see

any changes that are required for your infrastructure. All Terraform commands

should now work.



If you ever set or change modules or backend configuration for Terraform,

rerun this command to reinitialize your working directory. If you forget, other

commands will detect it and remind you to do so if necessary.

Validate terraform configurations.

$ terraform validate

Success! The configuration is valid.

Plan your deployment

$ terraform plan

Refreshing Terraform state in-memory prior to plan...

The refreshed state will be used to calculate this plan, but will not be

persisted to local or remote state storage.





------------------------------------------------------------------------



An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:

+ create



Terraform will perform the following actions:



# module.temp01.ovirt_vm.vm will be created

+ resource "ovirt_vm" "vm"

+ clone = true

+ cluster_id = "c5529b5d-1b4e-46e6-9cb1-5d44c28cd65b"

+ cores = 2

+ high_availability = true

+ id = (known after apply)

+ memory = 2048

+ name = "temp01"

+ sockets = 1

+ status = (known after apply)

+ template_id = "fd4b04a9-74b5-4287-adbc-3d5c6711d53f"

+ threads = 1



+ initialization

+ dns_search = "example.com"

+ dns_servers = "8.8.8.8"

+ host_name = "temp01.example.com"

+ timezone = "Africa/Nairobi"



+ nic_configuration

+ address = "192.168.10.11"

+ boot_proto = "static"

+ gateway = "192.168.10.254"

+ label = "eth0"

+ netmask = "255.255.255.0"

+ on_boot = true









Plan: 1 to add, 0 to change, 0 to destroy.



------------------------------------------------------------------------



Note: You didn't specify an "-out" parameter to save this plan, so Terraform

can't guarantee that exactly these actions will be performed if

"terraform apply" is subsequently run.

Execute creation

$ terraform apply

An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:

+ create



Terraform will perform the following actions:



# module.temp01.ovirt_vm.vm will be created

+ resource "ovirt_vm" "vm"

+ clone = true

+ cluster_id = "c5529b5d-1b4e-46e6-9cb1-5d44c28cd65b"

+ cores = 2

+ high_availability = true

+ id = (known after apply)

+ memory = 2048

+ name = "temp01"

+ sockets = 1

+ status = (known after apply)

+ template_id = "fd4b04a9-74b5-4287-adbc-3d5c6711d53f"

+ threads = 1



+ initialization

+ dns_search = "example.com"

+ dns_servers = "8.8.8.8"

+ host_name = "temp01.example.com"

+ timezone = "Africa/Nairobi"



+ nic_configuration

+ address = "192.168.10.11"

+ boot_proto = "static"

+ gateway = "192.168.10.254"

+ label = "eth0"

+ netmask = "255.255.255.0"

+ on_boot = true









Plan: 1 to add, 0 to change, 0 to destroy.



Do you want to perform these actions?

Terraform will perform the actions described above.

Only 'yes' will be accepted to approve.



Enter a value: yes

The apply command will have output similar to below.

module.temp01.ovirt_vm.vm: Creating...

module.temp01.ovirt_vm.vm: Still creating... [10s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [20s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [30s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [40s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [50s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [1m0s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [1m10s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [1m20s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [1m30s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [1m40s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [1m50s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [2m0s elapsed]

module.temp01.ovirt_vm.vm: Still creating... [2m10s elapsed]

module.temp01.ovirt_vm.vm: Creation complete after 2m11s [id=2ad55c71-2e1a-4ce0-89a0-cda845f83fa2]



Apply complete! Resources: 1 added, 0 changed, 0 destroyed.



The state of your infrastructure has been saved to the path

below. This state is required to modify and destroy your

infrastructure, so keep it safe. To inspect the complete state

use the `terraform show` command.



State path: ovirt_terraform.tfstate

Login to your RHEV / oVirt environment and confirm the VM creation.

deploy-vms-on-ovirt-rhev-with-terraform-1024x473

Modify main.tf to add more resources

Let’s update the file to create another VM and disk.

# Create VM call temp01

module "temp01"

source = "../modules/vms"

cluster_id = "c5529b5d-1b4e-46e6-9cb1-5d44c28cd65b"

vm_name = "temp01"

vm_hostname = "temp01.example.com"

vm_dns_servers = "8.8.8.8"

vm_dns_search = "example.com"

vm_memory = "2048"

vm_cpu_cores = "2"

vm_timezone = "Africa/Nairobi"

vm_template_id = "fd4b04a9-74b5-4287-adbc-3d5c6711d53f"

vm_nic_device = "eth0"

vm_nic_ip_address = "192.168.10.11"

vm_nic_gateway = "192.168.10.254"

vm_nic_netmask = "255.255.255.0"





module "temp02"

source = "../modules/vms"

cluster_id = "c5529b5d-1b4e-46e6-9cb1-5d44c28cd65b"

vm_name = "temp02"

vm_hostname = "temp02.example.com"

vm_dns_servers = "8.8.8.8"

vm_dns_search = "example.com"

vm_memory = "2048"

vm_cpu_cores = "2"

vm_timezone = "Africa/Nairobi"

vm_template_id = "fd4b04a9-74b5-4287-adbc-3d5c6711d53f"

vm_nic_device = "eth0"

vm_nic_ip_address = "192.168.10.12"

vm_nic_gateway = "192.168.10.254"

vm_nic_netmask = "255.255.255.0"





## Create and attach Disk to VM temp02

module "temp02_disk02"

source = "../modules/vms"

name = "temp02_disk02"

size = "50"

storage_domain_id = "a5542689-bd73-4f16-846e-697822e4ad2c"

vm_id = "$module.temp02.id"

Run initialization.

$ terraform init

Apply configurations:

$ terraform plan

$ terraform apply

Destroying your infrastructure only requires one command

$ terraform destroy

module.temp01.ovirt_vm.vm: Refreshing state... [id=2ad55c71-2e1a-4ce0-89a0-cda845f83fa2]



An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:

- destroy



Terraform will perform the following actions:



# module.temp01.ovirt_vm.vm will be destroyed

- resource "ovirt_vm" "vm"

- clone = true -> null

- cluster_id = "c5529b5d-1b4e-46e6-9cb1-5d44c28cd65b" -> null

- cores = 2 -> null

- high_availability = true -> null

- id = "2ad55c71-2e1a-4ce0-89a0-cda845f83fa2" -> null

- memory = 2048 -> null

- name = "temp01" -> null

- sockets = 1 -> null

- status = "up" -> null

- template_id = "fd4b04a9-74b5-4287-adbc-3d5c6711d53f" -> null

- threads = 1 -> null



- initialization

- dns_search = "example.com" -> null

- dns_servers = "8.8.8.8" -> null

- host_name = "temp01.example.com" -> null

- timezone = "Africa/Nairobi" -> null



- nic_configuration

- address = "192.168.10.11" -> null

- boot_proto = "static" -> null

- gateway = "192.168.10.254" -> null

- label = "eth0" -> null

- netmask = "255.255.255.0" -> null

- on_boot = true -> null









Plan: 0 to add, 0 to change, 1 to destroy.



Do you really want to destroy all resources?

Terraform will destroy all your managed infrastructure, as shown above.

There is no undo. Only 'yes' will be accepted to confirm.



Enter a value: yes

module.temp01.ovirt_vm.vm: Destroying... [id=2ad55c71-2e1a-4ce0-89a0-cda845f83fa2]

module.temp01.ovirt_vm.vm: Still destroying... [id=2ad55c71-2e1a-4ce0-89a0-cda845f83fa2, 10s elapsed]

module.temp01.ovirt_vm.vm: Destruction complete after 20s



Destroy complete! Resources: 1 destroyed.

Refer to documentation pages for more examples on how to use oVirt provider resources and data sources.

https://www.computingpost.com/how-to-provision-vms-on-ovirt-rhev-with-terraform/?feed_id=10299&_unique_id=63431236961f5

--

--

ComputingPost

ComputingPost — Linux Howtos, Tutorials, Guides, News, Tips and Tricks.