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.
- Terraform 1.8.0 or later.
- Git
- Your preferred text editor / Integrated Development Environment (IDE) (such as VisualStudio Code)
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 areindicated 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 areindicated 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 areindicated 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 areindicated 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.