Skip to content

First Steps

This section provides an easy to understand, simple example of creating and deploying a configuration group to an SD-WAN router. This helps to get familiar using Network-as-Code to manage Catalyst SD-WAN.

The repository used in this example can be found at: https://github.com/netascode/nac-sdwan-simple-example

This example assumes you have installed the following prerequisites.

Getting Started

Start by cloning the repository to your local system:

git clone https://github.com/netascode/nac-sdwan-simple-example.git

Open the folder in your preferred editor / IDE.

The working area should look like this (the editor shown here is vsCode):

The main.tf file contains the required providers, provider settings and points to the location of all *.yaml file definitions.

module "sdwan" {
source = "netascode/nac-sdwan/sdwan"
version = "1.1.0"
yaml_directories = ["data"]
}

Configuration Group and Feature Profiles Definition

An example configuration group and feature profiles definition is provided in data/configuration.nac.yaml. This contains minimal configuration required to deploy a configuration group to a router.

Before diving into this file it is worth to understand the *.yaml files and structure in the data folder a bit better. As different teams might be responsible for different parts of the infrastructure, these definitions need to be flexible. Some organisations might want to use a single *.yaml file for their entire configuration, whilst others prefer *.yaml file per country, administrative domain or feature (e.g. network features and security features). The name of the yaml files are completely arbitrary. These two examples are explained below.

It is possible to group multiple WAN interfaces in the same *.yaml file. This yaml file contains two interfaces inet and mpls for WAN VPN.

cat configuration.nac.yaml
---
sdwan:
feature_profiles:
transport_profiles:
- name: transport
wan_vpn:
name: wan_vpn
ethernet_interfaces:
- name: inet
interface_name_variable: inet_interface_name
- name: mpls
interface_name_variable: mpls_interface_name

Similarly it is possible to split the configuration of WAN VPN interfaces into multiple *.yaml files. The two yaml files refer to the same WAN VPN wan_vpn but contain different interfaces inet and mpls.

cat wan_vpn_inet.nac.yaml
---
sdwan:
feature_profiles:
transport_profiles:
- name: transport
wan_vpn:
name: wan_vpn
ethernet_interfaces:
- name: inet
interface_name_variable: inet_interface_name
cat wan_vpn_mpls.nac.yaml
---
sdwan:
feature_profiles:
transport_profiles:
- name: transport
wan_vpn:
name: wan_vpn
ethernet_interfaces:
- name: mpls
interface_name_variable: mpls_interface_name

Sites Definition

An example configuration group attachment definition with site-specific variables is provided in data/sites.nac.yaml. This defines which configuration group should be used by each router and provides values for variables required by the configuration group.

cat sites.nac.yaml
---
sdwan:
sites:
- id: 1
routers:
- chassis_id: C8K-3D1A8960-6E76-532C-DA93-50626FC5797E
configuration_group: branches
device_variables:
host_name: edge1
system_ip: 10.0.0.1
site_id: 1
pseudo_commit_timer: 300
inet_interface_name: GigabitEthernet1
mpls_interface_name: GigabitEthernet2

As described before, the file structure is flexible. You can have all sites/routers defined in a single *.yaml file or split site/routers definitions into multiple files based on country, site type, site role etc.

Now that you are familiar with the structure it is time to get into the example.

Step 1: Configuration Group Validation

Navigate to data/configuration.nac.yaml and take note of the structure. This example contains a configuration group named branches, feature profiles system and transport and required features inside the feature profiles. The transport has two WAN interfaces defined, both configured for dynamic IPv4 address.

---
---
sdwan:
configuration_groups:
- name: branches # Make sure there is no existing configuration group named 'branches'
system_profile: system
transport_profile: transport
feature_profiles:
system_profiles:
- name: system # Make sure there is no existing profile named 'system'
aaa:
name: aaa
users:
- name: admin
password: YudmqT6MWZyak3M
basic:
name: basic
bfd:
name: bfd
logging:
name: logging
global:
name: global
omp:
name: omp
transport_profiles:
- name: transport # Make sure there is no existing profile named 'transport'
wan_vpn:
name: wan_vpn
ethernet_interfaces:
- name: inet
interface_name_variable: inet_interface_name
ipv4_configuration_type: dynamic
shutdown: false
tunnel_interface:
color: biz-internet
- name: mpls
interface_name_variable: mpls_interface_name
ipv4_configuration_type: dynamic
shutdown: false
tunnel_interface:
color: mpls

Navigate to data/sites.nac.yaml and take note of the structure. This example has single C8000V router assigned to a configuration group.

---
---
sdwan:
sites:
- id: 1
routers:
- chassis_id: C8K-3D1A8960-6E76-532C-DA93-50626FC5797E
configuration_group: branches
configuration_group_deploy: true
device_variables:
host_name: edge1
system_ip: 10.0.0.1
site_id: 1
pseudo_commit_timer: 300
inet_interface_name: GigabitEthernet1
mpls_interface_name: GigabitEthernet2

Step 2: Configuration Group Deployment

Make sure to update the provider block in the main.tf file in the root folder with the right credentials and Catalyst SD-WAN Manager IP address. For more information see: Terraform Provider Documentation.

provider "sdwan" {
username = "username"
password = "password"
url = "https://sdwan-manager.url"
}

Initialise Terraform: (This initializes the working directory containing the terraform configuration files, and installs all required providers and modules. This could take several minutes depending on the available bandwidth, as all the Network-as-Code modules are downloaded automatically.)

terraform init

Run terraform apply: (This applies the changes defined by your Terraform configuration to create, update or destroy resources)

terraform apply

Followed by yes to approve.

Upon success you should receive the following output:

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

Navigate to your SD-WAN Manager and verify that your configuration group branches has been deployed successfully:

Before expanding on additional use-cases it is worth understanding how you can add and remove resources. This will be covered in step 3 and 4.

Step 3: Adding additional resources

Now that the new configuration group is deployed it becomes easy to add additional features to configuration group. Add a new ntp feature by adding the following lines to the system feature profile section in configuration.nac.yaml:

sdwan:
feature_profiles:
system_profiles:
- name: system
ntp:
name: ntp
servers:
- hostname_ip: ntp.example.com

The configuration.nac.yaml file with the new Bridge Domain should look like this:

---
sdwan:
configuration_groups:
- name: branches
system_profile: system
transport_profile: transport
feature_profiles:
system_profiles:
- name: system
ntp:
name: ntp
servers:
- hostname_ip: ntp.example.com
aaa:
name: aaa
users:
- name: admin
password: YudmqT6MWZyak3M
basic:
name: basic
bfd:
name: bfd
logging:
name: logging
global:
name: global
omp:
name: omp
transport_profiles:
- name: transport
wan_vpn:
name: wan_vpn
ethernet_interfaces:
- name: inet
interface_name_variable: inet_interface_name
ipv4_configuration_type: dynamic
shutdown: false
tunnel_interface:
color: biz-internet
- name: mpls
interface_name_variable: mpls_interface_name
ipv4_configuration_type: dynamic
shutdown: false
tunnel_interface:
color: mpls

Save the file and run terraform apply

terraform apply

Terraform will compare the state file with the new plan and calculate any resources that need to be added, changed or destroyed. In this case 1 new resources will be created and 1 resource will be updated. Terraform will create a new NTP feature and trigger a change on the configuration group so the new configuration including NTP will be pushed to the device attached to this configuration group.

Output:

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
+ create
~ update in-place
Terraform will perform the following actions:
# module.sdwan.sdwan_configuration_group.configuration_group["branches"] will be updated in-place
~ resource "sdwan_configuration_group" "configuration_group" {
~ feature_versions = [
# (4 unchanged elements hidden)
"0",
+ (known after apply),
"0",
# (3 unchanged elements hidden)
]
id = "590b6d06-953b-47ee-bfcf-00f5fe62440b"
name = "branches"
# (4 unchanged attributes hidden)
}
# module.sdwan.sdwan_system_ntp_feature.system_ntp_feature["system-ntp"] will be created
+ resource "sdwan_system_ntp_feature" "system_ntp_feature" {
+ feature_profile_id = "2f5ff543-034b-418d-b552-94737cde0dc0"
+ id = (known after apply)
+ name = "ntp"
+ servers = [
+ {
+ hostname_ip_address = "ntp.example.com"
},
]
+ version = (known after apply)
}
Plan: 1 to add, 1 to change, 0 to destroy.

Followed by yes to approve.

Navigate to Catalyst SD-WAN Manager and make sure that the ntp feature was added to the system feature profile.

Step 4: Removing resources

In this step you will remove ntp feature, which was created in step 3.

Remove the Bridge Domain ntp section from configuration.nac.yaml

ntp:
name: ntp
servers:
- hostname_ip: ntp.example.com

The configuration.nac.yaml file should once again look like this:

---
sdwan:
configuration_groups:
- name: branches
system_profile: system
transport_profile: transport
feature_profiles:
system_profiles:
- name: system
aaa:
name: aaa
users:
- name: admin
password: YudmqT6MWZyak3M
basic:
name: basic
bfd:
name: bfd
logging:
name: logging
global:
name: global
omp:
name: omp
transport_profiles:
- name: transport
wan_vpn:
name: wan_vpn
ethernet_interfaces:
- name: inet
interface_name_variable: inet_interface_name
ipv4_configuration_type: dynamic
shutdown: false
tunnel_interface:
color: biz-internet
- name: mpls
interface_name_variable: mpls_interface_name
ipv4_configuration_type: dynamic
shutdown: false
tunnel_interface:
color: mpls

Save the file and run terraform apply:

terraform apply

Terraform will compare the state file with the new plan and calculate any resources that need to be added, changed or destroyed. In this case 1 resource will be destroyed (removing NTP feature) and one will be changed (triggering repush of configuration group to a device).

Output:

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

Followed by yes to approve.

Navigate to SD-WAN and make sure that the NTP feature was removed from system feature profile.

Step 5: Making changes

You have now added and removed resources, but what if you want to change additional configuration settings? For example; how would you change the BFD multiplier for your overlay? Which attributes can you use, and which values are expected? This is where the Data Model Docs come in. This section contains a list of all the resources that are currently supported. Under each resource you can find a list of attributes, their type, any constraints, whether they are required and whether they have a default value. It also contains a short and comprehensive example of that resource.

If you navigate to Data Models > Catalyst SD-WAN > Features - System > System BFD Feature, you can see that for multiplier the allowed values numbers from 1 to 6. You can also configure this parameter as device-specific by specifying variable name in the multiplier_variable attribute (this is discussed in the next step)

Update the configuration.nac.yaml file by adding the line multipler: 5 under bfd feature.

multipler: 5

The section for bfd feature should look like this:

bfd:
name: bfd
multiplier: 5

Save the file and run terraform apply:

terraform apply

Terraform will compare the existing state file with the new plan and calculate any resources that need to be added, changed or destroyed. In this case 2 resource will be changed: one updating the bfd feature with new configuration and one triggering the configuration group deployment. The resources will be updated in-place.

Output:

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.sdwan.sdwan_configuration_group.configuration_group["branches"] will be updated in-place
~ resource "sdwan_configuration_group" "configuration_group" {
~ feature_versions = [
# (1 unchanged element hidden)
"0",
+ (known after apply),
"0",
# (4 unchanged elements hidden)
"0",
- "0",
]
id = "590b6d06-953b-47ee-bfcf-00f5fe62440b"
name = "branches"
# (4 unchanged attributes hidden)
}
# module.sdwan.sdwan_system_bfd_feature.system_bfd_feature["system-bfd"] will be updated in-place
~ resource "sdwan_system_bfd_feature" "system_bfd_feature" {
id = "f1a0ed22-85cb-45d3-9711-ccfef5601e9b"
+ multiplier = 5
name = "bfd"
~ version = 0 -> (known after apply)
# (1 unchanged attribute hidden)
}
Plan: 0 to add, 2 to change, 0 to destroy.

Followed by yes to approve.

This will update the existing BFD feature with the new multiplier value. Navigate to Catalyst SD-WAN Manager and make sure that the BFD feature was updated with the new multiplier configuration.

Step 6: Updating device-specific values

In the previous step you’ve set BFD multiplier to a global value of 5. This means all devices assigned to this configuration group will have this value configured. What if you would like to use a different value for each device? You can use device-specific variables by appending parameter name multiplier with _variable and specifying variable name. Change the multiplier 5 to multiplier_variable: bfd_multiplier.

The section for bfd feature should look like this:

bfd:
name: bfd
multiplier_variable: bfd_multiplier

Since we’ve added a device-specific value, we can now specify a value in the sites.nac.yaml. Add new variable at the end of the file. The updated sites.nac.yaml file should look like below

sdwan:
sites:
- id: 1
routers:
- chassis_id: C8K-3D1A8960-6E76-532C-DA93-50626FC5797E
configuration_group: branches
configuration_group_deploy: true
device_variables:
host_name: edge1
system_ip: 10.0.0.1
site_id: 1
pseudo_commit_timer: 300
inet_interface_name: GigabitEthernet1
mpls_interface_name: GigabitEthernet2
bfd_multiplier: 3

Save the file and run terraform apply:

terraform apply

Terraform will compare the existing state file with the new plan and calculate any resources that need to be added, changed or destroyed. In this case variable will be added to bfd feature and new value for the variable will be added in the configuration group resource.

Output:

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.sdwan.sdwan_configuration_group.configuration_group["branches"] will be updated in-place
~ resource "sdwan_configuration_group" "configuration_group" {
~ devices = [
~ {
id = "C8K-3D1A8960-6E76-532C-DA93-50626FC5797E"
~ variables = [
+ {
+ name = "bfd_multiplier"
+ value = "3"
},
# (6 unchanged elements hidden)
]
# (1 unchanged attribute hidden)
},
]
~ feature_versions = [
# (1 unchanged element hidden)
"0",
~ "1" -> (known after apply),
"0",
# (5 unchanged elements hidden)
]
id = "590b6d06-953b-47ee-bfcf-00f5fe62440b"
name = "branches"
# (3 unchanged attributes hidden)
}
# module.sdwan.sdwan_system_bfd_feature.system_bfd_feature["system-bfd"] will be updated in-place
~ resource "sdwan_system_bfd_feature" "system_bfd_feature" {
id = "f1a0ed22-85cb-45d3-9711-ccfef5601e9b"
- multiplier = 5 -> null
+ multiplier_variable = "{{bfd_multiplier}}"
name = "bfd"
~ version = 1 -> (known after apply)
# (1 unchanged attribute hidden)
}
Plan: 0 to add, 2 to change, 0 to destroy.

Followed by yes to approve.

This will update the existing BFD feature with the new multiplier variable name and configuration group with value for a newly created variable. If you would like to update the value, you can go back to sites.nac.yaml and modify the device_variables section.

Step 7: Working with default values

The previous step explained how to change a setting on a single resource. If you have specific configuration you wish to apply to each instance of that resource you can leverage a defaults.nac.yaml file. The main.tf plan passes the content of defaults.nac.yaml to the module. This allows a user to modify any default settings to reflect their requirements. By default, the IPv6 is not configured on WAN VPN ethernet interfaces. In this example you will modify defaults to enable IPv6 on all WAN VPN interfaces that are created. Navigate to defaults.nac.yaml and explore the file:

# Overwrite default values here
# defaults:
# sdwan:
# feature_profiles:
# transport_profiles:
# wan_vpn:
# ethernet_interfaces:
# ipv6_configuration_type: dynamic

The defaults.nac.yaml file follows the same structure as the other yaml files in the inventory. Uncomment the lines and run terraform apply. The output will show that the terraform apply action will update the WAN VPN ethernet interfaces with its new configuration setting.

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.sdwan.sdwan_configuration_group.configuration_group["branches"] will be updated in-place
~ resource "sdwan_configuration_group" "configuration_group" {
~ feature_versions = [
# (6 unchanged elements hidden)
"0",
- "0",
- "0",
+ (known after apply),
+ (known after apply),
]
id = "590b6d06-953b-47ee-bfcf-00f5fe62440b"
name = "branches"
# (4 unchanged attributes hidden)
}
# module.sdwan.sdwan_transport_wan_vpn_interface_ethernet_feature.transport_wan_vpn_interface_ethernet_feature["transport-wan_vpn-inet"] will be updated in-place
~ resource "sdwan_transport_wan_vpn_interface_ethernet_feature" "transport_wan_vpn_interface_ethernet_feature" {
+ enable_dhcpv6 = true
id = "76c87db3-2c51-4adf-989f-bc333f02ca22"
~ ipv6_configuration_type = "none" -> "dynamic"
name = "inet"
~ version = 0 -> (known after apply)
# (9 unchanged attributes hidden)
}
# module.sdwan.sdwan_transport_wan_vpn_interface_ethernet_feature.transport_wan_vpn_interface_ethernet_feature["transport-wan_vpn-mpls"] will be updated in-place
~ resource "sdwan_transport_wan_vpn_interface_ethernet_feature" "transport_wan_vpn_interface_ethernet_feature" {
+ enable_dhcpv6 = true
id = "7e6cb43c-7821-4ba8-afc3-8226302ef754"
~ ipv6_configuration_type = "none" -> "dynamic"
name = "mpls"
~ version = 0 -> (known after apply)
# (9 unchanged attributes hidden)
}
Plan: 0 to add, 3 to change, 0 to destroy.

Step 8: Changing configuration in the GUI

Imagine that someone unaware of the automation efforts makes a change directly in the GUI to one of the objects created by Terraform.

Delete the mpls feature from transport feature profile via GUI:

Because the Terraform state now differs from the running configuration a simple terraform apply will prompt you to recreate the mpls feature. Terraform is able to detect configuration drift and reconcile it.

</snip>
Plan: 1 to add, 1 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.

This even works when changing properties of an object. The resource will be modified back to its desired state when terraform apply is executed. Feel free to make modifications via the GUI and restore those manual actions.

Step 9: Cleaning up

That is it for this simple example. Feel free to experiment with additional resources. The final step is to clean up the configuration.

Run terraform destroy to remove the configuration:

terraform destroy

Output:

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

Followed by yes to approve.

Navigate to SD-WAN Manager and make sure that configuration group branches and the associated feature profiles have been removed.