SSHLibrary.Put_Directory ${schemas} destination=./schemas
[Return] --schemas-dir ./schemas
+NetconfKeywords__Deploy_Custom_RPC
+ [Arguments] ${rpc_config}
+ [Documentation] Internal keyword for Install_And_Start_TestTool
+ ... This deploys the optional custom rpc file.
+ ... Drop out of the keyword, returning no command line argument when there
+ ... is no rpc file to deploy.
+ BuiltIn.Return_From_Keyword_If '${rpc_config}' == 'none' ${EMPTY}
+ SSHKeywords.Copy_File_To_Tools_System ${TOOLS_SYSTEM_1_IP} ${rpc_config} /tmp
+ [Return] --rpc-config /tmp/customaction.xml
+
NetconfKeywords__Check_Device_Is_Up
[Arguments] ${last-port}
${count}= SSHKeywords.Count_Port_Occurences ${last-port} LISTEN java
BuiltIn.Wait_Until_Keyword_Succeeds ${TESTTOOL_BOOT_TIMEOUT} 1s Check_Device_Up_And_Running ${number}
Install_And_Start_Testtool
- [Arguments] ${device-count}=10 ${debug}=true ${schemas}=none ${tool_options}=${EMPTY} ${java_options}=${TESTTOOL_DEFAULT_JAVA_OPTIONS} ${mdsal}=true
+ [Arguments] ${device-count}=10 ${debug}=true ${schemas}=none ${rpc_config}=none ${tool_options}=${EMPTY} ${java_options}=${TESTTOOL_DEFAULT_JAVA_OPTIONS}
+ ... ${mdsal}=true
[Documentation] Install and run testtool.
${filename}= NexusKeywords.Deploy_Test_Tool netconf netconf-testtool
- Start_Testtool ${filename} ${device-count} ${debug} ${schemas} ${tool_options} ${java_options}
- ... ${mdsal}
+ Start_Testtool ${filename} ${device-count} ${debug} ${schemas} ${rpc_config} ${tool_options}
+ ... ${java_options} ${mdsal}
Start_Testtool
- [Arguments] ${filename} ${device-count}=10 ${debug}=true ${schemas}=none ${tool_options}=${EMPTY} ${java_options}=${TESTTOOL_DEFAULT_JAVA_OPTIONS}
- ... ${mdsal}=true
+ [Arguments] ${filename} ${device-count}=10 ${debug}=true ${schemas}=none ${rpc_config}=none ${tool_options}=${EMPTY}
+ ... ${java_options}=${TESTTOOL_DEFAULT_JAVA_OPTIONS} ${mdsal}=true
[Documentation] Arrange to collect tool's output into a log file.
... Will use specific ${schemas} unless argument resolves to 'none',
... which signifies that there are no additional schemas to be deployed.
... If so the directory for the additional schemas is deleted on the
... remote machine and the additional schemas argument is left out.
${schemas_option}= NetconfKeywords__Deploy_Additional_Schemas ${schemas}
- ${command}= NexusKeywords.Compose_Full_Java_Command ${java_options} -jar ${filename} ${tool_options} --device-count ${device-count} --debug ${debug} ${schemas_option} --md-sal ${mdsal}
+ ${rpc_config_option}= NetconfKeywords__Deploy_Custom_RPC ${rpc_config}
+ ${command}= NexusKeywords.Compose_Full_Java_Command ${java_options} -jar ${filename} ${tool_options} --device-count ${device-count} --debug ${debug} ${schemas_option} ${rpc_config_option} --md-sal ${mdsal}
BuiltIn.Log Running testtool: ${command}
${logfile}= Utils.Get_Log_File_Name testtool
BuiltIn.Set_Suite_Variable ${testtool_log} ${logfile}
BuiltIn.Run_Keyword_If ${verify} Verify_Response_As_Json_Templated response=${response_text} folder=${folder} base_name=response mapping=${mapping}
[Return] ${response_text}
+Post_As_Json_Rfc8040_Templated
+ [Arguments] ${folder} ${mapping}={} ${session}=default ${verify}=False ${iterations}=${EMPTY} ${iter_start}=1
+ ... ${additional_allowed_status_codes}=${NO_STATUS_CODES} ${explicit_status_codes}=${NO_STATUS_CODES} ${http_timeout}=${EMPTY}
+ [Documentation] Add arguments sensible for JSON data, return Post_Templated response text.
+ ... Optionally, verification against response.json (no iteration) is called.
+ ... Only subset of JSON data is verified and returned if JMES path is specified in
+ ... file ${folder}${/}jmespath.expr.
+ ... Response status code must be one of values from ${explicit_status_codes} if specified or one of set
+ ... created from all positive HTTP status codes together with ${additional_allowed_status_codes}.
+ ... RFC8040 defines RESTCONF protocol, for configuring data defined in YANG version 1
+ ... or YANG version 1.1, using the datastore concepts defined in NETCONF.
+ ${response_text} = Post_Templated folder=${folder} base_name=data extension=json accept=${ACCEPT_EMPTY} content_type=${HEADERS_YANG_RFC8040_JSON}
+ ... mapping=${mapping} session=${session} normalize_json=True endline=${\n} iterations=${iterations} iter_start=${iter_start}
+ ... additional_allowed_status_codes=${additional_allowed_status_codes} explicit_status_codes=${explicit_status_codes} http_timeout=${http_timeout}
+ BuiltIn.Run_Keyword_If ${verify} Verify_Response_As_Json_Templated response=${response_text} folder=${folder} base_name=response mapping=${mapping}
+ [Return] ${response_text}
+
Post_As_Xml_Templated
[Arguments] ${folder} ${mapping}={} ${session}=default ${verify}=False ${iterations}=${EMPTY} ${iter_start}=1
... ${additional_allowed_status_codes}=${NO_STATUS_CODES} ${explicit_status_codes}=${NO_STATUS_CODES} ${http_timeout}=${EMPTY}
--- /dev/null
+*** Settings ***
+Documentation netconf-connector CRUD-Action test suite.
+...
+... Copyright (c) 2019 Ericsson Software Technology AB. 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
+...
+...
+... Perform basic operations (Create, Read, Update and Delete or CRUD) on device
+... data mounted onto a netconf connector using RPC for node supporting Yang 1.1
+... addition and see if invoking Action Operation work.
+Suite Setup Setup_Everything
+Suite Teardown Teardown_Everything
+Test Setup SetupUtils.Setup_Test_With_Logging_And_Without_Fast_Failing
+Library Collections
+Library RequestsLibrary
+Library OperatingSystem
+Library String
+Library SSHLibrary timeout=10s
+Resource ${CURDIR}/../../../libraries/CompareStream.robot
+Resource ${CURDIR}/../../../libraries/FailFast.robot
+Resource ${CURDIR}/../../../libraries/NetconfKeywords.robot
+Resource ${CURDIR}/../../../libraries/SetupUtils.robot
+Resource ${CURDIR}/../../../libraries/TemplatedRequests.robot
+Resource ${CURDIR}/../../../variables/Variables.robot
+
+*** Variables ***
+${DIRECTORY_WITH_TEMPLATE_FOLDERS} ${CURDIR}/../../../variables/netconf/CRUD
+${DEVICE_NAME} netconf-test-device
+${DEVICE_TYPE_RPC} rpc-device
+${DEVICE_TYPE_RPC_CREATE} rpc-create-device
+${DEVICE_TYPE_RPC_DELETE} rpc-delete-device
+${USE_NETCONF_CONNECTOR} ${False}
+${DELETE_LOCATION} delete_location
+${RPC_FILE} ${CURDIR}/../../../variables/netconf/CRUD/customaction/customaction.xml
+
+*** Test Cases ***
+Check_Device_Is_Not_Configured_At_Beginning
+ [Documentation] Sanity check making sure our device is not there. Fail if found.
+ [Tags] critical
+ NetconfKeywords.Check_Device_Has_No_Netconf_Connector ${DEVICE_NAME}
+
+Configure_Device_On_Netconf
+ [Documentation] Make request to configure a testtool device on Netconf connector.
+ [Tags] critical
+ NetconfKeywords.Configure_Device_In_Netconf ${DEVICE_NAME} device_type=${DEVICE_TYPE} http_timeout=2 http_method=post
+
+Check_ODL_Has_Netconf_Connector_For_Device
+ [Documentation] Get the list of configured devices and search for our device there. Fail if not found.
+ [Tags] critical
+ ${count} = NetconfKeywords.Count_Netconf_Connectors_For_Device ${DEVICE_NAME}
+ Builtin.Should_Be_Equal_As_Strings ${count} 1
+
+Wait_For_Device_To_Become_Connected
+ [Documentation] Wait until the device becomes available through Netconf.
+ NetconfKeywords.Wait_Device_Connected ${DEVICE_NAME}
+
+Check_Device_Data_Is_Empty
+ [Documentation] Get the device data and make sure it is empty.
+ Run_Keyword_If_Less_Than_Neon Check_Config_Data <data xmlns\="${ODL_NETCONF_NAMESPACE}"></data>
+ Run_Keyword_If_At_Least_Neon Check_Config_Data <data xmlns\="${ODL_NETCONF_NAMESPACE}"/>
+
+Invoke_Yang1.1_Action_Via_Xml_Post
+ [Documentation] Send a sample test data label into the device and check that the request went OK.
+ ${template_as_string} = BuiltIn.Set_Variable {'DEVICE_NAME': '${DEVICE_NAME}'}
+ TemplatedRequests.Post_As_Xml_Templated ${DIRECTORY_WITH_TEMPLATE_FOLDERS}${/}dataorigaction ${template_as_string}
+
+Invoke_Yang1.1_Action_Via_Json_Post
+ [Documentation] Send a sample test data label into the device and check that the request went OK.
+ ${template_as_string} = BuiltIn.Set_Variable {'DEVICE_NAME': '${DEVICE_NAME}'}
+ TemplatedRequests.Post_As_Json_RFC8040_Templated ${DIRECTORY_WITH_TEMPLATE_FOLDERS}${/}dataorigaction ${template_as_string}
+
+Deconfigure_Device_From_Netconf
+ [Documentation] Make request to deconfigure the testtool device on Netconf connector.
+ [Tags] critical
+ [Setup] SetupUtils.Setup_Test_With_Logging_And_Without_Fast_Failing
+ CompareStream.Run_Keyword_If_At_Most_Nitrogen NetconfKeywords.Remove_Device_From_Netconf ${DEVICE_NAME} location=${DELETE_LOCATION}
+ CompareStream.Run_Keyword_If_At_Least_Oxygen NetconfKeywords.Configure_Device_In_Netconf ${DEVICE_NAME} device_type=${DEVICE_TYPE_RPC_DELETE} http_timeout=2 http_method=post
+
+Check_Device_Going_To_Be_Gone_After_Deconfiguring
+ [Documentation] Check that the device is really going to be gone. Fail
+ ... if found after one minute. This is an expected behavior as the
+ ... delete request is sent to the config subsystem which then triggers
+ ... asynchronous destruction of the netconf connector referring to the
+ ... device and the device's data. This test makes sure this
+ ... asynchronous operation does not take unreasonable amount of time
+ ... by making sure that both the netconf connector and the device's
+ ... data is gone before reporting success.
+ [Tags] critical
+ NetconfKeywords.Wait_Device_Fully_Removed ${DEVICE_NAME}
+
+*** Keywords ***
+Setup_Everything
+ [Documentation] Initialize SetupUtils. Setup everything needed for the test cases.
+ SetupUtils.Setup_Utils_For_Setup_And_Teardown
+ RequestsLibrary.Create_Session operational http://${ODL_SYSTEM_IP}:${RESTCONFPORT}${OPERATIONAL_API} auth=${AUTH}
+ NetconfKeywords.Setup_Netconf_Keywords
+ ${DEVICE_TYPE_RPC} = BuiltIn.Set_Variable_If """${USE_NETCONF_CONNECTOR}""" == """True""" default ${DEVICE_TYPE_RPC}
+ ${DEVICE_TYPE} = CompareStream.Set_Variable_If_At_Most_Nitrogen ${DEVICE_TYPE_RPC} ${DEVICE_TYPE_RPC_CREATE}
+ BuiltIn.Set_Suite_Variable ${DEVICE_TYPE}
+ OperatingSystem.File Should Exist ${RPC_FILE}
+ NetconfKeywords.Install_And_Start_Testtool device-count=1 schemas=${CURDIR}/../../../variables/netconf/CRUD/schemas rpc_config=${RPC_FILE}
+
+Teardown_Everything
+ [Documentation] Teardown the test infrastructure, perform cleanup and release all resources.
+ RequestsLibrary.Delete_All_Sessions
+ BuiltIn.Run_Keyword_And_Ignore_Error NetconfKeywords.Stop_Testtool
+
+Get_Config_Data
+ [Documentation] Get and return the config data from the device.
+ ${url} = Builtin.Set_Variable ${CONFIG_API}/network-topology:network-topology/topology/topology-netconf/node/${DEVICE_NAME}/yang-ext:mount
+ ${data} = TemplatedRequests.Get_As_Xml_From_Uri ${url}
+ [Return] ${data}
+
+Check_Config_Data
+ [Arguments] ${expected} ${contains}=False
+ ${data} = Get_Config_Data
+ BuiltIn.Run_Keyword_Unless ${contains} BuiltIn.Should_Be_Equal_As_Strings ${data} ${expected}
+ BuiltIn.Run_Keyword_If ${contains} BuiltIn.Should_Contain ${data} ${expected}
--- /dev/null
+# Place the suites in run order:
+integration/test/csit/suites/netconf/ready
+integration/test/csit/suites/netconf/apidocs
+integration/test/csit/suites/netconf/MDSAL
+integration/test/csit/suites/netconf/CRUD
+integration/test/csit/suites/netconf/CRUD-ACTION
+integration/test/csit/suites/netconf/notifications
+integration/test/csit/suites/netconf/KeyAuth
+
--- /dev/null
+# Place the suites in run order:
+integration/test/csit/suites/netconf/ready
+integration/test/csit/suites/netconf/apidocs
+integration/test/csit/suites/netconf/MDSAL
+integration/test/csit/suites/netconf/CRUD
+integration/test/csit/suites/netconf/CRUD-ACTION
+integration/test/csit/suites/netconf/notifications
+integration/test/csit/suites/netconf/KeyAuth
+
${GET_INTENTS_URI} /retconf/config/intent:intents # FIXME: Move to a separate Nemo-related Resource and add description.
&{HEADERS} Content-Type=application/json # Deprecated. Sometimes conflicts with argument name. TODO: Migrate most suites to TemplatedRequests, then chose a more descriptive name.
&{HEADERS_YANG_JSON} Content-Type=application/yang.data+json # Content type for JSON data, used to work around Requests auto-serialization. TODO: Hide into more specific Resource if possible.
+&{HEADERS_YANG_RFC8040_JSON} Content-Type=application/yang-data+json
&{HEADERS_XML} Content-Type=application/xml # Content type for XML data. TODO: Hide into more specific Resource if possible.
${KARAF_PROMPT_LOGIN} opendaylight-user # This is used for karaf console login.
${ICMP_TYPE} 135
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<rpcs>
+ <rpc>
+ <input>
+ <action xmlns="urn:ietf:params:xml:ns:yang:1">
+ <interfaces xmlns="https://example.com/ns/example-action">
+ <interface>
+ <name>eth1</name>
+ <reset>
+ <delay>600</delay>
+ </reset>
+ </interface>
+ </interfaces>
+ </action>
+ </input>
+ <output>
+ <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:sys="https://example.com/ns/example-action">
+ <ok />
+ </rpc-reply>
+ </output>
+ </rpc>
+</rpcs>
+
--- /dev/null
+rests/data/network-topology:network-topology/topology=topology-netconf/node=$DEVICE_NAME/yang-ext:mount/example-action:interfaces/interface=eth1/reset
--- /dev/null
+{
+ "example-action:input":{
+ "delay":600
+ }
+}
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<input xmlns="https://example.com/ns/example-action">
+ <delay>600</delay>
+</input>
+
--- /dev/null
+module example-action {
+ yang-version 1.1;
+ namespace "https://example.com/ns/example-action";
+ prefix act;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ organization
+ "Example, Inc.";
+ contact
+ "support at example.com";
+ description
+ "Example Actions Data Model Module.";
+
+ revision 2016-07-07 {
+ description
+ "Initial version.";
+ reference
+ "example.com document 2-9973.";
+ }
+
+ container interfaces {
+ description
+ "System interfaces.";
+ list interface {
+ key "name";
+ description
+ "One interface entry.";
+ leaf name {
+ type string;
+ description
+ "Interface name.";
+ }
+
+ action reset {
+ description
+ "Reset an interface.";
+ input {
+ leaf delay {
+ type uint32;
+ units "seconds";
+ default "0";
+ description
+ "Number of seconds to wait before starting the
+ interface reset.";
+ }
+ }
+ }
+
+ action get-last-reset-time {
+ description
+ "Retrieve the last interface reset time.";
+
+ output {
+ leaf last-reset {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "Date and time of the last interface reset, or
+ the last reboot time of the device.";
+ }
+ }
+ }
+ }
+ }
+ rpc reboot {
+ description "Reboot operation.";
+ input {
+ leaf delay {
+ type uint32;
+ units "seconds";
+ default 0;
+ description "Number of seconds to wait before initiating the reboot operation.";
+ }
+ leaf message {
+ type string;
+ description "Log message to display when reboot is started.";
+ }
+ leaf language {
+ type string;
+ description "Language identifier string.";
+ reference "RFC 5646.";
+ }
+ }
+ }
+}
+