tf-bindgen 0.1.0

Automatically generates Rust bindings for Terraform providers.
Documentation
# Complex Resources

While creating a Docker image and container is straight forward, it may become a bit harder than using heavily nested resources (e.g. Kubernetes resources). In this section, we will create a Kubernetes pod with a NGINX container running inside. It will be equivalent to the following HCL code:

```terraform
terraform {
	required_providers = {
		kubernetes = {
			source = "kubernetes"
			version = "3.0.2"
		}
	}
}

provider "kubernetes" {
	config_path = "~/.kube/config"
}

resource "kubernetes_pod" "nginx" {
	metadata {
		name = "nginx"
	}
	spec {
		container {
			name = "nginx"
			image = "nginx"
			port {
				container_port = 80
			}
		}
	}
}
```

Similar to the docker example in the previous section, we need to add our dependencies:

```sh
cargo add --git https://github.com/robert-oleynik/tf-bindgen
cargo add --git https://github.com/robert-oleynik/tf-kubernetes
```

In this case, we will use the Kubernetes bindings instead of the Docker bindings. We also will start similar to the docker example by setting up our stack and Kubernetes provider:

```rust
use tf_bindgen::Stack;
use tf_kubernetes::Kubernetes;
use tf_kubernetes::resource::kubernetes_pod::*;

let stack = Stack::new("postgres");

Kubernetes::create(&stack)
	.config_path("~/.kube/config")
	.build();
```

## Create a Complex Resource

You have already seen how to set attributes of Terraform resources. We will use the same setters, like `config_path`, to set our nested structures. Important is that we have to create these nested structures, before we can pass them to the setter.

```rust
let metadata = KubernetesPodMetadata::builder()
	.name("nginx")
	.build();
```

As this snippet shows, the exposed builder will not need a scope or an ID to create a nested type. In addition, we will not use `create` but rather `builder` to create our builder object.

We can repeat this for our nested type `spec` :

```rust
let port = KubernetesPodSpecContainerPort::builder()
	.container_port(80)
	.build();
let container = KubernetesPodSpecContainer::builder()
	.name("nginx")
	.image("nginx")
	.port(port)
	.build();
let spec = KubernetesPodSpec::builder()
	.container(vec![container])
	.build();
```

You can notice a few things:

- Nested types of nested types will be created using the same builder pattern,
- they can be passed using the setter, and
- we can pass multiple nested types by using an array (in our case using `vec!`).

To finalize it, we can use our created `metadata` and `spec` object and pass it to our Kubernetes pod resource:

```rust
KubernetesPod::create(&stack, "nginx")
	.metadata(metadata)
	.spec(spec)
	.build();
```

## Using `tf_bindgen::codegen::resource`

While using builder is a nice way to set these attributes and allows very flexible code, using multiple builders in a row result in higher complexity than using HCL. That is the reason we implemented `tf_bindgen::codegen::resource` macro. It allows using a simplified HCL syntax to create resources. Our Kubernetes pod resource using this macro would look like:

```rust
tf_bindgen::codegen::resource! {
	&stack,
	resource "kubernetes_pod" "nginx" {
		metadata {
			name = "nginx"
		}
		spec {
			container {
				name = "nginx"
				image = "nginx"
				port {
					container_port = 80
				}
			}
		}
	}
}
```

This macro use the same builders as shown in the section before and will return the resulting resource.