It has been awhile since I have played with Terraform and I was recently investigating on whether I could use Terraform to automate the activation of the Tanzu Kubernetes Grid (TKG) Service on a VMware Cloud on AWS SDDC, which is a part of VMware's new managed Kubernetes offering called VMware Cloud with Tanzu services. Although there is an existing VMware Cloud on AWS (VMC-A) Terraform provider, it currently does not support configuring or managing the TKG Service.
Today, customers can automate VMware Cloud with Tanzu services with a simple REST API and with that in mind, I was curious if calling into a REST API using Terraform was even a thing? While searching online, I not only came to find out that directly calling a REST API using Terraform was a thing but that there were actually a few Terraform providers that enabled this capability. The most popular being Mastercard's Restapi Terraform provider, which was also updated just a couple of weeks ago.
I ended up learning a ton more about Terraform through this exercise and the final solution has been contributed to Ryan Johnson's amazing VMware Terraform Examples repo. I also have to give a huge shoutout to Ryan, who I consider one of the experts in the community for all things VMware and Terraform! I was also able to bounce some ideas and also learn a few new tricks in one of our recent conversations.
Background
If you are interested in the details on how I leveraged Mastercard's Restapi Terraform provider, the following section will break down the main.tf file which contains all the business logic for calling into VMware Cloud with Tanzu services REST API. If you are just interested in just using the solution, jump down further in the blog post on how to get started.
L13-24 - Here we are creating the restapi provider object to represent the API calls directed to the VMware Cloud Services Platform (CSP) which is required to translate our VMware Cloud Refresh Token into a usable Access Token for subsequent API calls. Since we will be calling two different VMware Cloud API endpoints, we are also using the alias reference feature in Terraform, so we can refer to the specific restapi resource in sub-sequent calls. In the example below, the alias is called "csp" and the URI is defined within the variables.tf file and must contain only the base URL.
provider "restapi" { alias = "csp" uri = var.csp_uri debug = var.debug write_returns_object = true headers = { Content-Type = "application/x-www-form-urlencoded" } create_method = "POST" }
L27-32 - Here we are creating the restapi resource that will perform the POST request (defined in our provider) to the specific URL path of our API including our VMware Cloud Refresh Token payload. One thing that I found that was required for the resource was to assign some ID and since the return payload does not contain any unique identifier, I ended up using the expires_in value from the JSON payload. There maybe a more ideal method here such as auto-generating some random number to assign.
resource "restapi_object" "retrieve_access_token" { provider = restapi.csp path = "/csp/gateway/am/api/auth/api-tokens/authorize?refresh_token=${var.refresh_token}" data = "" id_attribute = "expires_in" }
L37-47 - Here we are creating the restapi provider object to represent the API calls directed to the VMware Cloud API which includes retrieving the vSphere Cluster ID that we wish to activate our TKG Service and then finally the actual activation. For the alias, we have named this "vmc" and and the URI is defined within the variables.tf file. We also need to add some additional headers including our CSP authorization Access Token from the above resource.
provider "restapi" { alias = "vmc" uri = var.vmc_uri debug = var.debug write_returns_object = true headers = { csp-auth-token = restapi_object.retrieve_access_token.api_data.access_token Content-Type = "application/json" } }
L50-57 - Here we are creating the restapi resource that will perform a GET request for the desired VMC-A SDDC matching the user provided sddc_id variable. The depends_on parameter is used to ensure that we have a VMC Access Token before proceeding.
resource "restapi_object" "get_sddc_cluster" { depends_on = [restapi_object.retrieve_access_token] create_method = "GET" provider = restapi.vmc path = "/vmc/api/orgs/${var.org_id}/sddcs/${var.sddc_id}" data = "" }
L60-62 - Here we define a local variable that is used to store the vSphere Cluster ID that matches the user provided cluster_name variable. We also make use of the output object, so that we can easily debug and view the value from this filter.
locals { cluster_id = [for cluster in jsondecode(restapi_object.get_sddc_cluster.api_response).resource_config.clusters : cluster.cluster_id if cluster.cluster_name == var.cluster_name][0] } output "debug_cluster_id" { value = local.cluster_id }
L69-76 - Here we are creating the final restapi resource that will perform a POST request to activate the TKG Service. The depends_on parameter is also used to ensure that both the VMC Access Token and vSphere Cluster ID values exists before proceeding to this step. In addition to the specific URI path of the API to enable TKG Service, we also need to provide the required JSON payload which contains four parameters: ingress_cidr, egress_cidr, service_cidr and namespace_cidr. Details of these parameters are defined in the variables.tf file and is the exact same input required when activating TKG Service using the VMC Console.
resource "restapi_object" "activate_tanzu_service" { depends_on = [restapi_object.retrieve_access_token, local.cluster_id] create_method = "POST" provider = restapi.vmc path = "/api/wcp/v1/orgs/${var.org_id}/deployments/${var.sddc_id}/clusters/${local.cluster_id}/operations/enable-wcp" data = "{\"ingress_cidr\":[\"${var.ingress_cidr}\"],\"egress_cidr\": [\"${var.egress_cidr}\"],\"service_cidr\": \"${var.service_cidr}\",\"namespace_cidr\": [\"${var.namespace_cidr}\"]}" }
L78-80 - Here we construct the output to show the VMC Task Id that is returned upon starting the TKG Service activation which can be used to track further progress or you can simply watch the VMC Console.
output "tanzu_service_activation_task" { value = restapi_object.activate_tanzu_service.api_data }
Getting Started
If you are interested in just using the Terraform automation, the following section will help you get started:
Step 1 - Either clone or manually download the terraform-examples-vmware repo to your local system and the change into terrafom-examples-vmware/vmware-cloud/vmc-activate-tanzu-service directory.
git clone https://github.com/tenthirtyam/terrafom-examples-vmware.git
Step 2 - Make a copy of the terraform.tfvars.example file and update the variables with the values within your VMC-A environment.
cp terraform.tfvars.example terraform.tfvars
Step 3 - Initialize the directory which will automatically pull down the required Terraform providers.
terraform init
Step 4 - Next, run run the validate command to verify that our input is good before proceeding to next step.
terraform validate
Step 5 - Lets now run plan command to evaluate our desired resources and the expected outputs.
terraform plan
Step 6 - If the previous operation did not have any issues, we are now ready to run the apply command which will start the activation of the TKG Service on our VMC-A SDDC Cluster.
terraform apply -auto-approve
If the operation was successful, you will see task output while TKG Service is activating. You can navigate to the VMC Console and wait for the operation to complete which can take ~30 minutes or so.
Hopefully the ability to activate the TKG Service for a VMC SDDC will be possible in the future using the VMC Terraform provider, but in the mean time, hopefully this was a good example demonstrating how you can incorporate imperative automation and calling specific REST API directly within Terraform.
Paul Turner says
I like it. Great example of the power of Ryan’s work on terraform toolkit.