Giter Club home page Giter Club logo

pyaoscx's Introduction

pyaoscx

These modules are written for AOS-CX API v10.04 and later. These scripts are written for devices running AOS-CX firmware version 10.04 or greater.

See the Release Notes for more information.

Please note that pyaoscx v2 is not backwards compatible for pyaoscx v1 and earlier, so please specify the correct version when using pyaoscx in requirements.txt files

It is also important to note that the latest code commits on the Master branch in Git are usually ahead of the official releases and tags, so please be aware of this when cloning the repo versus doing a pip install pyaoscx

Structure

Detailed information about the structure and design can be found in the Design document.

  • REST API call functions are found in the modules in /pyaoscx.
  • REST API call functions are combined into other functions that emulate low-level processes. These low-level process functions are also placed in files in /pyaoscx.
  • Functions from the /pyaoscx files (API functions and low-level functions) are combined to emulate larger network configuration processes (workflows). These workflow scripts stored in the /workflows folder.

How to contribute

Please see the accompanying CONTRIBUTING.md file for guidelines on how to contribute to this repository.

Git Workflow

This repo adheres to the 'shared repo' git workflow:

  1. Clone the repo to a local machine:

    git clone <repo_URL>

  2. Checkout a local working branch:

    git checkout -b <local_working_branch_name>

  3. Add and amend files in the local working branch:

    git add <file_name>

  4. Commit regularly. Each commit should encompass a single logical change to the repo (e.g. adding a new function in /pyaoscx is one commit; writing docstrings for all functions in a module is another commit). Include an explanatory message with each commit:

    git commit -m "<Clear_explanation_of_commit_here>"

  5. Push commits to github.hpe.com:

    git push origin <local_working_branch_name>

  6. Merge changes using a Pull Request on github.hpe.com. Ensure the PR has a relevant title and additional comments if necessary. PRs should be raised regularly once code is tested and the user satisfied that it is ready for submission. Do not put off creaing a PR until a whole project is complete. The larger the PR, the difficult it is to successfully merge.

Setup

Before starting ensure the switch REST API is enabled. Instructions for checking and changing whether or not the REST API is enabled status are available in the ArubaOS-CX Rest API Guide. This includes making sure each device has an administrator account with a password, and each device has https-server rest access-mode read-write and enabled on the reachable vrf.

How to run this code

In order to run the workflow scripts, please complete the steps below:

  1. install virtual env (refer https://docs.python.org/3/library/venv.html). Make sure python version 3 is installed in system.

    $ python3 -m venv switchenv
    
  2. Activate the virtual env

    $ source switchenv/bin/activate
    in Windows:
    $ venv/Scripts/activate.bat
    
  3. Install the pyaoscx package

    (switchenv)$ pip install pyaoscx
    
  4. Now you can run different workflows from pyaoscx/workflows (e.g. print_system_info.py)

  5. Keep in mind that the workflows perform high-level configuration processes; they are highly dependent on the configuration already on the switch prior to running the workflows. For this reason, the comment at the top of each workflow script describes any necessary preconditions.

Troubleshooting Issues

  1. If you encounter module import errors, make sure that the package has been installed correctly.

Additionally, please read the RELEASE-NOTES.md file for the current release information and known issues.

pyaoscx's People

Contributors

ajavier avatar alvinc13 avatar blag avatar danielalvaradob avatar danielgarciavaglio avatar dcorderohpe avatar derekwanghpearuba avatar isela-aley avatar joss-ag avatar tchiapuziowong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyaoscx's Issues

Feature request: support for autocheckpoint

We'd like to use pyaoscx for the following workflow:

  1. Retrieve JSON configuration for a switch from NetBox.
  2. Create an autocheckpoint with a 5 minute timeout.
  3. Upload the configuration to switch.
  4. Acknowledge autocheckpoint before 5 minute timeout.

For this workflow we need a pyaoscx function that calls the "/configs/autocheckpoint" API endpoint with POST for enabling the autocheckpoint with a specific time in minutes and with PUT for acknowledging the checkpoint before the timer runs out. Would it be possible to implement this?

Firmware update fails

Hello,

pyaoscx version 2.3.1

I tried to upload firmware but get an error:
pyaoscx.exceptions.response_error.ResponseError: "RESPONSE ERROR: Invalid URL 'firmware?image=secondary': No scheme supplied. Perhaps you meant http://firmware?image=secondary?: Response: POST"

Implement Ruff

Please implement the Ruff linter and resolve issues. I suggest configuring Ruff with all rules enabled by default and then selectively disable problematic rules. Ruff covers a significant fraction of pylint's rules and those from many other linters. Ruff implements all or virtually all of flake8 rules - so, you could remove flake8. Ruff should be run under Github CI.

Unable to create a Loopback

I am trying to create a lookback using pyaoscx ver 2.1.0

my code is:

from pyaoscx.session import Session
from pyaoscx.pyaoscx_factory import PyaoscxFactory

import urllib3
import traceback
import logging

urllib3.disable_warnings()

host = "192.168.91.200"
version = "10.04"

s = Session(host, version)
s.open("admin", "admin")

try:
factory = PyaoscxFactory(s)
loopback_2 = factory.interface("loopback2")
loopback_2.configure_loopback("fred", ipv4=["7.7.7.7/32"], description=None)

except Exception as e:
logging.error(traceback.format_exc())

finally:
session.close()

The error I get is:

ERROR:root:Traceback (most recent call last):
File "create_lo2.py", line 32, in
loopback_2.configure_loopback("fred", ipv4=["7.7.7.7/32"], description=None)
File "C:\Users\user1\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pyaoscx\interface.py", line 1430, in configure_loopback
return self.apply()
File "C:\Users\user1\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pyaoscx\pyaoscx_module.py", line 33, in ensure_connected
return fnct(self, *args, **kwargs)
File "C:\Users\user1\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pyaoscx\interface.py", line 534, in apply
modified = self.update()
File "C:\Users\user1\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pyaoscx\pyaoscx_module.py", line 33, in ensure_connected
return fnct(self, *args, **kwargs)
File "C:\Users\user1\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pyaoscx\interface.py", line 730, in update
raise GenericOperationError(
pyaoscx.exceptions.generic_op_error.GenericOperationError: GENERIC OPERATION ERROR

any assistance appreciated

docs are not readable.

I can not find the guide about how to use pyaoscx for each module and the docs in the github are not readable.

Checkpoint support

Hi,
First of all, thanks for the module.

I was wondering if there're plans for supporting checkpoint management, rollback, etc.

Get Interface of all MAC addresses

Hello,

apologies if this is not the right location.

Using python 3.8 and latest pyaoscx in pip

I've been trying to use this library to get all the VLANs, their MAC addresses and which interface each MAC address is on.

https://github.com/aruba/pyaoscx/blob/master/pyaoscx/mac.py#L142 has a bit about port is under get() - but it's not under get_all() so I'm thinking maybe it's not possible?

Do you have some suggestion for how one could get this piece of information with one API call? (My workaround right now is to make lots of API calls, one for each Mac address directly the REST API without using this library to get the information). Do you happen to know if there some way to run a command like show mac-address-table ?

Could I throw in the depth= parameter in some good place?

I created a gist with an example code that tries to print the port but it doesn't, it fails with

$ python example_mac.py 
<class 'pyaoscx.mac.Mac'>
['_Mac__modified', '__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', '_abc_impl', '_extract_missing_parameters_from', '_get_and_copy_data', '_get_data', '_is_replace_required', '_mac_path', '_original_attributes', '_parent_vlan', '_post_data', '_put_data', '_send_data', '_set_configuration_items', '_set_vlan', '_uri', 'apply', 'base_uri', 'config_attrs', 'connected', 'create', 'delete', 'deprecated', 'display_name', 'from_id', 'from_response', 'from_uri', 'get', 'get_all', 'get_info', 'get_info_format', 'get_uri', 'indices', 'info_format', 'mac_address', 'mac_format', 'materialized', 'modified', 'path', 'resource_uri_name', 'session', 'update', 'uri_path', 'was_modified']
Ran into exception: 'Mac' object has no attribute 'port'. Closing session.
Traceback (most recent call last):
  File "example_mac.py", line 46, in get_aruba_macs
    print(macs[mac].port)
AttributeError: 'Mac' object has no attribute 'port'

https://gist.github.com/martbhell/ffa751efd09f156bc6eb3d4ce7890460

Push to PyPi

when will recent updates be pushed to pypi? I need the poe_interface capability, and it has not been push out...

Connection via IPv6 using IP-Address fails

Trying to connect to a device using and IPv6 Address fails with the error: raise LoginError("Cookies were not set correctly. Login failed")
I did encase the IP Address in square brackets like [2001:db8:1::25], as it is customary for URLs. Without the brackets, I got even more parsing errors.

In the file session.py:159 in method open(...): )

        self.connected = (
            hasattr(cookies, "_cookies") and self.ip in cookies._cookies
        )

the check for connected fails, as for some reason unknown to me the switch returns the cookie with the address [2001:db8:1::25].local. This extra .local at the end of the ip fails the test condition.

I tried to mitigate by also checking for .local, and that is a workaround for my development machine at the moment.

        self.connected = hasattr(cookies, '_cookies') and (self.ip in cookies._cookies or "%s.local"% self.ip in cookies._cookies)

I would really appreciate a fix for this in the official pypi version (or in aos-cx, whatever is preferred), as plan to run this on ipv6-only networks, and newly deployed switches do not have dns entries yet.
If I need to push this via my SE or a support case, please tell me as that would be possible.

can't update vlan info

I try to use pyaoscx (2.1.0) for update vlan information based on workflow.py script

i write the following script

from pyaoscx.session import Session
from pyaoscx.pyaoscx_factory import PyaoscxFactory
from pyaoscx.vlan import Vlan
from pyaoscx.interface import Interface
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# There are two approaches to workflows, both using the session.
version = '10.04'
switch_ip = '10.200.11.225'
s = Session(switch_ip, version)
s.open('admin', 'MyPassword')

try:
    vlan100 = Vlan(s, 100)
    vlan100.get()
    print ("vlan100 {}".format(vlan100))

    #update vlan 100 (voice and description)
    vlan100.voice = True
    vlan100.name = "My Vlan"
    vlan100.description = "My description"
    print ("vlan100 {}".format(vlan100))
    vlan100.apply()

    vlan100.get()
    print ("vlan100 {}".format(vlan100))

    # ===========================================================
    # ===========================================================
    # ===========================================================

except Exception as error:
    print('Ran into exception: {}. Closing session.'.format(error))

finally:
    # At the end, the session MUST be closed
    s.close()

but don't work :

vlan100 Vlan, name: 'vlan100' ID: '100' and description: 'None'
vlan100 Vlan, name: 'My Vlan' ID: '100' and description: 'My description'
vlan100 Vlan, name: 'vlan100' ID: '100' and description: 'None'

other objects, such as lldp ?

This class is good, but appears to miss some features, such as interface lldp neighbors, and interface known/heard ethernet addresses (ie the switching table)? Will this be implemented at some point ?

aoscx_l3_interface fails on 6200 tries to fetch BGP details from sw that doesn't support BGP

The 6200 doesn't support BGP,

swagger on the 6200 shows the BGP method:
https://<ip of 6200>/rest/v10.04/system/vrfs/default/bgp_routers

However it returns a 404
unknown attribute for VRF: bgp_routers

In ansible aoscx_l3_interface on a 6200 (or 6100 which would be an issue anyway as the 6100 does not support Routed only ports) will throw an error as it's not handling this response, which is valid given the devices don't support it.

Traceback (most recent call last):
  File "/home/wade/.ansible/tmp/ansible-local-24017e3clgz02/ansible-tmp-1642567562.535256-24022-51633859472383/AnsiballZ_aoscx_l3_interface.py", line 107, in <module>
    _ansiballz_main()
  File "/home/wade/.ansible/tmp/ansible-local-24017e3clgz02/ansible-tmp-1642567562.535256-24022-51633859472383/AnsiballZ_aoscx_l3_interface.py", line 99, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/home/wade/.ansible/tmp/ansible-local-24017e3clgz02/ansible-tmp-1642567562.535256-24022-51633859472383/AnsiballZ_aoscx_l3_interface.py", line 47, in invoke_module
    runpy.run_module(mod_name='ansible_collections.arubanetworks.aoscx.plugins.modules.aoscx_l3_interface', init_globals=dict(_module_fqn='ansible_collections.arubanetworks.aoscx.plugins.modules.aoscx_l3_interface', _modlib_path=modlib_path),
  File "/usr/lib64/python3.8/runpy.py", line 207, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "/usr/lib64/python3.8/runpy.py", line 97, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/usr/lib64/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/tmp/ansible_aoscx_l3_interface_payload__jl9wziz/ansible_aoscx_l3_interface_payload.zip/ansible_collections/arubanetworks/aoscx/plugins/modules/aoscx_l3_interface.py", line 314, in <module>
  File "/tmp/ansible_aoscx_l3_interface_payload__jl9wziz/ansible_aoscx_l3_interface_payload.zip/ansible_collections/arubanetworks/aoscx/plugins/modules/aoscx_l3_interface.py", line 217, in main
  File "/home/wade/.local/lib/python3.8/site-packages/pyaoscx/pyaoscx_module.py", line 48, in is_materialized
    return fnct(self, *args, **kwargs)
  File "/home/wade/.local/lib/python3.8/site-packages/pyaoscx/interface.py", line 1114, in configure_l3
    vrf_obj.get()
  File "/home/wade/.local/lib/python3.8/site-packages/pyaoscx/pyaoscx_module.py", line 33, in ensure_connected
    return fnct(self, *args, **kwargs)
  File "/home/wade/.local/lib/python3.8/site-packages/pyaoscx/vrf.py", line 159, in get
    BgpRouter.get_all(self.session, self)
  File "/home/wade/.local/lib/python3.8/site-packages/pyaoscx/bgp_router.py", line 197, in get_all
    raise GenericOperationError(response.text, response.status_code)
pyaoscx.exceptions.generic_op_error.GenericOperationError: GENERIC OPERATION ERROR: unknown attribute for VRF: bgp_routers
 Code: 404

From the looks of it we need to either handle the unknown attribute for VRF: bgp_routers and set to None or whatever we need to denote BGP is not configured, or ideally look at the model/capabilities of the switch and skip the API call entirely for the models that don't support it.

FYI: the 6200 supports Routed Only Ports, but only after setting system internal-vlan-range I expect the l3_interface module doesn't check for that today, as it's quirk specific to the 6200.

Interface configuration fails when Interface is attached to an VRF other than default

Running the test on Ubuntu 20.04 and testing with virtual Aruba CX

Switch:
sw01# sh ver

ArubaOS-CX
(c) Copyright Hewlett Packard Enterprise Development LP

Version : Virtual.10.07.0010
Build Date :
Build ID : ArubaOS-CX:Virtual.10.07.0010:c075dcdbb1f5:202106100007
Build SHA : c075dcdbb1f5c2d88d501045bc6386f1dfa49bbc
Active Image :

Service OS Version :
BIOS Version :

My virtual environment:
(test) arne@linux:~/test$ pip list
Package Version


certifi 2021.5.30
charset-normalizer 2.0.6
idna 3.2
netaddr 0.8.0
pip 20.0.2
pkg-resources 0.0.0
pyaoscx 2.0.1
PyYAML 5.4.1
requests 2.26.0
setuptools 44.0.0
urllib3 1.26.6

My testscript:
(test) arne@linux:~/test$ cat sw01-int-down.py
from pyaoscx.session import Session
from pyaoscx.pyaoscx_factory import PyaoscxFactory
#from pyaoscx.vlan import Vlan
from pyaoscx.interface import Interface

There are two approaches to workflows, both using the session.

version = '10.04'
switch_ip = 'sw01.ao-test.net'
s = Session(switch_ip, version)
s.open('admin', 'Pass0rd123!')

Try block is used so that session closes even on error.

try:
#port_1_1_7 = Interface(s, '1/1/7')
#port_1_1_7.get()
#port_1_1_7.admin = 'down'
# Apply changes
#port_1_1_7.apply()
port_1_1_8 = Interface(s, '1/1/8')
port_1_1_8.get()
port_1_1_8.admin = 'down'
# Apply changes
port_1_1_8.apply()
#port_1_1_9 = Interface(s, '1/1/9')
#port_1_1_9.get()
#port_1_1_9.admin = 'down'
# Apply changes
#port_1_1_9.apply()

except Exception as error:
print('Ran into exception: {}. Closing session.'.format(error))

finally:
# At the end, the session MUST be closed
s.close()

Error message when changing 1/1/7 or 1/1/8
Ran into exception: RESPONSE ERROR in maximum recursion depth exceeded while calling a Python object: GET. Closing session.

Interface config:
interface 1/1/7
no shutdown
vrf attach transport
ip address 10.200.99.129/29
ip ospf 1 area 0.0.0.0
interface 1/1/8
no shutdown
vrf attach transport
ip address 10.200.99.145/29
ip ospf 1 area 0.0.0.0
interface 1/1/9
no shutdown
no routing
vlan trunk native 1
vlan trunk allowed all

PoeInterface does not work

I have a CX6300 switch, which serves PoE to a bunch of Aruba AP's. When I run the code snippet below, I get an error stating "UNSUPPORTED CAPABILITY, This device is not PoE capable.", for either 10.04 or 10.08 api.
I can get interfaces shutdown, enabled, vlan changes, and more, but not this.
Any ideas ? (I am using the latest github pull, with the recent mac() fixes)

Output:

Getting sesion for 10.112.1.75
Firmware = FL.10.08.1040
Platform = 6300

Getting interface list...
Interface 1/1/1:
   poe.get() error - exception: 'UNSUPPORTED CAPABILITY, This device is not PoE capable.'
 ... (other interfaces removed for brevity)

My test code:

import sys
  
from pyaoscx.session import Session
from pyaoscx.device import Device
from pyaoscx.interface import Interface
from pyaoscx.poe_interface import PoEInterface

# disable unknown SSL cert warnings:
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

switch_ip = '10.112.1.75'
username = '***'
password = '***'

API_VERSION = '10.08'   # "10.04" or "10.08"

s =  Session(ip_address=switch_ip, api=API_VERSION)
try:
    print(f"Getting sesion for {switch_ip}")
    s.open(username=username, password=password)
except Exception as error:
    print('s.open() exception: {}. Cannot open session.'.format(error))
    sys.exit()

device = Device(s)
device.get()
print(f"Firmware = {device.firmware_version}")
print(f"Platform = {device.platform_name}")

print("\nGetting interface list...")
interface_dict = Interface.get_facts(session=s)
for ifname in interface_dict:
    print(f"Interface {ifname}:")
    try:
        # go get PoE info:
        interface = Interface(session=s, name=ifname)
        try:
            poe = PoEInterface(session=s, parent_interface=interface)
            try:
                poe.get(selector='status')
                print("   POE Exists!")
            except Exception as error:
                print(f"   poe.get() error - exception: {format(error)}")
        except Exception as error:
            print(f"   PoEInterface() error - exception: {format(error)}")
    except Exception as error:
        print(f"   Interface() error - exception: {format(error)}")

s.close()

pyaoscx.mac.get_all not working when a VRRP is configured

Hello,

i found an issue with getting the MAC addresses if a VRRP is configured and i would consider this as a bug. This is also used in other modules for example when getting a VLAN via VLAN.get(session,vlan_id).

When there is a VRRP configured for a VLAN the variable mac['port'] equals None.

mac_obj.port = Interface.from_response(session, mac["port"])

As far is i know this is right as there is no logical or physical Port assigned to the virtual MAC address of the VRRP. Still this is leading to an error, because later on api.py tries to access the items of mac['port'].

Before that the variable is handed over to interface.py as response_data:

def from_response(cls, session, response_data):
"""
Create an Interface object given a response_data related to the
Interface object.
:param cls: Object's class.
:param session: pyaoscx.Session object used to represent a logical
connection to the device.
:param response_data: The response must be a dictionary of the form:
{ "<interface_name>": URL }, with URL:
"/rest/v10.04/system/interfaces/<interface_name>"
:return: Interface object.
"""
interfaces_id_arr = session.api.get_keys(
response_data, Interface.resource_uri_name
)
interface_name = interfaces_id_arr[0]
return session.api.get_module(session, "Interface", interface_name)

After this response_data is handed over to api.py. Which finally tries to access the items of response_data which then leads to the Error "Ran into exception: 'NoneType' object has no attribute 'items'. Closing session."

pyaoscx/pyaoscx/api.py

Lines 84 to 101 in 648cfc7

def get_keys(self, response_data, module_name=None):
"""
Given a response_data obtain the indices of said dictionary and return
them. Get keys should be used for only one element in the
dictionary.
:param response_data: a dictionary object in the form of:
{
"idx_1,idx_2": "/rest/v10.0X/system/<module>/<idx_1>,<idx_2>",
}
:return indices: List of indices.
"""
indices = None
for k, v in response_data.items():
indices = k
indices = indices.split(",")
return indices

This happens because it is not checked at any point either if the current MAC address is a VRRP or if the port of the MAC address equals None. Those two points mentioned could also be a possible solution in my opinion which could be implemented via changing line 214 in mac.py to one of the following snippets:

Check if the port of the MAC address is None

if mac['port'] is not None:
    mac_obj.port = Interface.from_response(session, mac["port"])
else:
    mac_obj.port = None

Check if the given MAC address is configured via a VRRP

if 'vrrp' not in indices:
    mac_obj.port = Interface.from_response(session, mac["port"])
else:
    mac_obj.port = None

Those are just suggestions and i don't know if they are implemented in the right way to work for every usecase of pyaoscx.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.