Wired Intelligent Edge

last person joined: yesterday 

Bring performance and reliability to your network with the HPE Aruba Networking Core, Aggregation, and Access layer switches. Discuss the latest features and functionality of your switching devices, and find ways to improve security across your network to bring together a mobile-first solution
Expand all | Collapse all

Are concurrent REST API sessions possible on HP-2920

This thread has been viewed 2 times
  • 1.  Are concurrent REST API sessions possible on HP-2920

    Posted Sep 07, 2018 06:51 PM

    I have a need to run POE bounce on many ports on my HP 2920. I have a Python script to do this which iterates a list of ports and then uses REST API to send the appopriate requests via the CLI endpoint. This works but it is slow. I would like to speed things up by opening multiple concurrent REST API sessions.

    Do I need each session to be a different user, or is it OK to use the same user for multiple sessions (and if so, how many sessions will I get)?

    I'm finding it very hard to get information about REST API users, but I do know that during my experiments to make this work I've managed to periodically exhaust the available REST  sessions... but I have no idea how to change that number either!



  • 2.  RE: Are concurrent REST API sessions possible on HP-2920

    MVP GURU
    Posted Sep 08, 2018 02:59 AM

    Hi Paul,

     

    Do you are using HTTP Keepalive ?

    Because i found this week a issue when use HTTP Keepalive and REST API...

    It is very slow between each API call... (need to wait 5secs)



  • 3.  RE: Are concurrent REST API sessions possible on HP-2920

    Posted Sep 08, 2018 07:06 PM

    Yes I am definitely seeing a delay of about that time (5 seconds). It's very odd. Even with just two threads, I am able to see the logins happen almost simultaneously, and they have unique cookies, but the sessions are not executing the poe operation concurrently or anything close to concurrently. I'm quite disappointed in the behavior, although I've found nothing in Aruba documenation that even talks about REST API concurrency. 



  • 4.  RE: Are concurrent REST API sessions possible on HP-2920

    MVP GURU
    Posted Sep 09, 2018 12:48 PM

    What your code ? because if you disable Keep Alive, it will be very fast (need to recreate a TCP session for each HTTP command)

     



  • 5.  RE: Are concurrent REST API sessions possible on HP-2920

    Posted Sep 09, 2018 10:01 PM

    I am using python Requests module, and I do see that keep-alive is enabled by default :(https://requests.readthedocs.io/en/master/user/advanced/#keep-alive) so I will disable it and try again. I will update here with the results.



  • 6.  RE: Are concurrent REST API sessions possible on HP-2920

    MVP GURU
    Posted Sep 10, 2018 03:30 AM

    What code do you are using ?

     

    because, yes on python with request KeepAlive is enable... but with this code, i don't reuse the TCP Session.....

     

    url_login = "http://@ip/rest/v4/login-sessions"
    payload_login = {"userName" : "admin", "password" : "enable"}
    
    get_cookie = requests.post(url_login, data=json.dumps(payload_login), verify=False)
    
    
    headers = {'cookie' : get_cookie.json()['cookie']}
    
    
    try:
        url_lldp = "http://@ip/rest/v3/lldp/remote-device"
        lldp = requests.get(url_lldp, headers=headers, verify=False)
        print("Get lldp neighbor (v3) : ")
        for u in lldp.json()['lldp_remote_device_element']:
            pprint.pprint(u)
    finally:
        delete_session = requests.delete(url_login, headers=headers, verify=False)
        print(delete_session.status_code)


  • 7.  RE: Are concurrent REST API sessions possible on HP-2920

    Posted Sep 10, 2018 01:30 PM

    Thanks for graciously sharing your code. I am not seeing concurrent operations. You do a login, save the cookie, use it in a single GET, then you logout. These are sequential operations. How would it behave if you iterated over 

    lldp_remote_device_element 

    and issued some other GET request concurrently on each of the elements, maybe using

    with futures.ThreadPoolExecutor

    to handle the concurrent Requests?

     

    I will post some of my own code soon. Thx again for sharing you code.



  • 8.  RE: Are concurrent REST API sessions possible on HP-2920

    Posted Sep 10, 2018 02:51 PM

    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

     

     



  • 9.  RE: Are concurrent REST API sessions possible on HP-2920

    MVP GURU
    Posted Sep 11, 2018 05:10 AM

    Do you have a example of yaml file ? (for try your code...)

     

    Yes, it is only a small example (but if make multiple get, i don't have issue with this code...)

     

    and also why don' t use directly the poe API ?



  • 10.  RE: Are concurrent REST API sessions possible on HP-2920

    Posted Sep 11, 2018 12:51 PM

     

    By tomorrow I will attach a YAML file, and also a requirements.txt so you can use a virtual env. Meantime, would you be kind enough to send me a link to the poe API? I had read that the CLI service was suggested because API had insufficient functionality for poe. I would certainly much prefer to use direct poe API and any example code you have for that would be incredibly welcome! Thanks again for taking your time to assist me and follow-up each day on this issue.



  • 11.  RE: Are concurrent REST API sessions possible on HP-2920
    Best Answer

    MVP GURU
    Posted Sep 11, 2018 02:28 PM

    You need to download REST API JSON and Schema

     

    https://h10145.www1.hpe.com/downloads/SoftwareReleases.aspx?ProductNumber=J9836A&lang=&cc=&prodSeriesId=

    And after go on folder device-rest-api -> services and common or wired following what you need for PoE it is on wired and open HTML file

     



  • 12.  RE: Are concurrent REST API sessions possible on HP-2920

    Posted Sep 28, 2018 01:18 PM

    Thx for your help. Attatched is the code that worked (note I use 3 threads for API access, as more than that causes the switch to reject sessions, which I assumed must be a switch limitation). I did not include a requirements.txt for a virtual environment, so you will need to pip install requests and yaml to your virtual environment.

     

    Since I cannot upload files with .py extension...

    Please rename the attached aruba_common.txt  and aruba_commands.txt to .py files

    Please rename the attached aruba.txt file to aruba.yaml

     

     

    How to use...

     

    import aruba_commands
    # YAML config file provides the data for looking-up the named switch credentials and port numbers on which named devices are found
    using aruba_commands.switch_session(switch_name='bbsb') as session:

    # PoE bounce the switch ports on which the 'fca' and 'vns' devices are found session.poe_bounce(['fca', 'vns']

     

    Attachment(s)

    txt
    aruba_common.txt   4 KB 1 version
    txt
    aruba_commands.txt   5 KB 1 version
    txt
    aruba.txt   2 KB 1 version