Suite for TCPMD5 added, suite for PCEP expanded.
authorVratko Polak <vrpolak@cisco.com>
Wed, 22 Apr 2015 17:05:57 +0000 (19:05 +0200)
committerVratko Polak <vrpolak@cisco.com>
Fri, 24 Apr 2015 18:46:49 +0000 (20:46 +0200)
The TCPMD5 suite covers entirety of
https://wiki.opendaylight.org/view/TCPMD5:Lithium_Feature_Tests#How_to_test

Notable library (Robot Resource file in fact) is introduced:
ConfigViaRestconf, which simplifies the task of overriding
config-subsystem state at runtime using restconf, at least for XML data.
Tcpmd5-specific config data is present in variables file.

Testplan is included, which in future would run
all suites needed for testing user-facing karaf features
of BGPCEP and TCPMD5 projects.

Also, clone of basicpcep is added, named pcepuser.
The reason is that the new name is more natural
for the new testplan contents, but we do not want to break
existing jobs using basicpcep suite right now.

+ Pcep variables file contains comments, helpful and structured.
+ Resource (library) for PCEP operations added.
+ The pcepuser suite now covers the entire
https://wiki.opendaylight.org/view/BGP_LS_PCEP:Lithium_Feature_Tests#How_to_test

+ pep8 compliant
+ applied: python -m robot.tidy --inplace
+ ${RESTCONFPORT} and ${NEXUSURL_PREFIX} used
- ConfigViaRestconf keywords for JSON data are not implemented at all
- Quality of tcpmd5 variables file is somewhat lacking

Change-Id: I94e77d2effef77f7bf8c23d4bc61f2ceeeb3a034
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
test/csit/libraries/ConfigViaRestconf.robot [new file with mode: 0644]
test/csit/libraries/PcepOperations.robot [new file with mode: 0644]
test/csit/suites/bgpcep/pcepuser/pcepuser.robot [new file with mode: 0644]
test/csit/suites/bgpcep/tcpmd5user/tcpmd5user.robot [new file with mode: 0644]
test/csit/testplans/bgpcep-userfeatures.txt [new file with mode: 0644]
test/csit/variables/pcepuser/variables.py [new file with mode: 0644]
test/csit/variables/tcpmd5user/variables.py [new file with mode: 0644]

diff --git a/test/csit/libraries/ConfigViaRestconf.robot b/test/csit/libraries/ConfigViaRestconf.robot
new file mode 100644 (file)
index 0000000..0b9b347
--- /dev/null
@@ -0,0 +1,40 @@
+*** 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
diff --git a/test/csit/libraries/PcepOperations.robot b/test/csit/libraries/PcepOperations.robot
new file mode 100644 (file)
index 0000000..15226b6
--- /dev/null
@@ -0,0 +1,60 @@
+*** 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"}}
diff --git a/test/csit/suites/bgpcep/pcepuser/pcepuser.robot b/test/csit/suites/bgpcep/pcepuser/pcepuser.robot
new file mode 100644 (file)
index 0000000..5022e43
--- /dev/null
@@ -0,0 +1,162 @@
+*** 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
diff --git a/test/csit/suites/bgpcep/tcpmd5user/tcpmd5user.robot b/test/csit/suites/bgpcep/tcpmd5user/tcpmd5user.robot
new file mode 100644 (file)
index 0000000..243a805
--- /dev/null
@@ -0,0 +1,180 @@
+*** 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
diff --git a/test/csit/testplans/bgpcep-userfeatures.txt b/test/csit/testplans/bgpcep-userfeatures.txt
new file mode 100644 (file)
index 0000000..388c177
--- /dev/null
@@ -0,0 +1,4 @@
+# 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
diff --git a/test/csit/variables/pcepuser/variables.py b/test/csit/variables/pcepuser/variables.py
new file mode 100644 (file)
index 0000000..302fb00
--- /dev/null
@@ -0,0 +1,243 @@
+"""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
diff --git a/test/csit/variables/tcpmd5user/variables.py b/test/csit/variables/tcpmd5user/variables.py
new file mode 100644 (file)
index 0000000..02770a6
--- /dev/null
@@ -0,0 +1,207 @@
+"""
+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