From 61c458600508ed70963de0191f47f2bb3c728346 Mon Sep 17 00:00:00 2001 From: Palmer Sample Date: Thu, 27 Apr 2023 13:39:44 -0400 Subject: [PATCH 1/4] Change implementations to check for exploded attribute before executing that method --- docs/changelog/2023/may.rst | 9 +++++++++ src/rest/connector/libs/apic/implementation.py | 4 +++- src/rest/connector/libs/bigip/implementation.py | 4 +++- src/rest/connector/libs/dcnm/implementation.py | 4 +++- src/rest/connector/libs/dnac/implementation.py | 4 +++- src/rest/connector/libs/elasticsearch/implementation.py | 4 +++- src/rest/connector/libs/iosxe/implementation.py | 4 +++- src/rest/connector/libs/nd/implementation.py | 4 +++- src/rest/connector/libs/nexusdashboard/implementation.py | 4 +++- src/rest/connector/libs/nso/implementation.py | 4 +++- src/rest/connector/libs/nxos/aci/implementation.py | 4 +++- src/rest/connector/libs/nxos/implementation.py | 4 +++- src/rest/connector/libs/viptela/implementation.py | 4 +++- src/rest/connector/libs/virl/implementation.py | 4 +++- src/rest/connector/libs/vmware/implementation.py | 4 +++- src/rest/connector/libs/webex/implementation.py | 4 +++- 16 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 docs/changelog/2023/may.rst diff --git a/docs/changelog/2023/may.rst b/docs/changelog/2023/may.rst new file mode 100644 index 0000000..5bfba85 --- /dev/null +++ b/docs/changelog/2023/may.rst @@ -0,0 +1,9 @@ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* All connectors (except xpresso) + * Change implementation of ip/host address to remove default .exploded + method. If an ipaddress object is passed, .exploded will still be used, + otherwise use the raw IP data. This enables dynamic testbed creation + using string values for IP addresses. diff --git a/src/rest/connector/libs/apic/implementation.py b/src/rest/connector/libs/apic/implementation.py index aaf29ab..b6793e8 100644 --- a/src/rest/connector/libs/apic/implementation.py +++ b/src/rest/connector/libs/apic/implementation.py @@ -102,7 +102,9 @@ def connect(self, timeout=30, retries=3, retry_wait=10): if 'host' in self.connection_info: ip = self.connection_info['host'] else: - ip = self.connection_info['ip'].exploded + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded if 'port' in self.connection_info: port = self.connection_info['port'] self.url = 'https://{ip}:{port}/'.format(ip=ip, port=port) diff --git a/src/rest/connector/libs/bigip/implementation.py b/src/rest/connector/libs/bigip/implementation.py index 5812a09..87c35e9 100755 --- a/src/rest/connector/libs/bigip/implementation.py +++ b/src/rest/connector/libs/bigip/implementation.py @@ -169,7 +169,9 @@ def connect( "Cannot add ssh tunnel. Connection %s may not have ip/host or port.\n%s" % (self.via, e)) else: - self.ip = self.connection_info['ip'].exploded + self.ip = self.connection_info['ip'] + if hasattr(self.ip, 'exploded'): + self.ip = self.ip.exploded self.port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/dcnm/implementation.py b/src/rest/connector/libs/dcnm/implementation.py index ab6aead..39212de 100644 --- a/src/rest/connector/libs/dcnm/implementation.py +++ b/src/rest/connector/libs/dcnm/implementation.py @@ -128,7 +128,9 @@ def connect(self, timeout=10, port=443, protocol='https'): try: host = self.connection_info['host'] except KeyError: - host = self.connection_info['ip'].exploded + host = self.connection_info['ip'] + if hasattr(host, 'exploded'): + host = host.exploded port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/dnac/implementation.py b/src/rest/connector/libs/dnac/implementation.py index b6924c3..3abf3f5 100644 --- a/src/rest/connector/libs/dnac/implementation.py +++ b/src/rest/connector/libs/dnac/implementation.py @@ -78,7 +78,9 @@ def connect(self, timeout=30): try: host = self.connection_info['host'] except KeyError: - host = self.connection_info['ip'].exploded + host = self.connection_info['ip'] + if hasattr(host, 'exploded'): + host = host.exploded port = self.connection_info.get('port', 443) self.verify = self.connection_info.get('verify', True) diff --git a/src/rest/connector/libs/elasticsearch/implementation.py b/src/rest/connector/libs/elasticsearch/implementation.py index 1a3e1e7..a4c804c 100644 --- a/src/rest/connector/libs/elasticsearch/implementation.py +++ b/src/rest/connector/libs/elasticsearch/implementation.py @@ -94,7 +94,9 @@ def connect(self, timeout=30, port="9200", protocol='https'): if 'host' in self.connection_info: ip = self.connection_info['host'] else: - ip = self.connection_info['ip'].exploded + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded if 'protocol' in self.connection_info: protocol = self.connection_info['protocol'] if 'port' in self.connection_info: diff --git a/src/rest/connector/libs/iosxe/implementation.py b/src/rest/connector/libs/iosxe/implementation.py index 43a47b7..6d4881e 100644 --- a/src/rest/connector/libs/iosxe/implementation.py +++ b/src/rest/connector/libs/iosxe/implementation.py @@ -114,7 +114,9 @@ def connect(self, "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 + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/nd/implementation.py b/src/rest/connector/libs/nd/implementation.py index b75bf26..75ca32b 100644 --- a/src/rest/connector/libs/nd/implementation.py +++ b/src/rest/connector/libs/nd/implementation.py @@ -93,7 +93,9 @@ def connect(self, timeout=30, retries=3, retry_wait=10): if 'host' in self.connection_info: ip = self.connection_info['host'] else: - ip = self.connection_info['ip'].exploded + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded if 'port' in self.connection_info: port = self.connection_info['port'] self.url = 'https://{ip}:{port}/'.format(ip=ip, port=port) diff --git a/src/rest/connector/libs/nexusdashboard/implementation.py b/src/rest/connector/libs/nexusdashboard/implementation.py index d4c9e3a..c6310cd 100644 --- a/src/rest/connector/libs/nexusdashboard/implementation.py +++ b/src/rest/connector/libs/nexusdashboard/implementation.py @@ -108,7 +108,9 @@ def connect(self, timeout=10, protocol='https'): try: host = self.connection_info['host'] except KeyError: - host = self.connection_info['ip'].exploded + host = self.connection_info['ip'] + if hasattr(host, 'exploded'): + host = host.exploded if 'protocol' in self.connection_info: protocol = self.connection_info['protocol'] diff --git a/src/rest/connector/libs/nso/implementation.py b/src/rest/connector/libs/nso/implementation.py index 2c8a874..219bc57 100644 --- a/src/rest/connector/libs/nso/implementation.py +++ b/src/rest/connector/libs/nso/implementation.py @@ -108,7 +108,9 @@ def connect(self, "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 + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/nxos/aci/implementation.py b/src/rest/connector/libs/nxos/aci/implementation.py index 45c3385..ed57224 100644 --- a/src/rest/connector/libs/nxos/aci/implementation.py +++ b/src/rest/connector/libs/nxos/aci/implementation.py @@ -105,7 +105,9 @@ def connect(self, timeout=30): if 'host' in self.connection_info: ip = self.connection_info['host'] else: - ip = self.connection_info['ip'].exploded + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded if 'port' in self.connection_info: port = self.connection_info['port'] self.url = 'https://{ip}:{port}/'.format(ip=ip, port=port) diff --git a/src/rest/connector/libs/nxos/implementation.py b/src/rest/connector/libs/nxos/implementation.py index e1ccbfd..689ac22 100644 --- a/src/rest/connector/libs/nxos/implementation.py +++ b/src/rest/connector/libs/nxos/implementation.py @@ -136,7 +136,9 @@ def connect(self, timeout=30, port=443, protocol='https', retries=3, retry_wait= "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 + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: protocol = self.connection_info['protocol'] diff --git a/src/rest/connector/libs/viptela/implementation.py b/src/rest/connector/libs/viptela/implementation.py index 6470d3d..35eb710 100644 --- a/src/rest/connector/libs/viptela/implementation.py +++ b/src/rest/connector/libs/viptela/implementation.py @@ -101,7 +101,9 @@ def connect(self, timeout=30, port="8443", protocol='https'): "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 + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/virl/implementation.py b/src/rest/connector/libs/virl/implementation.py index 7dbe85d..97eebd3 100644 --- a/src/rest/connector/libs/virl/implementation.py +++ b/src/rest/connector/libs/virl/implementation.py @@ -117,7 +117,9 @@ def connect(self, timeout=30, port="19399", protocol='http'): "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 + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded port = self.connection_info.get('port', '19399') if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/vmware/implementation.py b/src/rest/connector/libs/vmware/implementation.py index 597bf2e..6d7ad4d 100644 --- a/src/rest/connector/libs/vmware/implementation.py +++ b/src/rest/connector/libs/vmware/implementation.py @@ -128,7 +128,9 @@ def connect(self, timeout=10, port=443, protocol='https'): try: host = self.connection_info['host'] except KeyError: - host = self.connection_info['ip'].exploded + host = self.connection_info['ip'] + if hasattr(host, 'exploded'): + host = host.exploded port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/webex/implementation.py b/src/rest/connector/libs/webex/implementation.py index 8f58f51..b644c13 100644 --- a/src/rest/connector/libs/webex/implementation.py +++ b/src/rest/connector/libs/webex/implementation.py @@ -95,7 +95,9 @@ def connect(self, timeout=30): if 'host' in self.connection_info: ip = self.connection_info['host'] else: - ip = self.connection_info['ip'].exploded + ip = self.connection_info['ip'] + if hasattr(ip, 'exploded'): + ip = ip.exploded if 'port' in self.connection_info: port = self.connection_info['port'] self.url = 'https://{ip}:{port}/'.format(ip=ip, port=port) From 7140e746c2b43597f06dd4bb54c66b5b9619966d Mon Sep 17 00:00:00 2001 From: Palmer Sample Date: Thu, 27 Apr 2023 13:39:44 -0400 Subject: [PATCH 2/4] Change implementations to check for exploded attribute before executing that method --- docs/changelog/2023/may.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/changelog/2023/may.rst b/docs/changelog/2023/may.rst index 5bfba85..34f271e 100644 --- a/docs/changelog/2023/may.rst +++ b/docs/changelog/2023/may.rst @@ -4,6 +4,6 @@ * All connectors (except xpresso) * Change implementation of ip/host address to remove default .exploded - method. If an ipaddress object is passed, .exploded will still be used, - otherwise use the raw IP data. This enables dynamic testbed creation - using string values for IP addresses. + attribute. If an ipaddress object is passed, .exploded will still be + used, otherwise use the raw IP data. This enables dynamic testbed + creation using string values for IP addresses. From b421cfeca870bb907d34a294ae6cfdf6ef18c6fe Mon Sep 17 00:00:00 2001 From: Palmer Sample Date: Thu, 27 Apr 2023 16:57:46 -0400 Subject: [PATCH 3/4] Updated IOS XE implementation to properly generate an IPv6 URL --- src/rest/connector/libs/iosxe/implementation.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/rest/connector/libs/iosxe/implementation.py b/src/rest/connector/libs/iosxe/implementation.py index 6d4881e..753e833 100644 --- a/src/rest/connector/libs/iosxe/implementation.py +++ b/src/rest/connector/libs/iosxe/implementation.py @@ -10,6 +10,8 @@ from rest.connector.implementation import Implementation as RestImplementation from rest.connector.utils import get_username_password +from ipaddress import ip_address, IPv6Address + # create a logger for this module log = logging.getLogger(__name__) @@ -117,8 +119,13 @@ def connect(self, ip = self.connection_info['ip'] if hasattr(ip, 'exploded'): ip = ip.exploded + else: + ip = ip_address(ip) port = self.connection_info.get('port', port) + if isinstance(ip, IPv6Address): + ip = f"[{ip}]" + if 'protocol' in self.connection_info: protocol = self.connection_info['protocol'] From 8f91994f33a80396538cb89f5716e6cd394df803 Mon Sep 17 00:00:00 2001 From: Palmer Sample Date: Fri, 28 Apr 2023 10:36:55 -0400 Subject: [PATCH 4/4] Updated IP validation per reviewer comments to properly explode and format IPv6 URLs --- .../libs/apic/acisdk_implementation.py | 12 +++++++++++- src/rest/connector/libs/apic/implementation.py | 10 +++++++++- src/rest/connector/libs/bigip/implementation.py | 11 ++++++++++- src/rest/connector/libs/dcnm/implementation.py | 10 +++++++++- src/rest/connector/libs/dnac/implementation.py | 11 +++++++++-- .../libs/elasticsearch/implementation.py | 10 +++++++++- src/rest/connector/libs/iosxe/implementation.py | 17 +++++++++-------- src/rest/connector/libs/nd/implementation.py | 10 +++++++++- .../libs/nexusdashboard/implementation.py | 10 +++++++++- src/rest/connector/libs/nso/implementation.py | 10 +++++++++- .../connector/libs/nxos/aci/implementation.py | 11 +++++++++-- src/rest/connector/libs/nxos/implementation.py | 11 ++++++++++- .../connector/libs/viptela/implementation.py | 11 ++++++++++- src/rest/connector/libs/virl/implementation.py | 11 +++++++++-- .../connector/libs/vmware/implementation.py | 11 ++++++++++- src/rest/connector/libs/webex/implementation.py | 10 +++++++++- 16 files changed, 150 insertions(+), 26 deletions(-) diff --git a/src/rest/connector/libs/apic/acisdk_implementation.py b/src/rest/connector/libs/apic/acisdk_implementation.py index 8ef83e5..67d41d5 100644 --- a/src/rest/connector/libs/apic/acisdk_implementation.py +++ b/src/rest/connector/libs/apic/acisdk_implementation.py @@ -1,6 +1,7 @@ import requests import urllib3 +from ipaddress import ip_address, IPv4Address, IPv6Address from functools import wraps from importlib import import_module from logging import getLogger @@ -57,7 +58,16 @@ def __init__(self, *args, **kwargs): if 'host' in self.connection_info: ip = self.connection_info['host'] else: - ip = self.connection_info['ip'].exploded + ip = self.connection_info['ip'] + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: + ip = ip.exploded + if 'port' in self.connection_info: port = self.connection_info['port'] self.url = f'https://{ip}:{port}/' diff --git a/src/rest/connector/libs/apic/implementation.py b/src/rest/connector/libs/apic/implementation.py index b6793e8..0d2c881 100644 --- a/src/rest/connector/libs/apic/implementation.py +++ b/src/rest/connector/libs/apic/implementation.py @@ -3,6 +3,7 @@ import logging import requests +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.exceptions import RequestException @@ -103,8 +104,15 @@ def connect(self, timeout=30, retries=3, retry_wait=10): ip = self.connection_info['host'] else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: ip = ip.exploded + if 'port' in self.connection_info: port = self.connection_info['port'] self.url = 'https://{ip}:{port}/'.format(ip=ip, port=port) diff --git a/src/rest/connector/libs/bigip/implementation.py b/src/rest/connector/libs/bigip/implementation.py index 87c35e9..0b14daf 100755 --- a/src/rest/connector/libs/bigip/implementation.py +++ b/src/rest/connector/libs/bigip/implementation.py @@ -2,6 +2,8 @@ import logging import time +from ipaddress import ip_address, IPv4Address, IPv6Address + # Genie, pyATS, ROBOT imports # from pyats.connections import BaseConnection from rest.connector.utils import get_username_password @@ -170,8 +172,15 @@ def connect( % (self.via, e)) else: self.ip = self.connection_info['ip'] - if hasattr(self.ip, 'exploded'): + if not isinstance(self.ip, (IPv4Address, IPv6Address)): + self.ip = ip_address(self.ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(self.ip, IPv6Address): + self.ip = f"[{self.ip.exploded}]" + else: self.ip = self.ip.exploded + self.port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/dcnm/implementation.py b/src/rest/connector/libs/dcnm/implementation.py index 39212de..240689e 100644 --- a/src/rest/connector/libs/dcnm/implementation.py +++ b/src/rest/connector/libs/dcnm/implementation.py @@ -3,6 +3,7 @@ import json import logging import requests +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.auth import HTTPBasicAuth from requests.exceptions import RequestException @@ -129,8 +130,15 @@ def connect(self, timeout=10, port=443, protocol='https'): host = self.connection_info['host'] except KeyError: host = self.connection_info['ip'] - if hasattr(host, 'exploded'): + if not isinstance(host, (IPv4Address, IPv6Address)): + host = ip_address(host) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(host, IPv6Address): + host = f"[{host.exploded}]" + else: host = host.exploded + port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/dnac/implementation.py b/src/rest/connector/libs/dnac/implementation.py index 3abf3f5..deea487 100644 --- a/src/rest/connector/libs/dnac/implementation.py +++ b/src/rest/connector/libs/dnac/implementation.py @@ -1,6 +1,7 @@ import json import logging import requests +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.auth import HTTPBasicAuth from requests.exceptions import RequestException @@ -79,9 +80,15 @@ def connect(self, timeout=30): host = self.connection_info['host'] except KeyError: host = self.connection_info['ip'] - if hasattr(host, 'exploded'): + if not isinstance(host, (IPv4Address, IPv6Address)): + host = ip_address(host) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(host, IPv6Address): + host = f"[{host.exploded}]" + else: host = host.exploded - + port = self.connection_info.get('port', 443) self.verify = self.connection_info.get('verify', True) diff --git a/src/rest/connector/libs/elasticsearch/implementation.py b/src/rest/connector/libs/elasticsearch/implementation.py index a4c804c..0a99d62 100644 --- a/src/rest/connector/libs/elasticsearch/implementation.py +++ b/src/rest/connector/libs/elasticsearch/implementation.py @@ -2,6 +2,7 @@ import logging import requests +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.exceptions import RequestException from pyats.connections import BaseConnection @@ -95,8 +96,15 @@ def connect(self, timeout=30, port="9200", protocol='https'): ip = self.connection_info['host'] else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: ip = ip.exploded + if 'protocol' in self.connection_info: protocol = self.connection_info['protocol'] if 'port' in self.connection_info: diff --git a/src/rest/connector/libs/iosxe/implementation.py b/src/rest/connector/libs/iosxe/implementation.py index 753e833..61436aa 100644 --- a/src/rest/connector/libs/iosxe/implementation.py +++ b/src/rest/connector/libs/iosxe/implementation.py @@ -3,6 +3,7 @@ import re import urllib.request import requests +from ipaddress import ip_address, IPv4Address, IPv6Address from dict2xml import dict2xml from requests.exceptions import RequestException @@ -10,8 +11,6 @@ from rest.connector.implementation import Implementation as RestImplementation from rest.connector.utils import get_username_password -from ipaddress import ip_address, IPv6Address - # create a logger for this module log = logging.getLogger(__name__) @@ -117,14 +116,16 @@ def connect(self, % (self.via, e)) else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): - ip = ip.exploded - else: + if not isinstance(ip, (IPv4Address, IPv6Address)): ip = ip_address(ip) - port = self.connection_info.get('port', port) - if isinstance(ip, IPv6Address): - ip = f"[{ip}]" + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: + ip = ip.exploded + + port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: protocol = self.connection_info['protocol'] diff --git a/src/rest/connector/libs/nd/implementation.py b/src/rest/connector/libs/nd/implementation.py index 75ca32b..80d6e90 100644 --- a/src/rest/connector/libs/nd/implementation.py +++ b/src/rest/connector/libs/nd/implementation.py @@ -4,6 +4,7 @@ import time import urllib.parse +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.exceptions import RequestException from pyats.connections import BaseConnection @@ -94,8 +95,15 @@ def connect(self, timeout=30, retries=3, retry_wait=10): ip = self.connection_info['host'] else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: ip = ip.exploded + if 'port' in self.connection_info: port = self.connection_info['port'] self.url = 'https://{ip}:{port}/'.format(ip=ip, port=port) diff --git a/src/rest/connector/libs/nexusdashboard/implementation.py b/src/rest/connector/libs/nexusdashboard/implementation.py index c6310cd..062189f 100644 --- a/src/rest/connector/libs/nexusdashboard/implementation.py +++ b/src/rest/connector/libs/nexusdashboard/implementation.py @@ -3,6 +3,8 @@ import json import logging import requests + +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.auth import HTTPBasicAuth from requests.exceptions import RequestException @@ -109,7 +111,13 @@ def connect(self, timeout=10, protocol='https'): host = self.connection_info['host'] except KeyError: host = self.connection_info['ip'] - if hasattr(host, 'exploded'): + if not isinstance(host, (IPv4Address, IPv6Address)): + host = ip_address(host) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(host, IPv6Address): + host = f"[{host.exploded}]" + else: host = host.exploded if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/nso/implementation.py b/src/rest/connector/libs/nso/implementation.py index 219bc57..c5dc794 100644 --- a/src/rest/connector/libs/nso/implementation.py +++ b/src/rest/connector/libs/nso/implementation.py @@ -2,6 +2,7 @@ import json import logging import requests +from ipaddress import ip_address, IPv4Address, IPv6Address from dict2xml import dict2xml from requests.exceptions import RequestException @@ -109,8 +110,15 @@ def connect(self, % (self.via, e)) else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: ip = ip.exploded + port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/nxos/aci/implementation.py b/src/rest/connector/libs/nxos/aci/implementation.py index ed57224..8c6d7b6 100644 --- a/src/rest/connector/libs/nxos/aci/implementation.py +++ b/src/rest/connector/libs/nxos/aci/implementation.py @@ -2,9 +2,9 @@ import logging import requests +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.exceptions import RequestException - from pyats.connections import BaseConnection from rest.connector.implementation import Implementation as Imp from rest.connector.utils import get_username_password @@ -106,8 +106,15 @@ def connect(self, timeout=30): ip = self.connection_info['host'] else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: ip = ip.exploded + if 'port' in self.connection_info: port = self.connection_info['port'] self.url = 'https://{ip}:{port}/'.format(ip=ip, port=port) diff --git a/src/rest/connector/libs/nxos/implementation.py b/src/rest/connector/libs/nxos/implementation.py index 689ac22..7475fb0 100644 --- a/src/rest/connector/libs/nxos/implementation.py +++ b/src/rest/connector/libs/nxos/implementation.py @@ -2,6 +2,8 @@ import time import logging import requests + +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.auth import HTTPBasicAuth from requests.exceptions import RequestException @@ -137,8 +139,15 @@ def connect(self, timeout=30, port=443, protocol='https', retries=3, retry_wait= % (self.via, e)) else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: ip = ip.exploded + port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: protocol = self.connection_info['protocol'] diff --git a/src/rest/connector/libs/viptela/implementation.py b/src/rest/connector/libs/viptela/implementation.py index 35eb710..808f6aa 100644 --- a/src/rest/connector/libs/viptela/implementation.py +++ b/src/rest/connector/libs/viptela/implementation.py @@ -2,6 +2,8 @@ import logging import requests +from ipaddress import ip_address, IPv4Address, IPv6Address + from pyats.connections import BaseConnection from rest.connector.implementation import Implementation from rest.connector.utils import get_username_password @@ -102,8 +104,15 @@ def connect(self, timeout=30, port="8443", protocol='https'): % (self.via, e)) else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: ip = ip.exploded + port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/virl/implementation.py b/src/rest/connector/libs/virl/implementation.py index 97eebd3..d624c98 100644 --- a/src/rest/connector/libs/virl/implementation.py +++ b/src/rest/connector/libs/virl/implementation.py @@ -1,9 +1,9 @@ import logging import requests +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.exceptions import RequestException - from pyats.connections import BaseConnection from rest.connector.implementation import Implementation from rest.connector.utils import get_username_password @@ -118,8 +118,15 @@ def connect(self, timeout=30, port="19399", protocol='http'): % (self.via, e)) else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: ip = ip.exploded + port = self.connection_info.get('port', '19399') if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/vmware/implementation.py b/src/rest/connector/libs/vmware/implementation.py index 6d7ad4d..4885453 100644 --- a/src/rest/connector/libs/vmware/implementation.py +++ b/src/rest/connector/libs/vmware/implementation.py @@ -3,6 +3,8 @@ import json import logging import requests + +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.auth import HTTPBasicAuth from requests.exceptions import RequestException @@ -129,8 +131,15 @@ def connect(self, timeout=10, port=443, protocol='https'): host = self.connection_info['host'] except KeyError: host = self.connection_info['ip'] - if hasattr(host, 'exploded'): + if not isinstance(host, (IPv4Address, IPv6Address)): + host = ip_address(host) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(host, IPv6Address): + host = f"[{host.exploded}]" + else: host = host.exploded + port = self.connection_info.get('port', port) if 'protocol' in self.connection_info: diff --git a/src/rest/connector/libs/webex/implementation.py b/src/rest/connector/libs/webex/implementation.py index b644c13..886ea11 100644 --- a/src/rest/connector/libs/webex/implementation.py +++ b/src/rest/connector/libs/webex/implementation.py @@ -2,6 +2,7 @@ import logging import requests +from ipaddress import ip_address, IPv4Address, IPv6Address from requests.exceptions import RequestException from pyats.connections import BaseConnection @@ -96,8 +97,15 @@ def connect(self, timeout=30): ip = self.connection_info['host'] else: ip = self.connection_info['ip'] - if hasattr(ip, 'exploded'): + if not isinstance(ip, (IPv4Address, IPv6Address)): + ip = ip_address(ip) + + # Properly format IPv6 URL if a v6 address is provided + if isinstance(ip, IPv6Address): + ip = f"[{ip.exploded}]" + else: ip = ip.exploded + if 'port' in self.connection_info: port = self.connection_info['port'] self.url = 'https://{ip}:{port}/'.format(ip=ip, port=port)