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
-
Provider : a provider is responsible for understanding API (of an application or cloud like OCI) and to expose/understand resources.
-
Resource : almost any infrastructure type can be represented as a resource (cloud computer instance, load balance, DNS records, etc).
Terraform's features are:
-
Infrastructure as Code
Infrastructure is described using a high-level configuration syntax.
So blueprint of a datacenter can be versioned and treated as any other code.
-
Execution Plans
Terraform has a "planning" step where it generates an execution plan.
The execution plan shows what Terraform will do when code is applied.
This is like dry run.
-
Resource Graph
Terraform builds a graph of all resources, and parallelizes the creation and modification of any non-dependent resources.
This gives insight into dependencies in the infrastructure.
-
Change Automation
Complex changes can be applied to infrastructure with minimal human interaction.
Execution plan and resource graph reads what Terraform will change and in what order.
For example, quick Ansible vs Terrafor:
- Ansible
- Does work via SSH
- It's procedural (procedural describes exact steps to be performed)
- Terraform
- Does work via provider (then via API)
- It's declarative (declarative "declares" final result or state, not the process how to get there)
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:
- Place variables in its own file, variables.tf (Terraform loads all .tf files that are present in a directory)
variable "cobbler_username" {}
variable "cobbler_password" {}
variable "cobbler_url" {default="http://cobbler-server.domain.com/cobbler_api"}
Use environment variables, since Terraform uses them like "TF_VAR_name", example here: TF_VAR_cobbler_username and TF_VAR_cobbler_password
$ export TF_VAR_cobbler_username=zarko
... do the work, then maybe remove env variable ...
$ unset TF_VAR_cobbler_username
Use command line flag -var
$ terraform plan -var 'cobbler_username=zarko'
Variables that have constant value can be in .tfvar file, example "myself.tfvars", with content cobbler_username = "zarko"
then run:
$ terraform plan -var-file=myself.tfvars
Variables can be also lists or maps.
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