Abstract
We require a nightly rebooting of our Ruckus Wireless WiFi access points. The Ruckus controllers (ZoneDirector™ and FlexMaster™) do not offer that capability [automated reboots] via their web interface. This blog posts describes a method of using the ruby expect library, ssh, cron, Ruckus’s CLI, and a ruby script to reboot the APs.
Create A Less-privileged User
We need to create a less-privileged (i.e. not a “Super Admin” user). You can probably guess where this is heading: we’re going to need to keep a plaintext copy of this user’s password on disk. Sure, we’re going to do our best job to lock down the file so no one can read it, but we need to plan for the worst: we need to minimize the amount of damage that can be done in the event the account is compromised.
- log into the web interface of the ZoneDirector (e.g. https://zone-director.pivotallabs.com)
- Configure → Roles → Create new
Name: ruckus_reboot
Description: For automated rebooting of the Ruckus APs
Administration: checked: Allow ZoneDirector Administration
selected: Operator Admin (Change settings affecting single AP’s only) - Click OK
- Configure → Users → Create new
- User Name: ruckus_reboot
Full Name: Reboot APs
Password: Iluvmuhdawg! (use a different password; this one is an example)
Confirm Password: Iluvmuhdawg!
Role: ruckus_reboot - Click OK
Put ruckus_reboot’s password in a safe place
We copy the password into a file that can only be read by the root user. Remember to substitute the password you originally created for the ruckus_reboot user:
echo 'Iluvmuhdawg!' | sudo tee ~root/.ruckus_reboot_passwd.txt
sudo chmod 400 ~root/.ruckus_reboot_passwd.txt
The Manual Procedure
We use the newly-created user to ssh into the ZoneDirector and reboot the APs. First, we log into the ZoneDirector to find out the MAC address of the AP we want to reboot:
$ ssh zone-director.pivotallabs.com
Please login: ruckus_reboot
Password:
Welcome to the Ruckus Wireless ZoneDirector 1100 Command Line Interface
ruckus> enable
ruckus# show ap all
AP:
ID:
1:
MAC Address= 50:a7:33:22:99:b0
Model= zf7962
...
Secondly, we use the MAC address of the WiFi AP (i.e. “50:a7:33:22:99:b0”) to tell the ZoneDirector to reboot that particular AP:
ruckus# debug
ruckus(debug)# restart-ap 50:a7:33:22:99:b0
The command was executed successfully.
ruckus(debug)# quit
No changes have been saved.
ruckus# exit
Exit Ruckus CLI.
Connection to ruckus-mgt closed.
The Automated Procedure (the Code)
We write a ruby script to automate the manual procedure. There are two aspects: first, we compile a list of the MAC addresses of the WiFi APs we want to reboot; secondly, we reboot the APs. The first is accomplished by using the show ap all
command and parsing it for the MAC addresses, and the second is accomplished by looping through the list of MAC addresses and sending the restart-ap
command. Copy the following script into a file named ap-reboot.rb
:
#!/usr/bin/env ruby
#
# ap-reboot.rb ruckus-zone-director ruckus-admin-account
#
# EXAMPLE: ap-reboot.rb zone-director.pivotallabs.com ruckus_reboot < ~root/.ruckus_reboot_passwd.txt
#
# This script remotely logs into a Ruckus Zone Director and reboots the APs
#
require 'pty'
require 'expect'
raise "#{__FILE__.gsub(/.*//, '')} ruckus-zone-director ruckus-admin-account" if ARGV.length != 2
password = STDIN.gets.chop
$expect_verbose=true
aps = []
def harvest_mac_addrs(buffers)
aps = []
buffers.each do |buffer|
buffer.lines do |line|
next if !line.match(/MAC Address/)
# chop chop for 'r' 'n'
mac_addr = line.chop.chop.gsub(/.*MAC Address= /, '')
aps << mac_addr
end
end
aps
end
PTY.spawn("ssh", ARGV[0]) do |ssh_out, ssh_in, pid|
ssh_out.expect(/ease login: /) { |r| ssh_in.printf("#n") }
ssh_out.expect(/assword: /) { |r| ssh_in.printf("#{password}n") }
ssh_out.expect(/uckus> /) { |r| ssh_in.printf("enablen") }
ssh_out.expect(/uckus# /) { |r| ssh_in.printf("show ap alln") }
ssh_out.expect(/uckus# /) do |r|
aps = harvest_mac_addrs(r)
ssh_in.printf("debugn")
end
aps.each do |ap|
ssh_out.expect(/uckus(debug)# /) do |r|
ssh_in.printf("restart-ap #{ap}n")
sleep(120)
end
end
ssh_out.expect(/uckus(debug)# /) { |r| ssh_in.printf("quitn") }
ssh_out.expect(/uckus# /) { |r| ssh_in.printf("exitn") }
end
Copy the script into place
$ sudo chmod 755 ap-reboot.rb
$ sudo cp -i ap-reboot.rb /usr/local/sbin/
Test the script
- Log into the ZoneDirector’s web interface (e.g. https://zone-director.pivotallabs.com).
- Monitor → Access Points
In a terminal, type the following:
sudo ssh zone-director.pivotallabs.com
Reply “yes” if you’re asked if you still want to connect even though the authenticity “can’t be established”. This step is merely to populate the ssh key; you don’t need to log in. Hit Ctrl-C if you’re presented with the “Please login:” prompt.
sudo cat ~root/.ruckus_reboot_passwd.txt | sudo /usr/local/sbin/ap-reboot.rb zone-director.pivotallabs.com ruckus_reboot
The length of time the script takes to finish executing is approximately 2.5 minutes/AP. It requires ~30 seconds per AP for setup, and it waits 120 seconds between each AP reboot.
From your browser, you can watch the APs rebooting (i.e. An AP’s status will change to “Disconnected” when it’s rebooting).
Add the script to the crontab
We decide to reboot the APs beginning at 54 minutes past midnight. We add the line to /etc/crontab on an Apple OS X 10.6 machine. Note that the existence of the /etc/crontab file is distribution-dependent: The file does not exist on later versions of OS X but does exist on FreeBSD 9.1 and Ubuntu 13.04.
$ sudo vim /etc/crontab
54 0 * * * root /usr/local/sbin/ap-reboot.rb zone-director.pivotallabs.com ruckus_reboot < ~root/.ruckus_reboot_passwd.txt > /dev/null 2>&1
Acknowledgements
What to expect from the Ruby expect library? is an excellent primer.