Exemplo n.º 1
0
def main():
    password = getpass()
    nxos1 = {
        'host': 'nxos1.twb-tech.com',
        'username': '******',
        'password': password,
        'transport': 'https',
        'port': 8443,
    }
    nxos2 = {   # noqa
        'host': 'nxos2.twb-tech.com',
        'username': '******',
        'password': password,
        'transport': 'https',
        'port': 8443,
    }

    print()
    for device in (nxos1, ):
        nxapi_conn = Device(**device)
        print('-' * 40)
        route_table = nxapi_conn.show('show ip route vrf management')
        route_table = process_route_table(route_table)
        for route_entry in route_table:
            if route_entry['ipprefix'] == '0.0.0.0/0':
                next_hop = extract_next_hop(route_entry)
                print("Default Gateway: {}".format(next_hop))
                break
        print('-' * 40)
    print()
Exemplo n.º 2
0
def main():
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    password = getpass()
    for host in ['nxos1.twb-tech.com', 'nxos2.twb-tech.com']:
        device = Device(host=host,
                        username='******',
                        password=password,
                        transport='https',
                        port=8443)
        result = device.show('show ip route vrf management')
        # ipnexthop = result['TABLE_vrf']['ROW_vrf']['TABLE_addrf']['ROW_addrf']['TABLE_prefix']['ROW_prefix'][0]['TABLE_path']['ROW_path']['ipnexthop']
        route_table = result['TABLE_vrf']['ROW_vrf']['TABLE_addrf'][
            'ROW_addrf']['TABLE_prefix']['ROW_prefix']
        print()
        print(host)
        print('-' * 40)
        print(route_table)
        print('-' * 40)

        for route_entry in route_table:
            if route_entry['ipprefix'] == '0.0.0.0/0':
                next_hop = route_entry['TABLE_path']['ROW_path']['ipnexthop']
                print("Default Gateway: {}".format(next_hop))
                break
        print('-' * 40)
        print()
Exemplo n.º 3
0
def main():
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    for host in ['nxos1.twb-tech.com', 'nxos2.twb-tech.com']:
        device = Device(host=host,
                        username='******',
                        password=getpass(),
                        transport='https',
                        port=8443)
        print(device.show('show hostname'))
Exemplo n.º 4
0
def main():
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    hosts = ['nxos1.twb-tech.com', 'nxos2.twb-tech.com']
    password = getpass()
    command_list = ['interface Loopback66', 'ip address 172.31.255.66/32']

    for host in hosts:
	    device = Device(host=host,
	    	username='******',
	    	password=password,
	    	transport='https',
	    	port=8443)
	    device.config_list(command_list)
	    result = device.show('show run interface loopback66', raw_text=True)
	    print(result)
Exemplo n.º 5
0
def main():
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    for host in ['nxos1.twb-tech.com', 'nxos2.twb-tech.com']:
        device = Device(host=host,
                        username='******',
                        password=getpass(),
                        transport='https',
                        port=8443)
        result = device.show('show ip route vrf management')
        ipnexthop = result['TABLE_vrf']['ROW_vrf']['TABLE_addrf']['ROW_addrf'][
            'TABLE_prefix']['ROW_prefix'][0]['TABLE_path']['ROW_path'][
                'ipnexthop']
        print()
        print("The next hop IP address for the default route is {}.".format(
            ipnexthop))
        print()
Exemplo n.º 6
0
 def open(self):
     try:
         self.device = NXOSDevice(self.hostname,
                                  self.username,
                                  self.password,
                                  timeout=self.timeout,
                                  port=self.port,
                                  transport=self.transport)
         self.device.show('show hostname')
         self.up = True
     except (CLIError, ValueError):
         # unable to open connection
         raise ConnectionException('Cannot connect to {}'.format(self.hostname))
Exemplo n.º 7
0
 def open(self):
     try:
         self.device = NXOSDevice(self.hostname,
                                  self.username,
                                  self.password,
                                  timeout=self.timeout,
                                  port=self.port,
                                  transport=self.transport)
         self.device.show('show hostname')
         self.up = True
     except (CLIError, ValueError):
         # unable to open connection
         raise ConnectionException('Cannot connect to {}'.format(
             self.hostname))
Exemplo n.º 8
0
def main():
    password = getpass()
    nxos1 = {
        'host': 'nxos1.twb-tech.com',
        'username': '******',
        'password': password,
        'transport': 'https',
        'port': 8443,
    }
    nxos2 = {   # noqa
        'host': 'nxos2.twb-tech.com',
        'username': '******',
        'password': password,
        'transport': 'https',
        'port': 8443,
    }

    config_commands = ['interface Loopback99', 'ip address 172.31.254.99/32']
    for device in (nxos1, ):
        nxapi_conn = Device(**device)
        nxapi_conn.config_list(config_commands)
        output = nxapi_conn.show('show run interface loopback99',
                                 raw_text=True)
        print(output)
Exemplo n.º 9
0
 def __init__(self,
              host,
              username,
              password,
              transport="http",
              timeout=30,
              port=None,
              **kwargs):
     super().__init__(host,
                      username,
                      password,
                      device_type="cisco_nxos_nxapi")
     self.transport = transport
     self.timeout = timeout
     self.native = NXOSNative(host,
                              username,
                              password,
                              transport=transport,
                              timeout=timeout,
                              port=port)
Exemplo n.º 10
0
 def __init__(self,
              host,
              username,
              password,
              transport='http',
              timeout=30,
              port=None,
              **kwargs):
     super(NXOSDevice, self).__init__(host,
                                      username,
                                      password,
                                      vendor='cisco',
                                      device_type='cisco_nxos_nxapi')
     self.transport = transport
     self.timeout = timeout
     self.native = NXOSNative(host,
                              username,
                              password,
                              transport=transport,
                              timeout=timeout,
                              port=port)
Exemplo n.º 11
0
def main():
    """Configure BGP using NX-API."""
    # Nexus switches
    switch_ip = raw_input("Enter switch IP: ")
    username = '******'
    password = getpass()
    eth_intf = "Ethernet 2/1"
    intf_ip = '10.1.4.1/30'
    peer_ip = '10.1.4.2'
    as_number = '10'

    config_eth = ['interface ' + eth_intf, 'ip address ' + intf_ip]

    config_bgp = [
        'license grace-period',
        'feature bgp',
        'router bgp ' + as_number,
        'neighbor {} remote-as {}'.format(peer_ip, as_number),
        'address-family ipv4 unicast',
    ]

    nxs = Device(host=switch_ip,
                 username=username,
                 password=password,
                 transport='https',
                 port=8443)

    print "\nCurrent Ethernet config: "
    cmd = 'show run int {}'.format(eth_intf)
    print nxs.show(cmd, raw_text=True)

    print "\nConfig Eth Interface:"
    results = nxs.config_list(config_eth)
    if check_nxapi_errors(results):
        print "...interface configured successfully."

    print "\nCurrent Ethernet config: "
    cmd = 'show run int {}'.format(eth_intf)
    print nxs.show(cmd, raw_text=True)

    print
    print "-" * 50
    print "BGP Config"
    print "-" * 50

    cmd = 'show run bgp'
    print nxs.show(cmd, raw_text=True)

    print "\nConfigure BGP"
    results = nxs.config_list(config_bgp)
    if check_nxapi_errors(results):
        print "...BGP configured successfully."

    cmd = 'show run bgp'
    print nxs.show(cmd, raw_text=True)

    print "\nVerify BGP (requires both peers)."
    print "Sleeping..."
    time.sleep(15)
    cmd = 'show bgp session'
    bgp_out = nxs.show(cmd)
    pprint(bgp_out)

    print "\nSaving config..."
    print nxs.save()
Exemplo n.º 12
0
 def setUp(self, mock_rpc):
     self.device = Device("host", "user", "pass")
     self.rpc = mock_rpc
     self.send_request = mock_rpc.return_value.send_request
     self.send_request.side_effect = send_request
Exemplo n.º 13
0
class NXOSDevice(BaseDevice):
    def __init__(self, host, username, password, transport='http', timeout=30, port=None, **kwargs):
        super(NXOSDevice, self).__init__(host, username, password, vendor='cisco', device_type=NXOS_API_DEVICE_TYPE)
        self.transport = transport
        self.timeout = timeout

        self.native = NXOSNative(host, username, password, transport=transport, timeout=timeout, port=port)

    def open(self):
        pass

    def close(self):
        pass

    def set_timeout(self, timeout):
        self.native.timeout = timeout

    def config(self, command):
        try:
            self.native.config(command)
        except CLIError as e:
            raise CommandError(command, str(e))

    def config_list(self, commands):
        try:
            self.native.config_list(commands)
        except CLIError as e:
            raise CommandListError(commands, e.command, str(e))

    def show(self, command, raw_text=False):
        try:
            return strip_unicode(self.native.show(command, raw_text=raw_text))
        except CLIError as e:
            raise CommandError(command, str(e))

    def show_list(self, commands, raw_text=False):
        try:
            return strip_unicode(self.native.show_list(commands, raw_text=raw_text))
        except CLIError as e:
            raise CommandListError(commands, e.command, str(e))

    def save(self, filename='startup-config'):
        return self.native.save(filename=filename)

    def file_copy_remote_exists(self, src, dest):
        return self.native.file_copy_remote_exists(src, dest)

    def file_copy(self, src, dest):
        try:
            return self.native.file_copy(src, dest)
        except NXOSFileTransferError:
            raise FileTransferError

    def reboot(self, timer=0, confirm=False):
        self.native.reboot(confirm=confirm)

    def get_boot_options(self):
        return self.native.get_boot_options()

    def set_boot_options(self, image_name, kickstart=None, **vendor_specifics):
        return self.native.set_boot_options(image_name, kickstart=kickstart)

    def checkpoint(self, filename):
        return self.native.checkpoint(filename)

    def rollback(self, filename):
        try:
            self.native.rollback(filename)
        except CLIError:
            raise RollbackError('Rollback unsuccessful, %s may not exist.' % filename)

    def backup_running_config(self, filename):
        self.native.backup_running_config(filename)

    @property
    def facts(self):
        if hasattr(self, '_facts'):
            return self._facts

        facts = strip_unicode(self.native.facts)
        facts['vendor'] = self.vendor

        self._facts = facts
        return self._facts

    @property
    def running_config(self):
        return self.native.running_config

    @property
    def startup_config(self):
        return self.show('show startup-config', raw_text=True)
Exemplo n.º 14
0
class NXOSDriver(NetworkDriver):
    def __init__(self,
                 hostname,
                 username,
                 password,
                 timeout=60,
                 optional_args=None):
        if optional_args is None:
            optional_args = {}
        self.hostname = hostname
        self.username = username
        self.password = password
        self.timeout = timeout
        self.up = False
        self.replace = True
        self.loaded = False
        self.fc = None
        self.changed = False
        self.replace_file = None
        self.merge_candidate = ''

        if optional_args is None:
            optional_args = {}

        self.transport = optional_args.get('nxos_protocol', 'http')

        if self.transport == 'https':
            self.port = optional_args.get('port', 443)
        elif self.transport == 'http':
            self.port = optional_args.get('port', 80)

    def open(self):
        try:
            self.device = NXOSDevice(self.hostname,
                                     self.username,
                                     self.password,
                                     timeout=self.timeout,
                                     port=self.port,
                                     transport=self.transport)
            self.device.show('show hostname')
            self.up = True
        except (CLIError, ValueError):
            # unable to open connection
            raise ConnectionException('Cannot connect to {}'.format(
                self.hostname))

    def close(self):
        if self.changed:
            self._delete_file(self.backup_file)
        self.device = None

    @staticmethod
    def _compute_timestamp(stupid_cisco_output):
        """
        Some fields such `uptime` are returned as: 23week(s) 3day(s)
        This method will determine the epoch of the event.
        e.g.: 23week(s) 3day(s) -> 1462248287
        """
        if not stupid_cisco_output or stupid_cisco_output == 'never':
            return -1.0

        if '(s)' in stupid_cisco_output:
            pass
        elif ':' in stupid_cisco_output:
            stupid_cisco_output = stupid_cisco_output.replace(
                ':', 'hour(s) ', 1)
            stupid_cisco_output = stupid_cisco_output.replace(
                ':', 'minute(s) ', 1)
            stupid_cisco_output += 'second(s)'
        else:
            stupid_cisco_output = stupid_cisco_output.replace('d', 'day(s) ')
            stupid_cisco_output = stupid_cisco_output.replace('h', 'hour(s)')

        things = {
            'second(s)': {
                'weight': 1
            },
            'minute(s)': {
                'weight': 60
            },
            'hour(s)': {
                'weight': 3600
            },
            'day(s)': {
                'weight': 24 * 3600
            },
            'week(s)': {
                'weight': 7 * 24 * 3600
            },
            'year(s)': {
                'weight': 365.25 * 24 * 3600
            }
        }

        things_keys = things.keys()
        for part in stupid_cisco_output.split():
            for key in things_keys:
                if key in part:
                    things[key]['count'] = napalm_base.helpers.convert(
                        int, part.replace(key, ''), 0)

        delta = sum([
            det.get('count', 0) * det.get('weight') for det in things.values()
        ])
        return time.time() - delta

    @staticmethod
    def _get_reply_body(result):
        # useful for debugging
        ret = result.get('ins_api', {}).get('outputs',
                                            {}).get('output',
                                                    {}).get('body', {})
        # Original 'body' entry may have been an empty string, don't return that.
        if not isinstance(ret, dict):
            return {}
        return ret

    @staticmethod
    def _get_table_rows(parent_table, table_name, row_name):
        # because if an inconsistent piece of shit.
        # {'TABLE_intf': [{'ROW_intf': {
        # vs
        # {'TABLE_mac_address': {'ROW_mac_address': [{
        # vs
        # {'TABLE_vrf': {'ROW_vrf': {'TABLE_adj': {'ROW_adj': {
        _table = parent_table.get(table_name)
        _table_rows = []
        if isinstance(_table, list):
            _table_rows = [_table_row.get(row_name) for _table_row in _table]
        elif isinstance(_table, dict):
            _table_rows = _table.get(row_name)
        if not isinstance(_table_rows, list):
            _table_rows = [_table_rows]
        return _table_rows

    @staticmethod
    def fix_checkpoint_string(string, filename):
        # used to generate checkpoint-like files
        pattern = '''!Command: Checkpoint cmd vdc 1'''

        if '!Command' in string:
            return re.sub('!Command.*', pattern.format(filename), string)
        else:
            return "{0}\n{1}".format(pattern.format(filename), string)

    def _get_reply_table(self, result, table_name, row_name):
        return self._get_table_rows(result, table_name, row_name)

    def _get_command_table(self, command, table_name, row_name):
        json_output = self.device.show(command)
        return self._get_reply_table(json_output, table_name, row_name)

    def is_alive(self):
        if self.device:
            return {'is_alive': True}
        else:
            return {'is_alive': False}

    def load_replace_candidate(self, filename=None, config=None):
        self.replace = True
        self.loaded = True

        if not filename and not config:
            raise ReplaceConfigException(
                'filename or config param must be provided.')

        if filename is None:
            temp_file = tempfile.NamedTemporaryFile()
            temp_file.write(config)
            temp_file.flush()
            cfg_filename = temp_file.name
        else:
            cfg_filename = filename

        self.replace_file = cfg_filename

        with open(self.replace_file, 'r') as f:
            file_content = f.read()

        file_content = self.fix_checkpoint_string(file_content,
                                                  self.replace_file)
        temp_file = tempfile.NamedTemporaryFile()
        temp_file.write(file_content)
        temp_file.flush()
        self.replace_file = cfg_filename

        self._send_file(temp_file.name, cfg_filename)

    def load_merge_candidate(self, filename=None, config=None):
        self.replace = False
        self.loaded = True

        if not filename and not config:
            raise MergeConfigException(
                'filename or config param must be provided.')

        self.merge_candidate += '\n'  # insert one extra line
        if filename is not None:
            with open(filename, "r") as f:
                self.merge_candidate += f.read()
        else:
            self.merge_candidate += config

    def _send_file(self, filename, dest):
        self.fc = FileCopy(self.device, filename, dst=dest.split('/')[-1])
        try:
            if not self.fc.remote_file_exists():
                self.fc.send()
            elif not self.fc.file_already_exists():
                commands = [
                    'terminal dont-ask', 'delete {0}'.format(self.fc.dst)
                ]
                self.device.config_list(commands)
                self.fc.send()
        except NXOSFileTransferError as fte:
            raise ReplaceConfigException(fte.message)

    def _create_sot_file(self):
        """Create Source of Truth file to compare."""
        commands = ['terminal dont-ask', 'checkpoint file sot_file']
        self.device.config_list(commands)

    def _get_diff(self, cp_file):
        """Get a diff between running config and a proposed file."""
        diff = []
        self._create_sot_file()
        diff_out = self.device.show(
            'show diff rollback-patch file {0} file {1}'.format(
                'sot_file',
                self.replace_file.split('/')[-1]),
            raw_text=True)
        try:
            diff_out = diff_out.split('#Generating Rollback Patch')[1].replace(
                'Rollback Patch is Empty', '').strip()
            for line in diff_out.splitlines():
                if line:
                    if line[0].strip() != '!':
                        diff.append(line.rstrip(' '))
        except (AttributeError, KeyError):
            raise ReplaceConfigException(
                'Could not calculate diff. It\'s possible the given file doesn\'t exist.'
            )
        return '\n'.join(diff)

    def _get_merge_diff(self):
        diff = []
        running_config = self.get_config(retrieve='running')['running']
        running_lines = running_config.splitlines()
        for line in self.merge_candidate.splitlines():
            if line not in running_lines and line:
                if line[0].strip() != '!':
                    diff.append(line)
        return '\n'.join(diff)
        # the merge diff is not necessarily what needs to be loaded
        # for example under NTP, as the `ntp commit` command might be
        # alread configured, it is mandatory to be sent
        # otherwise it won't take the new configuration - see #59
        # https://github.com/napalm-automation/napalm-nxos/issues/59
        # therefore this method will return the real diff
        # but the merge_candidate will remain unchanged
        # previously: self.merge_candidate = '\n'.join(diff)

    def compare_config(self):
        if self.loaded:
            if not self.replace:
                return self._get_merge_diff()
                # return self.merge_candidate
            diff = self._get_diff(self.fc.dst)
            return diff
        return ''

    def _commit_merge(self):
        commands = [
            command for command in self.merge_candidate.splitlines() if command
        ]
        self.device.config_list(commands)
        if not self.device.save():
            raise CommandErrorException('Unable to commit config!')

    def _save_config(self, filename):
        """Save the current running config to the given file."""
        self.device.show('checkpoint file {}'.format(filename), raw_text=True)

    def _disable_confirmation(self):
        self.device.config('terminal dont-ask')

    def _load_config(self):
        cmd = 'rollback running file {0}'.format(
            self.replace_file.split('/')[-1])
        self._disable_confirmation()
        try:
            rollback_result = self.device.config(cmd)
        except ConnectionError:
            # requests will raise an error with verbose warning output
            return True
        except Exception:
            return False
        if 'Rollback failed.' in rollback_result['msg']:
            raise ReplaceConfigException(rollback_result['msg'])
        return True

    def commit_config(self):
        if self.loaded:
            self.backup_file = 'config_' + str(datetime.now()).replace(
                ' ', '_')
            self._save_config(self.backup_file)
            if self.replace:
                if self._load_config() is False:
                    raise ReplaceConfigException
            else:
                try:
                    self._commit_merge()
                    self.merge_candidate = ''  # clear the merge buffer
                except Exception as e:
                    raise MergeConfigException(str(e))

            self.changed = True
            self.loaded = False
        else:
            raise ReplaceConfigException('No config loaded.')

    def _delete_file(self, filename):
        commands = [
            'terminal dont-ask', 'delete {}'.format(filename),
            'no terminal dont-ask'
        ]
        self.device.show_list(commands, raw_text=True)

    def discard_config(self):
        if self.loaded:
            self.merge_candidate = ''  # clear the buffer
        if self.loaded and self.replace:
            try:
                self._delete_file(self.fc.dst)
            except CLIError:
                pass
        self.loaded = False

    def rollback(self):
        if self.changed:
            self.device.rollback(self.backup_file)
            self.device.save()
            self.changed = False

    def get_facts(self):
        pynxos_facts = self.device.facts
        final_facts = {
            key: value
            for key, value in pynxos_facts.items()
            if key not in ['interfaces', 'uptime_string', 'vlans']
        }

        if pynxos_facts['interfaces']:
            final_facts['interface_list'] = pynxos_facts['interfaces']
        else:
            final_facts['interface_list'] = self.get_interfaces().keys()

        final_facts['vendor'] = 'Cisco'

        hostname_cmd = 'show hostname'
        hostname = self.device.show(hostname_cmd).get('hostname')
        if hostname:
            final_facts['fqdn'] = hostname

        return final_facts

    def get_interfaces(self):
        interfaces = {}
        iface_cmd = 'show interface'
        interfaces_out = self.device.show(iface_cmd)
        interfaces_body = interfaces_out['TABLE_interface']['ROW_interface']

        for interface_details in interfaces_body:
            interface_name = interface_details.get('interface')
            # Earlier version of Nexus returned a list for 'eth_bw' (observed on 7.1(0)N1(1a))
            interface_speed = interface_details.get('eth_bw', 0)
            if isinstance(interface_speed, list):
                interface_speed = interface_speed[0]
            interface_speed = int(interface_speed / 1000)
            if 'admin_state' in interface_details:
                is_up = interface_details.get('admin_state', '') == 'up'
            else:
                is_up = interface_details.get('state', '') == 'up'
            interfaces[interface_name] = {
                'is_up':
                is_up,
                'is_enabled': (interface_details.get('state') == 'up'),
                'description':
                py23_compat.text_type(
                    interface_details.get('desc', '').strip('"')),
                'last_flapped':
                self._compute_timestamp(
                    interface_details.get('eth_link_flapped', '')),
                'speed':
                interface_speed,
                'mac_address':
                napalm_base.helpers.convert(
                    napalm_base.helpers.mac,
                    interface_details.get('eth_hw_addr')),
            }
        return interfaces

    def get_lldp_neighbors(self):
        results = {}
        try:
            command = 'show lldp neighbors'
            lldp_raw_output = self.cli([command]).get(command, '')
            lldp_neighbors = napalm_base.helpers.textfsm_extractor(
                self, 'lldp_neighbors', lldp_raw_output)
        except CLIError:
            lldp_neighbors = []

        for neighbor in lldp_neighbors:
            local_iface = neighbor.get('local_interface')
            if neighbor.get(local_iface) is None:
                if local_iface not in results:
                    results[local_iface] = []

            neighbor_dict = {}
            neighbor_dict['hostname'] = py23_compat.text_type(
                neighbor.get('neighbor'))
            neighbor_dict['port'] = py23_compat.text_type(
                neighbor.get('neighbor_interface'))

            results[local_iface].append(neighbor_dict)
        return results

    def get_bgp_neighbors(self):
        results = {}
        try:
            cmd = 'show bgp sessions vrf all'
            vrf_list = self._get_command_table(cmd, 'TABLE_vrf', 'ROW_vrf')
        except CLIError:
            vrf_list = []

        for vrf_dict in vrf_list:
            result_vrf_dict = {}
            result_vrf_dict['router_id'] = py23_compat.text_type(
                vrf_dict['router-id'])
            result_vrf_dict['peers'] = {}
            neighbors_list = vrf_dict.get('TABLE_neighbor',
                                          {}).get('ROW_neighbor', [])

            if isinstance(neighbors_list, dict):
                neighbors_list = [neighbors_list]

            for neighbor_dict in neighbors_list:
                neighborid = napalm_base.helpers.ip(
                    neighbor_dict['neighbor-id'])
                remoteas = napalm_base.helpers.as_number(
                    neighbor_dict['remoteas'])

                result_peer_dict = {
                    'local_as': int(vrf_dict['local-as']),
                    'remote_as': remoteas,
                    'remote_id': neighborid,
                    'is_enabled': True,
                    'uptime': -1,
                    'description': py23_compat.text_type(''),
                    'is_up': True
                }
                result_peer_dict['address_family'] = {
                    'ipv4': {
                        'sent_prefixes': -1,
                        'accepted_prefixes': -1,
                        'received_prefixes': -1
                    }
                }
                result_vrf_dict['peers'][neighborid] = result_peer_dict

            vrf_name = vrf_dict['vrf-name-out']
            if vrf_name == 'default':
                vrf_name = 'global'
            results[vrf_name] = result_vrf_dict
        return results

    def _set_checkpoint(self, filename):
        commands = [
            'terminal dont-ask', 'checkpoint file {0}'.format(filename)
        ]
        self.device.config_list(commands)

    def _get_checkpoint_file(self):
        filename = 'temp_cp_file_from_napalm'
        self._set_checkpoint(filename)
        cp_out = self.device.show('show file {0}'.format(filename),
                                  raw_text=True)
        self._delete_file(filename)
        return cp_out

    def get_lldp_neighbors_detail(self, interface=''):
        lldp_neighbors = {}
        filter = ''
        if interface:
            filter = 'interface {name} '.format(name=interface)

        command = 'show lldp neighbors {filter}detail'.format(filter=filter)
        # seems that some old devices may not return JSON output...

        try:
            lldp_neighbors_table_str = self.cli([command]).get(command)
            # thus we need to take the raw text output
            lldp_neighbors_list = lldp_neighbors_table_str.splitlines()
        except CLIError:
            lldp_neighbors_list = []

        if not lldp_neighbors_list:
            return lldp_neighbors  # empty dict

        CHASSIS_REGEX = '^(Chassis id:)\s+([a-z0-9\.]+)$'
        PORT_REGEX = '^(Port id:)\s+([0-9]+)$'
        LOCAL_PORT_ID_REGEX = '^(Local Port id:)\s+(.*)$'
        PORT_DESCR_REGEX = '^(Port Description:)\s+(.*)$'
        SYSTEM_NAME_REGEX = '^(System Name:)\s+(.*)$'
        SYSTEM_DESCR_REGEX = '^(System Description:)\s+(.*)$'
        SYST_CAPAB_REEGX = '^(System Capabilities:)\s+(.*)$'
        ENABL_CAPAB_REGEX = '^(Enabled Capabilities:)\s+(.*)$'
        VLAN_ID_REGEX = '^(Vlan ID:)\s+(.*)$'

        lldp_neighbor = {}
        interface_name = None

        for line in lldp_neighbors_list:
            chassis_rgx = re.search(CHASSIS_REGEX, line, re.I)
            if chassis_rgx:
                lldp_neighbor = {
                    'remote_chassis_id':
                    napalm_base.helpers.mac(chassis_rgx.groups()[1])
                }
                continue
            lldp_neighbor['parent_interface'] = ''
            port_rgx = re.search(PORT_REGEX, line, re.I)
            if port_rgx:
                lldp_neighbor['parent_interface'] = py23_compat.text_type(
                    port_rgx.groups()[1])
                continue
            local_port_rgx = re.search(LOCAL_PORT_ID_REGEX, line, re.I)
            if local_port_rgx:
                interface_name = local_port_rgx.groups()[1]
                continue
            port_descr_rgx = re.search(PORT_DESCR_REGEX, line, re.I)
            if port_descr_rgx:
                lldp_neighbor['remote_port'] = py23_compat.text_type(
                    port_descr_rgx.groups()[1])
                lldp_neighbor[
                    'remote_port_description'] = py23_compat.text_type(
                        port_descr_rgx.groups()[1])
                continue
            syst_name_rgx = re.search(SYSTEM_NAME_REGEX, line, re.I)
            if syst_name_rgx:
                lldp_neighbor['remote_system_name'] = py23_compat.text_type(
                    syst_name_rgx.groups()[1])
                continue
            syst_descr_rgx = re.search(SYSTEM_DESCR_REGEX, line, re.I)
            if syst_descr_rgx:
                lldp_neighbor[
                    'remote_system_description'] = py23_compat.text_type(
                        syst_descr_rgx.groups()[1])
                continue
            syst_capab_rgx = re.search(SYST_CAPAB_REEGX, line, re.I)
            if syst_capab_rgx:
                lldp_neighbor['remote_system_capab'] = py23_compat.text_type(
                    syst_capab_rgx.groups()[1])
                continue
            syst_enabled_rgx = re.search(ENABL_CAPAB_REGEX, line, re.I)
            if syst_enabled_rgx:
                lldp_neighbor[
                    'remote_system_enable_capab'] = py23_compat.text_type(
                        syst_enabled_rgx.groups()[1])
                continue
            vlan_rgx = re.search(VLAN_ID_REGEX, line, re.I)
            if vlan_rgx:
                # at the end of the loop
                if interface_name not in lldp_neighbors.keys():
                    lldp_neighbors[interface_name] = []
                lldp_neighbors[interface_name].append(lldp_neighbor)
        return lldp_neighbors

    def cli(self, commands):
        cli_output = {}
        if type(commands) is not list:
            raise TypeError('Please enter a valid list of commands!')

        for command in commands:
            command_output = self.device.show(command, raw_text=True)
            cli_output[py23_compat.text_type(command)] = command_output
        return cli_output

    def get_arp_table(self):
        arp_table = []
        command = 'show ip arp'
        arp_table_vrf = self._get_command_table(command, 'TABLE_vrf',
                                                'ROW_vrf')
        arp_table_raw = self._get_table_rows(arp_table_vrf[0], 'TABLE_adj',
                                             'ROW_adj')

        for arp_table_entry in arp_table_raw:
            raw_ip = arp_table_entry.get('ip-addr-out')
            raw_mac = arp_table_entry.get('mac')
            age = arp_table_entry.get('time-stamp')
            if age == '-':
                age_sec = float(-1)
            else:
                age_time = ''.join(age.split(':'))
                age_sec = float(3600 * int(age_time[:2]) +
                                60 * int(age_time[2:4]) + int(age_time[4:]))
            interface = py23_compat.text_type(arp_table_entry.get('intf-out'))
            arp_table.append({
                'interface':
                interface,
                'mac':
                napalm_base.helpers.convert(napalm_base.helpers.mac, raw_mac,
                                            raw_mac),
                'ip':
                napalm_base.helpers.ip(raw_ip),
                'age':
                age_sec
            })
        return arp_table

    def _get_ntp_entity(self, peer_type):
        ntp_entities = {}
        command = 'show ntp peers'
        ntp_peers_table = self._get_command_table(command, 'TABLE_peers',
                                                  'ROW_peers')

        for ntp_peer in ntp_peers_table:
            if ntp_peer.get('serv_peer', '').strip() != peer_type:
                continue
            peer_addr = napalm_base.helpers.ip(
                ntp_peer.get('PeerIPAddress').strip())
            ntp_entities[peer_addr] = {}

        return ntp_entities

    def get_ntp_peers(self):
        return self._get_ntp_entity('Peer')

    def get_ntp_servers(self):
        return self._get_ntp_entity('Server')

    def get_ntp_stats(self):
        ntp_stats = []
        command = 'show ntp peer-status'
        ntp_stats_table = self._get_command_table(command, 'TABLE_peersstatus',
                                                  'ROW_peersstatus')

        for ntp_peer in ntp_stats_table:
            peer_address = napalm_base.helpers.ip(
                ntp_peer.get('remote').strip())
            syncmode = ntp_peer.get('syncmode')
            stratum = int(ntp_peer.get('st'))
            hostpoll = int(ntp_peer.get('poll'))
            reachability = int(ntp_peer.get('reach'))
            delay = float(ntp_peer.get('delay'))
            ntp_stats.append({
                'remote': peer_address,
                'synchronized': (syncmode == '*'),
                'referenceid': peer_address,
                'stratum': stratum,
                'type': '',
                'when': '',
                'hostpoll': hostpoll,
                'reachability': reachability,
                'delay': delay,
                'offset': 0.0,
                'jitter': 0.0
            })
        return ntp_stats

    def get_interfaces_ip(self):
        interfaces_ip = {}
        ipv4_command = 'show ip interface'
        ipv4_interf_table_vrf = self._get_command_table(
            ipv4_command, 'TABLE_intf', 'ROW_intf')

        for interface in ipv4_interf_table_vrf:
            interface_name = py23_compat.text_type(
                interface.get('intf-name', ''))
            address = napalm_base.helpers.ip(interface.get('prefix'))
            prefix = int(interface.get('masklen', ''))
            if interface_name not in interfaces_ip.keys():
                interfaces_ip[interface_name] = {}
            if 'ipv4' not in interfaces_ip[interface_name].keys():
                interfaces_ip[interface_name]['ipv4'] = {}
            if address not in interfaces_ip[interface_name].get('ipv4'):
                interfaces_ip[interface_name]['ipv4'][address] = {}
            interfaces_ip[interface_name]['ipv4'][address].update(
                {'prefix_length': prefix})
            secondary_addresses = interface.get('TABLE_secondary_address', {})\
                                           .get('ROW_secondary_address', [])
            if type(secondary_addresses) is dict:
                secondary_addresses = [secondary_addresses]
            for secondary_address in secondary_addresses:
                secondary_address_ip = napalm_base.helpers.ip(
                    secondary_address.get('prefix1'))
                secondary_address_prefix = int(
                    secondary_address.get('masklen1', ''))
                if 'ipv4' not in interfaces_ip[interface_name].keys():
                    interfaces_ip[interface_name]['ipv4'] = {}
                if secondary_address_ip not in interfaces_ip[
                        interface_name].get('ipv4'):
                    interfaces_ip[interface_name]['ipv4'][
                        secondary_address_ip] = {}
                interfaces_ip[interface_name]['ipv4'][
                    secondary_address_ip].update(
                        {'prefix_length': secondary_address_prefix})

        ipv6_command = 'show ipv6 interface'
        ipv6_interf_table_vrf = self._get_command_table(
            ipv6_command, 'TABLE_intf', 'ROW_intf')

        for interface in ipv6_interf_table_vrf:
            interface_name = py23_compat.text_type(
                interface.get('intf-name', ''))
            address = napalm_base.helpers.ip(
                interface.get('addr', '').split('/')[0])
            prefix = interface.get('prefix', '').split('/')[-1]
            if prefix:
                prefix = int(interface.get('prefix', '').split('/')[-1])
            else:
                prefix = 128
            if interface_name not in interfaces_ip.keys():
                interfaces_ip[interface_name] = {}
            if 'ipv6' not in interfaces_ip[interface_name].keys():
                interfaces_ip[interface_name]['ipv6'] = {}
            if address not in interfaces_ip[interface_name].get('ipv6'):
                interfaces_ip[interface_name]['ipv6'][address] = {}
            interfaces_ip[interface_name]['ipv6'][address].update(
                {'prefix_length': prefix})
            secondary_addresses = interface.get('TABLE_sec_addr',
                                                {}).get('ROW_sec_addr', [])
            if type(secondary_addresses) is dict:
                secondary_addresses = [secondary_addresses]
            for secondary_address in secondary_addresses:
                sec_prefix = secondary_address.get('sec-prefix', '').split('/')
                secondary_address_ip = napalm_base.helpers.ip(sec_prefix[0])
                secondary_address_prefix = int(sec_prefix[-1])
                if 'ipv6' not in interfaces_ip[interface_name].keys():
                    interfaces_ip[interface_name]['ipv6'] = {}
                if secondary_address_ip not in interfaces_ip[
                        interface_name].get('ipv6'):
                    interfaces_ip[interface_name]['ipv6'][
                        secondary_address_ip] = {}
                interfaces_ip[interface_name]['ipv6'][
                    secondary_address_ip].update(
                        {'prefix_length': secondary_address_prefix})
        return interfaces_ip

    def get_mac_address_table(self):
        mac_table = []
        command = 'show mac address-table'
        mac_table_raw = self._get_command_table(command, 'TABLE_mac_address',
                                                'ROW_mac_address')

        for mac_entry in mac_table_raw:
            raw_mac = mac_entry.get('disp_mac_addr')
            interface = py23_compat.text_type(mac_entry.get('disp_port'))
            vlan = int(mac_entry.get('disp_vlan'))
            active = True
            static = (mac_entry.get('disp_is_static') != '0')
            moves = 0
            last_move = 0.0
            mac_table.append({
                'mac': napalm_base.helpers.mac(raw_mac),
                'interface': interface,
                'vlan': vlan,
                'active': active,
                'static': static,
                'moves': moves,
                'last_move': last_move
            })
        return mac_table

    def get_snmp_information(self):
        snmp_information = {}
        snmp_command = 'show running-config'
        snmp_raw_output = self.cli([snmp_command]).get(snmp_command, '')
        snmp_config = napalm_base.helpers.textfsm_extractor(
            self, 'snmp_config', snmp_raw_output)

        if not snmp_config:
            return snmp_information

        snmp_information = {
            'contact': py23_compat.text_type(''),
            'location': py23_compat.text_type(''),
            'community': {},
            'chassis_id': py23_compat.text_type('')
        }

        for snmp_entry in snmp_config:
            contact = py23_compat.text_type(snmp_entry.get('contact', ''))
            if contact:
                snmp_information['contact'] = contact
            location = py23_compat.text_type(snmp_entry.get('location', ''))
            if location:
                snmp_information['location'] = location

            community_name = py23_compat.text_type(
                snmp_entry.get('community', ''))
            if not community_name:
                continue

            if community_name not in snmp_information['community'].keys():
                snmp_information['community'][community_name] = {
                    'acl':
                    py23_compat.text_type(snmp_entry.get('acl', '')),
                    'mode':
                    py23_compat.text_type(snmp_entry.get('mode', '').lower())
                }
            else:
                acl = py23_compat.text_type(snmp_entry.get('acl', ''))
                if acl:
                    snmp_information['community'][community_name]['acl'] = acl
                mode = py23_compat.text_type(
                    snmp_entry.get('mode', '').lower())
                if mode:
                    snmp_information['community'][community_name][
                        'mode'] = mode
        return snmp_information

    def get_users(self):
        _CISCO_TO_CISCO_MAP = {'network-admin': 15, 'network-operator': 5}

        _DEFAULT_USER_DICT = {'password': '', 'level': 0, 'sshkeys': []}

        users = {}
        command = 'show running-config'
        section_username_raw_output = self.cli([command]).get(command, '')
        section_username_tabled_output = napalm_base.helpers.textfsm_extractor(
            self, 'users', section_username_raw_output)

        for user in section_username_tabled_output:
            username = user.get('username', '')
            if not username:
                continue
            if username not in users:
                users[username] = _DEFAULT_USER_DICT.copy()

            password = user.get('password', '')
            if password:
                users[username]['password'] = py23_compat.text_type(
                    password.strip())

            level = 0
            role = user.get('role', '')
            if role.startswith('priv'):
                level = int(role.split('-')[-1])
            else:
                level = _CISCO_TO_CISCO_MAP.get(role, 0)
            if level > users.get(username).get('level'):
                # unfortunately on Cisco you can set different priv levels for the same user
                # Good news though: the device will consider the highest level
                users[username]['level'] = level

            sshkeytype = user.get('sshkeytype', '')
            sshkeyvalue = user.get('sshkeyvalue', '')
            if sshkeytype and sshkeyvalue:
                if sshkeytype not in ['ssh-rsa', 'ssh-dsa']:
                    continue
                users[username]['sshkeys'].append(
                    py23_compat.text_type(sshkeyvalue))
        return users

    def traceroute(self,
                   destination,
                   source=c.TRACEROUTE_SOURCE,
                   ttl=c.TRACEROUTE_TTL,
                   timeout=c.TRACEROUTE_TIMEOUT,
                   vrf=c.TRACEROUTE_VRF):
        _HOP_ENTRY_PROBE = [
            '\s+',
            '(',  # beginning of host_name (ip_address) RTT group
            '(',  # beginning of host_name (ip_address) group only
            '([a-zA-Z0-9\.:-]*)',  # hostname
            '\s+',
            '\(?([a-fA-F0-9\.:][^\)]*)\)?'  # IP Address between brackets
            ')?',  # end of host_name (ip_address) group only
            # also hostname/ip are optional -- they can or cannot be specified
            # if not specified, means the current probe followed the same path as the previous
            '\s+',
            '(\d+\.\d+)\s+ms',  # RTT
            '|\*',  # OR *, when non responsive hop
            ')'  # end of host_name (ip_address) RTT group
        ]

        _HOP_ENTRY = [
            '\s?',  # space before hop index?
            '(\d+)',  # hop index
        ]

        traceroute_result = {}
        timeout = 5  # seconds
        probes = 3  # 3 probes/jop and this cannot be changed on NXOS!

        version = ''
        try:
            version = '6' if IPAddress(destination).version == 6 else ''
        except AddrFormatError:
            return {
                'error':
                'Destination doest not look like a valid IP Address: {}'.
                format(destination)
            }

        source_opt = ''
        if source:
            source_opt = 'source {source}'.format(source=source)

        command = 'traceroute{version} {destination} {source_opt}'.format(
            version=version, destination=destination, source_opt=source_opt)

        try:
            traceroute_raw_output = self.cli([command]).get(command)
        except CommandErrorException:
            return {
                'error':
                'Cannot execute traceroute on the device: {}'.format(command)
            }

        hop_regex = ''.join(_HOP_ENTRY + _HOP_ENTRY_PROBE * probes)
        traceroute_result['success'] = {}
        if traceroute_raw_output:
            for line in traceroute_raw_output.splitlines():
                hop_search = re.search(hop_regex, line)
                if not hop_search:
                    continue
                hop_details = hop_search.groups()
                hop_index = int(hop_details[0])
                previous_probe_host_name = '*'
                previous_probe_ip_address = '*'
                traceroute_result['success'][hop_index] = {'probes': {}}
                for probe_index in range(probes):
                    host_name = hop_details[3 + probe_index * 5]
                    ip_address_raw = hop_details[4 + probe_index * 5]
                    ip_address = napalm_base.helpers.convert(
                        napalm_base.helpers.ip, ip_address_raw, ip_address_raw)
                    rtt = hop_details[5 + probe_index * 5]
                    if rtt:
                        rtt = float(rtt)
                    else:
                        rtt = timeout * 1000.0
                    if not host_name:
                        host_name = previous_probe_host_name
                    if not ip_address:
                        ip_address = previous_probe_ip_address
                    if hop_details[1 + probe_index * 5] == '*':
                        host_name = '*'
                        ip_address = '*'
                    traceroute_result['success'][hop_index]['probes'][
                        probe_index + 1] = {
                            'host_name': py23_compat.text_type(host_name),
                            'ip_address': py23_compat.text_type(ip_address),
                            'rtt': rtt
                        }
                    previous_probe_host_name = host_name
                    previous_probe_ip_address = ip_address
        return traceroute_result

    def get_config(self, retrieve='all'):
        config = {
            'startup': '',
            'running': '',
            'candidate': ''
        }  # default values

        if retrieve.lower() in ('running', 'all'):
            _cmd = 'show running-config'
            config['running'] = py23_compat.text_type(
                self.cli([_cmd]).get(_cmd))
        if retrieve.lower() in ('startup', 'all'):
            _cmd = 'show startup-config'
            config['startup'] = py23_compat.text_type(
                self.cli([_cmd]).get(_cmd))
        return config
Exemplo n.º 15
0
def main():

    switch_ip = "31.220.71.66"
    username = '******'
    password = getpass()
    eth_inf = "Ethernet 2/2"
    int_ip = "10.1.4.6/30"
    peer_ip = "10.1.4.5"
    AS = "10"

    configure_int = [
        "interface " + eth_inf,
        "ip address " + int_ip,
    ]

    configure_bgp = [
        "license grace-period",
        "feature bgp",
        "router bgp " + AS,
        "neighbor {} remote-as {}".format(peer_ip, AS),
        "address-family ipv4 unicast",
    ]

    nxs = Device(host=switch_ip,
                 username=username,
                 password=password,
                 transport="https",
                 port=8443)

    print "current config of Ethernet interface :"
    cmd = "show run int {}".format(eth_inf)
    print nxs.show(cmd, raw_text=True)

    print "\nConfiguring Ethernet Interface:"
    nxs.config_list(configure_int)

    print "new config of Ethernet interface :"
    cmd = "show run int {}".format(eth_inf)
    print nxs.show(cmd, raw_text=True)

    print "current BGP config :"
    cmd = 'show run bgp'
    print nxs.show(cmd, raw_text=True)

    print "\nConfiguring BGP"
    nxs.config_list(configure_bgp)

    print "new BGP config :"
    cmd = 'show run bgp'
    print nxs.show(cmd, raw_text=True)

    print "\nVerifying  BGP peers"
    cmd = 'show bgp session'
    print nxs.show(cmd, raw_text=True)

    print "\nSaving config..."
    print nxs.save()
Exemplo n.º 16
0
#!/usr/bin/env python
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from pprint import pprint
from getpass import getpass
from pynxos.device import Device

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

#nexus_ip = "34.195.147.241"
nexus_ip = "nxos1.twb-tech.com"
nxs_test = Device(host=nexus_ip,
                  username="******",
                  password=getpass(),
                  transport='https',
                  port=8443)

#### FACTS
print "\nFacts"
print '-' * 50
pprint(nxs_test.facts)
raw_input("\n\nHit a key to continue: ")

###### SHOW
print "\nShow hostname"
print '-' * 50
print nxs_test.show("show hostname")
print '-' * 50
raw_input("\n\nHit a key to continue: ")

###### SHOW RAW TEXT
Exemplo n.º 17
0
#!/usr/bin/env python
from __future__ import unicode_literals, print_function
from pynxos.device import Device
from getpass import getpass
from pprint import pprint as pp

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

nxos1 = Device(host='nxos1.twb-tech.com',
               username='******',
               password=getpass(),
               transport='https',
               port='8443')

nxos2 = Device(host='nxos2.twb-tech.com',
               username='******',
               password=getpass(),
               transport='https',
               port='8443')

command = "show ip route vrf management"
output = nxos1.show(command)

routes = output['TABLE_vrf']['ROW_vrf']['TABLE_addrf']['ROW_addrf'][
    'TABLE_prefix']['ROW_prefix']
for route in routes:
    if route['ipprefix'] == '0.0.0.0/0':
        print(route['TABLE_path']['ROW_path']['ipnexthop'])
Exemplo n.º 18
0
from pynxos.device import Device
from getpass import getpass

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

password = '******'
nxos1 = {
    'host': 'nxos1.twb-tech.com',
    'username': '******',
    'password': password,
    'transport': 'https',
    'port': 8443,
}
nxos2 = {
    'host': 'nxos2.twb-tech.com',
    'username': '******',
    'password': password,
    'transport': 'https',
    'port': 8443,
}

print()
for device in (nxos1, nxos2):
    nxapi_conn = Device(**device)
    print('-' * 40)
    print(nxapi_conn.show('show hostname'))
    print('-' * 40)
print()
Exemplo n.º 19
0
from __future__ import print_function, unicode_literals
from pynxos.device import Device
from getpass import getpass
from pprint import pprint

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

device = Device(host='nxos2.twb-tech.com',
                username='******',
                password=getpass(),
                transport='https',
                port=8443)

print(device.show('show hostname'))

# Show command
command = 'show version'
output = device.show(command)
pprint(output)

# Show comand with raw_text i.e. unstructured data
command = 'show version'
output = device.show(command, raw_text=True)
print(output)

# Config command
commands = [
    'logging history size 300',
Exemplo n.º 20
0
class NXOSDevice(BaseDevice):
    def __init__(self,
                 host,
                 username,
                 password,
                 transport='http',
                 timeout=30,
                 port=None,
                 **kwargs):
        super(NXOSDevice, self).__init__(host,
                                         username,
                                         password,
                                         vendor='cisco',
                                         device_type='cisco_nxos_nxapi')
        self.transport = transport
        self.timeout = timeout
        self.native = NXOSNative(host,
                                 username,
                                 password,
                                 transport=transport,
                                 timeout=timeout,
                                 port=port)

    def _image_booted(self, image_name, **vendor_specifics):
        version_data = self.show("show version", raw_text=True)
        if re.search(image_name, version_data):
            return True

        return False

    def _wait_for_device_reboot(self, timeout=3600):
        start = time.time()
        while time.time() - start < timeout:
            try:
                self.show("show hostname")
                return
            except:
                pass

        raise RebootTimeoutError(hostname=self.facts["hostname"],
                                 wait_time=timeout)

    def backup_running_config(self, filename):
        self.native.backup_running_config(filename)

    def checkpoint(self, filename):
        return self.native.checkpoint(filename)

    def close(self):
        pass

    def config(self, command):
        try:
            self.native.config(command)
        except CLIError as e:
            raise CommandError(command, str(e))

    def config_list(self, commands):
        try:
            self.native.config_list(commands)
        except CLIError as e:
            raise CommandListError(commands, e.command, str(e))

    @property
    def facts(self):
        if hasattr(self, '_facts'):
            return self._facts

        facts = strip_unicode(self.native.facts)
        facts['vendor'] = self.vendor

        self._facts = facts
        return self._facts

    def file_copy(self, src, dest=None, file_system='bootflash:'):
        if not self.file_copy_remote_exists(src, dest, file_system):
            dest = dest or os.path.basename(src)
            try:
                file_copy = self.native.file_copy(src,
                                                  dest,
                                                  file_system=file_system)
                if not self.file_copy_remote_exists(src, dest, file_system):
                    raise FileTransferError(
                        message="Attempted file copy, "
                        "but could not validate file existed after transfer")
                return file_copy
            except NXOSFileTransferError as e:
                print(str(e))
                raise FileTransferError

    # TODO: Make this an internal method since exposing file_copy should be sufficient
    def file_copy_remote_exists(self,
                                src,
                                dest=None,
                                file_system='bootflash:'):
        dest = dest or os.path.basename(src)
        return self.native.file_copy_remote_exists(src,
                                                   dest,
                                                   file_system=file_system)

    def get_boot_options(self):
        return self.native.get_boot_options()

    def open(self):
        pass

    def reboot(self, confirm=False, timer=0):
        if timer != 0:
            raise RebootTimerError(self.device_type)

        self.native.reboot(confirm=confirm)

    def rollback(self, filename):
        try:
            self.native.rollback(filename)
        except CLIError:
            raise RollbackError('Rollback unsuccessful, %s may not exist.' %
                                filename)

    @property
    def running_config(self):
        return self.native.running_config

    def save(self, filename='startup-config'):
        return self.native.save(filename=filename)

    def set_boot_options(self, image_name, kickstart=None, **vendor_specifics):
        file_system = vendor_specifics.get("file_system")
        if file_system is None:
            file_system = "bootflash:"

        file_system_files = self.show("dir {0}".format(file_system),
                                      raw_text=True)
        if re.search(image_name, file_system_files) is None:
            raise NTCFileNotFoundError(hostname=self.facts.get("hostname"),
                                       file=image_name,
                                       dir=file_system)
        if kickstart is not None:
            if re.search(kickstart, file_system_files) is None:
                raise NTCFileNotFoundError(hostname=self.facts.get("hostname"),
                                           file=image_name,
                                           dir=file_system)

            kickstart = file_system + kickstart

        image_name = file_system + image_name

        return self.native.set_boot_options(image_name, kickstart=kickstart)

    def set_timeout(self, timeout):
        self.native.timeout = timeout

    def show(self, command, raw_text=False):
        try:
            return strip_unicode(self.native.show(command, raw_text=raw_text))
        except CLIError as e:
            raise CommandError(command, str(e))

    def show_list(self, commands, raw_text=False):
        try:
            return strip_unicode(
                self.native.show_list(commands, raw_text=raw_text))
        except CLIError as e:
            raise CommandListError(commands, e.command, str(e))

    @property
    def startup_config(self):
        return self.show('show startup-config', raw_text=True)
Exemplo n.º 21
0
class TestDevice(unittest.TestCase):
    @mock.patch("pynxos.device.RPCClient")
    def setUp(self, mock_rpc):
        self.device = Device("host", "user", "pass")
        self.rpc = mock_rpc
        self.send_request = mock_rpc.return_value.send_request
        self.send_request.side_effect = send_request

    def test_init(self):
        self.assertEqual(self.device.host, "host")
        self.assertEqual(self.device.username, "user")
        self.assertEqual(self.device.password, "pass")
        self.assertEqual(self.device.transport, "http")
        self.assertEqual(self.device.timeout, 30)

        self.rpc.assert_called_with("host", "user", "pass", transport="http", port=None)

    def test_show(self):
        result = self.device.show("sh clock")
        expected = {"simple_time": "18:06:31.021 UTC Tue Mar 22 2016\n"}

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(["sh clock"], method=u"cli", timeout=30)

    def test_show_empty_response(self):
        self.send_request.return_value = []
        self.send_request.side_effect = None

        result = self.device.show("sh clock")
        expected = {}

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(["sh clock"], method=u"cli", timeout=30)

    def test_show_raw_text(self):
        result = self.device.show("sh clock", raw_text=True)
        expected = "18:29:19.583 UTC Tue Mar 22 2016\n"

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(["sh clock"], method=u"cli_ascii", timeout=30)

    def test_show_list(self):
        result = self.device.show_list(["sh clock", "sh hostname"])
        expected = [{"simple_time": "18:52:45.084 UTC Tue Mar 22 2016\n"}, {"hostname": "N9K2.ntc.com"}]

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(["sh clock", "sh hostname"], method=u"cli", timeout=30)

    def test_show_list_raw_text(self):
        result = self.device.show_list(["sh clock", "sh hostname"], raw_text=True)
        expected = ["18:55:38.720 UTC Tue Mar 22 2016\n", "N9K2.ntc.com \n"]

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(["sh clock", "sh hostname"], method=u"cli_ascii", timeout=30)

    def test_config(self):
        result = self.device.config("int ethernet 1/1")
        expected = None

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(["int ethernet 1/1"], method=u"cli", timeout=30)

    def test_config_list(self):
        result = self.device.config_list(["int ethernet 1/1", "no shutdown"])
        expected = [None, None]

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(["int ethernet 1/1", "no shutdown"], method=u"cli", timeout=30)

    def test_save(self):
        result = self.device.save()
        expected = True

        self.assertEqual(result, expected)
        self.send_request.assert_called_with([u"copy run startup-config"], method=u"cli_ascii", timeout=30)

    def test_save_error(self):
        result = self.device.save(filename="abc")
        expected = False

        self.assertEqual(result, expected)
        self.send_request.assert_called_with([u"copy run abc"], method=u"cli_ascii", timeout=30)

    @mock.patch("pynxos.device.FileCopy")
    def test_file_copy_remote_exists(self, mock_fc):
        mock_fc.return_value.remote_file_exists.return_value = True
        result = self.device.file_copy_remote_exists("source", dest="dest")

        self.assertEqual(result, True)
        mock_fc.assert_called_with(self.device, "source", dst="dest", file_system="bootflash:")

    @mock.patch("pynxos.device.FileCopy")
    def test_file_copy_remote_doesnt_exist(self, mock_fc):
        mock_fc.return_value.remote_file_exists.return_value = False
        result = self.device.file_copy_remote_exists("source", dest="dest")

        self.assertEqual(result, False)
        mock_fc.assert_called_with(self.device, "source", dst="dest", file_system="bootflash:")

    @mock.patch("pynxos.device.FileCopy")
    def test_file_copy(self, mock_fc):
        result = self.device.file_copy("source", dest="dest")

        mock_fc.assert_called_with(self.device, "source", dst="dest", file_system="bootflash:")
        mock_fc.return_value.send.assert_called_with()

    @mock.patch.object(Device, "show")
    def test_reboot(self, mock_show):
        self.device.reboot(confirm=True)

        mock_show.assert_any_call("terminal dont-ask")
        mock_show.assert_any_call("reload")

    @mock.patch.object(Device, "show")
    def test_set_boot_options(self, mock_show):
        self.device.set_boot_options("boot.sys")
        mock_show.assert_called_with("install all nxos boot.sys", raw_text=True)

    @mock.patch.object(Device, "show")
    def test_set_boot_options_kickstart(self, mock_show):
        self.device.set_boot_options("boot.sys", kickstart="boot.kick")
        mock_show.assert_called_with("install all system boot.sys kickstart boot.kick", raw_text=True)

    def test_get_boot_options(self):
        result = self.device.get_boot_options()
        expected = {
            "sys": "nxos.7.0.3.I2.1.bin",
            "status": 'This is the log of last installation.\nVerifying image bootflash:/nxos.7.0.3.I2.1.bin for boot variable "nxos".\n -- SUCCESS\nVerifying image type.\n -- SUCCESS\nPreparing "nxos" version info using image bootflash:/nxos.7.0.3.I2.1.bin.\n -- SUCCESS\nPreparing "bios" version info using image bootflash:/nxos.7.0.3.I2.1.bin.\n -- SUCCESS\nPerforming module support checks.\n -- SUCCESS\nNotifying services about system upgrade.\n -- SUCCESS\nCompatibility check is done:\nModule  bootable          Impact  Install-type  Reason\n------  --------  --------------  ------------  ------\n     1       yes      disruptive         reset  Reset due to single supervisor\nImages will be upgraded according to following table:\nModule       Image                  Running-Version(pri:alt)           New-Version  Upg-Required\n------  ----------  ----------------------------------------  --------------------  ------------\n     1        nxos                               6.1(2)I3(1)           7.0(3)I2(1)           yes\n     1        bios     v07.15(06/29/2014):v07.06(03/02/2014)    v07.34(08/11/2015)           yes\nSwitch will be reloaded for disruptive upgrade.\nInstall is in progress, please wait.\nPerforming runtime checks.\n -- SUCCESS\nSetting boot variables.\n -- SUCCESS\nPerforming configuration copy.\n -- SUCCESS\nModule 1: Refreshing compact flash and upgrading bios/loader/bootrom.\nWarning: please do not remove or power off the module at this time.\n -- SUCCESS\nFinishing the upgrade, switch will reboot in 10 seconds.\n',
        }

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(["show install all status"], method=u"cli_ascii", timeout=30)

    def test_get_boot_options_kickstart(self):
        def special_send_request(commands, method="cli", timeout=30.0):
            if commands == ["show boot"]:
                return json.load(open(os.path.join(CURRNENT_DIR, "mocks", "send_request_raw", "show_boot_kick.json")))
            elif commands == ["show install all status"]:
                return json.load(
                    open(os.path.join(CURRNENT_DIR, "mocks", "send_request_raw", "show_install_all_status_kick.json"))
                )

        self.send_request.side_effect = special_send_request

        result = self.device.get_boot_options()
        expected = {
            "sys": "n5000-uk9.7.2.1.N1.1.bin",
            "status": "This is the log of last installation.\nContinuing with installation process, please wait.\nThe login will be disabled until the installation is completed.\nPerforming supervisor state verification. \nSUCCESS\nSupervisor non-disruptive upgrade successful.\nInstall has been successful.\n",
            "kick": "n5000-uk9-kickstart.7.2.1.N1.1.bin",
        }

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(["show install all status"], method=u"cli_ascii", timeout=30)

    @mock.patch.object(Device, "show")
    def test_rollback(self, mock_show):
        self.device.rollback("rb_file")
        mock_show.assert_called_with("rollback running-config file rb_file", raw_text=True)

    @mock.patch.object(Device, "show_list")
    def test_checkpoint(self, mock_show_list):
        self.device.checkpoint("cp_file")
        mock_show_list.assert_called_with(["terminal dont-ask", "checkpoint file cp_file"], raw_text=True)

    def test_running_config(self):
        result = self.device.running_config
        expected = '!Command: show running-config\n!Time: Tue Mar 22 21:23:11 2016\nversion 7.0(3)I2(1)\nhostname N9K2\nvdc N9K2 id 1\n  limit-resource vlan minimum 16 maximum 4094\n  limit-resource vrf minimum 2 maximum 4096\n  limit-resource port-channel minimum 0 maximum 511\n  limit-resource u4route-mem minimum 248 maximum 248\n  limit-resource u6route-mem minimum 96 maximum 96\n  limit-resource m4route-mem minimum 58 maximum 58\n  limit-resource m6route-mem minimum 8 maximum 8\nfeature telnet\nfeature nxapi\nfeature bash-shell\nfeature scp-server\nfeature vrrp\nfeature tacacs+\ncfs eth distribute\nfeature pim\nfeature udld\nfeature interface-vlan\nfeature hsrp\nfeature lacp\nfeature dhcp\nfeature vpc\nfeature lldp\nfeature vtp\nonep\n  session key-required enabled\nno password strength-check\nusername admin password 5 $1$6Anve29g$aKsAE8iRKAQzY7sW1qKZh0  role network-admin\nusername cisco password 5 $1$nGd5VWnS$LJ/a9ztNEt6xruMCG2Erl/  role network-admin\nusername jay password 5 $1$K6cIEEfy$vkYaWr5tEdgr55C86b74u/  role network-operator\nusername ntc password 5 $1$0WWXa9uW$EnQSp3nRPD.nIZTqAE//11  role network-admin\nusername netauto password 5 $1$ITxT/Gi0$QbHUtgzTCFt39i4FYSuzl1  role network-admin\nnxapi http port 80\nnxapi https port 443\nbanner motd *\nDISCONNECT FROM DEVICE IMMEDIATELY.\nIF YOU CONTINUE, YOU WILL BE PROSECUTED TO THE FULLEST\nEXTENT OF THE LAW!!!!\n*\nssh login-attempts 10\nip domain-lookup\nip domain-name ntc.com\nip name-server 208.67.222.222\nip host puppet 176.126.88.189\ntacacs-server timeout 10\ntacacs-server deadtime 30\ntacacs-server host 5.6.7.8 \ntacacs-server host 1.2.3.4 key 7 "\\"hello\\"" \nradius-server host 1.2.3.4 authentication accounting \nobject-group ip address OBJECTGROUP-IP\n  10 1.1.1.1/24 \n  20 2.2.2.2/24 \nip access-list INBOUND_MGMT\n  statistics per-entry\n  20 permit tcp 63.118.185.0/24 10.1.100.21/32 eq 22 \n  30 permit icmp any 10.1.100.21/32 \n  40 permit tcp any 10.1.100.21/32 eq 443 \n  50 permit tcp any 10.1.100.21/32 eq www \n  60 permit ip 10.1.100.0/24 10.1.100.21/32 \n  80 permit tcp 89.101.133.0/24 10.1.100.21/32 eq 22 \n  90 permit udp any 10.1.100.21/32 eq snmp \n  100 permit udp any 10.1.100.20/32 eq snmp \n  110 permit tcp 79.52.99.64/32 10.1.100.21/32 eq 22 \n  120 permit tcp 176.126.88.189/32 10.1.100.21/32 eq 22 \nip access-list MYACL\n  10 permit tcp 1.1.1.1/32 eq www any established log \n  20 deny udp 2.1.1.1/20 neq 80 5.5.5.0/24 eq 443 \n  40 remark COMMENT REMARK BY ANSIBLE\n  100 permit ip 10.1.1.1/32 100.1.1.1/24 log \nip access-list ONE\n  15 deny eigrp 1.1.1.1/32 2.2.2.2/32 \n  30 permit tcp any gt smtp any lt 33 urg ack psh rst syn fin established dscp cs7 log \n  40 permit eigrp any any precedence flash fragments time-range RANGE log \n  50 permit udp any range 10 20 any dscp af11 \n  55 permit eigrp any any precedence flash fragments time-range RANGE log \n  65 permit tcp any any precedence routine \n  70 permit tcp any any precedence routine \nip access-list POLICY\n  10 permit 23 any any \nip access-list TWO\n  2 remark this is a test string\n  4 permit eigrp any any \n  10 permit tcp 1.1.1.1/32 eq www any established log \n  20 permit tcp 1.1.1.1/32 any \ntime-range RANGE\ntime-range TEIMER\nvtp domain ntc\nsnmp-server user jay network-operator auth md5 0xe3b9e394dff8a08e8dbfef2c3f9a6564 priv 0xe3b9e394dff8a08e8dbfef2c3f9a6564 localizedkey\nsnmp-server user ntc network-admin auth md5 0x779969ac744909382f0c4bf39275a2c3 priv 0x779969ac744909382f0c4bf39275a2c3 localizedkey\nsnmp-server user netauto network-admin auth md5 0xd85b615bbd22469d476b571844afe9e6 priv 0xd85b615bbd22469d476b571844afe9e6 localizedkey\nrmon event 1 log trap public description FATAL(1) owner PMON@FATAL\nrmon event 2 log trap public description CRITICAL(2) owner PMON@CRITICAL\nrmon event 3 log trap public description ERROR(3) owner PMON@ERROR\nrmon event 4 log trap public description WARNING(4) owner PMON@WARNING\nrmon event 5 log trap public description INFORMATION(5) owner PMON@INFO\nno snmp-server enable traps entity entity_mib_change\nno snmp-server enable traps entity entity_module_status_change\nno snmp-server enable traps entity entity_power_status_change\nno snmp-server enable traps entity entity_module_inserted\nno snmp-server enable traps entity entity_module_removed\nno snmp-server enable traps entity entity_unrecognised_module\nno snmp-server enable traps entity entity_fan_status_change\nno snmp-server enable traps entity entity_power_out_change\nno snmp-server enable traps link linkDown\nno snmp-server enable traps link linkUp\nno snmp-server enable traps link extended-linkDown\nno snmp-server enable traps link extended-linkUp\nno snmp-server enable traps link cieLinkDown\nno snmp-server enable traps link cieLinkUp\nno snmp-server enable traps link delayed-link-state-change\nno snmp-server enable traps rf redundancy_framework\nno snmp-server enable traps license notify-license-expiry\nno snmp-server enable traps license notify-no-license-for-feature\nno snmp-server enable traps license notify-licensefile-missing\nno snmp-server enable traps license notify-license-expiry-warning\nno snmp-server enable traps upgrade UpgradeOpNotifyOnCompletion\nno snmp-server enable traps upgrade UpgradeJobStatusNotify\nno snmp-server enable traps rmon risingAlarm\nno snmp-server enable traps rmon fallingAlarm\nno snmp-server enable traps rmon hcRisingAlarm\nno snmp-server enable traps rmon hcFallingAlarm\nno snmp-server enable traps entity entity_sensor\nno snmp-server enable traps entity cefcMIBEnableStatusNotification\nsnmp-server community networktocode group network-operator\nntp server 33.33.33.33 prefer key 32\nntp server 192.0.2.10 use-vrf ntc\nntp peer 2001:db8::4101\nntp authentication-key 42 md5 qpg 7\nntp trusted-key 42\nntp logging\nntp master 8\naaa authentication login console none \nip route 1.1.1.0/24 2.2.2.2 tag 90 80\nip route 1.1.1.1/32 10.1.10.2\nip route 1.1.1.1/32 10.10.10.1\nip route 1.1.1.1/32 10.10.20.1\nip pim ssm range 232.0.0.0/8\nno ip igmp snooping\nvlan 1-20,30,33,40,100-105,333,400-401\nvlan 2\n  name native\nvlan 10\n  name test_segment\nvlan 20\n  name peer_keepalive\nvlan 30\n  name Puppet\nvlan 33\n  name PuppetAnsible\nvlan 333\n  name webvlan\nvlan 400\n  name db_vlan\nvlan 401\n  name dba_vlan\nservice dhcp\nip dhcp relay\nipv6 dhcp relay\nvrf context TESTING\nvrf context TestVRF\n  shutdown\nvrf context keepalive\nvrf context management\n  ip domain-name ntc.com\n  ip name-server 208.67.222.222\n  ip route 0.0.0.0/0 10.1.100.1\nvrf context test\ninterface Vlan1\n  mtu 1600\ninterface Vlan10\n  no shutdown\n  mtu 1600\n  vrf member ntc\n  hsrp version 2\ninterface Vlan20\n  no shutdown\n  mtu 1600\n  vrf member keepalive\n  ip address 10.1.20.3/24\ninterface Vlan100\n  mtu 1600\n  no ip redirects\n  ip address 20.20.20.2/24\n  ip address 100.100.100.2/24 secondary\ninterface Vlan233\n  mtu 1600\ninterface port-channel11\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface port-channel12\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  spanning-tree port type network\ninterface port-channel100\n  mtu 9216\n  lacp min-links 2\ninterface Ethernet1/1\ninterface Ethernet1/2\ninterface Ethernet1/3\ninterface Ethernet1/4\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface Ethernet1/5\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface Ethernet1/6\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 11 mode active\ninterface Ethernet1/7\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 11 mode active\ninterface Ethernet1/8\ninterface Ethernet1/9\ninterface Ethernet1/10\ninterface Ethernet1/11\ninterface Ethernet1/12\ninterface Ethernet1/13\ninterface Ethernet1/14\ninterface Ethernet1/15\ninterface Ethernet1/16\ninterface Ethernet1/17\ninterface Ethernet1/18\ninterface Ethernet1/19\ninterface Ethernet1/20\ninterface Ethernet1/21\ninterface Ethernet1/22\ninterface Ethernet1/23\ninterface Ethernet1/24\ninterface Ethernet1/25\ninterface Ethernet1/26\ninterface Ethernet1/27\ninterface Ethernet1/28\n  mtu 9216\n  channel-group 100 mode active\ninterface Ethernet1/29\n  mtu 9216\n  channel-group 100 mode active\ninterface Ethernet1/30\n  ip access-group ONE in\ninterface Ethernet1/31\n  ip access-group POLICY out\n  no switchport\n  mtu 1700\ninterface Ethernet1/32\n  no switchport\n  mtu 1600\n  ip pim sparse-mode\n  ip igmp version 2\n  ip igmp startup-query-interval 31\n  ip igmp startup-query-count 2\n  ip igmp static-oif route-map ANOTHER_TEST\n  no shutdown\ninterface Ethernet1/33\n  ip access-group ONE in\n  no switchport\n  mtu 1600\n  ip pim sparse-mode\n  ip igmp static-oif 236.0.0.0\n  ip igmp static-oif 237.0.0.0\n  ip igmp static-oif 238.0.0.0\n  ip igmp static-oif 239.0.0.0 source 1.1.1.1\n  no shutdown\ninterface Ethernet1/34\ninterface Ethernet1/35\ninterface Ethernet1/36\ninterface Ethernet1/37\ninterface Ethernet1/38\ninterface Ethernet1/39\ninterface Ethernet1/40\ninterface Ethernet1/41\ninterface Ethernet1/42\ninterface Ethernet1/43\ninterface Ethernet1/44\ninterface Ethernet1/45\ninterface Ethernet1/46\ninterface Ethernet1/47\ninterface Ethernet1/48\ninterface Ethernet2/1\n  no switchport\n  vrf member ntc\n  ip address 10.1.100.13/24\n  no shutdown\ninterface Ethernet2/2\n  no switchport\n  mtu 1600\n  ip address 10.10.60.1/24\n  no shutdown\ninterface Ethernet2/3\n  no switchport\n  mtu 1600\n  ip address 10.10.70.1/24\n  no shutdown\ninterface Ethernet2/4\n  no switchport\n  mtu 1600\n  ip address 10.10.80.1/24\n  no shutdown\ninterface Ethernet2/5\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 12 mode active\ninterface Ethernet2/6\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 12 mode active\ninterface Ethernet2/7\ninterface Ethernet2/8\ninterface Ethernet2/9\ninterface Ethernet2/10\ninterface Ethernet2/11\n  shutdown\ninterface Ethernet2/12\n  shutdown\ninterface mgmt0\n  description out of band mgmt interface\n  ip access-group INBOUND_MGMT in\n  vrf member management\n  ip address 10.1.100.21/24\ninterface loopback10\n  vrf member ntc\ninterface loopback11\n  vrf member ntc\n  ip address 11.11.11.11/24\ninterface loopback13\n  ip address 13.13.13.13/24\ninterface loopback15\n  vrf member test\ninterface loopback16\ncli alias name puppetoper show puppet agent oper\ncli alias name puppetshow show puppet agent last-exec-log\ncli alias name puppetdump show puppet config\ncli alias name puppetfacter show puppet facter\ncli alias name puppetrun execute puppet agent-oneshot\ncli alias name puppetconfig show run | sec puppet\ncli alias name puppetexecute execute puppet agent-oneshot\nline console\nline vty\n  session-limit 16\n  exec-timeout 0\nboot nxos bootflash:/nxos.7.0.3.I2.1.bin \n'

        self.assertEqual(result, expected)

    def test_backup_running_config(self):
        temp_file = NamedTemporaryFile()
        self.device.backup_running_config(temp_file.name)

        expected = '!Command: show running-config\n!Time: Tue Mar 22 21:23:11 2016\nversion 7.0(3)I2(1)\nhostname N9K2\nvdc N9K2 id 1\n  limit-resource vlan minimum 16 maximum 4094\n  limit-resource vrf minimum 2 maximum 4096\n  limit-resource port-channel minimum 0 maximum 511\n  limit-resource u4route-mem minimum 248 maximum 248\n  limit-resource u6route-mem minimum 96 maximum 96\n  limit-resource m4route-mem minimum 58 maximum 58\n  limit-resource m6route-mem minimum 8 maximum 8\nfeature telnet\nfeature nxapi\nfeature bash-shell\nfeature scp-server\nfeature vrrp\nfeature tacacs+\ncfs eth distribute\nfeature pim\nfeature udld\nfeature interface-vlan\nfeature hsrp\nfeature lacp\nfeature dhcp\nfeature vpc\nfeature lldp\nfeature vtp\nonep\n  session key-required enabled\nno password strength-check\nusername admin password 5 $1$6Anve29g$aKsAE8iRKAQzY7sW1qKZh0  role network-admin\nusername cisco password 5 $1$nGd5VWnS$LJ/a9ztNEt6xruMCG2Erl/  role network-admin\nusername jay password 5 $1$K6cIEEfy$vkYaWr5tEdgr55C86b74u/  role network-operator\nusername ntc password 5 $1$0WWXa9uW$EnQSp3nRPD.nIZTqAE//11  role network-admin\nusername netauto password 5 $1$ITxT/Gi0$QbHUtgzTCFt39i4FYSuzl1  role network-admin\nnxapi http port 80\nnxapi https port 443\nbanner motd *\nDISCONNECT FROM DEVICE IMMEDIATELY.\nIF YOU CONTINUE, YOU WILL BE PROSECUTED TO THE FULLEST\nEXTENT OF THE LAW!!!!\n*\nssh login-attempts 10\nip domain-lookup\nip domain-name ntc.com\nip name-server 208.67.222.222\nip host puppet 176.126.88.189\ntacacs-server timeout 10\ntacacs-server deadtime 30\ntacacs-server host 5.6.7.8 \ntacacs-server host 1.2.3.4 key 7 "\\"hello\\"" \nradius-server host 1.2.3.4 authentication accounting \nobject-group ip address OBJECTGROUP-IP\n  10 1.1.1.1/24 \n  20 2.2.2.2/24 \nip access-list INBOUND_MGMT\n  statistics per-entry\n  20 permit tcp 63.118.185.0/24 10.1.100.21/32 eq 22 \n  30 permit icmp any 10.1.100.21/32 \n  40 permit tcp any 10.1.100.21/32 eq 443 \n  50 permit tcp any 10.1.100.21/32 eq www \n  60 permit ip 10.1.100.0/24 10.1.100.21/32 \n  80 permit tcp 89.101.133.0/24 10.1.100.21/32 eq 22 \n  90 permit udp any 10.1.100.21/32 eq snmp \n  100 permit udp any 10.1.100.20/32 eq snmp \n  110 permit tcp 79.52.99.64/32 10.1.100.21/32 eq 22 \n  120 permit tcp 176.126.88.189/32 10.1.100.21/32 eq 22 \nip access-list MYACL\n  10 permit tcp 1.1.1.1/32 eq www any established log \n  20 deny udp 2.1.1.1/20 neq 80 5.5.5.0/24 eq 443 \n  40 remark COMMENT REMARK BY ANSIBLE\n  100 permit ip 10.1.1.1/32 100.1.1.1/24 log \nip access-list ONE\n  15 deny eigrp 1.1.1.1/32 2.2.2.2/32 \n  30 permit tcp any gt smtp any lt 33 urg ack psh rst syn fin established dscp cs7 log \n  40 permit eigrp any any precedence flash fragments time-range RANGE log \n  50 permit udp any range 10 20 any dscp af11 \n  55 permit eigrp any any precedence flash fragments time-range RANGE log \n  65 permit tcp any any precedence routine \n  70 permit tcp any any precedence routine \nip access-list POLICY\n  10 permit 23 any any \nip access-list TWO\n  2 remark this is a test string\n  4 permit eigrp any any \n  10 permit tcp 1.1.1.1/32 eq www any established log \n  20 permit tcp 1.1.1.1/32 any \ntime-range RANGE\ntime-range TEIMER\nvtp domain ntc\nsnmp-server user jay network-operator auth md5 0xe3b9e394dff8a08e8dbfef2c3f9a6564 priv 0xe3b9e394dff8a08e8dbfef2c3f9a6564 localizedkey\nsnmp-server user ntc network-admin auth md5 0x779969ac744909382f0c4bf39275a2c3 priv 0x779969ac744909382f0c4bf39275a2c3 localizedkey\nsnmp-server user netauto network-admin auth md5 0xd85b615bbd22469d476b571844afe9e6 priv 0xd85b615bbd22469d476b571844afe9e6 localizedkey\nrmon event 1 log trap public description FATAL(1) owner PMON@FATAL\nrmon event 2 log trap public description CRITICAL(2) owner PMON@CRITICAL\nrmon event 3 log trap public description ERROR(3) owner PMON@ERROR\nrmon event 4 log trap public description WARNING(4) owner PMON@WARNING\nrmon event 5 log trap public description INFORMATION(5) owner PMON@INFO\nno snmp-server enable traps entity entity_mib_change\nno snmp-server enable traps entity entity_module_status_change\nno snmp-server enable traps entity entity_power_status_change\nno snmp-server enable traps entity entity_module_inserted\nno snmp-server enable traps entity entity_module_removed\nno snmp-server enable traps entity entity_unrecognised_module\nno snmp-server enable traps entity entity_fan_status_change\nno snmp-server enable traps entity entity_power_out_change\nno snmp-server enable traps link linkDown\nno snmp-server enable traps link linkUp\nno snmp-server enable traps link extended-linkDown\nno snmp-server enable traps link extended-linkUp\nno snmp-server enable traps link cieLinkDown\nno snmp-server enable traps link cieLinkUp\nno snmp-server enable traps link delayed-link-state-change\nno snmp-server enable traps rf redundancy_framework\nno snmp-server enable traps license notify-license-expiry\nno snmp-server enable traps license notify-no-license-for-feature\nno snmp-server enable traps license notify-licensefile-missing\nno snmp-server enable traps license notify-license-expiry-warning\nno snmp-server enable traps upgrade UpgradeOpNotifyOnCompletion\nno snmp-server enable traps upgrade UpgradeJobStatusNotify\nno snmp-server enable traps rmon risingAlarm\nno snmp-server enable traps rmon fallingAlarm\nno snmp-server enable traps rmon hcRisingAlarm\nno snmp-server enable traps rmon hcFallingAlarm\nno snmp-server enable traps entity entity_sensor\nno snmp-server enable traps entity cefcMIBEnableStatusNotification\nsnmp-server community networktocode group network-operator\nntp server 33.33.33.33 prefer key 32\nntp server 192.0.2.10 use-vrf ntc\nntp peer 2001:db8::4101\nntp authentication-key 42 md5 qpg 7\nntp trusted-key 42\nntp logging\nntp master 8\naaa authentication login console none \nip route 1.1.1.0/24 2.2.2.2 tag 90 80\nip route 1.1.1.1/32 10.1.10.2\nip route 1.1.1.1/32 10.10.10.1\nip route 1.1.1.1/32 10.10.20.1\nip pim ssm range 232.0.0.0/8\nno ip igmp snooping\nvlan 1-20,30,33,40,100-105,333,400-401\nvlan 2\n  name native\nvlan 10\n  name test_segment\nvlan 20\n  name peer_keepalive\nvlan 30\n  name Puppet\nvlan 33\n  name PuppetAnsible\nvlan 333\n  name webvlan\nvlan 400\n  name db_vlan\nvlan 401\n  name dba_vlan\nservice dhcp\nip dhcp relay\nipv6 dhcp relay\nvrf context TESTING\nvrf context TestVRF\n  shutdown\nvrf context keepalive\nvrf context management\n  ip domain-name ntc.com\n  ip name-server 208.67.222.222\n  ip route 0.0.0.0/0 10.1.100.1\nvrf context test\ninterface Vlan1\n  mtu 1600\ninterface Vlan10\n  no shutdown\n  mtu 1600\n  vrf member ntc\n  hsrp version 2\ninterface Vlan20\n  no shutdown\n  mtu 1600\n  vrf member keepalive\n  ip address 10.1.20.3/24\ninterface Vlan100\n  mtu 1600\n  no ip redirects\n  ip address 20.20.20.2/24\n  ip address 100.100.100.2/24 secondary\ninterface Vlan233\n  mtu 1600\ninterface port-channel11\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface port-channel12\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  spanning-tree port type network\ninterface port-channel100\n  mtu 9216\n  lacp min-links 2\ninterface Ethernet1/1\ninterface Ethernet1/2\ninterface Ethernet1/3\ninterface Ethernet1/4\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface Ethernet1/5\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface Ethernet1/6\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 11 mode active\ninterface Ethernet1/7\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 11 mode active\ninterface Ethernet1/8\ninterface Ethernet1/9\ninterface Ethernet1/10\ninterface Ethernet1/11\ninterface Ethernet1/12\ninterface Ethernet1/13\ninterface Ethernet1/14\ninterface Ethernet1/15\ninterface Ethernet1/16\ninterface Ethernet1/17\ninterface Ethernet1/18\ninterface Ethernet1/19\ninterface Ethernet1/20\ninterface Ethernet1/21\ninterface Ethernet1/22\ninterface Ethernet1/23\ninterface Ethernet1/24\ninterface Ethernet1/25\ninterface Ethernet1/26\ninterface Ethernet1/27\ninterface Ethernet1/28\n  mtu 9216\n  channel-group 100 mode active\ninterface Ethernet1/29\n  mtu 9216\n  channel-group 100 mode active\ninterface Ethernet1/30\n  ip access-group ONE in\ninterface Ethernet1/31\n  ip access-group POLICY out\n  no switchport\n  mtu 1700\ninterface Ethernet1/32\n  no switchport\n  mtu 1600\n  ip pim sparse-mode\n  ip igmp version 2\n  ip igmp startup-query-interval 31\n  ip igmp startup-query-count 2\n  ip igmp static-oif route-map ANOTHER_TEST\n  no shutdown\ninterface Ethernet1/33\n  ip access-group ONE in\n  no switchport\n  mtu 1600\n  ip pim sparse-mode\n  ip igmp static-oif 236.0.0.0\n  ip igmp static-oif 237.0.0.0\n  ip igmp static-oif 238.0.0.0\n  ip igmp static-oif 239.0.0.0 source 1.1.1.1\n  no shutdown\ninterface Ethernet1/34\ninterface Ethernet1/35\ninterface Ethernet1/36\ninterface Ethernet1/37\ninterface Ethernet1/38\ninterface Ethernet1/39\ninterface Ethernet1/40\ninterface Ethernet1/41\ninterface Ethernet1/42\ninterface Ethernet1/43\ninterface Ethernet1/44\ninterface Ethernet1/45\ninterface Ethernet1/46\ninterface Ethernet1/47\ninterface Ethernet1/48\ninterface Ethernet2/1\n  no switchport\n  vrf member ntc\n  ip address 10.1.100.13/24\n  no shutdown\ninterface Ethernet2/2\n  no switchport\n  mtu 1600\n  ip address 10.10.60.1/24\n  no shutdown\ninterface Ethernet2/3\n  no switchport\n  mtu 1600\n  ip address 10.10.70.1/24\n  no shutdown\ninterface Ethernet2/4\n  no switchport\n  mtu 1600\n  ip address 10.10.80.1/24\n  no shutdown\ninterface Ethernet2/5\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 12 mode active\ninterface Ethernet2/6\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 12 mode active\ninterface Ethernet2/7\ninterface Ethernet2/8\ninterface Ethernet2/9\ninterface Ethernet2/10\ninterface Ethernet2/11\n  shutdown\ninterface Ethernet2/12\n  shutdown\ninterface mgmt0\n  description out of band mgmt interface\n  ip access-group INBOUND_MGMT in\n  vrf member management\n  ip address 10.1.100.21/24\ninterface loopback10\n  vrf member ntc\ninterface loopback11\n  vrf member ntc\n  ip address 11.11.11.11/24\ninterface loopback13\n  ip address 13.13.13.13/24\ninterface loopback15\n  vrf member test\ninterface loopback16\ncli alias name puppetoper show puppet agent oper\ncli alias name puppetshow show puppet agent last-exec-log\ncli alias name puppetdump show puppet config\ncli alias name puppetfacter show puppet facter\ncli alias name puppetrun execute puppet agent-oneshot\ncli alias name puppetconfig show run | sec puppet\ncli alias name puppetexecute execute puppet agent-oneshot\nline console\nline vty\n  session-limit 16\n  exec-timeout 0\nboot nxos bootflash:/nxos.7.0.3.I2.1.bin \n'
        contents = temp_file.read()

        self.assertEqual(contents, expected)

    def test_facts(self):
        self.assertEqual(hasattr(self.device, "_facts"), False)

        expected = {
            "uptime_string": "07:05:47:10",
            "uptime": 625630,
            "vlans": [
                "1",
                "2",
                "3",
                "4",
                "5",
                "6",
                "7",
                "8",
                "9",
                "10",
                "11",
                "12",
                "13",
                "14",
                "15",
                "16",
                "17",
                "18",
                "19",
                "20",
                "30",
                "33",
                "40",
                "100",
                "101",
                "102",
                "103",
                "104",
                "105",
                "333",
                "400",
                "401",
            ],
            u"os_version": "7.0(3)I2(1)",
            u"serial_number": "SAL1819S6BE",
            u"model": "Nexus9000 C9396PX Chassis",
            u"hostname": "N9K2",
            "interfaces": [
                "mgmt0",
                "Ethernet1/1",
                "Ethernet1/2",
                "Ethernet1/3",
                "Ethernet1/4",
                "Ethernet1/5",
                "Ethernet1/6",
                "Ethernet1/7",
                "Ethernet1/8",
                "Ethernet1/9",
                "Ethernet1/10",
                "Ethernet1/11",
                "Ethernet1/12",
                "Ethernet1/13",
                "Ethernet1/14",
                "Ethernet1/15",
                "Ethernet1/16",
                "Ethernet1/17",
                "Ethernet1/18",
                "Ethernet1/19",
                "Ethernet1/20",
                "Ethernet1/21",
                "Ethernet1/22",
                "Ethernet1/23",
                "Ethernet1/24",
                "Ethernet1/25",
                "Ethernet1/26",
                "Ethernet1/27",
                "Ethernet1/28",
                "Ethernet1/29",
                "Ethernet1/30",
                "Ethernet1/31",
                "Ethernet1/32",
                "Ethernet1/33",
                "Ethernet1/34",
                "Ethernet1/35",
                "Ethernet1/36",
                "Ethernet1/37",
                "Ethernet1/38",
                "Ethernet1/39",
                "Ethernet1/40",
                "Ethernet1/41",
                "Ethernet1/42",
                "Ethernet1/43",
                "Ethernet1/44",
                "Ethernet1/45",
                "Ethernet1/46",
                "Ethernet1/47",
                "Ethernet1/48",
                "Ethernet2/1",
                "Ethernet2/2",
                "Ethernet2/3",
                "Ethernet2/4",
                "Ethernet2/5",
                "Ethernet2/6",
                "Ethernet2/7",
                "Ethernet2/8",
                "Ethernet2/9",
                "Ethernet2/10",
                "Ethernet2/11",
                "Ethernet2/12",
                "port-channel11",
                "port-channel12",
                "port-channel100",
                "loopback10",
                "loopback11",
                "loopback13",
                "loopback15",
                "loopback16",
                "Vlan1",
                "Vlan10",
                "Vlan20",
                "Vlan100",
                "Vlan233",
            ],
            "fqdn": "N/A",
        }

        self.assertEqual(self.device.facts, expected)
        self.assertEqual(hasattr(self.device, "_facts"), True)  # caching test
        self.assertEqual(self.device.facts, expected)  # caching test
Exemplo n.º 22
0

def check_nxapi_errors(results, verbose=False):
    """Return True if all commands are None"""
    for entry in results:
        if entry is not None:
            if verbose:
                print entry
            return False
    return True




nexus_ip = "nxos3.twb-tech.com"
nxs = Device(host=nexus_ip, username="******", password="******", transport='https', port=8443)

#nxs_facts = nxs.facts
#pprint (nxs_facts)


def main():
    """Configure BGP using NX-API."""
    # Nexus switches
    # switch_ip = raw_input("Enter switch IP: ")
    # username = '******'
    # password = getpass()
    eth_intf = "Ethernet 2/2"
    intf_ip = '10.1.4.5/30'
    peer_ip = '10.1.4.6'
    as_number = '10'
Exemplo n.º 23
0
#!/usr/bin/env python
from pprint import pprint
from getpass import getpass
from pynxos.device import Device

nexus_ip = "nxos1.twb-tech.com"
nxs_test = Device(host=nexus_ip, username="******", password=getpass(),
                  transport='https', port=8443)

my_facts = nxs_test.facts
pprint(nxs_test.facts)
Exemplo n.º 24
0
class NXOSDevice(BaseDevice):
    """Cisco NXOS Device Implementation."""

    vendor = "cisco"

    def __init__(self,
                 host,
                 username,
                 password,
                 transport="http",
                 timeout=30,
                 port=None,
                 **kwargs):
        super().__init__(host,
                         username,
                         password,
                         device_type="cisco_nxos_nxapi")
        self.transport = transport
        self.timeout = timeout
        self.native = NXOSNative(host,
                                 username,
                                 password,
                                 transport=transport,
                                 timeout=timeout,
                                 port=port)

    def _image_booted(self, image_name, **vendor_specifics):
        version_data = self.show("show version", raw_text=True)
        if re.search(image_name, version_data):
            return True

        return False

    def _wait_for_device_reboot(self, timeout=600):
        start = time.time()
        while time.time() - start < timeout:
            try:
                self.refresh_facts()
                if self.uptime < 180:
                    return
            except:  # noqa E722 # nosec
                pass

        raise RebootTimeoutError(hostname=self.hostname, wait_time=timeout)

    def backup_running_config(self, filename):
        self.native.backup_running_config(filename)

    @property
    def boot_options(self):
        return self.native.get_boot_options()

    def checkpoint(self, filename):
        return self.native.checkpoint(filename)

    def close(self):
        pass

    def config(self, command):
        try:
            self.native.config(command)
        except CLIError as e:
            raise CommandError(command, str(e))

    def config_list(self, commands):
        try:
            self.native.config_list(commands)
        except CLIError as e:
            raise CommandListError(commands, e.command, str(e))

    @property
    def uptime(self):
        if self._uptime is None:
            self._uptime = self.native.facts.get("uptime")

        return self._uptime

    @property
    def hostname(self):
        if self._hostname is None:
            self._hostname = self.native.facts.get("hostname")

        return self._hostname

    @property
    def interfaces(self):
        if self._interfaces is None:
            self._interfaces = self.native.facts.get("interfaces")

        return self._interfaces

    @property
    def vlans(self):
        if self._vlans is None:
            self._vlans = self.native.facts.get("vlans")

        return self._vlans

    @property
    def fqdn(self):
        if self._fqdn is None:
            self._fqdn = self.native.facts.get("fqdn")

        return self._fqdn

    @property
    def model(self):
        if self._model is None:
            self._model = self.native.facts.get("model")

        return self._model

    @property
    def os_version(self):
        if self._os_version is None:
            self._os_version = self.native.facts.get("os_version")

        return self._os_version

    @property
    def serial_number(self):
        if self._serial_number is None:
            self._serial_number = self.native.facts.get("serial_number")

        return self._serial_number

    def file_copy(self, src, dest=None, file_system="bootflash:"):
        if not self.file_copy_remote_exists(src, dest, file_system):
            dest = dest or os.path.basename(src)
            try:
                file_copy = self.native.file_copy(src,
                                                  dest,
                                                  file_system=file_system)
                if not self.file_copy_remote_exists(src, dest, file_system):
                    raise FileTransferError(
                        message=
                        "Attempted file copy, but could not validate file existed after transfer"
                    )
                return file_copy
            except NXOSFileTransferError as e:
                print(str(e))
                raise FileTransferError

    # TODO: Make this an internal method since exposing file_copy should be sufficient
    def file_copy_remote_exists(self,
                                src,
                                dest=None,
                                file_system="bootflash:"):
        dest = dest or os.path.basename(src)
        return self.native.file_copy_remote_exists(src,
                                                   dest,
                                                   file_system=file_system)

    def install_os(self, image_name, **vendor_specifics):
        timeout = vendor_specifics.get("timeout", 3600)
        if not self._image_booted(image_name):
            self.set_boot_options(image_name, **vendor_specifics)
            self._wait_for_device_reboot(timeout=timeout)
            if not self._image_booted(image_name):
                raise OSInstallError(hostname=self.facts.get("hostname"),
                                     desired_boot=image_name)
            self.save()

            return True

        return False

    def open(self):
        pass

    def reboot(self, timer=0, **kwargs):
        """
        Reload the controller or controller pair.

        Args:
            timer (int, optional): The time to wait before reloading. Defaults to 0.

        Raises:
            RebootTimerError: When the device is still unreachable after the timeout period.

        Example:
            >>> device = NXOSDevice(**connection_args)
            >>> device.reboot()
            >>
        """
        if kwargs.get("confirm"):
            warnings.warn("Passing 'confirm' to reboot method is deprecated.",
                          DeprecationWarning)

        if timer != 0:
            raise RebootTimerError(self.device_type)

        self.native.reboot(confirm=True)

    def rollback(self, filename):
        try:
            self.native.rollback(filename)
        except CLIError:
            raise RollbackError("Rollback unsuccessful, %s may not exist." %
                                filename)

    @property
    def running_config(self):
        return self.native.running_config

    def save(self, filename="startup-config"):
        return self.native.save(filename=filename)

    def set_boot_options(self, image_name, kickstart=None, **vendor_specifics):
        file_system = vendor_specifics.get("file_system")
        if file_system is None:
            file_system = "bootflash:"

        file_system_files = self.show("dir {0}".format(file_system),
                                      raw_text=True)
        if re.search(image_name, file_system_files) is None:
            raise NTCFileNotFoundError(hostname=self.hostname,
                                       file=image_name,
                                       dir=file_system)

        if kickstart is not None:
            if re.search(kickstart, file_system_files) is None:
                raise NTCFileNotFoundError(hostname=self.hostname,
                                           file=kickstart,
                                           dir=file_system)

            kickstart = file_system + kickstart

        image_name = file_system + image_name
        self.native.timeout = 300
        upgrade_result = self.native.set_boot_options(image_name,
                                                      kickstart=kickstart)
        self.native.timeout = 30

        return upgrade_result

    def set_timeout(self, timeout):
        self.native.timeout = timeout

    def show(self, command, raw_text=False):
        try:
            return self.native.show(command, raw_text=raw_text)
        except CLIError as e:
            raise CommandError(command, str(e))

    def show_list(self, commands, raw_text=False):
        try:
            return self.native.show_list(commands, raw_text=raw_text)
        except CLIError as e:
            raise CommandListError(commands, e.command, str(e))

    @property
    def startup_config(self):
        return self.show("show startup-config", raw_text=True)
import socket  # Library that will allow for socket timeouts to be coupled with try: except:
import sys  # Library of variables that have strong interaction with the interpreter
import requests  # Main Python library for HTTP and HTTPS interactions
# import pynxos
import time

banner = ('-' * 80)  # Create a banner for use as a section separator

# Turn off SSL warnings
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

nxos1 = Device(host='nxos1.twb-tech.com',
               username='******',
               password='******',
               transport='https',
               port=8443)

nxos2 = Device(host='nxos1.twb-tech.com',
               username='******',
               password='******',
               transport='https',
               port=8443)

raw_route_table = nxos1.show('show ip route vrf management')
pprint(raw_route_table)

print()
print(banner)
print()
Exemplo n.º 26
0
#!/usr/bin/env python
from pprint import pprint
from getpass import getpass
from pynxos.device import Device

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

nexus_ip = "nxos4.twb-tech.com"
nxs_test = Device(host=nexus_ip, username="******", password= '******',
                  transport='https', port=8443)
print 'hello'
my_facts = nxs_test.facts
pprint(nxs_test.facts)

print "show version text:"

output = nxs_test.show("show version")
print output

print 'proc_board_id ' + output['proc_board_id']


Exemplo n.º 27
0
class NXOSDevice(BaseDevice):
    def __init__(self,
                 host,
                 username,
                 password,
                 transport='http',
                 timeout=30,
                 port=None,
                 **kwargs):
        super(NXOSDevice, self).__init__(host,
                                         username,
                                         password,
                                         vendor='cisco',
                                         device_type=NXOS_API_DEVICE_TYPE)
        self.transport = transport
        self.timeout = timeout

        self.native = NXOSNative(host,
                                 username,
                                 password,
                                 transport=transport,
                                 timeout=timeout,
                                 port=port)

    def open(self):
        pass

    def close(self):
        pass

    def set_timeout(self, timeout):
        self.native.timeout = timeout

    def config(self, command):
        try:
            self.native.config(command)
        except CLIError as e:
            raise CommandError(command, str(e))

    def config_list(self, commands):
        try:
            self.native.config_list(commands)
        except CLIError as e:
            raise CommandListError(commands, e.command, str(e))

    def show(self, command, raw_text=False):
        try:
            return strip_unicode(self.native.show(command, raw_text=raw_text))
        except CLIError as e:
            raise CommandError(command, str(e))

    def show_list(self, commands, raw_text=False):
        try:
            return strip_unicode(
                self.native.show_list(commands, raw_text=raw_text))
        except CLIError as e:
            raise CommandListError(commands, e.command, str(e))

    def save(self, filename='startup-config'):
        return self.native.save(filename=filename)

    def file_copy_remote_exists(self,
                                src,
                                dest=None,
                                file_system='bootflash:'):
        dest = dest or os.path.basename(src)
        return self.native.file_copy_remote_exists(src,
                                                   dest,
                                                   file_system=file_system)

    def file_copy(self, src, dest=None, file_system='bootflash:'):
        dest = dest or os.path.basename(src)
        try:
            return self.native.file_copy(src, dest, file_system=file_system)
        except NXOSFileTransferError as e:
            print str(e)
            raise FileTransferError

    def reboot(self, confirm=False, timer=0):
        if timer != 0:
            raise RebootTimerError(self.device_type)

        self.native.reboot(confirm=confirm)

    def get_boot_options(self):
        return self.native.get_boot_options()

    def set_boot_options(self, image_name, kickstart=None, **vendor_specifics):
        return self.native.set_boot_options(image_name, kickstart=kickstart)

    def checkpoint(self, filename):
        return self.native.checkpoint(filename)

    def rollback(self, filename):
        try:
            self.native.rollback(filename)
        except CLIError:
            raise RollbackError('Rollback unsuccessful, %s may not exist.' %
                                filename)

    def backup_running_config(self, filename):
        self.native.backup_running_config(filename)

    @property
    def facts(self):
        if hasattr(self, '_facts'):
            return self._facts

        facts = strip_unicode(self.native.facts)
        facts['vendor'] = self.vendor

        self._facts = facts
        return self._facts

    @property
    def running_config(self):
        return self.native.running_config

    @property
    def startup_config(self):
        return self.show('show startup-config', raw_text=True)
Exemplo n.º 28
0
class TestDevice(unittest.TestCase):
    @mock.patch('pynxos.device.RPCClient')
    def setUp(self, mock_rpc):
        self.device = Device('host', 'user', 'pass')
        self.rpc = mock_rpc
        self.send_request = mock_rpc.return_value.send_request
        self.send_request.side_effect = send_request

    def test_init(self):
        self.assertEqual(self.device.host, 'host')
        self.assertEqual(self.device.username, 'user')
        self.assertEqual(self.device.password, 'pass')
        self.assertEqual(self.device.transport, 'http')
        self.assertEqual(self.device.timeout, 30)

        self.rpc.assert_called_with('host',
                                    'user',
                                    'pass',
                                    transport='http',
                                    port=None)

    def test_show(self):
        result = self.device.show('sh clock')
        expected = {'simple_time': '18:06:31.021 UTC Tue Mar 22 2016\n'}

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(['sh clock'],
                                             method=u'cli',
                                             timeout=30)

    def test_show_empty_response(self):
        self.send_request.return_value = []
        self.send_request.side_effect = None

        result = self.device.show('sh clock')
        expected = {}

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(['sh clock'],
                                             method=u'cli',
                                             timeout=30)

    def test_show_raw_text(self):
        result = self.device.show('sh clock', raw_text=True)
        expected = '18:29:19.583 UTC Tue Mar 22 2016\n'

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(['sh clock'],
                                             method=u'cli_ascii',
                                             timeout=30)

    def test_show_list(self):
        result = self.device.show_list(['sh clock', 'sh hostname'])
        expected = [{
            'simple_time': '18:52:45.084 UTC Tue Mar 22 2016\n'
        }, {
            'hostname': 'N9K2.ntc.com'
        }]

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(['sh clock', 'sh hostname'],
                                             method=u'cli',
                                             timeout=30)

    def test_show_list_raw_text(self):
        result = self.device.show_list(['sh clock', 'sh hostname'],
                                       raw_text=True)
        expected = ['18:55:38.720 UTC Tue Mar 22 2016\n', 'N9K2.ntc.com \n']

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(['sh clock', 'sh hostname'],
                                             method=u'cli_ascii',
                                             timeout=30)

    def test_config(self):
        result = self.device.config('int ethernet 1/1')
        expected = None

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(['int ethernet 1/1'],
                                             method=u'cli',
                                             timeout=30)

    def test_config_list(self):
        result = self.device.config_list(['int ethernet 1/1', 'no shutdown'])
        expected = [None, None]

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(
            ['int ethernet 1/1', 'no shutdown'], method=u'cli', timeout=30)

    def test_save(self):
        result = self.device.save()
        expected = True

        self.assertEqual(result, expected)
        self.send_request.assert_called_with([u'copy run startup-config'],
                                             method=u'cli_ascii',
                                             timeout=30)

    def test_save_error(self):
        result = self.device.save(filename='abc')
        expected = False

        self.assertEqual(result, expected)
        self.send_request.assert_called_with([u'copy run abc'],
                                             method=u'cli_ascii',
                                             timeout=30)

    @mock.patch('pynxos.device.FileCopy')
    def test_file_copy_remote_exists(self, mock_fc):
        mock_fc.return_value.remote_file_exists.return_value = True
        result = self.device.file_copy_remote_exists('source', dest='dest')

        self.assertEqual(result, True)
        mock_fc.assert_called_with(self.device,
                                   'source',
                                   dst='dest',
                                   file_system='bootflash:')

    @mock.patch('pynxos.device.FileCopy')
    def test_file_copy_remote_doesnt_exist(self, mock_fc):
        mock_fc.return_value.remote_file_exists.return_value = False
        result = self.device.file_copy_remote_exists('source', dest='dest')

        self.assertEqual(result, False)
        mock_fc.assert_called_with(self.device,
                                   'source',
                                   dst='dest',
                                   file_system='bootflash:')

    @mock.patch('pynxos.device.FileCopy')
    def test_file_copy(self, mock_fc):
        result = self.device.file_copy('source', dest='dest')

        mock_fc.assert_called_with(self.device,
                                   'source',
                                   dst='dest',
                                   file_system='bootflash:')
        mock_fc.return_value.send.assert_called_with()

    @mock.patch.object(Device, 'show')
    def test_reboot(self, mock_show):
        self.device.reboot(confirm=True)

        mock_show.assert_any_call('terminal dont-ask')
        mock_show.assert_any_call('reload')

    @mock.patch.object(Device, 'show')
    def test_set_boot_options(self, mock_show):
        self.device.set_boot_options('boot.sys')
        mock_show.assert_called_with('install all nxos boot.sys',
                                     raw_text=True)

    @mock.patch.object(Device, 'show')
    def test_set_boot_options_kickstart(self, mock_show):
        self.device.set_boot_options('boot.sys', kickstart='boot.kick')
        mock_show.assert_called_with(
            'install all system boot.sys kickstart boot.kick', raw_text=True)

    def test_get_boot_options(self):
        result = self.device.get_boot_options()
        expected = {
            'sys':
            'nxos.7.0.3.I2.1.bin',
            'status':
            'This is the log of last installation.\nVerifying image bootflash:/nxos.7.0.3.I2.1.bin for boot variable "nxos".\n -- SUCCESS\nVerifying image type.\n -- SUCCESS\nPreparing "nxos" version info using image bootflash:/nxos.7.0.3.I2.1.bin.\n -- SUCCESS\nPreparing "bios" version info using image bootflash:/nxos.7.0.3.I2.1.bin.\n -- SUCCESS\nPerforming module support checks.\n -- SUCCESS\nNotifying services about system upgrade.\n -- SUCCESS\nCompatibility check is done:\nModule  bootable          Impact  Install-type  Reason\n------  --------  --------------  ------------  ------\n     1       yes      disruptive         reset  Reset due to single supervisor\nImages will be upgraded according to following table:\nModule       Image                  Running-Version(pri:alt)           New-Version  Upg-Required\n------  ----------  ----------------------------------------  --------------------  ------------\n     1        nxos                               6.1(2)I3(1)           7.0(3)I2(1)           yes\n     1        bios     v07.15(06/29/2014):v07.06(03/02/2014)    v07.34(08/11/2015)           yes\nSwitch will be reloaded for disruptive upgrade.\nInstall is in progress, please wait.\nPerforming runtime checks.\n -- SUCCESS\nSetting boot variables.\n -- SUCCESS\nPerforming configuration copy.\n -- SUCCESS\nModule 1: Refreshing compact flash and upgrading bios/loader/bootrom.\nWarning: please do not remove or power off the module at this time.\n -- SUCCESS\nFinishing the upgrade, switch will reboot in 10 seconds.\n'
        }

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(['show install all status'],
                                             method=u'cli_ascii',
                                             timeout=30)

    def test_get_boot_options_kickstart(self):
        def special_send_request(commands, method='cli', timeout=30.0):
            if commands == ['show boot']:
                return json.load(
                    open(
                        os.path.join(CURRNENT_DIR, 'mocks', 'send_request_raw',
                                     'show_boot_kick.json')))
            elif commands == ['show install all status']:
                return json.load(
                    open(
                        os.path.join(CURRNENT_DIR, 'mocks', 'send_request_raw',
                                     'show_install_all_status_kick.json')))

        self.send_request.side_effect = special_send_request

        result = self.device.get_boot_options()
        expected = {
            'sys': 'n5000-uk9.7.2.1.N1.1.bin',
            'status':
            'This is the log of last installation.\nContinuing with installation process, please wait.\nThe login will be disabled until the installation is completed.\nPerforming supervisor state verification. \nSUCCESS\nSupervisor non-disruptive upgrade successful.\nInstall has been successful.\n',
            'kick': 'n5000-uk9-kickstart.7.2.1.N1.1.bin'
        }

        self.assertEqual(result, expected)
        self.send_request.assert_called_with(['show install all status'],
                                             method=u'cli_ascii',
                                             timeout=30)

    @mock.patch.object(Device, 'show')
    def test_rollback(self, mock_show):
        self.device.rollback('rb_file')
        mock_show.assert_called_with('rollback running-config file rb_file',
                                     raw_text=True)

    @mock.patch.object(Device, 'show_list')
    def test_checkpoint(self, mock_show_list):
        self.device.checkpoint('cp_file')
        mock_show_list.assert_called_with(
            ['terminal dont-ask', 'checkpoint file cp_file'], raw_text=True)

    def test_running_config(self):
        result = self.device.running_config
        expected = '!Command: show running-config\n!Time: Tue Mar 22 21:23:11 2016\nversion 7.0(3)I2(1)\nhostname N9K2\nvdc N9K2 id 1\n  limit-resource vlan minimum 16 maximum 4094\n  limit-resource vrf minimum 2 maximum 4096\n  limit-resource port-channel minimum 0 maximum 511\n  limit-resource u4route-mem minimum 248 maximum 248\n  limit-resource u6route-mem minimum 96 maximum 96\n  limit-resource m4route-mem minimum 58 maximum 58\n  limit-resource m6route-mem minimum 8 maximum 8\nfeature telnet\nfeature nxapi\nfeature bash-shell\nfeature scp-server\nfeature vrrp\nfeature tacacs+\ncfs eth distribute\nfeature pim\nfeature udld\nfeature interface-vlan\nfeature hsrp\nfeature lacp\nfeature dhcp\nfeature vpc\nfeature lldp\nfeature vtp\nonep\n  session key-required enabled\nno password strength-check\nusername admin password 5 $1$6Anve29g$aKsAE8iRKAQzY7sW1qKZh0  role network-admin\nusername cisco password 5 $1$nGd5VWnS$LJ/a9ztNEt6xruMCG2Erl/  role network-admin\nusername jay password 5 $1$K6cIEEfy$vkYaWr5tEdgr55C86b74u/  role network-operator\nusername ntc password 5 $1$0WWXa9uW$EnQSp3nRPD.nIZTqAE//11  role network-admin\nusername netauto password 5 $1$ITxT/Gi0$QbHUtgzTCFt39i4FYSuzl1  role network-admin\nnxapi http port 80\nnxapi https port 443\nbanner motd *\nDISCONNECT FROM DEVICE IMMEDIATELY.\nIF YOU CONTINUE, YOU WILL BE PROSECUTED TO THE FULLEST\nEXTENT OF THE LAW!!!!\n*\nssh login-attempts 10\nip domain-lookup\nip domain-name ntc.com\nip name-server 208.67.222.222\nip host puppet 176.126.88.189\ntacacs-server timeout 10\ntacacs-server deadtime 30\ntacacs-server host 5.6.7.8 \ntacacs-server host 1.2.3.4 key 7 "\\"hello\\"" \nradius-server host 1.2.3.4 authentication accounting \nobject-group ip address OBJECTGROUP-IP\n  10 1.1.1.1/24 \n  20 2.2.2.2/24 \nip access-list INBOUND_MGMT\n  statistics per-entry\n  20 permit tcp 63.118.185.0/24 10.1.100.21/32 eq 22 \n  30 permit icmp any 10.1.100.21/32 \n  40 permit tcp any 10.1.100.21/32 eq 443 \n  50 permit tcp any 10.1.100.21/32 eq www \n  60 permit ip 10.1.100.0/24 10.1.100.21/32 \n  80 permit tcp 89.101.133.0/24 10.1.100.21/32 eq 22 \n  90 permit udp any 10.1.100.21/32 eq snmp \n  100 permit udp any 10.1.100.20/32 eq snmp \n  110 permit tcp 79.52.99.64/32 10.1.100.21/32 eq 22 \n  120 permit tcp 176.126.88.189/32 10.1.100.21/32 eq 22 \nip access-list MYACL\n  10 permit tcp 1.1.1.1/32 eq www any established log \n  20 deny udp 2.1.1.1/20 neq 80 5.5.5.0/24 eq 443 \n  40 remark COMMENT REMARK BY ANSIBLE\n  100 permit ip 10.1.1.1/32 100.1.1.1/24 log \nip access-list ONE\n  15 deny eigrp 1.1.1.1/32 2.2.2.2/32 \n  30 permit tcp any gt smtp any lt 33 urg ack psh rst syn fin established dscp cs7 log \n  40 permit eigrp any any precedence flash fragments time-range RANGE log \n  50 permit udp any range 10 20 any dscp af11 \n  55 permit eigrp any any precedence flash fragments time-range RANGE log \n  65 permit tcp any any precedence routine \n  70 permit tcp any any precedence routine \nip access-list POLICY\n  10 permit 23 any any \nip access-list TWO\n  2 remark this is a test string\n  4 permit eigrp any any \n  10 permit tcp 1.1.1.1/32 eq www any established log \n  20 permit tcp 1.1.1.1/32 any \ntime-range RANGE\ntime-range TEIMER\nvtp domain ntc\nsnmp-server user jay network-operator auth md5 0xe3b9e394dff8a08e8dbfef2c3f9a6564 priv 0xe3b9e394dff8a08e8dbfef2c3f9a6564 localizedkey\nsnmp-server user ntc network-admin auth md5 0x779969ac744909382f0c4bf39275a2c3 priv 0x779969ac744909382f0c4bf39275a2c3 localizedkey\nsnmp-server user netauto network-admin auth md5 0xd85b615bbd22469d476b571844afe9e6 priv 0xd85b615bbd22469d476b571844afe9e6 localizedkey\nrmon event 1 log trap public description FATAL(1) owner PMON@FATAL\nrmon event 2 log trap public description CRITICAL(2) owner PMON@CRITICAL\nrmon event 3 log trap public description ERROR(3) owner PMON@ERROR\nrmon event 4 log trap public description WARNING(4) owner PMON@WARNING\nrmon event 5 log trap public description INFORMATION(5) owner PMON@INFO\nno snmp-server enable traps entity entity_mib_change\nno snmp-server enable traps entity entity_module_status_change\nno snmp-server enable traps entity entity_power_status_change\nno snmp-server enable traps entity entity_module_inserted\nno snmp-server enable traps entity entity_module_removed\nno snmp-server enable traps entity entity_unrecognised_module\nno snmp-server enable traps entity entity_fan_status_change\nno snmp-server enable traps entity entity_power_out_change\nno snmp-server enable traps link linkDown\nno snmp-server enable traps link linkUp\nno snmp-server enable traps link extended-linkDown\nno snmp-server enable traps link extended-linkUp\nno snmp-server enable traps link cieLinkDown\nno snmp-server enable traps link cieLinkUp\nno snmp-server enable traps link delayed-link-state-change\nno snmp-server enable traps rf redundancy_framework\nno snmp-server enable traps license notify-license-expiry\nno snmp-server enable traps license notify-no-license-for-feature\nno snmp-server enable traps license notify-licensefile-missing\nno snmp-server enable traps license notify-license-expiry-warning\nno snmp-server enable traps upgrade UpgradeOpNotifyOnCompletion\nno snmp-server enable traps upgrade UpgradeJobStatusNotify\nno snmp-server enable traps rmon risingAlarm\nno snmp-server enable traps rmon fallingAlarm\nno snmp-server enable traps rmon hcRisingAlarm\nno snmp-server enable traps rmon hcFallingAlarm\nno snmp-server enable traps entity entity_sensor\nno snmp-server enable traps entity cefcMIBEnableStatusNotification\nsnmp-server community networktocode group network-operator\nntp server 33.33.33.33 prefer key 32\nntp server 192.0.2.10 use-vrf ntc\nntp peer 2001:db8::4101\nntp authentication-key 42 md5 qpg 7\nntp trusted-key 42\nntp logging\nntp master 8\naaa authentication login console none \nip route 1.1.1.0/24 2.2.2.2 tag 90 80\nip route 1.1.1.1/32 10.1.10.2\nip route 1.1.1.1/32 10.10.10.1\nip route 1.1.1.1/32 10.10.20.1\nip pim ssm range 232.0.0.0/8\nno ip igmp snooping\nvlan 1-20,30,33,40,100-105,333,400-401\nvlan 2\n  name native\nvlan 10\n  name test_segment\nvlan 20\n  name peer_keepalive\nvlan 30\n  name Puppet\nvlan 33\n  name PuppetAnsible\nvlan 333\n  name webvlan\nvlan 400\n  name db_vlan\nvlan 401\n  name dba_vlan\nservice dhcp\nip dhcp relay\nipv6 dhcp relay\nvrf context TESTING\nvrf context TestVRF\n  shutdown\nvrf context keepalive\nvrf context management\n  ip domain-name ntc.com\n  ip name-server 208.67.222.222\n  ip route 0.0.0.0/0 10.1.100.1\nvrf context test\ninterface Vlan1\n  mtu 1600\ninterface Vlan10\n  no shutdown\n  mtu 1600\n  vrf member ntc\n  hsrp version 2\ninterface Vlan20\n  no shutdown\n  mtu 1600\n  vrf member keepalive\n  ip address 10.1.20.3/24\ninterface Vlan100\n  mtu 1600\n  no ip redirects\n  ip address 20.20.20.2/24\n  ip address 100.100.100.2/24 secondary\ninterface Vlan233\n  mtu 1600\ninterface port-channel11\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface port-channel12\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  spanning-tree port type network\ninterface port-channel100\n  mtu 9216\n  lacp min-links 2\ninterface Ethernet1/1\ninterface Ethernet1/2\ninterface Ethernet1/3\ninterface Ethernet1/4\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface Ethernet1/5\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface Ethernet1/6\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 11 mode active\ninterface Ethernet1/7\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 11 mode active\ninterface Ethernet1/8\ninterface Ethernet1/9\ninterface Ethernet1/10\ninterface Ethernet1/11\ninterface Ethernet1/12\ninterface Ethernet1/13\ninterface Ethernet1/14\ninterface Ethernet1/15\ninterface Ethernet1/16\ninterface Ethernet1/17\ninterface Ethernet1/18\ninterface Ethernet1/19\ninterface Ethernet1/20\ninterface Ethernet1/21\ninterface Ethernet1/22\ninterface Ethernet1/23\ninterface Ethernet1/24\ninterface Ethernet1/25\ninterface Ethernet1/26\ninterface Ethernet1/27\ninterface Ethernet1/28\n  mtu 9216\n  channel-group 100 mode active\ninterface Ethernet1/29\n  mtu 9216\n  channel-group 100 mode active\ninterface Ethernet1/30\n  ip access-group ONE in\ninterface Ethernet1/31\n  ip access-group POLICY out\n  no switchport\n  mtu 1700\ninterface Ethernet1/32\n  no switchport\n  mtu 1600\n  ip pim sparse-mode\n  ip igmp version 2\n  ip igmp startup-query-interval 31\n  ip igmp startup-query-count 2\n  ip igmp static-oif route-map ANOTHER_TEST\n  no shutdown\ninterface Ethernet1/33\n  ip access-group ONE in\n  no switchport\n  mtu 1600\n  ip pim sparse-mode\n  ip igmp static-oif 236.0.0.0\n  ip igmp static-oif 237.0.0.0\n  ip igmp static-oif 238.0.0.0\n  ip igmp static-oif 239.0.0.0 source 1.1.1.1\n  no shutdown\ninterface Ethernet1/34\ninterface Ethernet1/35\ninterface Ethernet1/36\ninterface Ethernet1/37\ninterface Ethernet1/38\ninterface Ethernet1/39\ninterface Ethernet1/40\ninterface Ethernet1/41\ninterface Ethernet1/42\ninterface Ethernet1/43\ninterface Ethernet1/44\ninterface Ethernet1/45\ninterface Ethernet1/46\ninterface Ethernet1/47\ninterface Ethernet1/48\ninterface Ethernet2/1\n  no switchport\n  vrf member ntc\n  ip address 10.1.100.13/24\n  no shutdown\ninterface Ethernet2/2\n  no switchport\n  mtu 1600\n  ip address 10.10.60.1/24\n  no shutdown\ninterface Ethernet2/3\n  no switchport\n  mtu 1600\n  ip address 10.10.70.1/24\n  no shutdown\ninterface Ethernet2/4\n  no switchport\n  mtu 1600\n  ip address 10.10.80.1/24\n  no shutdown\ninterface Ethernet2/5\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 12 mode active\ninterface Ethernet2/6\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 12 mode active\ninterface Ethernet2/7\ninterface Ethernet2/8\ninterface Ethernet2/9\ninterface Ethernet2/10\ninterface Ethernet2/11\n  shutdown\ninterface Ethernet2/12\n  shutdown\ninterface mgmt0\n  description out of band mgmt interface\n  ip access-group INBOUND_MGMT in\n  vrf member management\n  ip address 10.1.100.21/24\ninterface loopback10\n  vrf member ntc\ninterface loopback11\n  vrf member ntc\n  ip address 11.11.11.11/24\ninterface loopback13\n  ip address 13.13.13.13/24\ninterface loopback15\n  vrf member test\ninterface loopback16\ncli alias name puppetoper show puppet agent oper\ncli alias name puppetshow show puppet agent last-exec-log\ncli alias name puppetdump show puppet config\ncli alias name puppetfacter show puppet facter\ncli alias name puppetrun execute puppet agent-oneshot\ncli alias name puppetconfig show run | sec puppet\ncli alias name puppetexecute execute puppet agent-oneshot\nline console\nline vty\n  session-limit 16\n  exec-timeout 0\nboot nxos bootflash:/nxos.7.0.3.I2.1.bin \n'

        self.assertEqual(result, expected)

    def test_backup_running_config(self):
        temp_file = NamedTemporaryFile()
        self.device.backup_running_config(temp_file.name)

        expected = '!Command: show running-config\n!Time: Tue Mar 22 21:23:11 2016\nversion 7.0(3)I2(1)\nhostname N9K2\nvdc N9K2 id 1\n  limit-resource vlan minimum 16 maximum 4094\n  limit-resource vrf minimum 2 maximum 4096\n  limit-resource port-channel minimum 0 maximum 511\n  limit-resource u4route-mem minimum 248 maximum 248\n  limit-resource u6route-mem minimum 96 maximum 96\n  limit-resource m4route-mem minimum 58 maximum 58\n  limit-resource m6route-mem minimum 8 maximum 8\nfeature telnet\nfeature nxapi\nfeature bash-shell\nfeature scp-server\nfeature vrrp\nfeature tacacs+\ncfs eth distribute\nfeature pim\nfeature udld\nfeature interface-vlan\nfeature hsrp\nfeature lacp\nfeature dhcp\nfeature vpc\nfeature lldp\nfeature vtp\nonep\n  session key-required enabled\nno password strength-check\nusername admin password 5 $1$6Anve29g$aKsAE8iRKAQzY7sW1qKZh0  role network-admin\nusername cisco password 5 $1$nGd5VWnS$LJ/a9ztNEt6xruMCG2Erl/  role network-admin\nusername jay password 5 $1$K6cIEEfy$vkYaWr5tEdgr55C86b74u/  role network-operator\nusername ntc password 5 $1$0WWXa9uW$EnQSp3nRPD.nIZTqAE//11  role network-admin\nusername netauto password 5 $1$ITxT/Gi0$QbHUtgzTCFt39i4FYSuzl1  role network-admin\nnxapi http port 80\nnxapi https port 443\nbanner motd *\nDISCONNECT FROM DEVICE IMMEDIATELY.\nIF YOU CONTINUE, YOU WILL BE PROSECUTED TO THE FULLEST\nEXTENT OF THE LAW!!!!\n*\nssh login-attempts 10\nip domain-lookup\nip domain-name ntc.com\nip name-server 208.67.222.222\nip host puppet 176.126.88.189\ntacacs-server timeout 10\ntacacs-server deadtime 30\ntacacs-server host 5.6.7.8 \ntacacs-server host 1.2.3.4 key 7 "\\"hello\\"" \nradius-server host 1.2.3.4 authentication accounting \nobject-group ip address OBJECTGROUP-IP\n  10 1.1.1.1/24 \n  20 2.2.2.2/24 \nip access-list INBOUND_MGMT\n  statistics per-entry\n  20 permit tcp 63.118.185.0/24 10.1.100.21/32 eq 22 \n  30 permit icmp any 10.1.100.21/32 \n  40 permit tcp any 10.1.100.21/32 eq 443 \n  50 permit tcp any 10.1.100.21/32 eq www \n  60 permit ip 10.1.100.0/24 10.1.100.21/32 \n  80 permit tcp 89.101.133.0/24 10.1.100.21/32 eq 22 \n  90 permit udp any 10.1.100.21/32 eq snmp \n  100 permit udp any 10.1.100.20/32 eq snmp \n  110 permit tcp 79.52.99.64/32 10.1.100.21/32 eq 22 \n  120 permit tcp 176.126.88.189/32 10.1.100.21/32 eq 22 \nip access-list MYACL\n  10 permit tcp 1.1.1.1/32 eq www any established log \n  20 deny udp 2.1.1.1/20 neq 80 5.5.5.0/24 eq 443 \n  40 remark COMMENT REMARK BY ANSIBLE\n  100 permit ip 10.1.1.1/32 100.1.1.1/24 log \nip access-list ONE\n  15 deny eigrp 1.1.1.1/32 2.2.2.2/32 \n  30 permit tcp any gt smtp any lt 33 urg ack psh rst syn fin established dscp cs7 log \n  40 permit eigrp any any precedence flash fragments time-range RANGE log \n  50 permit udp any range 10 20 any dscp af11 \n  55 permit eigrp any any precedence flash fragments time-range RANGE log \n  65 permit tcp any any precedence routine \n  70 permit tcp any any precedence routine \nip access-list POLICY\n  10 permit 23 any any \nip access-list TWO\n  2 remark this is a test string\n  4 permit eigrp any any \n  10 permit tcp 1.1.1.1/32 eq www any established log \n  20 permit tcp 1.1.1.1/32 any \ntime-range RANGE\ntime-range TEIMER\nvtp domain ntc\nsnmp-server user jay network-operator auth md5 0xe3b9e394dff8a08e8dbfef2c3f9a6564 priv 0xe3b9e394dff8a08e8dbfef2c3f9a6564 localizedkey\nsnmp-server user ntc network-admin auth md5 0x779969ac744909382f0c4bf39275a2c3 priv 0x779969ac744909382f0c4bf39275a2c3 localizedkey\nsnmp-server user netauto network-admin auth md5 0xd85b615bbd22469d476b571844afe9e6 priv 0xd85b615bbd22469d476b571844afe9e6 localizedkey\nrmon event 1 log trap public description FATAL(1) owner PMON@FATAL\nrmon event 2 log trap public description CRITICAL(2) owner PMON@CRITICAL\nrmon event 3 log trap public description ERROR(3) owner PMON@ERROR\nrmon event 4 log trap public description WARNING(4) owner PMON@WARNING\nrmon event 5 log trap public description INFORMATION(5) owner PMON@INFO\nno snmp-server enable traps entity entity_mib_change\nno snmp-server enable traps entity entity_module_status_change\nno snmp-server enable traps entity entity_power_status_change\nno snmp-server enable traps entity entity_module_inserted\nno snmp-server enable traps entity entity_module_removed\nno snmp-server enable traps entity entity_unrecognised_module\nno snmp-server enable traps entity entity_fan_status_change\nno snmp-server enable traps entity entity_power_out_change\nno snmp-server enable traps link linkDown\nno snmp-server enable traps link linkUp\nno snmp-server enable traps link extended-linkDown\nno snmp-server enable traps link extended-linkUp\nno snmp-server enable traps link cieLinkDown\nno snmp-server enable traps link cieLinkUp\nno snmp-server enable traps link delayed-link-state-change\nno snmp-server enable traps rf redundancy_framework\nno snmp-server enable traps license notify-license-expiry\nno snmp-server enable traps license notify-no-license-for-feature\nno snmp-server enable traps license notify-licensefile-missing\nno snmp-server enable traps license notify-license-expiry-warning\nno snmp-server enable traps upgrade UpgradeOpNotifyOnCompletion\nno snmp-server enable traps upgrade UpgradeJobStatusNotify\nno snmp-server enable traps rmon risingAlarm\nno snmp-server enable traps rmon fallingAlarm\nno snmp-server enable traps rmon hcRisingAlarm\nno snmp-server enable traps rmon hcFallingAlarm\nno snmp-server enable traps entity entity_sensor\nno snmp-server enable traps entity cefcMIBEnableStatusNotification\nsnmp-server community networktocode group network-operator\nntp server 33.33.33.33 prefer key 32\nntp server 192.0.2.10 use-vrf ntc\nntp peer 2001:db8::4101\nntp authentication-key 42 md5 qpg 7\nntp trusted-key 42\nntp logging\nntp master 8\naaa authentication login console none \nip route 1.1.1.0/24 2.2.2.2 tag 90 80\nip route 1.1.1.1/32 10.1.10.2\nip route 1.1.1.1/32 10.10.10.1\nip route 1.1.1.1/32 10.10.20.1\nip pim ssm range 232.0.0.0/8\nno ip igmp snooping\nvlan 1-20,30,33,40,100-105,333,400-401\nvlan 2\n  name native\nvlan 10\n  name test_segment\nvlan 20\n  name peer_keepalive\nvlan 30\n  name Puppet\nvlan 33\n  name PuppetAnsible\nvlan 333\n  name webvlan\nvlan 400\n  name db_vlan\nvlan 401\n  name dba_vlan\nservice dhcp\nip dhcp relay\nipv6 dhcp relay\nvrf context TESTING\nvrf context TestVRF\n  shutdown\nvrf context keepalive\nvrf context management\n  ip domain-name ntc.com\n  ip name-server 208.67.222.222\n  ip route 0.0.0.0/0 10.1.100.1\nvrf context test\ninterface Vlan1\n  mtu 1600\ninterface Vlan10\n  no shutdown\n  mtu 1600\n  vrf member ntc\n  hsrp version 2\ninterface Vlan20\n  no shutdown\n  mtu 1600\n  vrf member keepalive\n  ip address 10.1.20.3/24\ninterface Vlan100\n  mtu 1600\n  no ip redirects\n  ip address 20.20.20.2/24\n  ip address 100.100.100.2/24 secondary\ninterface Vlan233\n  mtu 1600\ninterface port-channel11\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface port-channel12\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  spanning-tree port type network\ninterface port-channel100\n  mtu 9216\n  lacp min-links 2\ninterface Ethernet1/1\ninterface Ethernet1/2\ninterface Ethernet1/3\ninterface Ethernet1/4\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface Ethernet1/5\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\ninterface Ethernet1/6\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 11 mode active\ninterface Ethernet1/7\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 11 mode active\ninterface Ethernet1/8\ninterface Ethernet1/9\ninterface Ethernet1/10\ninterface Ethernet1/11\ninterface Ethernet1/12\ninterface Ethernet1/13\ninterface Ethernet1/14\ninterface Ethernet1/15\ninterface Ethernet1/16\ninterface Ethernet1/17\ninterface Ethernet1/18\ninterface Ethernet1/19\ninterface Ethernet1/20\ninterface Ethernet1/21\ninterface Ethernet1/22\ninterface Ethernet1/23\ninterface Ethernet1/24\ninterface Ethernet1/25\ninterface Ethernet1/26\ninterface Ethernet1/27\ninterface Ethernet1/28\n  mtu 9216\n  channel-group 100 mode active\ninterface Ethernet1/29\n  mtu 9216\n  channel-group 100 mode active\ninterface Ethernet1/30\n  ip access-group ONE in\ninterface Ethernet1/31\n  ip access-group POLICY out\n  no switchport\n  mtu 1700\ninterface Ethernet1/32\n  no switchport\n  mtu 1600\n  ip pim sparse-mode\n  ip igmp version 2\n  ip igmp startup-query-interval 31\n  ip igmp startup-query-count 2\n  ip igmp static-oif route-map ANOTHER_TEST\n  no shutdown\ninterface Ethernet1/33\n  ip access-group ONE in\n  no switchport\n  mtu 1600\n  ip pim sparse-mode\n  ip igmp static-oif 236.0.0.0\n  ip igmp static-oif 237.0.0.0\n  ip igmp static-oif 238.0.0.0\n  ip igmp static-oif 239.0.0.0 source 1.1.1.1\n  no shutdown\ninterface Ethernet1/34\ninterface Ethernet1/35\ninterface Ethernet1/36\ninterface Ethernet1/37\ninterface Ethernet1/38\ninterface Ethernet1/39\ninterface Ethernet1/40\ninterface Ethernet1/41\ninterface Ethernet1/42\ninterface Ethernet1/43\ninterface Ethernet1/44\ninterface Ethernet1/45\ninterface Ethernet1/46\ninterface Ethernet1/47\ninterface Ethernet1/48\ninterface Ethernet2/1\n  no switchport\n  vrf member ntc\n  ip address 10.1.100.13/24\n  no shutdown\ninterface Ethernet2/2\n  no switchport\n  mtu 1600\n  ip address 10.10.60.1/24\n  no shutdown\ninterface Ethernet2/3\n  no switchport\n  mtu 1600\n  ip address 10.10.70.1/24\n  no shutdown\ninterface Ethernet2/4\n  no switchport\n  mtu 1600\n  ip address 10.10.80.1/24\n  no shutdown\ninterface Ethernet2/5\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 12 mode active\ninterface Ethernet2/6\n  switchport mode trunk\n  switchport trunk native vlan 2\n  switchport trunk allowed vlan 2-20\n  channel-group 12 mode active\ninterface Ethernet2/7\ninterface Ethernet2/8\ninterface Ethernet2/9\ninterface Ethernet2/10\ninterface Ethernet2/11\n  shutdown\ninterface Ethernet2/12\n  shutdown\ninterface mgmt0\n  description out of band mgmt interface\n  ip access-group INBOUND_MGMT in\n  vrf member management\n  ip address 10.1.100.21/24\ninterface loopback10\n  vrf member ntc\ninterface loopback11\n  vrf member ntc\n  ip address 11.11.11.11/24\ninterface loopback13\n  ip address 13.13.13.13/24\ninterface loopback15\n  vrf member test\ninterface loopback16\ncli alias name puppetoper show puppet agent oper\ncli alias name puppetshow show puppet agent last-exec-log\ncli alias name puppetdump show puppet config\ncli alias name puppetfacter show puppet facter\ncli alias name puppetrun execute puppet agent-oneshot\ncli alias name puppetconfig show run | sec puppet\ncli alias name puppetexecute execute puppet agent-oneshot\nline console\nline vty\n  session-limit 16\n  exec-timeout 0\nboot nxos bootflash:/nxos.7.0.3.I2.1.bin \n'
        contents = temp_file.read()

        self.assertEqual(contents, expected)

    def test_facts(self):
        self.assertEqual(hasattr(self.device, '_facts'), False)

        expected = {
            'uptime_string':
            '07:05:47:10',
            'uptime':
            625630,
            'vlans': [
                '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12',
                '13', '14', '15', '16', '17', '18', '19', '20', '30', '33',
                '40', '100', '101', '102', '103', '104', '105', '333', '400',
                '401'
            ],
            u'os_version':
            '7.0(3)I2(1)',
            u'serial_number':
            'SAL1819S6BE',
            u'model':
            'Nexus9000 C9396PX Chassis',
            u'hostname':
            'N9K2',
            'interfaces': [
                'mgmt0', 'Ethernet1/1', 'Ethernet1/2', 'Ethernet1/3',
                'Ethernet1/4', 'Ethernet1/5', 'Ethernet1/6', 'Ethernet1/7',
                'Ethernet1/8', 'Ethernet1/9', 'Ethernet1/10', 'Ethernet1/11',
                'Ethernet1/12', 'Ethernet1/13', 'Ethernet1/14', 'Ethernet1/15',
                'Ethernet1/16', 'Ethernet1/17', 'Ethernet1/18', 'Ethernet1/19',
                'Ethernet1/20', 'Ethernet1/21', 'Ethernet1/22', 'Ethernet1/23',
                'Ethernet1/24', 'Ethernet1/25', 'Ethernet1/26', 'Ethernet1/27',
                'Ethernet1/28', 'Ethernet1/29', 'Ethernet1/30', 'Ethernet1/31',
                'Ethernet1/32', 'Ethernet1/33', 'Ethernet1/34', 'Ethernet1/35',
                'Ethernet1/36', 'Ethernet1/37', 'Ethernet1/38', 'Ethernet1/39',
                'Ethernet1/40', 'Ethernet1/41', 'Ethernet1/42', 'Ethernet1/43',
                'Ethernet1/44', 'Ethernet1/45', 'Ethernet1/46', 'Ethernet1/47',
                'Ethernet1/48', 'Ethernet2/1', 'Ethernet2/2', 'Ethernet2/3',
                'Ethernet2/4', 'Ethernet2/5', 'Ethernet2/6', 'Ethernet2/7',
                'Ethernet2/8', 'Ethernet2/9', 'Ethernet2/10', 'Ethernet2/11',
                'Ethernet2/12', 'port-channel11', 'port-channel12',
                'port-channel100', 'loopback10', 'loopback11', 'loopback13',
                'loopback15', 'loopback16', 'Vlan1', 'Vlan10', 'Vlan20',
                'Vlan100', 'Vlan233'
            ],
            'fqdn':
            'N/A'
        }

        self.assertEqual(self.device.facts, expected)
        self.assertEqual(hasattr(self.device, '_facts'), True)  # caching test
        self.assertEqual(self.device.facts, expected)  # caching test
Exemplo n.º 29
0
interface = 'Eth 2/4'
ip_address2 = ['192.168.5.1/24', '192.168.5.2/24']

nexus3_dict = {
    'hostname': nexus3_ip,
    'ip': '192.168.5.1/24',
    'peer_ip': '192.168.5.2'
}
nexus4_dict = {
    'hostname': nexus4_ip,
    'ip': '192.168.5.2/24',
    'peer_ip': '192.168.5.1'
}

i = 0
for switch in [nexus3_dict, nexus4_dict]:
    nxs_switch = Device(host=switch['hostname'],
                        username="******",
                        password='******',
                        transport='https',
                        port=8443)
    config_int_txt = 'interface ' + interface
    config_ip_txt = 'ip address ' + switch['ip']
    config_bgp_txt = [
        'router bgp 10', 'neighbor {} remote-as 10'.format(switch['peer_ip']),
        'address-family ipv4 unicast'
    ]
    config_list = [config_int_txt, config_ip_txt] + config_bgp_txt
    config_interface = nxs_switch.config_list(config_list)
Exemplo n.º 30
0
 def setUp(self, mock_rpc):
     self.device = Device('host', 'user', 'pass')
     self.rpc = mock_rpc
     self.send_request = mock_rpc.return_value.send_request
     self.send_request.side_effect = send_request
Exemplo n.º 31
0
import socket  # Library that will allow for socket timeouts to be coupled with try: except:
import sys  # Library of variables that have strong interaction with the interpreter
import requests  # Main Python library for HTTP and HTTPS interactions
# import pynxos
import time

banner = ('-' * 80)  # Create a banner for use as a section separator

# Turn off SSL warnings
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

nxos1 = Device(host='nxos1.twb-tech.com',
               username='******',
               password='******',
               transport='https',
               port=8443)

nxos2 = Device(host='nxos1.twb-tech.com',
               username='******',
               password='******',
               transport='https',
               port=8443)

device_list = [nxos1, nxos2]

for host in device_list:
    print()
    print(host.show('show hostname'))
Exemplo n.º 32
0
#!/usr/bin/env python
from __future__ import unicode_literals, print_function
from pynxos.device import Device
from getpass import getpass
from pprint import pprint as pp

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

nxos1 = Device(host='nxos1.twb-tech.com',
               username='******',
               password=getpass(),
               transport='https',
               port='8443')

nxos2 = Device(host='nxos2.twb-tech.com',
               username='******',
               password=getpass(),
               transport='https',
               port='8443')

print(nxos1.show('show hostname'))
print(nxos2.show('show hostname'))


Exemplo n.º 33
0
#!/usr/bin/env python
from __future__ import unicode_literals, print_function
from pynxos.device import Device
from getpass import getpass
from pprint import pprint as pp

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

nxos1 = Device(host='nxos1.twb-tech.com',
               username='******',
               password=getpass(),
               transport='https',
               port='8443')

#nxos2 = Device(host='nxos2.twb-tech.com',
#               username='******',
#               password=getpass(),
#               transport='https',
#               port='8443')

print(nxos1.show('show hostname'))

commands = [
    'interface Loopback68',
    'ip address 172.16.68.68 255.255.255.255'
]

nxos1.config_list(commands)
Exemplo n.º 34
0
from getpass import getpass
import requests
from pynxos.device import Device
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

nexus_ip = "153.92.39.248"
nxs_test = Device(host=nexus_ip,
                  username="******",
                  password=getpass(),
                  transport='https',
                  port=8443)

print nxs_test.show("show version")
print(nxs_test.facts)
Exemplo n.º 35
0
    def __init__(self, host, username, password, transport='http', timeout=30, port=None, **kwargs):
        super(NXOSDevice, self).__init__(host, username, password, vendor='cisco', device_type=NXOS_API_DEVICE_TYPE)
        self.transport = transport
        self.timeout = timeout

        self.native = NXOSNative(host, username, password, transport=transport, timeout=timeout, port=port)
Exemplo n.º 36
0
class NXOSDriver(NetworkDriver):
    def __init__(self, hostname, username, password, timeout=60, optional_args=None):
        if optional_args is None:
            optional_args = {}
        self.hostname = hostname
        self.username = username
        self.password = password
        self.timeout = timeout
        self.up = False
        self.replace = True
        self.loaded = False
        self.fc = None
        self.changed = False
        self.replace_file = None
        self.merge_candidate = ''

        if optional_args is None:
            optional_args = {}

        # nxos_protocol is there for backwards compatibility, transport is the preferred method
        self.transport = optional_args.get('transport', optional_args.get('nxos_protocol', 'https'))

        if self.transport == 'https':
            self.port = optional_args.get('port', 443)
        elif self.transport == 'http':
            self.port = optional_args.get('port', 80)

    def open(self):
        try:
            self.device = NXOSDevice(self.hostname,
                                     self.username,
                                     self.password,
                                     timeout=self.timeout,
                                     port=self.port,
                                     transport=self.transport)
            self.device.show('show hostname')
            self.up = True
        except (CLIError, ValueError):
            # unable to open connection
            raise ConnectionException('Cannot connect to {}'.format(self.hostname))

    def close(self):
        if self.changed:
            self._delete_file(self.backup_file)
        self.device = None

    @staticmethod
    def _compute_timestamp(stupid_cisco_output):
        """
        Some fields such `uptime` are returned as: 23week(s) 3day(s)
        This method will determine the epoch of the event.
        e.g.: 23week(s) 3day(s) -> 1462248287
        """
        if not stupid_cisco_output or stupid_cisco_output == 'never':
            return -1.0

        if '(s)' in stupid_cisco_output:
            pass
        elif ':' in stupid_cisco_output:
            stupid_cisco_output = stupid_cisco_output.replace(':', 'hour(s) ', 1)
            stupid_cisco_output = stupid_cisco_output.replace(':', 'minute(s) ', 1)
            stupid_cisco_output += 'second(s)'
        else:
            stupid_cisco_output = stupid_cisco_output.replace('d', 'day(s) ')
            stupid_cisco_output = stupid_cisco_output.replace('h', 'hour(s)')

        things = {
            'second(s)': {
                'weight': 1
            },
            'minute(s)': {
                'weight': 60
            },
            'hour(s)': {
                'weight': 3600
            },
            'day(s)': {
                'weight': 24 * 3600
            },
            'week(s)': {
                'weight': 7 * 24 * 3600
            },
            'year(s)': {
                'weight': 365.25 * 24 * 3600
            }
        }

        things_keys = things.keys()
        for part in stupid_cisco_output.split():
            for key in things_keys:
                if key in part:
                    things[key]['count'] = napalm.base.helpers.convert(
                        int, part.replace(key, ''), 0)

        delta = sum([det.get('count', 0) * det.get('weight') for det in things.values()])
        return time.time() - delta

    @staticmethod
    def _get_reply_body(result):
        # useful for debugging
        ret = result.get('ins_api', {}).get('outputs', {}).get('output', {}).get('body', {})
        # Original 'body' entry may have been an empty string, don't return that.
        if not isinstance(ret, dict):
            return {}
        return ret

    @staticmethod
    def _get_table_rows(parent_table, table_name, row_name):
        # because if an inconsistent piece of shit.
        # {'TABLE_intf': [{'ROW_intf': {
        # vs
        # {'TABLE_mac_address': {'ROW_mac_address': [{
        # vs
        # {'TABLE_vrf': {'ROW_vrf': {'TABLE_adj': {'ROW_adj': {
        _table = parent_table.get(table_name)
        _table_rows = []
        if isinstance(_table, list):
            _table_rows = [_table_row.get(row_name) for _table_row in _table]
        elif isinstance(_table, dict):
            _table_rows = _table.get(row_name)
        if not isinstance(_table_rows, list):
            _table_rows = [_table_rows]
        return _table_rows

    @staticmethod
    def fix_checkpoint_string(string, filename):
        # used to generate checkpoint-like files
        pattern = '''!Command: Checkpoint cmd vdc 1'''

        if '!Command' in string:
            return re.sub('!Command.*', pattern.format(filename), string)
        else:
            return "{0}\n{1}".format(pattern.format(filename), string)

    def _get_reply_table(self, result, table_name, row_name):
        return self._get_table_rows(result, table_name, row_name)

    def _get_command_table(self, command, table_name, row_name):
        json_output = self.device.show(command)
        return self._get_reply_table(json_output, table_name, row_name)

    def is_alive(self):
        if self.device:
            return {'is_alive': True}
        else:
            return {'is_alive': False}

    def load_replace_candidate(self, filename=None, config=None):
        self.replace = True
        self.loaded = True

        if not filename and not config:
            raise ReplaceConfigException('filename or config param must be provided.')

        if filename is None:
            temp_file = tempfile.NamedTemporaryFile()
            temp_file.write(config)
            temp_file.flush()
            cfg_filename = temp_file.name
        else:
            cfg_filename = filename

        self.replace_file = cfg_filename

        with open(self.replace_file, 'r') as f:
            file_content = f.read()

        file_content = self.fix_checkpoint_string(file_content, self.replace_file)
        temp_file = tempfile.NamedTemporaryFile()
        temp_file.write(file_content.encode())
        temp_file.flush()
        self.replace_file = cfg_filename

        self._send_file(temp_file.name, cfg_filename)

    def load_merge_candidate(self, filename=None, config=None):
        self.replace = False
        self.loaded = True

        if not filename and not config:
            raise MergeConfigException('filename or config param must be provided.')

        self.merge_candidate += '\n'  # insert one extra line
        if filename is not None:
            with open(filename, "r") as f:
                self.merge_candidate += f.read()
        else:
            self.merge_candidate += config

    def _send_file(self, filename, dest):
        self.fc = FileCopy(self.device, filename, dst=dest.split('/')[-1])
        try:
            if not self.fc.remote_file_exists():
                self.fc.send()
            elif not self.fc.file_already_exists():
                commands = ['terminal dont-ask',
                            'delete {0}'.format(self.fc.dst)]
                self.device.config_list(commands)
                self.fc.send()
        except NXOSFileTransferError as fte:
            raise ReplaceConfigException(fte.message)

    def _create_sot_file(self):
        """Create Source of Truth file to compare."""
        commands = ['terminal dont-ask', 'checkpoint file sot_file']
        self.device.config_list(commands)

    def _get_diff(self, cp_file):
        """Get a diff between running config and a proposed file."""
        diff = []
        self._create_sot_file()
        diff_out = self.device.show(
            'show diff rollback-patch file {0} file {1}'.format(
                'sot_file', self.replace_file.split('/')[-1]), raw_text=True)
        try:
            diff_out = diff_out.split(
                '#Generating Rollback Patch')[1].replace(
                    'Rollback Patch is Empty', '').strip()
            for line in diff_out.splitlines():
                if line:
                    if line[0].strip() != '!':
                        diff.append(line.rstrip(' '))
        except (AttributeError, KeyError):
            raise ReplaceConfigException(
                'Could not calculate diff. It\'s possible the given file doesn\'t exist.')
        return '\n'.join(diff)

    def _get_merge_diff(self):
        diff = []
        running_config = self.get_config(retrieve='running')['running']
        running_lines = running_config.splitlines()
        for line in self.merge_candidate.splitlines():
            if line not in running_lines and line:
                if line[0].strip() != '!':
                    diff.append(line)
        return '\n'.join(diff)
        # the merge diff is not necessarily what needs to be loaded
        # for example under NTP, as the `ntp commit` command might be
        # alread configured, it is mandatory to be sent
        # otherwise it won't take the new configuration - see #59
        # https://github.com/napalm-automation/napalm-nxos/issues/59
        # therefore this method will return the real diff
        # but the merge_candidate will remain unchanged
        # previously: self.merge_candidate = '\n'.join(diff)

    def compare_config(self):
        if self.loaded:
            if not self.replace:
                return self._get_merge_diff()
                # return self.merge_candidate
            diff = self._get_diff(self.fc.dst)
            return diff
        return ''

    def _commit_merge(self):
        commands = [command for command in self.merge_candidate.splitlines() if command]
        self.device.config_list(commands)
        if not self.device.save():
            raise CommandErrorException('Unable to commit config!')

    def _save_config(self, filename):
        """Save the current running config to the given file."""
        self.device.show('checkpoint file {}'.format(filename), raw_text=True)

    def _disable_confirmation(self):
        self.device.config('terminal dont-ask')

    def _load_config(self):
        cmd = 'rollback running file {0}'.format(self.replace_file.split('/')[-1])
        self._disable_confirmation()
        try:
            rollback_result = self.device.config(cmd)
        except ConnectionError:
            # requests will raise an error with verbose warning output
            return True
        except Exception:
            return False
        if 'Rollback failed.' in rollback_result['msg'] or 'ERROR' in rollback_result:
            raise ReplaceConfigException(rollback_result['msg'])
        return True

    def commit_config(self):
        if self.loaded:
            self.backup_file = 'config_' + str(datetime.now()).replace(' ', '_')
            self._save_config(self.backup_file)
            if self.replace:
                if self._load_config() is False:
                    raise ReplaceConfigException
            else:
                try:
                    self._commit_merge()
                    self.merge_candidate = ''  # clear the merge buffer
                except Exception as e:
                    raise MergeConfigException(str(e))

            self.changed = True
            self.loaded = False
        else:
            raise ReplaceConfigException('No config loaded.')

    def _delete_file(self, filename):
        commands = ['terminal dont-ask',
                    'delete {}'.format(filename),
                    'no terminal dont-ask']
        self.device.show_list(commands, raw_text=True)

    def discard_config(self):
        if self.loaded:
            self.merge_candidate = ''  # clear the buffer
        if self.loaded and self.replace:
            try:
                self._delete_file(self.fc.dst)
            except CLIError:
                pass
        self.loaded = False

    def rollback(self):
        if self.changed:
            self.device.rollback(self.backup_file)
            self.device.save()
            self.changed = False

    def get_facts(self):
        pynxos_facts = self.device.facts
        final_facts = {key: value for key, value in pynxos_facts.items() if
                       key not in ['interfaces', 'uptime_string', 'vlans']}

        if pynxos_facts['interfaces']:
            final_facts['interface_list'] = pynxos_facts['interfaces']
        else:
            final_facts['interface_list'] = self.get_interfaces().keys()

        final_facts['vendor'] = 'Cisco'

        hostname_cmd = 'show hostname'
        hostname = self.device.show(hostname_cmd).get('hostname')
        if hostname:
            final_facts['fqdn'] = hostname

        return final_facts

    def get_interfaces(self):
        interfaces = {}
        iface_cmd = 'show interface'
        interfaces_out = self.device.show(iface_cmd)
        interfaces_body = interfaces_out['TABLE_interface']['ROW_interface']

        for interface_details in interfaces_body:
            interface_name = interface_details.get('interface')
            # Earlier version of Nexus returned a list for 'eth_bw' (observed on 7.1(0)N1(1a))
            interface_speed = interface_details.get('eth_bw', 0)
            if isinstance(interface_speed, list):
                interface_speed = interface_speed[0]
            interface_speed = int(interface_speed / 1000)
            if 'admin_state' in interface_details:
                is_up = interface_details.get('admin_state', '') == 'up'
            else:
                is_up = interface_details.get('state', '') == 'up'
            interfaces[interface_name] = {
                'is_up': is_up,
                'is_enabled': (interface_details.get('state') == 'up'),
                'description': py23_compat.text_type(interface_details.get('desc', '').strip('"')),
                'last_flapped': self._compute_timestamp(
                    interface_details.get('eth_link_flapped', '')),
                'speed': interface_speed,
                'mac_address': napalm.base.helpers.convert(
                    napalm.base.helpers.mac, interface_details.get('eth_hw_addr')),
            }
        return interfaces

    def get_lldp_neighbors(self):
        results = {}
        try:
            command = 'show lldp neighbors'
            lldp_raw_output = self.cli([command]).get(command, '')
            lldp_neighbors = napalm.base.helpers.textfsm_extractor(
                                self, 'lldp_neighbors', lldp_raw_output)
        except CLIError:
            lldp_neighbors = []

        for neighbor in lldp_neighbors:
            local_iface = neighbor.get('local_interface')
            if neighbor.get(local_iface) is None:
                if local_iface not in results:
                    results[local_iface] = []

            neighbor_dict = {}
            neighbor_dict['hostname'] = py23_compat.text_type(neighbor.get('neighbor'))
            neighbor_dict['port'] = py23_compat.text_type(neighbor.get('neighbor_interface'))

            results[local_iface].append(neighbor_dict)
        return results

    def get_bgp_neighbors(self):
        results = {}
        bgp_state_dict = {
            'Idle': {'is_up': False, 'is_enabled': True},
            'Active': {'is_up': False, 'is_enabled': True},
            'Open': {'is_up': False, 'is_enabled': True},
            'Established': {'is_up': True, 'is_enabled': True},
            'Closing': {'is_up': True, 'is_enabled': True},
            'Shutdown': {'is_up': False, 'is_enabled': False},
        }

        try:
            cmd = 'show bgp sessions vrf all'
            vrf_list = self._get_command_table(cmd, 'TABLE_vrf', 'ROW_vrf')
        except CLIError:
            vrf_list = []

        for vrf_dict in vrf_list:
            result_vrf_dict = {}
            result_vrf_dict['router_id'] = py23_compat.text_type(vrf_dict['router-id'])
            result_vrf_dict['peers'] = {}
            neighbors_list = vrf_dict.get('TABLE_neighbor', {}).get('ROW_neighbor', [])

            if isinstance(neighbors_list, dict):
                neighbors_list = [neighbors_list]

            for neighbor_dict in neighbors_list:
                neighborid = napalm.base.helpers.ip(neighbor_dict['neighbor-id'])
                remoteas = napalm.base.helpers.as_number(neighbor_dict['remoteas'])
                state = py23_compat.text_type(neighbor_dict['state'])

                bgp_state = bgp_state_dict[state]

                result_peer_dict = {
                    'local_as': int(vrf_dict['local-as']),
                    'remote_as': remoteas,
                    'remote_id': neighborid,
                    'is_enabled': bgp_state['is_enabled'],
                    'uptime': -1,
                    'description': '',
                    'is_up': bgp_state['is_up'],
                }
                result_peer_dict['address_family'] = {
                    'ipv4': {
                        'sent_prefixes': -1,
                        'accepted_prefixes': -1,
                        'received_prefixes': -1
                    }
                }
                result_vrf_dict['peers'][neighborid] = result_peer_dict

            vrf_name = vrf_dict['vrf-name-out']
            if vrf_name == 'default':
                vrf_name = 'global'
            results[vrf_name] = result_vrf_dict
        return results

    def _set_checkpoint(self, filename):
        commands = ['terminal dont-ask', 'checkpoint file {0}'.format(filename)]
        self.device.config_list(commands)

    def _get_checkpoint_file(self):
        filename = 'temp_cp_file_from_napalm'
        self._set_checkpoint(filename)
        cp_out = self.device.show('show file {0}'.format(filename), raw_text=True)
        self._delete_file(filename)
        return cp_out

    def get_lldp_neighbors_detail(self, interface=''):
        lldp_neighbors = {}
        filter = ''
        if interface:
            filter = 'interface {name} '.format(name=interface)

        command = 'show lldp neighbors {filter}detail'.format(filter=filter)
        # seems that some old devices may not return JSON output...

        try:
            lldp_neighbors_table_str = self.cli([command]).get(command)
            # thus we need to take the raw text output
            lldp_neighbors_list = lldp_neighbors_table_str.splitlines()
        except CLIError:
            lldp_neighbors_list = []

        if not lldp_neighbors_list:
            return lldp_neighbors  # empty dict

        CHASSIS_REGEX = r'^(Chassis id:)\s+([a-z0-9\.]+)$'
        PORT_REGEX = r'^(Port id:)\s+([0-9]+)$'
        LOCAL_PORT_ID_REGEX = r'^(Local Port id:)\s+(.*)$'
        PORT_DESCR_REGEX = r'^(Port Description:)\s+(.*)$'
        SYSTEM_NAME_REGEX = r'^(System Name:)\s+(.*)$'
        SYSTEM_DESCR_REGEX = r'^(System Description:)\s+(.*)$'
        SYST_CAPAB_REEGX = r'^(System Capabilities:)\s+(.*)$'
        ENABL_CAPAB_REGEX = r'^(Enabled Capabilities:)\s+(.*)$'
        VLAN_ID_REGEX = r'^(Vlan ID:)\s+(.*)$'

        lldp_neighbor = {}
        interface_name = None

        for line in lldp_neighbors_list:
            chassis_rgx = re.search(CHASSIS_REGEX, line, re.I)
            if chassis_rgx:
                lldp_neighbor = {
                    'remote_chassis_id': napalm.base.helpers.mac(chassis_rgx.groups()[1])
                }
                continue
            lldp_neighbor['parent_interface'] = ''
            port_rgx = re.search(PORT_REGEX, line, re.I)
            if port_rgx:
                lldp_neighbor['parent_interface'] = py23_compat.text_type(port_rgx.groups()[1])
                continue
            local_port_rgx = re.search(LOCAL_PORT_ID_REGEX, line, re.I)
            if local_port_rgx:
                interface_name = local_port_rgx.groups()[1]
                continue
            port_descr_rgx = re.search(PORT_DESCR_REGEX, line, re.I)
            if port_descr_rgx:
                lldp_neighbor['remote_port'] = py23_compat.text_type(port_descr_rgx.groups()[1])
                lldp_neighbor['remote_port_description'] = py23_compat.text_type(
                                                            port_descr_rgx.groups()[1])
                continue
            syst_name_rgx = re.search(SYSTEM_NAME_REGEX, line, re.I)
            if syst_name_rgx:
                lldp_neighbor['remote_system_name'] = py23_compat.text_type(
                                                        syst_name_rgx.groups()[1])
                continue
            syst_descr_rgx = re.search(SYSTEM_DESCR_REGEX, line, re.I)
            if syst_descr_rgx:
                lldp_neighbor['remote_system_description'] = py23_compat.text_type(
                                                                syst_descr_rgx.groups()[1])
                continue
            syst_capab_rgx = re.search(SYST_CAPAB_REEGX, line, re.I)
            if syst_capab_rgx:
                lldp_neighbor['remote_system_capab'] = py23_compat.text_type(
                                                        syst_capab_rgx.groups()[1])
                continue
            syst_enabled_rgx = re.search(ENABL_CAPAB_REGEX, line, re.I)
            if syst_enabled_rgx:
                lldp_neighbor['remote_system_enable_capab'] = py23_compat.text_type(
                                                                syst_enabled_rgx.groups()[1])
                continue
            vlan_rgx = re.search(VLAN_ID_REGEX, line, re.I)
            if vlan_rgx:
                # at the end of the loop
                if interface_name not in lldp_neighbors.keys():
                    lldp_neighbors[interface_name] = []
                lldp_neighbors[interface_name].append(lldp_neighbor)
        return lldp_neighbors

    def cli(self, commands):
        cli_output = {}
        if type(commands) is not list:
            raise TypeError('Please enter a valid list of commands!')

        for command in commands:
            command_output = self.device.show(command, raw_text=True)
            cli_output[py23_compat.text_type(command)] = command_output
        return cli_output

    def get_arp_table(self):
        arp_table = []
        command = 'show ip arp'
        arp_table_vrf = self._get_command_table(command, 'TABLE_vrf', 'ROW_vrf')
        arp_table_raw = self._get_table_rows(arp_table_vrf[0], 'TABLE_adj', 'ROW_adj')

        for arp_table_entry in arp_table_raw:
            raw_ip = arp_table_entry.get('ip-addr-out')
            raw_mac = arp_table_entry.get('mac')
            age = arp_table_entry.get('time-stamp')
            if age == '-':
                age_sec = -1.0
            elif ':' not in age:
                # Cisco sometimes returns a sub second arp time 0.411797
                try:
                    age_sec = float(age)
                except ValueError:
                    age_sec = -1.0
            else:
                fields = age.split(':')
                if len(fields) == 3:
                    try:
                        fields = [float(x) for x in fields]
                        hours, minutes, seconds = fields
                        age_sec = 3600 * hours + 60 * minutes + seconds
                    except ValueError:
                        age_sec = -1.0
            age_sec = round(age_sec, 1)

            interface = py23_compat.text_type(arp_table_entry.get('intf-out'))
            arp_table.append({
                'interface': interface,
                'mac': napalm.base.helpers.convert(
                    napalm.base.helpers.mac, raw_mac, raw_mac),
                'ip': napalm.base.helpers.ip(raw_ip),
                'age': age_sec
            })
        return arp_table

    def _get_ntp_entity(self, peer_type):
        ntp_entities = {}
        command = 'show ntp peers'
        ntp_peers_table = self._get_command_table(command, 'TABLE_peers', 'ROW_peers')

        for ntp_peer in ntp_peers_table:
            if ntp_peer.get('serv_peer', '').strip() != peer_type:
                continue
            peer_addr = napalm.base.helpers.ip(ntp_peer.get('PeerIPAddress').strip())
            ntp_entities[peer_addr] = {}

        return ntp_entities

    def get_ntp_peers(self):
        return self._get_ntp_entity('Peer')

    def get_ntp_servers(self):
        return self._get_ntp_entity('Server')

    def get_ntp_stats(self):
        ntp_stats = []
        command = 'show ntp peer-status'
        ntp_stats_table = self._get_command_table(command, 'TABLE_peersstatus', 'ROW_peersstatus')

        for ntp_peer in ntp_stats_table:
            peer_address = napalm.base.helpers.ip(ntp_peer.get('remote').strip())
            syncmode = ntp_peer.get('syncmode')
            stratum = int(ntp_peer.get('st'))
            hostpoll = int(ntp_peer.get('poll'))
            reachability = int(ntp_peer.get('reach'))
            delay = float(ntp_peer.get('delay'))
            ntp_stats.append({
                'remote': peer_address,
                'synchronized': (syncmode == '*'),
                'referenceid': peer_address,
                'stratum': stratum,
                'type': '',
                'when': '',
                'hostpoll': hostpoll,
                'reachability': reachability,
                'delay': delay,
                'offset': 0.0,
                'jitter': 0.0
            })
        return ntp_stats

    def get_interfaces_ip(self):
        interfaces_ip = {}
        ipv4_command = 'show ip interface'
        ipv4_interf_table_vrf = self._get_command_table(ipv4_command, 'TABLE_intf', 'ROW_intf')

        for interface in ipv4_interf_table_vrf:
            interface_name = py23_compat.text_type(interface.get('intf-name', ''))
            address = napalm.base.helpers.ip(interface.get('prefix'))
            prefix = int(interface.get('masklen', ''))
            if interface_name not in interfaces_ip.keys():
                interfaces_ip[interface_name] = {}
            if 'ipv4' not in interfaces_ip[interface_name].keys():
                interfaces_ip[interface_name]['ipv4'] = {}
            if address not in interfaces_ip[interface_name].get('ipv4'):
                interfaces_ip[interface_name]['ipv4'][address] = {}
            interfaces_ip[interface_name]['ipv4'][address].update({
                'prefix_length': prefix
            })
            secondary_addresses = interface.get('TABLE_secondary_address', {})\
                                           .get('ROW_secondary_address', [])
            if type(secondary_addresses) is dict:
                secondary_addresses = [secondary_addresses]
            for secondary_address in secondary_addresses:
                secondary_address_ip = napalm.base.helpers.ip(secondary_address.get('prefix1'))
                secondary_address_prefix = int(secondary_address.get('masklen1', ''))
                if 'ipv4' not in interfaces_ip[interface_name].keys():
                    interfaces_ip[interface_name]['ipv4'] = {}
                if secondary_address_ip not in interfaces_ip[interface_name].get('ipv4'):
                    interfaces_ip[interface_name]['ipv4'][secondary_address_ip] = {}
                interfaces_ip[interface_name]['ipv4'][secondary_address_ip].update({
                    'prefix_length': secondary_address_prefix
                })

        ipv6_command = 'show ipv6 interface'
        ipv6_interf_table_vrf = self._get_command_table(ipv6_command, 'TABLE_intf', 'ROW_intf')

        for interface in ipv6_interf_table_vrf:
            interface_name = py23_compat.text_type(interface.get('intf-name', ''))
            address = napalm.base.helpers.ip(interface.get('addr', '').split('/')[0])
            prefix = interface.get('prefix', '').split('/')[-1]
            if prefix:
                prefix = int(interface.get('prefix', '').split('/')[-1])
            else:
                prefix = 128
            if interface_name not in interfaces_ip.keys():
                interfaces_ip[interface_name] = {}
            if 'ipv6' not in interfaces_ip[interface_name].keys():
                interfaces_ip[interface_name]['ipv6'] = {}
            if address not in interfaces_ip[interface_name].get('ipv6'):
                interfaces_ip[interface_name]['ipv6'][address] = {}
            interfaces_ip[interface_name]['ipv6'][address].update({
                'prefix_length': prefix
            })
            secondary_addresses = interface.get('TABLE_sec_addr', {}).get('ROW_sec_addr', [])
            if type(secondary_addresses) is dict:
                secondary_addresses = [secondary_addresses]
            for secondary_address in secondary_addresses:
                sec_prefix = secondary_address.get('sec-prefix', '').split('/')
                secondary_address_ip = napalm.base.helpers.ip(sec_prefix[0])
                secondary_address_prefix = int(sec_prefix[-1])
                if 'ipv6' not in interfaces_ip[interface_name].keys():
                    interfaces_ip[interface_name]['ipv6'] = {}
                if secondary_address_ip not in interfaces_ip[interface_name].get('ipv6'):
                    interfaces_ip[interface_name]['ipv6'][secondary_address_ip] = {}
                interfaces_ip[interface_name]['ipv6'][secondary_address_ip].update({
                    'prefix_length': secondary_address_prefix
                })
        return interfaces_ip

    def get_mac_address_table(self):
        mac_table = []
        command = 'show mac address-table'
        mac_table_raw = self._get_command_table(command, 'TABLE_mac_address', 'ROW_mac_address')

        for mac_entry in mac_table_raw:
            raw_mac = mac_entry.get('disp_mac_addr')
            interface = py23_compat.text_type(mac_entry.get('disp_port'))
            vlan = int(mac_entry.get('disp_vlan'))
            active = True
            static = (mac_entry.get('disp_is_static') != '0')
            moves = 0
            last_move = 0.0
            mac_table.append({
                'mac': napalm.base.helpers.mac(raw_mac),
                'interface': interface,
                'vlan': vlan,
                'active': active,
                'static': static,
                'moves': moves,
                'last_move': last_move
            })
        return mac_table

    def get_snmp_information(self):
        snmp_information = {}
        snmp_command = 'show running-config'
        snmp_raw_output = self.cli([snmp_command]).get(snmp_command, '')
        snmp_config = napalm.base.helpers.textfsm_extractor(self, 'snmp_config', snmp_raw_output)

        if not snmp_config:
            return snmp_information

        snmp_information = {
            'contact': py23_compat.text_type(''),
            'location': py23_compat.text_type(''),
            'community': {},
            'chassis_id': py23_compat.text_type('')
        }

        for snmp_entry in snmp_config:
            contact = py23_compat.text_type(snmp_entry.get('contact', ''))
            if contact:
                snmp_information['contact'] = contact
            location = py23_compat.text_type(snmp_entry.get('location', ''))
            if location:
                snmp_information['location'] = location

            community_name = py23_compat.text_type(snmp_entry.get('community', ''))
            if not community_name:
                continue

            if community_name not in snmp_information['community'].keys():
                snmp_information['community'][community_name] = {
                    'acl': py23_compat.text_type(snmp_entry.get('acl', '')),
                    'mode': py23_compat.text_type(snmp_entry.get('mode', '').lower())
                }
            else:
                acl = py23_compat.text_type(snmp_entry.get('acl', ''))
                if acl:
                    snmp_information['community'][community_name]['acl'] = acl
                mode = py23_compat.text_type(snmp_entry.get('mode', '').lower())
                if mode:
                    snmp_information['community'][community_name]['mode'] = mode
        return snmp_information

    def get_users(self):
        _CISCO_TO_CISCO_MAP = {
            'network-admin': 15,
            'network-operator': 5
        }

        _DEFAULT_USER_DICT = {
            'password': '',
            'level': 0,
            'sshkeys': []
        }

        users = {}
        command = 'show running-config'
        section_username_raw_output = self.cli([command]).get(command, '')
        section_username_tabled_output = napalm.base.helpers.textfsm_extractor(
            self, 'users', section_username_raw_output)

        for user in section_username_tabled_output:
            username = user.get('username', '')
            if not username:
                continue
            if username not in users:
                users[username] = _DEFAULT_USER_DICT.copy()

            password = user.get('password', '')
            if password:
                users[username]['password'] = py23_compat.text_type(password.strip())

            level = 0
            role = user.get('role', '')
            if role.startswith('priv'):
                level = int(role.split('-')[-1])
            else:
                level = _CISCO_TO_CISCO_MAP.get(role, 0)
            if level > users.get(username).get('level'):
                # unfortunately on Cisco you can set different priv levels for the same user
                # Good news though: the device will consider the highest level
                users[username]['level'] = level

            sshkeytype = user.get('sshkeytype', '')
            sshkeyvalue = user.get('sshkeyvalue', '')
            if sshkeytype and sshkeyvalue:
                if sshkeytype not in ['ssh-rsa', 'ssh-dsa']:
                    continue
                users[username]['sshkeys'].append(py23_compat.text_type(sshkeyvalue))
        return users

    def traceroute(self,
                   destination,
                   source=c.TRACEROUTE_SOURCE,
                   ttl=c.TRACEROUTE_TTL,
                   timeout=c.TRACEROUTE_TIMEOUT,
                   vrf=c.TRACEROUTE_VRF):
        _HOP_ENTRY_PROBE = [
            r'\s+',
            r'(',  # beginning of host_name (ip_address) RTT group
            r'(',  # beginning of host_name (ip_address) group only
            r'([a-zA-Z0-9\.:-]*)',  # hostname
            r'\s+',
            r'\(?([a-fA-F0-9\.:][^\)]*)\)?'  # IP Address between brackets
            r')?',  # end of host_name (ip_address) group only
            # also hostname/ip are optional -- they can or cannot be specified
            # if not specified, means the current probe followed the same path as the previous
            r'\s+',
            r'(\d+\.\d+)\s+ms',  # RTT
            r'|\*',  # OR *, when non responsive hop
            r')'  # end of host_name (ip_address) RTT group
        ]

        _HOP_ENTRY = [
            r'\s?',  # space before hop index?
            r'(\d+)',  # hop index
        ]

        traceroute_result = {}
        timeout = 5  # seconds
        probes = 3  # 3 probes/jop and this cannot be changed on NXOS!

        version = ''
        try:
            version = '6' if IPAddress(destination).version == 6 else ''
        except AddrFormatError:
            return {'error': 'Destination doest not look like a valid IP Address: {}'.format(
                destination)}

        source_opt = ''
        if source:
            source_opt = 'source {source}'.format(source=source)

        command = 'traceroute{version} {destination} {source_opt}'.format(
            version=version,
            destination=destination,
            source_opt=source_opt
        )

        try:
            traceroute_raw_output = self.cli([command]).get(command)
        except CommandErrorException:
            return {'error': 'Cannot execute traceroute on the device: {}'.format(command)}

        hop_regex = ''.join(_HOP_ENTRY + _HOP_ENTRY_PROBE * probes)
        traceroute_result['success'] = {}
        if traceroute_raw_output:
            for line in traceroute_raw_output.splitlines():
                hop_search = re.search(hop_regex, line)
                if not hop_search:
                    continue
                hop_details = hop_search.groups()
                hop_index = int(hop_details[0])
                previous_probe_host_name = '*'
                previous_probe_ip_address = '*'
                traceroute_result['success'][hop_index] = {'probes': {}}
                for probe_index in range(probes):
                    host_name = hop_details[3+probe_index*5]
                    ip_address_raw = hop_details[4+probe_index*5]
                    ip_address = napalm.base.helpers.convert(
                        napalm.base.helpers.ip, ip_address_raw, ip_address_raw)
                    rtt = hop_details[5+probe_index*5]
                    if rtt:
                        rtt = float(rtt)
                    else:
                        rtt = timeout * 1000.0
                    if not host_name:
                        host_name = previous_probe_host_name
                    if not ip_address:
                        ip_address = previous_probe_ip_address
                    if hop_details[1+probe_index*5] == '*':
                        host_name = '*'
                        ip_address = '*'
                    traceroute_result['success'][hop_index]['probes'][probe_index+1] = {
                        'host_name': py23_compat.text_type(host_name),
                        'ip_address': py23_compat.text_type(ip_address),
                        'rtt': rtt
                    }
                    previous_probe_host_name = host_name
                    previous_probe_ip_address = ip_address
        return traceroute_result

    def get_config(self, retrieve='all'):
        config = {
            'startup': '',
            'running': '',
            'candidate': ''
        }  # default values

        if retrieve.lower() in ('running', 'all'):
            _cmd = 'show running-config'
            config['running'] = py23_compat.text_type(self.cli([_cmd]).get(_cmd))
        if retrieve.lower() in ('startup', 'all'):
            _cmd = 'show startup-config'
            config['startup'] = py23_compat.text_type(self.cli([_cmd]).get(_cmd))
        return config