--- /dev/null
+*** Settings ***
+Documentation Robot keyword library (Resource) for runtime changes to config subsystem state using restconf calls.
+...
+... Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+...
+... This program and the accompanying materials are made available under the
+... terms of the Eclipse Public License v1.0 which accompanies this distribution,
+... and is available at http://www.eclipse.org/legal/epl-v10.html
+Library ${CURDIR}/RequestsLibrary.py
+Variables ${CURDIR}/../variables/Variables.py
+
+*** Keywords ***
+Setup_Config_Via_Restconf
+ [Documentation] Creates Requests session to be used by subsequent keywords.
+ # Do not append slash at the end uf URL, Requests would add another, resulting in error.
+ Create_Session cvr_session http://${CONTROLLER}:${RESTCONFPORT}/restconf/config/network-topology:network-topology/topology/topology-netconf/node/controller-config/yang-ext:mount headers=${HEADERS_XML} auth=${AUTH}
+
+Teardown_Config_Via_Restconf
+ [Documentation] Teardown to pair with Setup (otherwise no-op).
+ Log TODO: The following line does not seem to be implemented by RequestsLibrary. Look for a workaround.
+ # Delete_Session cvr_session
+
+Post_Xml_Config_Module_Via_Restconf
+ [Arguments] ${xml_data}
+ [Documentation] Post new XML configuration to config:modules
+ # Also no slash here
+ Post_Xml_Config_Via_Restconf config:modules ${xml_data}
+
+Post_Xml_Config_Service_Via_Restconf
+ [Arguments] ${xml_data}
+ [Documentation] Post new XML configuration to config:services
+ Post_Xml_Config_Via_Restconf config:services ${xml_data}
+
+Post_Xml_Config_Via_Restconf
+ [Arguments] ${uri_part} ${xml_data}
+ [Documentation] Post XML data to given controller-config URI, check reponse text is empty and status_code is 204.
+ ${response}= RequestsLibrary.Post cvr_session ${uri_part} data=${xml_data}
+ Log ${response.text}
+ Should_Be_Empty ${response.text}
+ Should_Be_Equal_As_Strings ${response.status_code} 204
--- /dev/null
+*** Settings ***
+Documentation Robot keyword library (Resource) for performing PCEP operations via restconf calls.
+...
+... Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+...
+... This program and the accompanying materials are made available under the
+... terms of the Eclipse Public License v1.0 which accompanies this distribution,
+... and is available at http://www.eclipse.org/legal/epl-v10.html
+Library ${CURDIR}/RequestsLibrary.py
+Variables ${CURDIR}/../variables/Variables.py
+
+*** Keywords ***
+Setup_Pcep_Operations
+ [Documentation] Creates Requests session to be used by subsequent keywords.
+ # Do not append slash at the end uf URL, Requests would add another, resulting in error.
+ Create_Session pcep_session http://${CONTROLLER}:${RESTCONFPORT}/restconf/operations headers=${HEADERS_XML} auth=${AUTH}
+
+Teardown_Pcep_Operations
+ [Documentation] Teardown to pair with Setup (otherwise no-op).
+ Log TODO: The following line does not seem to be implemented by RequestsLibrary. Look for a workaround.
+ # Delete_Session pcep_session
+
+Add_Xml_Lsp_Return_Json
+ [Arguments] ${xml_data}
+ [Documentation] Instantiate LSP according to XML data and return response (json) text.
+ # Also no slash here
+ ${response}= Operate_Xml_Lsp_Return_Json network-topology-pcep:add-lsp ${xml_data}
+ [Return] ${response}
+
+Update_Xml_Lsp_Return_Json
+ [Arguments] ${xml_data}
+ [Documentation] Update LSP according to XML data and return response (json) text.
+ # Also no slash here
+ ${response}= Operate_Xml_Lsp_Return_Json network-topology-pcep:update-lsp ${xml_data}
+ [Return] ${response}
+
+Remove_Xml_Lsp_Return_Json
+ [Arguments] ${xml_data}
+ [Documentation] Remove LSP according to XML data and return response (json) text.
+ # Also no slash here
+ ${response}= Operate_Xml_Lsp_Return_Json network-topology-pcep:remove-lsp ${xml_data}
+ [Return] ${response}
+
+Operate_Xml_Lsp_Return_Json
+ [Arguments] ${uri_part} ${xml_data}
+ [Documentation] Post XML data to given pcep-operations URI, check status_code is 200 and return response text (JSON).
+ ${response}= RequestsLibrary.Post pcep_session ${uri_part} data=${xml_data}
+ Should_Be_Equal_As_Strings ${response.status_code} 200
+ [Return] ${response.text}
+
+Pcep_Json_Is_Success
+ [Arguments] ${text}
+ [Documentation] Given text should be equal to successfull json response.
+ Should_Be_Equal_As_Strings ${text} {"output":{}}
+
+Pcep_Json_Is_Refused
+ [Arguments] ${text}
+ [Documentation] Given text should be equal to json response when device refuses tunnel removal.
+ # FIXME: We probably should normalize text as json (and by that, test whether it is a json at all).
+ Should_Be_Equal_As_Strings ${text} {"output":{"error":[{"error-object":{"ignore":false,"processing-rule":false,"type":19,"value":9}}],"failure":"failed"}}
--- /dev/null
+*** Settings ***
+Documentation Basic tests for odl-bgpcep-pcep-all feature.
+...
+... Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+...
+... This program and the accompanying materials are made available under the
+... terms of the Eclipse Public License v1.0 which accompanies this distribution,
+... and is available at http://www.eclipse.org/legal/epl-v10.html
+Suite Setup Set_It_Up
+Suite Teardown Tear_It_Down
+Library OperatingSystem
+Library SSHLibrary prompt=]>
+Library ${CURDIR}/../../../libraries/RequestsLibrary.py
+Library ${CURDIR}/../../../libraries/HsfJson/hsf_json.py
+Resource ${CURDIR}/../../../libraries/PcepOperations.robot
+Variables ${CURDIR}/../../../variables/Variables.py
+Variables ${CURDIR}/../../../variables/pcepuser/variables.py ${MININET}
+
+*** Variables ***
+${ExpDir} ${CURDIR}/expected
+${ActDir} ${CURDIR}/actual
+
+*** Test Cases ***
+Topology_Precondition
+ [Documentation] Compare current pcep-topology to off_json variable.
+ ... Timeout is long enough to ODL boot, to see that pcep is ready, with no PCC is connected.
+ [Tags] critical
+ Wait_Until_Keyword_Succeeds 300 1 Compare_Topology ${off_json} 010_Topology_Precondition
+
+Start_Pcc_Mock
+ [Documentation] Execute pcc-mock on Mininet, fail is Open is not sent, keep it running for next tests.
+ ${command}= Set_Variable java -jar ${filename} --local-address ${MININET} --remote-address ${CONTROLLER} 2>&1 | tee pccmock.log
+ Log ${command}
+ Write ${command}
+ Read_Until started, sent proposal Open
+
+Topology_Default
+ [Documentation] Compare pcep-topology to default_json, which includes a tunnel from pcc-mock.
+ ... Timeout is lower than in Precondition, as state from pcc-mock should be updated quickly.
+ [Tags] critical
+ Wait_Until_Keyword_succeeds 5 1 Compare_Topology ${default_json} 020_Topology_Default
+
+Update_Delegated
+ [Documentation] Perform update-lsp on the mocked tunnel, check response is success.
+ [Tags] critical
+ ${text}= Update_Xml_Lsp_Return_Json ${update_delegated_xml}
+ Pcep_Json_Is_Success ${text}
+
+Topology_Updated
+ [Documentation] Compare pcep-topology to default_json, which includes the updated tunnel.
+ [Tags] critical
+ Wait_Until_Keyword_succeeds 5 1 Compare_Topology ${updated_json} 030_Topology_Updated
+
+Refuse_Remove_Delegated
+ [Documentation] Perform remove-lsp on the mocked tunnel, check that mock-pcc has refused to remove it.
+ [Tags] critical
+ ${text}= Remove_Xml_Lsp_Return_Json ${remove_delegated_xml}
+ Pcep_Json_Is_Refused ${text}
+
+Topology_Still_Updated
+ [Documentation] Compare pcep-topology to default_json, which includes the updated tunnel, to verify that refusal did not break topology.
+ [Tags] critical
+ Wait_Until_Keyword_succeeds 5 1 Compare_Topology ${updated_json} 040_Topology_Still_Updated
+
+Add_Instantiated
+ [Documentation] Perform add-lsp to create new tunnel, check that response is success.
+ [Tags] critical
+ ${text}= Add_Xml_Lsp_Return_Json ${add_instantiated_xml}
+ Pcep_Json_Is_Success ${text}
+
+Topology_Second_Default
+ [Documentation] Compare pcep-topology to default_json, which includes the updated delegated and default instantiated tunnel.
+ [Tags] critical
+ Wait_Until_Keyword_succeeds 5 1 Compare_Topology ${updated_default_json} 050_Topology_Second_Default
+
+Update_Instantiated
+ [Documentation] Perform update-lsp on the newly instantiated tunnel, check that response is success.
+ [Tags] critical
+ ${text}= Update_Xml_Lsp_Return_Json ${update_instantiated_xml}
+ Pcep_Json_Is_Success ${text}
+
+Topology_Second_Updated
+ [Documentation] Compare pcep-topology to default_json, which includes the updated delegated and updated instantiated tunnel.
+ [Tags] critical
+ Wait_Until_Keyword_succeeds 5 1 Compare_Topology ${updated_updated_json} 060_Topology_Second_Updated
+
+Remove_Instantiated
+ [Documentation] Perform remove-lsp on the instantiated tunnel, check that response is success.
+ [Tags] critical
+ ${text}= Remove_Xml_Lsp_Return_Json ${remove_instantiated_xml}
+ Pcep_Json_Is_Success ${text}
+
+Topology_Again_Updated
+ [Documentation] Compare pcep-topology to default_json, which includes the updated tunnel, to verify that instantiated tunnel was removed.
+ [Tags] critical
+ Wait_Until_Keyword_succeeds 5 1 Compare_Topology ${updated_json} 070_Topology_Again_Updated
+
+Stop_Pcc_Mock
+ [Documentation] Send ctrl+c to pcc-mock, fails if no prompt is seen
+ ... after 3 seconds (the default for SSHLibrary)
+ ${command}= Evaluate chr(int(3))
+ Log ${command}
+ Write ${command}
+ Read_Until_Prompt
+
+Topology_Postcondition
+ [Documentation] Compare curent pcep-topology to "off_json" again.
+ [Tags] critical
+ Wait_Until_Keyword_Succeeds 5 1 Compare_Topology ${off_json} 080_Topology_Postcondition
+
+*** Keywords ***
+Set_It_Up
+ [Documentation] Create SSH session to Mininet machine, prepare HTTP client session to Controller.
+ ... Figure out latest pcc-mock version and download it from Nexus to Mininet.
+ ... Also, delete and create directories for json diff handling.
+ Open_Connection ${MININET}
+ Login_With_Public_Key ${MININET_USER} ${USER_HOME}/.ssh/id_rsa any
+ Create_Session ses http://${CONTROLLER}:${RESTCONFPORT}/restconf/operational/network-topology:network-topology auth=${AUTH}
+ ${urlbase}= Set_Variable ${NEXUSURL_PREFIX}/content/repositories/opendaylight.snapshot/org/opendaylight/bgpcep/pcep-pcc-mock
+ ${version}= Execute_Command curl ${urlbase}/maven-metadata.xml | grep latest | cut -d '>' -f 2 | cut -d '<' -f 1
+ Log ${version}
+ ${namepart}= Execute_Command curl ${urlbase}/${version}/maven-metadata.xml | grep value | head -n 1 | cut -d '>' -f 2 | cut -d '<' -f 1
+ Log ${namepart}
+ Set_Suite_Variable ${filename} pcep-pcc-mock-${namepart}-executable.jar
+ Log ${filename}
+ ${response}= Execute_Command wget -q -N ${urlbase}/${version}/${filename} 2>&1
+ Log ${response}
+ Remove_Directory ${ExpDir}
+ Remove_Directory ${ActDir}
+ Create_Directory ${ExpDir}
+ Create_Directory ${ActDir}
+ Setup_Pcep_Operations
+
+Compare_Topology
+ [Arguments] ${expected} ${name}
+ [Documentation] Get current pcep-topology as json, normalize both expected and actual json.
+ ... Save normalized jsons to files for later processing.
+ ... Error codes and normalized jsons should match exactly.
+ ${normexp}= Hsf_Json ${expected}
+ Log ${normexp}
+ Create_File ${ExpDir}${/}${name} ${normexp}
+ ${resp}= RequestsLibrary.Get ses topology/pcep-topology
+ Log ${resp}
+ Log ${resp.text}
+ ${normresp}= Hsf_Json ${resp.text}
+ Log ${normresp}
+ Create_File ${ActDir}${/}${name} ${normresp}
+ Should_Be_Equal_As_Strings ${resp.status_code} 200
+ Should_Be_Equal ${normresp} ${normexp}
+
+Tear_It_Down
+ [Documentation] Download pccmock.log and Log its contents.
+ ... Compute and Log the diff between expected and actual normalized responses.
+ ... Close both HTTP client session and SSH connection to Mininet.
+ SSHLibrary.Get_File pccmock.log
+ ${pccmocklog}= Run cat pccmock.log
+ Log ${pccmocklog}
+ ${diff}= Run diff -dur ${ExpDir} ${ActDir}
+ Log ${diff}
+ Teardown_Pcep_Operations
+ Delete_All_Sessions
+ Close_All_Connections
--- /dev/null
+*** Settings ***
+Documentation TCPMD5 user-facing feature system tests, using PCEP.
+...
+... Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+...
+... This program and the accompanying materials are made available under the
+... terms of the Eclipse Public License v1.0 which accompanies this distribution,
+... and is available at http://www.eclipse.org/legal/epl-v10.html
+Suite Setup Set_It_Up
+Suite Teardown Tear_It_Down
+Library OperatingSystem
+Library SSHLibrary prompt=]>
+Library ${CURDIR}/../../../libraries/RequestsLibrary.py
+Library ${CURDIR}/../../../libraries/HsfJson/hsf_json.py
+Resource ${CURDIR}/../../../libraries/ConfigViaRestconf.robot
+Resource ${CURDIR}/../../../libraries/PcepOperations.robot
+Variables ${CURDIR}/../../../variables/Variables.py
+Variables ${CURDIR}/../../../variables/tcpmd5user/variables.py ${MININET}
+Variables ${CURDIR}/../../../variables/pcepuser/variables.py ${MININET}
+
+*** Variables ***
+${ExpDir} ${CURDIR}/expected
+${ActDir} ${CURDIR}/actual
+
+*** Test Cases ***
+Topology_Precondition
+ [Documentation] Compare current pcep-topology to "offjson" variable.
+ ... Timeout is long enough to see that pcep is ready, with no PCC is connected.
+ [Tags] critical
+ Wait_Until_Keyword_Succeeds 300 1 Compare_Topology ${offjson} Pre
+
+Start_Secure_Pcc_Mock
+ [Documentation] Execute pcc-mock on Mininet with password set, fail if pcc-mock returns. Keep pcc-mock running for next test cases.
+ [Tags] critical
+ ${command}= Set_Variable java -jar ${filename} --password topsecret --local-address ${MININET} --remote-address ${CONTROLLER} 2>&1 | tee pccmock.log
+ Log ${command}
+ Write ${command}
+ Run_Keyword_And_Expect_Error * Read_Until_Prompt
+
+Topology_Unauthorized_1
+ [Documentation] Try to catch a glimpse of pcc-mock in pcep-topology. Pass if no change from Precondition is detected over 1 minute.
+ [Tags] critical
+ Run_Keyword_And_Expect_Error * Wait_Until_Keyword_Succeeds 10 1 Run_Keyword_And_Expect_Error *
+ ... Compare_Topology ${offjson} Una1
+ # RKAEE WUKS RKAEE equals poor man's Wait_For_Keyword_To_Fail (and pass iff it does not fail)
+ # Maybe explicit contruction with :FOR and time-based exit will be more readable?
+
+Enable_Tcpmd5_No_Password_Yet
+ [Documentation] Send series of restconf posts according to https://wiki.opendaylight.org/view/BGP_LS_PCEP:TCP_MD5_Guide#RESTCONF_Configuration
+ ... Every post should return empty text with 204 status code.
+ [Tags] critical
+ Post_Xml_Config_Module_Via_Restconf ${key_access_module}
+ Post_Xml_Config_Service_Via_Restconf ${key_access_service}
+ Post_Xml_Config_Module_Via_Restconf ${client_channel_module}
+ Post_Xml_Config_Service_Via_Restconf ${client_channel_service}
+ Post_Xml_Config_Module_Via_Restconf ${server_channel_module}
+ Post_Xml_Config_Service_Via_Restconf ${server_channel_service}
+ Post_Xml_Config_Module_Via_Restconf ${pcep_dispatcher_module}
+
+Topology_Unauthorized_2
+ [Documentation] The same logic as Topology_Unauthorized_1 as password was not provided to ODL.
+ [Tags] critical
+ Run_Keyword_And_Expect_Error * Wait_Until_Keyword_Succeeds 10 1 Run_Keyword_And_Expect_Error *
+ ... Compare_Topology ${offjson} Una2
+
+Set_Wrong_Password
+ [Documentation] Send restconf post to configure password for pcep dispatcher for client with Mininet IP address.
+ ... This password does not match what pcc-mock uses.
+ [Tags] critical
+ Post_Xml_Config_Module_Via_Restconf ${passwd_changeme_module}
+
+Topology_Unauthorized_3
+ [Documentation] The same logic as Topology_Unauthorized_1 as incorrect password was provided to ODL.
+ [Tags] critical
+ Run_Keyword_And_Expect_Error * Wait_Until_Keyword_Succeeds 10 1 Run_Keyword_And_Expect_Error *
+ ... Compare_Topology ${offjson} Una3
+
+Set_Correct_Password
+ [Documentation] Send restconf post to configure password for pcep dispatcher for client with Mininet IP address.
+ ... This password finally matches what pcc-mock uses.
+ [Tags] critical
+ Post_Xml_Config_Module_Via_Restconf ${passwd_topsecret_module}
+
+Topology_Intercondition
+ [Documentation] Compare pcep-topology to "onjson", which includes a tunnel from pcc-mock.
+ [Tags] xfail
+ Wait_Until_Keyword_Succeeds 10 1 Compare_Topology ${onjson} Inter
+
+Update_Delegated
+ [Documentation] Perform update-lsp on the mocked tunnel, check response is success.
+ [Tags] critical
+ ${text}= Update_Xml_Lsp_Return_Json ${update_delegated_xml}
+ Pcep_Json_Is_Success ${text}
+
+Topology_Updated
+ [Documentation] Compare pcep-topology to default_json, which includes the updated tunnel.
+ [Tags] critical
+ Wait_Until_Keyword_succeeds 5 1 Compare_Topology ${updated_json} 010_Topology_Updated
+
+Unset_Password
+ [Documentation] Send restconf post to de-configure password for pcep dispatcher for client with Mininet IP address.
+ [Tags] critical
+ Post_Xml_Config_Module_Via_Restconf ${no_passwd_module}
+
+Topology_Unauthorized_4
+ [Documentation] The same logic as Topology_Unauthorized_1 as the correct password is no longer configured on ODL.
+ [Tags] critical
+ Run_Keyword_And_Expect_Error * Wait_Until_Keyword_Succeeds 10 1 Run_Keyword_And_Expect_Error *
+ ... Compare_Topology ${offjson} Una4
+
+Stop_Pcc_Mock
+ [Documentation] Send ctrl+c to pcc-mock, fails if no prompt is seen
+ ... after 3 seconds (the default for SSHLibrary)
+ ${command}= Evaluate chr(int(3))
+ Log ${command}
+ Write ${command}
+ Read_Until_Prompt
+
+Topology_Postcondition
+ [Documentation] Compare curent pcep-topology to "offjson" again.
+ ... Timeout is lower than in Precondition,
+ ... but data from pcc-mock should be gone quickly.
+ [Tags] critical
+ Wait_Until_Keyword_Succeeds 10 1 Compare_Topology ${offjson} Post
+
+*** Keywords ***
+Set_It_Up
+ [Documentation] Create SSH session to Mininet machine, prepare HTTP client session to Controller.
+ ... Figure out latest pcc-mock version and download it from Nexus to Mininet.
+ ... Also, delete and create directories for json diff handling.
+ Open_Connection ${MININET}
+ Login_With_Public_Key ${MININET_USER} ${USER_HOME}/.ssh/id_rsa any
+ Create_Session ses http://${CONTROLLER}:${RESTCONFPORT}/restconf/operational/network-topology:network-topology auth=${AUTH}
+ # TODO: Figure out a way how to share pcc-mock instance with pcepuser suite.
+ ${urlbase}= Set_Variable ${NEXUSURL_PREFIX}/content/repositories/opendaylight.snapshot/org/opendaylight/bgpcep/pcep-pcc-mock
+ ${version}= Execute_Command curl ${urlbase}/maven-metadata.xml | grep latest | cut -d '>' -f 2 | cut -d '<' -f 1
+ Log ${version}
+ ${namepart}= Execute_Command curl ${urlbase}/${version}/maven-metadata.xml | grep value | head -n 1 | cut -d '>' -f 2 | cut -d '<' -f 1
+ Log ${namepart}
+ Set_Suite_Variable ${filename} pcep-pcc-mock-${namepart}-executable.jar
+ Log ${filename}
+ ${response}= Execute_Command wget -q -N ${urlbase}/${version}/${filename} 2>&1
+ Log ${response}
+ Remove_Directory ${ExpDir}
+ Remove_Directory ${ActDir}
+ Create_Directory ${ExpDir}
+ Create_Directory ${ActDir}
+ Setup_Config_Via_Restconf
+ Setup_Pcep_Operations
+
+Compare_Topology
+ [Arguments] ${expected} ${name}
+ [Documentation] Get current pcep-topology as json, normalize both expected and actual json.
+ ... Save normalized jsons to files for later processing.
+ ... Error codes and normalized jsons should match exactly.
+ ${normexp}= Hsf_Json ${expected}
+ Log ${normexp}
+ Create_File ${ExpDir}${/}${name} ${normexp}
+ ${resp}= RequestsLibrary.Get ses topology/pcep-topology
+ Log ${resp}
+ Log ${resp.text}
+ ${normresp}= Hsf_Json ${resp.text}
+ Log ${normresp}
+ Create_File ${ActDir}${/}${name} ${normresp}
+ Should_Be_Equal_As_Strings ${resp.status_code} 200
+ Should_Be_Equal ${normresp} ${normexp}
+
+Tear_It_Down
+ [Documentation] Download pccmock.log and Log its contents.
+ ... Compute and Log the diff between expected and actual normalized responses.
+ ... Close both HTTP client session and SSH connection to Mininet.
+ SSHLibrary.Get_File pccmock.log
+ ${pccmocklog}= Run cat pccmock.log
+ Log ${pccmocklog}
+ ${diff}= Run diff -dur ${ExpDir} ${ActDir}
+ Log ${diff}
+ Teardown_Pcep_Operations
+ Teardown_Config_Via_Restconf
+ Delete_All_Sessions
+ Close_All_Connections
--- /dev/null
+# Place the suites in run order:
+integration/test/csit/suites/bgpcep/pcepuser
+integration/test/csit/suites/bgpcep/tcpmd5user
+# integration/test/csit/suites/bgpcep/bgpuser is not implemented yet
--- /dev/null
+"""Variables file for pcepuser suite.
+
+Expected JSON templates are fairly long,
+therefore there are moved out of testcase file.
+Also, it is needed to generate base64 encoded tunnel name
+from Mininet IP (which is not known beforehand),
+so it is easier to employ Python here,
+than do manipulation in Robot file."""
+# Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+__author__ = "Vratko Polak"
+__copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
+__license__ = "Eclipse Public License v1.0"
+__email__ = "vrpolak@cisco.com"
+
+import binascii
+from string import Template
+
+
+def get_variables(mininet_ip):
+ """Return dict of variables for the given IP address of Mininet VM."""
+ variables = {}
+ # 'V' style of explanation.
+ # Comments analyze from high level, to low level, then code builds from low level back to high level.
+ # ### Pcep-topology JSON responses.
+ # Some testcases see only the tunnel created by pcc-mock start: "delegated tunnel" (ID 1).
+ # Other testcases see also tunnel created on ODL demand: "instatntiated tunnel" (ID 2).
+ # Both tunnels can have two states. "Default" upon creation with single hop "1.1.1.1",
+ # and "updated" after update-lsp, which prepends another hop "2.2.2.2".
+ # Variable naming always specifies delegated state first, and ends with _json to distinguish from operation data.
+ # The whole list: default_json, updated_json, updated_default_json, updated_updated_json.
+ # Oh, and the state without mock-pcc connected is off_json.
+ # off_json has '{}' substring and no variable data, so here it is as a special case:
+ variables['off_json'] = '''{
+ "topology": [
+ {
+ "topology-id": "pcep-topology",
+ "topology-types": {
+ "network-topology-pcep:topology-pcep": {}
+ }
+ }
+ ]
+}'''
+ # Ok, other _json strings will have more regular structure and some variable data,
+ # so we will be using templates heavily.
+ # First off, there is segment describing PCC which conatins IP address but is otherwise constant.
+ # So the top-level template will look like this:
+ json_templ = Template('''{
+ "topology": [
+ {
+ "node": [
+ {
+ "network-topology-pcep:path-computation-client": {
+ "ip-address": "$IP",
+ "reported-lsp": [$LSPS
+ ],
+ "state-sync": "synchronized",
+ "stateful-tlv": {
+ "odl-pcep-ietf-stateful07:stateful": {
+ "lsp-update-capability": true,
+ "odl-pcep-ietf-initiated00:initiation": true
+ }
+ }
+ },
+ "node-id": "pcc://$IP"
+ }
+ ],
+ "topology-id": "pcep-topology",
+ "topology-types": {
+ "network-topology-pcep:topology-pcep": {}
+ }
+ }
+ ]
+}''')
+ # The _json variables will differ only in $LSPS, but $IP will be present inside.
+ # Thus, the $IP substitution will come last, and any auxiliary substitutions before this final one
+ # will have to use safe_substitute().
+ # As you see, $LSPS is in json_templ without preceding newline.
+ # As a rule, a segment will always start with endline and end without endline,
+ # so that we can add comma where needed.
+ # Discussion amout delegated and instantiated implies that $LSPS is either a single delegated LSP
+ # or a pair of delegated and instantiated (separated by comma) LSPS, in appropriate state.
+ # Of course, one LSP always follow a structure, for which here is the template:
+ lsp_templ = Template('''
+ {
+ "name": "$NAME",
+ "path": [
+ {
+ "ero": {
+ "ignore": false,
+ "processing-rule": false,
+ "subobject": [$HOPS
+ ]
+ },
+ "lsp-id": $ID,
+ "odl-pcep-ietf-stateful07:lsp": {
+ "administrative": true,
+ "delegate": true,
+ "ignore": false,
+ "odl-pcep-ietf-initiated00:create": false,
+ "operational": "up",
+ "plsp-id": $ID,
+ "processing-rule": false,
+ "remove": false,
+ "sync": true,
+ "tlvs": {
+ "lsp-identifiers": {
+ "ipv4": {
+ "ipv4-extended-tunnel-id": "$IP",
+ "ipv4-tunnel-endpoint-address": "1.1.1.1",
+ "ipv4-tunnel-sender-address": "$IP"
+ },
+ "lsp-id": $ID,
+ "tunnel-id": $ID
+ },
+ "symbolic-path-name": {
+ "path-name": "$CODE"
+ }
+ }
+ }
+ }
+ ]
+ }''')
+ # IDs were already talked about, IP will be set last. Now, $NAME.
+ # Pcc-mock uses a fixed naming scheme for delegated tunnels, so one more template can be written,
+ # but it is so simple we can write just the one-line code instead:
+ delegated_name = 'pcc_' + mininet_ip + '_tunnel_1' # 1 == ID
+ # For the instantiated tunnel, user is free to specify anything, even charachers such as \u0000 work.
+ # But as we need to plug the name to XML, let us try something more friendly:
+ instantiated_name = 'Instantiated tunnel' # the space is only somewhat evil character :)
+ # What is CODE? The NAME in base64 encoding (without endline):
+ delegated_code = binascii.b2a_base64(delegated_name)[:-1] # remove endline added by the library function
+ instantiated_code = binascii.b2a_base64(instantiated_name)[:-1]
+ # The remaining segment is HOPS, and that is the place where default and updated states differ.
+ # Once gain, there is a template for a single hop:
+ hop_templ = Template('''
+ {
+ "ip-prefix": {
+ "ip-prefix": "$HOPIP/32"
+ },
+ "loose": false
+ }''')
+ # The low-to-high part of V comes now, it is just substituting and concatenating.
+ # Hops:
+ final_hop = hop_templ.substitute({'HOPIP': '1.1.1.1'})
+ update_hop = hop_templ.substitute({'HOPIP': '2.2.2.2'})
+ both_hops = update_hop + ',' + final_hop
+ # Lsps:
+ default_lsp_templ = Template(lsp_templ.safe_substitute({'HOPS': final_hop}))
+ updated_lsp_templ = Template(lsp_templ.safe_substitute({'HOPS': both_hops}))
+ repl_dict = {'NAME': delegated_name, 'ID': '1', 'CODE': delegated_code}
+ delegated_default_lsp = default_lsp_templ.safe_substitute(repl_dict)
+ delegated_updated_lsp = updated_lsp_templ.safe_substitute(repl_dict)
+ repl_dict = {'NAME': instantiated_name, 'ID': '2', 'CODE': instantiated_code}
+ instantiated_default_lsp = default_lsp_templ.safe_substitute(repl_dict)
+ instantiated_updated_lsp = updated_lsp_templ.safe_substitute(repl_dict)
+ # Json templates (without IP set).
+ repl_dict = {'LSPS': delegated_default_lsp}
+ default_json_templ = Template(json_templ.safe_substitute(repl_dict))
+ repl_dict = {'LSPS': delegated_updated_lsp}
+ updated_json_templ = Template(json_templ.safe_substitute(repl_dict))
+ repl_dict = {'LSPS': delegated_updated_lsp + ',' + instantiated_default_lsp}
+ updated_default_json_templ = Template(json_templ.safe_substitute(repl_dict))
+ repl_dict = {'LSPS': delegated_updated_lsp + ',' + instantiated_updated_lsp}
+ updated_updated_json_templ = Template(json_templ.safe_substitute(repl_dict))
+ # Final json variables.
+ repl_dict = {'IP': mininet_ip}
+ variables['default_json'] = default_json_templ.substitute(repl_dict)
+ variables['updated_json'] = updated_json_templ.substitute(repl_dict)
+ variables['updated_default_json'] = updated_default_json_templ.substitute(repl_dict)
+ variables['updated_updated_json'] = updated_updated_json_templ.substitute(repl_dict)
+ # ### Pcep operations XML data.
+ # There are three operations, so let us just write templates from information at
+ # 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
+ # _xml describes content type and also distinguishes from similarly named _json strings.
+ add_xml_templ = Template('''<input xmlns="urn:opendaylight:params:xml:ns:yang:topology:pcep">
+ <node>pcc://$IP</node>
+ <name>$NAME</name>
+ <network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">/topo:network-topology/topo:topology'''
+ + '''[topo:topology-id="pcep-topology"]</network-topology-ref>
+ <arguments>
+ <lsp xmlns="urn:opendaylight:params:xml:ns:yang:pcep:ietf:stateful">
+ <delegate>true</delegate>
+ <administrative>true</administrative>
+ </lsp>
+ <endpoints-obj>
+ <ipv4>
+ <source-ipv4-address>$IP</source-ipv4-address>
+ <destination-ipv4-address>1.1.1.1</destination-ipv4-address>
+ </ipv4>
+ </endpoints-obj>
+ <ero>
+ <subobject>
+ <loose>false</loose>
+ <ip-prefix><ip-prefix>1.1.1.1/32</ip-prefix></ip-prefix>
+ </subobject>
+ </ero>
+ </arguments>
+</input>''')
+ update_xml_templ = Template('''<input xmlns="urn:opendaylight:params:xml:ns:yang:topology:pcep">
+ <node>pcc://$IP</node>
+ <name>$NAME</name>
+ <network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">/topo:network-topology/topo:topology'''
+ + '''[topo:topology-id="pcep-topology"]</network-topology-ref>
+ <arguments>
+ <lsp xmlns="urn:opendaylight:params:xml:ns:yang:pcep:ietf:stateful">
+ <delegate>true</delegate>
+ <administrative>true</administrative>
+ </lsp>
+ <ero>
+ <subobject>
+ <loose>false</loose>
+ <ip-prefix><ip-prefix>2.2.2.2/32</ip-prefix></ip-prefix>
+ </subobject>
+ <subobject>
+ <loose>false</loose>
+ <ip-prefix><ip-prefix>1.1.1.1/32</ip-prefix></ip-prefix>
+ </subobject>
+ </ero>
+ </arguments>
+</input>''')
+ remove_xml_templ = Template('''<input xmlns="urn:opendaylight:params:xml:ns:yang:topology:pcep">
+ <node>pcc://$IP</node>
+ <name>$NAME</name>
+ <network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">/topo:network-topology/topo:topology'''
+ + '''[topo:topology-id="pcep-topology"]</network-topology-ref>
+</input>''')
+ # The operations can be applied to either delegated or instantiated tunnel, NAME is the only distinguishing value.
+ # Also, the final IP substitution can be done here.
+ repl_dict = {'IP': mininet_ip}
+ repl_dict['NAME'] = delegated_name
+ variables['update_delegated_xml'] = update_xml_templ.substitute(repl_dict)
+ variables['remove_delegated_xml'] = remove_xml_templ.substitute(repl_dict)
+ repl_dict['NAME'] = instantiated_name
+ variables['add_instantiated_xml'] = add_xml_templ.substitute(repl_dict)
+ variables['update_instantiated_xml'] = update_xml_templ.substitute(repl_dict)
+ variables['remove_instantiated_xml'] = remove_xml_templ.substitute(repl_dict)
+ # All variables ready.
+ return variables
--- /dev/null
+"""
+Variables file for tcpmd5user suite.
+
+Expected JSON templates are fairly long,
+therefore there are moved out of testcase file.
+Also, it is needed to generate base64 encoded tunnel name
+from Mininet IP (which is not known beforehand),
+so it is easier to employ Python here,
+than do manipulation in Robot file.
+"""
+# Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+__author__ = "Vratko Polak"
+__copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
+__license__ = "Eclipse Public License v1.0"
+__email__ = "vrpolak@cisco.com"
+
+import binascii
+from string import Template
+
+
+# FIXME: Migrate values shared by other suites to separate Python module.
+
+def get_variables(mininet_ip):
+ """Return dict of variables for the given IPv4 address of Mininet VM."""
+ # TODO: Document in 'V' fashion, as in pcepuser/variables.py using more systematic local variable names.
+ # Dict of variables to return, starts empty and grows as function proceeds.
+ variables = {}
+ # Given mininet_ip, this will be the sympolic name uf tunnel under test.
+ tunnelname = 'pcc_' + mininet_ip + '_tunnel_1'
+ # Base64 code for the symbolic name, as that is present in datastore.
+ pathcode = binascii.b2a_base64(tunnelname)[:-1] # remove endline
+ # JSON response when pcep-topology is ready but no PCC is connected.
+ variables['offjson'] = '''{
+ "topology": [
+ {
+ "topology-id": "pcep-topology",
+ "topology-types": {
+ "network-topology-pcep:topology-pcep": {}
+ }
+ }
+ ]
+}'''
+ # Template of JSON response with pcep-topology seeing 1 PCC 1 LSP.
+ onjsontempl = Template('''{
+ "topology": [
+ {
+ "node": [
+ {
+ "network-topology-pcep:path-computation-client": {
+ "ip-address": "$IP",
+ "reported-lsp": [
+ {
+ "name": "$NAME",
+ "path": [
+ {
+ "ero": {
+ "ignore": false,
+ "processing-rule": false,
+ "subobject": [
+ {
+ "ip-prefix": {
+ "ip-prefix": "1.1.1.1/32"
+ },
+ "loose": false
+ }
+ ]
+ },
+ "lsp-id": 1,
+ "odl-pcep-ietf-stateful07:lsp": {
+ "administrative": true,
+ "delegate": true,
+ "ignore": false,
+ "odl-pcep-ietf-initiated00:create": false,
+ "operational": "up",
+ "plsp-id": 1,
+ "processing-rule": false,
+ "remove": false,
+ "sync": true,
+ "tlvs": {
+ "lsp-identifiers": {
+ "ipv4": {
+ "ipv4-extended-tunnel-id": "$IP",
+ "ipv4-tunnel-endpoint-address": "1.1.1.1",
+ "ipv4-tunnel-sender-address": "$IP"
+ },
+ "lsp-id": 1,
+ "tunnel-id": 1
+ },
+ "symbolic-path-name": {
+ "path-name": "$CODE"
+ }
+ }
+ }
+ }
+ ]
+ }
+ ],
+ "state-sync": "synchronized",
+ "stateful-tlv": {
+ "odl-pcep-ietf-stateful07:stateful": {
+ "lsp-update-capability": true,
+ "odl-pcep-ietf-initiated00:initiation": true
+ }
+ }
+ },
+ "node-id": "pcc://$IP"
+ }
+ ],
+ "topology-id": "pcep-topology",
+ "topology-types": {
+ "network-topology-pcep:topology-pcep": {}
+ }
+ }
+ ]
+}''')
+ # Dictionly which tells values for placeholders.
+ repl_dict = {'IP': mininet_ip, 'NAME': tunnelname, 'CODE': pathcode}
+ # The finalized JSON.
+ variables['onjson'] = onjsontempl.substitute(repl_dict)
+ # The following strings are XML data.
+ # See https://wiki.opendaylight.org/view/BGP_LS_PCEP:TCP_MD5_Guide#RESTCONF_Configuration
+ # For curl, string is suitable to became -d argument only after
+ # replacing ' -> '"'"' and enclosing in single quotes.
+ variables['key_access_module'] = '''<module xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:jni:cfg">x:native-key-access-factory</type>
+ <name>global-key-access-factory</name>
+</module>'''
+ variables['key_access_service'] = '''<service xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:cfg">x:key-access-factory</type>
+ <instance>
+ <name>global-key-access-factory</name>
+ <provider>/modules/module[type='native-key-access-factory'][name='global-key-access-factory']</provider>
+ </instance>
+</service>'''
+ variables['client_channel_module'] = '''<module xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:netty:cfg">x:md5-client-channel-factory</type>
+ <name>md5-client-channel-factory</name>
+ <key-access-factory xmlns="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:netty:cfg">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:cfg">x:key-access-factory</type>
+ <name>global-key-access-factory</name>
+ </key-access-factory>
+</module>'''
+ variables['client_channel_service'] = '''<service xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:netty:cfg">x:md5-channel-factory</type>
+ <instance>
+ <name>md5-client-channel-factory</name>
+ <provider>/modules/module[type='md5-client-channel-factory'][name='md5-client-channel-factory']</provider>
+ </instance>
+</service>'''
+ variables['server_channel_module'] = '''<module xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:netty:cfg">'''
+ # What is your favourite way to concatenate strings without resembling tuple?
+ variables['server_channel_module'] += '''prefix:md5-server-channel-factory-impl</type>
+ <name>md5-server-channel-factory</name>
+ <server-key-access-factory xmlns="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:netty:cfg">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:cfg">x:key-access-factory</type>
+ <name>global-key-access-factory</name>
+ </server-key-access-factory>
+</module>'''
+ variables['server_channel_service'] = '''<service xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:netty:cfg">'''
+ variables['server_channel_service'] += '''prefix:md5-server-channel-factory</type>
+ <instance>
+ <name>md5-server-channel-factory</name>
+ <provider>/modules/module[type='md5-server-channel-factory-impl'][name='md5-server-channel-factory']</provider>
+ </instance>
+</service>'''
+ variables['pcep_dispatcher_module'] = '''<module xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:pcep:impl">x:pcep-dispatcher-impl</type>
+ <name>global-pcep-dispatcher</name>
+ <md5-channel-factory xmlns="urn:opendaylight:params:xml:ns:yang:controller:pcep:impl">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:netty:cfg">x:md5-channel-factory</type>
+ <name>md5-client-channel-factory</name>
+ </md5-channel-factory>
+ <md5-server-channel-factory xmlns="urn:opendaylight:params:xml:ns:yang:controller:pcep:impl">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:tcpmd5:netty:cfg">x:md5-server-channel-factory</type>
+ <name>md5-server-channel-factory</name>
+ </md5-server-channel-factory>
+</module>'''
+ # Template to set password.
+ passwd_templ = Template('''<module xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <type xmlns:x="urn:opendaylight:params:xml:ns:yang:controller:pcep:topology:provider">x:pcep-topology-provider</type>
+ <name>pcep-topology</name>
+ <client xmlns="urn:opendaylight:params:xml:ns:yang:controller:pcep:topology:provider">
+ <address xmlns="urn:opendaylight:params:xml:ns:yang:controller:pcep:topology:provider">$IP</address>
+$PASSWD </client>
+</module>''')
+ # We use three template instantiations. No password:
+ repl_dict = {'IP': mininet_ip, 'PASSWD': ''}
+ variables['no_passwd_module'] = passwd_templ.substitute(repl_dict)
+ changeme = ''' <password>changeme</password>
+'''
+ # wrong password
+ repl_dict = {'IP': mininet_ip, 'PASSWD': changeme}
+ variables['passwd_changeme_module'] = passwd_templ.substitute(repl_dict)
+ # and correct password.
+ topsecret = ''' <password>topsecret</password>
+'''
+ repl_dict = {'IP': mininet_ip, 'PASSWD': topsecret}
+ variables['passwd_topsecret_module'] = passwd_templ.substitute(repl_dict)
+ # All variables set, return dict to Robot.
+ return variables