UPDATE github repo for this (H/T Scott Lowe)
One of the customers I’m currently supporting is performing a migration of their NetApp storage from classic 7-mode to Clustered Data OnTap. It’s a fiber channel environment so lots of FC zoning changes are required. To minimize mistakes and ensure consistency, some form of automation is needed. The Cisco MDS fiber channel switches run a version of NX-OS but it’s relatively old and doesn’t include an accessible API-based interface.
Enter Kirk Byers' excellent NetMiko python library. The initial task was to get zones available to present the new Clustered Data OnTap storage to various hosts. Since the customer already has zoning to the 7mode environment, we can get the host WWPNs from existing fcaliases on the switches and create our new zones using that information. With netmiko, I can leverage ssh to grab the information needed in a programmatic fashion and I can push the new zones directly to the switches.
The first trick is generating zoning commands using existing fcalias entries.
We’re relying on straightforward pattern matching of hostnames to fcalias
names on the switch to do this. Here’s the help output from the script
genzonesfromexistingfcaliases.py
usage: genzonesfromexistingfcaliases.py [-h] --hostname HOSTNAME
--hosts_filename HOSTS_FILENAME --vsan
VSAN --zoneset ZONESET
[--fcalias_filename FCALIAS_FILENAME]
[--target_fcalias TARGET_FCALIAS]
[--username USERNAME]
[--get_from_switch]
[--password PASSWORD] [--use_keys]
[--backout] [--key_file KEY_FILE]
Generate zoning commands from input file listing of short hostnames one per
line. Will match against switch fcalias entries by hostname pattern. print to
STDOUT. redirect with > filename.txt
optional arguments:
-h, --help show this help message and exit
--hostname HOSTNAME MDS switch fqdn or IP.
--hosts_filename HOSTS_FILENAME
list of hosts to match against. one per line
--vsan VSAN VSAN for fcaliases/zones
--zoneset ZONESET zoneset name
--fcalias_filename FCALIAS_FILENAME
generated fcaliases output from 'ssh
username@switchname show fcalias >
switch_fcaliases.txt'
--target_fcalias TARGET_FCALIAS
optional fcalias name of cDOT cluster on switch.
default ='NAC1'
--username USERNAME optional username to ssh into mds switch. Alternate:
set environment variable MDS_USERNAME. If neither
exists, defaults to current OS username
--get_from_switch get fcaliases directly from switch instead of file.
NOTE: not yet implemented
--password PASSWORD optional password to ssh into mds switch. Alternate:
set environment variable MDS_PASSWORD. If unset
use_keys defaults to True.
--use_keys use ssh keys to log into switch
--backout generate backout commands
--key_file KEY_FILE filename for ssh key file
There are several inputs required here. You need a switch hostname to login
to, a file of hostnames to pattern match against, a VSAN identifier, and a
zoneset identifier as well. Those of course you get from the switch as
well. In the current version I supply the output of show fcalias
from the
switch in a text file. I have a todo item to simply grab this directly from
the switch during the run of the script. Also, it wouldn’t be too hard to use
devalias entries in lieu of fcaliases.
The output is a simple text file of zoning commands. If you have an ssh key setup on the switch already, you can log straight in without providing a password parameter or (better) environment variable. Here’s an example of running it:
sharney@ubuntu-san-automation:~/source$ python ./genzonesfromexistingfcaliases.py \
--hostname mds1 --hosts_file my_hosts.txt --fcalias_filename mds1_sh_fcalias.txt \
--vsan 101 --zoneset ZS_MDS1 > mds1_my_hosts_zones.txt
which produced a file that looks like this:
zone name myhostt001_01_NAC1 vsan 101
member fcalias NAC1
member fcalias myhostt001_01
zone name myhostt002_01_NAC1 vsan 101
member fcalias NAC1
member fcalias myhostt002_01
zoneset name ZS_MDS1 vsan 101
member myhostt001_01_NAC1
member myhostt002_01_NAC1
the NAC1
fcalias is a default target fcalias as noted in the help output.
This a text file you could just cut and paste directly into the switch and
then activate the zoneset. You’ll also note that we can create a backout file
which removes the configuration entries.
While cut and pasting is fine, where’s the fun in that. dozones.py
can
actually login to the switch and execute. Here’s the help output
./dozones.py --help
usage: dozones.py [-h] --hostname HOSTNAME --filename FILENAME
[--username USERNAME]
[--password PASSWORD] [--use_keys] [--dry_run]
[--key_file KEY_FILE] [--activate_zoneset]
push zoning configuration to MDS switch from generated command file. Zoneset
name and VSAN are derived form the input file.
optional arguments:
-h, --help show this help message and exit
--hostname HOSTNAME MDS switch fqdn or IP.
--filename FILENAME Generated file with zoning commands to push to the mds
switch.
--username USERNAME optional username to ssh into mds switch. Alternate:
set environment variable MDS_USERNAME. If neither
exists, defaults to current OS username
--password PASSWORD optional password to ssh into mds switch. Alternate:
set environment variable MDS_PASSWORD. If unset
use_keys defaults to True.
--use_keys use ssh keys to log into switch
--dry_run don't do anything. just print some debug output
--key_file KEY_FILE filename for ssh key file
--activate_zoneset add the 'zoneset activate' command to activate the updated zoneset
The --activate
parameter is provided as perhaps an additional safety valve.
Once you activate the zoneset you’re making the change ‘for real’ so to speak
and an error here would be significant. You can add zones and even add zones
to a zoneset without necessarily activating that zoneset. You could then do a
final check of the active zoneset and your updated zoneset prior to manually
activating if desired.
Here’s a sample --dry_run
which does login to switch but doesn’t execute the
commands.
sharney@ubuntu-san-automation:~/source$ ./dozones.py --hostname 10.10.1.1 --filename mds1_my_hosts_zones.txt --dry_run --activate
DRY RUN: prompt = MDS1#
DRY RUN: command list = ['zone name myhostt001_01_NAC1 vsan 101', 'member fcalias NAC1', 'member fcalias myhostt001_01', 'zone name myhostt002_01_NAC1 vsan 101', 'member fcalias NAC1', 'member fcalias myhostt002_01', 'zoneset name ZS_MDS1 vsan 101', 'member myhostt001_01_NAC1', 'member myhostt002_01_NAC1']
['zoneset activate name ZS_MDS1 vsan 101']
DRY RUN: activate command = ['zoneset activate name ZS_MDS1 vsan 101']
when you run it without --dry_run
it will show you the commands executed on
the switch. eg:
sharney@ubuntu-san-automation:~/source$ ./dozones.py --hostname 10.10.1.1 --filename mds1_my_hosts_zones.txt -activate
config term
Enter configuration commands, one per line. End with CNTL/Z.
MDS1(config-zone)# zone name myhostt001_01_NAC1 vsan 101
MDS1(config-zone)# member fcalias NAC1
MDS1(config-zone)# member fcalias myhostt001_01
MDS1(config-zone)# zone name myhostt002_01_NAC1 vsan 101
MDS1(config-zone)# member fcalias NAC1
MDS1(config-zone)# member fcalias myhostt002_01
MDS1(config-zone)# zoneset name ZS_MDS1 vsan 201
MDS1(config-zoneset)# member myhostt001_01_NAC1
MDS1(config-zoneset)# member myhostt002_01_NAC1
MDS1(config-zoneset)# end
MDS1#
['zoneset activate name ZS_MDS1 vsan 201']
config term
Enter configuration commands, one per line. End with CNTL/Z.
MDS1(config)# zoneset activate name ZS_MDS1 vsan 101
WARNING: New Zoneset ZS_MDS1 is significantly bigger than current active Zoneset ZS_MDS1. Do you want to continue? (y/n) [n] y
MDS1#
One interesting wrinkle came up in testing that pushing a large amount of
zoning changes to an active zoneset results in a confirmation prompt on the
switch. With an assist from Kirk Byers (netmiko’s author) I was able to work
through this and catch and respond to the prompt which preserves the
automation. Also note that dozones.py
does copy the updated switch running
configuration to the startup configuration.
This has been used several times at the customer site now. This is a large enough customer that we have a switch in a lab that we can test against. I don’t have a virtual MDS switch I can test and as near as I can tell if that’s available it’s at a substantial subscription cost. It’s better to be able to test against a real switch in any case and we have one.
This is just a first step, of course. Some plans going forward
- add the automated grab of fcalias entries
- reduce the required manual inputs for the zoning commands generation script. There’s too many opportunites for error.
- there are some assumptions here that one VSAN is used, that pattern matching against legacy existing zones will work
- ultimately create scripts to generate new zoning workflow
- ‘ansiblize’ this to create provisioning workflows. I’ve done some initial work on an ansible module for NetApp cDOT
- Matt Oswalt’s work on this was a key jumping off point. with UCS and CDOT having virtualized interfaces (WWPNs) that we can grab directly, it’s not too hard to see that one can bulid a playbook or series of playbooks to provision these items.