CallHome Tests First draft. 82/52982/37
authorajaychhabria <ajay1005@gmail.com>
Mon, 17 Apr 2017 23:45:23 +0000 (23:45 +0000)
committerLuis Gomez <ecelgp@gmail.com>
Tue, 18 Apr 2017 00:34:32 +0000 (00:34 +0000)
Change-Id: I5fae3a5dfff79ff61657bf02933f1f9933b47329
Signed-off-by: ajaychhabria <ajay1005@gmail.com>
csit/libraries/NetconfCallHome.robot [new file with mode: 0644]
csit/suites/netconf/callhome/callhome.robot [new file with mode: 0644]
csit/testplans/netconf-callhome.txt [new file with mode: 0644]
csit/variables/netconf/callhome/credentials_set.sh [new file with mode: 0755]
csit/variables/netconf/callhome/datastore-server.xml [new file with mode: 0644]
csit/variables/netconf/callhome/docker-compose.yaml [new file with mode: 0644]
csit/variables/netconf/callhome/whitelist_add.sh [new file with mode: 0755]

diff --git a/csit/libraries/NetconfCallHome.robot b/csit/libraries/NetconfCallHome.robot
new file mode 100644 (file)
index 0000000..a5d120a
--- /dev/null
@@ -0,0 +1,82 @@
+*** Settings ***
+Library           SSHLibrary
+Library           RequestsLibrary
+Resource          SSHKeywords.robot
+Resource          ../variables/Variables.robot
+
+*** Variables ***
+${mount_point_url}    /restconf/operational/network-topology:network-topology/topology/topology-netconf/
+${device_status}    /restconf/operational/odl-netconf-callhome-server:netconf-callhome-server
+${whitelist}      /restconf/config/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices
+${substring1}     "netconf-node-topology:connection-status":"connected"
+${substring2}     "node-id":"netopeer"
+${substring3}     "netconf-node-topology:available-capabilities"
+
+*** Keywords ***
+Check Device status
+    [Arguments]    ${status}    ${id}=netopeer
+    [Documentation]    Checks the operational device status.
+    @{expectedValues}    Create List    "unique-id":"${id}"    "callhome-status:device-status":"${status}"
+    Run Keyword If    '${status}'=='FAILED_NOT_ALLOWED' or '${status}'=='FAILED_AUTH_FAILURE'    Remove Values From List    ${expectedValues}    "unique-id":"${id}"
+    Utils.Check For Elements At URI    ${device_status}    ${expectedValues}
+
+Get Netopeer Ready
+    [Documentation]    Pulls the netopeer image from the docker repository. Points ODL(CallHome Server) IP in the files used by netopeer(CallHome Client).
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker pull sdnhub/netopeer    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker images    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    Reset Docker Compose Configuration
+
+Reset Docker Compose Configuration
+    [Documentation]    Resets the docker compose configurations.
+    SSHLibrary.Put File    ${CURDIR}/../variables/netconf/callhome/docker-compose.yaml    .
+    SSHLibrary.Put File    ${CURDIR}/../variables/netconf/callhome/datastore-server.xml    .
+    SSHLibrary.Execute_Command    sed -i -e 's/ODL_SYSTEM_IP/${ODL_SYSTEM_IP}/g' docker-compose.yaml
+    SSHLibrary.Execute_Command    sed -i -e 's/ODL_SYSTEM_IP/${ODL_SYSTEM_IP}/g' datastore-server.xml
+
+Get Environment Ready
+    [Documentation]    Get the scripts ready to set credentials and control whitelist maintained by the CallHome server.
+    SSHLibrary.Put File    ${CURDIR}/../variables/netconf/callhome/whitelist_add.sh    .
+    SSHLibrary.Put File    ${CURDIR}/../variables/netconf/callhome/credentials_set.sh    .
+    SSHLibrary.Execute_Command    chmod +x whitelist_add.sh
+    SSHLibrary.Execute_Command    chmod +x credentials_set.sh
+    SSHLibrary.Execute_Command    sed -i -e 's/ODL_SYSTEM_IP/${ODL_SYSTEM_IP}/g' credentials_set.sh
+    SSHLibrary.Execute_Command    sed -i -e 's/ODL_SYSTEM_IP/${ODL_SYSTEM_IP}/g' whitelist_add.sh
+
+Install Docker Compose on tools system
+    [Documentation]    Install docker-compose on tools system.
+    ${netopeer_conn_id} =    SSHKeywords.Open_Connection_To_Tools_System
+    Builtin.Set Suite Variable    ${netopeer_conn_id}
+    SSHLibrary.Write    sudo curl -L "https://github.com/docker/compose/releases/download/1.11.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
+    ${output}=    Wait Until Keyword Succeeds    30s    2s    SSHLibrary.Read_Until_Prompt
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    sudo chmod +x /usr/local/bin/docker-compose    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+
+Uninstall Docker Compose on tools system
+    [Documentation]    Uninstall docker-compose on tools system
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    pip uninstall docker-compose    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+
+Suite Teardown
+    [Documentation]    Tearing down the setup.
+    Uninstall Docker Compose on tools system
+    RequestsLibrary.Delete_All_Sessions
+    SSHLibrary.Close_All_Connections
+
+Test Teardown
+    [Documentation]    Tears down the docker running netopeer and deletes entry from the whitelist.
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker-compose down    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker ps -a    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    ${resp} =    RequestsLibrary.Delete_Request    session    ${whitelist}
+
+Suite Setup
+    [Documentation]    Get the suite ready for callhome test cases.
+    RequestsLibrary.Create_Session    session    http://${ODL_SYSTEM_IP}:${RESTCONFPORT}    auth=${AUTH}
+    Install Docker Compose on tools system
+    Get Environment Ready
+    Get Netopeer Ready
+    ${netconf_mount_expected_values}    Create list    ${substring1}    ${substring2}    ${substring3}
+    Set Suite Variable    ${netconf_mount_expected_values}
diff --git a/csit/suites/netconf/callhome/callhome.robot b/csit/suites/netconf/callhome/callhome.robot
new file mode 100644 (file)
index 0000000..113f954
--- /dev/null
@@ -0,0 +1,64 @@
+*** Settings ***
+Documentation     Test suite to verify callhome functionality where the Call Home Server(CONTROLLER) is provisioned with device
+...               certificates when docker-compose is invoked. Every test case does a SED operation to search and replace words
+...               to cover the happy path and negative scenarios.
+Suite Setup       Suite Setup
+Suite Teardown    Suite Teardown
+Test Setup        Reset Docker Compose Configuration
+Test Teardown     Test Teardown
+Resource          ../../../libraries/NetconfCallHome.robot
+
+*** Test Cases ***
+CallHome with Incorrect global Credentials
+    [Documentation]    Incorrect global credentials should result to mount failure. FAILED_AUTH_FAILURE should be the device status.
+    SSHLibrary.Execute_Command    sed -i -e 's/global root/global incorrect/g' docker-compose.yaml
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker-compose up -d    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    Wait Until Keyword Succeeds    30s    2s    NetconfCallHome.Check Device Status    FAILED_AUTH_FAILURE
+    Wait Until Keyword Succeeds    30s    2s    Run Keyword And Expect Error    *    Utils.Check For Elements At URI    ${mount_point_url}
+    ...    ${netconf_mount_expected_values}
+
+CallHome with Incorrect per-device Credentials
+    [Documentation]    Incorrect per-device credentials should result to mount failure. FAILED_AUTH_FAILURE should be the device status.
+    SSHLibrary.Execute_Command    sed -i -e 's/global root/per-device netopeer incorrect/g' docker-compose.yaml
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker-compose up -d    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    Wait Until Keyword Succeeds    30s    2s    NetconfCallHome.Check Device Status    FAILED_AUTH_FAILURE
+    Wait Until Keyword Succeeds    30s    2s    Run Keyword And Expect Error    *    Utils.Check For Elements At URI    ${mount_point_url}
+    ...    ${netconf_mount_expected_values}
+
+CallHome with Incorrect Node-id
+    [Documentation]    CallHome from device that does not have an entry in per-device credential with result to mount point failure.
+    SSHLibrary.Execute_Command    sed -i -e 's/global/per-device incorrect_hostname/g' docker-compose.yaml    return_rc=True
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker-compose up -d    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    Wait Until Keyword Succeeds    30s    2s    NetconfCallHome.Check Device Status    DISCONNECTED
+    Wait Until Keyword Succeeds    30s    2s    Run Keyword And Expect Error    *    Utils.Check For Elements At URI    ${mount_point_url}
+    ...    ${netconf_mount_expected_values}
+
+CallHome with Rogue Devices
+    [Documentation]    A Rogue Device will fail to callhome and wont be able to mount because the keys are not added in whitelist.
+    ...    FAILED_NOT_ALLOWED should be the device status.
+    SSHLibrary.Execute_Command    sed -i -e 's,\/root\/whitelist_add.sh \$\$\{HOSTNAME\}\;,,g' docker-compose.yaml
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker-compose up -d    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    Wait Until Keyword Succeeds    30s    2s    NetconfCallHome.Check Device Status    FAILED_NOT_ALLOWED
+    Wait Until Keyword Succeeds    30s    2s    Run Keyword And Expect Error    *    Utils.Check For Elements At URI    ${mount_point_url}
+    ...    ${netconf_mount_expected_values}
+
+Successful CallHome with correct global credentials
+    [Documentation]    Device being in whitelist of the Call Home server along with correct global credentials will result to successful mount.
+    ...    CONNECTED should be the device status.
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker-compose up -d    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    Wait Until Keyword Succeeds    30s    2s    NetconfCallHome.Check Device Status    CONNECTED
+    Wait Until Keyword Succeeds    30s    2s    Utils.Check For Elements At URI    ${mount_point_url}    ${netconf_mount_expected_values}
+
+Successful CallHome with correct per-device credentials
+    [Documentation]    Device being in whitelist of the Call Home server along with correct per-device credentials will result to successful mount.
+    ...    CONNECTED should be the device status.
+    SSHLibrary.Execute_Command    sed -i -e 's/global/per-device netopeer/g' docker-compose.yaml
+    ${stdout}    ${stderr}    ${rc}=    SSHLibrary.Execute Command    docker-compose up -d    return_stdout=True    return_stderr=True
+    ...    return_rc=True
+    Wait Until Keyword Succeeds    30s    2s    NetconfCallHome.Check Device Status    CONNECTED
+    Wait Until Keyword Succeeds    30s    2s    Utils.Check For Elements At URI    ${mount_point_url}    ${netconf_mount_expected_values}
diff --git a/csit/testplans/netconf-callhome.txt b/csit/testplans/netconf-callhome.txt
new file mode 100644 (file)
index 0000000..5d37af0
--- /dev/null
@@ -0,0 +1,2 @@
+# Place the suites in run order:
+integration/test/csit/suites/netconf/callhome
diff --git a/csit/variables/netconf/callhome/credentials_set.sh b/csit/variables/netconf/callhome/credentials_set.sh
new file mode 100755 (executable)
index 0000000..fd80f20
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/bash
+
+# This script is called within the docker-compose to provision the controller with either
+# the global or per-device credentials.
+
+stderr() { echo "$@" 1>&2; }
+
+[ $# -eq 0 ] && { stderr "Usage: $0 ( -global | -per-device id ) username password(s)"; exit 1; }
+
+: ${1?"Usage: $0 -global | -per-device"}
+
+option=${1};
+
+if [[ "${option}" == "-per-device" ]]; then
+  : ${2?"Usage: $0 Device Id"}
+  : ${3?"Usage: $0 Device Username"}
+  : ${4?"Usage: $0 Device Password"}
+  devid=${2}
+  user=${3}
+  shift; shift; shift
+  pwds="$@"
+elif [[ "${option}" == "-global" ]]; then
+  : ${2?"Usage: $0 Global Username"}
+  : ${3?"Usage: $0 Global Password"}
+  devid=""
+  user=${2}
+  shift; shift
+  pwds="$@"
+else
+  stderr "$0: must supply -global or -per-device command line argument for global password changes, not '${option}''"
+  exit 1
+fi
+
+pwdsjson=""
+
+for pwd in $pwds; do
+  if [[ ! -z "$pwdsjson" ]]; then
+    pwdsjson+=","
+  fi
+  pwdsjson+="'$pwd'"
+done
+
+set -e
+controller=ODL_SYSTEM_IP
+port=8181
+basicauth="YWRtaW46YWRtaW4="
+
+baseurl="http://${controller}:${port}/restconf/config/odl-netconf-callhome-server:netconf-callhome-server"
+
+if [[ "${option}" == "-global" ]]; then
+  url="${baseurl}/global/credentials"
+else
+  url="${baseurl}/allowed-devices/device/${devid}/credentials"
+fi
+
+set +e
+read -r -d '' payload << EOM
+{
+    "credentials": {
+       "username": "${user}",
+         "passwords": [${pwdsjson}]
+    }
+}
+EOM
+set -e
+
+payload=$(echo "${payload}" | tr '\n' ' ' | tr -s " ")
+
+echo "PUT of user (${user}) and pwd (${pwd})"
+res=$(curl -s -X PUT \
+      -H "Authorization: Basic ${basicauth}" \
+      -H "Content-Type: application/json" \
+      -H "Cache-Control: no-cache" \
+      --data "${payload}" \
+      ${url})
+
+if [[ $res == *"error-message"* ]]; then
+  stderr "$0: ${res}"
+  exit 1
+fi
+
+echo "Getting user/pwd ..."
+
+res=$(curl -s -X GET \
+      -H "Authorization: Basic ${basicauth}" \
+      -H "Cache-Control: no-cache" \
+      ${url})
+echo ${res}
diff --git a/csit/variables/netconf/callhome/datastore-server.xml b/csit/variables/netconf/callhome/datastore-server.xml
new file mode 100644 (file)
index 0000000..8762a29
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<datastores xmlns="urn:cesnet:tmc:datastores:file">
+  <running lock="">
+    <netconf xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-server">
+      <ssh>
+        <call-home>
+          <applications>
+            <application>
+              <name>test</name>
+              <servers>
+                <server>
+                  <address>ODL_SYSTEM_IP</address>
+                  <port>6666</port>
+                </server>
+              </servers>
+              <host-keys>
+                <host-key>
+                  <name>localhost</name>
+                </host-key>
+              </host-keys>
+            </application>
+          </applications>
+        </call-home>
+      </ssh>
+    </netconf>
+  </running>
+  <startup lock="">
+    <netconf xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-server">
+      <ssh>
+        <call-home>
+          <applications>
+            <application>
+              <name>test</name>
+              <servers>
+                <server>
+                  <address>ODL_SYSTEM_IP</address>
+                  <port>6666</port>
+                </server>
+              </servers>
+              <host-keys>
+                <host-key>
+                  <name>localhost</name>
+                </host-key>
+              </host-keys>
+            </application>
+          </applications>
+        </call-home>
+      </ssh>
+    </netconf>
+  </startup>
+  <candidate modified="false" lock=""/>
+</datastores>
diff --git a/csit/variables/netconf/callhome/docker-compose.yaml b/csit/variables/netconf/callhome/docker-compose.yaml
new file mode 100644 (file)
index 0000000..6eb1e78
--- /dev/null
@@ -0,0 +1,17 @@
+# Controller needs to be provisoned with the unique-id of the device(netopeer) and public key.
+# The way this is done with docker compose is:
+# 1. A new docker instance is spawned and public key is generated.
+# 2. We create new pair of keys to ensure it is different than the snapshot of the image.
+# 3. Execute script to send REST to provision netopeer unique-id + public key + credentials in controller.
+# 4. Start netopeer.
+
+netopeer:
+  image: sdnhub/netopeer
+  hostname: netopeer
+  command: sh -c "apt-get update;apt-get install curl --force-yes -y;echo -e 'y/n' | ssh-keygen -q -N '' -f /etc/ssh/ssh_host_rsa_key;/root/whitelist_add.sh $${HOSTNAME};/root/credentials_set.sh -global root root;/root/netopeer/server/netopeer-server -v 3"
+  environment:
+     - controller_ip=ODL_SYSTEM_IP
+  volumes:
+    - ./datastore-server.xml:/usr/local/etc/netopeer/cfgnetopeer/datastore-server.xml
+    - ./whitelist_add.sh:/root/whitelist_add.sh
+    - ./credentials_set.sh:/root/credentials_set.sh
diff --git a/csit/variables/netconf/callhome/whitelist_add.sh b/csit/variables/netconf/callhome/whitelist_add.sh
new file mode 100755 (executable)
index 0000000..ef569aa
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# This script is called within the docker-compose to get the public RSA key of the
+# device(callhome client) and provision the controller.
+
+set -e
+
+key3="$(cat /etc/ssh/ssh_host_rsa_key.pub)"
+parts=($key3)
+hostkey=${parts[1]}
+id=$1
+controller=ODL_SYSTEM_IP
+echo "Adding key for ${id} to ${controller}"
+echo "Found host key: ${hostkey}"
+
+port=8181
+basicauth="YWRtaW46YWRtaW4="
+
+set +e
+read -r -d '' payload << EOM
+{
+    "device": [
+        {
+            "ssh-host-key": "${hostkey}",
+            "unique-id": "${id}"
+        }
+     ]
+}
+EOM
+set -e
+
+payload=$(echo "${payload}" | tr '\n' ' ' | tr -s " ")
+
+url="http://${controller}:${port}/restconf/config/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices"
+
+echo "POST to whitelist"
+res=$(curl -s -X POST -H "Authorization: Basic ${basicauth}" \
+      -H "Content-Type: application/json" \
+      -H "Cache-Control: no-cache" \
+      -H "Postman-Token: 656d7e0d-2f48-5135-3569-06b2a27a709d" \
+      --data "${payload}" \
+      ${url})
+echo $res
+if [[ $res == *"data-exists"* ]]; then
+  echo "Whitelist already has that entry."
+fi