def sign_envelope(envelope, keyfile, certfile, password=None): """Sign given SOAP envelope with WSSE sig using given key and cert. Sign the wsu:Timestamp node in the wsse:Security header and the soap:Body; both must be present. Add a ds:Signature node in the wsse:Security header containing the signature. Use EXCL-C14N transforms to normalize the signed XML (so that irrelevant whitespace or attribute ordering changes don't invalidate the signature). Use SHA1 signatures. Expects to sign an incoming document something like this (xmlns attributes omitted for readability): <soap:Envelope> <soap:Header> <wsse:Security mustUnderstand="true"> <wsu:Timestamp> <wsu:Created>2015-06-25T21:53:25.246276+00:00</wsu:Created> <wsu:Expires>2015-06-25T21:58:25.246276+00:00</wsu:Expires> </wsu:Timestamp> </wsse:Security> </soap:Header> <soap:Body> ... </soap:Body> </soap:Envelope> After signing, the sample document would look something like this (note the added wsu:Id attr on the soap:Body and wsu:Timestamp nodes, and the added ds:Signature node in the header, with ds:Reference nodes with URI attribute referencing the wsu:Id of the signed nodes): <soap:Envelope> <soap:Header> <wsse:Security mustUnderstand="true"> <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> <SignedInfo> <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <Reference URI="#id-d0f9fd77-f193-471f-8bab-ba9c5afa3e76"> <Transforms> <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <DigestValue>nnjjqTKxwl1hT/2RUsBuszgjTbI=</DigestValue> </Reference> <Reference URI="#id-7c425ac1-534a-4478-b5fe-6cae0690f08d"> <Transforms> <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <DigestValue>qAATZaSqAr9fta9ApbGrFWDuCCQ=</DigestValue> </Reference> </SignedInfo> <SignatureValue>Hz8jtQb...bOdT6ZdTQ==</SignatureValue> <KeyInfo> <wsse:SecurityTokenReference> <X509Data> <X509Certificate>MIIDnzC...Ia2qKQ==</X509Certificate> <X509IssuerSerial> <X509IssuerName>...</X509IssuerName> <X509SerialNumber>...</X509SerialNumber> </X509IssuerSerial> </X509Data> </wsse:SecurityTokenReference> </KeyInfo> </Signature> <wsu:Timestamp wsu:Id="id-7c425ac1-534a-4478-b5fe-6cae0690f08d"> <wsu:Created>2015-06-25T22:00:29.821700+00:00</wsu:Created> <wsu:Expires>2015-06-25T22:05:29.821700+00:00</wsu:Expires> </wsu:Timestamp> </wsse:Security> </soap:Header> <soap:Body wsu:Id="id-d0f9fd77-f193-471f-8bab-ba9c5afa3e76"> ... </soap:Body> </soap:Envelope> """ # Create the Signature node. signature = xmlsec.template.create( envelope, xmlsec.Transform.EXCL_C14N, xmlsec.Transform.RSA_SHA1, ) # Add a KeyInfo node with X509Data child to the Signature. XMLSec will fill # in this template with the actual certificate details when it signs. key_info = xmlsec.template.ensure_key_info(signature) x509_data = xmlsec.template.add_x509_data(key_info) xmlsec.template.x509_data_add_issuer_serial(x509_data) xmlsec.template.x509_data_add_certificate(x509_data) # Load the signing key and certificate. key = xmlsec.Key.from_file(keyfile, xmlsec.KeyFormat.PEM, password=password) key.load_cert_from_file(certfile, xmlsec.KeyFormat.PEM) # Insert the Signature node in the wsse:Security header. security = get_security_header(envelope) security.insert(0, signature) # Perform the actual signing. ctx = xmlsec.SignatureContext() ctx.key = key security.append(etree.Element(QName(ns.WSU, 'Timestamp'))) soap_env = detect_soap_env(envelope) _sign_node(ctx, signature, envelope.find(QName(soap_env, 'Body'))) _sign_node(ctx, signature, security.find(QName(ns.WSU, 'Timestamp'))) ctx.sign(signature) # Place the X509 data inside a WSSE SecurityTokenReference within # KeyInfo. The recipient expects this structure, but we can't rearrange # like this until after signing, because otherwise xmlsec won't populate # the X509 data (because it doesn't understand WSSE). sec_token_ref = etree.SubElement(key_info, QName(ns.WSSE, 'SecurityTokenReference')) sec_token_ref.append(x509_data)
def parse_png(png, hname): neighbors = {} devices = {} console_dev = '' console_port = '' mgmt_dev = '' mgmt_port = '' for child in png: if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for link in child.findall(str(QName(ns, "DeviceLinkBase"))): linktype = link.find(str(QName(ns, "ElementType"))).text if linktype != "DeviceInterfaceLink" and linktype != "UnderlayInterfaceLink": continue enddevice = link.find(str(QName(ns, "EndDevice"))).text endport = link.find(str(QName(ns, "EndPort"))).text startdevice = link.find(str(QName(ns, "StartDevice"))).text startport = link.find(str(QName(ns, "StartPort"))).text if enddevice == hname: if port_alias_map.has_key(endport): endport = port_alias_map[endport] neighbors[endport] = { 'name': startdevice, 'port': startport } else: if port_alias_map.has_key(startport): startport = port_alias_map[startport] neighbors[startport] = {'name': enddevice, 'port': endport} if child.tag == str(QName(ns, "Devices")): for device in child.findall(str(QName(ns, "Device"))): (lo_prefix, mgmt_prefix, name, hwsku, d_type) = parse_device(device) device_data = { 'lo_addr': lo_prefix, 'type': d_type, 'mgmt_addr': mgmt_prefix, 'hwsku': hwsku } devices[name] = device_data if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for if_link in child.findall(str(QName(ns, 'DeviceLinkBase'))): if str(QName(ns3, "type")) in if_link.attrib: link_type = if_link.attrib[str(QName(ns3, "type"))] if link_type == 'DeviceSerialLink': for node in if_link: if node.tag == str(QName(ns, "EndPort")): console_port = node.text.split()[-1] elif node.tag == str(QName(ns, "EndDevice")): console_dev = node.text elif link_type == 'DeviceMgmtLink': for node in if_link: if node.tag == str(QName(ns, "EndPort")): mgmt_port = node.text.split()[-1] elif node.tag == str(QName(ns, "EndDevice")): mgmt_dev = node.text return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port)
def parse_cpg(cpg, hname): bgp_sessions = {} myasn = None bgp_peers_with_range = {} for child in cpg: tag = child.tag if tag == str(QName(ns, "PeeringSessions")): for session in child.findall(str(QName(ns, "BGPSession"))): start_router = session.find(str(QName(ns, "StartRouter"))).text start_peer = session.find(str(QName(ns, "StartPeer"))).text end_router = session.find(str(QName(ns, "EndRouter"))).text end_peer = session.find(str(QName(ns, "EndPeer"))).text rrclient = 1 if session.find(str(QName( ns, "RRClient"))) is not None else 0 if session.find(str(QName(ns, "HoldTime"))) is not None: holdtime = session.find(str(QName(ns, "HoldTime"))).text else: holdtime = 180 if session.find(str(QName(ns, "KeepAliveTime"))) is not None: keepalive = session.find(str(QName(ns, "KeepAliveTime"))).text else: keepalive = 60 nhopself = 1 if session.find(str(QName( ns, "NextHopSelf"))) is not None else 0 if end_router.lower() == hname.lower(): bgp_sessions[start_peer.lower()] = { 'name': start_router, 'local_addr': end_peer.lower(), 'rrclient': rrclient, 'holdtime': holdtime, 'keepalive': keepalive, 'nhopself': nhopself } else: bgp_sessions[end_peer.lower()] = { 'name': end_router, 'local_addr': start_peer.lower(), 'rrclient': rrclient, 'holdtime': holdtime, 'keepalive': keepalive, 'nhopself': nhopself } elif child.tag == str(QName(ns, "Routers")): for router in child.findall(str(QName(ns1, "BGPRouterDeclaration"))): asn = router.find(str(QName(ns1, "ASN"))).text hostname = router.find(str(QName(ns1, "Hostname"))).text if hostname.lower() == hname.lower(): myasn = asn peers = router.find(str(QName(ns1, "Peers"))) for bgpPeer in peers.findall(str(QName(ns, "BGPPeer"))): addr = bgpPeer.find(str(QName(ns, "Address"))).text if bgpPeer.find( str(QName(ns1, "PeersRange")) ) is not None: # FIXME: is better to check for type BGPPeerPassive name = bgpPeer.find(str(QName(ns1, "Name"))).text ip_range = bgpPeer.find( str(QName(ns1, "PeersRange"))).text ip_range_group = ip_range.split( ';') if ip_range and ip_range != "" else [] bgp_peers_with_range[name] = { 'name': name, 'ip_range': ip_range_group } if bgpPeer.find(str(QName(ns1, "Address"))) is not None: bgp_peers_with_range[name][ 'src_address'] = bgpPeer.find( str(QName(ns1, "Address"))).text if bgpPeer.find(str(QName(ns1, "PeerAsn"))) is not None: bgp_peers_with_range[name][ 'peer_asn'] = bgpPeer.find( str(QName(ns1, "PeerAsn"))).text else: for peer in bgp_sessions: bgp_session = bgp_sessions[peer] if hostname.lower() == bgp_session['name'].lower(): bgp_session['asn'] = asn bgp_sessions = { key: bgp_sessions[key] for key in bgp_sessions if bgp_sessions[key].has_key('asn') and int(bgp_sessions[key]['asn']) != 0 } return bgp_sessions, myasn, bgp_peers_with_range
def parse_xml(filename, platform=None, port_config_file=None): root = ET.parse(filename).getroot() mini_graph_path = filename u_neighbors = None u_devices = None hwsku = None bgp_sessions = None bgp_asn = None intfs = None vlan_intfs = None pc_intfs = None vlans = None pcs = None mgmt_intf = None lo_intf = None neighbors = None devices = None hostname = None syslog_servers = [] dhcp_servers = [] ntp_servers = [] mgmt_routes = [] erspan_dst = [] bgp_peers_with_range = None deployment_id = None hwsku_qn = QName(ns, "HwSku") hostname_qn = QName(ns, "Hostname") for child in root: if child.tag == str(hwsku_qn): hwsku = child.text if child.tag == str(hostname_qn): hostname = child.text ports = parse_port_config(hwsku, platform, port_config_file) for child in root: if child.tag == str(QName(ns, "DpgDec")): (intfs, lo_intfs, mgmt_intf, vlans, pcs, acls) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) = parse_png(child, hostname) elif child.tag == str(QName(ns, "UngDec")): (u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname) elif child.tag == str(QName(ns, "MetadataDeclaration")): (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id) = parse_meta(child, hostname) results = {} results['minigraph_hwsku'] = hwsku # sorting by lambdas are not easily done without custom filters. # TODO: add jinja2 filter to accept a lambda to sort a list of dictionaries by attribute. # TODO: alternatively (preferred), implement class containers for multiple-attribute entries, enabling sort by attr results['minigraph_bgp'] = sorted(bgp_sessions, key=lambda x: x['addr']) results['minigraph_bgp_asn'] = bgp_asn results['minigraph_bgp_peers_with_range'] = bgp_peers_with_range # TODO: sort does not work properly on all interfaces of varying lengths. Need to sort by integer group(s). phyport_intfs = [] vlan_intfs = [] pc_intfs = [] for intf in intfs: intfname = intf['attachto'] if intfname[0:4] == 'Vlan': vlan_intfs.append(intf) elif intfname[0:11] == 'PortChannel': pc_intfs.append(intf) else: phyport_intfs.append(intf) results['minigraph_interfaces'] = sorted(phyport_intfs, key=lambda x: x['attachto']) results['minigraph_vlan_interfaces'] = sorted(vlan_intfs, key=lambda x: x['attachto']) results['minigraph_portchannel_interfaces'] = sorted( pc_intfs, key=lambda x: x['attachto']) results['minigraph_ports'] = ports results['minigraph_vlans'] = vlans results['minigraph_portchannels'] = pcs results['minigraph_mgmt_interface'] = mgmt_intf results['minigraph_lo_interfaces'] = lo_intfs results['minigraph_acls'] = acls results['minigraph_neighbors'] = neighbors results['minigraph_devices'] = devices results['minigraph_underlay_neighbors'] = u_neighbors results['minigraph_underlay_devices'] = u_devices results['minigraph_as_xml'] = mini_graph_path if devices != None: results['minigraph_console'] = get_console_info( devices, console_dev, console_port) results['minigraph_mgmt'] = get_mgmt_info(devices, mgmt_dev, mgmt_port) results['minigraph_hostname'] = hostname results['inventory_hostname'] = hostname results['syslog_servers'] = syslog_servers results['dhcp_servers'] = dhcp_servers results['ntp_servers'] = ntp_servers results['forced_mgmt_routes'] = mgmt_routes results['erspan_dst'] = erspan_dst results['deployment_id'] = deployment_id return results
def parse_dpg(dpg, hname): for child in dpg: hostname = child.find(str(QName(ns, "Hostname"))) if hostname.text != hname: continue ipintfs = child.find(str(QName(ns, "IPInterfaces"))) intfs = {} for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))): intfalias = ipintf.find(str(QName(ns, "AttachTo"))).text intfname = port_alias_map.get(intfalias, intfalias) ipprefix = ipintf.find(str(QName(ns, "Prefix"))).text intfs[(intfname, ipprefix)] = {} lointfs = child.find(str(QName(ns, "LoopbackIPInterfaces"))) lo_intfs = {} for lointf in lointfs.findall(str(QName(ns1, "LoopbackIPInterface"))): intfname = lointf.find(str(QName(ns, "AttachTo"))).text ipprefix = lointf.find(str(QName(ns1, "PrefixStr"))).text lo_intfs[(intfname, ipprefix)] = {} mgmtintfs = child.find(str(QName(ns, "ManagementIPInterfaces"))) mgmt_intf = {} for mgmtintf in mgmtintfs.findall( str(QName(ns1, "ManagementIPInterface"))): intfname = mgmtintf.find(str(QName(ns, "AttachTo"))).text ipprefix = mgmtintf.find(str(QName(ns1, "PrefixStr"))).text mgmtipn = ipaddress.IPNetwork(ipprefix) gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) mgmt_intf[(intfname, ipprefix)] = {'gwaddr': gwaddr} pcintfs = child.find(str(QName(ns, "PortChannelInterfaces"))) pc_intfs = [] pcs = {} for pcintf in pcintfs.findall(str(QName(ns, "PortChannel"))): pcintfname = pcintf.find(str(QName(ns, "Name"))).text pcintfmbr = pcintf.find(str(QName(ns, "AttachTo"))).text pcmbr_list = pcintfmbr.split(';') for i, member in enumerate(pcmbr_list): pcmbr_list[i] = port_alias_map.get(member, member) pcs[pcintfname] = {'members': pcmbr_list} vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) vlan_intfs = [] vlans = {} vlan_members = {} for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): vintfname = vintf.find(str(QName(ns, "Name"))).text vlanid = vintf.find(str(QName(ns, "VlanID"))).text vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text vmbr_list = vintfmbr.split(';') for i, member in enumerate(vmbr_list): vmbr_list[i] = port_alias_map.get(member, member) sonic_vlan_member_name = "Vlan%s%s%s" % (vlanid, KEY_SEPARATOR, vmbr_list[i]) vlan_members[sonic_vlan_member_name] = { 'tagging_mode': 'untagged' } vlan_attributes = {'vlanid': vlanid} # If this VLAN requires a DHCP relay agent, it will contain a <DhcpRelays> element # containing a list of DHCP server IPs if vintf.find(str(QName(ns, "DhcpRelays"))) is not None: vintfdhcpservers = vintf.find(str(QName(ns, "DhcpRelays"))).text vdhcpserver_list = vintfdhcpservers.split(';') vlan_attributes['dhcp_servers'] = vdhcpserver_list sonic_vlan_name = "Vlan%s" % vlanid vlans[sonic_vlan_name] = vlan_attributes aclintfs = child.find(str(QName(ns, "AclInterfaces"))) acls = {} for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))): aclname = aclintf.find(str(QName(ns, "InAcl"))).text.upper().replace( " ", "_").replace("-", "_") aclattach = aclintf.find(str(QName(ns, "AttachTo"))).text.split(';') acl_intfs = [] is_mirror = False for member in aclattach: member = member.strip() if pcs.has_key(member): acl_intfs.extend( pcs[member]['members'] ) # For ACL attaching to port channels, we break them into port channel members elif vlans.has_key(member): print >> sys.stderr, "Warning: ACL " + aclname + " is attached to a Vlan interface, which is currently not supported" elif port_alias_map.has_key(member): acl_intfs.append(port_alias_map[member]) elif member.lower() == 'erspan': is_mirror = True # Erspan session will be attached to all front panel ports acl_intfs = port_alias_map.values() break if acl_intfs: acls[aclname] = { 'policy_desc': aclname, 'ports': acl_intfs, 'type': 'MIRROR' if is_mirror else 'L3' } return intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, acls return None, None, None, None, None, None, None
def _setitem( self, key: Union[str, QName], val: Union[Set[str], List[str], str], applying_mark: bool = False, ): if not self._updating: raise RuntimeError( "Metadata not opened for editing, use with block") qkey = self._qname(key) if (self.mark and not applying_mark and qkey in ( self._qname('xmp:MetadataDate'), self._qname('pdf:Producer'), )): # Complain if user writes self[pdf:Producer] = ... and because it will # be overwritten on save, unless self._updating_mark, in which case # the action was initiated internally log.warning( f"Update to {key} will be overwritten because metadata was opened " "with set_pikepdf_as_editor=True") if isinstance(val, str) and qkey in (self._qname('dc:creator')): log.error(f"{key} should be set to a list of strings") def add_array(node, items: Iterable): rdf_type = next(c.rdf_type for c in XMP_CONTAINERS if isinstance(items, c.py_type)) seq = etree.SubElement(node, str(QName(XMP_NS_RDF, rdf_type))) tag_attrib: Optional[Dict[str, str]] = None if rdf_type == 'Alt': tag_attrib = {str(QName(XMP_NS_XML, 'lang')): 'x-default'} for item in items: el = etree.SubElement(seq, str(QName(XMP_NS_RDF, 'li')), attrib=tag_attrib) el.text = _clean(item) try: # Locate existing node to replace node, attrib, _oldval, _parent = next(self._get_elements(key)) if attrib: if not isinstance(val, str): raise TypeError(val) node.set(attrib, _clean(val)) elif isinstance(val, (list, set)): for child in node.findall('*'): node.remove(child) add_array(node, val) elif isinstance(val, str): for child in node.findall('*'): node.remove(child) if str(self._qname(key)) in LANG_ALTS: add_array(node, AltList([_clean(val)])) else: node.text = _clean(val) else: raise TypeError(val) except StopIteration: # Insert a new node rdf = self._get_rdf_root() if str(self._qname(key)) in LANG_ALTS: val = AltList([_clean(val)]) if isinstance(val, (list, set)): rdfdesc = etree.SubElement( rdf, str(QName(XMP_NS_RDF, 'Description')), attrib={str(QName(XMP_NS_RDF, 'about')): ''}, ) node = etree.SubElement(rdfdesc, self._qname(key)) add_array(node, val) elif isinstance(val, str): _rdfdesc = etree.SubElement( # lgtm [py/unused-local-variable] rdf, str(QName(XMP_NS_RDF, 'Description')), attrib={ QName(XMP_NS_RDF, 'about'): '', self._qname(key): _clean(val), }, ) else: raise TypeError(val) from None
def parse_dpg(dpg, hname): for child in dpg: hostname = child.find(str(QName(ns, "Hostname"))) if hostname.text != hname: continue ipintfs = child.find(str(QName(ns, "IPInterfaces"))) intfs = [] for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))): intfalias = ipintf.find(str(QName(ns, "AttachTo"))).text intfname = port_alias_map.get(intfalias, intfalias) ipprefix = ipintf.find(str(QName(ns, "Prefix"))).text ipn = ipaddress.IPNetwork(ipprefix) ipaddr = ipn.ip prefix_len = ipn.prefixlen addr_bits = ipn.max_prefixlen subnet = ipaddress.IPNetwork( str(ipn.network) + '/' + str(prefix_len)) ipmask = ipn.netmask intf = {'addr': ipaddr, 'subnet': subnet} if isinstance(ipn, ipaddress.IPv4Network): intf['mask'] = ipmask else: intf['mask'] = str(prefix_len) intf.update({'attachto': intfname, 'prefixlen': int(prefix_len)}) # TODO: remove peer_addr after dependency removed ipaddr_val = int(ipn.ip) peer_addr_val = None if int(prefix_len) == addr_bits - 2: if ipaddr_val & 0x3 == 1: peer_addr_val = ipaddr_val + 1 else: peer_addr_val = ipaddr_val - 1 elif int(prefix_len) == addr_bits - 1: if ipaddr_val & 0x1 == 0: peer_addr_val = ipaddr_val + 1 else: peer_addr_val = ipaddr_val - 1 if peer_addr_val is not None: intf['peer_addr'] = ipaddress.IPAddress(peer_addr_val) intfs.append(intf) lointfs = child.find(str(QName(ns, "LoopbackIPInterfaces"))) lo_intfs = [] for lointf in lointfs.findall(str(QName(ns1, "LoopbackIPInterface"))): intfname = lointf.find(str(QName(ns, "AttachTo"))).text ipprefix = lointf.find(str(QName(ns1, "PrefixStr"))).text ipn = ipaddress.IPNetwork(ipprefix) ipaddr = ipn.ip prefix_len = ipn.prefixlen ipmask = ipn.netmask lo_intf = { 'name': intfname, 'addr': ipaddr, 'prefixlen': prefix_len } if isinstance(ipn, ipaddress.IPv4Network): lo_intf['mask'] = ipmask else: lo_intf['mask'] = str(prefix_len) lo_intfs.append(lo_intf) mgmtintfs = child.find(str(QName(ns, "ManagementIPInterfaces"))) mgmt_intf = None for mgmtintf in mgmtintfs.findall( str(QName(ns1, "ManagementIPInterface"))): ipprefix = mgmtintf.find(str(QName(ns1, "PrefixStr"))).text mgmtipn = ipaddress.IPNetwork(ipprefix) ipaddr = mgmtipn.ip prefix_len = str(mgmtipn.prefixlen) ipmask = mgmtipn.netmask gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) mgmt_intf = { 'addr': ipaddr, 'prefixlen': prefix_len, 'mask': ipmask, 'gwaddr': gwaddr } pcintfs = child.find(str(QName(ns, "PortChannelInterfaces"))) pc_intfs = [] pcs = {} for pcintf in pcintfs.findall(str(QName(ns, "PortChannel"))): pcintfname = pcintf.find(str(QName(ns, "Name"))).text pcintfmbr = pcintf.find(str(QName(ns, "AttachTo"))).text pcmbr_list = pcintfmbr.split(';') for i, member in enumerate(pcmbr_list): pcmbr_list[i] = port_alias_map.get(member, member) pcs[pcintfname] = {'name': pcintfname, 'members': pcmbr_list} vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) vlan_intfs = [] vlans = {} for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): vintfname = vintf.find(str(QName(ns, "Name"))).text vlanid = vintf.find(str(QName(ns, "VlanID"))).text vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text vmbr_list = vintfmbr.split(';') for i, member in enumerate(vmbr_list): vmbr_list[i] = port_alias_map.get(member, member) vlan_attributes = { 'name': vintfname, 'members': vmbr_list, 'vlanid': vlanid } sonic_vlan_name = "Vlan%s" % vlanid vlans[sonic_vlan_name] = vlan_attributes aclintfs = child.find(str(QName(ns, "AclInterfaces"))) acls = {} for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))): aclname = aclintf.find(str(QName(ns, "InAcl"))).text.lower().replace( " ", "_").replace("-", "_") aclattach = aclintf.find(str(QName(ns, "AttachTo"))).text.split(';') acl_intfs = [] is_mirror = False for member in aclattach: member = member.strip() if pcs.has_key(member): acl_intfs.extend( pcs[member]['members'] ) # For ACL attaching to port channels, we break them into port channel members elif vlans.has_key(member): print >> sys.stderr, "Warning: ACL " + aclname + " is attached to a Vlan interface, which is currently not supported" elif port_alias_map.has_key(member): acl_intfs.append(port_alias_map[member]) elif member.lower() == 'erspan': is_mirror = True # Erspan session will be attached to all front panel ports acl_intfs = port_alias_map.values() break if acl_intfs: acls[aclname] = {'AttachTo': acl_intfs, 'IsMirror': is_mirror} return intfs, lo_intfs, mgmt_intf, vlans, pcs, acls return None, None, None, None, None, None
def test_property_is_element(self): var = XmlElement(name="foo", qname=QName("foo")) self.assertIsInstance(var, XmlVar) self.assertTrue(var.is_element)
def test_property_is_wildcard(self): var = XmlWildcard(name="foo", qname=QName("foo")) self.assertIsInstance(var, XmlVar) self.assertTrue(var.is_wildcard)
def test_property_is_list(self): var = XmlVar(name="foo", qname=QName("foo")) self.assertFalse(var.is_list) var = XmlVar(name="foo", qname=QName("foo"), types=[int], default=list) self.assertTrue(var.is_list)
def test_matches(self): var = XmlVar(name="foo", qname=QName("foo")) self.assertTrue(var.matches(QNames.ALL)) self.assertTrue(var.matches(var.qname)) self.assertFalse(var.matches(QName("bar")))
def test_property_is_tokens(self): var = XmlText(name="foo", qname=QName("foo")) self.assertFalse(var.is_tokens) var = XmlText(name="foo", qname=QName("foo"), default=list) self.assertTrue(var.is_tokens)
def test_property_is_attributes(self): var = XmlAttributes(name="foo", qname=QName("foo")) self.assertIsInstance(var, XmlVar) self.assertTrue(var.is_attributes)
def is_text_property(property): tag = QName(property).localname return tag in ['bstr', 'lpstr', 'lpwstr']
def compose(self, data_dict, root_name=None): root_name = root_name or self.root_name root = Element(QName(NS.ds, root_name), nsmap=vars(NS)) return root
def test_property_is_any_type(self): var = XmlWildcard(name="foo", qname=QName("foo")) self.assertTrue(var.is_any_type)
pass # pylint: disable=unnecessary-pass class AltList(list): pass XMP_CONTAINERS = [ XmpContainer('Alt', AltList, AltList.append), XmpContainer('Bag', set, set.add), XmpContainer('Seq', list, list.append), ] LANG_ALTS = frozenset([ str(QName(XMP_NS_DC, 'title')), str(QName(XMP_NS_DC, 'description')), str(QName(XMP_NS_DC, 'rights')), str(QName(XMP_NS_XMP_RIGHTS, 'UsageTerms')), ]) # These are the illegal characters in XML 1.0. (XML 1.1 is a bit more permissive, # but we'll be strict to ensure wider compatibility.) re_xml_illegal_chars = re.compile( r"(?u)[^\x09\x0A\x0D\x20-\U0000D7FF\U0000E000-\U0000FFFD\U00010000-\U0010FFFF]" ) re_xml_illegal_bytes = re.compile( br"[^\x09\x0A\x0D\x20-\xFF]|�" # br"&#(?:[0-9]|0[0-9]|1[0-9]|2[0-9]|3[0-1]|x[0-9A-Fa-f]|x0[0-9A-Fa-f]|x1[0-9A-Fa-f]);" )
def test_matches(self): var = XmlWildcard(name="foo", qname=QName("foo")) self.assertTrue(var.matches(QNames.ALL)) self.assertTrue(var.matches(QName("a"))) var = XmlWildcard(name="foo", qname=QName("foo"), namespaces=["tns"]) self.assertFalse(var.matches(QName("a"))) self.assertTrue(var.matches(QName("tns", "a"))) var = XmlWildcard(name="foo", qname=QName("foo"), namespaces=["##any"]) self.assertTrue(var.matches(QName("a"))) self.assertTrue(var.matches(QName("tns", "a"))) var = XmlWildcard(name="foo", qname=QName("foo"), namespaces=[""]) self.assertTrue(var.matches(QName("a"))) self.assertFalse(var.matches(QName("tns", "a"))) var = XmlWildcard(name="foo", qname=QName("foo"), namespaces=["!tns"]) self.assertTrue(var.matches(QName("foo", "a"))) self.assertFalse(var.matches(QName("tns", "a")))
def test_compose(composer, data_dict, schema): billing_reference = composer.compose(data_dict) assert billing_reference.tag == QName(NS.cac, "BillingReference").text additional_document_reference = billing_reference.find( QName(NS.cac, "AdditionalDocumentReference")) assert additional_document_reference.find(QName(NS.cbc, "ID")).text == "JD-11-2018" assert additional_document_reference.find(QName( NS.cbc, "IssueDate")).text == "2018-11-30" assert additional_document_reference.find(QName( NS.cbc, "DocumentType")).text == u"Decisión de la JD" billing_reference_line = billing_reference.find( QName(NS.cac, "BillingReferenceLine")) assert billing_reference_line.find(QName(NS.cbc, "ID")) is not None assert billing_reference_line.find(QName(NS.cbc, "Amount")).text == ("15031725.00") assert billing_reference_line.find(QName( NS.cbc, "Amount")).attrib.get('currencyID') == 'COP' invoice_document_reference = billing_reference.find( QName(NS.cac, "InvoiceDocumentReference")) assert invoice_document_reference.find(QName(NS.cbc, "ID")).text == "PRUE980000094" assert invoice_document_reference.find(QName( NS.cbc, "UUID")).text == ("3d5a434b014429b551864c49a84164d58b11ea02") assert invoice_document_reference.find(QName( NS.cbc, "IssueDate")).text == "2018-11-30" schema.assertValid(billing_reference)
def _fields(self): fields = [] field = None # noinspection PyPep8Naming fldCharType = qn('w:fldCharType') instr = qn('w:instr') root = self._p.getroottree() instructions = '' for run in self.runs: for chld in run._r.getchildren(): tag = QName(chld.tag).localname if tag == 'fldChar': if chld.attrib.get(fldCharType) == 'begin': field = Field(self) field.xpath_start = root.getpath(run._r) elif chld.attrib.get( fldCharType) == 'end' and field is not None: if instructions: lex = shlex.shlex(instructions, posix=True) lex.whitespace_split = True lex.commenters = '' lex.escape = '' try: tokens = list(lex) except ValueError as e: raise ParserException(str(e) + chld.text, chld) field.code = tokens[0] fmt_target = None for token in tokens[1:]: if fmt_target is not None: field.format[fmt_target].append(token) fmt_target = None elif token.startswith('\\'): fmt_target = token[1:] else: field.extra.append(token) field.xpath_end = root.getpath(run._r) fields.append(field) field = None instructions = '' elif field: if tag == 't': field.default = chld.text elif tag == 'instrText' and chld.text.strip(): instructions += chld.text for fld in self._p.xpath('./w:fldSimple'): if fld.attrib.get(instr): field = Field(self) field.xpath_start = root.getpath(fld) field.xpath_end = root.getpath(fld) if fld.find(qn('w:r')): field.default = fld.find(qn('w:r'))[0].text lex = shlex.shlex(fld.attrib.get(instr), posix=True) lex.whitespace_split = True lex.commenters = '' lex.escape = '' tokens = list(lex) field.code = tokens[0] fmt_target = None for token in tokens[1:]: if fmt_target is not None: field.format[fmt_target].append(token) fmt_target = None elif token.startswith('\\'): fmt_target = token[1:] else: field.extra.append(token) fields.append(field) return fields
def parse_cpg(cpg, hname): bgp_sessions = [] myasn = None bgp_peers_with_range = [] for child in cpg: tag = child.tag if tag == str(QName(ns, "PeeringSessions")): for session in child.findall(str(QName(ns, "BGPSession"))): start_router = session.find(str(QName(ns, "StartRouter"))).text start_peer = session.find(str(QName(ns, "StartPeer"))).text end_router = session.find(str(QName(ns, "EndRouter"))).text end_peer = session.find(str(QName(ns, "EndPeer"))).text if end_router == hname: bgp_sessions.append({ 'name': start_router, 'addr': start_peer, 'peer_addr': end_peer }) else: bgp_sessions.append({ 'name': end_router, 'addr': end_peer, 'peer_addr': start_peer }) elif child.tag == str(QName(ns, "Routers")): for router in child.findall(str(QName(ns1, "BGPRouterDeclaration"))): asn = router.find(str(QName(ns1, "ASN"))).text hostname = router.find(str(QName(ns1, "Hostname"))).text if hostname == hname: myasn = int(asn) peers = router.find(str(QName(ns1, "Peers"))) for bgpPeer in peers.findall(str(QName(ns, "BGPPeer"))): addr = bgpPeer.find(str(QName(ns, "Address"))).text if bgpPeer.find(str(QName(ns1, "PeersRange"))) is not None: name = bgpPeer.find(str(QName(ns1, "Name"))).text ip_range = bgpPeer.find( str(QName(ns1, "PeersRange"))).text ip_range_group = ip_range.split( ';') if ip_range and ip_range != "" else [] bgp_peers_with_range.append({ 'name': name, 'ip_range': ip_range_group }) else: for bgp_session in bgp_sessions: if hostname == bgp_session['name']: bgp_session['asn'] = int(asn) return bgp_sessions, myasn, bgp_peers_with_range
def parse_dpg(dpg, hname): for child in dpg: hostname = child.find(str(QName(ns, "Hostname"))) if hostname.text != hname: continue ipintfs = child.find(str(QName(ns, "IPInterfaces"))) intfs = [] vlan_map = {} for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))): intfname = ipintf.find(str(QName(ns, "AttachTo"))).text ipprefix = ipintf.find(str(QName(ns, "Prefix"))).text ipn = ipaddress.IPNetwork(ipprefix) ipaddr = ipn.ip prefix_len = ipn.prefixlen addr_bits = ipn.max_prefixlen subnet = ipaddress.IPNetwork( str(ipn.network) + '/' + str(prefix_len)) ipmask = ipn.netmask intf = {'addr': ipaddr, 'subnet': subnet} if isinstance(ipn, ipaddress.IPv4Network): intf['mask'] = ipmask else: intf['mask'] = str(prefix_len) if intfname[0:4] == "Vlan": if intfname in vlan_map: vlan_map[intfname].append(intf) else: vlan_map[intfname] = [intf] else: intf.update({'name': intfname, 'prefixlen': int(prefix_len)}) if port_alias_map.has_key(intfname): intf['alias'] = port_alias_map[intfname] else: intf['alias'] = intfname # TODO: remove peer_addr after dependency removed ipaddr_val = int(ipn.ip) peer_addr_val = None if int(prefix_len) == addr_bits - 2: if ipaddr_val & 0x3 == 1: peer_addr_val = ipaddr_val + 1 else: peer_addr_val = ipaddr_val - 1 elif int(prefix_len) == addr_bits - 1: if ipaddr_val & 0x1 == 0: peer_addr_val = ipaddr_val + 1 else: peer_addr_val = ipaddr_val - 1 if peer_addr_val is not None: intf['peer_addr'] = ipaddress.IPAddress(peer_addr_val) intfs.append(intf) pcintfs = child.find(str(QName(ns, "PortChannelInterfaces"))) pc_intfs = [] for pcintf in pcintfs.findall(str(QName(ns, "PortChannel"))): pcintfname = pcintf.find(str(QName(ns, "Name"))).text pcintfmbr = pcintf.find(str(QName(ns, "AttachTo"))).text pcmbr_list = pcintfmbr.split(';', 1) pc_intfs.append({'name': pcintfname, 'members': pcmbr_list}) lointfs = child.find(str(QName(ns, "LoopbackIPInterfaces"))) lo_intfs = [] for lointf in lointfs.findall(str(QName(ns1, "LoopbackIPInterface"))): intfname = lointf.find(str(QName(ns, "AttachTo"))).text ipprefix = lointf.find(str(QName(ns1, "PrefixStr"))).text ipn = ipaddress.IPNetwork(ipprefix) ipaddr = ipn.ip prefix_len = ipn.prefixlen ipmask = ipn.netmask lo_intf = { 'name': intfname, 'addr': ipaddr, 'prefixlen': prefix_len } if isinstance(ipn, ipaddress.IPv4Network): lo_intf['mask'] = ipmask else: lo_intf['mask'] = str(prefix_len) lo_intfs.append(lo_intf) mgmtintfs = child.find(str(QName(ns, "ManagementIPInterfaces"))) mgmt_intf = None for mgmtintf in mgmtintfs.findall( str(QName(ns1, "ManagementIPInterface"))): ipprefix = mgmtintf.find(str(QName(ns1, "PrefixStr"))).text mgmtipn = ipaddress.IPNetwork(ipprefix) ipaddr = mgmtipn.ip prefix_len = str(mgmtipn.prefixlen) ipmask = mgmtipn.netmask gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) mgmt_intf = { 'addr': ipaddr, 'prefixlen': prefix_len, 'mask': ipmask, 'gwaddr': gwaddr } vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) vlan_intfs = [] for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): vintfname = vintf.find(str(QName(ns, "Name"))).text vlanid = vintf.find(str(QName(ns, "VlanID"))).text vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text vmbr_list = vintfmbr.split(';') vlan_attributes = { 'name': vintfname, 'members': vmbr_list, 'vlanid': vlanid } for addrtuple in vlan_map.get(vintfname, []): vlan_attributes.update(addrtuple) vlan_intfs.append(copy.deepcopy(vlan_attributes)) return intfs, lo_intfs, mgmt_intf, vlan_intfs, pc_intfs return None, None, None, None, None
def test_compose(composer, data_dict, schema): debit_note_line = composer.compose(data_dict) assert debit_note_line.tag == QName(NS.cac, "DebitNoteLine").text assert debit_note_line.findtext(QName(NS.cbc, 'ID')) == '1' assert debit_note_line.findtext(QName(NS.cbc, 'UUID')) == 'abcd123' line_extension_amount = debit_note_line.find( QName(NS.cbc, "LineExtensionAmount")) assert line_extension_amount.text == "3456788.00" assert line_extension_amount.attrib['currencyID'] == 'COP' discrepancy_response = debit_note_line.find( QName(NS.cac, "DiscrepancyResponse")) response_code = discrepancy_response.find(QName(NS.cbc, "ResponseCode")) assert response_code.text == "2" assert debit_note_line.find(QName(NS.cac, "BillingReference")) is not None tax_total = debit_note_line.find(QName(NS.cac, "TaxTotal")) assert tax_total.find(QName(NS.cbc, "TaxAmount")).text == "2856027.75" assert tax_total.find(QName(NS.cbc, "TaxAmount")).attrib.get('currencyID') == "COP" item = debit_note_line.find(QName(NS.cac, "Item")) assert item.find(QName(NS.cbc, "Description")).text == ("[CARD] Graphics Card") assert item.find(QName(NS.cbc, "AdditionalInformation")).text == ( "El sistema de la DIAN indico que la firma digital " "esta fallida") schema.assertValid(debit_note_line)
def parse_xml(filename, hostname): mini_graph_path, root = reconcile_mini_graph_locations(filename, hostname) u_neighbors = None u_devices = None hwsku = None bgp_sessions = None bgp_asn = None intfs = None vlan_intfs = None pc_intfs = None mgmt_intf = None lo_intf = None neighbors = None devices = None syslog_servers = [] dhcp_servers = [] ntp_servers = [] hwsku_qn = QName(ns, "HwSku") for child in root: if child.tag == str(hwsku_qn): hwsku = child.text # port_alias_map maps ngs port name to sonic port name if hwsku == "Force10-S6000": for i in range(0, 128, 4): port_alias_map["fortyGigE0/%d" % i] = "Ethernet%d" % i elif hwsku == "Force10-S6100": for i in range(0, 4): for j in range(0, 16): port_alias_map["fortyGigE1/%d/%d" % (i + 1, j + 1)] = "Ethernet%d" % (i * 16 + j) elif hwsku == "Arista-7050-QX32": for i in range(1, 25): port_alias_map["Ethernet%d/1" % i] = "Ethernet%d" % ((i - 1) * 4) for i in range(25, 33): port_alias_map["Ethernet%d" % i] = "Ethernet%d" % ((i - 1) * 4) else: for i in range(0, 128, 4): port_alias_map["Ethernet%d" % i] = "Ethernet%d" % i for child in root: if child.tag == str(QName(ns, "DpgDec")): (intfs, lo_intfs, mgmt_intf, vlan_intfs, pc_intfs) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_asn) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) = parse_png(child, hostname) elif child.tag == str(QName(ns, "UngDec")): (u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname) elif child.tag == str(QName(ns, "MetadataDeclaration")): (syslog_servers, dhcp_servers, ntp_servers) = parse_meta(child, hostname) # Replace port with alias in Vlan interfaces members if vlan_intfs is not None: for vlan in vlan_intfs: for i, member in enumerate(vlan['members']): vlan['members'][i] = port_alias_map[member] # Convert vlan members into a space-delimited string vlan['members'] = " ".join(vlan['members']) # Replace port with alias in port channel interfaces members if pc_intfs is not None: for pc in pc_intfs: for i, member in enumerate(pc['members']): pc['members'][i] = port_alias_map[member] # Create port index map. Since we currently output a mix of NGS names # and SONiC mapped names, we include both in this map. # SONiC aliases, when sorted in natural sort order, match the phyical port # index order, so we sort by SONiC port alias, and map # back to NGS names after sorting using this inverted map # # TODO: Move all alias-related code out of minigraph_facts.py and into # its own module to be used as another layer after parsing the minigraph. inverted_port_alias_map = {v: k for k, v in port_alias_map.iteritems()} # Start by creating a list of all port aliases port_alias_list = [] for k, v in port_alias_map.iteritems(): port_alias_list.append(v) # Sort the list in natural order port_alias_list_sorted = natsorted(port_alias_list) # Create map from SONiC alias to physical index and NGS name to physical index port_index_map = {} for idx, val in enumerate(port_alias_list_sorted): port_index_map[val] = idx port_index_map[inverted_port_alias_map[val]] = idx # Create maps: # from SONiC phy iface name to NGS phy iface name # from NGS phy iface name to SONiC phy iface name # These maps include mappings from original name to original name too iface_map_sonic_to_ngs = {} iface_map_ngs_to_sonic = {} for val in port_alias_list_sorted: iface_map_sonic_to_ngs[val] = inverted_port_alias_map[val] iface_map_sonic_to_ngs[ inverted_port_alias_map[val]] = inverted_port_alias_map[val] iface_map_ngs_to_sonic[inverted_port_alias_map[val]] = val iface_map_ngs_to_sonic[val] = val # Generate results Tree = lambda: defaultdict(Tree) results = Tree() results['minigraph_hwsku'] = hwsku # sorting by lambdas are not easily done without custom filters. # TODO: add jinja2 filter to accept a lambda to sort a list of dictionaries by attribute. # TODO: alternatively (preferred), implement class containers for multiple-attribute entries, enabling sort by attr results['minigraph_bgp'] = sorted(bgp_sessions, key=lambda x: x['addr']) results['minigraph_bgp_asn'] = bgp_asn # TODO: sort does not work properly on all interfaces of varying lengths. Need to sort by integer group(s). results['minigraph_interfaces'] = sorted(intfs, key=lambda x: x['name']) results['minigraph_vlan_interfaces'] = vlan_intfs results['minigraph_portchannel_interfaces'] = pc_intfs results['minigraph_mgmt_interface'] = mgmt_intf results['minigraph_lo_interfaces'] = lo_intfs results['minigraph_neighbors'] = neighbors results['minigraph_devices'] = devices results['minigraph_underlay_neighbors'] = u_neighbors results['minigraph_underlay_devices'] = u_devices # note - this may include files under acs/ansible/minigraph, or those under the default cache folder. # (see ANSIBLE_USER_MINIGRAPH_PATH at the top of the module) results['minigraph_as_xml'] = mini_graph_path results['minigraph_console'] = get_console_info(devices, console_dev, console_port) results['minigraph_mgmt'] = get_mgmt_info(devices, mgmt_dev, mgmt_port) results['minigraph_port_indices'] = port_index_map results['minigraph_map_sonic_to_ngs'] = iface_map_sonic_to_ngs results['minigraph_map_ngs_to_sonic'] = iface_map_ngs_to_sonic results['syslog_servers'] = syslog_servers results['dhcp_servers'] = dhcp_servers results['ntp_servers'] = ntp_servers return results
def parse_xml(filename, platform=None, port_config_file=None): root = ET.parse(filename).getroot() mini_graph_path = filename u_neighbors = None u_devices = None hwsku = None bgp_sessions = None bgp_asn = None intfs = None vlan_intfs = None pc_intfs = None vlans = None vlan_members = None pcs = None mgmt_intf = None lo_intf = None neighbors = None devices = None hostname = None port_speeds = {} port_descriptions = {} syslog_servers = [] dhcp_servers = [] ntp_servers = [] mgmt_routes = [] erspan_dst = [] bgp_peers_with_range = None deployment_id = None hwsku_qn = QName(ns, "HwSku") hostname_qn = QName(ns, "Hostname") for child in root: if child.tag == str(hwsku_qn): hwsku = child.text if child.tag == str(hostname_qn): hostname = child.text (ports, alias_map) = get_port_config(hwsku, platform, port_config_file) port_alias_map.update(alias_map) for child in root: if child.tag == str(QName(ns, "DpgDec")): (intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, acls) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) = parse_png(child, hostname) elif child.tag == str(QName(ns, "UngDec")): (u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname) elif child.tag == str(QName(ns, "MetadataDeclaration")): (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id) = parse_meta(child, hostname) elif child.tag == str(QName(ns, "DeviceInfos")): (port_speeds, port_descriptions) = parse_deviceinfo(child, hwsku) results = {} results['DEVICE_METADATA'] = { 'localhost': { 'bgp_asn': bgp_asn, 'deployment_id': deployment_id, 'hostname': hostname, 'hwsku': hwsku, 'type': devices[hostname]['type'] } } results['BGP_NEIGHBOR'] = bgp_sessions results['BGP_PEER_RANGE'] = bgp_peers_with_range if mgmt_routes: # TODO: differentiate v4 and v6 mgmt_intf.itervalues().next()['forced_mgmt_routes'] = mgmt_routes results['MGMT_INTERFACE'] = mgmt_intf results['LOOPBACK_INTERFACE'] = lo_intfs phyport_intfs = {} vlan_intfs = {} pc_intfs = {} for intf in intfs: if intf[0][0:4] == 'Vlan': vlan_intfs[intf] = {} elif intf[0][0:11] == 'PortChannel': pc_intfs[intf] = {} else: phyport_intfs[intf] = {} results['INTERFACE'] = phyport_intfs results['VLAN_INTERFACE'] = vlan_intfs results['PORTCHANNEL_INTERFACE'] = pc_intfs for port_name in port_speeds: ports.setdefault(port_name, {})['speed'] = port_speeds[port_name] for port_name in port_descriptions: ports.setdefault(port_name, {})['description'] = port_descriptions[port_name] results['PORT'] = ports results['PORTCHANNEL'] = pcs results['VLAN'] = vlans results['VLAN_MEMBER'] = vlan_members results['DEVICE_NEIGHBOR'] = neighbors results['DEVICE_NEIGHBOR_METADATA'] = { key: devices[key] for key in devices if key != hostname } results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers) results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers) results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) results['ACL_TABLE'] = acls mirror_sessions = {} if erspan_dst: lo_addr = '0.0.0.0' for lo in lo_intfs: lo_network = ipaddress.IPNetwork(lo[1]) if lo_network.version == 4: lo_addr = str(lo_network.ip) break count = 0 for dst in erspan_dst: mirror_sessions['everflow{}'.format(count)] = { "dst_ip": dst, "src_ip": lo_addr } count += 1 results['MIRROR_SESSION'] = mirror_sessions return results
def parse_png(png, hname): neighbors = {} devices = {} console_dev = '' console_port = '' mgmt_dev = '' mgmt_port = '' for child in png: if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for link in child.findall(str(QName(ns, "DeviceLinkBase"))): linktype = link.find(str(QName(ns, "ElementType"))).text if linktype != "DeviceInterfaceLink" and linktype != "UnderlayInterfaceLink": continue enddevice = link.find(str(QName(ns, "EndDevice"))).text endport = link.find(str(QName(ns, "EndPort"))).text startdevice = link.find(str(QName(ns, "StartDevice"))).text startport = link.find(str(QName(ns, "StartPort"))).text if enddevice == hname: neighbors[endport] = { 'name': startdevice, 'port': startport } else: neighbors[startport] = {'name': enddevice, 'port': endport} if child.tag == str(QName(ns, "Devices")): for device in child.findall(str(QName(ns, "Device"))): lo_addr = None # don't shadow type() d_type = None mgmt_addr = None hwsku = None if str(QName(ns3, "type")) in device.attrib: d_type = device.attrib[str(QName(ns3, "type"))] for node in device: if node.tag == str(QName(ns, "Address")): lo_addr = node.find(str(QName( ns2, "IPPrefix"))).text.split('/')[0] elif node.tag == str(QName(ns, "ManagementAddress")): mgmt_addr = node.find(str(QName( ns2, "IPPrefix"))).text.split('/')[0] elif node.tag == str(QName(ns, "Hostname")): name = node.text elif node.tag == str(QName(ns, "HwSku")): hwsku = node.text devices[name] = { 'lo_addr': lo_addr, 'type': d_type, 'mgmt_addr': mgmt_addr, 'hwsku': hwsku } if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for if_link in child.findall(str(QName(ns, 'DeviceLinkBase'))): if str(QName(ns3, "type")) in if_link.attrib: link_type = if_link.attrib[str(QName(ns3, "type"))] if link_type == 'DeviceSerialLink': for node in if_link: if node.tag == str(QName(ns, "EndPort")): console_port = node.text.split()[-1] elif node.tag == str(QName(ns, "EndDevice")): console_dev = node.text elif link_type == 'DeviceMgmtLink': for node in if_link: if node.tag == str(QName(ns, "EndPort")): mgmt_port = node.text.split()[-1] elif node.tag == str(QName(ns, "EndDevice")): mgmt_dev = node.text return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port)
def parse_dpg(dpg, hname): for child in dpg: hostname = child.find(str(QName(ns, "Hostname"))) if hostname.text.lower() != hname.lower(): continue ipintfs = child.find(str(QName(ns, "IPInterfaces"))) intfs = {} for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))): intfalias = ipintf.find(str(QName(ns, "AttachTo"))).text intfname = port_alias_map.get(intfalias, intfalias) ipprefix = ipintf.find(str(QName(ns, "Prefix"))).text intfs[(intfname, ipprefix)] = {} lointfs = child.find(str(QName(ns, "LoopbackIPInterfaces"))) lo_intfs = {} for lointf in lointfs.findall(str(QName(ns1, "LoopbackIPInterface"))): intfname = lointf.find(str(QName(ns, "AttachTo"))).text ipprefix = lointf.find(str(QName(ns1, "PrefixStr"))).text lo_intfs[(intfname, ipprefix)] = {} mgmtintfs = child.find(str(QName(ns, "ManagementIPInterfaces"))) mgmt_intf = {} for mgmtintf in mgmtintfs.findall( str(QName(ns1, "ManagementIPInterface"))): intfname = mgmtintf.find(str(QName(ns, "AttachTo"))).text ipprefix = mgmtintf.find(str(QName(ns1, "PrefixStr"))).text mgmtipn = ipaddress.IPNetwork(ipprefix) gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) mgmt_intf[(intfname, ipprefix)] = {'gwaddr': gwaddr} pcintfs = child.find(str(QName(ns, "PortChannelInterfaces"))) pc_intfs = [] pcs = {} pc_members = {} intfs_inpc = [] # List to hold all the LAG member interfaces for pcintf in pcintfs.findall(str(QName(ns, "PortChannel"))): pcintfname = pcintf.find(str(QName(ns, "Name"))).text pcintfmbr = pcintf.find(str(QName(ns, "AttachTo"))).text pcmbr_list = pcintfmbr.split(';') pc_intfs.append(pcintfname) for i, member in enumerate(pcmbr_list): pcmbr_list[i] = port_alias_map.get(member, member) intfs_inpc.append(pcmbr_list[i]) pc_members[(pcintfname, pcmbr_list[i])] = {'NULL': 'NULL'} if pcintf.find(str(QName(ns, "Fallback"))) != None: pcs[pcintfname] = { 'members': pcmbr_list, 'fallback': pcintf.find(str(QName(ns, "Fallback"))).text, 'min_links': str(int(math.ceil(len() * 0.75))) } else: pcs[pcintfname] = { 'members': pcmbr_list, 'min_links': str(int(math.ceil(len(pcmbr_list) * 0.75))) } vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) vlan_intfs = [] vlans = {} vlan_members = {} for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): vintfname = vintf.find(str(QName(ns, "Name"))).text vlanid = vintf.find(str(QName(ns, "VlanID"))).text vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text vmbr_list = vintfmbr.split(';') for i, member in enumerate(vmbr_list): vmbr_list[i] = port_alias_map.get(member, member) sonic_vlan_member_name = "Vlan%s" % (vlanid) vlan_members[(sonic_vlan_member_name, vmbr_list[i])] = { 'tagging_mode': 'untagged' } vlan_attributes = {'vlanid': vlanid} # If this VLAN requires a DHCP relay agent, it will contain a <DhcpRelays> element # containing a list of DHCP server IPs vintf_node = vintf.find(str(QName(ns, "DhcpRelays"))) if vintf_node is not None and vintf_node.text is not None: vintfdhcpservers = vintf_node.text vdhcpserver_list = vintfdhcpservers.split(';') vlan_attributes['dhcp_servers'] = vdhcpserver_list sonic_vlan_name = "Vlan%s" % vlanid if sonic_vlan_name != vintfname: vlan_attributes['alias'] = vintfname vlans[sonic_vlan_name] = vlan_attributes aclintfs = child.find(str(QName(ns, "AclInterfaces"))) acls = {} for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))): aclname = aclintf.find(str(QName(ns, "InAcl"))).text.upper().replace( " ", "_").replace("-", "_") aclattach = aclintf.find(str(QName(ns, "AttachTo"))).text.split(';') acl_intfs = [] is_mirror = False # TODO: Ensure that acl_intfs will only ever contain front-panel interfaces (e.g., # maybe we should explicity ignore management and loopback interfaces?) because we # decide an ACL is a Control Plane ACL if acl_intfs is empty below. for member in aclattach: member = member.strip() if pcs.has_key(member): # If try to attach ACL to a LAG interface then we shall add the LAG to # to acl_intfs directly instead of break it into member ports, ACL attach # to LAG will be applied to all the LAG members internally by SAI/SDK acl_intfs.append(member) elif vlans.has_key(member): print >> sys.stderr, "Warning: ACL " + aclname + " is attached to a Vlan interface, which is currently not supported" elif port_alias_map.has_key(member): acl_intfs.append(port_alias_map[member]) # Give a warning if trying to attach ACL to a LAG member interface, correct way is to attach ACL to the LAG interface if port_alias_map[member] in intfs_inpc: print >> sys.stderr, "Warning: ACL " + aclname + " is attached to a LAG member interface " + port_alias_map[ member] + ", instead of LAG interface" elif member.lower().startswith('erspan'): is_mirror = True # Erspan session will be attached to all front panel ports, # if panel ports is a member port of LAG, should add the LAG # to acl table instead of the panel ports acl_intfs = pc_intfs[:] for panel_port in port_alias_map.values(): if panel_port not in intfs_inpc: acl_intfs.append(panel_port) break if acl_intfs: acls[aclname] = { 'policy_desc': aclname, 'ports': acl_intfs, 'type': 'MIRROR' if is_mirror else 'L3' } elif is_mirror: acls[aclname] = {'policy_desc': aclname, 'type': 'MIRROR'} else: # This ACL has no interfaces to attach to -- consider this a control plane ACL try: aclservice = aclintf.find(str(QName(ns, "Type"))).text # If we already have an ACL with this name and this ACL is bound to a different service, # append the service to our list of services if aclname in acls: if acls[aclname]['type'] != 'CTRLPLANE': print >> sys.stderr, "Warning: ACL '%s' type mismatch. Not updating ACL." % aclname elif acls[aclname]['services'] == aclservice: print >> sys.stderr, "Warning: ACL '%s' already contains service '%s'. Not updating ACL." % ( aclname, aclservice) else: acls[aclname]['services'].append(aclservice) else: acls[aclname] = { 'policy_desc': aclname, 'type': 'CTRLPLANE', 'services': [aclservice] } except: print >> sys.stderr, "Warning: Ignoring Control Plane ACL %s without type" % aclname return intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls return None, None, None, None, None, None, None
def parse_png(png, hname): neighbors = {} devices = {} console_dev = '' console_port = '' mgmt_dev = '' mgmt_port = '' port_speeds = {} console_ports = {} for child in png: if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for link in child.findall(str(QName(ns, "DeviceLinkBase"))): linktype = link.find(str(QName(ns, "ElementType"))).text if linktype == "DeviceSerialLink": enddevice = link.find(str(QName(ns, "EndDevice"))).text endport = link.find(str(QName(ns, "EndPort"))).text startdevice = link.find(str(QName(ns, "StartDevice"))).text startport = link.find(str(QName(ns, "StartPort"))).text baudrate = link.find(str(QName(ns, "Bandwidth"))).text flowcontrol = 1 if link.find(str(QName(ns, "FlowControl"))) is not None and link.find(str(QName(ns, "FlowControl"))).text == 'true' else 0 if enddevice.lower() == hname.lower(): console_ports[endport] = { 'remote_device': startdevice, 'baud_rate': baudrate, 'flow_control': flowcontrol } else: console_ports[startport] = { 'remote_device': enddevice, 'baud_rate': baudrate, 'flow_control': flowcontrol } continue if linktype != "DeviceInterfaceLink" and linktype != "UnderlayInterfaceLink": continue enddevice = link.find(str(QName(ns, "EndDevice"))).text endport = link.find(str(QName(ns, "EndPort"))).text startdevice = link.find(str(QName(ns, "StartDevice"))).text startport = link.find(str(QName(ns, "StartPort"))).text bandwidth_node = link.find(str(QName(ns, "Bandwidth"))) bandwidth = bandwidth_node.text if bandwidth_node is not None else None if enddevice.lower() == hname.lower(): if port_alias_map.has_key(endport): endport = port_alias_map[endport] neighbors[endport] = {'name': startdevice, 'port': startport} if bandwidth: port_speeds[endport] = bandwidth else: if port_alias_map.has_key(startport): startport = port_alias_map[startport] neighbors[startport] = {'name': enddevice, 'port': endport} if bandwidth: port_speeds[startport] = bandwidth if child.tag == str(QName(ns, "Devices")): for device in child.findall(str(QName(ns, "Device"))): (lo_prefix, mgmt_prefix, name, hwsku, d_type, deployment_id) = parse_device(device) device_data = {'lo_addr': lo_prefix, 'type': d_type, 'mgmt_addr': mgmt_prefix, 'hwsku': hwsku } if deployment_id: device_data['deployment_id'] = deployment_id devices[name] = device_data if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for if_link in child.findall(str(QName(ns, 'DeviceLinkBase'))): if str(QName(ns3, "type")) in if_link.attrib: link_type = if_link.attrib[str(QName(ns3, "type"))] if link_type == 'DeviceSerialLink': for node in if_link: if node.tag == str(QName(ns, "EndPort")): console_port = node.text.split()[-1] elif node.tag == str(QName(ns, "EndDevice")): console_dev = node.text elif link_type == 'DeviceMgmtLink': for node in if_link: if node.tag == str(QName(ns, "EndPort")): mgmt_port = node.text.split()[-1] elif node.tag == str(QName(ns, "EndDevice")): mgmt_dev = node.text return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speeds, console_ports)
def parse_xml(filename, platform=None, port_config_file=None): root = ET.parse(filename).getroot() mini_graph_path = filename u_neighbors = None u_devices = None hwsku = None bgp_sessions = None bgp_asn = None intfs = None vlan_intfs = None pc_intfs = None vlans = None vlan_members = None pcs = None mgmt_intf = None lo_intf = None neighbors = None devices = None hostname = None docker_routing_config_mode = "unified" port_speeds_default = {} port_speed_png = {} port_descriptions = {} console_ports = {} syslog_servers = [] dhcp_servers = [] ntp_servers = [] tacacs_servers = [] mgmt_routes = [] erspan_dst = [] bgp_peers_with_range = None deployment_id = None hwsku_qn = QName(ns, "HwSku") hostname_qn = QName(ns, "Hostname") docker_routing_config_mode_qn = QName(ns, "DockerRoutingConfigMode") for child in root: if child.tag == str(hwsku_qn): hwsku = child.text if child.tag == str(hostname_qn): hostname = child.text if child.tag == str(docker_routing_config_mode_qn): docker_routing_config_mode = child.text (ports, alias_map) = get_port_config(hwsku, platform, port_config_file) port_alias_map.update(alias_map) for child in root: if child.tag == str(QName(ns, "DpgDec")): (intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, port_speed_png, console_ports) = parse_png(child, hostname) elif child.tag == str(QName(ns, "UngDec")): (u_neighbors, u_devices, _, _, _, _, _, _) = parse_png(child, hostname) elif child.tag == str(QName(ns, "MetadataDeclaration")): (syslog_servers, dhcp_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id) = parse_meta(child, hostname) elif child.tag == str(QName(ns, "DeviceInfos")): (port_speeds_default, port_descriptions) = parse_deviceinfo(child, hwsku) current_device = [ devices[key] for key in devices if key.lower() == hostname.lower() ][0] results = {} results['DEVICE_METADATA'] = { 'localhost': { 'bgp_asn': bgp_asn, 'deployment_id': deployment_id, 'docker_routing_config_mode': docker_routing_config_mode, 'hostname': hostname, 'hwsku': hwsku, 'type': current_device['type'] } } results['BGP_NEIGHBOR'] = bgp_sessions results['BGP_PEER_RANGE'] = bgp_peers_with_range if mgmt_routes: # TODO: differentiate v4 and v6 mgmt_intf.itervalues().next()['forced_mgmt_routes'] = mgmt_routes results['MGMT_PORT'] = {} results['MGMT_INTERFACE'] = {} mgmt_intf_count = 0 mgmt_alias_reverse_mapping = {} for key in mgmt_intf: alias = key[0] if mgmt_alias_reverse_mapping.has_key(alias): name = mgmt_alias_reverse_mapping[alias] else: name = 'eth' + str(mgmt_intf_count) mgmt_intf_count += 1 mgmt_alias_reverse_mapping[alias] = name results['MGMT_PORT'][name] = {'alias': alias, 'admin_status': 'up'} results['MGMT_INTERFACE'][(name, key[1])] = mgmt_intf[key] results['LOOPBACK_INTERFACE'] = lo_intfs phyport_intfs = {} vlan_intfs = {} pc_intfs = {} vlan_invert_mapping = { v['alias']: k for k, v in vlans.items() if v.has_key('alias') } for intf in intfs: if intf[0][0:4] == 'Vlan': vlan_intfs[intf] = {} elif vlan_invert_mapping.has_key(intf[0]): vlan_intfs[(vlan_invert_mapping[intf[0]], intf[1])] = {} elif intf[0][0:11] == 'PortChannel': pc_intfs[intf] = {} else: phyport_intfs[intf] = {} results['INTERFACE'] = phyport_intfs results['VLAN_INTERFACE'] = vlan_intfs for port_name in port_speeds_default: # ignore port not in port_config.ini if not ports.has_key(port_name): continue ports.setdefault(port_name, {})['speed'] = port_speeds_default[port_name] for port_name in port_speed_png: # not consider port not in port_config.ini if port_name not in ports: print >> sys.stderr, "Warning: ignore interface '%s' as it is not in the port_config.ini" % port_name continue ports.setdefault(port_name, {})['speed'] = port_speed_png[port_name] for port_name, port in ports.items(): if port.get('speed') == '100000': port['fec'] = 'rs' # set port description if parsed from deviceinfo for port_name in port_descriptions: # ignore port not in port_config.ini if not ports.has_key(port_name): continue ports.setdefault(port_name, {})['description'] = port_descriptions[port_name] for port_name, port in ports.items(): if not port.get('description'): if neighbors.has_key(port_name): # for the ports w/o description set it to neighbor name:port port['description'] = "%s:%s" % (neighbors[port_name]['name'], neighbors[port_name]['port']) else: # for the ports w/o neighbor info, set it to port alias port['description'] = port.get('alias', port_name) # set default port MTU as 9100 for port in ports.itervalues(): port['mtu'] = '9100' # asymmetric PFC is disabled by default for port in ports.itervalues(): port['pfc_asym'] = 'off' # set physical port default admin status up for port in phyport_intfs: if port[0] in ports: ports.get(port[0])['admin_status'] = 'up' for member in pc_members.keys() + vlan_members.keys(): port = ports.get(member[1]) if port: port['admin_status'] = 'up' results['PORT'] = ports results['CONSOLE_PORT'] = console_ports if port_config_file: port_set = set(ports.keys()) for (pc_name, mbr_map) in pcs.items(): # remove portchannels that contain ports not existing in port_config.ini # when port_config.ini exists if not set(mbr_map['members']).issubset(port_set): print >> sys.stderr, "Warning: ignore '%s' as part of its member interfaces is not in the port_config.ini" % pc_name del pcs[pc_name] # set default port channel MTU as 9100 and admin status up for pc in pcs.itervalues(): pc['mtu'] = '9100' pc['admin_status'] = 'up' results['PORTCHANNEL'] = pcs results['PORTCHANNEL_MEMBER'] = pc_members for pc_intf in pc_intfs.keys(): # remove portchannels not in PORTCHANNEL dictionary if pc_intf[0] not in pcs: print >> sys.stderr, "Warning: ignore '%s' interface '%s' as '%s' is not in the valid PortChannel list" % ( pc_intf[0], pc_intf[1], pc_intf[0]) del pc_intfs[pc_intf] results['PORTCHANNEL_INTERFACE'] = pc_intfs results['VLAN'] = vlans results['VLAN_MEMBER'] = vlan_members for nghbr in neighbors.keys(): # remove port not in port_config.ini if nghbr not in ports: print >> sys.stderr, "Warning: ignore interface '%s' in DEVICE_NEIGHBOR as it is not in the port_config.ini" % nghbr del neighbors[nghbr] results['DEVICE_NEIGHBOR'] = neighbors results['DEVICE_NEIGHBOR_METADATA'] = { key: devices[key] for key in devices if key.lower() != hostname.lower() } results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers) results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers) results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) results['TACPLUS_SERVER'] = dict((item, { 'priority': '1', 'tcp_port': '49' }) for item in tacacs_servers) results['ACL_TABLE'] = acls mirror_sessions = {} if erspan_dst: lo_addr = '0.0.0.0' for lo in lo_intfs: lo_network = ipaddress.IPNetwork(lo[1]) if lo_network.version == 4: lo_addr = str(lo_network.ip) break count = 0 for dst in erspan_dst: mirror_sessions['everflow{}'.format(count)] = { "dst_ip": dst, "src_ip": lo_addr } count += 1 results['MIRROR_SESSION'] = mirror_sessions return results
def _etree_mutate_fix_localname(etree): for _x in etree.iter(Element): # side-effect to remove some (wrongfully) surviving namespace stuff from HTML(5)Parser if _x.tag != QName(_x).localname: _x.tag = QName(_x).localname return etree