HomeGuidesAPI Reference
GuidesAPI ReferenceGitHubAirheads Developer CommunityLog In

Getting Started with Terraform and AOS-CX

Terraform is a relatively new stateful open-source infrastructure as code tool created by Hashicorp. It allows users to define resources and infrastructure in declarative configuration files to build, change, and version infrastructure. Terraform is very popular in the data center environment due to it's human readable syntax and it's ability to provision across multiple cloud and on premises systems. It is considered one of the more advanced frameworks for orchestration and infrastructure.

How Terraform Works

Terraform uses a high-level configuration language called HashiCorp Configuration Language (HCL) to define a desired end state in configuration files. Terraform requires two input sources:

  • Terraform Configuration: User defines what needs to be configured or provisioned and their desired state
  • Terraform State: Current state of devices/infrastructure

The Terraform configuration files use "providers" created by vendors to define resources that allow the tool to communicate and configure the infrastructure.

Terraform uses a declarative approach and determines what actions to take based on the current state devices are in compared to what is defined in the TF (Terraform) configuration files. It does this by executing the following stages:

  • Refresh: TF will query the infrastructure provider to get the current state.
  • Plan: TF will create an execution plan based on the difference between the defined configuration and the current state.
  • Apply: TF will execute the plan and save the details of the provisioned resources.
  • Destroy (optional): TF will destroy the resources/infrastructure, it works similar to "Apply" in which it will get the current state and then create/execute a plan to remove the resources.

It is recommended to follow HashiCorp's documentation that explains all the different components of Terraform and how to get started to provision your infrastructure.

Installing Terraform

❗️

Refer to Terraform Installation Guide

Please refer to the Terraform Installation Guide for up-to-date information regarding installation, or if you are having trouble installing Terraform.

Using the AOS-CX Terraform Provider

👍

AOS-CX Terraform Provider now available on the Terraform Registry!

Information including latest version and documentation can be found here!

The Terraform Provider for AOS-CX provides a set of configuration management modules and resources specifically designed to manage/configure AOS-CX switches using REST API. Similar to that of our AOS-CX Ansible Collection, the provider is organized by resources that are feature specific. Users will define these resources as well as the switch connection information in their Terraform state file, and Terraform will check, validate, and configure the CX switch to match the desired state using REST APIs.

How the AOS-CX Terraform Provider Works

The AOS-CX Terraform Provider follows the required behavior for all Terraform providers in enforcing a declarative approach. The AOS-CX provider initially logs into the switch and creates cookie based session that's used for the entire execution, then through a series of REST API calls, the provider will ensure the switch is in the defined state.
Here's what a typical execution will look like:

  • Login to the switch using the credentials found in the Terraform state file
  • Retrieve the current state of the switch (executes a GET)
  • Compare what was found with the what is defined in the state file
  • If modifications are necessary the follow could occur:
    • POST method is executed to create a resource
    • PATCH or PUT method is executed to update a resource
    • DELETE method is executed to remove a resource

Requirements

Installing the AOS-CX Terraform Provider

In Terraform version 0.13 they added support for automatically downloading providers from the Terraform Registry. Users can simply define the AOS-CX provider as one of the required_providers in their Terraform state file and Terraform will install the provider upon executing terraform init. As we continue to develop more features and improve functionality, the current version of the provider is considered a prerelease. Therefore users will have to specify the exact version of the provider they'll want to use, the latest support version can be found on the Terraform Registry or on the AOS-CX Terraform Provider Github.

terraform {
  required_providers {
    aoscx = {
      version = "0.0.1-pre"
      source  = "aruba/aoscx"
    }
  }
}

To ensure the required_providers block is properly defined, execute terraform init and the output should look similar to the following:

[email protected]:~/go/src/terraform-provider-aoscx$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding aruba/aoscx versions matching "0.0.1-pre"...
- Using aruba/aoscx v0.0.1-pre from the shared cache directory

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 that are 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 is defined then users will define the resources they want Terraform manage on their CX switch. To see all supported resources and their required/optional values see the provider's documentation.

Here's a full sample Terraform state file:

terraform {
  required_providers {
    aoscx = {
      version = "0.0.1-pre"
      source  = "aruba/aoscx"
    }
  }
}

provider "aoscx" {
  hostname = "10.6.7.16"
  username = "admin"
  password = "admin"
}

resource "aoscx_vlan" "vlan42" {
        vlan_id = 42
        name = "terraform vlan"
        admin_state = "down"
}

resource "aoscx_vlan" "vlan20" {
        vlan_id = 20
        name = "voice vlan"
}
resource "aoscx_interface" "int_1_1_14" {
        name = "1/1/14"
        admin_state = "down"
        description = "terraform_uplink"
}

resource "aoscx_l2_interface" "int_1_1_15" {
        interface = "1/1/15"
        admin_state = "up"
        description = "terraform_downlink"
        vlan_mode = "access"
        vlan_tag = 42
}
resource "aoscx_l2_interface" "int_1_1_16" {
        interface = "1/1/16"
        admin_state = "down"
        vlan_mode = "trunk"
        vlan_ids = [20, 42]
        native_vlan_tag = true
}

Once that's defined, users will run Terraform as they typically would by executing the terraform apply command and accepting (or auto-approving) the proposed changes, here's the output of applying the above sample state file:

[email protected]:~/go/src/terraform-provider-aoscx$ terraform apply -auto-approve

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:

  # aoscx_interface.int_1_1_14 will be created
  + resource "aoscx_interface" "int_1_1_14" {
      + admin_state = "down"
      + description = "terraform_uplink"
      + id          = (known after apply)
      + name        = "1/1/14"
    }

  # aoscx_l2_interface.int_1_1_15 will be created
  + resource "aoscx_l2_interface" "int_1_1_15" {
      + admin_state       = "up"
      + description       = "terraform_downlink"
      + id                = (known after apply)
      + interface         = "1/1/15"
      + native_vlan_tag   = false
      + trunk_allowed_all = false
      + vlan_mode         = "access"
      + vlan_tag          = 42
    }

  # aoscx_l2_interface.int_1_1_16 will be created
  + resource "aoscx_l2_interface" "int_1_1_16" {
      + admin_state       = "down"
      + id                = (known after apply)
      + interface         = "1/1/16"
      + native_vlan_tag   = true
      + trunk_allowed_all = false
      + vlan_ids          = [
          + 20,
          + 42,
        ]
      + vlan_mode         = "trunk"
      + vlan_tag          = 1
    }

  # aoscx_vlan.vlan20 will be created
  + resource "aoscx_vlan" "vlan20" {
      + admin_state = "up"
      + id          = (known after apply)
      + name        = "voice vlan"
      + vlan_id     = 20
    }

  # aoscx_vlan.vlan42 will be created
  + resource "aoscx_vlan" "vlan42" {
      + admin_state = "down"
      + id          = (known after apply)
      + name        = "terraform vlan"
      + vlan_id     = 42
    }

Plan: 5 to add, 0 to change, 0 to destroy.
aoscx_vlan.vlan42: Creating...
aoscx_vlan.vlan20: Creating...
aoscx_l2_interface.int_1_1_15: Creating...
aoscx_interface.int_1_1_14: Creating...
aoscx_l2_interface.int_1_1_16: Creating...
aoscx_vlan.vlan42: Creation complete after 1s [id=42]
aoscx_vlan.vlan20: Creation complete after 1s [id=20]
aoscx_interface.int_1_1_14: Creation complete after 1s [id=1/1/14]
aoscx_l2_interface.int_1_1_15: Creation complete after 1s [id=1/1/15]
aoscx_l2_interface.int_1_1_16: Creation complete after 1s [id=1/1/16]
╷
│ Warning: VLAN Already Existing
│
│   with aoscx_vlan.vlan42,
│   on main.tf line 16, in resource "aoscx_vlan" "vlan42":
│   16: resource "aoscx_vlan" "vlan42" {
│
│ *
│
│ (and one more similar warning elsewhere)
╵
╷
│ Warning: Interface Already Existing
│
│   with aoscx_interface.int_1_1_14,
│   on main.tf line 26, in resource "aoscx_interface" "int_1_1_14":
│   26: resource "aoscx_interface" "int_1_1_14" {
│
│ 1/1/14
│
│ (and 2 more similar warnings elsewhere)
╵

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

Session Limitation

Due to the Terraform framework design there is no logout/cleanup functionality, therefore REST API sessions are subject to closing based on timeout. Depending on the timing of consecutive executions and the configured session-timeout of the https-server (Default: 20 minutes. Maximum: 480 min (8 hours). 0 disables the timeout, but the maximum is still enforced).

This may cause the following error to appear after multiple consecutive executions:

[email protected]:~/go/src/sandbox$ terraform apply --auto-approve
╷
│ Error: Plugin did not respond
│
│   with provider["registry.terraform.io/aruba/aoscx"],
│   on main.tf line 10, in provider "aoscx":
│   10: provider "aoscx" {
│
│ The plugin encountered an error, and failed to respond to the
│ plugin.(*GRPCProvider).ConfigureProvider call. The plugin logs may contain more
│ details.
╵

Currently the workaround is to execute the following command in the manager context to close out all sessions, wait 10 seconds, then continue to execute the terraform apply command:
switch# https-server session close all

This is also documented under the project's Github.