Avatar

For the past several years, I’ve tried to give at least one Terraform-centric session at Cisco Live. That’s because they’re fun and make for awesome demos. What’s a technical talk without a demo? But I also see huge crowds every time I talk about Terraform. While I wasn’t an economics major, I do know if demand is this large, we need a larger supply!

That’s why I decided to step back and focus to the basics of Terraform and its operation. The configuration applied won’t be anything complex, but it should explain some basic structures and requirements for Terraform to do its thing against a single piece of infrastructure, Cisco ACI. Don’t worry if you’re not an ACI expert; deep ACI knowledge isn’t required for what we’ll be configuring.

The HCL File: What Terraform will configure

A basic Terraform configuration file is written in Hashicorp Configuration Language (HCL). This domain-specific language (DSL) is similar in structure to JSON, but it adds components for things like control structures, large configuration blocks, and intuitive variable assignments (rather than simple key-value pairs).

At the top of every Terraform HCL file, we must declare the providers we’ll need to gather from the Terraform registry. A provider supplies the linkage between the Terraform binary and the endpoint to be configured by defining what can be configured and what the API endpoints and the data payloads should look like. In our example, we’ll only need to gather the ACI provider, which is defined like this:

terraform {

  required_providers {

    aci = {

      source = “CiscoDevNet/aci”

    }

  }

}

Once you declare the required providers, you have to tell Terraform how to connect to the ACI fabric, which we do through the provider-specific configuration block:

provider "aci" {

username = "admin"

password = "C1sco12345"

url      = "https://10.10.20.14"

insecure = true

}

Notice the name we gave the ACI provider (aci) in the terraform configuration block matches the declaration for the provider configuration. We’re telling Terraform the provider we named aci should use the following configuration to connect to the controller. Also, note the username, password, url, and insecure configuration options are nested within curly braces { }. This indicates to Terraform that all this configuration should all be grouped together, regardless of whitespaces, indentation, or the use of tabs vs. spaces.

Now that we have a connection method to the ACI controller, we can define the configuration we want to apply to our datacenter fabric. We do this using a resource configuration block. Within Terraform, we call something a resource when we want to change its configuration; it’s a data source when we only want to read in the configuration that already exists. The configuration block contains two arguments, the name of the tenant we’ll be creating and a description for that tenant.

resource "aci_tenant" "demo_tenant" {

name        = "TheU_Tenant"

description = "Demo tenant for the U"

}

Once we write that configuration to a file, we can save it and begin the process to apply this configuration to our fabric using Terraform.

The Terraform workflow: How Terraform applies configuration

Terraform’s workflow to apply configuration is straightforward and stepwise. Once we’ve written the configuration, we can perform a terraform init, which will gather the providers from the Terraform registry who have been declared in the HCL file, install them into the project folder, and ensure they are signed with the same PGP key that HashiCorp has on file (to ensure end-to-end security). The output of this will look similar to this:

[I] theu-terraform » terraform init


Initializing the backend...


Initializing provider plugins...

- Finding latest version of ciscodevnet/aci...

- Installing ciscodevnet/aci v2.9.0...

- Installed ciscodevnet/aci v2.9.0 (signed by a HashiCorp partner, key ID 433649E2C56309DE)


Partner and community providers are signed by their developers.

If you'd like to know more about provider signing, you can read about it here:

https://www.terraform.io/docs/cli/plugins/signing.html


Terraform has created a lock file .terraform.lock.hcl to record the provider

selections it made above. Include this file in your version control repository

so that Terraform can guarantee to make the same selections by default when

you run "terraform init" in the future.


Terraform has been successfully initialized!

You may now begin working with Terraform. Try running “terraform plan” to see any changes required for your infrastructure. All Terraform commands should now work.

If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.

Once the provider has been gathered, we can invoke terraform plan to see what changes will occur in the infrastructure prior to applying the config. I’m using the reservable ACI sandbox from Cisco DevNet  for the backend infrastructure but you can use the Always-On sandbox or any other ACI simulator or hardware instance. Just be sure to change the target username, password, and url in the HCL configuration file.

Performing the plan action will output the changes that need to be made to the infrastructure, based on what Terraform currently knows about the infrastructure (which in this case is nothing, as Terraform has not applied any configuration yet). For our configuration, the following output will appear:

[I] theu-terraform » terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:

 + create

Terraform will perform the following actions:


# aci_tenant.demo_tenant will be created

+ resource "aci_tenant" "demo_tenant" {

+ annotation                    = "orchestrator:terraform"

+ description                   = "Demo tenant for the U"

+ id                            = (known after apply)

+ name                          = "TheU_Tenant"

+ name_alias                    = (known after apply)

+ relation_fv_rs_tenant_mon_pol = (known after apply)

}


Plan: 1 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if

you run "terraform apply" now.

We can see that the items with a plus symbol (+) next to them are to be created, and they align with what we had in the configuration originally. Great!  Now we can apply this configuration. We perform this by using the terraform apply command. After invoking the command, we’ll be prompted if we want to create this change, and we’ll respond with “yes.”

[I] theu-terraform » terraform apply                                                      


Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the

following symbols:

  + create


Terraform will perform the following actions:


  # aci_tenant.demo_tenant will be created

  + resource "aci_tenant" "demo_tenant" {

      + annotation                    = "orchestrator:terraform"

      + description                   = "Demo tenant for the U"

      + id                            = (known after apply)

      + name                          = "TheU_Tenant"

      + name_alias                    = (known after apply)

      + relation_fv_rs_tenant_mon_pol = (known after apply)

    }


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


aci_tenant.demo_tenant: Creating...

aci_tenant.demo_tenant: Creation complete after 3s [id=uni/tn-TheU_Tenant]


Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

The configuration has now been applied to the fabric!  If you’d like to verify, log in to the fabric and click on the Tenants tab. You should see the newly created tenant.

Finally – if you’d like to delete the tenant the same way you created it, you don’t have to create any complex rollback configuration. Simply invoke terraform destroy from the command line. Terraform will verify the state that exists locally within your project aligns with what exists on the fabric; then it will indicate what will be removed. After a quick confirmation, you’ll see that the tenant is removed, and you can verify in the Tenants tab of the fabric.

[I] theu-terraform » terraform destroy                                                    

aci_tenant.demo_tenant: Refreshing state... [id=uni/tn-TheU_Tenant]


Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the

following symbols:

  - destroy


Terraform will perform the following actions:


  # aci_tenant.demo_tenant will be destroyed

  - resource "aci_tenant" "demo_tenant" {

      - annotation  = "orchestrator:terraform" -> null

      - description = "Demo tenant for the U" -> null

      - id          = "uni/tn-TheU_Tenant" -> null

      - name        = "TheU_Tenant" -> null

    }



Plan: 0 to add, 0 to change, 1 to destroy.


Do you really want to destroy all resources?

  Terraform will destroy all your managed infrastructure, as shown above.

  There is no undo. Only 'yes' will be accepted to confirm.


  Enter a value: yes


aci_tenant.demo_tenant: Destroying... [id=uni/tn-TheU_Tenant]

aci_tenant.demo_tenant: Destruction complete after 1s


Destroy complete! Resources: 1 destroyed.

Complete Infrastructure as Code lifecycle management with a single tool is pretty amazing, huh?

A bonus tip

Another tip regarding Terraform and HCL relates to the workflow section above. I described the use of curly braces to avoid the need to ensure whitespace is correct or tab width is uniform within the configuration file. This is generally a good thing, as we can focus on what we want to deploy rather than minutiae of the config. However, sometimes it helps when you format the configuration in a way that’s aligned and easier to read, even if it doesn’t affect the outcome of what is deployed.

In these instances, you can invoke terraform fmt within your project folder, and it will automatically format all Terraform HCL files into aligned and readable text. You can try this yourself by adding a tab or multiple spaces before an argument or maybe between the = sign within some of the HCL. Save the file, run the formatter, and then reopen the file to see the changes. Pretty neat, huh?

Want to know more?

For a deeper dive beyond this introductory video, I have several Terraform videos on our YouTube channel that dive into more complex configurations as well as other options that exist within Terraform. You can also watch the video below, which offers sample code links to get your hands dirty with Terraform.

As always, if you have any questions, drop them in the comments below or find me on Twitter @qsnyder.

 

Join the Cisco Learning Network today for free.

Follow Cisco Learning & Certifications

Twitter | Facebook | LinkedIn | Instagram | YouTube

Use #CiscoCert to join the conversation.

 

Read next: Introduction to Terraform with Cisco ACI, Part 1 by Conor Murphy


Authors

Quinn Snyder

Senior Technical Advocate

Learning & Certifications