2 from netaddr import IPAddress
3 from string import Template
6 def get_active_controller_from_json(resp, service):
7 """Gets index of active controller running specified service
9 :param resp: JSON formatted response from EOS
11 :param service: EOS Service to look for
13 :return: Index of controller
15 entities = json.loads(resp)['entity-owners']['entity-type']
16 for entity in entities:
17 if entity['type'] == "org.opendaylight.mdsal.ServiceEntityType":
18 for instance in entity['entity']:
19 if service in instance['id']:
20 return int(instance['owner'][-1:])
25 """Gets modulo of number
27 :param num: Number to be used
29 :param base: Base used
31 :returns: Int representing modulo of specified numbers.
34 return int(num) % int(base)
37 def get_average_of_items(items):
38 """Gets average of items in provided list
40 :param items: To be proceed
41 :return: Average value
44 return sum(items) / len(items)
47 def get_opposing_mode(mode):
48 """Generate string representing opposing SXP peer mode
50 :param mode: SXP peer mode
52 :returns: String with opposing SXP peer mode.
57 elif 'listener' == mode:
62 def get_ip_from_number(n, base=2130706432):
63 """Generate string representing Ipv4 from specified number plus base value
65 :param n: Number to be converted
67 :param base: Starting index
69 :returns: String containing Ipv4.
72 ip = IPAddress(int(base) + n)
76 def get_ip_from_number_and_ip(n, ip_address):
77 """Generate string representing Ipv4 from specified number and IPAddress
79 :param n: Number to be converted
81 :param ip_address: Base address
83 :returns: String containing Ipv4.
86 ip = IPAddress(int(IPAddress(ip_address)) + n)
90 def lower_version(ver1, ver2):
91 """Generate xml containing SGT mach data
93 :param ver1: Version of SXP protocol for compare
95 :param ver2: Version of SXP protocol for compare
97 :returns: String containing lower from those two specified versions.
108 def get_filter_entry(seq, entry_type, sgt="", esgt="", acl="", eacl="", pl="", epl="", ps=""):
109 """Generate xml containing FilterEntry data
111 :param seq: Sequence of entry
113 :param entry_type: Type of entry (permit/deny)
114 :type entry_type: str
115 :param sgt: SGT matches to be added to entry
117 :param esgt: SGT ranges match to be added to entry
119 :param acl: ACL matches to be added to entry
121 :param eacl: EACL matches to be added to entry
123 :param pl: PrefixList matches to be added to entry
125 :param epl: ExtendedPrefixList matches to be added to entry
127 :param ps: PeerSequence matches to be added to entry
129 :returns: String containing xml data for request
133 # Generate XML request containing combination of Matches of different types
135 args = sgt.split(',')
136 entries += add_sgt_matches_xml(args)
138 args = esgt.split(',')
139 entries += add_sgt_range_xml(args[0], args[1])
141 entries += add_pl_entry_xml(pl)
143 args = epl.split(',')
144 entries += add_epl_entry_xml(args[0], args[1], args[2])
146 args = acl.split(',')
147 entries += add_acl_entry_xml(args[0], args[1])
149 args = eacl.split(',')
150 entries += add_eacl_entry_xml(args[0], args[1], args[2], args[3])
153 entries += add_ps_entry_xml(args[0], args[1])
154 # Wrap entries in ACL/PrefixList according to specified values
156 return add_pl_entry_default_xml(seq, entry_type, entries)
158 return add_ps_entry_default_xml(seq, entry_type, entries)
159 return add_acl_entry_default_xml(seq, entry_type, entries)
162 def add_peers(*args):
163 """Generate xml containing Peer mach data
165 :param args: Peers data
167 :returns: String containing xml data for request
172 <peer-address>$ip</peer-address>
175 for count, value in enumerate(args):
176 peers += templ.substitute({'ip': value})
180 def add_domains(*args):
181 """Generate xml containing Domain mach data
183 :param args: Domain data
185 :returns: String containing xml data for request
193 for count, value in enumerate(args):
194 peers += templ.substitute({'name': value})
198 def add_sgt_matches_xml(sgt_entries):
199 """Generate xml containing SGT mach data
201 :param sgt_entries: SGT matches
202 :type sgt_entries: str
203 :returns: String containing xml data for request
207 <matches>$sgt</matches>''')
209 for sgt in sgt_entries:
210 matches += templ.substitute({'sgt': sgt})
214 def add_sgt_range_xml(start, end):
215 """Generate xml containing SGT RangeMach data
217 :param start: Start range of SGT
219 :param end: End range of SGT
221 :returns: String containing xml data for request
225 <sgt-start>$start</sgt-start>
226 <sgt-end>$end</sgt-end>''')
227 match = templ.substitute({'start': start, 'end': end})
231 def add_acl_entry_default_xml(seq, entry_type, acl_entries):
232 """Generate xml containing AccessList data
234 :param seq: Sequence of PrefixList entry
236 :param entry_type: Entry type (permit/deny)
237 :type entry_type: str
238 :param acl_entries: XML data containing AccessList entries
239 :type acl_entries: str
240 :returns: String containing xml data for request
245 <entry-type>$entry_type</entry-type>
246 <entry-seq>$seq</entry-seq>$acl_entries
248 matches = templ.substitute(
249 {'seq': seq, 'entry_type': entry_type, 'acl_entries': acl_entries})
253 def add_acl_entry_xml(ip, mask):
254 """Generate xml containing AccessList data
256 :param ip: Ipv4/6 address
258 :param mask: Ipv4/6 wildcard mask
260 :returns: String containing xml data for request
265 <ip-address>$ip</ip-address>
266 <wildcard-mask>$mask</wildcard-mask>
268 return templ.substitute({'ip': ip, 'mask': mask})
271 def add_eacl_entry_xml(ip, mask, amask, wmask):
272 """Generate xml containing ExtendedAccessList data
274 :param ip: Ipv4/6 address
276 :param mask: Ipv4/6 wildcard mask
278 :param amask: Ipv4/6 address mask
280 :param wmask: Ipv4/6 address wildcard mask
282 :returns: String containing xml data for request
287 <ip-address>$ip</ip-address>
288 <wildcard-mask>$mask</wildcard-mask>
290 <address-mask>$amask</address-mask>
291 <wildcard-mask>$wmask</wildcard-mask>
294 return templ.substitute({'ip': ip, 'mask': mask, 'amask': amask, 'wmask': wmask})
297 def add_ps_entry_default_xml(seq, entry_type, ps_entries):
298 """Generate xml containing PeerSequence data
300 :param seq: Sequence of PrefixList entry
302 :param entry_type: Entry type (permit/deny)
303 :type entry_type: str
304 :param ps_entries: XML data containing PeerSequence entries
305 :type ps_entries: str
306 :returns: String containing xml data for request
310 <peer-sequence-entry xmlns="urn:opendaylight:sxp:controller">
311 <entry-type>$entry_type</entry-type>
312 <entry-seq>$seq</entry-seq>$ps_entries
313 </peer-sequence-entry>''')
314 return templ.substitute({'seq': seq, 'entry_type': entry_type, 'ps_entries': ps_entries})
317 def add_pl_entry_default_xml(seq, entry_type, pl_entries):
318 """Generate xml containing PrefixList data
320 :param seq: Sequence of PrefixList entry
322 :param entry_type: Entry type (permit/deny)
323 :type entry_type: str
324 :param pl_entries: XML data containing PrefixList entries
325 :type pl_entries: str
326 :returns: String containing xml data for request
330 <prefix-list-entry xmlns="urn:opendaylight:sxp:controller">
331 <entry-type>$entry_type</entry-type>
332 <entry-seq>$seq</entry-seq>$pl_entries
333 </prefix-list-entry>''')
334 return templ.substitute({'seq': seq, 'entry_type': entry_type, 'pl_entries': pl_entries})
337 def add_pl_entry_xml(prefix):
338 """Generate xml containing PrefixList data
340 :param prefix: Ipv4/6 prefix
342 :returns: String containing xml data for request
347 <ip-prefix>$prefix</ip-prefix>
348 </prefix-list-match>''')
349 return templ.substitute({'prefix': prefix})
352 def add_epl_entry_xml(prefix, op, mask):
353 """Generate xml containing Extended PrefixList data
355 :param prefix: Ipv4/6 prefix
357 :param op: PrefixList option (ge/le/eq)
359 :param mask: Ipv4/6 Mask
361 :returns: String containing xml data for request
366 <ip-prefix>$prefix</ip-prefix>
368 <mask-range>$op</mask-range>
369 <mask-value>$mask</mask-value>
371 </prefix-list-match>''')
372 return templ.substitute({'prefix': prefix, 'mask': mask, 'op': op})
375 def add_ps_entry_xml(op, length):
376 """Generate xml containing Extended PrefixList data
378 :param op: PrefixList option (ge/le/eq)
380 :param length: PeerSequence length
382 :returns: String containing xml data for request
386 <peer-sequence-length>$length</peer-sequence-length>
387 <peer-sequence-range>$op</peer-sequence-range>
389 return templ.substitute({'length': length, 'op': op})
392 def parse_peer_groups(groups_json):
393 """Parse JSON string into Array of PeerGroups
395 :param groups_json: JSON containing PeerGroups
396 :type groups_json: str
397 :returns: Array containing PeerGroups.
400 data = json.loads(groups_json)
401 groups = data['output']
403 for group in groups.values():
408 def parse_connections(connections_json):
409 """Parse JSON string into Array of Connections
411 :param connections_json: JSON containing Connections
412 :type connections_json: str
413 :returns: Array containing Connections.
416 data = json.loads(connections_json)
417 output = data['output']
420 connections = output['connections']
421 for connection in connections.values():
426 def find_connection(connections_json, version, mode, ip, port, state):
427 """Test if Connection with specified values is contained in JSON
429 :param connections_json: JSON containing Connections
430 :type connections_json: str
431 :param version: Version of SXP protocol (version1/2/3/4)
433 :param mode: Mode of SXP peer (speaker/listener/both)
435 :param ip: Ipv4/6 address of remote peer
437 :param port: Port on with remote peer listens
439 :param state: State of connection (on/off/pendingOn/deleteHoldDown)
441 :returns: True if Connection with specified params was found, otherwise False.
444 for connection in parse_connections(connections_json):
445 if (connection['peer-address'] == ip and connection['tcp-port'] == int(port) and (
446 mode.strip() == 'any' or connection['mode'] == mode) and connection['version'] == version):
449 elif connection['state'] == state:
454 def parse_bindings(bindings_json):
455 """Parse JSON string into Array of Bindings
457 :param bindings_json: JSON containing Bindings
458 :type bindings_json: str
459 :returns: Array containing Bindings.
462 data = json.loads(bindings_json)
464 for bindings_json in data['output'].values():
465 for binding in bindings_json:
466 output.append(binding)
470 def find_binding(bindings, sgt, prefix):
471 """Test if Binding with specified values is contained in JSON
473 :param bindings: JSON containing Bindings
475 :param sgt: Source Group Tag
477 :param prefix: Ipv4/6 prefix
479 :returns: True if Binding with specified params was found, otherwise False.
482 for binding in parse_bindings(bindings):
483 if binding['sgt'] == int(sgt):
484 for ip_prefix in binding['ip-prefix']:
485 if ip_prefix == prefix:
490 def parse_prefix_groups(prefix_groups_json, source_):
491 """Parse JSON string into Array of PrefixGroups
493 :param prefix_groups_json: JSON containing PrefixGroups
494 :type prefix_groups_json: str
495 :param source_: Source of PrefixGroups (sxp/local)
497 :returns: Array containing PrefixGroups.
500 data = json.loads(prefix_groups_json)
501 bindings = data['sxp-node:master-database']
503 for binding in bindings.values():
504 for binding_source in binding:
505 if source_ == "any" or binding_source['binding-source'] == source_:
506 for prefix_group in binding_source['prefix-group']:
507 output.append(prefix_group)
511 def find_binding_legacy(prefix_groups_json, sgt, prefix, source_, action):
512 """Test if Binding with specified values is contained in JSON
514 :param prefix_groups_json: JSON containing Bindings and PrefixGroups
515 :type prefix_groups_json: str
516 :param sgt: Source Group Tag
518 :param prefix: Ipv4/6 prefix
520 :param source_: Source of binding (local/sxp)
522 :param action: Action for binding (add/delete)
524 :returns: True if Binding with specified params was found, otherwise False.
528 for prefixgroup in parse_prefix_groups(prefix_groups_json, source_):
529 if prefixgroup['sgt'] == int(sgt):
530 for binding in prefixgroup['binding']:
531 if binding['ip-prefix'] == prefix and binding['action'] == action:
536 def add_connection_xml(version, mode, ip, port, node, password_, domain_name, bindings_timeout=0, security_mode=''):
537 """Generate xml for Add Connection request
539 :param version: Version of SXP protocol (version1/2/3/4)
541 :param mode: Mode of SXP peer (speaker/listener/both)
543 :param ip: Ipv4/6 address of remote peer
545 :param port: Port on with remote peer listens
547 :param node: Ipv4 address of node
549 :param password_: Password type (none/default)
551 :param domain_name: Name of Domain
552 :type domain_name: str
553 :param security_mode: Default/TSL security
554 :type security_mode: str
555 :param bindings_timeout: Specifies DHD and Reconciliation timers
556 :type bindings_timeout: int
557 :returns: String containing xml data for request
560 templ = Template('''<input>
561 <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
563 <connections xmlns="urn:opendaylight:sxp:controller">
565 <peer-address>$ip</peer-address>
566 <tcp-port>$port</tcp-port>
567 <password>$password_</password>
569 <version>$version</version>
570 <description>Connection to ISR-G2</description>
573 <hold-time-min-acceptable>45</hold-time-min-acceptable>
574 <keep-alive-time>30</keep-alive-time>
575 <reconciliation-time>$timeout</reconciliation-time>
576 <delete-hold-down-time>$timeout</delete-hold-down-time>
577 <hold-time>90</hold-time>
578 <hold-time-max>180</hold-time-max>
579 <hold-time-min>90</hold-time-min>
585 data = templ.substitute(
586 {'ip': ip, 'port': port, 'mode': mode, 'version': version, 'node': node,
587 'password_': password_, 'domain': get_domain_name(domain_name), 'timeout': bindings_timeout,
588 'security_type': '<security-type>' + security_mode + '</security-type>' if security_mode else ''})
592 def delete_connections_xml(address, port, node, domain_name):
593 """Generate xml for Delete Connection request
595 :param address: Ipv4/6 address of remote peer
597 :param port: Port on with remote peer listens
599 :param node: Ipv4 address of node
601 :param domain_name: Name of Domain
602 :type domain_name: str
603 :returns: String containing xml data for request
606 templ = Template('''<input>
607 <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
609 <peer-address xmlns="urn:opendaylight:sxp:controller">$address</peer-address>
610 <tcp-port xmlns="urn:opendaylight:sxp:controller">$port</tcp-port>
612 data = templ.substitute({'address': address, 'port': port, 'node': node, 'domain': get_domain_name(domain_name)})
616 def add_peer_group_xml(name, peers, ip):
617 """Generate xml for Add PeerGroups request
619 :param name: Name of PeerGroup
621 :param peers: XML formatted peers that will be added to group
623 :param ip: Ipv4 address of node
625 :returns: String containing xml data for request
628 templ = Template('''<input>
629 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
630 <sxp-peer-group xmlns="urn:opendaylight:sxp:controller">
631 <name xmlns="urn:opendaylight:sxp:controller">$name</name>
632 <sxp-peers xmlns="urn:opendaylight:sxp:controller">$peers</sxp-peers>
635 data = templ.substitute({'name': name, 'peers': peers, 'ip': ip})
639 def delete_peer_group_xml(name, ip):
640 """Generate xml for Delete PeerGroup request
642 :param name: Name of PeerGroup
644 :param ip: Ipv4 address of node
646 :returns: String containing xml data for request
649 templ = Template('''<input>
650 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
651 <peer-group-name xmlns="urn:opendaylight:sxp:controller">$name</peer-group-name>
653 data = templ.substitute({'name': name, 'ip': ip})
657 def get_peer_groups_from_node_xml(ip):
658 """Generate xml for Get PeerGroups request
660 :param ip: Ipv4 address of node
662 :returns: String containing xml data for request
665 templ = Template('''<input>
666 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
668 data = templ.substitute({'ip': ip})
672 def add_filter_xml(group, filter_type, entries, ip, policy=None):
673 """Generate xml for Add Filter request
675 :param group: Name of group containing filter
677 :param filter_type: Type of filter
678 :type filter_type: str
679 :param entries: XML formatted entries that will be added in filter
681 :param ip: Ipv4 address of node
683 :param policy: Policy of filter update mechanism
685 :returns: String containing xml data for request
689 policy = "<filter-policy>" + policy + "</filter-policy>"
692 templ = Template('''<input>
693 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
694 <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
695 <sxp-filter xmlns="urn:opendaylight:sxp:controller">
697 <filter-type>$filter_type</filter-type>$entries
700 data = templ.substitute(
701 {'group': group, 'filter_type': filter_type, 'ip': ip, 'entries': entries, 'filter_policy': policy})
705 def add_domain_filter_xml(domain, domains, entries, ip, filter_name=None):
706 """Generate xml for Add Domain Filter request
708 :param domain: Name of Domain containing filter
710 :param domains: Domains on which filter will be applied
712 :param entries: XML formatted entries that will be added in filter
714 :param ip: Ipv4 address of node
716 :param filter_name: Name of filter
717 :type filter_name: str
718 :returns: String containing xml data for request
722 filter_name = "<filter-name>" + filter_name + "</filter-name>"
723 templ = Template('''<input>
724 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
725 <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
726 <sxp-domain-filter xmlns="urn:opendaylight:sxp:controller">
728 <domains>$domains</domains>
732 data = templ.substitute(
733 {'domain': domain, 'domains': domains, 'ip': ip, 'entries': entries, 'filter_name': filter_name})
737 def delete_filter_xml(group, filter_type, ip):
738 """Generate xml for Delete Filter request
740 :param group: Name of group containing filter
742 :param filter_type: Type of filter
743 :type filter_type: str
744 :param ip: Ipv4 address of node
746 :returns: String containing xml data for request
749 templ = Template('''<input>
750 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
751 <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
752 <filter-type xmlns="urn:opendaylight:sxp:controller">$filter_type</filter-type>
754 data = templ.substitute(
755 {'group': group, 'filter_type': filter_type, 'ip': ip})
759 def delete_domain_filter_xml(domain, ip, filter_name=None):
760 """Generate xml for Delete Filter request
762 :param domain: Name of Domain containing filter
764 :param ip: Ipv4 address of node
766 :param filter_name: Name of filter
767 :type filter_name: str
768 :returns: String containing xml data for request
772 filter_name = '<filter-name xmlns="urn:opendaylight:sxp:controller">' + filter_name + "</filter-name>"
773 templ = Template('''<input>
774 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
775 <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
778 data = templ.substitute(
779 {'domain': domain, 'ip': ip, 'filter_name': filter_name})
783 def get_connections_from_node_xml(ip, domain_name):
784 """Generate xml for Get Connections request
786 :param ip: Ipv4 address of node
788 :param domain_name: Name of Domain
789 :type domain_name: str
790 :returns: String containing xml data for request
793 templ = Template('''<input>
794 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
797 data = templ.substitute({'ip': ip, 'domain': get_domain_name(domain_name)})
801 def get_bindings_from_node_xml(ip, binding_range, domain_name):
802 """Generate xml for Get Bindings request
804 :param binding_range: All or only Local bindings
805 :type binding_range: str
806 :param ip: Ipv4 address of node
808 :param domain_name: Name of Domain
809 :type domain_name: str
810 :returns: String containing xml data for request
813 templ = Template('''<input>
814 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
815 <bindings-range xmlns="urn:opendaylight:sxp:controller">$range</bindings-range>
818 data = templ.substitute({'ip': ip, 'range': binding_range, 'domain': get_domain_name(domain_name)})
822 def add_node_xml(node_id, port, password, version, node_ip=None, expansion=0, bindings_timeout=0, keystores=None,
824 """Generate xml for Add Node request
826 :param node_id: Ipv4 address formatted node id
828 :param node_ip: Ipv4 address of node
830 :param port: Node port number
832 :param password: TCP-MD5 password
834 :param version: Sxp device version
836 :param expansion: Bindings expansion
838 :param bindings_timeout: Specifies DHD and Reconciliation timers
839 :type bindings_timeout: int
840 :param keystores: SSL keystore and truststore specification
841 :type keystores: dict
842 :returns: String containing xml data for request
850 <location>$keystore</location>
852 <path-type>PATH</path-type>
853 <password>$passwd</password>
856 <location>$truststore</location>
858 <path-type>PATH</path-type>
859 <password>$passwd</password>
861 <certificate-password>$passwd</certificate-password>
864 {'keystore': keystores['keystore'], 'truststore': keystores['truststore'], 'passwd': keystores['password']})
866 templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
867 <node-id>$id</node-id>
869 <retry-open-time>$retry_open_timer</retry-open-time>
870 <hold-time-min-acceptable>120</hold-time-min-acceptable>
871 <delete-hold-down-time>$timeout</delete-hold-down-time>
872 <hold-time-min>90</hold-time-min>
873 <reconciliation-time>$timeout</reconciliation-time>
874 <hold-time>90</hold-time>
875 <hold-time-max>180</hold-time-max>
876 <keep-alive-time>30</keep-alive-time>
878 <mapping-expanded>$expansion</mapping-expanded>
881 <password>$password</password>
883 <tcp-port>$port</tcp-port>
884 <version>$version</version>
885 <description>ODL SXP Controller</description>
886 <source-ip>$ip</source-ip>
888 data = templ.substitute(
889 {'ip': node_ip or node_id, 'id': node_id, 'port': port, 'password': password,
890 'version': version, 'expansion': expansion, 'timeout': bindings_timeout, 'tls': tls,
891 'retry_open_timer': retry_open_timer})
895 def delete_node_xml(node_id):
896 """Generate xml for Delete node request
898 :param node_id: Ipv4 address formatted node id
900 :returns: String containing xml data for request
903 templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
904 <node-id>$id</node-id>
906 data = templ.substitute({'id': node_id})
910 def add_domain_xml_fluorine(node_id, name, sgt, prefixes, origin):
911 """Generate xml for Add Domain request (Fluorine version: bindings with origin)
913 :param node_id: Id of node
915 :param name: Name of Domain
917 :param sgt: Security group
919 :param prefixes: List of ip-prefixes
921 :param origin: Origin of added bindings
923 :returns: String containing xml data for request
927 if prefixes != 'None':
929 for prefix in prefixes.split(','):
930 xml_prefixes += '\n' + '<ip-prefix>' + prefix + '</ip-prefix>'
932 master_database += '''<master-database>
937 </master-database>'''
938 master_database = Template(master_database).substitute(({'sgt': sgt, 'xml_prefixes': xml_prefixes}))
940 templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
941 <node-id>$id</node-id>
942 <domain-name>$name</domain-name>
943 <origin>$origin</origin>
947 data = templ.substitute({'name': name, 'id': node_id, 'origin': origin, 'master_database': master_database})
951 def add_domain_xml_oxygen(node_id, name, sgt, prefixes):
952 """Generate xml for Add Domain request (Oxygen version: bindings without origin)
954 :param node_id: Id of node
956 :param name: Name of Domain
958 :param sgt: Security group
960 :param prefixes: List of ip-prefixes
962 :returns: String containing xml data for request
966 if prefixes != 'None':
968 for prefix in prefixes.split(','):
969 xml_prefixes += '\n' + '<ip-prefix>' + prefix + '</ip-prefix>'
971 master_database += '''<master-database>
976 </master-database>'''
977 master_database = Template(master_database).substitute(({'sgt': sgt, 'xml_prefixes': xml_prefixes}))
979 templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
980 <node-id>$id</node-id>
981 <domain-name>$name</domain-name>
985 data = templ.substitute({'name': name, 'id': node_id, 'master_database': master_database})
989 def delete_domain_xml(node_id, name):
990 """Generate xml for Remove Domain request
992 :param node_id: Id of node
994 :param name: Name of Domain
996 :returns: String containing xml data for request
999 templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
1000 <node-id>$node_id</node-id>
1001 <domain-name>$name</domain-name>
1004 data = templ.substitute({'node_id': node_id, 'name': name})
1008 def get_domain_name(domain_name):
1009 """Generate xml for Get Bindings request
1011 :param domain_name: Name of Domain
1012 :type domain_name: str
1013 :returns: String containing xml data for request
1016 if domain_name == 'global':
1019 return '<domain-name xmlns="urn:opendaylight:sxp:controller">' + domain_name + '</domain-name>'
1022 def add_bindings_xml_fluorine(node_id, domain, sgt, prefixes, origin):
1023 """Generate xml for Add Bindings request (Fluorine version with origin type)
1025 :param node_id: Id of node
1027 :param domain: Name of Domain
1029 :param sgt: Security group
1031 :param prefixes: List of ip-prefixes
1033 :param origin: Origin of added bindings
1035 :returns: String containing xml data for request
1039 for prefix in prefixes.split(','):
1040 xml_prefixes += '\n' + '<ip-prefix>' + prefix + '</ip-prefix>'
1041 templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
1042 <node-id>$id</node-id>
1043 <domain-name>$name</domain-name>
1044 <origin>$origin</origin>
1052 data = templ.substitute({'name': domain, 'id': node_id, 'sgt': sgt, 'xml_prefixes': xml_prefixes, 'origin': origin})
1056 def add_bindings_xml_oxygen(node_id, domain, sgt, prefixes):
1057 """Generate xml for Add Bindings request (Oxygen version without origin type)
1059 :param node_id: Id of node
1061 :param domain: Name of Domain
1063 :param sgt: Security group
1065 :param prefixes: List of ip-prefixes
1067 :returns: String containing xml data for request
1071 for prefix in prefixes.split(','):
1072 xml_prefixes += '\n' + '<ip-prefix>' + prefix + '</ip-prefix>'
1073 templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
1074 <node-id>$id</node-id>
1075 <domain-name>$name</domain-name>
1081 data = templ.substitute({'name': domain, 'id': node_id, 'sgt': sgt, 'xml_prefixes': xml_prefixes})
1085 def delete_bindings_xml(node_id, domain, sgt, prefixes):
1086 """Generate xml for Remove Bindings request
1088 :param node_id: Id of node
1090 :param domain: Name of Domain
1092 :param sgt: Security group
1094 :param prefixes: Comma separated list of ip-prefixes
1096 :returns: String containing xml data for request
1100 for prefix in prefixes.split(','):
1101 xml_prefixes += '\n' + '<ip-prefix>' + prefix + '</ip-prefix>'
1102 templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
1103 <node-id>$id</node-id>
1104 <domain-name>$name</domain-name>
1110 data = templ.substitute({'name': domain, 'id': node_id, 'sgt': sgt, 'xml_prefixes': xml_prefixes})
1114 def prefix_range(start, end):
1115 """Generate and concatenate ip-prefixes
1117 :param start: Start index
1119 :param end: End index
1121 :returns: String containing concatenated ip-prefixes
1129 prefixes += get_ip_from_number(index + start) + '/32'
1136 def route_definition_xml(virtual_ip, net_mask, interface):
1137 """Generate xml for Add Bindings request
1139 :param interface: Network interface name
1140 :type interface: str
1141 :param net_mask: NetMask of virtual ip
1143 :param virtual_ip: Virtual ip
1144 :type virtual_ip: str
1145 :returns: String containing xml data for request
1148 templ = Template('''
1149 <routing-definition>
1150 <ip-address>$vip</ip-address>
1151 <interface>$interface</interface>
1152 <netmask>$mask</netmask>
1153 </routing-definition>
1155 data = templ.substitute({'mask': net_mask, 'vip': virtual_ip, 'interface': interface})
1159 def route_definitions_xml(routes, old_routes=None):
1160 """Generate xml for Add Bindings request
1162 :param routes: XML formatted data containing RouteDefinitions
1164 :param old_routes: Routes add to request that needs to persist
1165 :type old_routes: str
1166 :returns: String containing xml data for request
1169 if old_routes and "</sxp-cluster-route>" in old_routes:
1170 templ = Template(old_routes.replace("</sxp-cluster-route>", "$routes</sxp-cluster-route>"))
1172 templ = Template('''<sxp-cluster-route xmlns="urn:opendaylight:sxp:cluster:route">
1174 </sxp-cluster-route>
1176 data = templ.substitute({'routes': routes})
1180 def add_binding_origin_xml(origin, priority):
1181 """Generate xml for Add Binding Origin request
1183 :param origin: Origin type
1185 :param priority: Origin priority
1187 :returns: String containing xml data for request
1190 templ = Template('''<input xmlns="urn:opendaylight:sxp:config:controller">
1191 <origin>$origin</origin>
1192 <priority>$priority</priority>
1194 data = templ.substitute({'origin': origin, 'priority': priority})
1198 def update_binding_origin_xml(origin, priority):
1199 """Generate xml for Update Binding Origin request
1201 :param origin: Origin type
1203 :param priority: Origin priority
1205 :returns: String containing xml data for request
1208 templ = Template('''<input xmlns="urn:opendaylight:sxp:config:controller">
1209 <origin>$origin</origin>
1210 <priority>$priority</priority>
1212 data = templ.substitute({'origin': origin, 'priority': priority})
1216 def delete_binding_origin_xml(origin):
1217 """Generate xml for Delete Binding Origin request
1219 :param origin: Origin type
1221 :returns: String containing xml data for request
1224 templ = Template('''<input xmlns="urn:opendaylight:sxp:config:controller">
1225 <origin>$origin</origin>
1227 data = templ.substitute({'origin': origin})
1231 def find_binding_origin(origins_json, origin):
1232 """Test if Binding origin of specified value is contained in JSON
1234 :param origins_json: JSON containing Binding origins
1235 :type origins_json: str
1236 :param origin: Origin to be found
1238 :returns: True if Binding origin of specified origin type was found, otherwise False.
1241 for json_origin in parse_binding_origins(origins_json):
1242 if json_origin['origin'] == origin:
1247 def find_binding_origin_with_priority(origins_json, origin, priority):
1248 """Test if Binding origin of specified value and priority is contained in JSON
1250 :param origins_json: JSON containing Binding origins
1251 :type origins_json: str
1252 :param origin: Origin to be found
1254 :param priority: desired priority of origin
1256 :returns: True if Binding origin of specified origin type with desired priority was found, otherwise False.
1259 for json_origin in parse_binding_origins(origins_json):
1260 if json_origin['origin'] == origin:
1261 if json_origin['priority'] == int(priority):
1266 def parse_binding_origins(origins_json):
1267 """Parse JSON string into Array of Binding origins
1269 :param origins_json: JSON containing Binding origins
1270 :type origins_json: str
1271 :returns: Array containing Binding origins.
1275 for origins in origins_json['binding-origins'].values():
1276 for origin in origins:
1277 output.append(origin)