1 """Variables file for pcepuser suite.
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.
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
16 from string import Template
19 __author__ = "Vratko Polak"
20 __copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
21 __license__ = "Eclipse Public License v1.0"
22 __email__ = "vrpolak@cisco.com"
25 def get_variables(mininet_ip):
26 """Return dict of variables for the given IP address of Mininet VM."""
28 # 'V' style of explanation.
29 # Comments analyze from high level, to low level, then code builds from low level back to high level.
30 # ### Pcep-topology JSON responses.
31 # Some testcases see only the tunnel created by pcc-mock start: "delegated tunnel" (ID 1).
32 # Other testcases see also tunnel created on ODL demand: "instatntiated tunnel" (ID 2).
33 # Both tunnels can have two states. "Default" upon creation with single hop "1.1.1.1",
34 # and "updated" after update-lsp, which prepends another hop "2.2.2.2".
35 # Variable naming always specifies delegated state first, and ends with _json to distinguish from operation data.
36 # The whole list: default_json, updated_json, updated_default_json, updated_updated_json.
37 # Oh, and the state without mock-pcc connected is off_json.
38 # off_json has '{}' substring and no variable data, so here it is as a special case:
39 variables['off_json'] = '''{
42 "topology-id": "pcep-topology",
44 "network-topology-pcep:topology-pcep": {}
49 # Ok, other _json strings will have more regular structure and some variable data,
50 # so we will be using templates heavily.
51 # First off, there is segment describing PCC which conatins IP address but is otherwise constant.
52 # So the top-level template will look like this:
53 json_templ = Template('''{
54 "network-topology-pcep:path-computation-client": {
56 "reported-lsp": [$LSPS
58 "state-sync": "synchronized",
60 "odl-pcep-ietf-stateful07:stateful": {
61 "lsp-update-capability": true,
62 "odl-pcep-ietf-initiated00:initiation": true
67 # The _json variables will differ only in $LSPS, but $IP will be present inside.
68 # Thus, the $IP substitution will come last, and any auxiliary substitutions before this final one
69 # will have to use safe_substitute().
70 # As you see, $LSPS is in json_templ without preceding newline.
71 # As a rule, a segment will always start with endline and end without endline,
72 # so that we can add comma where needed.
73 # Discussion amout delegated and instantiated implies that $LSPS is either a single delegated LSP
74 # or a pair of delegated and instantiated (separated by comma) LSPS, in appropriate state.
75 # Of course, one LSP always follow a structure, for which here is the template:
76 lsp_templ = Template('''
83 "processing-rule": false,
88 "odl-pcep-ietf-stateful07:lsp": {
89 "administrative": true,
92 "odl-pcep-ietf-initiated00:create": $CREATED,
95 "processing-rule": false,
101 "ipv4-extended-tunnel-id": "$IP",
102 "ipv4-tunnel-endpoint-address": "1.1.1.1",
103 "ipv4-tunnel-sender-address": "$IP"
108 "symbolic-path-name": {
116 # IDs were already talked about, IP will be set last. Now, $NAME.
117 # Pcc-mock uses a fixed naming scheme for delegated tunnels, so one more template can be written,
118 # but it is so simple we can write just the one-line code instead:
119 delegated_name = 'pcc_' + mininet_ip + '_tunnel_1' # 1 == ID
120 # For the instantiated tunnel, user is free to specify anything, even charachers such as \u0000 work.
121 # But as we need to plug the name to XML, let us try something more friendly:
122 instantiated_name = 'Instantiated tunnel' # the space is only somewhat evil character :)
123 # What is CODE? The NAME in base64 encoding (without endline):
124 delegated_code = binascii.b2a_base64(delegated_name)[:-1] # remove endline added by the library function
125 instantiated_code = binascii.b2a_base64(instantiated_name)[:-1]
126 # The remaining segment is HOPS, and that is the place where default and updated states differ.
127 # Once again, there is a template for a single hop:
128 hop_templ = Template('''
131 "ip-prefix": "$HOPIP/32"
135 # The low-to-high part of V comes now, it is just substituting and concatenating.
137 final_hop = hop_templ.substitute({'HOPIP': '1.1.1.1'})
138 update_hop = hop_templ.substitute({'HOPIP': '2.2.2.2'})
139 both_hops = update_hop + ',' + final_hop
141 default_lsp_templ = Template(lsp_templ.safe_substitute({'HOPS': final_hop}))
142 updated_lsp_templ = Template(lsp_templ.safe_substitute({'HOPS': both_hops}))
143 repl_dict = {'NAME': delegated_name, 'ID': '1', 'CODE': delegated_code, 'CREATED': 'false'}
144 delegated_default_lsp = default_lsp_templ.safe_substitute(repl_dict)
145 delegated_updated_lsp = updated_lsp_templ.safe_substitute(repl_dict)
146 repl_dict = {'NAME': instantiated_name, 'ID': '2', 'CODE': instantiated_code, 'CREATED': 'true'}
147 instantiated_default_lsp = default_lsp_templ.safe_substitute(repl_dict)
148 instantiated_updated_lsp = updated_lsp_templ.safe_substitute(repl_dict)
149 # Json templates (without IP set).
150 repl_dict = {'LSPS': delegated_default_lsp}
151 default_json_templ = Template(json_templ.safe_substitute(repl_dict))
152 repl_dict = {'LSPS': delegated_updated_lsp}
153 updated_json_templ = Template(json_templ.safe_substitute(repl_dict))
154 repl_dict = {'LSPS': delegated_updated_lsp + ',' + instantiated_default_lsp}
155 updated_default_json_templ = Template(json_templ.safe_substitute(repl_dict))
156 repl_dict = {'LSPS': delegated_updated_lsp + ',' + instantiated_updated_lsp}
157 updated_updated_json_templ = Template(json_templ.safe_substitute(repl_dict))
158 # Final json variables.
159 repl_dict = {'IP': mininet_ip}
160 variables['default_json'] = default_json_templ.substitute(repl_dict)
161 variables['updated_json'] = updated_json_templ.substitute(repl_dict)
162 variables['updated_default_json'] = updated_default_json_templ.substitute(repl_dict)
163 variables['updated_updated_json'] = updated_updated_json_templ.substitute(repl_dict)
164 # ### Pcep operations XML data.
165 # There are three operations, so let us just write templates from information at
166 # 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
167 # _xml describes content type and also distinguishes from similarly named _json strings.
168 add_xml_templ = Template(
169 '<input xmlns="urn:opendaylight:params:xml:ns:yang:topology:pcep">\n'
170 ' <node>pcc://$IP</node>\n'
171 ' <name>$NAME</name>\n'
172 ' <network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">'
173 '/topo:network-topology/topo:topology[topo:topology-id="pcep-topology"]'
174 '</network-topology-ref>\n'
176 ' <lsp xmlns="urn:opendaylight:params:xml:ns:yang:pcep:ietf:stateful">\n'
177 ' <delegate>true</delegate>\n'
178 ' <administrative>true</administrative>\n'
182 ' <source-ipv4-address>$IP</source-ipv4-address>\n'
183 ' <destination-ipv4-address>1.1.1.1</destination-ipv4-address>\n'
185 ' </endpoints-obj>\n'
188 ' <loose>false</loose>\n'
189 ' <ip-prefix><ip-prefix>1.1.1.1/32</ip-prefix></ip-prefix>\n'
195 update_xml_templ = Template(
196 '<input xmlns="urn:opendaylight:params:xml:ns:yang:topology:pcep">\n'
197 ' <node>pcc://$IP</node>\n'
198 ' <name>$NAME</name>\n'
199 ' <network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">'
200 '/topo:network-topology/topo:topology[topo:topology-id="pcep-topology"]'
201 '</network-topology-ref>\n'
203 ' <lsp xmlns="urn:opendaylight:params:xml:ns:yang:pcep:ietf:stateful">\n'
204 ' <delegate>true</delegate>\n'
205 ' <administrative>true</administrative>\n'
209 ' <loose>false</loose>\n'
210 ' <ip-prefix><ip-prefix>2.2.2.2/32</ip-prefix></ip-prefix>\n'
213 ' <loose>false</loose>\n'
214 ' <ip-prefix><ip-prefix>1.1.1.1/32</ip-prefix></ip-prefix>\n'
220 remove_xml_templ = Template(
221 '<input xmlns="urn:opendaylight:params:xml:ns:yang:topology:pcep">\n'
222 ' <node>pcc://$IP</node>\n'
223 ' <name>$NAME</name>\n'
224 ' <network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">'
225 '/topo:network-topology/topo:topology[topo:topology-id="pcep-topology"]'
226 '</network-topology-ref>\n'
229 # The operations can be applied to either delegated or instantiated tunnel, NAME is the only distinguishing value.
230 # Also, the final IP substitution can be done here.
231 repl_dict = {'IP': mininet_ip}
232 repl_dict['NAME'] = delegated_name
233 variables['update_delegated_xml'] = update_xml_templ.substitute(repl_dict)
234 variables['remove_delegated_xml'] = remove_xml_templ.substitute(repl_dict)
235 repl_dict['NAME'] = instantiated_name
236 variables['add_instantiated_xml'] = add_xml_templ.substitute(repl_dict)
237 variables['update_instantiated_xml'] = update_xml_templ.substitute(repl_dict)
238 variables['remove_instantiated_xml'] = remove_xml_templ.substitute(repl_dict)
239 # All variables ready.