EEM in Catalyst Center templates 📅👨‍💼

2024-10-05 · Series: None · Tags: Catalyst Center, Automation

Introducing Catalyst Center templating to brownfield environments often require dynamic configuration outside of what jinja can offer. I will cover a few scenarios below that demonstrates when and how EEM applets can assist you in overcoming some limitations in CC templating.

TL;DR

Why EEM?

Jinja templates on the Catalyst Center are flexible enough to cover most scenarios where dynamic configuration is required, but it has a few notable limitations. The main ones I face regularly are the lack of access to inventory variables & interactive commands in onboarding templates, and when your desired configuration requires referencing operational data.

Ideally I would like to push python scripts to achieve on-box automation as you can with ZTP. This is unfortunately not possible through DNAC templates yet(let me know if you know how to achieve this!). That leaves us with EEM as the best available mechanism to achieve on-box automation.

Note: The big disadvantage of utilizing EEM/on-box automation is that you lose the possibility of performing compliance checks against template contents. Handling configuration through jinja templating on the CC should hence be preferred whenever it is possible.

Auto-configuration for trunks

One of the first steps to achieve an operational L2 network when deploying switches is to configure inter-switch trunks. In an ideal world you’d be able to adhere to a consistent design and port-layout, but this is unfortunately often not the case in existing environments.

I’ve based this on the EEM scripts in this community post for setting port descriptions. It triggers upon receiving CDP updates and configures trunks with appropriate descriptions.

What the applet doesn’t do is save the config. It turns out that you will be unable to log in over SSH if you save the config too requently on IOS-XE. You also probably don’t want this to be running after the initial device deployment. The solution to both of these problems is to deploy a second applet that cleans up and writes the config after 2 hours.

event manager applet auto-trunk authorization bypass
 {# Decided to use "update" as "add" turned out to not always be reliable #}
 event neighbor-discovery interface regexp .* cdp update ratelimit 3

 {# Configure ports for access points #}
 action 01 regexp "(Trans-Bridge)" "$_nd_cdp_capabilities_string" 
 action 02 if $_regexp_result eq "1"
 action 03  regexp "^([^\.]+)" "$_nd_cdp_entry_name" match host
 action 04  cli command "enable"
 action 05  cli command "config t"
 action 06  cli command "interface $_nd_local_intf_name"
 action 07  cli command "description $host"
 action 08  cli command "switchport mode trunk"
 {# Replace with appropriate VLAN for your environment #}
 action 09  cli command "switchport trunk native vlan 40" 
 action 10  cli command "switchport nonegotiate"
 action 11 end
!
 {# Configure ports for routers and switches #}
 action 12 regexp "(Switch|Router)" "$_nd_cdp_capabilities_string"
 action 13 if $_regexp_result eq "1"
 action 14  regexp "^([^\.]+)" "$_nd_cdp_entry_name" match host
 action 15  cli command "enable"
 action 16  cli command "config t"
 action 17  cli command "interface $_nd_local_intf_name"
 action 18  cli command "description TO: $host:$_nd_port_id" 
 action 19  cli command "switchport mode trunk"
 action 20  cli command "switchport nonegotiate"
 action 21 end
 action 22 exit
!
 {# Cleanup applet #}
event manager applet un-auto-trunk authorization bypass 
 event timer countdown time 7200
 action 00 cli command "enable"
 action 01 cli command "config t"
 action 02 cli command "no event manager applet auto-trunk"
 action 03 cli command "no event manager applet un-auto-trunk"
 action 04 cli command "do write"

Configuring access-ports

Common practice dictates that everything not essential for device onboarding should be handled in day-n templates. That said, handling access port config in the onboarding templates has one major benefit: It allows you to pre-claim devices in bulk and have them be deployed with basic functionality by others without your direct involvement. This allows you to perform device provisioning in batches, both saving you/the team time and giving you more calendar flexibility.

Configuring access ports in onboarding templates is difficult since you’re not able to access the inventory variables. Assuming that you are working with a standardised port layout you can use the following EEM applet to configure the on-box.

Once the switches have been onboarded you have a couple options for maintaining and enforcing standardised port configs. You can either push a day-n template with a fixed port layout, or you can push a template that apples config based on interface type(either match VLAN or description). I usually end up with a combination - all new switches are provisioned with the former and existing devices are provisioned with the latter.

event manager applet auto-access-port
 event timer countdown time 10
 action 000 cli command "enable"

 {# Get all lines of show int desc containing physical interfaces #}
 action 001 cli command "show int desc | i /"
 action 002 foreach line "$_cli_result" "\n"

  {# Capture port-name to $portname variable #}
  action 003 regexp "([A-Z][a-z]*[0-9,/]+)" "$line" match portname

  {# Verify that the port belongs to the main module/regular ports #}
  action 004 regexp "0/[0-9]*" "$portname"
  action 005 if $_regexp_result eq "1"

   {# Configure first 8 ports in VLAN 10 #}
   action 006 regexp ".*0/[1-8].*" "$portname"
   action 007 if $_regexp_result eq "1"
    action 008 cli command "configure terminal"
    action 009 cli command "interface $portname"
    action 010 cli command "description TO: IOT (VL10)" 
    action 011 cli command "switchport access vlan 10"
    action 012 cli command "switchport mode access"
    action 013 cli command "switchport nonegotiate"
   action 014 cli command "end"

   {# Configure remaining ports in VLAN 20 #}
   action 016 else
	action 017 cli command "configure terminal"
	action 018 cli command "interface $portname"
	action 019 cli command "description TO: Employees (VL20)" 
	action 020 cli command "switchport access vlan 20"
	action 021 cli command "switchport mode access"
	action 022 cli command "switchport nonegotiate"
	action 023 cli command "end"
   action 024 end

  action 025 end
 action 026 end

DHCP snooping

Configuration of DHCP snooping trusted interfaces without consistent topologies require on-box automation as it must rely on operational state information.

If your topologies are simple enough with no secondary paths to fail over to this applet is all you need to set the correct trusted interface. In all other situations it functions as an ensurance that you will have at least one functioning trusted interface. We’ve all enabled DHCP snooping without a trusted interface right?

The applet works by finding the egress interface towards the gateway device. It does this by pinging the gateway and checking the ARP and the mac-address tables.

! @start-ignore-compliance
event manager applet auto-snoop
event timer countdown time 1

{# Find default gateway address #}
action 001 cli command "enable"
action 002 cli command "show ip route 0.0.0.0 0.0.0.0 | i [0-9]*\.[0-9]*\.[0-9]*$"
action 003 regexp "([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)" "$_cli_result" match gateway

{# Ensure MAC is in CAM #}
action 100 syslog msg "Starting DHCP Snooping link-config"
action 101 cli command "enable"
action 102 set complete "false"
action 103 while complete eq "false"
 action 104 cli command "ping $gateway"
 action 105 cli command "show ip arp | i $gateway"  
 action 106 regexp "Incomplete" "$_cli_result"
 action 107 if $_regexp_result eq "0"
  action 108 set complete "true"
  action 109 end
 action 110 end

{# Find "upstream" facing interface and configure it as trusted #}
action 201 cli command "show ip arp | i $gateway"  
action 202 regexp "( [0-9,a-f]*.[0-9,a-f]*\.[0-9,a-f]* )" "$_cli_result" match macaddr
action 203 cli command "show mac address-table | i $macaddr"  
action 204 regexp "([A-Z][a-z][a-z,A-Z,0-9,/]*)" "$_cli_result" match interface
action 205 cli command "configure terminal"
action 206 cli command "interface $interface"
action 207 cli command "ip dhcp snooping trust"
action 208 cli command "no event manager applet auto-snoop"
action 209 cli command "do write"
action 210 syslog msg "DHCP Snooping link-config complete"

! @end-ignore-compliance
ip dhcp snooping vlan 10, 20
ip dhcp snooping

Summary

EEM is useful for achieving dynamic configuration with templates in a couple scenarios:

  • When facing limitations in CC templating
  • When operational data is required to achieve the desired configuration.

You can use the countdown event to trigger the applet immediately after the template is pushed. You will likely want to make your config applets temporal by either making them delete themselves, or utilising a second applet to clean up both applets.

I covered a few examples above and will be uploading more snippets to this Github repo going forwards.


See Also

Got feedback or a question?
Feel free to contact me at hello@torbjorn.dev