Generating terraform DSL dynamically

10/28/2018

Is there some python/go library to generate Terraform code from a JSON file, or is there any templating language to generate terraform code.

Use case:

I need to register all the Kubernetes services of type node port on my cluster, on external load balancer, and there is a terraform provider for that external load balancer that takes the service and namespace name and some other parameters and registers the service on a pool, once the pool is created with correct service , and namespace name, then the load balancer automatically do discovery of nodeports and node IPs and keep the pool updated all the time. Currently, I have to edit the terraform code manually to add the service names and other stuff, to update the load balancer config to create the pool for k8s service.

Once I figure out how to generate/update the terraform file from the given state of the cluster, I will put this process as cluster daemon in a pod, that will run the script every X interval so that the load balancer is updated when users create and delete k8s services.

Example record in terraform file:

   # Pool automatically populated by K8s Service Discovery
resource "vtm_pool" "<cluster name>_<k8s namsepace>_<k8s service name>" {
  name                          = ""<cluster name>_<k8s namsepace>_<service name>""
  monitors                      = ["Ping"]
  service_discovery_enabled     = "true"
  service_discovery_interval    = "15"
  service_discovery_plugin      = "${var.k8s_discovery_plugin}"
  service_discovery_plugin_args = "-s <k8s service name > -n <k8s namsepace> -c <kubeconf file name>"
}
-- Ijaz Ahmad Khan
kubernetes
python
terraform

1 Answer

10/28/2018

Terraform has a couple of hook points that might work for you.

The overall approach you're suggesting will probably work fine. The HCL syntax itself isn't that complicated, and you could just write it out. Hashicorp has a Go library that can read and write it.

Terraform also directly supports JSON input as well. The syntax is harder to hand-write but probably easier to machine-generate. There are a couple of subtleties in how the HCL syntax converts to JSON and it's probably worth reading through that whole page (even the HCL part), but this might be easiest to machine-generate.

If I had to do this, I might reach for a Terraform external data source. That can run any program that produces JSON output, but once you have that it's "natively" in Terraform space. You could write something like (untested):

data "external" "services" {
  program = ["kubectl", "get", "service",
             "-o", "json",
             "--field-selector", "spec.type==LoadBalancer"]
}
resource "vtm_pool" "k8s_services" {
  count = "${length(data.external.services.result)}"
  name = "${data.external.services.*.metadata.name[count.index]}"
}

(In the past, I've had trouble where Terraform can get very fixated on specific indices, and so if you do something like this and the kubectl output returns the Service objects in a different order, it might want to go off and swap which load balancer is which; or if something gets deleted, every other load balancer might get reassigned.)

The "most right" (but hardest) answer would be to teach Kubernetes about your cloud load balancer. There is a standard (Go) k8s.io/cloud-provider interface you can implement, and a handful of providers in the main Kubernetes source tree. I'd guess the fake cloud provider is as good a starting point as any.

-- David Maze
Source: StackOverflow