Here is my code as a work in progress. The output (at the very bottom of this post) suggests that everything is working fine, but in fact only 1 of the 2 poe bounce operations actually does a bounce. I can tell this because the connected devices have power indicator lights, and only one of them goes off.
I apologize for the anount of code, this is still a work in progress and not tidy!
"""aruba_commands_v2.py"""
import argparse
from concurrent import futures
import contextlib
import requests
import sys
import time
import aruba_common_v2
available_projects = aruba_common_v2.cfg.get('cpus', {})
available_switches = aruba_common_v2.cfg.get('switches', {})
def valid_project(project):
return True if project in available_projects else False
@contextlib.contextmanager
def switch_session(switch_name):
"""Use this context manager to ensure that we logout of the switch session"""
session = None
try:
session = SwitchSession(switch_name)
yield session
except RuntimeError:
raise
finally:
session and session.end_session()
class SwitchSession:
"""
Encapsulates all operations a switch session can perform.
Prefer to use the switch_session context manager as it will call end_session for you.
Otherwise make sure to call end_session (essentially a __del__() but we shouldn't
rely on Python to run it, as if it fails to, we'll leave sessions active.
"""
def __init__(self, switch_name):
# Modify session for no keep-alive
self.s = requests.Session()
# This should remove keep-alive, but I see no difference in behavior, so commenting it out for now
# del self.s.headers['Connection']
self.cookie = aruba_common_v2.login_os(self.s, switch_name)
if self.cookie is None:
raise RuntimeError('Switch login failed. Unable to get a cookie.')
self.ip = aruba_common_v2.cfg['switches'][switch_name]['ip']
self.base_url = 'http://{}/rest/v{}/'.format(self.ip, aruba_common_v2.api_version)
self.switch_name = switch_name
print(self.cookie)
def end_session(self):
"""Logout of the session."""
aruba_common_v2.logout_os(self.s, self.base_url, self.cookie)
def poe_bounce(self, projects, sleep_time=0):
"""
Bounce power on specified project.
:param str projects: projects to bounce
:param int sleep_time: time (seconds) to wait before restoring power
"""
if not isinstance(projects, list):
projects = [projects]
for project in projects:
if valid_project(project):
self.poe_disable(project)
if sleep_time > 0:
print('Waiting for {} seconds before restoring power to project {}.'.format(sleep_time, project))
time.sleep(sleep_time)
self.poe_enable(project)
else:
print('Invalid project {} cannot be bounced.'. format(project))
def poe_disable(self, projects):
"""
Disable power on specified project.
:param str projects: projects to bounce
"""
if not isinstance(projects, list):
projects = [projects]
for project in projects:
if valid_project(project):
port_number = aruba_common_v2.cfg['cpus'][project]['switch_port_{}'.format(self.switch_name[-1:])]
print('Performing poe disable for project {} on port {}.'.format(project, port_number))
commands = [
'configure terminal',
'interface {}'.format(port_number),
'no power-over-ethernet'
]
for cmd in commands:
aruba_common_v2.execute_cli(self.s, self.base_url, cmd, self.cookie)
else:
print('Invalid project {} cannot be poe disabled.'. format(project))
def poe_enable(self, projects):
"""
Enable power on specified port.
:param str projects: projects to bounce
"""
if not isinstance(projects, list):
projects = [projects]
for project in projects:
if valid_project(project):
port_number = aruba_common_v2.cfg['cpus'][project]['switch_port_{}'.format(self.switch_name[-1:])]
print('Performing poe enable for project {} on port {}.'.format(project, port_number))
commands = [
'configure terminal',
'interface {}'.format(port_number),
'power-over-ethernet'
]
for cmd in commands:
aruba_common_v2.execute_cli(self.s, self.base_url, cmd, self.cookie)
else:
print('Invalid project {} cannot be poe enabled.'. format(project))
def get_port_by_id(self, port_number):
"""
Get info on specified port
:param str port_number: port number
:return: JSON response
"""
port = '/ports/{}'.format(port_number)
return aruba_common_v2.execute_api_get(self.base_url, port, self.cookie)
def main():
parser = argparse.ArgumentParser(description='Bounce, enable or disable a project.')
# All arguments are positional and required
parser.add_argument(
'operation',
default='bounce',
choices=['bounce', 'enable', 'disable'],
help='POE operation to perform'
)
parser.add_argument(
'projects',
default='fca',
nargs='+',
choices=available_projects,
help='Project to operate on (default: %(default)s)'
)
parser.add_argument(
'switch',
choices=available_switches,
help='Switch to operate on'
)
parser.add_argument(
'-sleep',
'--sleep',
type=int,
default=0,
help='For bounce only, the time (seconds) between disabling and enabling the port'
)
args = parser.parse_args()
if 'all' in args.projects:
args.projects = available_projects
def switch_operation(project):
with switch_session(args.switch) as session:
print(session)
if 'bounce' in args.operation:
session.poe_bounce(project, args.sleep)
elif 'enable' in args.operation:
session.poe_enable(project)
else:
session.poe_disable(project)
with futures.ThreadPoolExecutor(2) as executor:
executor.map(switch_operation, args.projects)
sys.exit(0)
if __name__ == '__main__':
main()
And another file...
""aruba_common_v2.py.
You shouldn't need to import this module directly.
Instead, import aruba_commands and use its context manager function to issue poe commands.
"""
import json
import os
import sys
import requests
import yaml
YAML_CONFIG = 'Bench_Bird_s4_2p0.yaml'
user = ''user
password = 'password'
# Stacked switches should use version 3 or higher
api_version = '3'
try:
cfg = yaml.load(
open(
os.path.join(
os.path.dirname(__file__),
YAML_CONFIG),
'r'
)
)
except FileNotFoundError as error:
print('Bench Bird YAML configuration file is required: {}'.format(error))
sys.exit(1)
def login_os(s, switch_name):
"""
Login to ArubaOS REST API
:param string switch_name: name of the switch
:return: cookie header for REST API access for current session
:rtype: string
:Example:
>>>login_os('bbsa')
"""
params = {'userName': user, 'password': password}
proxies = {'http': None, 'https': None}
ip = cfg['switches'][switch_name]['ip']
url_login = 'http://{}/rest/v{}/login-sessions'.format(ip, api_version)
response = s.post(url_login, verify=False, data=json.dumps(params), proxies=proxies, timeout=3)
if response.status_code == 201:
print('Login to switch {} is successful.'.format(switch_name))
session = response.json()
r_cookie = session['cookie']
return r_cookie
else:
print('Login to switch {} returned HTTP {}.'.format(switch_name, response.status_code))
def logout_os(s, url, cookie):
"""
Logout of ArubaOS REST API
:param str url: base url of switch
:param str cookie: cookie header for REST API access for current session
:Example:
>>>logout_os('http://10.2.8.3/rest/v3/', 'e3k...Tse')
"""
url_login = url + "login-sessions"
headers = {'cookie': cookie}
proxies = {'http': None, 'https': None}
response = s.delete(url_login, headers=headers, verify=False, proxies=proxies)
if response.status_code == 204:
print('Logout of switch is successful.')
else:
print('Logout of switch is not successful ({}).'.format(response.status_code))
def execute_cli(s, url, cmd, cookie):
"""
Send CLI commands supported on ArubaOS switch via REST API.
:param str url: base url of switch
:param str cookie: cookie header for REST API access for current session
:param str cmd: cli command to be executed
:return JSON response
:Example:
>>>execute_cli('http://10.2.8.3/rest/v3/', 'show vlan', 'e3k...Tse')
"""
url = url + 'cli'
headers = {'cookie': cookie}
command = {"cmd": cmd}
response = s.post(url, verify=False, data=json.dumps(command), headers=headers)
print(response.json()['status'])
return response.json()
And finally here is output...
Login to switch bbsb is successful.
sessionId=6o2yHYGCxV7tjyfLkyQVBy8HRlRMqzgJV3quJgIT59grvhc9mGKFTvBUU6Z1tWx
<__main__.SwitchSession object at 0x108e55c18>
Performing poe disable for project mc on port 5.
Login to switch bbsb is successful.
sessionId=fyLQID4bzgrDhcvlFbhrgYrAsLAfH6QCtaWkDJVpzDJdqmGwis0YMxMos3gHo0a
<__main__.SwitchSession object at 0x108e55160>
Performing poe disable for project vns on port 4.
CCS_SUCCESS
CCS_SUCCESS
CCS_SUCCESS
CCS_SUCCESS
CCS_SUCCESS
Performing poe enable for project mc on port 5.
CCS_SUCCESS
Performing poe enable for project vns on port 4.
CCS_SUCCESS
CCS_SUCCESS
CCS_SUCCESS
CCS_SUCCESS
CCS_SUCCESS
CCS_SUCCESS
Logout of switch is successful.
Logout of switch is successful.
Process finished with exit code 0