Finally the nodes will defined in the code. A module will be used to define these nodes, as several nodes need to be deployed with the same resource configuration.
Example:
module "host01-node" {
source = "../modules/kvm-node"
name = "host01"
dns_domain = var.dns_domain
memory = 8192 # in Mb
vcpu = 4
disk_size = 40 # in Gb
ip_address = "10.1.2.10"
gw_address = var.gw_address
user_pwd = var.default_password
install_image = libvirt_volume.local_install_image.id
libvirt_pool = libvirt_pool.default
libvirt_network = libvirt_network.my_network
}
The module will first define some storage resources which are required for the installation and post-installation steps. Post-installation steps are managed by “cloud-init” and require its own storage volume. This storage volume is configured by two templates (hashicorp/template provider):
- the cloud-init configuration file
- the network configuration file
data "template_file" "user_data" {
template = "${file("${path.module}/templates/cloud-init.cfg")}"
vars = {
hostname = var.name
fqdn = "${var.name}.${var.dns_domain}"
password = var.user_pwd
}
}
data "template_file" "network_config" {
template = "${file("${path.module}/templates/network-config.cfg")}"
vars = {
domain = var.dns_domain
ip_address = var.ip_address
gw_address = var.gw_address
}
}
resource "libvirt_cloudinit_disk" "commoninit" {
name = "${var.name}-commoninit.iso"
pool = var.libvirt_pool.name
user_data = "${data.template_file.user_data.rendered}"
network_config = "${data.template_file.network_config.rendered}"
}
The last storage volume defined is the virtual disk used by the virtual node:
resource "libvirt_volume" "node-disk-qcow2" {
name = "${var.name}-disk-ubuntu-focal.qcow2"
pool = var.libvirt_pool.name
size = 1024*1024*1024*var.disk_size
base_volume_id = var.install_image
base_volume_pool = var.libvirt_pool.name
format = "qcow2"
}
This volume is based on the “local_install_image” which was created previously.
Finally, since all extra resources are defined, the virtual node resource can be configured:
resource "libvirt_domain" "kvm_node" {
name = var.name
memory = var.memory
vcpu = var.vcpu
qemu_agent = true
autostart = true
cloudinit = libvirt_cloudinit_disk.commoninit.id
network_interface {
network_id = var.libvirt_network.id
}
console {
type = "pty"
target_port = "0"
target_type = "serial"
}
console {
type = "pty"
target_type = "virtio"
target_port = "1"
}
disk {
volume_id = libvirt_volume.node-disk-qcow2.id
}
}
The network interface just needs to be assigned to an existing network, the actual IP configuration will be done by cloud-init.
Having all configuration in place, Terraform needs to be initialized and it should create a plan (which will be saved to a file) of what needs to be deployed.
terraform init --upgrade terraform plan -out myplan
Once the plan successfully finishes and the changes have been reviewed, apply the plan to roll out the changes:
terraform apply "myplan"
The code snippets in this article can be downloaded from: https://github.com/insani4c/terraform-libvirt