Use Terraform to manage OpenStack Cluster

Use Terraform to manage OpenStack Cluster
Photo by C Dustin / Unsplash

After having a production and homelab OpenStack for a while, I could say that provisioning Workloads, managing it with an Admin and Tenant perspective is important.

Terraform is an open-source Infrastructure as code software tool that is used for provisioning network, server, cloud platforms and more, since Terraform is a declarative language, it can act as a blue print of the infrastructure that you are working on. This is a very helpful to know what would be added and removed on your infrastructure and can be managed by Git as well as a GitOps use case.

For this article lets cover the basics of managing an OpenStack cluster using Terraform and recrete the Demo project of OpenStack via Terraform.

Installation of Terraform

Since I use a Centos as jumphost where I will run Terraform based on the official documentation we need to do the following:

  1. Install yum-utils first
$ sudo dnf install yum-utils -y
  1. Add Hashicop Terraform repo
$ sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
  1. Install terraform
$ sudo dnf install terraform -y
  1. Check Installation
$ terraform –version

Create your terraform script for OpenStack provider

In Terraform you need what you call a provider, A Provider basically is a converter that terraform calls to convert your .tf into API calls to the platform that we will orchestrate, there are 3 types of providers namely Official,Partner and Community. Official providers are Hashicorp maintained, Partner are maintained by technology companies that partners with Hashicorp, and Community basically maintained by Open Source Community.

For OpenStack there is a good Community provider in this link, For us to use this provider we need to create a .tf file, lets call it main.tf

$ vi main.tf

The content will be

terraform {
  required_version = ">= 0.14.0"
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "1.49.0"
    }
  }
}
provider "openstack" {
  user_name   = “OS_USERNAME”
  tenant_name = “OS_TENANT”
  password    = “OS_PASSWORD”
  auth_url    = “OS_AUTH_URL”
  region      = “OS_REGION”
}

You need to change the OS_USERNAME, OS_TENANT, OS_PASSWORD, OS_AUTH_URL, and  OS_REGION variables, for it to work.

Admin terraform file

As an Admin for OpenStack is focused on provisioning External Network, Routers, Users, Images, Tenant Profile,  and its Quotas.

for this example will provision,Flavors, a Router connected to an External Network, a Test Image a Tenant profile and a User.

Let’s create first a Admin directory for your Admin related provisioning.

$ mkdir AdminTF
$ cd AdminTF

In the main.tf

terraform {
  required_version = ">= 0.14.0"
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "1.49.0"
    }
  }
}
provider "openstack" {
  user_name   = “OS_USERNAME”
  tenant_name = “admin”
  password    = “OS_PASSWORD”
  auth_url    = “OS_AUTH_URL”
  region      = “OS_REGION”
}
resource "openstack_compute_flavor_v2" "small-flavor" {
  name      = "small"
  ram       = "4096"
  vcpus     = "1"
  disk      = "0"
  flavor_id = "1"
  is_public = "true"
}
resource "openstack_compute_flavor_v2" "medium-flavor" {
  name      = "medium"
  ram       = "8192"
  vcpus     = "2"
  disk      = "0"
  flavor_id = "2"
  is_public = "true"
}
resource "openstack_compute_flavor_v2" "large-flavor" {
  name      = "large"
  ram       = "16384"
  vcpus     = "4"
  disk      = "0"
  flavor_id = "3"
  is_public = "true"
}
resource "openstack_compute_flavor_v2" "xlarge-flavor" {
  name      = "xlarge"
  ram       = "32768"
  vcpus     = "8"
  disk      = "0"
  flavor_id = "4"
  is_public = "true"
}
resource "openstack_networking_network_v2" "external-network" {
  name           = "external-network"
  admin_state_up = "true"
  external       = "true"
  segments {
    network_type     = "flat"
    physical_network = "physnet1"
  }
}
resource "openstack_networking_subnet_v2" "external-subnet" {
  name            = "external-subnet"
  network_id      = openstack_networking_network_v2.external-network.id
  cidr            = "10.0.0.0/8"
  gateway_ip      = "10.0.0.1"
  dns_nameservers = ["10.0.0.254", "10.0.0.253"]
  allocation_pool {
    start = "10.0.0.1"
    end   = "10.0.254.254"
  }
}
resource "openstack_networking_router_v2" "external-router" {
  name                = "external-router"
  admin_state_up      = true
  external_network_id = openstack_networking_network_v2.external-network.id
}
resource "openstack_images_image_v2" "cirros" {
  name             = "cirros"
  image_source_url = "https://download.cirros-cloud.net/0.6.1/cirros-0.6.1-x86_64-disk.img"
  container_format = "bare"
  disk_format      = "qcow2"
  properties = {
    key = "value"
  }
}
resource "openstack_identity_project_v3" "demo-project" {
  name = "Demo"
}
resource "openstack_identity_user_v3" "demo-user" {
  name               = "demo-user"
  default_project_id = openstack_identity_project_v3.demo-project.id
  password = "demo"
}

Tenant terraform file

As a Tenant usually you create VMs, Network, and Security groups for your VMs.

For this example, we will use the user created above by the admins

Let’s first create a Tenant directory for your Tenant related provisioning.

$ mkdir TenantTF
$ cd TenantTF

In the main.tf

terraform {
  required_version = ">= 0.14.0"
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "1.49.0"
    }
  }
}
provider "openstack" {
  user_name   = “demo-user”
  tenant_name = “demo”
  password    = “demo”
  auth_url    = “OS_AUTH_URL”
  region      = “OS_REGION”
}
resource "openstack_compute_keypair_v2" "demo-keypair" {
  name       = "demo-key"
  public_key = "ssh-rsa ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
}


resource "openstack_networking_network_v2" "demo-network" {
  name           = "demo-network"
  admin_state_up = "true"
}
resource "openstack_networking_subnet_v2" "demo-subnet" {
  network_id = openstack_networking_network_v2.demo-network.id
  name       = "demo-subnet"
  cidr       = "192.168.26.0/24"
}
resource "openstack_networking_router_interface_v2" "demo-router-interface" {
  router_id = “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”
  subnet_id = openstack_networking_subnet_v2.demo-subnet.id
}
resource "openstack_compute_instance_v2" "demo-instance" {
  name            = "demo"
  image_id        = "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
  flavor_id       = "3"
  key_pair        = "demo-key"
  security_groups = ["default"]
  metadata = {
    this = "that"
  }
  network {
    name = "demo-network"
  }
}

Initialize your Terraform

Next after creating your terraform files you need to initialize Terraform

For Admin

$ cd AdminTF
$ terraform init
$ terraform fmt

For Tenants

$ cd TenantTF
$ terraform init
$ terraform fmt

terraform init will download the provider from the registry for us to use in provisioning that we will do for this project, terraform fmt will format the files for it to be neat if you will add it in repositories.

Create your Terraform plan

Next will be create the plan for you to see what resources will be created.

For Admin

$ cd AdminTF
$ terraform validate
$ terraform plan

For Tenants

$ cd TenantTF
$ terraform validate
$ terraform plan

terraform validate will validate the .tf files if the syntax is correct, terraform plan will create a planfile in cache where all managed resources be tracked in creation and destroy.

Apply your your first TF

Finally deploying the resources we will do <code>terraform apply</code> this will apply all states of the resources that is in the plan file.

For Admin

$ cd AdminTF
$ terraform apply

For Tenants

$ cd TenantTF
$ terraform apply

Next Steps

It took long enough previously I created an article how to deploy a minimal openstack cluster with raspberry pi, but lets see how to have more detailed Terraform and Ansible, and some CI/CD with GitLab.