- Over a Third of Firms Struggling With Shadow AI
- Most companies will increase IT spending in 2025. But there's a twist in the tale
- Generative AI in healthcare: benefits and challenges according to CIOs
- AI ed etica: la priorità è mitigare i rischi e assicurare la compliance
- “국내 포털 중 최초”···이스트에이드, 줌에 AI 검색 요약 기능 지원
Making Your First Terraform File Doesn’t Have to Be Scary
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
Share: