How to install your own Terraform provider in IBM Cloud Automation Manager

Originally posted on IBM Cloud Automation Manager blog by Hendrik van Run on 25 July 2019

Disclaimer: Although this blog post was created by Hendrik van Run, it reflects the work done by Jonathon Goldsworthy on a client project!

Introduction

Out of the box, IBM Cloud Automation Manager (CAM) ships with a number of Terraform providers. This is great to get started and handles common use-cases. IBM also provides support should you encounter any issues. However often there are cases where you need to use one or more Terraform providers that are not installed in CAM by default. Hashicorp has endorsed a growinglist of Terraform providers, which can be found here.

Let’s assume that you have CAM installed and need to import one of those Terraform providers, for example the F5 BIG-IP one. This can be used to automate creation of resources on a Big IP F5 solution, for example to manage Virtual IP (VIP) addresses for load balancing purposes. The steps below outline exactly what you need to do in order to start using the F5 BIG-IP Terraform provider with CAM.

Downloading and building the Terraform provider

Preparation

The F5 BIG-IP Terraform provider is available from github.com here. But before we proceed, please make sure to review README.md of the Big IP F5 Terrarform provider. Note that it requires Go 1.11 (or higher) to build the provider, and Terraform 0.10.x (or higher) to use the Terraform provider.

As documented here in the IBM Knowledge Center, CAM 3.1.2.1 uses Terraform 11.11. So we meet the mimimum version requirements of the F5 BIG-IP Terraform provider.

We also need a machine where we can build the Terraform provider. This is typically a linux server, but note that it must match the OS and processor architecture of the servers hosting your IBM Cloud Private and CAM environmen! You will need internet connectivity in order to be able to download Go itself and the Terraform provider files from github.com. On this machine, we will need to make sure that Go 1.11 (or higher) is installed. In this blog post, we are using an Ubuntu server that does not have Go installed yet.

Download and install Go

Depending on the OS you are using, the instructions to install Go will vary. As we were using Ubuntu linux, we downloaded the .tar.gz file directly from the server and installed it:

root@tfbuild:/tmp# wget https://dl.google.com/go/go1.12.6.linux-amd64.tar.gz
root@tfbuild:/tmp# tar -C /usr/local -xzf /tmp/go1.12.6.linux-amd64.tar.gz

We now have Go installed, but we need to update the PATH:

root@tfbuild:/tmp# export PATH=$PATH:/usr/local/go/bin

Now run go version to confirm what version you have installed:

root@tfbuild:~# go version
go version go1.12.6 linux/amd64

This confirms that we just installed Go 1.12.6, so we meet the minimum version requirements to build the F5 BIG-IP Terraform provider!

Download and build the provider

A few preparatory steps are required.

To prepare the provider(s) in a specific directory on your linux server, such as your home directory, type the following:

root@tfbuild:~# mkdir go
root@tfbuild:~# echo $HOME
/root
root@tfbuild:~# export GOPATH=$HOME/go
root@tfbuild:~# cd $GOPATH
root@tfbuild:~/go# pwd
/root/go

You should now be in a subdirectory of your home directory, called go, with GOPATH set to this same directory. You will now create a subdirectory for your providers and change to it:

root@tfbuild:~/go# mkdir -p $GOPATH/src/github.com/terraform-providers
root@tfbuild:~/go# cd $GOPATH/src/github.com/terraform-providers
root@tfbuild:~/go/src/github.com/terraform-providers# pwd
/root/go/src/github.com/terraform-providers

Next, you will download the F5 provider:

root@tfbuild:~/go/src/github.com/terraform-providers# git clone https://github.com/terraform-providers/terraform-provider-bigip
Cloning into 'terraform-provider-bigip'...
remote: Enumerating objects: 13, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 12820 (delta 1), reused 5 (delta 0), pack-reused 12807
Receiving objects: 100% (12820/12820), 56.24 MiB | 9.73 MiB/s, done.
Resolving deltas: 100% (7321/7321), done.

Change to the provider directory and build it:

root@tfbuild:~/go/src/github.com/terraform-providers# cd terraform-provider-bigip/
root@tfbuild:~/go/src/github.com/terraform-providers/terraform-provider-bigip# make build
==> Checking that code complies with gofmt requirements...
go install

This will have built the provider and placed it in the $GOPATH/bin directory:

root@tfbuild:~/go/src/github.com/terraform-providers/terraform-provider-bigip# ls -rtl $GOPATH/bin
total 33980
-rwxr-xr-x 1 root root 34793179 Jul  4 07:20 terraform-provider-bigip

You should see a file of approximately 34 MB, named terraform-provider-bigip.

Importing your Terraform provider into CAM

Review the instructions in the CAM KnowledgeCenter for importing your own Terraform provider here. You will need to logon to the IBM Cloud Private cluster where you installed CAM cluster in order to import the new Terraform provider. We assume that you have both the cloudctl IBM Cloud Private CLI as well as the kubectl Kubernetes CLI installed on the machine where you built the Terraform provider. Please refer to the IBM Knowledge Center on how to install the cloudctl IBM Cloud Private CLI as well as the kubectl Kubernetes CLI.

First logon to the IBM Cloud Private cluster using cloudctl, note that you need to logon with a user that has administrative permissions. Enter your user name and password, and when you are given a choice of namespaces, type the number next to “services”.
This ensures that all your future kubectl commands are simplified, since they’ll only look at the services namespace, which is where CAM is installed.

root@tfbuild:~# cloudctl login -a https://<ICP_master>:8443Username> admin
Password>
Authenticating...
OK
Targeted account mycluster Account (id-mycluster-account)
Select a namespace:
1. cert-manager
2. default
3. ibmcom
4. icamserver
5. icp
6. kube-public
7. kube-system
8. platform
9. services
Enter a number> 9
Targeted namespace services
Configuring kubectl ...
Cluster "mycluster" set.
User "mycluster-user" set.
Context "mycluster-context" created.
Switched to context "mycluster-context".
OK
Configuring helm: /root./.helm
OK

Now use kubectl to identify the CAM provider pod and copy the new Terraform provider directly into the Terraform plugins directory of that pod:

root@tfbuild:~# kubectl cp terraform-provider-bigip $(kubectl get pods | grep cam-provider-terraform | awk '{print $1;}' | head -n 1):/home/terraform/.terraform.d/plugins/

If you have not logged into the namespace “services”, you will need to add  -n services  to both of the kubectl commands above. Of course the name of the file terraform-provider-bigip is our F5 BIG-IP Terraform provider, should you be using a different Terraform provider you would need to change the command accordingly.

Only a few more commands are required to set the correct ownership and permissions of the Terraform provider file inside the CAM provider pod:

root@tfbuild:~# kubectl exec $(kubectl get pods | grep cam-provider-terraform | awk '{print $1;}' | head -n 1) chown terraform:terraform /home/terraform/.terraform.d/plugins/terraform-provider-bigip
root@tfbuild:~# kubectl exec $(kubectl get pods | grep cam-provider-terraform | awk '{print $1;}' | head -n 1) chmod +x /home/terraform/.terraform.d/plugins/terraform-provider-bigip

You can run the command below to confirm that the permissions on the Terraform provider file, if it looks as shown below we are all set!

root@tfbuild:~# kubectl exec $(kubectl get pods | grep cam-provider-terraform | awk '{print $1;}' | head -n 1) -- ls -l /home/terraform/.terraform.d/plugins/terraform-provider-bigip
-rwxr-xr-x 1 terraform terraform 0 Jul  4 21:55 /home/terraform/.terraform.d/plugins/terraform-provider-bigip

Using the new Terraform provider in CAM

With the F5 BIG-IP Terraform provider in place, we can now start creating new Terraform templates in CAM. As usual, you can either use the CAM Template Designer or your own text editor to create the templates. Refer to the documentation of the F5 BIG-IP Terraform provider for details on what resources are supported. Below is an example of a simple main.tf Terraform template that automates the creation of a new Virtual IP address (VIP).

main.tf

provider "bigip" {
  username = "${var.f5_username}"
  password = "${var.f5_password}"
  address  = "${var.f5_address}"
}

resource "bigip_ltm_virtual_server" "vip" {
  name                       = "/_${var.vrf}/${var.vip_name}_VIP"
  port                       = "${var.vip_port}"
  source                     = "0.0.0.0/0"
  destination                = "${var.vip_destination_ip}"
  pool                       = "/_${var.vrf}/${var.vip_name}_Pool"
    mask                       = "255.255.255.255"
  profiles                   = ["/Common/tcp"]
  persistence_profiles       = ["/Common/tcp"]
  source_address_translation = "snat"
  snatpool                   = "/_${var.vrf}/${var.vip_name}_SNAT"
  ip_protocol                = "tcp"
  vlans                      = ["/_${var.vrf}/${var.vip_vlan}"]
  translate_address          = "enabled"
  translate_port             = "enabled"
  vlans_enabled              = "true"
}

Note that we used a number of variables defined in variables.tf, which can easily be exposed by defining CAM variables through camvariables.json as documented here in the IBM Cloud Automation Knowledge Center.

variables.tf

##################### Variables ###############################
## Provider connection variables ##

variable "f5_username" {
  description = "F5 BIGIP user name"
}

variable "f5_password" {
  description = "F5 BIGIP user password"
}

variable "f5_address" {
  description = "F5 BIGIP Address"
}

## Other variables ## 

variable "tn_name" {
  description = "Tenant name"
  default     = "XYZ_PROD"
}

variable "vrf" {
  description = "VRF identifier"
  default     = "INT"
}

variable "vip_name" {
  description = "Virtual server name"
}

variable "vip_port" {
  description = "Virtual server port number"
  default     = "80"
}

variable "vip_destination_ip" {
  description = "Virtual server destination IP address"
  type        = "string"
}

variable "vip_vlan" {
  description = "Virtual server VLAN"
  default     = "VLAN_1234"
}

Leave a comment

Design a site like this with WordPress.com
Get started