Terraform your (multi) cloud – part 1

Published by Andrea on

Terraform is one of my favorites open source tools, I started to use it with my internal VMware and after with cloud Azure and AWS.

The idea of describing an infrastructure with a configuration language is relatively new and starts to become more important with the adoption of private and public clouds.

The latest announcement of Anthos from Google gives you the importance of a multi-cloud approach and the needs of tools to manage it.

It sounds difficult but it’s easier than you can think and after the first definition of your current infrastructure in a couple of files, you can with some copy and past replicate very large and complicated configuration and in conjunction with Git you to can save and versioning your infrastructure!

I started with my private cloud on a VMware vSphere cluster that I know very well and helps me to understand the workflow and the basic command.

You can download Terraform from HashiCorp website download page:

https://www.terraform.io/downloads.html

Install Terraform is simple, just unzip it and moving it to a directory included in your system’s PATH or add the directory to your PATH.

To write files I suggest you use visual studio code with the extension for Terraform, it will be more easy to start with this new high-level language.

For VMware, I have created two files, variables.tf and build.tf.

The first variables.tf contains the address of my vCenter, DNS, user id and password:

variable "vsphere_server" {
description = "vsphere server for the environment"
default = "vcenter01.domain.com"
}

variable "vsphere_user" {
description = "vsphere user for the environment"
default = "administrator@vsphere.local"
}

variable "vsphere_password" {
description = "vsphere server password for the environment"
default = "Password!"
}

variable "virtual_machine_dns_servers" {
type = "list"
default = ["192.168.0.2", "192.168.0.3"]
}

build.tf contains the initial infrastructure definition and starts with the declaration of the provider and datacenter:

provider "vsphere" {
user = "${var.vsphere_user}"
password = "${var.vsphere_password}"
vsphere_server = "${var.vsphere_server}"

# if you have a self-signed cert
allow_unverified_ssl = true
}

data "vsphere_datacenter" "dc" {
name = "DC"
}

Now you can already send your first command to test if everything is ok from your infrastructure files directory:

terraform init

This will initialize various local settings and data that will be used by subsequent commands,  and download and install any plugin needed by your provider declaration, in this case only vSphere.

After this, you can edit the file adding Datastores, Clusters, Hosts, Resource pools, virtual switches etc.

data "vsphere_datastore" "datastore_01" {
name = "datastore_01
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_compute_cluster" "cluster" {
name = "VMCluster"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_host" "host1" {
name = "host01.domain.com"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_host" "host2" {
name = "host02.domain.com"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_network" "network" {
name = "LAN"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_resource_pool" "pool" {
name = "Server Pool"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_distributed_virtual_switch" "dvs1" {
name = "DSwitch1"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

Now you can test if your infrastructure definition is correct running:

terraform plan -out ./dc.out

If all is ok you’ll receive this message 

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.

This command will also create a file dc.out (or the filename you use in the command before) that you can use to apply the configuration to the infrastructure.

Now starts the show, with few lines added to the build.tf file we can create a VM

resource "vsphere_virtual_machine" "vm1" {
name = "spaziani-1"
resource_pool_id = "${data.vsphere_resource_pool.pool.id}"
datastore_id = "${data.vsphere_datastore.datastore_01.id}"

num_cpus = 2
memory = 4096
guest_id = "centos7_64Guest"

scsi_type = "pvscsi"

cdrom {
datastore_id = "${data.vsphere_datastore.datastore_01.id}"
path = "ISO/CentOS-7-x86_64-Everything-1804.iso"
}

network_interface {
network_id = "${data.vsphere_network.network.id}"
adapter_type = "vmxnet3"
}

disk {
label = "disk0"
size = "120"
eagerly_scrub = "false"
thin_provisioned = "true"
}

}

Add a portgroup to a DVS 

resource "vsphere_distributed_port_group" "pg" {
name = "terraform-pg"
distributed_virtual_switch_uuid = "${data.vsphere_distributed_virtual_switch.dvs1.id}"
active_uplinks = ["${data.vsphere_distributed_virtual_switch.dvs1.uplinks[0]}"]
standby_uplinks = ["${data.vsphere_distributed_virtual_switch.dvs1.uplinks[1]}"]
}

Create an affinity VMs to Hosts rules

resource "vsphere_compute_cluster_vm_group" "test_vm_group" {
name = "terraform-test-cluster-vm-group"
compute_cluster_id = "${data.vsphere_compute_cluster.cluster.id}"
virtual_machine_ids = ["${vsphere_virtual_machine.vm1.id}"]
}


resource "vsphere_compute_cluster_host_group" "test_host_group" {
name = "terraform-test-cluster-host-group"
compute_cluster_id = "${data.vsphere_compute_cluster.cluster.id}"
host_system_ids = ["${data.vsphere_host.host1.id}","${data.vsphere_host.host2.id}"]
}

resource "vsphere_compute_cluster_vm_host_rule" "test_vm_host_rule" {
compute_cluster_id = "${data.vsphere_compute_cluster.cluster.id}"
name = "terraform-test-cluster-vm-host-rule"
vm_group_name = "${vsphere_compute_cluster_vm_group.test_vm_group.name}"
affinity_host_group_name = "${vsphere_compute_cluster_host_group.test_host_group.name}"
}

If you add the VM scripts to the build.tf and run again the plan command you’ll receive 

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:

+ vsphere_virtual_machine.vm1

….

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

————————————————————————

This plan was saved to: ./dc.out

To perform exactly these actions, run the following command to apply:
terraform apply “./dc.out”

Check the results and if everything is ok you can execute

terraform apply “./dc.out”

and the creation of the VM starts

vsphere_virtual_machine.vm1: Creating…

In the end, you’ll receive an error because there are no VMware Tools installed, is a brand new Centos 7 from an ISO file but there’s no problem because Terraform will retrieve the other pieces of information at the next plan execution.

If you remove from the file the new vm1 resource section

resource "vsphere_virtual_machine" "vm1" ...

and execute a new terraform plan and apply the vm1 will be deleted

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:

– vsphere_virtual_machine.vm1

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

————————————————————————

This plan was saved to: ./dc.out

To perform exactly these actions, run the following command to apply:
terraform apply “./dc.out”

[root@localhost terraform]# terraform apply “./dc.out”
vsphere_virtual_machine.vm1: Destroying… (ID: 4234fd94-fadd-1252-bb96-e4df602d81cd)
vsphere_virtual_machine.vm1: Destruction complete after 0s

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

I hope this creates the right curiosity for the next article 😉