-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #127 from CiscoTestAutomation/ise_connector
Base ISE connector implementation, refactor abstraction
- Loading branch information
Showing
24 changed files
with
231 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
docs/changelog/undistributed/changelog_ise_20240711163922.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
-------------------------------------------------------------------------------- | ||
New | ||
-------------------------------------------------------------------------------- | ||
* connector | ||
* Add ISE connector base implementation |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='apic') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='bigip') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='dnac') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='elasticsearch') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='iosxe') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from genie import abstract | ||
abstract.declare_token(os='ise') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
|
||
import logging | ||
import urllib.request | ||
from requests.exceptions import RequestException | ||
|
||
from pyats.connections import BaseConnection | ||
from rest.connector.utils import get_username_password | ||
from rest.connector.implementation import Implementation as RestImplementation | ||
|
||
from ciscoisesdk import IdentityServicesEngineAPI | ||
|
||
# create a logger for this module | ||
log = logging.getLogger(__name__) | ||
|
||
|
||
class Implementation(RestImplementation): | ||
'''Rest Implementation for ISE | ||
Implementation of Rest connection to ISE servers | ||
YAML Example | ||
------------ | ||
devices: | ||
ise: | ||
os: ise | ||
connections: | ||
rest: | ||
class: rest.connector.Rest | ||
ip: 127.0.0.1 | ||
port: "443" | ||
protocol: https | ||
credentials: | ||
rest: | ||
username: admin | ||
password: admin | ||
Code Example | ||
------------ | ||
>>> from pyats.topology import loader | ||
>>> testbed = loader.load('topology.yaml') | ||
>>> device = testbed.devices['ise'] | ||
>>> device.connect(alias='rest', via='rest') | ||
>>> device.rest.connected | ||
True | ||
''' | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
if 'proxies' not in kwargs: | ||
self.proxies = urllib.request.getproxies() | ||
|
||
@BaseConnection.locked | ||
def connect(self, | ||
timeout=30, | ||
verbose=False, | ||
port="443", | ||
protocol='https', | ||
debug=False, | ||
**kwargs): | ||
'''connect to the device via REST | ||
Arguments | ||
--------- | ||
timeout (int): Timeout value | ||
Raises | ||
------ | ||
Exception | ||
--------- | ||
If the connection did not go well | ||
''' | ||
if self.connected: | ||
log.info(f'{self} already connected') | ||
return | ||
|
||
# support sshtunnel | ||
if 'sshtunnel' in self.connection_info: | ||
try: | ||
from unicon.sshutils import sshtunnel | ||
except ImportError: | ||
raise ImportError( | ||
'`unicon` is not installed for `sshtunnel`. Please install by `pip install unicon`.' | ||
) | ||
try: | ||
tunnel_port = sshtunnel.auto_tunnel_add(self.device, self.via) | ||
if tunnel_port: | ||
ip = self.device.connections[self.via].sshtunnel.tunnel_ip | ||
port = tunnel_port | ||
except AttributeError as e: | ||
raise AttributeError( | ||
"Cannot add ssh tunnel. Connection %s may not have ip/host or port.\n%s" | ||
% (self.via, e)) | ||
else: | ||
ip = self.connection_info.ip.exploded | ||
port = self.connection_info.get('port', port) | ||
|
||
if 'protocol' in self.connection_info: | ||
protocol = self.connection_info['protocol'] | ||
|
||
self.base_url = '{protocol}://{ip}:{port}'.format(protocol=protocol, | ||
ip=ip, | ||
port=port) | ||
|
||
username, password = get_username_password(self) | ||
|
||
self.api = IdentityServicesEngineAPI( | ||
username=username, password=password, | ||
base_url=self.base_url, uses_api_gateway=True, | ||
verify=False, debug=debug) | ||
|
||
version_request = self.api.version_and_patch.get_ise_version_and_patch() | ||
if version_request.status_code == 200: | ||
version_info = version_request.response | ||
# {'OperationResult': {'resultValue': [ | ||
# {'value': '3.3.0.430', 'name': 'version'}, {'value': '0', 'name': 'patch information'}]}} | ||
version_info_list = version_info.get('OperationResult', {}).get('resultValue', []) | ||
version_message_list = [] | ||
for version_nv in version_info_list: | ||
name = version_nv.get('name') | ||
value = version_nv.get('value') | ||
if name and value: | ||
version_message_list.append(f'{name}: {value}') | ||
if version_message_list: | ||
version_message = ' '.join(version_message_list) | ||
log.info(version_message) | ||
self._is_connected = True | ||
log.info("Connected successfully to '{d}'".format(d=self.device.name)) | ||
else: | ||
raise ConnectionError('Unable to connect to ISE server') | ||
|
||
return self.api | ||
|
||
@BaseConnection.locked | ||
def disconnect(self): | ||
""" | ||
""" | ||
self._is_connected = False | ||
return |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='nd') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='nexusdashboard') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='nso') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='nxos') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(platform='aci') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='viptela') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='virl') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='vmware') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='webex') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Enable abstraction using this directory name as the abstraction token | ||
try: | ||
from genie import abstract | ||
abstract.declare_token(__name__) | ||
abstract.declare_token(os='xpresso') | ||
except Exception as e: | ||
import warnings | ||
warnings.warn('Could not declare abstraction token: ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#!/bin/env python | ||
""" Unit tests for the rest.connector cisco-shared package. """ | ||
import os | ||
import unittest | ||
from requests.models import Response | ||
from unittest.mock import patch, MagicMock | ||
|
||
from pyats.topology import loader | ||
|
||
from rest.connector import Rest | ||
HERE = os.path.dirname(__file__) | ||
|
||
|
||
class test_rest_connector(unittest.TestCase): | ||
def setUp(self): | ||
self.testbed = loader.load(os.path.join(HERE, 'testbed.yaml')) | ||
self.device = self.testbed.devices['ise'] | ||
|
||
def test_init(self): | ||
connection = Rest(device=self.device, alias='rest', via='rest') | ||
self.assertEqual(connection.device, self.device) | ||
|
||
with self.assertRaises(NotImplementedError): | ||
self.assertRaises(connection.execute()) | ||
with self.assertRaises(NotImplementedError): | ||
self.assertRaises(connection.configure()) | ||
|
||
def test_connection(self): | ||
connection = Rest(device=self.device, alias='rest', via='rest') | ||
self.assertEqual(connection.connected, False) | ||
|
||
with patch('requests.session') as req: | ||
resp = Response() | ||
resp.headers['Content-type'] = 'application/json' | ||
resp.status_code = 200 | ||
resp._content = b'{"OperationResult": {"resultValue": [{"value": "3.3.0.430",' + \ | ||
b' "name": "version"}, {"value": "0", "name": "patch information"}]}}' | ||
req().request.return_value = resp | ||
connection.connect() | ||
self.assertEqual(connection.connected, True) | ||
connection.connect() | ||
self.assertEqual(connection.connected, True) | ||
|
||
# Now disconnect | ||
with patch('requests.session') as req: | ||
connection.disconnect() | ||
self.assertEqual(connection.connected, False) | ||
|
Oops, something went wrong.