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(
109 seq, entry_type, sgt="", esgt="", acl="", eacl="", pl="", epl="", ps=""
111 """Generate xml containing FilterEntry data
113 :param seq: Sequence of entry
115 :param entry_type: Type of entry (permit/deny)
116 :type entry_type: str
117 :param sgt: SGT matches to be added to entry
119 :param esgt: SGT ranges match to be added to entry
121 :param acl: ACL matches to be added to entry
123 :param eacl: EACL matches to be added to entry
125 :param pl: PrefixList matches to be added to entry
127 :param epl: ExtendedPrefixList matches to be added to entry
129 :param ps: PeerSequence matches to be added to entry
131 :returns: String containing xml data for request
135 # Generate XML request containing combination of Matches of different types
137 args = sgt.split(",")
138 entries += add_sgt_matches_xml(args)
140 args = esgt.split(",")
141 entries += add_sgt_range_xml(args[0], args[1])
143 entries += add_pl_entry_xml(pl)
145 args = epl.split(",")
146 entries += add_epl_entry_xml(args[0], args[1], args[2])
148 args = acl.split(",")
149 entries += add_acl_entry_xml(args[0], args[1])
151 args = eacl.split(",")
152 entries += add_eacl_entry_xml(args[0], args[1], args[2], args[3])
155 entries += add_ps_entry_xml(args[0], args[1])
156 # Wrap entries in ACL/PrefixList according to specified values
158 return add_pl_entry_default_xml(seq, entry_type, entries)
160 return add_ps_entry_default_xml(seq, entry_type, entries)
161 return add_acl_entry_default_xml(seq, entry_type, entries)
164 def add_peers(*args):
165 """Generate xml containing Peer mach data
167 :param args: Peers data
169 :returns: String containing xml data for request
175 <peer-address>$ip</peer-address>
179 for count, value in enumerate(args):
180 peers += templ.substitute({"ip": value})
184 def add_domains(*args):
185 """Generate xml containing Domain mach data
187 :param args: Domain data
189 :returns: String containing xml data for request
199 for count, value in enumerate(args):
200 peers += templ.substitute({"name": value})
204 def add_sgt_matches_xml(sgt_entries):
205 """Generate xml containing SGT mach data
207 :param sgt_entries: SGT matches
208 :type sgt_entries: str
209 :returns: String containing xml data for request
214 <matches>$sgt</matches>"""
217 for sgt in sgt_entries:
218 matches += templ.substitute({"sgt": sgt})
222 def add_sgt_range_xml(start, end):
223 """Generate xml containing SGT RangeMach data
225 :param start: Start range of SGT
227 :param end: End range of SGT
229 :returns: String containing xml data for request
234 <sgt-start>$start</sgt-start>
235 <sgt-end>$end</sgt-end>"""
237 match = templ.substitute({"start": start, "end": end})
241 def add_acl_entry_default_xml(seq, entry_type, acl_entries):
242 """Generate xml containing AccessList data
244 :param seq: Sequence of PrefixList entry
246 :param entry_type: Entry type (permit/deny)
247 :type entry_type: str
248 :param acl_entries: XML data containing AccessList entries
249 :type acl_entries: str
250 :returns: String containing xml data for request
256 <entry-type>$entry_type</entry-type>
257 <entry-seq>$seq</entry-seq>$acl_entries
260 matches = templ.substitute(
261 {"seq": seq, "entry_type": entry_type, "acl_entries": acl_entries}
266 def add_acl_entry_xml(ip, mask):
267 """Generate xml containing AccessList data
269 :param ip: Ipv4/6 address
271 :param mask: Ipv4/6 wildcard mask
273 :returns: String containing xml data for request
279 <ip-address>$ip</ip-address>
280 <wildcard-mask>$mask</wildcard-mask>
283 return templ.substitute({"ip": ip, "mask": mask})
286 def add_eacl_entry_xml(ip, mask, amask, wmask):
287 """Generate xml containing ExtendedAccessList data
289 :param ip: Ipv4/6 address
291 :param mask: Ipv4/6 wildcard mask
293 :param amask: Ipv4/6 address mask
295 :param wmask: Ipv4/6 address wildcard mask
297 :returns: String containing xml data for request
303 <ip-address>$ip</ip-address>
304 <wildcard-mask>$mask</wildcard-mask>
306 <address-mask>$amask</address-mask>
307 <wildcard-mask>$wmask</wildcard-mask>
311 return templ.substitute({"ip": ip, "mask": mask, "amask": amask, "wmask": wmask})
314 def add_ps_entry_default_xml(seq, entry_type, ps_entries):
315 """Generate xml containing PeerSequence data
317 :param seq: Sequence of PrefixList entry
319 :param entry_type: Entry type (permit/deny)
320 :type entry_type: str
321 :param ps_entries: XML data containing PeerSequence entries
322 :type ps_entries: str
323 :returns: String containing xml data for request
328 <peer-sequence-entry xmlns="urn:opendaylight:sxp:controller">
329 <entry-type>$entry_type</entry-type>
330 <entry-seq>$seq</entry-seq>$ps_entries
331 </peer-sequence-entry>"""
333 return templ.substitute(
334 {"seq": seq, "entry_type": entry_type, "ps_entries": ps_entries}
338 def add_pl_entry_default_xml(seq, entry_type, pl_entries):
339 """Generate xml containing PrefixList data
341 :param seq: Sequence of PrefixList entry
343 :param entry_type: Entry type (permit/deny)
344 :type entry_type: str
345 :param pl_entries: XML data containing PrefixList entries
346 :type pl_entries: str
347 :returns: String containing xml data for request
352 <prefix-list-entry xmlns="urn:opendaylight:sxp:controller">
353 <entry-type>$entry_type</entry-type>
354 <entry-seq>$seq</entry-seq>$pl_entries
355 </prefix-list-entry>"""
357 return templ.substitute(
358 {"seq": seq, "entry_type": entry_type, "pl_entries": pl_entries}
362 def add_pl_entry_xml(prefix):
363 """Generate xml containing PrefixList data
365 :param prefix: Ipv4/6 prefix
367 :returns: String containing xml data for request
373 <ip-prefix>$prefix</ip-prefix>
374 </prefix-list-match>"""
376 return templ.substitute({"prefix": prefix})
379 def add_epl_entry_xml(prefix, op, mask):
380 """Generate xml containing Extended PrefixList data
382 :param prefix: Ipv4/6 prefix
384 :param op: PrefixList option (ge/le/eq)
386 :param mask: Ipv4/6 Mask
388 :returns: String containing xml data for request
394 <ip-prefix>$prefix</ip-prefix>
396 <mask-range>$op</mask-range>
397 <mask-value>$mask</mask-value>
399 </prefix-list-match>"""
401 return templ.substitute({"prefix": prefix, "mask": mask, "op": op})
404 def add_ps_entry_xml(op, length):
405 """Generate xml containing Extended PrefixList data
407 :param op: PrefixList option (ge/le/eq)
409 :param length: PeerSequence length
411 :returns: String containing xml data for request
416 <peer-sequence-length>$length</peer-sequence-length>
417 <peer-sequence-range>$op</peer-sequence-range>
420 return templ.substitute({"length": length, "op": op})
423 def parse_peer_groups(groups_json):
424 """Parse JSON string into Array of PeerGroups
426 :param groups_json: JSON containing PeerGroups
427 :type groups_json: str
428 :returns: Array containing PeerGroups.
431 data = json.loads(groups_json)
432 groups = data["output"]
434 for group in groups.values():
439 def parse_connections(connections_json):
440 """Parse JSON string into Array of Connections
442 :param connections_json: JSON containing Connections
443 :type connections_json: str
444 :returns: Array containing Connections.
447 data = json.loads(connections_json)
448 output = data["output"]
451 connections = output["connections"]
452 for connection in connections.values():
457 def find_connection(connections_json, version, mode, ip, port, state):
458 """Test if Connection with specified values is contained in JSON
460 :param connections_json: JSON containing Connections
461 :type connections_json: str
462 :param version: Version of SXP protocol (version1/2/3/4)
464 :param mode: Mode of SXP peer (speaker/listener/both)
466 :param ip: Ipv4/6 address of remote peer
468 :param port: Port on with remote peer listens
470 :param state: State of connection (on/off/pendingOn/deleteHoldDown)
472 :returns: True if Connection with specified params was found, otherwise False.
475 for connection in parse_connections(connections_json):
477 connection["peer-address"] == ip
478 and connection["tcp-port"] == int(port)
479 and (mode.strip() == "any" or connection["mode"] == mode)
480 and connection["version"] == version
484 elif connection["state"] == state:
489 def parse_bindings(bindings_json):
490 """Parse JSON string into Array of Bindings
492 :param bindings_json: JSON containing Bindings
493 :type bindings_json: str
494 :returns: Array containing Bindings.
497 data = json.loads(bindings_json)
499 for bindings_json in data["output"].values():
500 for binding in bindings_json:
501 output.append(binding)
505 def find_binding(bindings, sgt, prefix):
506 """Test if Binding with specified values is contained in JSON
508 :param bindings: JSON containing Bindings
510 :param sgt: Source Group Tag
512 :param prefix: Ipv4/6 prefix
514 :returns: True if Binding with specified params was found, otherwise False.
517 for binding in parse_bindings(bindings):
518 if binding["sgt"] == int(sgt):
519 for ip_prefix in binding["ip-prefix"]:
520 if ip_prefix == prefix:
525 def parse_prefix_groups(prefix_groups_json, source_):
526 """Parse JSON string into Array of PrefixGroups
528 :param prefix_groups_json: JSON containing PrefixGroups
529 :type prefix_groups_json: str
530 :param source_: Source of PrefixGroups (sxp/local)
532 :returns: Array containing PrefixGroups.
535 data = json.loads(prefix_groups_json)
536 bindings = data["sxp-node:master-database"]
538 for binding in bindings.values():
539 for binding_source in binding:
540 if source_ == "any" or binding_source["binding-source"] == source_:
541 for prefix_group in binding_source["prefix-group"]:
542 output.append(prefix_group)
546 def find_binding_legacy(prefix_groups_json, sgt, prefix, source_, action):
547 """Test if Binding with specified values is contained in JSON
549 :param prefix_groups_json: JSON containing Bindings and PrefixGroups
550 :type prefix_groups_json: str
551 :param sgt: Source Group Tag
553 :param prefix: Ipv4/6 prefix
555 :param source_: Source of binding (local/sxp)
557 :param action: Action for binding (add/delete)
559 :returns: True if Binding with specified params was found, otherwise False.
563 for prefixgroup in parse_prefix_groups(prefix_groups_json, source_):
564 if prefixgroup["sgt"] == int(sgt):
565 for binding in prefixgroup["binding"]:
566 if binding["ip-prefix"] == prefix and binding["action"] == action:
571 def add_connection_xml(
582 """Generate xml for Add Connection request
584 :param version: Version of SXP protocol (version1/2/3/4)
586 :param mode: Mode of SXP peer (speaker/listener/both)
588 :param ip: Ipv4/6 address of remote peer
590 :param port: Port on with remote peer listens
592 :param node: Ipv4 address of node
594 :param password_: Password type (none/default)
596 :param domain_name: Name of Domain
597 :type domain_name: str
598 :param security_mode: Default/TSL security
599 :type security_mode: str
600 :param bindings_timeout: Specifies DHD and Reconciliation timers
601 :type bindings_timeout: int
602 :returns: String containing xml data for request
607 <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
609 <connections xmlns="urn:opendaylight:sxp:controller">
611 <peer-address>$ip</peer-address>
612 <tcp-port>$port</tcp-port>
613 <password>$password_</password>
615 <version>$version</version>
616 <description>Connection to ISR-G2</description>
619 <hold-time-min-acceptable>45</hold-time-min-acceptable>
620 <keep-alive-time>30</keep-alive-time>
621 <reconciliation-time>$timeout</reconciliation-time>
622 <delete-hold-down-time>$timeout</delete-hold-down-time>
623 <hold-time>90</hold-time>
624 <hold-time-max>180</hold-time-max>
625 <hold-time-min>90</hold-time-min>
632 data = templ.substitute(
639 "password_": password_,
640 "domain": get_domain_name(domain_name),
641 "timeout": bindings_timeout,
642 "security_type": "<security-type>" + security_mode + "</security-type>"
650 def delete_connections_xml(address, port, node, domain_name):
651 """Generate xml for Delete Connection request
653 :param address: Ipv4/6 address of remote peer
655 :param port: Port on with remote peer listens
657 :param node: Ipv4 address of node
659 :param domain_name: Name of Domain
660 :type domain_name: str
661 :returns: String containing xml data for request
666 <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
668 <peer-address xmlns="urn:opendaylight:sxp:controller">$address</peer-address>
669 <tcp-port xmlns="urn:opendaylight:sxp:controller">$port</tcp-port>
672 data = templ.substitute(
677 "domain": get_domain_name(domain_name),
683 def add_peer_group_xml(name, peers, ip):
684 """Generate xml for Add PeerGroups request
686 :param name: Name of PeerGroup
688 :param peers: XML formatted peers that will be added to group
690 :param ip: Ipv4 address of node
692 :returns: String containing xml data for request
697 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
698 <sxp-peer-group xmlns="urn:opendaylight:sxp:controller">
699 <name xmlns="urn:opendaylight:sxp:controller">$name</name>
700 <sxp-peers xmlns="urn:opendaylight:sxp:controller">$peers</sxp-peers>
704 data = templ.substitute({"name": name, "peers": peers, "ip": ip})
708 def delete_peer_group_xml(name, ip):
709 """Generate xml for Delete PeerGroup request
711 :param name: Name of PeerGroup
713 :param ip: Ipv4 address of node
715 :returns: String containing xml data for request
720 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
721 <peer-group-name xmlns="urn:opendaylight:sxp:controller">$name</peer-group-name>
724 data = templ.substitute({"name": name, "ip": ip})
728 def get_peer_groups_from_node_xml(ip):
729 """Generate xml for Get PeerGroups request
731 :param ip: Ipv4 address of node
733 :returns: String containing xml data for request
738 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
741 data = templ.substitute({"ip": ip})
745 def add_filter_xml(group, filter_type, entries, ip, policy=None):
746 """Generate xml for Add Filter request
748 :param group: Name of group containing filter
750 :param filter_type: Type of filter
751 :type filter_type: str
752 :param entries: XML formatted entries that will be added in filter
754 :param ip: Ipv4 address of node
756 :param policy: Policy of filter update mechanism
758 :returns: String containing xml data for request
762 policy = "<filter-policy>" + policy + "</filter-policy>"
767 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
768 <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
769 <sxp-filter xmlns="urn:opendaylight:sxp:controller">
771 <filter-type>$filter_type</filter-type>$entries
775 data = templ.substitute(
778 "filter_type": filter_type,
781 "filter_policy": policy,
787 def add_domain_filter_xml(domain, domains, entries, ip, filter_name=None):
788 """Generate xml for Add Domain Filter request
790 :param domain: Name of Domain containing filter
792 :param domains: Domains on which filter will be applied
794 :param entries: XML formatted entries that will be added in filter
796 :param ip: Ipv4 address of node
798 :param filter_name: Name of filter
799 :type filter_name: str
800 :returns: String containing xml data for request
804 filter_name = "<filter-name>" + filter_name + "</filter-name>"
807 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
808 <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
809 <sxp-domain-filter xmlns="urn:opendaylight:sxp:controller">
811 <domains>$domains</domains>
816 data = templ.substitute(
822 "filter_name": filter_name,
828 def delete_filter_xml(group, filter_type, ip):
829 """Generate xml for Delete Filter request
831 :param group: Name of group containing filter
833 :param filter_type: Type of filter
834 :type filter_type: str
835 :param ip: Ipv4 address of node
837 :returns: String containing xml data for request
842 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
843 <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
844 <filter-type xmlns="urn:opendaylight:sxp:controller">$filter_type</filter-type>
847 data = templ.substitute({"group": group, "filter_type": filter_type, "ip": ip})
851 def delete_domain_filter_xml(domain, ip, filter_name=None):
852 """Generate xml for Delete Filter request
854 :param domain: Name of Domain containing filter
856 :param ip: Ipv4 address of node
858 :param filter_name: Name of filter
859 :type filter_name: str
860 :returns: String containing xml data for request
865 '<filter-name xmlns="urn:opendaylight:sxp:controller">'
871 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
872 <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
876 data = templ.substitute({"domain": domain, "ip": ip, "filter_name": filter_name})
880 def get_connections_from_node_xml(ip, domain_name):
881 """Generate xml for Get Connections request
883 :param ip: Ipv4 address of node
885 :param domain_name: Name of Domain
886 :type domain_name: str
887 :returns: String containing xml data for request
892 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
896 data = templ.substitute({"ip": ip, "domain": get_domain_name(domain_name)})
900 def get_bindings_from_node_xml(ip, binding_range, domain_name):
901 """Generate xml for Get Bindings request
903 :param binding_range: All or only Local bindings
904 :type binding_range: str
905 :param ip: Ipv4 address of node
907 :param domain_name: Name of Domain
908 :type domain_name: str
909 :returns: String containing xml data for request
914 <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
915 <bindings-range xmlns="urn:opendaylight:sxp:controller">$range</bindings-range>
919 data = templ.substitute(
920 {"ip": ip, "range": binding_range, "domain": get_domain_name(domain_name)}
936 """Generate xml for Add Node request
938 :param node_id: Ipv4 address formatted node id
940 :param node_ip: Ipv4 address of node
942 :param port: Node port number
944 :param password: TCP-MD5 password
946 :param version: Sxp device version
948 :param expansion: Bindings expansion
950 :param bindings_timeout: Specifies DHD and Reconciliation timers
951 :type bindings_timeout: int
952 :param keystores: SSL keystore and truststore specification
953 :type keystores: dict
954 :returns: String containing xml data for request
963 <location>$keystore</location>
965 <path-type>PATH</path-type>
966 <password>$passwd</password>
969 <location>$truststore</location>
971 <path-type>PATH</path-type>
972 <password>$passwd</password>
974 <certificate-password>$passwd</certificate-password>
979 "keystore": keystores["keystore"],
980 "truststore": keystores["truststore"],
981 "passwd": keystores["password"],
986 """<input xmlns="urn:opendaylight:sxp:controller">
987 <node-id>$id</node-id>
989 <retry-open-time>$retry_open_timer</retry-open-time>
990 <hold-time-min-acceptable>120</hold-time-min-acceptable>
991 <delete-hold-down-time>$timeout</delete-hold-down-time>
992 <hold-time-min>90</hold-time-min>
993 <reconciliation-time>$timeout</reconciliation-time>
994 <hold-time>90</hold-time>
995 <hold-time-max>180</hold-time-max>
996 <keep-alive-time>30</keep-alive-time>
998 <mapping-expanded>$expansion</mapping-expanded>
1001 <password>$password</password>
1003 <tcp-port>$port</tcp-port>
1004 <version>$version</version>
1005 <description>ODL SXP Controller</description>
1006 <source-ip>$ip</source-ip>
1009 data = templ.substitute(
1011 "ip": node_ip or node_id,
1014 "password": password,
1016 "expansion": expansion,
1017 "timeout": bindings_timeout,
1019 "retry_open_timer": retry_open_timer,
1025 def delete_node_xml(node_id):
1026 """Generate xml for Delete node request
1028 :param node_id: Ipv4 address formatted node id
1030 :returns: String containing xml data for request
1034 """<input xmlns="urn:opendaylight:sxp:controller">
1035 <node-id>$id</node-id>
1038 data = templ.substitute({"id": node_id})
1042 def add_domain_xml_fluorine(node_id, name, sgt, prefixes, origin):
1043 """Generate xml for Add Domain request (Fluorine version: bindings with origin)
1045 :param node_id: Id of node
1047 :param name: Name of Domain
1049 :param sgt: Security group
1051 :param prefixes: List of ip-prefixes
1053 :param origin: Origin of added bindings
1055 :returns: String containing xml data for request
1058 master_database = ""
1059 if prefixes != "None":
1061 for prefix in prefixes.split(","):
1062 xml_prefixes += "\n" + "<ip-prefix>" + prefix + "</ip-prefix>"
1064 master_database += """<master-database>
1069 </master-database>"""
1070 master_database = Template(master_database).substitute(
1071 ({"sgt": sgt, "xml_prefixes": xml_prefixes})
1075 """<input xmlns="urn:opendaylight:sxp:controller">
1076 <node-id>$id</node-id>
1077 <domain-name>$name</domain-name>
1078 <origin>$origin</origin>
1083 data = templ.substitute(
1088 "master_database": master_database,
1094 def delete_domain_xml(node_id, name):
1095 """Generate xml for Remove Domain request
1097 :param node_id: Id of node
1099 :param name: Name of Domain
1101 :returns: String containing xml data for request
1105 """<input xmlns="urn:opendaylight:sxp:controller">
1106 <node-id>$node_id</node-id>
1107 <domain-name>$name</domain-name>
1111 data = templ.substitute({"node_id": node_id, "name": name})
1115 def get_domain_name(domain_name):
1116 """Generate xml for Get Bindings request
1118 :param domain_name: Name of Domain
1119 :type domain_name: str
1120 :returns: String containing xml data for request
1123 if domain_name == "global":
1127 '<domain-name xmlns="urn:opendaylight:sxp:controller">'
1133 def add_bindings_xml_fluorine(node_id, domain, sgt, prefixes, origin):
1134 """Generate xml for Add Bindings request (Fluorine version with origin type)
1136 :param node_id: Id of node
1138 :param domain: Name of Domain
1140 :param sgt: Security group
1142 :param prefixes: List of ip-prefixes
1144 :param origin: Origin of added bindings
1146 :returns: String containing xml data for request
1150 for prefix in prefixes.split(","):
1151 xml_prefixes += "\n" + "<ip-prefix>" + prefix + "</ip-prefix>"
1153 """<input xmlns="urn:opendaylight:sxp:controller">
1154 <node-id>$id</node-id>
1155 <domain-name>$name</domain-name>
1156 <origin>$origin</origin>
1165 data = templ.substitute(
1170 "xml_prefixes": xml_prefixes,
1177 def delete_bindings_xml(node_id, domain, sgt, prefixes):
1178 """Generate xml for Remove Bindings request
1180 :param node_id: Id of node
1182 :param domain: Name of Domain
1184 :param sgt: Security group
1186 :param prefixes: Comma separated list of ip-prefixes
1188 :returns: String containing xml data for request
1192 for prefix in prefixes.split(","):
1193 xml_prefixes += "\n" + "<ip-prefix>" + prefix + "</ip-prefix>"
1195 """<input xmlns="urn:opendaylight:sxp:controller">
1196 <node-id>$id</node-id>
1197 <domain-name>$name</domain-name>
1204 data = templ.substitute(
1205 {"name": domain, "id": node_id, "sgt": sgt, "xml_prefixes": xml_prefixes}
1210 def prefix_range(start, end):
1211 """Generate and concatenate ip-prefixes
1213 :param start: Start index
1215 :param end: End index
1217 :returns: String containing concatenated ip-prefixes
1225 prefixes += get_ip_from_number(index + start) + "/32"
1232 def route_definition_xml(virtual_ip, net_mask, interface):
1233 """Generate xml for Add Bindings request
1235 :param interface: Network interface name
1236 :type interface: str
1237 :param net_mask: NetMask of virtual ip
1239 :param virtual_ip: Virtual ip
1240 :type virtual_ip: str
1241 :returns: String containing xml data for request
1246 <routing-definition>
1247 <ip-address>$vip</ip-address>
1248 <interface>$interface</interface>
1249 <netmask>$mask</netmask>
1250 </routing-definition>
1253 data = templ.substitute(
1254 {"mask": net_mask, "vip": virtual_ip, "interface": interface}
1259 def route_definitions_xml(routes, old_routes=None):
1260 """Generate xml for Add Bindings request
1262 :param routes: XML formatted data containing RouteDefinitions
1264 :param old_routes: Routes add to request that needs to persist
1265 :type old_routes: str
1266 :returns: String containing xml data for request
1269 if old_routes and "</sxp-cluster-route>" in old_routes:
1271 old_routes.replace("</sxp-cluster-route>", "$routes</sxp-cluster-route>")
1275 """<sxp-cluster-route xmlns="urn:opendaylight:sxp:cluster:route">
1277 </sxp-cluster-route>
1280 data = templ.substitute({"routes": routes})
1284 def add_binding_origin_xml(origin, priority):
1285 """Generate xml for Add Binding Origin request
1287 :param origin: Origin type
1289 :param priority: Origin priority
1291 :returns: String containing xml data for request
1295 """<input xmlns="urn:opendaylight:sxp:config:controller">
1296 <origin>$origin</origin>
1297 <priority>$priority</priority>
1300 data = templ.substitute({"origin": origin, "priority": priority})
1304 def update_binding_origin_xml(origin, priority):
1305 """Generate xml for Update Binding Origin request
1307 :param origin: Origin type
1309 :param priority: Origin priority
1311 :returns: String containing xml data for request
1315 """<input xmlns="urn:opendaylight:sxp:config:controller">
1316 <origin>$origin</origin>
1317 <priority>$priority</priority>
1320 data = templ.substitute({"origin": origin, "priority": priority})
1324 def delete_binding_origin_xml(origin):
1325 """Generate xml for Delete Binding Origin request
1327 :param origin: Origin type
1329 :returns: String containing xml data for request
1333 """<input xmlns="urn:opendaylight:sxp:config:controller">
1334 <origin>$origin</origin>
1337 data = templ.substitute({"origin": origin})
1341 def find_binding_origin(origins_json, origin):
1342 """Test if Binding origin of specified value is contained in JSON
1344 :param origins_json: JSON containing Binding origins
1345 :type origins_json: str
1346 :param origin: Origin to be found
1348 :returns: True if Binding origin of specified origin type was found, otherwise False.
1351 for json_origin in parse_binding_origins(origins_json):
1352 if json_origin["origin"] == origin:
1357 def find_binding_origin_with_priority(origins_json, origin, priority):
1358 """Test if Binding origin of specified value and priority is contained in JSON
1360 :param origins_json: JSON containing Binding origins
1361 :type origins_json: str
1362 :param origin: Origin to be found
1364 :param priority: desired priority of origin
1366 :returns: True if Binding origin of specified origin type with desired priority was found, otherwise False.
1369 for json_origin in parse_binding_origins(origins_json):
1370 if json_origin["origin"] == origin:
1371 if json_origin["priority"] == int(priority):
1376 def parse_binding_origins(origins_json):
1377 """Parse JSON string into Array of Binding origins
1379 :param origins_json: JSON containing Binding origins
1380 :type origins_json: str
1381 :returns: Array containing Binding origins.
1385 for origins in origins_json["binding-origins"].values():
1386 for origin in origins:
1387 output.append(origin)