Skip to content

Commit

Permalink
Merge pull request napalm-automation-community#14 from napalm-automat…
Browse files Browse the repository at this point in the history
…ion-community/connection_rebuild

Connection rebuild

Closes napalm-automation-community#13
  • Loading branch information
hupebln authored Dec 15, 2021
2 parents b99c066 + c67a6ed commit 60e8320
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 40 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,27 @@ rest-interface
rest-interface session-idle-timeout 120 #optional
```

### optional_args
optional_args can be set during initialization like this:
```Python
from napalm import get_network_driver

d = get_network_driver("arubaoss")

with d('1.2.3.4', 'username', 'password', optional_args={'ssl_verify': False, "debugging": True}) as aruba:
print(aruba.get_config())
```

The following values can be set in optional_args:
- ssl_verify: bool/str = defaults to **True** - will be passed to the requests object (description can be found [here](https://docs.python-requests.org/en/latest/_modules/requests/sessions/#Session.request))
- keepalive: bool = defaults to **False** - sets the underlying TCP connection to either keep the connection or not and is a workaround for an issue with ArubaOS devices
(discussed [here](https://community.arubanetworks.com/community-home/digestviewer/viewthread?MID=28798#bme4aa3703-e476-4880-9cb4-9b208f86b2f4))
- keep_alive: bool = same as keepalive, just shadows it to be able to use the same keyword as in older Python requests versions
- debugging: bool = defaults to **False** - sets the level of the logging handler to logging.DEBUG
- disable_ssl_warnings: bool = defaults to **False** - disables ssl warnings from urllib3
- api: string = defaults to **v6** - defines the API version
- ssl: bool = defaults to **True**, sets http or https

### Saltstack
To use the driver with Saltstack, you would typically need a proxy minion.

Expand Down
64 changes: 40 additions & 24 deletions napalm_arubaoss/helper/base.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
"""Create the Session."""


from requests_futures.sessions import FuturesSession
from requests.models import Response
from concurrent.futures import as_completed
from json import JSONDecodeError
import base64
import logging

from napalm.base.exceptions import ConnectAuthError
from json import JSONDecodeError

from requests import Session
from requests.models import Response
from napalm.base.exceptions import ConnectAuthError, NapalmException


logger = logging.getLogger("arubaoss.helper.base")


class KeepAliveBoolError(NapalmException):
pass


class Connection:
"""Connection class."""

config = {"api_url": ""}

def __init__(self):
"""Initialize the class."""
self._apisession = None
self._apisession: Session = Session()

self.hostname = ""
self.username = ""
Expand Down Expand Up @@ -62,13 +66,29 @@ def login(self, hostname, username="", password="", timeout=10, optional_args=No

url = self.config["api_url"] + "login-sessions"

self._apisession = FuturesSession()
self._apisession = Session()
self._apisession.verify = optional_args.get("ssl_verify", True)
self._apisession.headers = {
"Content-Type": "application/json",
# "Connection": "close"
}
self._apisession.keep_alive = optional_args.get("keepalive", True)

keep_alive = optional_args.get(
"keepalive",
optional_args.get(
"keep_alive",
False
)
)

if not isinstance(keep_alive, bool):
raise KeepAliveBoolError(
"\"keepalive\"/\"keep_alive\" needs to be of type \"bool\""
)

if not keep_alive:
self._apisession.headers.update(
{"Connection": "close"}
)

params = {"userName": self.username, "password": self.password}

Expand Down Expand Up @@ -103,7 +123,7 @@ def get(self, *args, **kwargs) -> Response:
"""
ret = self._apisession.get(*args, **kwargs)

return ret.result()
return ret

def post(self, *args, **kwargs) -> Response:
"""
Expand All @@ -115,7 +135,7 @@ def post(self, *args, **kwargs) -> Response:
"""
ret = self._apisession.post(*args, **kwargs)

return ret.result()
return ret

def put(self, *args, **kwargs) -> Response:
"""
Expand All @@ -127,7 +147,7 @@ def put(self, *args, **kwargs) -> Response:
"""
ret = self._apisession.put(*args, **kwargs)

return ret.result()
return ret

def delete(self, *args, **kwargs) -> Response:
"""
Expand All @@ -139,7 +159,7 @@ def delete(self, *args, **kwargs) -> Response:
"""
ret = self._apisession.delete(*args, **kwargs)

return ret.result()
return ret

def cli(self, commands):
"""
Expand All @@ -156,28 +176,24 @@ def cli(self, commands):
self.cli_output["error"] = "Provide a list of commands"
return self.cli_output

async_calls = (
for command in commands:
self._apisession.post(
url=url,
json={"cmd": command},
timeout=self.timeout,
# bug #4 - random delay while re-using TCP connection - workaround:
# always close the TCP connection
headers={"Content-Type": "application/json", "Connection": "close"},
hooks={
"response": self._callback(output=self.cli_output, command=command)
},
"response": self._callback(
output=self.cli_output,
command=command
)
}
)
for command in commands
)

[call.result() for call in as_completed(async_calls)]

return self.cli_output

def _callback(self, *args, **kwargs):
"""
Return Callback for async calls.
Return Callback for request calls.
ArubaOSS.cli uses it.
Expand Down
39 changes: 24 additions & 15 deletions napalm_arubaoss/helper/compare_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""Backups and commit the configuration, and handles commit confirm."""

import logging

from time import sleep

from napalm.base.exceptions import CommandErrorException

logger = logging.getLogger("arubaoss.helper.compare_config")
Expand All @@ -26,18 +29,24 @@ def compare_config(self):
if not diff.ok:
raise CommandErrorException("diff generation failed, raise status")

diff_output = self.connection.get(check_url)

if not diff_output.status_code == 200:
raise CommandErrorException("diff generation failed, raise status")

if (
not diff_output.json()["diff_add_list"]
and not diff_output.json()["diff_remove_list"]
):
# return empty string to signal the candidate
# and running configs are the same

return ""
else:
return diff_output.json()
for loop_round in range(1, 6):
# wait a second to give the device time to process
logger.debug(f"loop round \"{loop_round}\"")
sleep(1)

diff_output = self.connection.get(check_url)

if not diff_output.status_code == 200:
raise CommandErrorException("diff generation failed, raise status")

if (
not diff_output.json()["diff_add_list"]
and not diff_output.json()["diff_remove_list"]
):
if loop_round == 5:
# return empty string to signal the candidate
# and running configs are the same
return ""
continue
else:
return diff_output.json()
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
napalm>=3.3.0
netaddr
requests
requests-futures
textfsm>=1.1.0
urllib3

0 comments on commit 60e8320

Please sign in to comment.