Back to the main page

Terraform basics with Cobbler example

Intro

Terraform is a tool for building and managing/changing infrastructure. Its architecture is "client-only".
This page is about Terraform version v0.11.13 Terraform's features are:

Ansible vs Terraform

For example, quick Ansible vs Terrafor:

Terraform installation

Get zipped file from https://www.terraform.io/downloads.html and unzip it and you'll have terraform executable file, that's all. If you like, create symbolic link to this specific Terraform version.
[zdudic@admin ~]ls -la /usr/local/bin/terraform
lrwxrwxrwx 1 root root 34 Apr 24 15:44 /usr/local/bin/terraform -> /admin/terraform_0.11.13/terraform

Working directory

Same as Vagrant, you need working directory where to store files (extension .tf) and run commands.

Debugging

Do "export TF_LOG=DEBUG" , then run commands.

Example ( managing Cobbler)

Provider

The provider for Cobbler is used to interact with Cobbler machine, hence correct credentials are needed so it can be used.
The working directory is /home/terraform/cobbler and file is cobbler.tf.

variable "cobbler_username" {default="zarko"}
variable "cobbler_password" {default="some-password"}
variable "cobbler_url" {default="http://cobbler-server.domain.com/cobbler_api"}
provider "cobbler" {
  username = "${var.cobbler_username}"
  password = "${var.cobbler_password}"
  url      = "${var.cobbler_url}"
  insecure = true
}

Initialization

Once there is new provider in configuration, it has to be initialized before use. Initialization downloads and installs the provider's plugin and prepares it to be used.
#  terraform init 
 
Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "cobbler" (1.0.1)...
...
 
* provider.cobbler: version = "~> 1.0"
 
Terraform has been successfully initialized!
... 
In working directory, this creates sub-dirs .terraform/plugins/linux_amd64/ with files lock.json and terraform-provider-cobbler_v1.0.1_x4

Variables

The cobbler.tf file defines some variables, before "provider" block. In that example, username/password is hard coded, not safe. If I want to be prompted for these, I can remove default value, hence will read:
 
variable "cobbler_username" {}
variable "cobbler_password" {}
Other ideas:

Resources

Distro

Not really useful, it requires running 'cobbler import' which actually does whole work.

Profile

This is resource for creating a profile, attended installation for ol7.5, meaning the provided kickstart file is empty. Add this code in cobbler.tf file.

resource "cobbler_profile" "OL-R7-U5-x86_64_attended" {
  name   = "OL-R7-U5-x86_64_attended"
  distro = "OL-R7-U5-x86_64"
  kickstart = "/var/lib/cobbler/kickstarts/default.ks"
}

Kickstart file

This resource creates a kickstart file on the Cobbler server. Add this code also in cobbler.tf file.

# Create a Cobbler ks
resource "cobbler_kickstart_file" "terraform-ks" {
  name = "/var/lib/cobbler/kickstarts/terraform-ks"
  body = <<-EOF
install
text
url --url=http://x.x.x.x/cobbler/links/OL-R7-U3-x86_64
network --device eth0 --bootproto static --ip x.x.x.x --netmask x.x.x.0 --gateway x.x.x.1 --nameserver x.x.x.x --hostname 
rootpw strong-passwd
firewall --disabled
authconfig --enableshadow --enablemd5
selinux --disabled
timezone --utc America/Los_Angeles
reboot
       EOF
}

Implementation

Once all .tf files are ready (provider, variables, resources), next commands can be run (all in the working directory).

Validate

To validate cobbler.tf file.

# terraform validate

Plan

Plan execution (dry run), note that "+" means addition, in this output only ks will be added.

#  terraform plan 
..
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:
   + cobbler_kickstart_file.terraform-test-ks
      id:   
      body: "install\ntext\nurl --url=http://x.x.x.x/cobbler/links/OL-R7-U3-x86_64\nnetwork 
             --device eth0 --bootproto static --ip x.x.x.x --netmask x.x.x.0 --gateway x.x.x.1 --nameserver x.x.x.x 
             --hostname \nrootpw strong-passwd\nfirewall --disabled\nauthconfig --enableshadow --enablemd5\nselinux 
             --disabled\ntimezone --utc America/Los_Angeles\nreboot\n"
      name: "/var/lib/cobbler/kickstarts/terraform-ks"
   
Plan: 1 to add, 0 to change, 0 to destroy.

Graph

"Graph" it.

#  terraform graph 
digraph {
        compound = "true"
        newrank = "true"
        subgraph "root" {
                "[root] cobbler_kickstart_file.terraform-test-ks" [label = "cobbler_kickstart_file.terraform-test-ks", shape = "box"]
                "[root] provider.cobbler" [label = "provider.cobbler", shape = "diamond"]
                "[root] cobbler_kickstart_file.terraform-test-ks" -> "[root] provider.cobbler"
                "[root] meta.count-boundary (count boundary fixup)" -> "[root] cobbler_kickstart_file.terraform-test-ks"
                "[root] provider.cobbler (close)" -> "[root] cobbler_kickstart_file.terraform-test-ks"
                "[root] provider.cobbler" -> "[root] var.cobbler_password"
                "[root] provider.cobbler" -> "[root] var.cobbler_url"
                "[root] provider.cobbler" -> "[root] var.cobbler_username"
                "[root] root" -> "[root] meta.count-boundary (count boundary fixup)"
                "[root] root" -> "[root] provider.cobbler (close)"
        }
}

Apply

Apply change.

# terraform apply

var.cobbler_password
  Enter a value: some-passwd

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:

  + cobbler_kickstart_file.terraform-test-ks
      id:   
      body: "install\ntext\nurl --url=http://x.x.x.x/cobbler/links/OL-R7-U3-x86_64\nnetwork --device eth0 
            --bootproto static --ip x.x.x.x --netmask x.x.x.0 --gateway x.x.x.1 --nameserver x.x.x.x --hostname \nrootpw strong-passwd\nfirewall 
            --disabled\nauthconfig --enableshadow --enablemd5\nselinux --disabled\ntimezone --utc America/Los_Angeles\nreboot\n"
      name: "/var/lib/cobbler/kickstarts/terraform-ks"

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

cobbler_kickstart_file.terraform-test-ks: Creating...
  body: "" => "install\ntext\nurl --url=http://x.x.x.x/cobbler/links/OL-R7-U3-x86_64\nnetwork --device eth0 
          --bootproto static --ip x.x.x.x --netmask x.x.x.0 --gateway x.x.x.1 --nameserver x.x.x.x 
          --hostname \nrootpw strong-passwd\nfirewall --disabled\nauthconfig --enableshadow --enablemd5\nselinux 
          --disabled\ntimezone --utc America/Los_Angeles\nreboot\n"
  name: "" => "/var/lib/cobbler/kickstarts/terraform-ks"
cobbler_kickstart_file.terraform-test-ks: Creation complete after 0s (ID: /var/lib/cobbler/kickstarts/terraform-ks)

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

State file

The file terraform.tfstate is created in the working directory, and "show" argument can read that state of infrastructure.
So if many people collaborate, have this file on NFS share or cloud (like OCI) object storage (accessible via http)
   # terraform show 

cobbler_kickstart_file.terraform-test-ks:
  id = /var/lib/cobbler/kickstarts/terraform-ks
  body = install
text
url --url=http://x.x.x.x/cobbler/links/OL-R7-U3-x86_64
network --device eth0 --bootproto static --ip x.x.x.x --netmask x.x.x.0 --gateway x.x.x.1 --nameserver x.x.x.x --hostname
rootpw strong-passwd
firewall --disabled
authconfig --enableshadow --enablemd5
selinux --disabled
timezone --utc America/Los_Angeles
reboot

  name = /var/lib/cobbler/kickstarts/terraform-ks
If I remove this ks file from infrastructure code, and run "terraform plan", it's expected to see 'destroy' action :
 
Resource actions are indicated with the following symbols:
  - destroy
Terraform will perform the following actions:
  - cobbler_kickstart_file.terraform-ks
Let's apply that, and now 'show' reads nothing, or something without this ks file.

State file is backed up into terraform.tfstate.backup, hence state change can be seen like:
 
# diff terraform.tfstate terraform.tfstate.backup
12c12,29
<             "resources": {},
---
>             "resources": {
>                 "cobbler_kickstart_file.terraform-ks": {
>                     "type": "cobbler_kickstart_file",
>                     "depends_on": [],
>                     "primary": {
>                         "id": "/var/lib/cobbler/kickstarts/terraform-ks",
>                         "attributes": {
>                             "body": "install\ntext\nurl --url=http://x.x.x.x/cobbler/links/OL-R7-U3-x86_64\nnetwork --device eth0 
>                                     --bootproto static --ip x.x.x.x --netmask x.x.x.0 --gateway x.x.x.1 --nameserver x.x.x.x 
>                                     --hostname \nrootpw strong-passwd\nfirewall --disabled\nauthconfig --enableshadow --enablemd5\nselinux 
>                                     --disabled\ntimezone --utc America/Los_Angeles\nreboot\n",
>                             "id": "/var/lib/cobbler/kickstarts/terraform-ks",
>                             "name": "/var/lib/cobbler/kickstarts/terraform-ks"
>                         },
>                         "meta": {},
>                         "tainted": false
>                     },
>                     "deposed": [],
>                     "provider": "provider.cobbler"
>                 }
>             },


Back to the main page