Configure a Cisco IOS-XE AP for an APoS Site Survey using Python

I wanted to play around and see how I could automate the process of preparing a Cisco AP for an APoS site survey. So I decided to try it out on a Catalyst 9120 running IOS-XE. In this article, I will explain how to use the script.

In order to make this work within a python script, we need to leverage a python library called pyserial which allows us to interact with the AP over a console connection.

DESCRIPTION

This script can be used to configure an Cisco AP for an APoS site survey.
This will only work if the AP is running IOS-XE (Tested with v16.12.02).
This will only work if the AP is running the EWC image with factory configurations.
​This script will rely on you to setup a console connection to the AP in order to work properly.

The set of configurations used to configure the AP can be found here: config-apos-c9120.txt

Note: this script has only been tested on macOS using an AirConsole.

PREREQUISITES

This script require you to have the following modules installed in your Python environment:

  • pyserial

If the module is not installed, run the following command to install it: pip install pyserial
I cannot guarantee that this script will work if the AP has already been configured. If it is the case, before running this script, please reset the AP to its factory configuration using this command: wireless ewc-ap factory-reset

I am text block. Click edit button to change this text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.

Before running the script, make sure that you perform the following:

  1. Make sure that the AP is running the EWC code
  2. Connect the AP to the network (and provide power via PoE)
  3. Wait for the AP to go through its initial booting sequence (this initial boot sequence lasts about 5mins, you should see a solid green LED when it is completed).
  4. Connect your console cable to the console port of the AP
  5. Connect the other end of the console cable to your computer

SCRIPT CONFIGURATIONS

All the configurations are located into the config.json file and it is used to configure the following settings:

  • Your console connection details:
    • YYT used by the serial connection (Ex: /dev/tty.AirConsole-68-raw-serial)
  • Settings related to the Embedded Wireless Controller:
    • Name
    • IP address
    • Netmask
    • Username
    • Password
  • Settings related to the SSIDs you want the AP to broadcast:
    • Name of the WLAN profile
    • Name of the SSID
    • PSK
    • Frequency band
  • Settings related to the AP we are using:
    • MAC address (can be found at the back of the AP. Make sure to use the “XXXXXXXXXXXX” format)
    • FRA AP (Dual-5GHz compatible AP)
    • Name
    • IP address
    • Netmask
    • Gateway
  • Configurations of the 5GHz radio settings:
    • Channel
    • Tx Power (using the Cisco Index value)
    • Channel Width
  • Configurations of the 2.4GHz radio settings:
    • Channel
    • Tx Power (using the Cisco Index value)
  • Configuration of the FRA radio setting:
    • Channel
    • Tx Power (using the Cisco Index value)
    • Channel Width

Here is an example:

{
  "tty": "/dev/tty.AirConsole-68-raw-serial",
  "ewc": {
    "name": "C9800-APoS-Survey",
    "ip": "192.168.20.100",
    "netmask": "255.255.255.0",
    "username": "admin",
    "password": "SemFioAPoS123!"
  },
  "wlans": [
    {
      "name": "Survey-5",
      "ssid": "Cisco Survey-5",
      "psk": "SemFio123"
    },
    {
      "name": "Survey-24",
      "ssid": "Cisco Survey-2.4",
      "psk": "SemFio123"
    }
  ],
  "ap": {
    "mac": "2CF89B216E1C",
    "fra_ap": "true",
    "name": "Survey-AP",
    "ip": "192.168.20.101",
    "netmask": "255.255.255.0",
    "gateway": "192.168.20.1",
    "band_5": {
      "channel": "44",
      "bandwidth": "20",
      "tx-power": "6"
    },
    "band_24": {
      "channel": "1",
      "tx-power": "5"
    },
    "band_fra": {
      "channel": "1",
      "bandwidth": "20",
      "tx-power": "5"
    }
  }
}

Make sure that you set the proper variables in this config.json file before running the script.

DOWNLOAD FROM MACOS TERMINAL

Here is how to install the script to use it on your own machine:
git clone https://github.com/francoisverges/semfio-cisco.git

Then you can navigate to the script directory:
cd semfio-mist/Setup-APoS-EWC

USAGE

Configure the config.json file with the proper parameters (as defined earlier)
In order to use the script, all you have to do is the following:
python3 setup-AP0S-EWC.py config.json

Here is what the output will look like if everything goes well:

** Setting up Cisco C9800 APoS AP
Connecting to /dev/tty.AirConsole-68-raw-serial...
 
########################################################################################################
#                                                                                                      #
#      Welcome to the Cisco Catalyst 9800-AP Embedded Wireless Controller command line interface       #
#                                                                                                      #
#                      !!! Please complete the DAY0 Device Provisioning !!!                            #
#                   !!! NOTE: COMPLETE ALL THE STEPS IN PROVISIONING GUIDE !!!                         #
#                                                                                                      #
#                     To access the provisioning guide type the below command:                         #
#                         more bootflash:ewc_day0_device_provisioning_guide                            #
#                                                                                                      #
########################################################################################################
 
WLC2CF8.9B21.6E1C>
WLC2CF8.9B21.6E1C>enable
WLC2CF8.9B21.6E1C#ap name AP2CF8.9B21.6E1C name Survey-AP
WLC2CF8.9B21.6E1C#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
WLC2CF8.9B21.6E1C(config)#line console 0
WLC2CF8.9B21.6E1C(config-line)#logging sync
WLC2CF8.9B21.6E1C(config-line)#exit
WLC2CF8.9B21.6E1C(config)#hostname C9800-APoS-Survey
C9800-APoS-Survey(config)#interface gigabitEthernet 0
C9800-APoS-Survey(config-if)#ip address 192.168.20.100 255.255.255.0
 
*Jul 14 20:10:17.964: %PNP-6-PNP_SAVING_TECH_SUMMARY: Saving PnP tech summary (pnp-tech-discovery-summary)... Please wait. Do not interrupt.
*Jul 14 20:10:19.309: %SYS-5-CONFIG_P: Configured programmatically by process PnP Agent Discovery from console as vty0
*Jul 14 20:10:21.170: %SYS-5-CONFIG_P: Configured programmatically by process PnP Agent Discovery from console as vty0
C9800-APoS-Survey(config-if)#$min privilege 15 password SemFioAPoS123!
 WARNING: Command has been added to the configuration using a type 0 password. However, type 0 passwords will soon be deprecated. Migrate to a supported password type
C9800-APoS-Survey(config)#ap profile default-ap-profile
C9800-APoS-Survey(config-ap-profile)#
*Jul 14 20:10:22.172: %PNP-6-PNP_TECH_SUMMARY_SAVED_OK: PnP tech summary (pnp-tech-discovery-summary) saved successfully.
*Jul 14 20:10:22.172: %PNP-6-PNP_DISCOVERY_STOPPED: PnP Discovery stopped (Config Wizard)
*Jul 14 20:10:23.214: %AAA-5-USER_RESET: User admin failed attempts reset by console
*Jul 14 20:10:23.214: %AAAA-4-CLI_DEPRECATED: WARNING: Command has been added to the configuration using a type 0 password. However, type 0 passwords will soon be deprecated. Migrate to a supported password type
C9800-APoS-Survey(config-ap-profile)#$APoS123! secret 0 SemFioAPoS123!
C9800-APoS-Survey(config-ap-profile)#
*Jul 14 20:10:23.430: %CAPWAPAC_SMGR_TRACE_MESSAGE-5-AP_JOIN_DISJOIN: Chassis 1 R0/0: wncd: AP Event: AP Name: Survey-AP, MAC: 2cf8.9b21.6e1c Disjoined
*Jul 14 20:10:24.529: %CAPWAP_IMGDWNLD_TRACE_MESSAGE-5-CAPWAPIMGDWNLD_EWC_AP_AP_LIST_EVENTS: Chassis 1 R0/0: wncd: List Event: AP with wtp_mac 10b3.c625.08e0 for Image Type ap1g7 is removed from Master AP list
C9800-APoS-Survey(config-ap-profile)#wlan Survey-5 1 "Cisco Survey-5"
C9800-APoS-Survey(config-wlan)#no security wpa akm dot1x
C9800-APoS-Survey(config-wlan)#security wpa psk set-key ascii 0 SemFio123
C9800-APoS-Survey(config-wlan)#security wpa akm psk
C9800-APoS-Survey(config-wlan)#no shutdown
C9800-APoS-Survey(config-wlan)#exit
C9800-APoS-Survey(config)#wlan Survey-24 2 "Cisco Survey-2.4"
C9800-APoS-Survey(config-wlan)#no security wpa akm dot1x
C9800-APoS-Survey(config-wlan)#security wpa psk set-key ascii 0 SemFio123
C9800-APoS-Survey(config-wlan)#security wpa akm psk
C9800-APoS-Survey(config-wlan)#no shutdown
C9800-APoS-Survey(config-wlan)#exit
C9800-APoS-Survey(config)#wireless profile policy Survey-5
C9800-APoS-Survey(config-wireless-policy)#no central association
C9800-APoS-Survey(config-wireless-policy)#no central dhcp
C9800-APoS-Survey(config-wireless-policy)#no central switching
C9800-APoS-Survey(config-wireless-policy)#http-tlv-caching
C9800-APoS-Survey(config-wireless-policy)#session-timeout 86400
C9800-APoS-Survey(config-wireless-policy)#no shutdown
C9800-APoS-Survey(config-wireless-policy)#exit
C9800-APoS-Survey(config)#wireless profile policy Survey-24
C9800-APoS-Survey(config-wireless-policy)#no central association
C9800-APoS-Survey(config-wireless-policy)#no central dhcp
C9800-APoS-Survey(config-wireless-policy)#no central switching
C9800-APoS-Survey(config-wireless-policy)#http-tlv-caching
C9800-APoS-Survey(config-wireless-policy)#session-timeout 86400
C9800-APoS-Survey(config-wireless-policy)#no shutdown
C9800-APoS-Survey(config-wireless-policy)#exit
C9800-APoS-Survey(config)#wireless tag policy default-policy-tag
C9800-APoS-Survey(config-policy-tag)#wlan Survey-5 policy Survey-5
C9800-APoS-Survey(config-policy-tag)#wlan Survey-24 policy Survey-24
C9800-APoS-Survey(config-policy-tag)#exit
C9800-APoS-Survey(config)#service password-encryption
C9800-APoS-Survey(config)#password encryption aes
C9800-APoS-Survey(config)#key config-key newpass SemFioAPoS123!
C9800-APoS-Survey(config)#end
Waiting for the AP to join the controller (it takes about 1min)......................................................................
*Jul 14 20:10:42.802: %SYS-5-CONFIG_I: Configured from console by console
C9800-APoS-Survey#
*Jul 14 20:11:10.294: %CAPWAPAC_SMGR_TRACE_MESSAGE-5-AP_JOIN_DISJOIN: Chassis 1 R0/0: wncd: AP Event: AP Name: Survey-AP, MAC: 2cf8.9b21.6e1c Joined
*Jul 14 20:11:10.496: %CAPWAP_IMGDWNLD_TRACE_MESSAGE-5-CAPWAPIMGDWNLD_EWC_AP_AP_LIST_EVENTS: Chassis 1 R0/0: wncd: List Event: AP with wtp_mac 10b3.c625.08e0 for Image Type ap1g7 is added to Master AP list
C9800-APoS-Survey#ap name Survey-AP dot11 dual-band channel 1
C9800-APoS-Survey#ap name Survey-AP dot11 dual-band txpower 5
C9800-APoS-Survey#ap name Survey-AP dot11 5ghz channel 44
C9800-APoS-Survey#ap name Survey-AP dot11 5ghz txpower 6
C9800-APoS-Survey#$2.168.20.101 netmask 255.255.255.0 gateway 192.168.20.1
Changing the AP's IP address will cause the AP to rejoin. Are you sure you want to continue?[y][confirm]
C9800-APoS-Survey#write memory
Building configuration...
Now, wait for the AP to reboot and start broadcasting the survey SSID!
Happy Site Survey!
 
** Time to run: 105.88 sec

Note: if you see the following output, juste validate your console connection and re-run the script:

** Setting up Cisco C9800 APoS AP
Traceback (most recent call last):
  File "/Users/francoisverges/SynologyDrive/Lab/Python/venv/py3.8-cisco/lib/python3.8/site-packages/serial/serialposix.py", line 265, in open
    self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
OSError: [Errno 16] Resource busy: '/dev/tty.AirConsole-68-raw-serial'
 
During handling of the above exception, another exception occurred:
 
Traceback (most recent call last):
  File "setup-APoS-EWC.py", line 187, in 
    main()
  File "setup-APoS-EWC.py", line 181, in main
    configure_APoS(configs)
  File "setup-APoS-EWC.py", line 59, in configure_APoS
    with serial.Serial(configs['tty'], timeout=1) as ser:
  File "/Users/francoisverges/SynologyDrive/Lab/Python/venv/py3.8-cisco/lib/python3.8/site-packages/serial/serialutil.py", line 240, in __init__
    self.open()
  File "/Users/francoisverges/SynologyDrive/Lab/Python/venv/py3.8-cisco/lib/python3.8/site-packages/serial/serialposix.py", line 268, in open
    raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
serial.serialutil.SerialException: [Errno 16] could not open port /dev/tty.AirConsole-68-raw-serial: [Errno 16] Resource busy: '/dev/tty.AirConsole-68-raw-serial'

Once the script is done, the AP will reboot. Wait for the reboot process to finish. The AP will then be ready for you to use for your APoS site survey.

You can connect it to your favourite PoE battery, wait for it to boot (it takes a while… wait for the LED to be green) and validate that the AP is broadcasting the survey SSID(s):

RESOURCES

Leave a Reply

Your email address will not be published. Required fields are marked *