def main(): """ Main execution routine """ description = ('Simple application that logs on to the APIC' ' and displays usage information for a given DN') creds = Credentials('apic', description) creds.add_argument("-d", "--dn_name", help="DN to query for usage information") args = creds.get() session = Session(args.url, args.login, args.password) resp = session.login() if not resp.ok: print('%% Could not login to APIC') url = '/api/mo/{}.json?query-target=children&target-subtree-class=relnFrom' url = url.format(args.dn_name) resp = session.get(url) if resp.ok: used_by = resp.json()['imdata'] for item in used_by: kls = next(iter(item)) attributes = item[kls]['attributes'] data.append((attributes['tDn'], kls)) print(tabulate(data, headers=["Used by", "Class"]))
def main(): """ Main Show VM Names Routine :return: None """ # Take login credentials from the command line if provided # Otherwise, take them from your environment variables file ~/.profile description = ('Simple application that logs on to the APIC' ' and displays all of the virtual machine names.') creds = Credentials('apic', description) args = creds.get() # Login to APIC session = Session(args.url, args.login, args.password) resp = session.login() if not resp.ok: print('%% Could not login to APIC') return # Make a direct call to the APIC REST API # Get all of the VMs (all objects of compVM class) and include the compVNic children # which contain the MAC address of the NIC. # The advantage of using acitoolkit Session.get() instead of direct Requests.get() calls # is that acitoolkit will automatically handle retries and pagination for queries with # large response data class_url = '/api/node/class/compVm.json?rsp-subtree=children&rsp-subtree-class=compVNic' ret = session.get(class_url) vm_list = ret.json()['imdata'] # Process the response. We're looking for the VM name and the associated vNIC MAC addresses. data = [] for vm in vm_list: vm_name = vm['compVm']['attributes']['name'] for vnic in vm['compVm']['children']: vm_mac = vnic['compVNic']['attributes']['mac'] # Store the VM name and MAC address. Note that VM names may be associated with # multiple MAC addresses if they have multiple vNICs. data.append((vm_name, vm_mac)) # Display the data downloaded print(tabulate(data, headers=["VMNAME", "MACADDRESS"]))
class FexCollector(object): def __init__(self, url, login, password): # Login to APIC self._apic = Session(url, login, password) if not self._apic.login().ok: self._logged_in = False print '%% Could not login to APIC' else: self._logged_in = True def _get_query(self, query_url, error_msg): resp = self._apic.get(query_url) if not resp.ok: print error_msg print resp.text return [] return resp.json()['imdata'] def get_fex_attributes(self, node_id, fex_id=None): if fex_id is None: query_url = ( '/api/mo/topology/pod-1/node-%s.json?query-target=subtree' '&target-subtree-class=satmDExtCh' % node_id) else: query_url = ( '/api/mo/topology/pod-1/node-%s.json?query-target=subtree' '&target-subtree-class=satmDExtCh&query-target-filter=eq(satmDExtCh.id, "%s")' % (node_id, fex_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_fabric_port_attributes(self, node_id, fex_id): query_url = ('/api/mo/topology/pod-1/node-%s.json?query-target=subtree' '&target-subtree-class=satmFabP&query-target-filter=' 'eq(satmFabP.extChId,"%s")' % (node_id, fex_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_transceiver_attributes(self, node_id, fab_port_id): query_url = ('/api/mo/topology/pod-1/node-%s/sys/satm/fabp-[%s].json?' 'query-target=subtree&target-subtree-class=satmRemoteFcot' ',satmRemoteFcotX2' % (node_id, fab_port_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_chassis_attributes(self, node_id, fex_id): query_url = '/api/mo/topology/pod-1/node-%s/sys/extch-%s.json' % ( node_id, fex_id) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_chassis_card_attributes(self, node_id, fex_id): query_url = ( '/api/mo/topology/pod-1/node-%s/sys/extch-%s.json?' 'query-target=subtree&target-subtree-class=eqptExtChCard' % (node_id, fex_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_chassis_running_attributes(self, node_id, fex_id): query_url = '/api/mo/topology/pod-1/node-%s/sys/extch-%s/running.json' % ( node_id, fex_id) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_chassis_cpu_attributes(self, node_id, fex_id): query_url = ('/api/mo/topology/pod-1/node-%s/sys/extch-%s.json?' 'query-target=subtree&target-subtree-class=eqptExtChCPU' % (node_id, fex_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_fex_ids(self, node_id): fex_attrs = self.get_fex_attributes(node_id) fex_ids = [] print fex_attrs for fex_attr in fex_attrs: fex_ids.append(str(fex_attr['satmDExtCh']['attributes']['id'])) return fex_ids def get_node_ids(self, node_id): """ Get the list of node ids from the command line arguments. If none, get all of the node ids :param args: Command line arguments :return: List of strings containing node ids """ if node_id is not None: names = [node_id] else: names = [] query_url = ('/api/node/class/fabricNode.json?' 'query-target-filter=eq(fabricNode.role,"leaf")') error_message = 'Could not get switch list from APIC.' nodes = self._get_query(query_url, error_message) for node in nodes: names.append(str(node['fabricNode']['attributes']['id'])) return names @staticmethod def print_fex(fex_attr, chassis_attr, detail=False): print 'FEX:%s Description: FEX0%s state: %s' % ( fex_attr['id'], fex_attr['id'], fex_attr['operSt']) print ' FEX version: %s [Switch version: %s]' % (fex_attr['ver'], fex_attr['swVer']) if detail: print ' FEX Interim version:', fex_attr['intVer'] print ' Switch Interim version:', fex_attr['swIntVer'] print ' Extender Model: %s, Extender Serial: %s' % (fex_attr['model'], fex_attr['ser']) print ' Part No:', chassis_attr['partNum'] if detail: print ' Card Id: %s,' % fex_attr['swCId'] print 'Mac Addr: %s,' % fex_attr['macAddr'] print 'Num Macs:', fex_attr['numMacs'] print ' Module Sw Gen:', fex_attr['swGen'] print ' [Switch Sw Gen: %s]' % fex_attr['swSwGen'] print ' pinning-mode: static Max-links: 1' print ' Fabric port for control traffic:', fex_attr['controlFPort'] @staticmethod def convert_to_ascii(data): data = str(data).split(',') resp = '' for letter in data: resp += str(unichr(int(letter))) return resp def print_fex_transceiver(self, node_id, fex_id): if fex_id is None: fex_ids = self.get_fex_ids(node_id) else: fex_ids = [fex_id] for fex_id in fex_ids: fab_port_num = 1 fab_ports = self.get_fabric_port_attributes(node_id, fex_id) for fab_port in fab_ports: fab_port_attr = fab_port['satmFabP']['attributes'] if fab_port_attr['id'].startswith('po'): continue print 'Fex Uplink:', fab_port_num print ' Fabric Port :', fab_port_attr['id'] if 'fcot-present' in fab_port_attr['flags']: transceiver_attr = self.get_transceiver_attributes( node_id, str(fab_port_attr['id'])) try: transceiver_attr = transceiver_attr[0][ 'satmRemoteFcot']['attributes'] except KeyError: raise NotImplementedError # probably satmRemoteFcotV2 print ' sfp is present' print ' name is', self.convert_to_ascii( transceiver_attr['vendorName']) print ' type is', transceiver_attr['typeName'] print ' part number is', self.convert_to_ascii( transceiver_attr['vendorPn']) print ' revision is', self.convert_to_ascii( transceiver_attr['vendorRev']) print ' serial number is', self.convert_to_ascii( transceiver_attr['vendorSn']) print ' nominal bitrate is %s MBits/sec' % str( int(transceiver_attr['brIn100MHz']) * 100) print ' Link length supported for 50/125mm fiber is 0 m(s)' print ' Link length supported for 62.5/125mm fiber is 0 m(s)' print ' Link length supported for copper is %s m' % transceiver_attr[ 'distIn1mForCu'] print ' cisco id is', transceiver_attr['xcvrId'] print ' cisco extended id number is', transceiver_attr[ 'xcvrExtId'] fab_port_num += 1 def print_fex_version(self, node_id, fex_id): if fex_id is None: fex_ids = self.get_fex_ids(node_id) else: fex_ids = [fex_id] for fex_id in fex_ids: chassis_attr = self.get_chassis_attributes(node_id, fex_id) chassis_attr = chassis_attr[0]['eqptExtCh']['attributes'] chassis_running_attr = self.get_chassis_running_attributes( node_id, fex_id) chassis_running_attr = chassis_running_attr[0][ 'firmwareExtChRunning']['attributes'] card_attr = self.get_chassis_card_attributes(node_id, fex_id) card_attr = card_attr[0]['eqptExtChCard']['attributes'] fex_attr = self.get_fex_attributes(node_id, fex_id) fex_attr = fex_attr[0]['satmDExtCh']['attributes'] cpu_attr = self.get_chassis_cpu_attributes(node_id, fex_id) cpu_attr = cpu_attr[0]['eqptExtChCPU']['attributes'] print 'Software' print ' Bootloader version: %s' % chassis_running_attr[ 'loaderVer'] print ' System boot mode: primary' print ' System image version: %s [build %s]' % ( fex_attr['ver'], fex_attr['intVer']) print '\nHardware' print ' Module: %s' % card_attr['descr'] print ' CPU: %s' % cpu_attr['model'] print ' Serial number: %s' % card_attr['modSerial'] print ' Bootflash: locked' # TODO: Finish - need to add timestamping def show_fex(self, node=None, fex_id=None, detail=False, transceiver=False, version=False): """ Show fex :param fex_id: String containing the specific FEX id. If none, all FEXs are used :param detail: Boolean indicating whether a detailed report should be given. :param transceiver: Boolean indicating whether a transceiver report should be given. :param version: Boolean indicating whether a version report should be given. :return: None """ for node_id in self.get_node_ids(node): if fex_id is None: if not (detail or transceiver or version): # Show fex data = [] for fex in self.get_fex_attributes(node_id): fex_attr = fex['satmDExtCh']['attributes'] data.append( (int(fex_attr['id']), 'FEX0' + str(fex_attr['id']), fex_attr['operSt'], fex_attr['model'], fex_attr['ser'])) data.sort(key=lambda tup: tup[0]) if len(data): print 'Switch:', node_id print tabulate(data, headers=[ 'Number', 'Description', 'State', 'Model', 'Serial' ]) print '\n' elif detail: # Show fex detail fex_ids = self.get_fex_ids(node_id) for fex_id in fex_ids: self.print_show_fex(node_id, fex_id, detailed=True) elif transceiver: self.print_fex_transceiver(node_id, None) elif detail: # Show fex <fex_id> detail self.print_show_fex(node_id, fex_id, detailed=True) elif transceiver: # Show fex <fex_id> transceiver self.print_fex_transceiver(node_id, fex_id) elif version: # Show fex <fex_id> version self.print_fex_version(node_id, fex_id) else: # Show fex <fex_id> self.print_show_fex(node_id, fex_id) def print_show_fex(self, node_id, fex_id, detailed=False): for fex in self.get_fex_attributes(node_id, fex_id): fex_attr = fex['satmDExtCh']['attributes'] for chassis in self.get_chassis_attributes(node_id, fex_attr['id']): chassis_attr = chassis['eqptExtCh']['attributes'] self.print_fex(fex_attr, chassis_attr) query_url = ( '/api/mo/topology/pod-1/node-%s.json?query-target=subtree' '&target-subtree-class=satmFabP&query-target-filter=eq(satmFabP.extChId,"%s")' % (node_id, fex_attr['id'])) resp = self._apic.get(query_url) if not resp.ok: print 'Could not collect APIC data for switch %s.' % node_id print resp.text return if int(resp.json()['totalCount']) > 0: print ' Fabric interface state:' for interface in resp.json()['imdata']: intf_attr = interface['satmFabP']['attributes'] print ' %15s - Interface %4s. State: %s' % ( intf_attr['id'], intf_attr['operSt'], intf_attr['fsmSt']) if detailed: query_url = ( '/api/mo/topology/pod-1/node-%s/sys/satm/fabp-[%s].json?query-target=subtree' '&target-subtree-class=satmHostP' % (node_id, intf_attr['id'])) resp = self._apic.get(query_url) if not resp.ok: print 'Could not collect APIC data for switch %s.' % node_id print resp.text return if int(resp.json()['totalCount']) > 0: data = [] for port in resp.json()['imdata']: port_attr = port['satmHostP']['attributes'] data.append( (port_attr['id'], port_attr['operSt'], port_attr['fabricPort'])) data.sort(key=lambda tup: tup[0]) print tabulate(data, headers=[ 'Fex Port', 'State', 'Fabric Port' ])
def main(): """ Main execution routine :return: None """ # Take login credentials from the command line if provided # Otherwise, take them from your environment variables file ~/.profile description = 'Simple application that logs on to the APIC and displays all of the Interfaces.' creds = Credentials('apic', description) creds.add_argument('--tenant', help='The name of Tenant') args = creds.get() # Login to APIC session = Session(args.url, args.login, args.password) resp = session.login() if not resp.ok: print('%% Could not login to APIC') sys.exit(0) resp = session.get('/api/class/ipv4Addr.json') intfs = json.loads(resp.text)['imdata'] for i in intfs: ip = i['ipv4Addr']['attributes']['addr'] op = i['ipv4Addr']['attributes']['operSt'] cfg = i['ipv4Addr']['attributes']['operStQual'] dn = i['ipv4Addr']['attributes']['dn'] node = dn.split('/')[2] intf = re.split(r'\[|\]', dn)[1] vrf = re.split(r'/|dom-', dn)[7] tn = vrf if vrf.find(":") != -1: tn = re.search("(.*):(.*)", vrf).group(1) check_longest_name(node, "Node") check_longest_name(intf, "Interface") check_longest_name(ip, "IP Address") check_longest_name(cfg, "Admin Status") check_longest_name(op, "Status") if args.tenant is None: if vrf not in data.keys(): data[vrf] = [] else: data[vrf].append((node, intf, ip, cfg, op)) else: if tn == args.tenant: if vrf not in data.keys(): data[vrf] = [] else: data[vrf].append((node, intf, ip, cfg, op)) for k in data.keys(): header = 'IP Interface Status for VRF "{}"'.format(k) print(header) template = '{0:' + str(longest_names["Node"]) + '} ' \ '{1:' + str(longest_names["Interface"]) + '} ' \ '{2:' + str(longest_names["IP Address"]) + '} ' \ '{3:' + str(longest_names["Admin Status"]) + '} ' \ '{4:' + str(longest_names["Status"]) + '}' print(template.format("Node", "Interface", "IP Address", "Admin Status", "Status")) print(template.format('-' * longest_names["Node"], '-' * longest_names["Interface"], '-' * longest_names["IP Address"], '-' * longest_names["Admin Status"], '-' * longest_names["Status"])) for rec in sorted(data[k]): print(template.format(*rec)) print('')
sys.exit(0) while True: try: inputnode = input("Enter the Node ID: ") if (len(inputnode) == 4): nodeidint = int(inputnode) break else: print("Node ID is INVALID ! try again") continue except ValueError: print("INVALID IP address ! Enter Numeric values only") resp = session.get( "/api/class/fvRsPathAtt.json?query-target-filter=wcard(fvRsPathAtt.tDn,\"" + inputnode + "\")") data = json.loads(resp.text)['imdata'] datacount = int(json.loads(resp.text)['totalCount']) fname = "EPG_Static_Ports_" + inputnode + ".csv" #fname = "EPGpathsdetailsapinode.csv" with open(fname, "w", newline='') as file: csv_file = csv.writer(file) csv_file.writerow( ["Tenant", "APP_Profile", "EPG_Name", "Node", "port", "encap", "Mode"]) numrow = 0 for i in data: itemone = (((i['fvRsPathAtt'])['attributes']))
# Take login credentials from the command line if provided # Otherwise, take them from your environment variables file ~/.profile description = 'Simple application that logs on to the APIC and extracts Node IDs, Node names and their serial numbers.' creds = Credentials('apic', description) creds.add_argument('--tenant', help='The name of Tenant') args = creds.get() # Login to APIC session = Session(args.url, args.login, args.password) resp = session.login() if not resp.ok: print('%% Could not login to APIC') sys.exit(0) resp = session.get( '/api/class/fabricNodeIdentP.json?rsp-subtree=full&rsp-prop-include=config-only' ) data = json.loads(resp.text)['imdata'] datacount = int(json.loads(resp.text)['totalCount']) fname = "NodeReginfo.csv" with open(fname, "w", newline='') as file: csv_file = csv.writer(file) csv_file.writerow(["Node ID", "Node Name", "Serial Number"]) numrow = 0 for i in data: itemone = (((i['fabricNodeIdentP'])['attributes'])) dnstr = itemone['dn'] nodename = itemone['name']
# Take login credentials from the command line if provided # Otherwise, take them from your environment variables file ~/.profile description = 'Application that logs on to the APIC, and extracts the BD information to a csv file. Only first 3 IP Subnets for a BD will be shown' creds = Credentials('apic', description) creds.add_argument('--tenant', help='The name of Tenant') args = creds.get() # Login to APIC session = Session(args.url, args.login, args.password) resp = session.login() if not resp.ok: print('%% Could not login to APIC') sys.exit(0) resp = session.get( '/api/class/fvBD.json?rsp-subtree=full&rsp-prop-include=config-only&order-by=fvBD.name' ) data = json.loads(resp.text)['imdata'] datacount = int(json.loads(resp.text)['totalCount']) #with open("./BDinfo.json") as file: # data = json.load(file)['imdata'] fname = "Bridge_Domain_Details.csv" with open(fname, "w", newline='') as file: csv_file = csv.writer(file) csv_file.writerow([ "Tenant", "BD Name", "Description", "ARP Flooding", "IP Learning", "LimitIPLearnToSubnets", "Unicast Routing", "UnknownMacUnicastAct", "IP_Subnet-1", "Subnet-1_Scope", "IP_Subnet-2", "Subnet-2_Scope",
class InterfaceBriefCollector(object): def __init__(self, url, login, password): # Login to APIC self._apic = Session(url, login, password) self._if_brief_headers = { 'l1PhysIf': ['Ethernet Interface', 'VLAN', 'Type', 'Mode', 'Status', 'Reason', 'Speed', 'Port Ch #'], 'pcAggrIf': ['Port-channel Interface', 'VLAN', 'Type', 'Mode', 'Status', 'Reason', 'Speed', 'Protocol'], 'l3LbRtdIf': ['Interface', 'Status', 'Description'], 'tunnelIf': ['Interface', 'Status', 'IP Address', 'Encap type', 'MTU'], 'sviIf': ['Interface', 'Secondary VLAN(Type)', 'Status', 'Reason'], 'l3EncRtdIf': [], 'mgmtMgmtIf': ['Port', 'VRF', 'Status', 'IP Address', 'Speed', 'MTU'], 'l2ExtIf': [], 'l2VfcIf': ['Interface', 'Vsan', 'Admin\nMode', 'Admin Trunk Mode', 'Status', 'Bind Info', 'Oper Mode', 'Oper Speed (Gbps)'] } self._if_types = self._if_brief_headers.keys() if not self._apic.login().ok: self._logged_in = False print '%% Could not login to APIC' else: self._logged_in = True self._interfaces = [] @property def _all_if_types_as_string(self): resp = '' for if_type in self._if_types: if len(resp): resp += ',' resp += if_type return resp def _get_query(self, query_url, error_msg): resp = self._apic.get(query_url) if not resp.ok: print error_msg print resp.text return [] return resp.json()['imdata'] def populate_interfaces(self, node_id, intf_id=None): query_url = ('/api/mo/topology/pod-1/node-%s/sys.json?query-target=subtree' '&target-subtree-class=%s&rsp-subtree=children&' 'rsp-subtree-class=ethpmPhysIf,l1RtMbrIfs,ethpmAggrIf' % (node_id, self._all_if_types_as_string)) error_message = 'Could not collect APIC data for switch %s.' % node_id interfaces = self._get_query(query_url, error_message) if intf_id is None: self._interfaces = interfaces else: self._interfaces = [] for interface in interfaces: for if_type in interface: if interface[if_type]['attributes']['id'] == intf_id: self._interfaces.append(interface) def _has_interface_type(self, if_type, intf_id=None): for interface in self._interfaces: if if_type in interface: if intf_id is None or intf_id == interface[if_type]['attributes']['id']: return True return False def _get_interface_type(self, if_type): resp = [] for interface in self._interfaces: if if_type in interface: resp.append(interface) return resp def get_node_ids(self, node_id): """ Get the list of node ids from the command line arguments. If none, get all of the node ids :param args: Command line arguments :return: List of strings containing node ids """ if node_id is not None: names = [node_id] else: names = [] query_url = ('/api/node/class/fabricNode.json?' 'query-target-filter=eq(fabricNode.role,"leaf")') error_message = 'Could not get switch list from APIC.' nodes = self._get_query(query_url, error_message) for node in nodes: names.append(str(node['fabricNode']['attributes']['id'])) return names @staticmethod def convert_to_ascii(data): data = str(data).split(',') resp = '' for letter in data: resp += str(unichr(int(letter))) return resp def _get_interface_type_brief_data(self, if_type, intf_id=None): data = [] for interface in self._interfaces: if if_type in interface: if intf_id is not None and intf_id != interface[if_type]['attributes']['id']: continue if_attrs = interface[if_type]['attributes'] if if_type == 'mgmtMgmtIf': data.append((if_attrs['id'], '--', if_attrs['adminSt'], '', if_attrs['speed'], if_attrs['mtu'])) elif if_type == 'l1PhysIf': port_channel = '--' for child in interface[if_type]['children']: if 'l1RtMbrIfs' in child: port_channel = child['l1RtMbrIfs']['attributes']['tSKey'] else: oper_attrs = child['ethpmPhysIf']['attributes'] data.append((if_attrs['id'], '--', 'eth', oper_attrs['operMode'], oper_attrs['operSt'], oper_attrs['operStQual'], oper_attrs['operSpeed'], port_channel)) elif if_type == 'tunnelIf': data.append((if_attrs['id'], if_attrs['operSt'], '--', if_attrs['tType'], if_attrs['cfgdMtu'])) elif if_type == 'pcAggrIf': for child in interface[if_type]['children']: protocol = '--' if if_attrs['pcMode'] in ['active', 'passive', 'mac-pin']: protocol = 'lacp' elif if_attrs['pcMode'] == 'static': protocol = 'none' if 'ethpmAggrIf' in child: oper_attrs = child['ethpmAggrIf']['attributes'] data.append((if_attrs['id'], '--', 'eth', oper_attrs['operMode'], oper_attrs['operSt'], oper_attrs['operStQual'], oper_attrs['operSpeed'], protocol)) elif if_type == 'sviIf': data.append((if_attrs['id'], '--', if_attrs['operSt'], if_attrs['operStQual'])) elif if_type == 'l3LbRtdIf': if len(if_attrs['descr']): description = if_attrs['descr'] else: description = '--' data.append((if_attrs['id'], if_attrs['adminSt'], description)) elif if_type == 'l2VfcIf': raise NotImplementedError # TODO: finish this return data def show_brief(self, node=None, intf_id=None): """ show interface brief :param node: String containing the specific switch id. If none, all switches are used :param intf_id: String containing the specific interface id. If none, all interfaces are used :return: None """ for node_id in self.get_node_ids(node): self.populate_interfaces(node_id, intf_id) for if_type in self._if_types: if self._has_interface_type(if_type, intf_id): data = self._get_interface_type_brief_data(if_type, intf_id) data.sort(key=lambda tup: tup[0]) if len(data): print tabulate(data, headers=self._if_brief_headers[if_type]) print
class FexCollector(object): def __init__(self, url, login, password): # Login to APIC self._apic = Session(url, login, password) if not self._apic.login().ok: self._logged_in = False print '%% Could not login to APIC' else: self._logged_in = True def _get_query(self, query_url, error_msg): resp = self._apic.get(query_url) if not resp.ok: print error_msg print resp.text return [] return resp.json()['imdata'] def get_fex_attributes(self, node_id, fex_id=None): if fex_id is None: query_url = ('/api/mo/topology/pod-1/node-%s.json?query-target=subtree' '&target-subtree-class=satmDExtCh' % node_id) else: query_url = ('/api/mo/topology/pod-1/node-%s.json?query-target=subtree' '&target-subtree-class=satmDExtCh&query-target-filter=eq(satmDExtCh.id, "%s")' % (node_id, fex_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_fabric_port_attributes(self, node_id, fex_id): query_url = ('/api/mo/topology/pod-1/node-%s.json?query-target=subtree' '&target-subtree-class=satmFabP&query-target-filter=' 'eq(satmFabP.extChId,"%s")' % (node_id, fex_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_transceiver_attributes(self, node_id, fab_port_id): query_url = ('/api/mo/topology/pod-1/node-%s/sys/satm/fabp-[%s].json?' 'query-target=subtree&target-subtree-class=satmRemoteFcot' ',satmRemoteFcotX2' % (node_id, fab_port_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_chassis_attributes(self, node_id, fex_id): query_url = '/api/mo/topology/pod-1/node-%s/sys/extch-%s.json' % (node_id, fex_id) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_chassis_card_attributes(self, node_id, fex_id): query_url = ('/api/mo/topology/pod-1/node-%s/sys/extch-%s.json?' 'query-target=subtree&target-subtree-class=eqptExtChCard' % (node_id, fex_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_chassis_running_attributes(self, node_id, fex_id): query_url = '/api/mo/topology/pod-1/node-%s/sys/extch-%s/running.json' % (node_id, fex_id) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_chassis_cpu_attributes(self, node_id, fex_id): query_url = ('/api/mo/topology/pod-1/node-%s/sys/extch-%s.json?' 'query-target=subtree&target-subtree-class=eqptExtChCPU' % (node_id, fex_id)) error_message = 'Could not collect APIC data for switch %s.' % node_id return self._get_query(query_url, error_message) def get_fex_ids(self, node_id): fex_attrs = self.get_fex_attributes(node_id) fex_ids = [] print fex_attrs for fex_attr in fex_attrs: fex_ids.append(str(fex_attr['satmDExtCh']['attributes']['id'])) return fex_ids def get_node_ids(self, node_id): """ Get the list of node ids from the command line arguments. If none, get all of the node ids :param args: Command line arguments :return: List of strings containing node ids """ if node_id is not None: names = [node_id] else: names = [] query_url = ('/api/node/class/fabricNode.json?' 'query-target-filter=eq(fabricNode.role,"leaf")') error_message = 'Could not get switch list from APIC.' nodes = self._get_query(query_url, error_message) for node in nodes: names.append(str(node['fabricNode']['attributes']['id'])) return names @staticmethod def print_fex(fex_attr, chassis_attr, detail=False): print 'FEX:%s Description: FEX0%s state: %s' % (fex_attr['id'], fex_attr['id'], fex_attr['operSt']) print ' FEX version: %s [Switch version: %s]' % (fex_attr['ver'], fex_attr['swVer']) if detail: print ' FEX Interim version:', fex_attr['intVer'] print ' Switch Interim version:', fex_attr['swIntVer'] print ' Extender Model: %s, Extender Serial: %s' % (fex_attr['model'], fex_attr['ser']) print ' Part No:', chassis_attr['partNum'] if detail: print ' Card Id: %s,' % fex_attr['swCId'] print 'Mac Addr: %s,' % fex_attr['macAddr'] print 'Num Macs:', fex_attr['numMacs'] print ' Module Sw Gen:', fex_attr['swGen'] print ' [Switch Sw Gen: %s]' % fex_attr['swSwGen'] print ' pinning-mode: static Max-links: 1' print ' Fabric port for control traffic:', fex_attr['controlFPort'] @staticmethod def convert_to_ascii(data): data = str(data).split(',') resp = '' for letter in data: resp += str(unichr(int(letter))) return resp def print_fex_transceiver(self, node_id, fex_id): if fex_id is None: fex_ids = self.get_fex_ids(node_id) else: fex_ids = [fex_id] for fex_id in fex_ids: fab_port_num = 1 fab_ports = self.get_fabric_port_attributes(node_id, fex_id) for fab_port in fab_ports: fab_port_attr = fab_port['satmFabP']['attributes'] if fab_port_attr['id'].startswith('po'): continue print 'Fex Uplink:', fab_port_num print ' Fabric Port :', fab_port_attr['id'] if 'fcot-present' in fab_port_attr['flags']: transceiver_attr = self.get_transceiver_attributes(node_id, str(fab_port_attr['id'])) try: transceiver_attr = transceiver_attr[0]['satmRemoteFcot']['attributes'] except KeyError: raise NotImplementedError # probably satmRemoteFcotV2 print ' sfp is present' print ' name is', self.convert_to_ascii(transceiver_attr['vendorName']) print ' type is', transceiver_attr['typeName'] print ' part number is', self.convert_to_ascii(transceiver_attr['vendorPn']) print ' revision is', self.convert_to_ascii(transceiver_attr['vendorRev']) print ' serial number is', self.convert_to_ascii(transceiver_attr['vendorSn']) print ' nominal bitrate is %s MBits/sec' % str(int(transceiver_attr['brIn100MHz']) * 100) print ' Link length supported for 50/125mm fiber is 0 m(s)' print ' Link length supported for 62.5/125mm fiber is 0 m(s)' print ' Link length supported for copper is %s m' % transceiver_attr['distIn1mForCu'] print ' cisco id is', transceiver_attr['xcvrId'] print ' cisco extended id number is', transceiver_attr['xcvrExtId'] fab_port_num += 1 def print_fex_version(self, node_id, fex_id): if fex_id is None: fex_ids = self.get_fex_ids(node_id) else: fex_ids = [fex_id] for fex_id in fex_ids: chassis_attr = self.get_chassis_attributes(node_id, fex_id) chassis_attr = chassis_attr[0]['eqptExtCh']['attributes'] chassis_running_attr = self.get_chassis_running_attributes(node_id, fex_id) chassis_running_attr = chassis_running_attr[0]['firmwareExtChRunning']['attributes'] card_attr = self.get_chassis_card_attributes(node_id, fex_id) card_attr = card_attr[0]['eqptExtChCard']['attributes'] fex_attr = self.get_fex_attributes(node_id, fex_id) fex_attr = fex_attr[0]['satmDExtCh']['attributes'] cpu_attr = self.get_chassis_cpu_attributes(node_id, fex_id) cpu_attr = cpu_attr[0]['eqptExtChCPU']['attributes'] print 'Software' print ' Bootloader version: %s' % chassis_running_attr['loaderVer'] print ' System boot mode: primary' print ' System image version: %s [build %s]' % (fex_attr['ver'], fex_attr['intVer']) print '\nHardware' print ' Module: %s' % card_attr['descr'] print ' CPU: %s' % cpu_attr['model'] print ' Serial number: %s' % card_attr['modSerial'] print ' Bootflash: locked' # TODO: Finish - need to add timestamping def show_fex(self, node=None, fex_id=None, detail=False, transceiver=False, version=False): """ Show fex :param fex_id: String containing the specific FEX id. If none, all FEXs are used :param detail: Boolean indicating whether a detailed report should be given. :param transceiver: Boolean indicating whether a transceiver report should be given. :param version: Boolean indicating whether a version report should be given. :return: None """ for node_id in self.get_node_ids(node): if fex_id is None: if not (detail or transceiver or version): # Show fex data = [] for fex in self.get_fex_attributes(node_id): fex_attr = fex['satmDExtCh']['attributes'] data.append((int(fex_attr['id']), 'FEX0' + str(fex_attr['id']), fex_attr['operSt'], fex_attr['model'], fex_attr['ser'])) data.sort(key=lambda tup: tup[0]) if len(data): print 'Switch:', node_id print tabulate(data, headers=['Number', 'Description', 'State', 'Model', 'Serial']) print '\n' elif detail: # Show fex detail fex_ids = self.get_fex_ids(node_id) for fex_id in fex_ids: self.print_show_fex(node_id, fex_id, detailed=True) elif transceiver: self.print_fex_transceiver(node_id, None) elif detail: # Show fex <fex_id> detail self.print_show_fex(node_id, fex_id, detailed=True) elif transceiver: # Show fex <fex_id> transceiver self.print_fex_transceiver(node_id, fex_id) elif version: # Show fex <fex_id> version self.print_fex_version(node_id, fex_id) else: # Show fex <fex_id> self.print_show_fex(node_id, fex_id) def print_show_fex(self, node_id, fex_id, detailed=False): for fex in self.get_fex_attributes(node_id, fex_id): fex_attr = fex['satmDExtCh']['attributes'] for chassis in self.get_chassis_attributes(node_id, fex_attr['id']): chassis_attr = chassis['eqptExtCh']['attributes'] self.print_fex(fex_attr, chassis_attr) query_url = ('/api/mo/topology/pod-1/node-%s.json?query-target=subtree' '&target-subtree-class=satmFabP&query-target-filter=eq(satmFabP.extChId,"%s")' % ( node_id, fex_attr['id'])) resp = self._apic.get(query_url) if not resp.ok: print 'Could not collect APIC data for switch %s.' % node_id print resp.text return if int(resp.json()['totalCount']) > 0: print ' Fabric interface state:' for interface in resp.json()['imdata']: intf_attr = interface['satmFabP']['attributes'] print ' %15s - Interface %4s. State: %s' % (intf_attr['id'], intf_attr['operSt'], intf_attr['fsmSt']) if detailed: query_url = ('/api/mo/topology/pod-1/node-%s/sys/satm/fabp-[%s].json?query-target=subtree' '&target-subtree-class=satmHostP' % (node_id, intf_attr['id'])) resp = self._apic.get(query_url) if not resp.ok: print 'Could not collect APIC data for switch %s.' % node_id print resp.text return if int(resp.json()['totalCount']) > 0: data = [] for port in resp.json()['imdata']: port_attr = port['satmHostP']['attributes'] data.append((port_attr['id'], port_attr['operSt'], port_attr['fabricPort'])) data.sort(key=lambda tup: tup[0]) print tabulate(data, headers=['Fex Port', 'State', 'Fabric Port'])
# Otherwise, take them from your environment variables file ~/.profile description = 'Application that logs on to the APIC, and extracts the L3outs paths along with their vlan encap and IP addresses' creds = Credentials('apic', description) creds.add_argument('--tenant', help='The name of Tenant') args = creds.get() # Login to APIC session = Session(args.url, args.login, args.password) resp = session.login() if not resp.ok: print('%% Could not login to APIC') sys.exit(0) resp = session.get( '/api/class/l3extRsPathL3OutAtt.json?rsp-subtree=full&rsp-prop-include=config-only&order-by=l3extRsPathL3OutAtt.dn' ) data = json.loads(resp.text)['imdata'] datacount = int(json.loads(resp.text)['totalCount']) #with open("./tt1l3outpaths.json") as file: # data = json.load(file)['imdata'] fname = "L3out_paths_IP.csv" with open(fname, "w", newline='') as file: csv_file = csv.writer(file) csv_file.writerow([ "Tenant", "L3OUT Name", "Logical Node Profile", "Logical Interface Profile", "If inst type", "Node ID", "Port ID", "vlan encap", "IP address", "VIP", "SIDE A IP address",
def main(): """ Main execution routine :return: None """ # Take login credentials from the command line if provided # Otherwise, take them from your environment variables file ~/.profile description = 'Simple application that logs on to the APIC and displays all of the Interfaces.' creds = Credentials('apic', description) creds.add_argument('--tenant', help='The name of Tenant') args = creds.get() # Login to APIC session = Session(args.url, args.login, args.password) resp = session.login() if not resp.ok: print('%% Could not login to APIC') sys.exit(0) resp = session.get('/api/class/ipv4Addr.json') intfs = json.loads(resp.text)['imdata'] for i in intfs: ip = i['ipv4Addr']['attributes']['addr'] op = i['ipv4Addr']['attributes']['operSt'] cfg = i['ipv4Addr']['attributes']['operStQual'] dn = i['ipv4Addr']['attributes']['dn'] node = dn.split('/')[2] intf = re.split(r'\[|\]', dn)[1] vrf = re.split(r'/|dom-', dn)[7] tn = vrf if vrf.find(":") != -1: tn = re.search("(.*):(.*)", vrf).group(1) check_longest_name(node, "Node") check_longest_name(intf, "Interface") check_longest_name(ip, "IP Address") check_longest_name(cfg, "Admin Status") check_longest_name(op, "Status") if args.tenant is None: if vrf not in data.keys(): data[vrf] = [] else: data[vrf].append((node, intf, ip, cfg, op)) else: if tn == args.tenant: if vrf not in data.keys(): data[vrf] = [] else: data[vrf].append((node, intf, ip, cfg, op)) for k in data.keys(): header = 'IP Interface Status for VRF "{}"'.format(k) print(header) template = '{0:' + str(longest_names["Node"]) + '} ' \ '{1:' + str(longest_names["Interface"]) + '} ' \ '{2:' + str(longest_names["IP Address"]) + '} ' \ '{3:' + str(longest_names["Admin Status"]) + '} ' \ '{4:' + str(longest_names["Status"]) + '}' print( template.format("Node", "Interface", "IP Address", "Admin Status", "Status")) print( template.format('-' * longest_names["Node"], '-' * longest_names["Interface"], '-' * longest_names["IP Address"], '-' * longest_names["Admin Status"], '-' * longest_names["Status"])) for rec in sorted(data[k]): print(template.format(*rec)) print('')
class InterfaceDetailedCollector(object): def __init__(self, url, login, password): # Login to APIC self._apic = Session(url, login, password) if not self._apic.login().ok: self._logged_in = False print '%% Could not login to APIC' else: self._logged_in = True self._interfaces = [] def _get_query(self, query_url, error_msg): resp = self._apic.get(query_url) if not resp.ok: print error_msg print resp.text return [] return resp.json()['imdata'] def _populate_beacon_states(self, data): for beacon_data in data: if 'eqptLocLed' not in beacon_data: continue dn = beacon_data['eqptLocLed']['attributes']['dn'] oper_state = beacon_data['eqptLocLed']['attributes']['operSt'] if 'leafport-' in dn: port_num = dn.partition('/leafport-')[2].partition('/')[0] mod_num = dn.partition('/lcslot-')[2].partition('/')[0] node_num = dn.partition('/node-')[2].partition('/')[0] beacon_interface_id = 'eth' + mod_num + '/' + port_num beacon_node_id = '/node-%s/' % node_num for interface in self._interfaces: if not interface.is_ether(): continue if interface.id == beacon_interface_id: if beacon_node_id in dn: interface.beacon_state = oper_state def populate_detailed_interfaces(self, node_id, intf_id=None): query_url = ('/api/mo/topology/pod-1/node-%s/sys.json?query-target=subtree' '&target-subtree-class=l1PhysIf,pcAggrIf,l3LbRtdIf,tunnelIf,sviIf,l3EncRtdIf,' 'mgmtMgmtIf,l2ExtIf,l2VfcIf,eqptLocLed&rsp-subtree=full&' 'rsp-subtree-class=ethpmPhysIf,ethpmPortCap,l1RtMbrIfs,ethpmAggrIf,' 'rmonEtherStats,rmonIfIn,rmonIfOut,rmonIfStorm,eqptIngrTotal5min,' 'eqptEgrTotal5min,l1EeeP,rmonDot3Stats' % node_id) error_message = 'Could not collect APIC data for switch %s.' % node_id interfaces = self._get_query(query_url, error_message) self._interfaces = [] if intf_id is None: for interface in interfaces: self._interfaces.append(Interface(interface)) else: for interface in interfaces: for if_type in interface: if if_type == 'eqptLocLed': continue if interface[if_type]['attributes']['id'] == intf_id: self._interfaces.append(Interface(interface)) self._populate_beacon_states(interfaces) def get_node_ids(self, node_id): """ Get the list of node ids from the command line arguments. If none, get all of the node ids :param args: Command line arguments :return: List of strings containing node ids """ if node_id is not None: names = [node_id] else: names = [] query_url = ('/api/node/class/fabricNode.json?' 'query-target-filter=eq(fabricNode.role,"leaf")') error_message = 'Could not get switch list from APIC.' nodes = self._get_query(query_url, error_message) for node in nodes: names.append(str(node['fabricNode']['attributes']['id'])) return names def show_detailed(self, node=None, intf_id=None): """ show interface :param node: String containing the specific switch id. If none, all switches are used :param intf_id: String containing the specific interface id. If none, all interfaces are used :return: None """ for node_id in self.get_node_ids(node): print 'Switch', node_id self.populate_detailed_interfaces(node_id, intf_id) for interface in self._interfaces: if interface.if_type == 'l1PhysIf': if interface.is_ether or interface.is_pc() or interface.is_tun(): state = interface.oper_st rsn = interface.oper_st_qual if state is None: state = "unknown" rsn = "unknown" if state == 'link-up': # see ethpm_copy_eth_port_log_info() # link-up state is physical up, but not operationally up state = 'down' if state == 'up': if not interface.is_tun() and interface.switching_st == 'disabled': print "%s is %s (%s)" % (interface.id, state, "out-of-service") else: print "%s is %s" % (interface.id, state) elif interface.oper_st_qual == "err-disabled": print "%s is %s (%s)" % (interface.id, state, interface.oper_err_dis_qual) else: print "%s is %s (%s)" % (interface.id, state, rsn) print 'admin state is', interface.admin_st if interface.is_member_pc(): print " Belongs to %s" % interface.port_channel_id if not interface.descr == '': print ' Port description is', interface.descr print ' Hardware:', interface.port_cap_speed, 'Ethernet, address:', interface.address, \ '(bia', interface.backplane_mac, ')' print ' MTU', interface.mtu, 'bytes, BW', interface.bw, 'Kbit, DLY', interface.delay, 'usec' print ' reliability', '%s/255' % interface.reliability, \ 'txload %d/255, rxload %d/255' % (interface.tx_load, interface.rx_load) print ' Encapsulation ARPA, medium is broadcast' if interface.layer != 'Layer2': print ' Port mode is routed' else: print " Port mode is %s" % interface.mode if not interface.is_mgmt() and interface.oper_mode == 'ips': duplex = 'auto' else: duplex = interface.oper_duplex print " %s-duplex, %sb/s%s" % (duplex, interface.speed, interface.fcot_str) if (interface.is_ether() and not interface.is_sub()) or interface.is_mgmt(): if not interface.is_mgmt(): print ' FEC (forward-error-correction) :', interface.oper_fec_mode print " Beacon is turned", interface.beacon_state print " Auto-Negotiation is turned", interface.auto_neg if interface.is_ether() or interface.is_pc() or interface.is_mgmt(): print " Input flow-control is off, output flow-control is off" if interface.mdix == 'auto': print " Auto-mdix is turned on" else: print " Auto-mdix is turned off" elif interface.is_loop(): print " Auto-mdix is turned off" if interface.is_ether() and not interface.is_sub() and interface.port_cap_fcot_capable == '1': if interface.port_cap_rate_mode == "1": rateMode = "dedicated" elif interface.port_cap_rate_mode == "2": rateMode = "shared" else: rateMode = interface.port_cap_rate_mode print " Rate mode is %s" % rateMode if interface.is_ether(): if interface.span_mode == "not-a-span-dest": print ' Switchport monitor is off' else: print ' Switchport monitor is on' if interface.is_ether() or interface.is_pc() or interface.is_mgmt(): print ' EtherType is', interface.dot1q_ethertype if interface.is_ether(): if interface.eee_state == "not-applicable": print " EEE (efficient-ethernet) : n/a" elif interface.eee_state == "enable": print " EEE (efficient-ethernet) : Operational" elif interface.eee_state == "disable": print " EEE (efficient-ethernet) : Disabled" elif interface.eee_state == "disagreed": print " EEE (efficient-ethernet) : Disagreed" if interface.last_link_st_chg.startswith('1970-'): print " Last link flapped never" else: last_flap = dateutil.parser.parse(interface.last_link_st_chg).replace(tzinfo=None) seconds_since_flap = datetime.datetime.now() - last_flap print " Last link flapped", seconds_since_flap if interface.is_ether() or interface.is_pc() or interface.is_svi(): last_clear = 'never' if interface.clear_ts != 'never': last_clear = dateutil.parser.parse(interface.clear_ts).replace(tzinfo=None) print ' Last clearing of "show interface" counters %s' % last_clear if not interface.is_svi(): print ' ', interface.reset_ctr,'interface resets' elif interface.is_tun(): pass if interface.is_svi(): pass elif interface.is_ether() or interface.is_pc(): print " 30 seconds input rate %d bits/sec, %d packets/sec" % \ (interface.input_bitrate_30sec, interface.input_packetrate_30sec) print " 30 seconds output rate %d bits/sec, %d packets/sec" % \ (interface.output_bitrate_30sec, interface.output_packetrate_30sec) print " Load-Interval #2: 5 minute (300 seconds)" print " input rate %d bps, %d pps; output rate %d bps, %d pps" % \ (interface.input_bitrate_300sec, interface.input_packetrate_300sec, interface.output_bitrate_300sec, interface.output_packetrate_300sec) if interface.layer == 'Layer3': print " L3 in Switched:" print " ucast: %d pkts, %d bytes - mcast: %d pkts, %d bytes" % \ (0, 0, 0, 0) # (stats.l3InSwitchedUcastPackets, # stats.l3InSwitchedUcastBytes, # stats.l3InSwitchedMcastPackets, # stats.l3InSwitchedMcastBytes) print " L3 out Switched:" print " ucast: %d pkts, %d bytes - mcast: %d pkts, %d bytes" % \ (0, 0, 0, 0) # (stats.l3OutSwitchedUcastPackets, # stats.l3OutSwitchedUcastBytes, # stats.l3OutSwitchedMcastPackets, # stats.l3OutSwitchedMcastBytes) if (interface.is_ether() or interface.is_pc()) and not interface.is_sub(): print " RX" ucast = "%d unicast packets" % interface.rx_unicast_packets mcast = "%d multicast packets" % interface.rx_multicast_packets bcast = "%d broadcast packets" % interface.rx_broadcast_packets print " %s %s %s" % (ucast, mcast, bcast) pkts = "%d input packets" % interface.rx_input_packets bytes = "%d bytes" % interface.rx_input_bytes print " %s %s" % (pkts, bytes) print ' ', interface.rx_oversize_packets, 'jumbo packets ',\ interface.rx_storm_supression_packets, 'storm suppression bytes' print ' ', interface.rx_runts, 'runts', interface.rx_oversize_packets,\ 'giants', interface.rx_crc, 'CRC 0 no buffer' print ' ', interface.rx_error_packets, 'input error',\ interface.rx_runts, 'short frame 0 overrun 0 underrun 0 ignored' print ' 0 watchdog 0 bad etype drop', interface.bad_proto_drop,\ 'bad proto drop 0 if down drop' print ' 0 input with dribble', interface.rx_input_discard, 'input discard' print ' ', interface.rx_pause_frames, 'Rx pause' print ' TX' print ' ', interface.tx_unicast_packets, 'unicast packets', interface.tx_multicast_packets,\ 'multicast packets', interface.tx_broadcast_packets, 'broadcast packets' print ' ', interface.tx_output_packets, 'output packets', interface.tx_output_bytes, 'bytes' print ' ', interface.tx_oversize_packets, 'jumbo packets' print ' ', interface.tx_error_packets, 'output error', interface.collisions, 'collision',\ interface.deferred_transmissions, 'deferred', interface.late_collisions, 'late collision' print ' 0 lost carrier', interface.carrier_sense_errors, '0 babble',\ interface.tx_output_discard, 'output discard' print ' ', interface.out_pause_frames, 'Tx pause' print ""
class InterfaceBriefCollector(object): def __init__(self, url, login, password): # Login to APIC self._apic = Session(url, login, password) self._if_brief_headers = { 'l1PhysIf': ['Ethernet Interface', 'VLAN', 'Type', 'Mode', 'Status', 'Reason', 'Speed', 'Port Ch #'], 'pcAggrIf': ['Port-channel Interface', 'VLAN', 'Type', 'Mode', 'Status', 'Reason', 'Speed', 'Protocol'], 'l3LbRtdIf': ['Interface', 'Status', 'Description'], 'tunnelIf': ['Interface', 'Status', 'IP Address', 'Encap type', 'MTU'], 'sviIf': ['Interface', 'Secondary VLAN(Type)', 'Status', 'Reason'], 'l3EncRtdIf': [], 'mgmtMgmtIf': ['Port', 'VRF', 'Status', 'IP Address', 'Speed', 'MTU'], 'l2ExtIf': [], 'l2VfcIf': ['Interface', 'Vsan', 'Admin\nMode', 'Admin Trunk Mode', 'Status', 'Bind Info', 'Oper Mode', 'Oper Speed (Gbps)'] } self._if_types = self._if_brief_headers.keys() if not self._apic.login().ok: self._logged_in = False print('%% Could not login to APIC') else: self._logged_in = True self._interfaces = [] @property def _all_if_types_as_string(self): resp = '' for if_type in self._if_types: if len(resp): resp += ',' resp += if_type return resp def _get_query(self, query_url, error_msg): resp = self._apic.get(query_url) if not resp.ok: print error_msg print resp.text return [] return resp.json()['imdata'] def populate_interfaces(self, node_id, intf_id=None): query_url = ('/api/mo/topology/pod-1/node-%s/sys.json?query-target=subtree' '&target-subtree-class=%s&rsp-subtree=children&' 'rsp-subtree-class=ethpmPhysIf,l1RtMbrIfs,ethpmAggrIf' % (node_id, self._all_if_types_as_string)) error_message = 'Could not collect APIC data for switch %s.' % node_id interfaces = self._get_query(query_url, error_message) if intf_id is None: self._interfaces = interfaces else: self._interfaces = [] for interface in interfaces: for if_type in interface: if interface[if_type]['attributes']['id'] == intf_id: self._interfaces.append(interface) def _has_interface_type(self, if_type, intf_id=None): for interface in self._interfaces: if if_type in interface: if intf_id is None or intf_id == interface[if_type]['attributes']['id']: return True return False def _get_interface_type(self, if_type): resp = [] for interface in self._interfaces: if if_type in interface: resp.append(interface) return resp def get_node_ids(self, node_id): """ Get the list of node ids from the command line arguments. If none, get all of the node ids :param args: Command line arguments :return: List of strings containing node ids """ if node_id is not None: names = [node_id] else: names = [] query_url = ('/api/node/class/fabricNode.json?' 'query-target-filter=eq(fabricNode.role,"leaf")') error_message = 'Could not get switch list from APIC.' nodes = self._get_query(query_url, error_message) for node in nodes: names.append(str(node['fabricNode']['attributes']['id'])) return names @staticmethod def convert_to_ascii(data): data = str(data).split(',') resp = '' for letter in data: resp += str(unichr(int(letter))) return resp def _get_interface_type_brief_data(self, if_type, intf_id=None): data = [] for interface in self._interfaces: if if_type in interface: if intf_id is not None and intf_id != interface[if_type]['attributes']['id']: continue if_attrs = interface[if_type]['attributes'] if if_type == 'mgmtMgmtIf': data.append((if_attrs['id'], '--', if_attrs['adminSt'], '', if_attrs['speed'], if_attrs['mtu'])) elif if_type == 'l1PhysIf': port_channel = '--' for child in interface[if_type]['children']: if 'l1RtMbrIfs' in child: port_channel = child['l1RtMbrIfs']['attributes']['tSKey'] else: oper_attrs = child['ethpmPhysIf']['attributes'] data.append((if_attrs['id'], '--', 'eth', oper_attrs['operMode'], oper_attrs['operSt'], oper_attrs['operStQual'], oper_attrs['operSpeed'], port_channel)) elif if_type == 'tunnelIf': data.append((if_attrs['id'], if_attrs['operSt'], '--', if_attrs['tType'], if_attrs['cfgdMtu'])) elif if_type == 'pcAggrIf': for child in interface[if_type]['children']: protocol = '--' if if_attrs['pcMode'] in ['active', 'passive', 'mac-pin']: protocol = 'lacp' elif if_attrs['pcMode'] == 'static': protocol = 'none' if 'ethpmAggrIf' in child: oper_attrs = child['ethpmAggrIf']['attributes'] data.append((if_attrs['id'], '--', 'eth', oper_attrs['operMode'], oper_attrs['operSt'], oper_attrs['operStQual'], oper_attrs['operSpeed'], protocol)) elif if_type == 'sviIf': data.append((if_attrs['id'], '--', if_attrs['operSt'], if_attrs['operStQual'])) elif if_type == 'l3LbRtdIf': if len(if_attrs['descr']): description = if_attrs['descr'] else: description = '--' data.append((if_attrs['id'], if_attrs['adminSt'], description)) elif if_type == 'l2VfcIf': raise NotImplementedError # TODO: finish this return data def show_brief(self, node=None, intf_id=None): """ show interface brief :param node: String containing the specific switch id. If none, all switches are used :param intf_id: String containing the specific interface id. If none, all interfaces are used :return: None """ for node_id in self.get_node_ids(node): self.populate_interfaces(node_id, intf_id) for if_type in self._if_types: if self._has_interface_type(if_type, intf_id): data = self._get_interface_type_brief_data(if_type, intf_id) data.sort(key=lambda tup: tup[0]) if len(data): print tabulate(data, headers=self._if_brief_headers[if_type]) print
class InterfaceCollector(object): def __init__(self, url, login, password): # Login to APIC self._apic = Session(url, login, password) if not self._apic.login().ok: self._logged_in = False print '%% Could not login to APIC' else: self._logged_in = True self._interfaces = [] self._port_channels = [] def _get_query(self, query_url, error_msg): resp = self._apic.get(query_url) if not resp.ok: print error_msg print resp.text return [] return resp.json()['imdata'] def populate_port_channels(self, node_id, intf_id=None): query_url = ('/api/mo/topology/pod-1/node-%s/sys.json?query-target=subtree' '&target-subtree-class=pcAggrIf&rsp-subtree=children&' 'rsp-subtree-class=ethpmAggrIf,pcRsMbrIfs' % node_id) error_message = 'Could not collect APIC data for switch %s.' % node_id port_channels = self._get_query(query_url, error_message) if intf_id is None: self._port_channels = port_channels else: self._port_channels = [] for port_channel in port_channels: for if_type in port_channel: if port_channel[if_type]['attributes']['id'] == intf_id: self._port_channels.append(port_channel) def populate_interfaces(self, node_id): query_url = ('/api/mo/topology/pod-1/node-%s/sys.json?query-target=subtree' '&target-subtree-class=l1PhysIf&rsp-subtree=children&' 'rsp-subtree-class=pcAggrMbrIf' % node_id) error_message = 'Could not collect APIC data for switch %s.' % node_id self._interfaces = self._get_query(query_url, error_message) def get_node_ids(self, node_id): """ Get the list of node ids from the command line arguments. If none, get all of the node ids :param args: Command line arguments :return: List of strings containing node ids """ if node_id is not None: names = [node_id] else: names = [] query_url = ('/api/node/class/fabricNode.json?' 'query-target-filter=eq(fabricNode.role,"leaf")') error_message = 'Could not get switch list from APIC.' nodes = self._get_query(query_url, error_message) for node in nodes: names.append(str(node['fabricNode']['attributes']['id'])) return names def _get_member_extension(self, port_channel): resp = '' for child in port_channel['pcAggrIf']['children']: if 'pcRsMbrIfs' in child: for interface in self._interfaces: if child['pcRsMbrIfs']['attributes']['tDn'] == interface['l1PhysIf']['attributes']['dn']: oper_attr = interface['l1PhysIf']['children'][0]['pcAggrMbrIf']['attributes'] if oper_attr['operSt'] == 'module-removed': resp = '(r)' elif oper_attr['operSt'] == 'up': resp = '(P)' elif oper_attr['channelingSt'] == 'individual': resp = "(I)" elif oper_attr['channelingSt'] == 'suspended': resp = "(s)" elif oper_attr['channelingSt'] == 'hot-standby': resp = "(H)" else: resp = "(D)" if resp != '': break return resp def show_summary(self, node=None, intf_id=None): """ show port-channel summary :param node: String containing the specific switch id. If none, all switches are used :param intf_id: String containing the specific interface id. If none, all interfaces are used :return: None """ for node_id in self.get_node_ids(node): self.populate_interfaces(node_id) self.populate_port_channels(node_id, intf_id) if not len(self._port_channels): continue print "Switch:", node_id print "Flags: D - Down P - Up in port-channel (members)" print " I - Individual H - Hot-standby (LACP only)" print " s - Suspended r - Module-removed" print " S - Switched R - Routed" print " U - Up (port-channel)" print " M - Not in use. Min-links not met" print " F - Configuration failed" data = [] for interface in self._port_channels: intf_attr = interface['pcAggrIf']['attributes'] name = intf_attr['id'] if intf_attr['layer'] == 'Layer2': name += "(S" else: name += "(R" for child in interface['pcAggrIf']['children']: if 'ethpmAggrIf' in child: oper_attr = child['ethpmAggrIf']['attributes'] if oper_attr['operSt'] == 'up': name += "U)" elif intf_attr['suspMinlinks'] == 'yes': name += "M)" else: name += "D)" members = oper_attr['activeMbrs'] while ',unspecified,' in members: members = members.replace(',unspecified,', ',') members = members.replace(',unspecified', '') members += self._get_member_extension(interface) protocol = 'none' if intf_attr['pcMode'] in ['active', 'passive', 'mac-pin']: protocol = 'lacp' data.append((int(intf_attr['id'][2:]), name, 'eth', protocol, members)) data.sort(key=lambda tup: tup[0]) headers = ['Group', 'Port channel', 'Type', 'Protocol', 'Member Ports'] print tabulate(data, headers=headers)
class InterfaceDetailedCollector(object): def __init__(self, url, login, password): # Login to APIC self._apic = Session(url, login, password) if not self._apic.login().ok: self._logged_in = False print('%% Could not login to APIC') else: self._logged_in = True self._interfaces = [] def _get_query(self, query_url, error_msg): resp = self._apic.get(query_url) if not resp.ok: print error_msg print resp.text return [] return resp.json()['imdata'] def _populate_beacon_states(self, data): for beacon_data in data: if 'eqptLocLed' not in beacon_data: continue dn = beacon_data['eqptLocLed']['attributes']['dn'] oper_state = beacon_data['eqptLocLed']['attributes']['operSt'] if 'leafport-' in dn: port_num = dn.partition('/leafport-')[2].partition('/')[0] mod_num = dn.partition('/lcslot-')[2].partition('/')[0] node_num = dn.partition('/node-')[2].partition('/')[0] beacon_interface_id = 'eth' + mod_num + '/' + port_num beacon_node_id = '/node-%s/' % node_num for interface in self._interfaces: if not interface.is_ether(): continue if interface.id == beacon_interface_id: if beacon_node_id in dn: interface.beacon_state = oper_state def populate_detailed_interfaces(self, node_id, intf_id=None): query_url = ('/api/mo/topology/pod-1/node-%s/sys.json?query-target=subtree' '&target-subtree-class=l1PhysIf,pcAggrIf,l3LbRtdIf,tunnelIf,sviIf,l3EncRtdIf,' 'mgmtMgmtIf,l2ExtIf,l2VfcIf,eqptLocLed&rsp-subtree=full&' 'rsp-subtree-class=ethpmPhysIf,ethpmPortCap,l1RtMbrIfs,ethpmAggrIf,' 'rmonEtherStats,rmonIfIn,rmonIfOut,rmonIfStorm,eqptIngrTotal5min,' 'eqptEgrTotal5min,l1EeeP,rmonDot3Stats' % node_id) error_message = 'Could not collect APIC data for switch %s.' % node_id interfaces = self._get_query(query_url, error_message) self._interfaces = [] if intf_id is None: for interface in interfaces: self._interfaces.append(Interface(interface)) else: for interface in interfaces: for if_type in interface: if if_type == 'eqptLocLed': continue if interface[if_type]['attributes']['id'] == intf_id: self._interfaces.append(Interface(interface)) self._populate_beacon_states(interfaces) def get_node_ids(self, node_id): """ Get the list of node ids from the command line arguments. If none, get all of the node ids :param args: Command line arguments :return: List of strings containing node ids """ if node_id is not None: names = [node_id] else: names = [] query_url = ('/api/node/class/fabricNode.json?' 'query-target-filter=eq(fabricNode.role,"leaf")') error_message = 'Could not get switch list from APIC.' nodes = self._get_query(query_url, error_message) for node in nodes: names.append(str(node['fabricNode']['attributes']['id'])) return names def show_detailed(self, node=None, intf_id=None): """ show interface :param node: String containing the specific switch id. If none, all switches are used :param intf_id: String containing the specific interface id. If none, all interfaces are used :return: None """ for node_id in self.get_node_ids(node): print('Switch', node_id) self.populate_detailed_interfaces(node_id, intf_id) for interface in self._interfaces: if interface.if_type == 'l1PhysIf': if interface.is_ether or interface.is_pc() or interface.is_tun(): state = interface.oper_st rsn = interface.oper_st_qual if state is None: state = "unknown" rsn = "unknown" if state == 'link-up': # see ethpm_copy_eth_port_log_info() # link-up state is physical up, but not operationally up state = 'down' if state == 'up': if not interface.is_tun() and interface.switching_st == 'disabled': print "%s is %s (%s)" % (interface.id, state, "out-of-service") else: print "%s is %s" % (interface.id, state) elif interface.oper_st_qual == "err-disabled": print "%s is %s (%s)" % (interface.id, state, interface.oper_err_dis_qual) else: print "%s is %s (%s)" % (interface.id, state, rsn) print('admin state is', interface.admin_st) if interface.is_member_pc(): print " Belongs to %s" % interface.port_channel_id if not interface.descr == '': print(' Port description is', interface.descr) print(' Hardware:', interface.port_cap_speed, 'Ethernet, address:', interface.address, \) '(bia', interface.backplane_mac, ')' print(' MTU', interface.mtu, 'bytes, BW', interface.bw, 'Kbit, DLY', interface.delay, 'usec') print(' reliability', '%s/255' % interface.reliability, \) 'txload %d/255, rxload %d/255' % (interface.tx_load, interface.rx_load) print(' Encapsulation ARPA, medium is broadcast') if interface.layer != 'Layer2': print(' Port mode is routed') else: print " Port mode is %s" % interface.mode if not interface.is_mgmt() and interface.oper_mode == 'ips': duplex = 'auto' else: duplex = interface.oper_duplex print " %s-duplex, %sb/s%s" % (duplex, interface.speed, interface.fcot_str) if (interface.is_ether() and not interface.is_sub()) or interface.is_mgmt(): if not interface.is_mgmt(): print(' FEC (forward-error-correction) :', interface.oper_fec_mode) print " Beacon is turned", interface.beacon_state print " Auto-Negotiation is turned", interface.auto_neg if interface.is_ether() or interface.is_pc() or interface.is_mgmt(): print " Input flow-control is off, output flow-control is off" if interface.mdix == 'auto': print " Auto-mdix is turned on" else: print " Auto-mdix is turned off" elif interface.is_loop(): print " Auto-mdix is turned off" if interface.is_ether() and not interface.is_sub() and interface.port_cap_fcot_capable == '1': if interface.port_cap_rate_mode == "1": rateMode = "dedicated" elif interface.port_cap_rate_mode == "2": rateMode = "shared" else: rateMode = interface.port_cap_rate_mode print " Rate mode is %s" % rateMode if interface.is_ether(): if interface.span_mode == "not-a-span-dest": print(' Switchport monitor is off') else: print(' Switchport monitor is on') if interface.is_ether() or interface.is_pc() or interface.is_mgmt(): print(' EtherType is', interface.dot1q_ethertype) if interface.is_ether(): if interface.eee_state == "not-applicable": print " EEE (efficient-ethernet) : n/a" elif interface.eee_state == "enable": print " EEE (efficient-ethernet) : Operational" elif interface.eee_state == "disable": print " EEE (efficient-ethernet) : Disabled" elif interface.eee_state == "disagreed": print " EEE (efficient-ethernet) : Disagreed" if interface.last_link_st_chg.startswith('1970-'): print " Last link flapped never" else: last_flap = dateutil.parser.parse(interface.last_link_st_chg).replace(tzinfo=None) seconds_since_flap = datetime.datetime.now() - last_flap print " Last link flapped", seconds_since_flap if interface.is_ether() or interface.is_pc() or interface.is_svi(): last_clear = 'never' if interface.clear_ts != 'never': last_clear = dateutil.parser.parse(interface.clear_ts).replace(tzinfo=None) print(' Last clearing of "show interface" counters %s' % last_clear) if not interface.is_svi(): print(' ', interface.reset_ctr,'interface resets') elif interface.is_tun(): pass if interface.is_svi(): pass elif interface.is_ether() or interface.is_pc(): print " 30 seconds input rate %d bits/sec, %d packets/sec" % \ (interface.input_bitrate_30sec, interface.input_packetrate_30sec) print " 30 seconds output rate %d bits/sec, %d packets/sec" % \ (interface.output_bitrate_30sec, interface.output_packetrate_30sec) print " Load-Interval #2: 5 minute (300 seconds)" print " input rate %d bps, %d pps; output rate %d bps, %d pps" % \ (interface.input_bitrate_300sec, interface.input_packetrate_300sec, interface.output_bitrate_300sec, interface.output_packetrate_300sec) if interface.layer == 'Layer3': print " L3 in Switched:" print " ucast: %d pkts, %d bytes - mcast: %d pkts, %d bytes" % \ (0, 0, 0, 0) # (stats.l3InSwitchedUcastPackets, # stats.l3InSwitchedUcastBytes, # stats.l3InSwitchedMcastPackets, # stats.l3InSwitchedMcastBytes) print " L3 out Switched:" print " ucast: %d pkts, %d bytes - mcast: %d pkts, %d bytes" % \ (0, 0, 0, 0) # (stats.l3OutSwitchedUcastPackets, # stats.l3OutSwitchedUcastBytes, # stats.l3OutSwitchedMcastPackets, # stats.l3OutSwitchedMcastBytes) if (interface.is_ether() or interface.is_pc()) and not interface.is_sub(): print " RX" ucast = "%d unicast packets" % interface.rx_unicast_packets mcast = "%d multicast packets" % interface.rx_multicast_packets bcast = "%d broadcast packets" % interface.rx_broadcast_packets print " %s %s %s" % (ucast, mcast, bcast) pkts = "%d input packets" % interface.rx_input_packets bytes = "%d bytes" % interface.rx_input_bytes print " %s %s" % (pkts, bytes) print(' ', interface.rx_oversize_packets, 'jumbo packets ',\) interface.rx_storm_supression_packets, 'storm suppression bytes' print(' ', interface.rx_runts, 'runts', interface.rx_oversize_packets,\) 'giants', interface.rx_crc, 'CRC 0 no buffer' print(' ', interface.rx_error_packets, 'input error',\) interface.rx_runts, 'short frame 0 overrun 0 underrun 0 ignored' print(' 0 watchdog 0 bad etype drop', interface.bad_proto_drop,\) 'bad proto drop 0 if down drop'
# Take login credentials from the command line if provided # Otherwise, take them from your environment variables file ~/.profile description = 'Simple application that logs on to the APIC and Extracts the L3out Static Routes information.' creds = Credentials('apic', description) creds.add_argument('--tenant', help='The name of Tenant') args = creds.get() # Login to APIC session = Session(args.url, args.login, args.password) resp = session.login() if not resp.ok: print('%% Could not login to APIC') sys.exit(0) resp = session.get( '/api/class/ipRouteP.json?rsp-subtree=full&rsp-prop-include=config-only&order-by=ipRouteP.dn' ) data = json.loads(resp.text)['imdata'] datacount = int(json.loads(resp.text)['totalCount']) fname = "Static_Route.csv" with open(fname, "w", newline='') as file: csv_file = csv.writer(file) csv_file.writerow([ "Tenant", "L3OUT", "Logical Node Profile", "Node ID", "IP Prefix", "Route Pref", "Next Hop", "NH Pref", "Route Control" ]) numrow = 0 for i in data: