def get_arp_table(self): """ 'show arp' output example: Address HWtype HWaddress Flags Mask Iface 10.129.2.254 ether 00:50:56:97:af:b1 C eth0 192.168.1.134 (incomplete) eth1 192.168.1.1 ether 00:50:56:ba:26:7f C eth1 10.129.2.97 ether 00:50:56:9f:64:09 C eth0 192.168.1.3 ether 00:50:56:86:7b:06 C eth1 """ output = self._send_command('arp -n') output = output.split("\n") output = output[1:] arp_table = list() for line in output: line = line.split() if "incomplete" in line[1]: macaddr = py23_compat.text_type("00:00:00:00:00:00") else: macaddr = py23_compat.text_type(line[2]) arp_table.append( { 'interface': py23_compat.text_type(line[-1]), 'mac': macaddr, 'ip': py23_compat.text_type(line[0]), 'age': 0.0 } ) return arp_table
def _compare_getter(src, dst): if isinstance(src, py23_compat.string_types): src = py23_compat.text_type(src) if isinstance(src, dict): mode = _mode(src.pop('_mode', '')) if 'list' in src.keys(): if not isinstance(dst, list): # This can happen with nested lists return False return _compare_getter_list(src['list'], dst, mode) return _compare_getter_dict(src, dst, mode) elif isinstance(src, py23_compat.string_types): if src.startswith('<') or src.startswith('>'): cmp_result = compare_numeric(src, dst) return cmp_result else: m = re.search(src, py23_compat.text_type(dst)) if m: return bool(m) else: return src == dst elif(type(src) == type(dst) == list): pairs = zip(src, dst) diff_lists = [[(k, x[k], y[k]) for k in x if not re.search(x[k], y[k])] for x, y in pairs if x != y] return empty_tree(diff_lists) else: return src == dst
def get_facts(self): facts = { 'vendor': py23_compat.text_type('FRRouting') } # Get "net show hostname" output. hostname = self.device.send_command('hostname') uptime_output = self._send_command("cat /proc/uptime | awk '{print $1}'") uptime = int(float(uptime_output)) os_version = self._send_command("vtysh -c 'show version'").split("\n") model = self._send_command("lsb_release -d | awk -F':' '{print $2}'").strip() serial_number = "123" iface_list = list() interfaces = self._send_command("vtysh -c 'show interface description'").split("\n") for line in interfaces[1:]: iface_name, status, protocol, description = (line.split() + [""]*99)[:4] iface_list.append(iface_name) facts['hostname'] = facts['fqdn'] = py23_compat.text_type(hostname) facts['os_version'] = py23_compat.text_type(os_version[0]) facts['model'] = py23_compat.text_type(model) facts['uptime'] = int(uptime) facts['serial_number'] = py23_compat.text_type(serial_number) facts['interface_list'] = string_parsers.sorted_nicely(iface_list) return facts
def get_lldp_neighbors_detail(self, interface=''): lldp_neighbors = {} lldp_show = self.device.show('lldp', delim='@$@') lines = lldp_show.splitlines()[1:-1] for line in lines: neighbor_details = line.split('@$@') port = py23_compat.text_type(neighbor_details[1].strip()) if interface and port != interface: continue chassis = napalm_base.helpers.convert(napalm_base.helpers.mac, neighbor_details[2].strip()) port_id = py23_compat.text_type(neighbor_details[3].strip()) port_descr = py23_compat.text_type(neighbor_details[4].strip()) system_name = py23_compat.text_type(neighbor_details[6].strip()) if port not in lldp_neighbors.keys(): lldp_neighbors[port] = [] lldp_neighbors[port].append({ 'parent_interface': u'', 'remote_port': port_id, 'remote_port_description': port_descr, 'remote_chassis_id': chassis, 'remote_system_name': system_name, 'remote_system_description': u'', 'remote_system_capab': u'', 'remote_system_enable_capab': u'' }) return lldp_neighbors
def get_interfaces(self): interfaces = {} interface_info = self.device.show('port config', delim='@$@') interfaces_lines = interface_info.splitlines()[1:-1] for line in interfaces_lines: interface_details = line.split('@$@') interface_name = py23_compat.text_type(interface_details[1]) up = (interface_details[4] != 'disable') enabled = (interface_details[8] == 'on') speed = 0 if up and interface_details[4].replace('g', '').isdigit(): speed = int(1e3 * int(interface_details[4].replace('g', ''))) # > 1G interfaces last_flap = 0.0 description = py23_compat.text_type(interface_details[17]) mac_address = py23_compat.text_type(interface_details[28]) interfaces[interface_name] = { 'is_up': up, 'is_enabled': enabled, 'description': description, 'last_flapped': last_flap, 'speed': speed, 'mac_address': napalm_base.helpers.convert( napalm_base.helpers.mac, mac_address) } return interfaces
def get_facts(self): system_status = self._get_command_with_vdom('get system status', vdom='global') performance_status = self._get_command_with_vdom( 'get system performance status', vdom='global') interfaces = self._execute_command_with_vdom( 'get system interface | grep ==', vdom='global') interface_list = [ x.split()[2] for x in interfaces if x.strip() is not '' ] domain = self._get_command_with_vdom('get system dns | grep domain', vdom='global')['domain'] return { 'vendor': py23_compat.text_type('Fortigate'), 'os_version': py23_compat.text_type( system_status['Version'].split(',')[0].split()[1]), 'uptime': convert_uptime_string_seconds(performance_status['Uptime']), 'serial_number': py23_compat.text_type(system_status['Serial-Number']), 'model': py23_compat.text_type( system_status['Version'].split(',')[0].split()[0]), 'hostname': py23_compat.text_type(system_status['Hostname']), 'fqdn': u'{}.{}'.format(system_status['Hostname'], domain), 'interface_list': interface_list }
def get_snmp_information(self): snmp_information = {} _SNMP_MODE_MAP_ = {'read-write': u'rw', 'read-only': u'ro'} switch_info = self.device.show('switch info', delim='@$@') chassis_id = switch_info.splitlines()[2].split('@$@')[-1] snmp_information['chassis_id'] = py23_compat.text_type(chassis_id) snmp_information['contact'] = u'' snmp_information['location'] = u'' snmp_information['community'] = {} snmp_communities = self.device.show('snmp community', delim='@$@') snmp_lines = snmp_communities.splitlines() for snmp_line in snmp_lines: snmp_line_details = snmp_line.split('@$@') snmp_community = py23_compat.text_type(snmp_line_details[1]) snmp_mode = _SNMP_MODE_MAP_.get(snmp_line_details[2], u'ro') snmp_acl = u'' snmp_information['community'][snmp_community] = { 'acl': snmp_acl, 'mode': snmp_mode } return snmp_information
def _compare_getter(src, dst): if isinstance(src, py23_compat.string_types): src = py23_compat.text_type(src) if isinstance(src, dict): mode = _mode(src.pop('_mode', '')) if 'list' in src.keys(): if not isinstance(dst, list): # This can happen with nested lists return False return _compare_getter_list(src['list'], dst, mode) return _compare_getter_dict(src, dst, mode) else: if isinstance(src, py23_compat.string_types): if src.startswith('<') or src.startswith('>'): cmp_result = compare_numeric(src, dst) return cmp_result else: m = re.search(src, py23_compat.text_type(dst)) return m is not None elif (type(src) == type(dst) == list): pairs = zip(src, dst) diff_lists = [[(k, x[k], y[k]) for k in x if not re.search(x[k], y[k])] for x, y in pairs if x != y] return empty_tree(diff_lists) else: return src == dst
def get_snmp_information(self): # 'acl' is not implemented yet output = self.device.send_command("show configuration") # convert the configuration to dictionary config = vyattaconfparser.parse_conf(output) snmp = dict() snmp["community"] = dict() try: for i in config["service"]["snmp"]["community"]: snmp["community"].update({ i: { "acl": py23_compat.text_type(""), "mode": py23_compat.text_type( config["service"]["snmp"]["community"][i] ["authorization"]) } }) snmp.update({ "chassis_id": py23_compat.text_type(""), "contact": py23_compat.text_type(config["service"]["snmp"]["contact"]), "location": py23_compat.text_type(config["service"]["snmp"]["location"]) }) return snmp except KeyError: return {}
def get_snmp_information(self): snmp_information = {} _SNMP_MODE_MAP_ = { 'read-write': u'rw', 'read-only': u'ro' } switch_info = self.device.show('switch info', delim='@$@') chassis_id = switch_info.splitlines()[2].split('@$@')[-1] snmp_information['chassis_id'] = py23_compat.text_type(chassis_id) snmp_information['contact'] = u'' snmp_information['location'] = u'' snmp_information['community'] = {} snmp_communities = self.device.show('snmp community', delim='@$@') snmp_lines = snmp_communities.splitlines() for snmp_line in snmp_lines: snmp_line_details = snmp_line.split('@$@') snmp_community = py23_compat.text_type(snmp_line_details[1]) snmp_mode = _SNMP_MODE_MAP_.get(snmp_line_details[2], u'ro') snmp_acl = u'' snmp_information['community'][snmp_community] = { 'acl': snmp_acl, 'mode': snmp_mode } return snmp_information
def get_lldp_neighbors_detail(self, interface=''): lldp_neighbors = {} lldp_show = self.device.show('lldp', delim='@$@') lines = lldp_show.splitlines()[1:-1] for line in lines: neighbor_details = line.split('@$@') port = py23_compat.text_type(neighbor_details[1].strip()) if interface and port != interface: continue chassis = napalm_base.helpers.convert( napalm_base.helpers.mac, neighbor_details[2].strip()) port_id = py23_compat.text_type(neighbor_details[3].strip()) port_descr = py23_compat.text_type(neighbor_details[4].strip()) system_name = py23_compat.text_type(neighbor_details[6].strip()) if port not in lldp_neighbors.keys(): lldp_neighbors[port] = [] lldp_neighbors[port].append({ 'parent_interface': u'', 'remote_port': port_id, 'remote_port_description': port_descr, 'remote_chassis_id': chassis, 'remote_system_name': system_name, 'remote_system_description': u'', 'remote_system_capab': u'', 'remote_system_enable_capab': u'' }) return lldp_neighbors
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 test_context_manager(self): with pytest.raises(napalm_base.exceptions.ConnectionException) as e, \ driver("blah", "bleh", "blih", optional_args=fail_args) as d: pass assert "You told me to do this" in py23_compat.text_type(e.value) with pytest.raises(AttributeError) as e, \ driver("blah", "bleh", "blih", optional_args=optional_args) as d: assert d.is_alive() == {u'is_alive': True} d.__fake_call() assert d.is_alive() == {u'is_alive': False} assert "object has no attribute" in py23_compat.text_type(e.value)
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
def test_not_mocking_getters(self): d = driver("blah", "bleh", "blih", optional_args=optional_args) d.open() with pytest.raises(NotImplementedError) as excinfo: d.get_route_to() expected = "You can provide mocked data in {}/get_route_to.1".format(optional_args["path"]) assert expected in py23_compat.text_type(excinfo.value) with pytest.raises(NotImplementedError) as excinfo: d.get_route_to() expected = "You can provide mocked data in {}/get_route_to.2".format(optional_args["path"]) assert expected in py23_compat.text_type(excinfo.value) d.close()
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 mac(raw): """ Converts a raw string to a standardised MAC Address EUI Format. :param raw: the raw string containing the value of the MAC Address :return: a string with the MAC Address in EUI format Example: .. code-block:: python >>> mac('0123.4567.89ab') u'01:23:45:67:89:AB' Some vendors like Cisco return MAC addresses like a9:c5:2e:7b:6: which is not entirely valid (with respect to EUI48 or EUI64 standards). Therefore we need to stuff with trailing zeros Example >>> mac('a9:c5:2e:7b:6:') u'A9:C5:2E:7B:60:00' If Cisco or other obscure vendors use their own standards, will throw an error and we can fix later, however, still works with weird formats like: >>> mac('123.4567.89ab') u'01:23:45:67:89:AB' >>> mac('23.4567.89ab') u'00:23:45:67:89:AB' """ if raw.endswith(':'): flat_raw = raw.replace(':', '') raw = '{flat_raw}{zeros_stuffed}'.format(flat_raw=flat_raw, zeros_stuffed='0' * (12 - len(flat_raw))) return py23_compat.text_type(EUI(raw, dialect=_MACFormat))
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_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_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 ip(addr, version=None): """ Converts a raw string to a valid IP address. Optional version argument will detect that \ object matches specified version. Motivation: the groups of the IP addreses may contain leading zeros. IPv6 addresses can \ contain sometimes uppercase characters. E.g.: 2001:0dB8:85a3:0000:0000:8A2e:0370:7334 has \ the same logical value as 2001:db8:85a3::8a2e:370:7334. However, their values as strings are \ not the same. :param raw: the raw string containing the value of the IP Address :param version: (optional) insist on a specific IP address version. :type version: int. :return: a string containing the IP Address in a standard format (no leading zeros, \ zeros-grouping, lowercase) Example: .. code-block:: python >>> ip('2001:0dB8:85a3:0000:0000:8A2e:0370:7334') u'2001:db8:85a3::8a2e:370:7334' """ addr_obj = IPAddress(addr) if version and addr_obj.version != version: raise ValueError("{} is not an ipv{} address".format(addr, version)) return py23_compat.text_type(addr_obj)
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
def get_mac_address_table(self): mac_table = [] mac_show = self.device.show('l2 table', delim='@$@') lines = mac_show.splitlines()[1:-1] for line in lines: mac_details = line.split('@$@') mac_raw = mac_details[2].strip() vlan = int(mac_details[3].strip()) ports = py23_compat.text_type(mac_details[8].strip()) active = (mac_details[9].strip == 'active') mac_table.append({ 'mac': napalm_base.helpers.convert(napalm_base.helpers.mac, mac_raw), 'interface': ports, 'vlan': vlan, 'active': active, 'static': False, 'moves': 0, 'last_move': 0.0 }) return mac_table
def get_mac_address_table(self): mac_table = [] mac_show = self.device.show('l2 table', delim='@$@') lines = mac_show.splitlines()[1:-1] for line in lines: mac_details = line.split('@$@') mac_raw = mac_details[2].strip() vlan = int(mac_details[3].strip()) ports = py23_compat.text_type(mac_details[8].strip()) active = (mac_details[9].strip == 'active') mac_table.append({ 'mac': napalm_base.helpers.convert( napalm_base.helpers.mac, mac_raw), 'interface': ports, 'vlan': vlan, 'active': active, 'static': False, 'moves': 0, 'last_move': 0.0 }) return mac_table
def get_firewall_policies(self): cmd = self._execute_command_with_vdom('show firewall policy') policy = dict() policy_id = None default_policy = dict() position = 1 for line in cmd: policy_data = line.strip() if policy_data.find("edit") == 0: policy_id = policy_data.split()[1] policy[policy_id] = dict() if policy_id is not None: if len(policy_data.split()) > 2: policy_setting = policy_data.split()[1] policy[policy_id][policy_setting] = policy_data.split( )[2].replace("\"", "") for key in policy: enabled = 'status' in policy[key] logtraffic = policy[key]['logtraffic'] if 'logtraffic' in policy[ key] else False action = 'permit' if 'action' in policy[key] else 'reject' policy_item = dict() default_policy[key] = list() policy_item['position'] = position policy_item['packet_hits'] = -1 policy_item['byte_hits'] = -1 policy_item['id'] = py23_compat.text_type(key) policy_item['enabled'] = enabled policy_item['schedule'] = py23_compat.text_type( policy[key]['schedule']) policy_item['log'] = py23_compat.text_type(logtraffic) policy_item['l3_src'] = py23_compat.text_type( policy[key]['srcaddr']) policy_item['l3_dst'] = py23_compat.text_type( policy[key]['dstaddr']) policy_item['service'] = py23_compat.text_type( policy[key]['service']) policy_item['src_zone'] = py23_compat.text_type( policy[key]['srcintf']) policy_item['dst_zone'] = py23_compat.text_type( policy[key]['dstintf']) policy_item['action'] = py23_compat.text_type(action) default_policy[key].append(policy_item) position = position + 1 return default_policy
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 get_facts(self): switch_info = self.device.show('switch info', delim='@$@') lines = switch_info.splitlines()[1:4] hostname = lines[0].split('@$@')[1].strip() model = lines[1].split('@$@')[1].strip() serial = lines[2].split('@$@')[1].strip() software_info = self.device.show('software', delim='@$@') lines = software_info.splitlines()[1:2] os_ver = lines[0].split('@$@')[1].strip() system_stats = self.device.show('system stats', delim='@$@') # one single line uptime_str = system_stats.split('@$@')[9].strip() uptime_days_split = uptime_str.split('d') uptime_days = int(uptime_days_split[0]) uptime_hours_split = uptime_days_split[-1].split('h') uptime_minutes_split = uptime_hours_split[-1].split('m') uptime_minutes = int(uptime_minutes_split[0]) uptime_seconds = int(uptime_minutes_split[-1].replace('s', '')) uptime = 24*3600*uptime_days + 60*uptime_minutes + uptime_seconds interfaces = [] port_stats = self.device.show('port stats', delim='@$@') lines = port_stats.splitlines()[1:-1] for line in lines: interface = line.split('@$@')[9].strip() interfaces.append(interface) facts = { 'vendor': u'Pluribus', 'os_version': py23_compat.text_type(os_ver), 'hostname': py23_compat.text_type(hostname), 'uptime': uptime, 'model': py23_compat.text_type(model), 'serial_number': py23_compat.text_type(serial), 'interface_list': interfaces, 'fqdn': u'' } return facts
def as_number(as_number_val): """Convert AS Number to standardized asplain notation as an integer.""" as_number_str = py23_compat.text_type(as_number_val) if '.' in as_number_str: big, little = as_number_str.split('.') return (int(big) << 16) + int(little) else: return int(as_number_str)
def get_facts(self): switch_info = self.device.show('switch info', delim='@$@') lines = switch_info.splitlines()[1:4] hostname = lines[0].split('@$@')[1].strip() model = lines[1].split('@$@')[1].strip() serial = lines[2].split('@$@')[1].strip() software_info = self.device.show('software', delim='@$@') lines = software_info.splitlines()[1:2] os_ver = lines[0].split('@$@')[1].strip() system_stats = self.device.show('system stats', delim='@$@') # one single line uptime_str = system_stats.split('@$@')[9].strip() uptime_days_split = uptime_str.split('d') uptime_days = int(uptime_days_split[0]) uptime_hours_split = uptime_days_split[-1].split('h') uptime_minutes_split = uptime_hours_split[-1].split('m') uptime_minutes = int(uptime_minutes_split[0]) uptime_seconds = int(uptime_minutes_split[-1].replace('s', '')) uptime = 24 * 3600 * uptime_days + 60 * uptime_minutes + uptime_seconds interfaces = [] port_stats = self.device.show('port stats', delim='@$@') lines = port_stats.splitlines()[1:-1] for line in lines: interface = line.split('@$@')[9].strip() interfaces.append(interface) facts = { 'vendor': u'Pluribus', 'os_version': py23_compat.text_type(os_ver), 'hostname': py23_compat.text_type(hostname), 'uptime': uptime, 'model': py23_compat.text_type(model), 'serial_number': py23_compat.text_type(serial), 'interface_list': interfaces, 'fqdn': u'' } return facts
def test_mock_error(self): d = driver("blah", "bleh", "blih", optional_args=optional_args) d.open() with pytest.raises(KeyError) as excinfo: d.get_bgp_neighbors() assert "Something" in py23_compat.text_type(excinfo.value) with pytest.raises(napalm_base.exceptions.ConnectionClosedException) as excinfo: d.get_bgp_neighbors() assert "Something" in py23_compat.text_type(excinfo.value) with pytest.raises(TypeError) as excinfo: d.get_bgp_neighbors() assert "Couldn't resolve exception NoIdeaException" in py23_compat.text_type( excinfo.value) d.close()
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 send_command_expect(self, command, **kwargs): """Fake execute a command in the device by just returning the content of a file.""" # cmd = re.sub(r'[\[\]\*\^\+\s\|/]', '_', command) cmd = '{}'.format(BaseTestDouble.sanitize_text(command)) file_path = 'dellos10/mock_data/{}.txt'.format(cmd) print("file_path :: " + file_path) output = self.read_txt_file(file_path) return py23_compat.text_type(output)
def get_interfaces(self): cmd_data = self._execute_command_with_vdom( 'diagnose hardware deviceinfo nic', vdom='global') interface_list = [ x.replace('\t', '') for x in cmd_data if x.startswith('\t') ] interface_statistics = {} for interface in interface_list: if_data = self._execute_command_with_vdom( 'diagnose hardware deviceinfo nic {}'.format(interface), vdom='global') parsed_data = {} if interface.startswith('mgmt'): for line in if_data: if line.startswith('Speed'): if line.split('\t')[-1].split(' ')[0].isdigit(): parsed_data['speed'] = int( line.split('\t')[-1].split(' ')[0]) else: parsed_data['speed'] = -1 elif line.startswith('Link'): parsed_data['is_up'] = line.split('\t')[-1] is 'up' elif line.startswith('Current_HWaddr'): parsed_data['mac_address'] = py23_compat.text_type( line.split('\t')[-1]) parsed_data['is_enabled'] = True parsed_data['description'] = u'' parsed_data['last_flapped'] = -1.0 else: for line in if_data: if line.startswith('Admin'): parsed_data['is_enabled'] = line.split(':')[-1] is 'up' elif line.startswith('PHY Status'): parsed_data['is_up'] = line.split(':')[-1] is 'up' elif line.startswith('PHY Speed'): parsed_data['speed'] = int(line.split(':')[-1]) elif line.startswith('Current_HWaddr'): parsed_data['mac_address'] = py23_compat.text_type( line.split(' ')[-1]) parsed_data['description'] = u'' parsed_data['last_flapped'] = -1.0 interface_statistics[interface] = parsed_data return interface_statistics
def get_users(self): users = {} _DEFAULT_USER_DETAILS = { 'level': 0, 'password': '', 'sshkeys': [] } role_level = {} roles_config = self.device.show('role', delim='@$@') for role in roles_config.splitlines(): role_details = role.split('@$@') role_name = role_details[2] level = 0 access = role_details[5] running_config = role_details[6] if access == 'read-write' and running_config == 'permit': level = 15 if (access == 'read-write' and running_config == 'deny') or\ (access == 'read-only' and running_config == 'permit'): level = 5 if access == 'read-only' and running_config == 'deny': level = 1 role_level[role_name] = level running_config = self.device.config._download_running_config() for line in running_config.splitlines(): if not line.startswith('import-password user-create'): continue user_details = _DEFAULT_USER_DETAILS.copy() user_config = line.split() username = py23_compat.text_type(user_config[3]) password = py23_compat.text_type(user_config[7]) role = user_config[9] level = role_level.get(role) user_details.update({ 'level': level, 'password': password, }) users[username] = user_details return users
def _compare_getter(src, dst): if isinstance(src, py23_compat.string_types): src = py23_compat.text_type(src) if isinstance(src, dict): mode = _mode(src.pop('_mode', '')) if 'list' in src.keys(): if not isinstance(dst, list): # This can happen with nested lists return False return _compare_getter_list(src['list'], dst, mode) return _compare_getter_dict(src, dst, mode) else: if isinstance(src, py23_compat.string_types): m = re.search(src, py23_compat.text_type(dst)) return m is not None else: return src == dst
def get_ntp_stats(self): """ 'ntpq -np' output example remote refid st t when poll reach delay offset jitter ============================================================================== 116.91.118.97 133.243.238.244 2 u 51 64 377 5.436 987971. 1694.82 219.117.210.137 .GPS. 1 u 17 64 377 17.586 988068. 1652.00 133.130.120.204 133.243.238.164 2 u 46 64 377 7.717 987996. 1669.77 """ output = self.device.send_command("ntpq -np") output = output.split("\n")[2:] ntp_stats = list() for ntp_info in output: if len(ntp_info) > 0: remote, refid, st, t, when, hostpoll, reachability, delay, offset, \ jitter = ntp_info.split() # 'remote' contains '*' if the machine synchronized with NTP server synchronized = "*" in remote match = re.search("(\d+\.\d+\.\d+\.\d+)", remote) ip = match.group(1) when = when if when != '-' else 0 ntp_stats.append({ "remote": py23_compat.text_type(ip), "referenceid": py23_compat.text_type(refid), "synchronized": bool(synchronized), "stratum": int(st), "type": py23_compat.text_type(t), "when": py23_compat.text_type(when), "hostpoll": int(hostpoll), "reachability": int(reachability), "delay": float(delay), "offset": float(offset), "jitter": float(jitter) }) return ntp_stats
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 get_ntp_stats(self): """ 'ntpq -np' output example remote refid st t when poll reach delay offset jitter ============================================================================== 116.91.118.97 133.243.238.244 2 u 51 64 377 5.436 987971. 1694.82 219.117.210.137 .GPS. 1 u 17 64 377 17.586 988068. 1652.00 133.130.120.204 133.243.238.164 2 u 46 64 377 7.717 987996. 1669.77 """ output = self._send_command("ntpq -np") output = output.split("\n")[2:] ntp_stats = list() for ntp_info in output: if len(ntp_info) > 0: remote, refid, st, t, when, hostpoll, reachability, delay, offset, \ jitter = ntp_info.split() # 'remote' contains '*' if the machine synchronized with NTP server synchronized = "*" in remote match = re.search("(\d+\.\d+\.\d+\.\d+)", remote) ip = match.group(1) when = when if when != '-' else 0 ntp_stats.append({ "remote": py23_compat.text_type(ip), "referenceid": py23_compat.text_type(refid), "synchronized": bool(synchronized), "stratum": int(st), "type": py23_compat.text_type(t), "when": py23_compat.text_type(when), "hostpoll": int(hostpoll), "reachability": int(reachability), "delay": float(delay), "offset": float(offset), "jitter": float(jitter) }) return ntp_stats
def get_lldp_neighbors(self): lldp_neighbors = {} lldp_show = self.device.show('lldp', delim='@$@') lines = lldp_show.splitlines()[1:-1] for line in lines: neighbor_details = line.split('@$@') port = py23_compat.text_type(neighbor_details[1].strip()) port_id = py23_compat.text_type(neighbor_details[3].strip()) system_name = py23_compat.text_type(neighbor_details[6].strip()) if port_id not in lldp_neighbors.keys(): lldp_neighbors[port_id] = [] lldp_neighbors[port_id].append({ 'port': port, 'hostname': system_name }) return lldp_neighbors
def test_basic(self): d = driver("blah", "bleh", "blih", optional_args=optional_args) assert d.is_alive() == {u'is_alive': False} d.open() assert d.is_alive() == {u'is_alive': True} d.close() assert d.is_alive() == {u'is_alive': False} with pytest.raises(napalm_base.exceptions.ConnectionClosedException) as excinfo: d.get_facts() assert "connection closed" in py23_compat.text_type(excinfo.value)
def test_arguments(self): d = driver("blah", "bleh", "blih", optional_args=optional_args) d.open() with pytest.raises(TypeError) as excinfo: d.get_route_to(1, 2, 3) assert "get_route_to: expected at most 3 arguments, got 4" in py23_compat.text_type( excinfo.value) with pytest.raises(TypeError) as excinfo: d.get_route_to(1, 1, protocol=2) assert "get_route_to: expected at most 3 arguments, got 3" in py23_compat.text_type( excinfo.value) with pytest.raises(TypeError) as excinfo: d.get_route_to(proto=2) assert "get_route_to got an unexpected keyword argument 'proto'" in py23_compat.text_type( excinfo.value) d.close()
def cli(self, commands): cli_output = {} if type(commands) is not list: raise TypeError('Please provide a valid list of commands!') for command in commands: cli_output[py23_compat.text_type(command)] = self.device.cli(command) return cli_output
def get_ntp_peers(self): output = self.device.send_command("ntpq -np") output_peers = output.split("\n")[2:] ntp_peers = dict() for line in output_peers: if len(line) > 0: match = re.search("(\d+\.\d+\.\d+\.\d+)\s+", line) ntp_peers.update({py23_compat.text_type(match.group(1)): {}}) return ntp_peers
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 cli(self, commands): cli_output = {} if type(commands) is not list: raise TypeError('Please provide a valid list of commands!') for command in commands: cli_output[py23_compat.text_type(command)] = self.device.cli( command) return cli_output
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_ntp_peers(self): output = self._send_command("ntpq -np") output_peers = output.split("\n")[2:] ntp_peers = dict() for line in output_peers: if len(line) > 0: match = re.search("(\d+\.\d+\.\d+\.\d+)\s+", line) ntp_peers.update({ py23_compat.text_type(match.group(1)): {} }) return ntp_peers
def get_config(self, retrieve='all'): config = { 'startup': '', 'running': '', 'candidate': '' } # default values if retrieve.lower() in ['running', 'all']: config['running'] = py23_compat.text_type(self.device.show('running config')) # no startup as pluribus is WYSIWYG, no commit needed return config
def textfsm_extractor(cls, template_name, raw_text): """ Applies a TextFSM template over a raw text and return the matching table. Main usage of this method will be to extract data form a non-structured output from a network device and return the values in a table format. :param cls: Instance of the driver class :param template_name: Specifies the name of the template to be used :param raw_text: Text output as the devices prompts on the CLI :return: table-like list of entries """ textfsm_data = list() cls.__class__.__name__.replace('Driver', '') current_dir = os.path.dirname(os.path.abspath(sys.modules[cls.__module__].__file__)) template_dir_path = '{current_dir}/utils/textfsm_templates'.format( current_dir=current_dir ) template_path = '{template_dir_path}/{template_name}.tpl'.format( template_dir_path=template_dir_path, template_name=template_name ) try: fsm_handler = textfsm.TextFSM(open(template_path)) except IOError: raise napalm_base.exceptions.TemplateNotImplemented( "TextFSM template {template_name}.tpl is not defined under {path}".format( template_name=template_name, path=template_dir_path ) ) except textfsm.TextFSMTemplateError as tfte: raise napalm_base.exceptions.TemplateRenderException( "Wrong format of TextFSM template {template_name}: {error}".format( template_name=template_name, error=py23_compat.text_type(tfte) ) ) objects = fsm_handler.ParseText(raw_text) for obj in objects: index = 0 entry = {} for entry_value in obj: entry[fsm_handler.header[index].lower()] = entry_value index += 1 textfsm_data.append(entry) return textfsm_data
def get_facts(self): facts = {} try: self.device.op(cmd='<show><system><info></info></system></show>') system_info_xml = xmltodict.parse(self.device.xml_root()) system_info_json = json.dumps(system_info_xml['response']['result']['system']) system_info = json.loads(system_info_json) except AttributeError: system_info = {} try: self.device.op(cmd='<show><interface>all</interface></show>') interfaces_xml = xmltodict.parse(self.device.xml_root()) interfaces_json = json.dumps(interfaces_xml['response']['result']) interfaces = json.loads(interfaces_json) except AttributeError: interfaces = {} if system_info: facts['hostname'] = system_info['hostname'] facts['vendor'] = py23_compat.text_type('Palo Alto Networks') facts['uptime'] = int(convert_uptime_string_seconds(system_info['uptime'])) facts['os_version'] = system_info['sw-version'] facts['serial_number'] = system_info['serial'] facts['model'] = system_info['model'] facts['fqdn'] = py23_compat.text_type('N/A') facts['interface_list'] = [] for element in interfaces: for entry in interfaces[element]: for intf in interfaces[element][entry]: if intf['name'] not in facts['interface_list']: facts['interface_list'].append(intf['name']) facts['interface_list'].sort() return facts