Skip to content

Commit

Permalink
Initial support for multicontext ASA's.
Browse files Browse the repository at this point in the history
Also we're introducing a delay optional argument (set 0.5ms). This argument can be used to delay subsequent API calls that could fail, for example any request directly following the interfaces/physical endpoint.
  • Loading branch information
wvandeun committed Jun 6, 2018
1 parent 86ecaf9 commit 4e31c22
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 4 deletions.
3 changes: 3 additions & 0 deletions napalm_asa/_MC_INCOMPATIBLE_ENDPOINTS.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MC_INCOMPATIBLE_ENDPOINTS=(
'/monitoring/serialnumber',
)
30 changes: 26 additions & 4 deletions napalm_asa/asa.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import json
import re
from collections import OrderedDict
import time

# import third party lib
from napalm_asa._MC_INCOMPATIBLE_ENDPOINTS import MC_INCOMPATIBLE_ENDPOINTS
from netaddr import IPNetwork

from napalm.base import NetworkDriver
Expand All @@ -37,7 +39,6 @@
)
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)


class RespFetcherHttps:
"""Response fetcher."""

Expand Down Expand Up @@ -143,6 +144,10 @@ def __init__(self,
self._context = None
self.port = optional_args.get('port', 443)
self.timeout = timeout
# delay factor is used for delaying api rest calls that show
# problematic behaviour when being followed by a subsequent call
# that follows to fast
self.delay = optional_args.get('delay', .5)
self.up = False
self.base_url = "https://{}:{}/api".format(self.hostname, self.port)
self.device = RespFetcherHttps(self.username, self.password, self.base_url, self.timeout)
Expand All @@ -162,6 +167,9 @@ def _delete_token(self):

def _send_request(self, endpoint, data=None):
"""Send request method."""

if self._proxy_to_other_context(endpoint):
endpoint = "{}?context={}".format(endpoint, self._context)
if data is None:
response = self.device.get_resp(endpoint)
else:
Expand Down Expand Up @@ -229,6 +237,11 @@ def _get_contexts(self):
self.contexts = [ c['name'] for c in resp['items']]
self.contexts.append('system')

def _proxy_to_other_context(self, endpoint):
return self.multicontext and \
self._context and \
endpoint not in MC_INCOMPATIBLE_ENDPOINTS

def open(self):
"""
Open a connection to the device.
Expand Down Expand Up @@ -258,12 +271,12 @@ def close(self):

def cli(self, commands):
"""Run CLI commands via the API."""

data = {
"commands": commands
}
}

endp = '/cli?context={}'.format(self._context) if self._context else '/cli'
response = self._send_request(endp, data)
response = self._send_request("/cli", data)

result_dict = {}

Expand Down Expand Up @@ -325,6 +338,15 @@ def get_interfaces(self):
for if_name in interfaces:
ifs.append(if_name)

# This is a nasty solution for an issue seen with ASA's
# using the /api/interfaces/physical endpoint. If you call
# that endpoint and then send another request to quickly
# (?), then the ASA closes the HTTPS connection without
# sending a reponse

if self.multicontext:
time.sleep(self.delay)

ifs_details = self._get_interfaces_details(ifs)

for if_name, details in ifs_details.items():
Expand Down

0 comments on commit 4e31c22

Please sign in to comment.