Add SXP device timeout parameters
[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, bindings_timeout=0):
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     :param bindings_timeout: Specifies DHD and Reconciliation timers
532     :type bindings_timeout: int
533     :returns: String containing xml data for request
534
535     """
536     templ = Template('''<input>
537    <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
538    $domain
539    <connections xmlns="urn:opendaylight:sxp:controller">
540       <connection>
541          <peer-address>$ip</peer-address>
542          <tcp-port>$port</tcp-port>
543          <password>$password_</password>
544          <mode>$mode</mode>
545          <version>$version</version>
546          <description>Connection to ISR-G2</description>
547          <connection-timers>
548             <hold-time-min-acceptable>45</hold-time-min-acceptable>
549             <keep-alive-time>30</keep-alive-time>
550             <reconciliation-time>$timeout</reconciliation-time>
551             <delete-hold-down-time>$timeout</delete-hold-down-time>
552          </connection-timers>
553       </connection>
554    </connections>
555 </input>
556 ''')
557     data = templ.substitute(
558         {'ip': ip, 'port': port, 'mode': mode, 'version': version, 'node': node,
559          'password_': password_, 'domain': get_domain_name(domain_name), 'timeout': bindings_timeout})
560     return data
561
562
563 def delete_connections_xml(address, port, node, domain_name):
564     """Generate xml for Delete Connection request
565
566     :param address: Ipv4/6 address of remote peer
567     :type address: string
568     :param port: Port on with remote peer listens
569     :type port: string
570     :param node: Ipv4 address of node
571     :type node: string
572     :param domain_name: Name of Domain
573     :type domain_name: string
574     :returns: String containing xml data for request
575
576     """
577     templ = Template('''<input>
578    <requested-node xmlns="urn:opendaylight:sxp:controller">$node</requested-node>
579    $domain
580    <peer-address xmlns="urn:opendaylight:sxp:controller">$address</peer-address>
581    <tcp-port xmlns="urn:opendaylight:sxp:controller">$port</tcp-port>
582 </input>''')
583     data = templ.substitute({'address': address, 'port': port, 'node': node, 'domain': get_domain_name(domain_name)})
584     return data
585
586
587 def update_binding_xml(sgt0, prefix0, sgt1, prefix1, ip, domain_name):
588     """Generate xml for Update Binding request
589
590     :param sgt0: Original Source Group Tag
591     :type sgt0: string
592     :param prefix0: Original Ipv4/6 prefix
593     :type prefix0: string
594     :param sgt1: New Source Group Tag
595     :type sgt1: string
596     :param prefix1: New Ipv4/6 prefix
597     :type prefix1: string
598     :param ip: Ipv4 address of node
599     :type ip: string
600     :param domain_name: Name of Domain
601     :type domain_name: string
602     :returns: String containing xml data for request
603
604     """
605     templ = Template('''<input>
606   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
607   $domain
608   <original-binding xmlns="urn:opendaylight:sxp:controller">
609     <sgt>$sgt0</sgt>
610     <ip-prefix>$prefix0</ip-prefix>
611   </original-binding>
612   <new-binding xmlns="urn:opendaylight:sxp:controller">
613     <sgt>$sgt1</sgt>
614     <ip-prefix>$prefix1</ip-prefix>
615   </new-binding>
616 </input>''')
617     data = templ.substitute(
618         {'sgt0': sgt0, 'sgt1': sgt1, 'prefix0': prefix0, 'prefix1': prefix1, 'ip': ip,
619          'domain': get_domain_name(domain_name)})
620     return data
621
622
623 def delete_binding_xml(sgt, prefix, ip, domain_name):
624     """Generate xml for Delete Binding request
625
626     :param sgt: Source Group Tag
627     :type sgt: string
628     :param prefix: Ipv4/6 prefix
629     :type prefix: string
630     :param ip: Ipv4 address of node
631     :type ip: string
632     :param domain_name: Name of Domain
633     :type domain_name: string
634     :returns: String containing xml data for request
635
636     """
637     templ = Template('''<input>
638   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
639   <sgt xmlns="urn:opendaylight:sxp:controller">$sgt</sgt>
640   <ip-prefix xmlns="urn:opendaylight:sxp:controller">$prefix</ip-prefix>
641   $domain
642 </input>''')
643     data = templ.substitute({'sgt': sgt, 'prefix': prefix, 'ip': ip, 'domain': get_domain_name(domain_name)})
644     return data
645
646
647 def add_peer_group_xml(name, peers, ip):
648     """Generate xml for Add PeerGroups request
649
650     :param name: Name of PeerGroup
651     :type name: string
652     :param peers: XML formatted peers that will be added to group
653     :type peers: string
654     :param ip: Ipv4 address of node
655     :type ip: string
656     :returns: String containing xml data for request
657
658     """
659     templ = Template('''<input>
660   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
661   <sxp-peer-group xmlns="urn:opendaylight:sxp:controller">
662     <name xmlns="urn:opendaylight:sxp:controller">$name</name>
663     <sxp-peers xmlns="urn:opendaylight:sxp:controller">$peers</sxp-peers>
664     </sxp-peer-group>
665 </input>''')
666     data = templ.substitute({'name': name, 'peers': peers, 'ip': ip})
667     return data
668
669
670 def delete_peer_group_xml(name, ip):
671     """Generate xml for Delete PeerGroup request
672
673     :param name: Name of PeerGroup
674     :type name: string
675     :param ip: Ipv4 address of node
676     :type ip: string
677     :returns: String containing xml data for request
678
679     """
680     templ = Template('''<input>
681   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
682   <peer-group-name xmlns="urn:opendaylight:sxp:controller">$name</peer-group-name>
683 </input>''')
684     data = templ.substitute({'name': name, 'ip': ip})
685     return data
686
687
688 def get_peer_groups_from_node_xml(ip):
689     """Generate xml for Get PeerGroups request
690
691     :param ip: Ipv4 address of node
692     :type ip: string
693     :returns: String containing xml data for request
694
695     """
696     templ = Template('''<input>
697    <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
698 </input>''')
699     data = templ.substitute({'ip': ip})
700     return data
701
702
703 def add_filter_xml(group, filter_type, entries, ip):
704     """Generate xml for Add Filter request
705
706     :param group: Name of group containing filter
707     :type group: string
708     :param filter_type: Type of filter
709     :type filter_type: string
710     :param entries: XML formatted entries that will be added in filter
711     :type entries: string
712     :param ip: Ipv4 address of node
713     :type ip: string
714     :returns: String containing xml data for request
715
716     """
717     templ = Template('''<input>
718   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
719   <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
720   <sxp-filter xmlns="urn:opendaylight:sxp:controller">
721     <filter-type>$filter_type</filter-type>$entries
722   </sxp-filter>
723 </input>''')
724     data = templ.substitute(
725         {'group': group, 'filter_type': filter_type, 'ip': ip, 'entries': entries})
726     return data
727
728
729 def add_domain_filter_xml(domain, domains, entries, ip, filter_name=None):
730     """Generate xml for Add Domain Filter request
731
732     :param domain: Name of Domain containing filter
733     :type domain: string
734     :param domains: Domains on which filter will be applied
735     :type domains: string
736     :param entries: XML formatted entries that will be added in filter
737     :type entries: string
738     :param ip: Ipv4 address of node
739     :type ip: string
740     :param filter_name: Name of filter
741     :type filter_name: string
742     :returns: String containing xml data for request
743
744     """
745     if filter_name:
746         filter_name = "<filter-name>" + filter_name + "</filter-name>"
747     templ = Template('''<input>
748   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
749   <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
750   <sxp-domain-filter xmlns="urn:opendaylight:sxp:controller">
751     $filter_name
752     <domains>$domains</domains>
753     $entries
754   </sxp-domain-filter>
755 </input>''')
756     data = templ.substitute(
757         {'domain': domain, 'domains': domains, 'ip': ip, 'entries': entries, 'filter_name': filter_name})
758     return data
759
760
761 def delete_filter_xml(group, filter_type, ip):
762     """Generate xml for Delete Filter request
763
764     :param group: Name of group containing filter
765     :type group: string
766     :param filter_type: Type of filter
767     :type filter_type: string
768     :param ip: Ipv4 address of node
769     :type ip: string
770     :returns: String containing xml data for request
771
772     """
773     templ = Template('''<input>
774   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
775   <peer-group-name xmlns="urn:opendaylight:sxp:controller">$group</peer-group-name>
776   <filter-type xmlns="urn:opendaylight:sxp:controller">$filter_type</filter-type>
777 </input>''')
778     data = templ.substitute(
779         {'group': group, 'filter_type': filter_type, 'ip': ip})
780     return data
781
782
783 def delete_domain_filter_xml(domain, ip, filter_name=None):
784     """Generate xml for Delete Filter request
785
786     :param domain: Name of Domain containing filter
787     :type domain: string
788     :param ip: Ipv4 address of node
789     :type ip: string
790     :param filter_name: Name of filter
791     :type filter_name: string
792     :returns: String containing xml data for request
793
794     """
795     if filter_name:
796         filter_name = '<filter-name xmlns="urn:opendaylight:sxp:controller">' + filter_name + "</filter-name>"
797     templ = Template('''<input>
798   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
799   <domain-name xmlns="urn:opendaylight:sxp:controller">$domain</domain-name>
800   $filter_name
801 </input>''')
802     data = templ.substitute(
803         {'domain': domain, 'ip': ip, 'filter_name': filter_name})
804     return data
805
806
807 def get_connections_from_node_xml(ip, domain_name):
808     """Generate xml for Get Connections request
809
810     :param ip: Ipv4 address of node
811     :type ip: string
812     :param domain_name: Name of Domain
813     :type domain_name: string
814     :returns: String containing xml data for request
815
816     """
817     templ = Template('''<input>
818    <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
819    $domain
820 </input>''')
821     data = templ.substitute({'ip': ip, 'domain': get_domain_name(domain_name)})
822     return data
823
824
825 def get_bindings_from_node_xml(ip, binding_range, domain_name):
826     """Generate xml for Get Bindings request
827
828     :param binding_range: All or only Local bindings
829     :type binding_range: string
830     :param ip: Ipv4 address of node
831     :type ip: string
832     :param domain_name: Name of Domain
833     :type domain_name: string
834     :returns: String containing xml data for request
835
836     """
837     templ = Template('''<input>
838   <requested-node xmlns="urn:opendaylight:sxp:controller">$ip</requested-node>
839   <bindings-range xmlns="urn:opendaylight:sxp:controller">$range</bindings-range>
840   $domain
841 </input>''')
842     data = templ.substitute({'ip': ip, 'range': binding_range, 'domain': get_domain_name(domain_name)})
843     return data
844
845
846 def add_node_xml(node_id, port, password, version, node_ip=None, expansion=0, bindings_timeout=0):
847     """Generate xml for Add Node request
848
849     :param node_id: Ipv4 address formatted node id
850     :type node_id: string
851     :param node_ip: Ipv4 address of node
852     :type node_ip: string
853     :param port: Node port number
854     :type port: int
855     :param password: TCP-MD5 password
856     :type password: string
857     :param version: Sxp device version
858     :type version: string
859     :param expansion: Bindings expansion
860     :type expansion: int
861     :param bindings_timeout: Specifies DHD and Reconciliation timers
862     :type bindings_timeout: int
863     :returns: String containing xml data for request
864
865     """
866     templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
867     <node-id>$id</node-id>
868     <timers>
869         <retry-open-time>1</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>
877     </timers>
878     <mapping-expanded>$expansion</mapping-expanded>
879     <security>
880         <password>$password</password>
881     </security>
882     <tcp-port>$port</tcp-port>
883     <version>$version</version>
884     <description>ODL SXP Controller</description>
885     <source-ip>$ip</source-ip>
886     <master-database></master-database>
887 </input>''')
888     data = templ.substitute(
889         {'ip': node_id if not node_ip else node_ip, 'id': node_id, 'port': port, 'password': password,
890          'version': version, 'expansion': expansion, 'timeout': bindings_timeout})
891     return data
892
893
894 def delete_node_xml(node_id):
895     """Generate xml for Delete node request
896
897     :param node_id: Ipv4 address formatted node id
898     :type node_id: string
899     :returns: String containing xml data for request
900
901     """
902     templ = Template('''<input xmlns="urn:opendaylight:sxp:controller">
903   <node-id>$id</node-id>
904 </input>''')
905     data = templ.substitute({'id': node_id})
906     return data
907
908
909 def add_domain_xml(node_id, name):
910     """Generate xml for Add Domain request
911
912     :param node_id: Id of node
913     :type node_id: string
914     :param name: Name of Domain
915     :type name: string
916     :returns: String containing xml data for request
917
918     """
919     templ = Template('''<input>
920   <node-id xmlns="urn:opendaylight:sxp:controller">$id</node-id>
921   <domain-name xmlns="urn:opendaylight:sxp:controller">$name</domain-name>
922 </input>''')
923     data = templ.substitute({'name': name, 'id': node_id})
924     return data
925
926
927 def delete_domain_xml(node_id, name):
928     """Generate xml for Remove Domain request
929
930     :param node_id: Id of node
931     :type node_id: string
932     :param name: Name of Domain
933     :type name: string
934     :returns: String containing xml data for request
935
936     """
937     return add_domain_xml(name, node_id)
938
939
940 def get_domain_name(domain_name):
941     """Generate xml for Get Bindings request
942
943     :param domain_name: Name of Domain
944     :type domain_name: string
945     :returns: String containing xml data for request
946
947     """
948     if domain_name == 'global':
949         return ''
950     else:
951         return '<domain-name xmlns="urn:opendaylight:sxp:controller">' + domain_name + '</domain-name>'
952
953
954 def add_bindings_xml(node_id, domain, sgt, prefixes):
955     """Generate xml for Add Bindings request
956
957     :param node_id: Id of node
958     :type node_id: string
959     :param domain: Name of Domain
960     :type domain: string
961     :param sgt: Security group
962     :type sgt: int
963     :param prefixes: List of ip-prefixes
964     :type prefixes: string
965     :returns: String containing xml data for request
966
967     """
968     bindings = ''
969     for prefix in prefixes.split(','):
970         bindings += '\n' + '<ip-prefix>' + prefix + '</ip-prefix>'
971     templ = Template('''<input>
972   <node-id xmlns="urn:opendaylight:sxp:controller">$id</node-id>
973   <domain-name xmlns="urn:opendaylight:sxp:controller">$name</domain-name>
974   <binding xmlns="urn:opendaylight:sxp:controller">
975       <sgt>$sgt</sgt>
976       $bindings
977   </binding>
978 </input>''')
979     data = templ.substitute({'name': domain, 'id': node_id, 'sgt': sgt, 'bindings': bindings})
980     return data
981
982
983 def delete_bindings_xml(node_id, domain, sgt, prefixes):
984     """Generate xml for Remove Bindings request
985
986     :param node_id: Id of node
987     :type node_id: string
988     :param domain: Name of Domain
989     :type domain: string
990     :param sgt: Security group
991     :type sgt: int
992     :param prefixes: List of ip-prefixes
993     :type prefixes: string
994     :returns: String containing xml data for request
995
996     """
997     return add_bindings_xml(node_id, domain, sgt, prefixes)
998
999
1000 def prefix_range(start, end):
1001     """Generate and concatenate ip-prefixes
1002
1003     :param start: Start index
1004     :type start: string
1005     :param end: End index
1006     :type end: string
1007     :returns: String containing concatenated ip-prefixes
1008
1009     """
1010     start = int(start)
1011     end = int(end)
1012     index = 0
1013     prefixes = ''
1014     while index < end:
1015         prefixes += get_ip_from_number(start + index) + '/32'
1016         index += 1
1017         if index < end:
1018             prefixes += ','
1019     return prefixes