Add SXP clustering CSIT
[integration/test.git] / csit / libraries / Sxp.py
1 import json
2 from ipaddr import IPAddress
3 from string import Template
4
5
6 def mod(num, base):
7     """Gets modulo of number
8
9     :param num: Number to be used
10     :type num: string
11     :param base: Base used
12     :type base: string
13     :returns: Int representing modulo of specified numbers.
14
15     """
16     return int(num) % int(base)
17
18
19 def get_opposing_mode(mode):
20     """Generate string representing opposing SXP peer mode
21
22         :param mode: SXP peer mode
23         :type mode: str
24         :returns: String with opposing SXP peer mode.
25
26         """
27     if 'speaker' == mode:
28         return 'listener'
29     elif 'listener' == mode:
30         return 'speaker'
31     return 'both'
32
33
34 def get_ip_from_number(n):
35     """Generate string representing Ipv4 from specified number that is added number 2130706432
36
37     :param n: Number to be converted
38     :type n: int
39     :returns: String containing Ipv4.
40
41     """
42     ip = IPAddress(2130706432 + n)
43     return str(ip)
44
45
46 def lower_version(ver1, ver2):
47     """Generate xml containing SGT mach data
48
49     :param ver1: Version of SXP protocol for compare
50     :type ver1: string
51     :param ver2: Version of SXP protocol for compare
52     :type ver2: string
53     :returns: String containing lower from those two specified versions.
54
55     """
56     v1 = int(ver1[-1:])
57     v2 = int(ver2[-1:])
58     if v1 <= v2:
59         return ver1
60     else:
61         return ver2
62
63
64 def get_filter_entry(seq, entry_type, sgt="", esgt="", acl="", eacl="", pl="", epl="", ps=""):
65     """Generate xml containing FilterEntry data
66
67     :param seq: Sequence of entry
68     :type seq: string
69     :param entry_type: Type of entry (permit/deny)
70     :type entry_type: string
71     :param sgt: SGT matches to be added to entry
72     :type sgt: string
73     :param esgt: SGT ranges match to be added to entry
74     :type esgt: string
75     :param acl: ACL matches to be added to entry
76     :type acl: string
77     :param eacl: EACL matches to be added to entry
78     :type eacl: string
79     :param pl: PrefixList matches to be added to entry
80     :type pl: string
81     :param epl: ExtendedPrefixList matches to be added to entry
82     :type epl: string
83     :param ps: PeerSequence matches to be added to entry
84     :type ps: string
85     :returns: String containing xml data for request
86
87     """
88     entries = ""
89     # Generate XML request containing combination of Matches of different types
90     if sgt:
91         args = sgt.split(',')
92         entries += add_sgt_matches_xml(args)
93     elif esgt:
94         args = esgt.split(',')
95         entries += add_sgt_range_xml(args[0], args[1])
96     if pl:
97         entries += add_pl_entry_xml(pl)
98     elif epl:
99         args = epl.split(',')
100         entries += add_epl_entry_xml(args[0], args[1], args[2])
101     if acl:
102         args = acl.split(',')
103         entries += add_acl_entry_xml(args[0], args[1])
104     elif eacl:
105         args = eacl.split(',')
106         entries += add_eacl_entry_xml(args[0], args[1], args[2], args[3])
107     if ps:
108         args = ps.split(',')
109         entries += add_ps_entry_xml(args[0], args[1])
110     # Wrap entries in ACL/PrefixList according to specified values
111     if pl or epl:
112         return add_pl_entry_default_xml(seq, entry_type, entries)
113     elif ps:
114         return add_ps_entry_default_xml(seq, entry_type, entries)
115     return add_acl_entry_default_xml(seq, entry_type, entries)
116
117
118 def add_peers(*args):
119     """Generate xml containing Peer mach data
120
121     :param args: Peers data
122     :type args: dict
123     :returns: String containing xml data for request
124
125     """
126     templ = Template('''
127         <sxp-peer>
128             <peer-address>$ip</peer-address>
129         </sxp-peer>''')
130     peers = ""
131     for count, value in enumerate(args):
132         peers += templ.substitute({'ip': value})
133     return peers
134
135
136 def add_domains(*args):
137     """Generate xml containing Domain mach data
138
139     :param args: Domain data
140     :type args: dict
141     :returns: String containing xml data for request
142
143     """
144     templ = Template('''
145         <domain>
146             <name>$name</name>
147         </domain>''')
148     peers = ""
149     for count, value in enumerate(args):
150         peers += templ.substitute({'name': value})
151     return peers
152
153
154 def add_sgt_matches_xml(sgt_entries):
155     """Generate xml containing SGT mach data
156
157     :param sgt_entries: SGT matches
158     :type sgt_entries: string
159     :returns: String containing xml data for request
160
161     """
162     templ = Template('''
163         <matches>$sgt</matches>''')
164     matches = ""
165     for sgt in sgt_entries:
166         matches += templ.substitute({'sgt': sgt})
167     return matches
168
169
170 def add_sgt_range_xml(start, end):
171     """Generate xml containing SGT RangeMach data
172
173     :param start: Start range of SGT
174     :type start: string
175     :param end: End range of SGT
176     :type end: string
177     :returns: String containing xml data for request
178
179     """
180     templ = Template('''
181         <sgt-start>$start</sgt-start>
182         <sgt-end>$end</sgt-end>''')
183     match = templ.substitute({'start': start, 'end': end})
184     return match
185
186
187 def add_acl_entry_default_xml(seq, entry_type, acl_entries):
188     """Generate xml containing AccessList data
189
190     :param seq: Sequence of PrefixList entry
191     :type seq: string
192     :param entry_type: Entry type (permit/deny)
193     :type entry_type: string
194     :param acl_entries: XML data containing AccessList entries
195     :type acl_entries: string
196     :returns: String containing xml data for request
197
198     """
199     templ = Template('''
200         <acl-entry>
201             <entry-type>$entry_type</entry-type>
202             <entry-seq>$seq</entry-seq>$acl_entries
203         </acl-entry>''')
204     matches = templ.substitute(
205         {'seq': seq, 'entry_type': entry_type, 'acl_entries': acl_entries})
206     return matches
207
208
209 def add_acl_entry_xml(ip, mask):
210     """Generate xml containing AccessList data
211
212     :param ip: Ipv4/6 address
213     :type ip: string
214     :param mask: Ipv4/6 wildcard mask
215     :type mask: string
216     :returns: String containing xml data for request
217
218     """
219     templ = Template('''
220         <acl-match>
221             <ip-address>$ip</ip-address>
222             <wildcard-mask>$mask</wildcard-mask>
223         </acl-match>''')
224     return templ.substitute({'ip': ip, 'mask': mask})
225
226
227 def add_eacl_entry_xml(ip, mask, amask, wmask):
228     """Generate xml containing ExtendedAccessList data
229
230     :param ip: Ipv4/6 address
231     :type ip: string
232     :param mask: Ipv4/6 wildcard mask
233     :type mask: string
234     :param amask: Ipv4/6 address mask
235     :type amask: string
236     :param wmask: Ipv4/6 address wildcard mask
237     :type wmask: string
238     :returns: String containing xml data for request
239
240     """
241     templ = Template('''
242         <acl-match>
243             <ip-address>$ip</ip-address>
244             <wildcard-mask>$mask</wildcard-mask>
245             <mask>
246               <address-mask>$amask</address-mask>
247               <wildcard-mask>$wmask</wildcard-mask>
248             </mask>
249         </acl-match>''')
250     return templ.substitute({'ip': ip, 'mask': mask, 'amask': amask, 'wmask': wmask})
251
252
253 def add_ps_entry_default_xml(seq, entry_type, ps_entries):
254     """Generate xml containing PeerSequence data
255
256     :param seq: Sequence of PrefixList entry
257     :type seq: string
258     :param entry_type: Entry type (permit/deny)
259     :type entry_type: string
260     :param ps_entries: XML data containing PeerSequence entries
261     :type ps_entries: string
262     :returns: String containing xml data for request
263
264     """
265     templ = Template('''
266     <peer-sequence-entry xmlns="urn:opendaylight:sxp:controller">
267           <entry-type>$entry_type</entry-type>
268           <entry-seq>$seq</entry-seq>$ps_entries
269     </peer-sequence-entry>''')
270     return templ.substitute({'seq': seq, 'entry_type': entry_type, 'ps_entries': ps_entries})
271
272
273 def add_pl_entry_default_xml(seq, entry_type, pl_entries):
274     """Generate xml containing PrefixList data
275
276     :param seq: Sequence of PrefixList entry
277     :type seq: string
278     :param entry_type: Entry type (permit/deny)
279     :type entry_type: string
280     :param pl_entries: XML data containing PrefixList entries
281     :type pl_entries: string
282     :returns: String containing xml data for request
283
284     """
285     templ = Template('''
286     <prefix-list-entry xmlns="urn:opendaylight:sxp:controller">
287           <entry-type>$entry_type</entry-type>
288           <entry-seq>$seq</entry-seq>$pl_entries
289     </prefix-list-entry>''')
290     return templ.substitute({'seq': seq, 'entry_type': entry_type, 'pl_entries': pl_entries})
291
292
293 def add_pl_entry_xml(prefix):
294     """Generate xml containing PrefixList data
295
296     :param prefix: Ipv4/6 prefix
297     :type prefix: string
298     :returns: String containing xml data for request
299
300     """
301     templ = Template('''
302         <prefix-list-match>
303             <ip-prefix>$prefix</ip-prefix>
304         </prefix-list-match>''')
305     return templ.substitute({'prefix': prefix})
306
307
308 def add_epl_entry_xml(prefix, op, mask):
309     """Generate xml containing Extended PrefixList data
310
311     :param prefix: Ipv4/6 prefix
312     :type prefix: string
313     :param op: PrefixList option (ge/le/eq)
314     :type op: string
315     :param mask: Ipv4/6 Mask
316     :type mask: string
317     :returns: String containing xml data for request
318
319     """
320     templ = Template('''
321         <prefix-list-match>
322             <ip-prefix>$prefix</ip-prefix>
323             <mask>
324                 <mask-range>$op</mask-range>
325                 <mask-value>$mask</mask-value>
326             </mask>
327         </prefix-list-match>''')
328     return templ.substitute({'prefix': prefix, 'mask': mask, 'op': op})
329
330
331 def add_ps_entry_xml(op, length):
332     """Generate xml containing Extended PrefixList data
333
334     :param op: PrefixList option (ge/le/eq)
335     :type op: string
336     :param length: PeerSequence length
337     :type length: string
338     :returns: String containing xml data for request
339
340     """
341     templ = Template('''
342         <peer-sequence-length>$length</peer-sequence-length>
343         <peer-sequence-range>$op</peer-sequence-range>
344         ''')
345     return templ.substitute({'length': length, 'op': op})
346
347
348 def parse_peer_groups(groups_json):
349     """Parse JSON string into Array of PeerGroups
350
351     :param groups_json: JSON containing PeerGroups
352     :type groups_json: string
353     :returns: Array containing PeerGroups.
354
355     """
356     data = json.loads(groups_json)
357     groups = data['output']
358     output = []
359     for group in groups.values():
360         output += group
361     return output
362
363
364 def parse_connections(connections_json):
365     """Parse JSON string into Array of Connections
366
367     :param connections_json: JSON containing Connections
368     :type connections_json: string
369     :returns: Array containing Connections.
370
371     """
372     data = json.loads(connections_json)
373     connections = data['output']['connections']
374     output = []
375     for connection in connections.values():
376         output += connection
377     return output
378
379
380 def find_connection(connections_json, version, mode, ip, port, state):
381     """Test if Connection with specified values is contained in JSON
382
383     :param connections_json: JSON containing Connections
384     :type connections_json: string
385     :param version: Version of SXP protocol (version1/2/3/4)
386     :type version: string
387     :param mode: Mode of SXP peer (speaker/listener/both)
388     :type mode: string
389     :param ip: Ipv4/6 address of remote peer
390     :type ip: string
391     :param port: Port on with remote peer listens
392     :type port: string
393     :param state: State of connection (on/off/pendingOn/deleteHoldDown)
394     :type state: string
395     :returns: True if Connection with specified params was found, otherwise False.
396
397     """
398     for connection in parse_connections(connections_json):
399         if (connection['peer-address'] == ip and connection['tcp-port'] == int(port) and (
400                         mode.strip() == 'any' or connection['mode'] == mode) and connection['version'] == version):
401             if state == 'none':
402                 return True
403             elif connection['state'] == state:
404                 return True
405     return False
406
407
408 def parse_bindings(bindings_json):
409     """Parse JSON string into Array of Bindings
410
411     :param bindings_json: JSON containing Bindings
412     :type bindings_json: string
413     :returns: Array containing Bindings.
414
415     """
416     data = json.loads(bindings_json)
417     output = []
418     for bindings_json in data['output'].values():
419         for binding in bindings_json:
420             output.append(binding)
421     return output
422
423
424 def find_binding(bindings, sgt, prefix):
425     """Test if Binding with specified values is contained in JSON
426
427     :param bindings: JSON containing Bindings
428     :type bindings: string
429     :param sgt: Source Group Tag
430     :type sgt: string
431     :param prefix: Ipv4/6 prefix
432     :type prefix: string
433     :returns: True if Binding with specified params was found, otherwise False.
434
435     """
436     for binding in parse_bindings(bindings):
437         if binding['sgt'] == int(sgt):
438             for ip_prefix in binding['ip-prefix']:
439                 if ip_prefix == prefix:
440                     return True
441     return False
442
443
444 def parse_prefix_groups(prefix_groups_json, source_):
445     """Parse JSON string into Array of PrefixGroups
446
447     :param prefix_groups_json: JSON containing PrefixGroups
448     :type prefix_groups_json: string
449     :param source_: Source of PrefixGroups (sxp/local)
450     :type source_: string
451     :returns: Array containing PrefixGroups.
452
453     """
454     data = json.loads(prefix_groups_json)
455     bindings = data['sxp-node:master-database']
456     output = []
457     for binding in bindings.values():
458         for binding_source in binding:
459             if source_ == "any" or binding_source['binding-source'] == source_:
460                 for prefix_group in binding_source['prefix-group']:
461                     output.append(prefix_group)
462     return output
463
464
465 def find_binding_legacy(prefix_groups_json, sgt, prefix, source_, action):
466     """Test if Binding with specified values is contained in JSON
467
468     :param prefix_groups_json: JSON containing Bindings and PrefixGroups
469     :type prefix_groups_json: string
470     :param sgt: Source Group Tag
471     :type sgt: string
472     :param prefix: Ipv4/6 prefix
473     :type prefix: string
474     :param source_: Source of binding (local/sxp)
475     :type source_: string
476     :param action: Action for binding (add/delete)
477     :type action: string
478     :returns: True if Binding with specified params was found, otherwise False.
479
480     """
481     found = False
482     for prefixgroup in parse_prefix_groups(prefix_groups_json, source_):
483         if prefixgroup['sgt'] == int(sgt):
484             for binding in prefixgroup['binding']:
485                 if binding['ip-prefix'] == prefix and binding['action'] == action:
486                     found = True
487     return found
488
489
490 def add_entry_xml(sgt, prefix, ip, domain_name):
491     """Generate xml for Add Bindings request
492
493     :param sgt: Source Group Tag
494     :type sgt: string
495     :param prefix: Ipv4/6 prefix
496     :type prefix: string
497     :param ip: Ipv4 address of node
498     :type ip: string
499     :param domain_name: Name of Domain
500     :type domain_name: string
501     :returns: String containing xml data for request
502
503     """
504     templ = Template('''<input>
505   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
506   $domain
507   <sgt xmlns="urn:opendaylight:sxp:controller">$sgt</sgt>
508   <ip-prefix xmlns="urn:opendaylight:sxp:controller">$prefix</ip-prefix>
509 </input>''')
510     data = templ.substitute({'sgt': sgt, 'prefix': prefix, 'ip': ip, 'domain': get_domain_name(domain_name)})
511     return data
512
513
514 def add_connection_xml(version, mode, ip, port, node, password_, domain_name):
515     """Generate xml for Add Connection request
516
517     :param version: Version of SXP protocol (version1/2/3/4)
518     :type version: string
519     :param mode: Mode of SXP peer (speaker/listener/both)
520     :type mode: string
521     :param ip: Ipv4/6 address of remote peer
522     :type ip: string
523     :param port: Port on with remote peer listens
524     :type port: string
525     :param node: Ipv4 address of node
526     :type node: string
527     :param password_: Password type (none/default)
528     :type password_: string
529     :param domain_name: Name of Domain
530     :type domain_name: string
531     :returns: String containing xml data for request
532
533     """
534     templ = Template('''<input>
535    <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
536    $domain
537    <connections xmlns="urn:opendaylight:sxp:controller">
538       <connection>
539          <peer-address>$ip</peer-address>
540          <tcp-port>$port</tcp-port>
541          <password>$password_</password>
542          <mode>$mode</mode>
543          <version>$version</version>
544          <description>Connection to ISR-G2</description>
545          <connection-timers>
546             <hold-time-min-acceptable>45</hold-time-min-acceptable>
547             <keep-alive-time>30</keep-alive-time>
548             <reconciliation-time>120</reconciliation-time>
549          </connection-timers>
550       </connection>
551    </connections>
552 </input>
553 ''')
554     data = templ.substitute(
555         {'ip': ip, 'port': port, 'mode': mode, 'version': version, 'node': node,
556          'password_': password_, 'domain': get_domain_name(domain_name)})
557     return data
558
559
560 def delete_connections_xml(address, port, node, domain_name):
561     """Generate xml for Delete Connection request
562
563     :param address: Ipv4/6 address of remote peer
564     :type address: string
565     :param port: Port on with remote peer listens
566     :type port: string
567     :param node: Ipv4 address of node
568     :type node: string
569     :param domain_name: Name of Domain
570     :type domain_name: string
571     :returns: String containing xml data for request
572
573     """
574     templ = Template('''<input>
575    <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
576    $domain
577    <peer-address xmlns="urn:opendaylight:sxp:controller">$address</peer-address>
578    <tcp-port xmlns="urn:opendaylight:sxp:controller">$port</tcp-port>
579 </input>''')
580     data = templ.substitute({'address': address, 'port': port, 'node': node, 'domain': get_domain_name(domain_name)})
581     return data
582
583
584 def update_binding_xml(sgt0, prefix0, sgt1, prefix1, ip, domain_name):
585     """Generate xml for Update Binding request
586
587     :param sgt0: Original Source Group Tag
588     :type sgt0: string
589     :param prefix0: Original Ipv4/6 prefix
590     :type prefix0: string
591     :param sgt1: New Source Group Tag
592     :type sgt1: string
593     :param prefix1: New Ipv4/6 prefix
594     :type prefix1: string
595     :param ip: Ipv4 address of node
596     :type ip: string
597     :param domain_name: Name of Domain
598     :type domain_name: string
599     :returns: String containing xml data for request
600
601     """
602     templ = Template('''<input>
603   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
604   $domain
605   <original-binding xmlns="urn:opendaylight:sxp:controller">
606     <sgt>$sgt0</sgt>
607     <ip-prefix>$prefix0</ip-prefix>
608   </original-binding>
609   <new-binding xmlns="urn:opendaylight:sxp:controller">
610     <sgt>$sgt1</sgt>
611     <ip-prefix>$prefix1</ip-prefix>
612   </new-binding>
613 </input>''')
614     data = templ.substitute(
615         {'sgt0': sgt0, 'sgt1': sgt1, 'prefix0': prefix0, 'prefix1': prefix1, 'ip': ip,
616          'domain': get_domain_name(domain_name)})
617     return data
618
619
620 def delete_binding_xml(sgt, prefix, ip, domain_name):
621     """Generate xml for Delete Binding request
622
623     :param sgt: Source Group Tag
624     :type sgt: string
625     :param prefix: Ipv4/6 prefix
626     :type prefix: string
627     :param ip: Ipv4 address of node
628     :type ip: string
629     :param domain_name: Name of Domain
630     :type domain_name: string
631     :returns: String containing xml data for request
632
633     """
634     templ = Template('''<input>
635   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
636   <sgt xmlns="urn:opendaylight:sxp:controller">$sgt</sgt>
637   <ip-prefix xmlns="urn:opendaylight:sxp:controller">$prefix</ip-prefix>
638   $domain
639 </input>''')
640     data = templ.substitute({'sgt': sgt, 'prefix': prefix, 'ip': ip, 'domain': get_domain_name(domain_name)})
641     return data
642
643
644 def add_peer_group_xml(name, peers, ip):
645     """Generate xml for Add PeerGroups request
646
647     :param name: Name of PeerGroup
648     :type name: string
649     :param peers: XML formatted peers that will be added to group
650     :type peers: string
651     :param ip: Ipv4 address of node
652     :type ip: string
653     :returns: String containing xml data for request
654
655     """
656     templ = Template('''<input>
657   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
658   <sxp-peer-group xmlns="urn:opendaylight:sxp:controller">
659     <name xmlns="urn:opendaylight:sxp:controller">$name</name>
660     <sxp-peers xmlns="urn:opendaylight:sxp:controller">$peers</sxp-peers>
661     </sxp-peer-group>
662 </input>''')
663     data = templ.substitute({'name': name, 'peers': peers, 'ip': ip})
664     return data
665
666
667 def delete_peer_group_xml(name, ip):
668     """Generate xml for Delete PeerGroup request
669
670     :param name: Name of PeerGroup
671     :type name: string
672     :param ip: Ipv4 address of node
673     :type ip: string
674     :returns: String containing xml data for request
675
676     """
677     templ = Template('''<input>
678   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
679   <peer-group-name xmlns="urn:opendaylight:sxp:controller">$name</peer-group-name>
680 </input>''')
681     data = templ.substitute({'name': name, 'ip': ip})
682     return data
683
684
685 def get_peer_groups_from_node_xml(ip):
686     """Generate xml for Get PeerGroups request
687
688     :param ip: Ipv4 address of node
689     :type ip: string
690     :returns: String containing xml data for request
691
692     """
693     templ = Template('''<input>
694    <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
695 </input>''')
696     data = templ.substitute({'ip': ip})
697     return data
698
699
700 def add_filter_xml(group, filter_type, entries, ip):
701     """Generate xml for Add Filter request
702
703     :param group: Name of group containing filter
704     :type group: string
705     :param filter_type: Type of filter
706     :type filter_type: string
707     :param entries: XML formatted entries that will be added in filter
708     :type entries: string
709     :param ip: Ipv4 address of node
710     :type ip: string
711     :returns: String containing xml data for request
712
713     """
714     templ = Template('''<input>
715   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
716   <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
717   <sxp-filter xmlns="urn:opendaylight:sxp:controller">
718     <filter-type>$filter_type</filter-type>$entries
719   </sxp-filter>
720 </input>''')
721     data = templ.substitute(
722         {'group': group, 'filter_type': filter_type, 'ip': ip, 'entries': entries})
723     return data
724
725
726 def add_domain_filter_xml(domain, domains, entries, ip, filter_name=None):
727     """Generate xml for Add Domain Filter request
728
729     :param domain: Name of Domain containing filter
730     :type domain: string
731     :param domains: Domains on which filter will be applied
732     :type domains: string
733     :param entries: XML formatted entries that will be added in filter
734     :type entries: string
735     :param ip: Ipv4 address of node
736     :type ip: string
737     :param filter_name: Name of filter
738     :type filter_name: string
739     :returns: String containing xml data for request
740
741     """
742     if filter_name:
743         filter_name = "<filter-name>" + filter_name + "</filter-name>"
744     templ = Template('''<input>
745   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
746   <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
747   <sxp-domain-filter xmlns="urn:opendaylight:sxp:controller">
748     $filter_name
749     <domains>$domains</domains>
750     $entries
751   </sxp-domain-filter>
752 </input>''')
753     data = templ.substitute(
754         {'domain': domain, 'domains': domains, 'ip': ip, 'entries': entries, 'filter_name': filter_name})
755     return data
756
757
758 def delete_filter_xml(group, filter_type, ip):
759     """Generate xml for Delete Filter request
760
761     :param group: Name of group containing filter
762     :type group: string
763     :param filter_type: Type of filter
764     :type filter_type: string
765     :param ip: Ipv4 address of node
766     :type ip: string
767     :returns: String containing xml data for request
768
769     """
770     templ = Template('''<input>
771   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
772   <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
773   <filter-type xmlns="urn:opendaylight:sxp:controller">$filter_type</filter-type>
774 </input>''')
775     data = templ.substitute(
776         {'group': group, 'filter_type': filter_type, 'ip': ip})
777     return data
778
779
780 def delete_domain_filter_xml(domain, ip, filter_name=None):
781     """Generate xml for Delete Filter request
782
783     :param domain: Name of Domain containing filter
784     :type domain: string
785     :param ip: Ipv4 address of node
786     :type ip: string
787     :param filter_name: Name of filter
788     :type filter_name: string
789     :returns: String containing xml data for request
790
791     """
792     if filter_name:
793         filter_name = '<filter-name xmlns="urn:opendaylight:sxp:controller">' + filter_name + "</filter-name>"
794     templ = Template('''<input>
795   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
796   <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
797   $filter_name
798 </input>''')
799     data = templ.substitute(
800         {'domain': domain, 'ip': ip, 'filter_name': filter_name})
801     return data
802
803
804 def get_connections_from_node_xml(ip, domain_name):
805     """Generate xml for Get Connections request
806
807     :param ip: Ipv4 address of node
808     :type ip: string
809     :param domain_name: Name of Domain
810     :type domain_name: string
811     :returns: String containing xml data for request
812
813     """
814     templ = Template('''<input>
815    <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
816    $domain
817 </input>''')
818     data = templ.substitute({'ip': ip, 'domain': get_domain_name(domain_name)})
819     return data
820
821
822 def get_bindings_from_node_xml(ip, binding_range, domain_name):
823     """Generate xml for Get Bindings request
824
825     :param binding_range: All or only Local bindings
826     :type binding_range: string
827     :param ip: Ipv4 address of node
828     :type ip: string
829     :param domain_name: Name of Domain
830     :type domain_name: string
831     :returns: String containing xml data for request
832
833     """
834     templ = Template('''<input>
835   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
836   <bindings-range xmlns="urn:opendaylight:sxp:controller">$range</bindings-range>
837   $domain
838 </input>''')
839     data = templ.substitute({'ip': ip, 'range': binding_range, 'domain': get_domain_name(domain_name)})
840     return data
841
842
843 def add_node_xml(node_id, port, password, version, node_ip=None, expansion=0):
844     """Generate xml for Add Node request
845
846     :param node_id: Ipv4 address formatted node id
847     :type node_id: string
848     :param node_ip: Ipv4 address of node
849     :type node_ip: string
850     :param port: Node port number
851     :type port: int
852     :param expansion: Bindings expansion
853     :type expansion: int
854     :returns: String containing xml data for request
855
856     """
857     templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
858     <node-id>$id</node-id>
859     <timers>
860         <retry-open-time>1</retry-open-time>
861         <hold-time-min-acceptable>120</hold-time-min-acceptable>
862         <delete-hold-down-time>120</delete-hold-down-time>
863         <hold-time-min>90</hold-time-min>
864         <reconciliation-time>120</reconciliation-time>
865         <hold-time>90</hold-time>
866         <hold-time-max>180</hold-time-max>
867         <keep-alive-time>30</keep-alive-time>
868     </timers>
869     <mapping-expanded>$expansion</mapping-expanded>
870     <security>
871         <password>$password</password>
872     </security>
873     <tcp-port>$port</tcp-port>
874     <version>$version</version>
875     <description>ODL SXP Controller</description>
876     <source-ip>$ip</source-ip>
877     <master-database></master-database>
878 </input>''')
879     data = templ.substitute(
880         {'ip': node_id if not node_ip else node_ip, 'id': node_id, 'port': port, 'password': password,
881          'version': version, 'expansion': expansion})
882     return data
883
884
885 def delete_node_xml(node_id):
886     """Generate xml for Delete node request
887
888     :param node_id: Ipv4 address formatted node id
889     :type node_id: string
890     :returns: String containing xml data for request
891
892     """
893     templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
894   <node-id>$id</node-id>
895 </input>''')
896     data = templ.substitute({'id': node_id})
897     return data
898
899
900 def add_domain_xml(node_id, name):
901     """Generate xml for Add Domain request
902
903     :param node_id: Id of node
904     :type node_id: string
905     :param name: Name of Domain
906     :type name: string
907     :returns: String containing xml data for request
908
909     """
910     templ = Template('''<input>
911   <node-id xmlns="urn:opendaylight:sxp:controller">$id</node-id>
912   <domain-name xmlns="urn:opendaylight:sxp:controller">$name</domain-name>
913 </input>''')
914     data = templ.substitute({'name': name, 'id': node_id})
915     return data
916
917
918 def delete_domain_xml(node_id, name):
919     """Generate xml for Remove Domain request
920
921     :param node_id: Id of node
922     :type node_id: string
923     :param name: Name of Domain
924     :type name: string
925     :returns: String containing xml data for request
926
927     """
928     return add_domain_xml(name, node_id)
929
930
931 def get_domain_name(domain_name):
932     """Generate xml for Get Bindings request
933
934     :param domain_name: Name of Domain
935     :type domain_name: string
936     :returns: String containing xml data for request
937
938     """
939     if domain_name == 'global':
940         return ''
941     else:
942         return '<domain-name xmlns="urn:opendaylight:sxp:controller">' + domain_name + '</domain-name>'
943
944
945 def add_bindings_xml(node_id, domain, sgt, prefixes):
946     """Generate xml for Add Bindings request
947
948     :param node_id: Id of node
949     :type node_id: string
950     :param domain: Name of Domain
951     :type domain: string
952     :param sgt: Security group
953     :type sgt: int
954     :param prefixes: List of ip-prefixes
955     :type prefixes: string
956     :returns: String containing xml data for request
957
958     """
959     bindings = ''
960     for prefix in prefixes.split(','):
961         bindings += '\n' + '<ip-prefix>' + prefix + '</ip-prefix>'
962     templ = Template('''<input>
963   <node-id xmlns="urn:opendaylight:sxp:controller">$id</node-id>
964   <domain-name xmlns="urn:opendaylight:sxp:controller">$name</domain-name>
965   <binding xmlns="urn:opendaylight:sxp:controller">
966       <sgt>$sgt</sgt>
967       $bindings
968   </binding>
969 </input>''')
970     data = templ.substitute({'name': domain, 'id': node_id, 'sgt': sgt, 'bindings': bindings})
971     return data
972
973
974 def delete_bindings_xml(node_id, domain, sgt, prefixes):
975     """Generate xml for Remove Bindings request
976
977     :param node_id: Id of node
978     :type node_id: string
979     :param domain: Name of Domain
980     :type domain: string
981     :param sgt: Security group
982     :type sgt: int
983     :param prefixes: List of ip-prefixes
984     :type prefixes: string
985     :returns: String containing xml data for request
986
987     """
988     return add_bindings_xml(node_id, domain, sgt, prefixes)
989
990
991 def prefix_range(start, end):
992     """Generate and concatenate ip-prefixes
993
994     :param start: Start index
995     :type start: string
996     :param end: End index
997     :type end: string
998     :returns: String containing concatenated ip-prefixes
999
1000     """
1001     start = int(start)
1002     end = int(end)
1003     index = 0
1004     prefixes = ''
1005     while index < end:
1006         prefixes += get_ip_from_number(start + index) + '/32'
1007         index += 1
1008         if index < end:
1009             prefixes += ','
1010     return prefixes