Example Repository

Due to the limitations of time in this lab, we have constructed a repository that contains a terraform module that will deploy a VXLAN/EVPN network. This module is designed to show what is possible with Terraform and how it can be used to deploy complex network topologies.

Terraform Module

Terraform modules are reusable components that encapsulate a set of resources and their configurations. They allow you to define infrastructure in a modular way, making it easier to manage and reuse code across different projects or environments. Modules can be used to create complex infrastructure setups, such as networks, virtual machines, databases by grouping related resources together.

The overall structure of Terraform is at the root is a project. The project contains a set of modules and data files.





Step 1 - Create Terraform Directory

The first step is to clone the repository that contains the Terraform module. This repository is hosted on GitHub and can be cloned using the following command:


cd /home/pod14/workspace/nxapilab
mkdir -p terraform-nxos
cd terraform-nxos


Terraform Module

Step 2 - Clone repository

The first step is to clone the repository that contains the Terraform module. This repository is hosted on GitHub and can be cloned using the following command:


git clone https://github.com/rafmuller/ltrdcn-3903-terra.git


This will create a directory called ltrdcn-3903-terra in your home directory. The repository contains two separate directories, one that is the module and the second a preset configuration files in YAML.


ls -l ltrdcn-3903-terra/


  (nxapilab) pod14 ~/workspace/nxapilab/terraform-nxos $: ls -l ltrdcn-3903-terra/
  total 20
  drwxr-xr-x 3 pod01 pod01 4096 Jun  5 15:57 data
  -rw-r--r-- 1 pod01 pod01 1070 Jun  5 15:57 LICENSE
  -rw-r--r-- 1 pod01 pod01 1261 Jun  5 15:57 main.tf
  -rw-r--r-- 1 pod01 pod01 2058 Jun  5 15:57 README.md
  drwxr-xr-x 2 pod01 pod01 4096 Jun  5 15:57 vxlan

Step 3 - Complete Module

We have left out from the module some code for you to complete. Inside of the module you are going to complete the ports resource. In this case we will be adding two componenents. Data that we need to build for the resources and then the resources themselves.

There is an empty file called nxos_interfaces_ports.tf inside of the module directory vxlan. First you need to open this file in the code editor.


code-server -r /home/pod14/workspace/nxapilab/terraform-nxos/ltrdcn-3903-terra/vxlan/nxos_interfaces_ports.tf


Step 4 - Add Layer2 Access Ports inside locals

The first step is to add the Layer2 Access Ports inside of the locals block. This code is a variable definition created by an iteration over various points of the configuration built inside of the data directory.


# .______     ______   .______     .___________.    _______.
# |   _  \   /  __  \  |   _  \    |           |   /       |
# |  |_)  | |  |  |  | |  |_)  |   `---|  |----`  |   (----`
# |   ___/  |  |  |  | |      /        |  |        \   \    
# |  |      |  `--'  | |  |\  \----.   |  |    .----)   |   
# | _|       \______/  | _| `._____|   |__|    |_______/    
#
# These reources are used to create the phyiscal interface ports that connect to the 
# switches.

locals{
  l2_access_ports = flatten([
    for device in try(local.devices, []) : [
      for interface in try(device.interfaces, []) : {
        key         = format("%s-%s", device.name, interface.id)
        device      = device.name
        id          = interface.id
        description = try(interface.description, "Configured by Terraform")
        mtu         = try(interface.mtu, 9216)
        speed       = try(interface.speed, "auto")
        admin_state = try(interface.admin_state, "up")
        layer       = "Layer2"
        l2_mode     = "access"
        vlan        = interface.vlans
      } if interface.link_type == "service-l2" && try(interface.l2_mode, null) == "access"
    ]
  ])
}


Step 5 - Add Layer2 Trunk Ports inside locals

The first step is to add the Layer2 Access Ports inside of the locals block. This code is a variable definition created by an iteration over various points of the configuration built inside of the data directory.


# .______     ______   .______     .___________.    _______.
# |   _  \   /  __  \  |   _  \    |           |   /       |
# |  |_)  | |  |  |  | |  |_)  |   `---|  |----`  |   (----`
# |   ___/  |  |  |  | |      /        |  |        \   \    
# |  |      |  `--'  | |  |\  \----.   |  |    .----)   |   
# | _|       \______/  | _| `._____|   |__|    |_______/    
#
# These reources are used to create the phyiscal interface ports that connect to the 
# switches.

locals{
  l2_access_ports = flatten([
    for device in try(local.devices, []) : [
      for interface in try(device.interfaces, []) : {
        key         = format("%s-%s", device.name, interface.id)
        device      = device.name
        id          = interface.id
        description = try(interface.description, "Configured by Terraform")
        mtu         = try(interface.mtu, 9216)
        speed       = try(interface.speed, "auto")
        admin_state = try(interface.admin_state, "up")
        layer       = "Layer2"
        l2_mode     = "access"
        vlan        = interface.vlans
      } if interface.link_type == "service-l2" && try(interface.l2_mode, null) == "access"
    ]
  ])

  l2_trunk_ports = flatten([
    for device in try(local.devices, []) : [
      for interface in try(device.interfaces, []) : {
        key         = format("%s-%s", device.name, interface.id)
        device      = device.name
        id          = interface.id
        description = try(interface.description, "Configured by Terraform")
        mtu         = try(interface.mtu, 9216)
        admin_state = try(interface.admin_state, "up")
        speed       = try(interface.speed, "auto")
        layer       = "Layer2"
        l2_mode     = "trunk"
        trunk_vlans = interface.vlans
      } if interface.link_type == "service-l2" && try(interface.l2_mode, null) == "trunk"
    ]
  ])

}

You may be asking why we have two different variables for the Layer2 ports. The reason is that we will be using two separate resources. For the Terraform NXOS provider to configure the access ports and trunk ports require different resources.

Instead of building logic in the resources to pick through the different types, we just build the data structure required for each port indedpendently. This also allows easier parameter control since access ports have less values than trunk ports.


Step 6 - Add resources.

The next step is to add the resources that will create the Layer2 Access and Trunk ports. These resources will use the data defined in the locals block.


resource "nxos_physical_interface" "vxlan_access_port_service_interface" {
  for_each     = { for interface in try(local.l2_access_ports, []) : interface.key => interface }
  device       = each.value.device
  interface_id = each.value.id
  description  = each.value.description
  mode         = "access"
  mtu          = each.value.mtu
  access_vlan  = "vlan-${each.value.vlan}"
  admin_state  = each.value.admin_state
  speed        = each.value.speed
  layer        = "Layer2"
}

resource "nxos_physical_interface" "vxlan_trunk_port_service_interface" {
  for_each     = { for interface in try(local.l2_trunk_ports, []) : interface.key => interface }
  device       = each.value.device
  interface_id = each.value.id
  description  = each.value.description
  mode         = "trunk"
  mtu          = each.value.mtu
  admin_state  = each.value.admin_state
  speed        = each.value.speed
  layer        = "Layer2"
  trunk_vlans  = each.value.trunk_vlans
  depends_on   = [nxos_feature_lacp.lacp]
}