Step 1: Move vm scripts to the right place
[integration/test.git] / test / csit / variables / pcepuser / variables.py
1 """Variables file for pcepuser suite.
2
3 Expected JSON templates are fairly long,
4 therefore there are moved out of testcase file.
5 Also, it is needed to generate base64 encoded tunnel name
6 from Mininet IP (which is not known beforehand),
7 so it is easier to employ Python here,
8 than do manipulation in Robot file."""
9 # Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
10 #
11 # This program and the accompanying materials are made available under the
12 # terms of the Eclipse Public License v1.0 which accompanies this distribution,
13 # and is available at http://www.eclipse.org/legal/epl-v10.html
14
15 __author__ = "Vratko Polak"
16 __copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
17 __license__ = "Eclipse Public License v1.0"
18 __email__ = "vrpolak@cisco.com"
19
20 import binascii
21 from string import Template
22
23
24 def get_variables(mininet_ip):
25     """Return dict of variables for the given IP address of Mininet VM."""
26     variables = {}
27     # 'V' style of explanation.
28     # Comments analyze from high level, to low level, then code builds from low level back to high level.
29     # ### Pcep-topology JSON responses.
30     # Some testcases see only the tunnel created by pcc-mock start: "delegated tunnel" (ID 1).
31     # Other testcases see also tunnel created on ODL demand: "instatntiated tunnel" (ID 2).
32     # Both tunnels can have two states. "Default" upon creation with single hop "1.1.1.1",
33     # and "updated" after update-lsp, which prepends another hop "2.2.2.2".
34     # Variable naming always specifies delegated state first, and ends with _json to distinguish from operation data.
35     # The whole list: default_json, updated_json, updated_default_json, updated_updated_json.
36     # Oh, and the state without mock-pcc connected is off_json.
37     # off_json has '{}' substring and no variable data, so here it is as a special case:
38     variables['off_json'] = '''{
39  "topology": [
40   {
41    "topology-id": "pcep-topology",
42    "topology-types": {
43     "network-topology-pcep:topology-pcep": {}
44    }
45   }
46  ]
47 }'''
48     # Ok, other _json strings will have more regular structure and some variable data,
49     # so we will be using templates heavily.
50     # First off, there is segment describing PCC which conatins IP address but is otherwise constant.
51     # So the top-level template will look like this:
52     json_templ = Template('''{
53  "topology": [
54   {
55    "node": [
56     {
57      "network-topology-pcep:path-computation-client": {
58       "ip-address": "$IP",
59       "reported-lsp": [$LSPS
60       ],
61       "state-sync": "synchronized",
62       "stateful-tlv": {
63        "odl-pcep-ietf-stateful07:stateful": {
64         "lsp-update-capability": true,
65         "odl-pcep-ietf-initiated00:initiation": true
66        }
67       }
68      },
69      "node-id": "pcc://$IP"
70     }
71    ],
72    "topology-id": "pcep-topology",
73    "topology-types": {
74     "network-topology-pcep:topology-pcep": {}
75    }
76   }
77  ]
78 }''')
79     # The _json variables will differ only in $LSPS, but $IP will be present inside.
80     # Thus, the $IP substitution will come last, and any auxiliary substitutions before this final one
81     # will have to use safe_substitute().
82     # As you see, $LSPS is in json_templ without preceding newline.
83     # As a rule, a segment will always start with endline and end without endline,
84     # so that we can add comma where needed.
85     # Discussion amout delegated and instantiated implies that $LSPS is either a single delegated LSP
86     # or a pair of delegated and instantiated (separated by comma) LSPS, in appropriate state.
87     # Of course, one LSP always follow a structure, for which here is the template:
88     lsp_templ = Template('''
89        {
90         "name": "$NAME",
91         "path": [
92          {
93           "ero": {
94            "ignore": false,
95            "processing-rule": false,
96            "subobject": [$HOPS
97            ]
98           },
99           "lsp-id": $ID,
100           "odl-pcep-ietf-stateful07:lsp": {
101            "administrative": true,
102            "delegate": true,
103            "ignore": false,
104            "odl-pcep-ietf-initiated00:create": false,
105            "operational": "up",
106            "plsp-id": $ID,
107            "processing-rule": false,
108            "remove": false,
109            "sync": true,
110            "tlvs": {
111             "lsp-identifiers": {
112              "ipv4": {
113               "ipv4-extended-tunnel-id": "$IP",
114               "ipv4-tunnel-endpoint-address": "1.1.1.1",
115               "ipv4-tunnel-sender-address": "$IP"
116              },
117              "lsp-id": $ID,
118              "tunnel-id": $ID
119             },
120             "symbolic-path-name": {
121              "path-name": "$CODE"
122             }
123            }
124           }
125          }
126         ]
127        }''')
128     # IDs were already talked about, IP will be set last. Now, $NAME.
129     # Pcc-mock uses a fixed naming scheme for delegated tunnels, so one more template can be written,
130     # but it is so simple we can write just the one-line code instead:
131     delegated_name = 'pcc_' + mininet_ip + '_tunnel_1'  # 1 == ID
132     # For the instantiated tunnel, user is free to specify anything, even charachers such as \u0000 work.
133     # But as we need to plug the name to XML, let us try something more friendly:
134     instantiated_name = 'Instantiated tunnel'  # the space is only somewhat evil character :)
135     # What is CODE? The NAME in base64 encoding (without endline):
136     delegated_code = binascii.b2a_base64(delegated_name)[:-1]  # remove endline added by the library function
137     instantiated_code = binascii.b2a_base64(instantiated_name)[:-1]
138     # The remaining segment is HOPS, and that is the place where default and updated states differ.
139     # Once gain, there is a template for a single hop:
140     hop_templ = Template('''
141             {
142              "ip-prefix": {
143               "ip-prefix": "$HOPIP/32"
144              },
145              "loose": false
146             }''')
147     # The low-to-high part of V comes now, it is just substituting and concatenating.
148     # Hops:
149     final_hop = hop_templ.substitute({'HOPIP': '1.1.1.1'})
150     update_hop = hop_templ.substitute({'HOPIP': '2.2.2.2'})
151     both_hops = update_hop + ',' + final_hop
152     # Lsps:
153     default_lsp_templ = Template(lsp_templ.safe_substitute({'HOPS': final_hop}))
154     updated_lsp_templ = Template(lsp_templ.safe_substitute({'HOPS': both_hops}))
155     repl_dict = {'NAME': delegated_name, 'ID': '1', 'CODE': delegated_code}
156     delegated_default_lsp = default_lsp_templ.safe_substitute(repl_dict)
157     delegated_updated_lsp = updated_lsp_templ.safe_substitute(repl_dict)
158     repl_dict = {'NAME': instantiated_name, 'ID': '2', 'CODE': instantiated_code}
159     instantiated_default_lsp = default_lsp_templ.safe_substitute(repl_dict)
160     instantiated_updated_lsp = updated_lsp_templ.safe_substitute(repl_dict)
161     # Json templates (without IP set).
162     repl_dict = {'LSPS': delegated_default_lsp}
163     default_json_templ = Template(json_templ.safe_substitute(repl_dict))
164     repl_dict = {'LSPS': delegated_updated_lsp}
165     updated_json_templ = Template(json_templ.safe_substitute(repl_dict))
166     repl_dict = {'LSPS': delegated_updated_lsp + ',' + instantiated_default_lsp}
167     updated_default_json_templ = Template(json_templ.safe_substitute(repl_dict))
168     repl_dict = {'LSPS': delegated_updated_lsp + ',' + instantiated_updated_lsp}
169     updated_updated_json_templ = Template(json_templ.safe_substitute(repl_dict))
170     # Final json variables.
171     repl_dict = {'IP': mininet_ip}
172     variables['default_json'] = default_json_templ.substitute(repl_dict)
173     variables['updated_json'] = updated_json_templ.substitute(repl_dict)
174     variables['updated_default_json'] = updated_default_json_templ.substitute(repl_dict)
175     variables['updated_updated_json'] = updated_updated_json_templ.substitute(repl_dict)
176     # ### Pcep operations XML data.
177     # There are three operations, so let us just write templates from information at
178     # https://wiki.opendaylight.org/view/BGP_LS_PCEP:Programmer_Guide#Tunnel_Management_for_draft-ietf-pce-stateful-pce-07_and_draft-ietf-pce-pce-initiated-lsp-00
179     # _xml describes content type and also distinguishes from similarly named _json strings.
180     add_xml_templ = Template('''<input xmlns="urn:opendaylight:params:xml:ns:yang:topology:pcep">
181  <node>pcc://$IP</node>
182  <name>$NAME</name>
183  <network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">/topo:network-topology/topo:topology'''
184                              + '''[topo:topology-id="pcep-topology"]</network-topology-ref>
185  <arguments>
186   <lsp xmlns="urn:opendaylight:params:xml:ns:yang:pcep:ietf:stateful">
187    <delegate>true</delegate>
188    <administrative>true</administrative>
189   </lsp>
190   <endpoints-obj>
191    <ipv4>
192     <source-ipv4-address>$IP</source-ipv4-address>
193     <destination-ipv4-address>1.1.1.1</destination-ipv4-address>
194    </ipv4>
195   </endpoints-obj>
196   <ero>
197    <subobject>
198     <loose>false</loose>
199     <ip-prefix><ip-prefix>1.1.1.1/32</ip-prefix></ip-prefix>
200    </subobject>
201   </ero>
202  </arguments>
203 </input>''')
204     update_xml_templ = Template('''<input xmlns="urn:opendaylight:params:xml:ns:yang:topology:pcep">
205  <node>pcc://$IP</node>
206  <name>$NAME</name>
207  <network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">/topo:network-topology/topo:topology'''
208                                 + '''[topo:topology-id="pcep-topology"]</network-topology-ref>
209  <arguments>
210   <lsp xmlns="urn:opendaylight:params:xml:ns:yang:pcep:ietf:stateful">
211    <delegate>true</delegate>
212    <administrative>true</administrative>
213   </lsp>
214   <ero>
215    <subobject>
216     <loose>false</loose>
217     <ip-prefix><ip-prefix>2.2.2.2/32</ip-prefix></ip-prefix>
218    </subobject>
219    <subobject>
220     <loose>false</loose>
221     <ip-prefix><ip-prefix>1.1.1.1/32</ip-prefix></ip-prefix>
222    </subobject>
223   </ero>
224  </arguments>
225 </input>''')
226     remove_xml_templ = Template('''<input xmlns="urn:opendaylight:params:xml:ns:yang:topology:pcep">
227  <node>pcc://$IP</node>
228  <name>$NAME</name>
229  <network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">/topo:network-topology/topo:topology'''
230                                 + '''[topo:topology-id="pcep-topology"]</network-topology-ref>
231 </input>''')
232     # The operations can be applied to either delegated or instantiated tunnel, NAME is the only distinguishing value.
233     # Also, the final IP substitution can be done here.
234     repl_dict = {'IP': mininet_ip}
235     repl_dict['NAME'] = delegated_name
236     variables['update_delegated_xml'] = update_xml_templ.substitute(repl_dict)
237     variables['remove_delegated_xml'] = remove_xml_templ.substitute(repl_dict)
238     repl_dict['NAME'] = instantiated_name
239     variables['add_instantiated_xml'] = add_xml_templ.substitute(repl_dict)
240     variables['update_instantiated_xml'] = update_xml_templ.substitute(repl_dict)
241     variables['remove_instantiated_xml'] = remove_xml_templ.substitute(repl_dict)
242     # All variables ready.
243     return variables