Add new SFC test suite with full node deployment 00/40600/42
authorMiguel Angel Munoz Gonzalez <miguel.angel.munoz.gonzalez@ericsson.com>
Tue, 21 Jun 2016 09:55:01 +0000 (11:55 +0200)
committerJamo Luhrsen <jluhrsen@redhat.com>
Wed, 17 Aug 2016 23:15:18 +0000 (23:15 +0000)
It simulates nodes with an additional csit vm and docker.
Each SF, SFF and classifier will have a container where it can be
executed.

Change-Id: I9c671e947e8d829dd548d32d814529057378ebd5
Signed-off-by: Miguel Angel Munoz Gonzalez <miguel.angel.munoz.gonzalez@ericsson.com>
14 files changed:
csit/libraries/Utils.robot
csit/suites/sfc/Full_Deploy/010__sfc_full_deploy.robot [new file with mode: 0644]
csit/suites/sfc/Full_Deploy/Dockerfile [new file with mode: 0644]
csit/suites/sfc/Full_Deploy/docker-ovs.sh [new file with mode: 0755]
csit/suites/sfc/Full_Deploy/setup-docker-image.sh [new file with mode: 0755]
csit/testplans/sfc-full-deploy.txt [new file with mode: 0644]
csit/variables/sfc/Variables.robot [new file with mode: 0644]
csit/variables/sfc/master/full-deploy/service-function-chains.json [new file with mode: 0644]
csit/variables/sfc/master/full-deploy/service-function-forwarders.json [new file with mode: 0644]
csit/variables/sfc/master/full-deploy/service-function-paths.json [new file with mode: 0644]
csit/variables/sfc/master/full-deploy/service-functions.json [new file with mode: 0644]
csit/variables/sfc/master/full-deploy/service-nodes.json [new file with mode: 0644]
csit/variables/sfc/master/full-deploy/service-random-schedule-type.json [new file with mode: 0644]
csit/variables/sfc/master/full-deploy/service-roundrobin-schedule-type.json [new file with mode: 0644]

index 1b7338c67aa329e9c0039998ea8fafd4c2769de5..712f936e87f5899b7088b7ba35abe93ef8936b89 100644 (file)
@@ -8,6 +8,7 @@ Library           Collections
 Library           RequestsLibrary
 Library           ./UtilLibrary.py
 Resource          KarafKeywords.robot
+Resource          TemplatedRequests.robot
 Variables         ../variables/Variables.py
 
 *** Variables ***
@@ -319,17 +320,17 @@ Post Elements To URI
     [Documentation]    Perform a POST rest operation, using the URL and data provided
     ${resp} =    RequestsLibrary.Post Request    ${session}    ${rest_uri}    data=${data}    headers=${headers}
     Log    ${resp.content}
-    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain    ${ALLOWED_STATUS_CODES}    ${resp.status_code}
 
 Remove All Elements At URI
     [Arguments]    ${uri}
     ${resp}    RequestsLibrary.Delete Request    session    ${uri}
-    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain    ${ALLOWED_STATUS_CODES}    ${resp.status_code}
 
 Remove All Elements At URI And Verify
     [Arguments]    ${uri}
     ${resp}    RequestsLibrary.Delete Request    session    ${uri}
-    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain    ${ALLOWED_STATUS_CODES}    ${resp.status_code}
     ${resp}    RequestsLibrary.Get Request    session    ${uri}
     Should Be Equal As Strings    ${resp.status_code}    404
 
@@ -337,20 +338,20 @@ Add Elements To URI From File
     [Arguments]    ${dest_uri}    ${data_file}    ${headers}=${headers}
     ${body}    OperatingSystem.Get File    ${data_file}
     ${resp}    RequestsLibrary.Put Request    session    ${dest_uri}    data=${body}    headers=${headers}
-    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain    ${ALLOWED_STATUS_CODES}    ${resp.status_code}
 
 Add Elements To URI From File And Verify
     [Arguments]    ${dest_uri}    ${data_file}    ${headers}=${headers}
     ${body}    OperatingSystem.Get File    ${data_file}
     ${resp}    RequestsLibrary.Put Request    session    ${dest_uri}    data=${body}    headers=${headers}
-    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain    ${ALLOWED_STATUS_CODES}    ${resp.status_code}
     ${resp}    RequestsLibrary.Get Request    session    ${dest_uri}
     Should Not Be Equal    ${resp.status_code}    404
 
 Add Elements To URI And Verify
     [Arguments]    ${dest_uri}    ${data_file}    ${headers}=${headers}
     ${resp}    RequestsLibrary.Put Request    session    ${dest_uri}    ${data_file}    headers=${headers}
-    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain    ${ALLOWED_STATUS_CODES}    ${resp.status_code}
     ${resp}    RequestsLibrary.Get Request    session    ${dest_uri}
     Should Not Be Equal    ${resp.status_code}    404
 
@@ -358,7 +359,7 @@ Post Elements To URI From File
     [Arguments]    ${dest_uri}    ${data_file}    ${headers}=${headers}
     ${body}    OperatingSystem.Get File    ${data_file}
     ${resp}    RequestsLibrary.Post Request    session    ${dest_uri}    data=${body}    headers=${headers}
-    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain    ${ALLOWED_STATUS_CODES}    ${resp.status_code}
 
 Run Process With Logging And Status Check
     [Arguments]    @{proc_args}
diff --git a/csit/suites/sfc/Full_Deploy/010__sfc_full_deploy.robot b/csit/suites/sfc/Full_Deploy/010__sfc_full_deploy.robot
new file mode 100644 (file)
index 0000000..a0c3857
--- /dev/null
@@ -0,0 +1,80 @@
+*** Settings ***
+Documentation     Test suite for SFC Service Functions, Operates functions from Restconf APIs.
+Suite Setup       Init Suite
+Suite Teardown    Delete All Sessions
+Library           SSHLibrary
+Library           Collections
+Library           OperatingSystem
+Library           RequestsLibrary
+Variables         ../../../variables/Variables.py
+Resource          ../../../variables/sfc/Variables.robot
+Resource          ../../../libraries/Utils.robot
+Resource          ../../../libraries/TemplatedRequests.robot
+*** Variables ***
+${CREATE_RSP1_INPUT}    {"input":{"parent-service-function-path":"SFP-1","name":"SFP-1-Path-1"}}
+${CREATE_RSP_FAILURE_INPUT}    {"input":{"parent-service-function-path":"SFC1-empty","name":"SFC1-empty-Path-1"}}
+*** Test Cases ***
+Basic Environment Setup Tests
+    [Documentation]    Prepare Basic Test Environment
+    Add Elements To URI From File    ${SERVICE_FORWARDERS_URI}    ${SERVICE_FORWARDERS_FILE}
+    Add Elements To URI From File    ${SERVICE_NODES_URI}    ${SERVICE_NODES_FILE}
+    Add Elements To URI From File    ${SERVICE_FUNCTIONS_URI}    ${SERVICE_FUNCTIONS_FILE}
+    Add Elements To URI From File    ${SERVICE_CHAINS_URI}    ${SERVICE_CHAINS_FILE}
+    Add Elements To URI From File    ${SERVICE_FUNCTION_PATHS_URI}    ${SERVICE_FUNCTION_PATHS_FILE}
+
+Create and Get Rendered Service Path
+    [Documentation]    Create and Get Rendered Service Path Through RESTConf APIs
+    Post Elements To URI As JSON    ${OPERATIONS_CREATE_RSP_URI}    ${CREATE_RSP1_INPUT}
+    ${resp}    RequestsLibrary.Get Request    session    ${OPERATIONAL_RSPS_URI}
+    Should Contain    ${ALLOWED_STATUS_CODES}    ${resp.status_code}
+    ${elements}=    Create List    SFP-1-Path-1    "parent-service-function-path":"SFP-1"    "hop-number":0    "service-index":255    "hop-number":1
+    ...    "service-index":254
+    Check For Elements At URI    ${OPERATIONAL_RSPS_URI}    ${elements}
+
+Clean Datastore After Tests
+    [Documentation]    Clean All Items In Datastore After Tests
+    Sleep    1
+    Remove All Elements At URI    ${SERVICE_FUNCTIONS_URI}
+    Remove All Elements At URI    ${SERVICE_FORWARDERS_URI}
+    Remove All Elements At URI    ${SERVICE_NODES_URI}
+    Remove All Elements At URI    ${SERVICE_CHAINS_URI}
+    Remove All Elements At URI    ${SERVICE_FUNCTION_PATHS_URI}
+
+*** Keywords ***
+Post Elements To URI As JSON
+    [Arguments]    ${uri}    ${data}
+    ${resp}    RequestsLibrary.Post Request    session    ${uri}    data=${data}    headers=${headers}
+    Should Contain    ${ALLOWED_STATUS_CODES}    ${resp.status_code}    
+
+Get JSON Elements From URI
+    [Arguments]    ${uri}
+    ${resp}    RequestsLibrary.Get Request    session    ${uri}
+    ${value}    To Json    ${resp.content}
+    [Return]    ${value}
+
+Init Suite
+    [Documentation]    Connect Create session and initialize ODL version specific variables
+    SSHLibrary.Open Connection    ${TOOLS_SYSTEM_IP}    timeout=3s
+    Utils.Flexible Mininet Login
+    SSHLibrary.Put File    ${CURDIR}/docker-ovs.sh    .    mode=0755
+    SSHLibrary.Put File    ${CURDIR}/Dockerfile    .    mode=0755
+    SSHLibrary.Put File    ${CURDIR}/setup-docker-image.sh    .    mode=0755
+    ${result}    SSHLibrary.Execute Command    ./setup-docker-image.sh > >(tee myFile.log) 2> >(tee myFile.log)    return_stderr=True    return_stdout=True    return_rc=True
+    log    ${result}
+    Should be equal as integers    ${result[2]}    0
+    ${result}    SSHLibrary.Execute Command    ./docker-ovs.sh spawn --nodes=6 --guests=1 --tun=vxlan-gpe --odl=${ODL_SYSTEM_IP} > >(tee myFile2.log) 2> >(tee myFile2.log)    return_stderr=True    return_stdout=True    return_rc=True
+    log    ${result}
+    Should be equal as integers    ${result[2]}    0
+    SSHLibrary.Close Connection
+    Create Session    session    http://${ODL_SYSTEM_IP}:${RESTCONFPORT}    auth=${AUTH}    headers=${HEADERS}
+    log    ${ODL_STREAM}
+    Run Keyword If    '${ODL_STREAM}' == 'stable-lithium'    Set Suite Variable    ${VERSION_DIR}    lithium
+    ...    ELSE    Set Suite Variable    ${VERSION_DIR}    master
+    Set Suite Variable    ${SERVICE_FUNCTIONS_FILE}    ${CURDIR}/../../../variables/sfc/${VERSION_DIR}/full-deploy/service-functions.json
+    Set Suite Variable    ${SERVICE_FORWARDERS_FILE}    ${CURDIR}/../../../variables/sfc/${VERSION_DIR}/full-deploy/service-function-forwarders.json
+    Set Suite Variable    ${SERVICE_NODES_FILE}    ${CURDIR}/../../../variables/sfc/${VERSION_DIR}/full-deploy/service-nodes.json
+    Set Suite Variable    ${SERVICE_CHAINS_FILE}    ${CURDIR}/../../../variables/sfc/${VERSION_DIR}/full-deploy/service-function-chains.json
+    Set Suite Variable    ${SERVICE_FUNCTION_PATHS_FILE}    ${CURDIR}/../../../variables/sfc/${VERSION_DIR}/full-deploy/service-function-paths.json
+    Set Suite Variable    ${SERVICE_RANDOM_SCHED_TYPE_FILE}    ${CURDIR}/../../../variables/sfc/${VERSION_DIR}/full-deploy/service-random-schedule-type.json
+    Set Suite Variable    ${SERVICE_ROUNDROBIN_SCHED_TYPE_FILE}    ${CURDIR}/../../../variables/sfc/${VERSION_DIR}/full-deploy/service-roundrobin-schedule-type.json
+
diff --git a/csit/suites/sfc/Full_Deploy/Dockerfile b/csit/suites/sfc/Full_Deploy/Dockerfile
new file mode 100644 (file)
index 0000000..6bdb2df
--- /dev/null
@@ -0,0 +1,49 @@
+FROM socketplane/busybox:latest
+MAINTAINER The SocketPlane Team <support@socketplane.io>
+ENV OVS openvswitch_2.5.90-1
+ENV SUPERVISOR_STDOUT_VERSION 0.1.1
+# Configure supervisord
+RUN mkdir -p /var/log/supervisor/
+ADD supervisord.conf /etc/
+# Install supervisor_stdout
+WORKDIR /opt
+RUN mkdir -p /var/log/supervisor/
+RUN mkdir -p /etc/openvswitch
+RUN wget https://pypi.python.org/packages/source/s/supervisor-stdout/supervisor-stdout-$SUPERVISOR_STDOUT_VERSION.tar.gz --no-check-certificate && \
+    tar -xzvf supervisor-stdout-0.1.1.tar.gz && \
+    mv supervisor-stdout-$SUPERVISOR_STDOUT_VERSION supervisor-stdout && \
+    rm supervisor-stdout-0.1.1.tar.gz && \
+    cd supervisor-stdout && \
+    python setup.py install -q
+# Get Open vSwitch
+WORKDIR /
+COPY ovs_package/${OVS}.tgz /
+RUN ls -la /
+RUN ls -la /var
+RUN tar -xzvf ${OVS}.tgz &&\
+    mv $OVS openvswitch &&\
+    cp -r openvswitch/* / &&\
+    rm -r openvswitch &&\
+    rm ${OVS}.tgz
+ADD configure-ovs.sh /usr/local/share/openvswitch/
+
+COPY libcrypto.so.10 /usr/lib
+COPY libssl.so.10 /usr/lib
+COPY libgssapi_krb5.so.2 /usr/lib
+COPY libkrb5.so.3 /usr/lib
+COPY libcom_err.so.2 /usr/lib
+COPY libk5crypto.so.3 /usr/lib
+COPY libkrb5support.so.0 /usr/lib
+COPY libkeyutils.so.1 /usr/lib
+COPY libselinux.so.1 /usr/lib
+COPY libpcre.so.1 /usr/lib
+COPY liblzma.so.5 /usr/lib
+
+
+# Create the database
+RUN ovsdb-tool create /etc/openvswitch/conf.db /usr/local/share/openvswitch/vswitch.ovsschema
+# Put the OVS Python modules on the Python Path
+RUN cp -r /usr/local/share/openvswitch/python/ovs /usr/lib/python2.7/site-packages/ovs
+CMD ["/usr/bin/supervisord"]
+
+
diff --git a/csit/suites/sfc/Full_Deploy/docker-ovs.sh b/csit/suites/sfc/Full_Deploy/docker-ovs.sh
new file mode 100755 (executable)
index 0000000..981f3cd
--- /dev/null
@@ -0,0 +1,353 @@
+#!/bin/bash
+# Copyright (C) 2014 Nicira, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BASED ON https://github.com/openvswitch/ovs/blob/master/utilities/ovs-docker
+# MODIFIED
+
+set -o xtrace
+#set -e #Exit script if a command fails
+
+# Check for programs we'll need.
+search_path () {
+    save_IFS=$IFS
+    IFS=:
+    for dir in $PATH; do
+        IFS=$save_IFS
+        if test -x "$dir/$1"; then
+            return 0
+        fi
+    done
+    IFS=$save_IFS
+    echo >&2 "$0: $1 not found in \$PATH, please install and try again"
+    exit 1
+}
+
+ovs_vsctl () {
+    sudo ovs-vsctl --timeout=60 "$@"
+}
+
+d_ovs_vsctl () {
+    CONTAINER="$1"
+    shift
+    sudo docker exec "$CONTAINER" ovs-vsctl --timeout=60 "$@"
+}
+
+create_netns_link () {
+    sudo mkdir -p /var/run/netns
+    if [ ! -e /var/run/netns/"$PID" ]; then
+        sudo ln -s /proc/"$PID"/ns/net /var/run/netns/"$PID"
+        trap 'delete_netns_link' 0
+        for signal in 1 2 3 13 14 15; do
+            trap 'delete_netns_link; trap - $signal; kill -$signal $$' $signal
+        done
+    fi
+}
+
+delete_netns_link () {
+    sudo rm -f /var/run/netns/"$PID"
+}
+
+connect_namespace_to_container () {
+
+    NAMESPACE="$1"
+    CONTAINER="$2"
+
+    if [ -z "$NAMESPACE" ] || [ -z "$CONTAINER" ]; then
+        echo >&2 "$UTIL add-port: not enough arguments (use --help for help)"
+        exit 1
+    fi
+
+    shift 2
+    while [ $# -ne 0 ]; do
+        case $1 in
+            --ipaddress=*)
+                ADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`
+                shift
+                ;;
+            --macaddress=*)
+                MACADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`
+                shift
+                ;;
+            *)
+                echo >&2 "$UTIL add-port: unknown option \"$1\""
+                exit 1
+                ;;
+        esac
+    done
+
+    if PID=`sudo docker inspect -f '{{.State.Pid}}' "$CONTAINER"`; then :; else
+        echo >&2 "$UTIL: Failed to get the PID of the container"
+        exit 1
+    fi
+
+    create_netns_link
+
+    CONTAINER_IF="v-$NAMESPACE"
+    NAMESPACE_IF="v-${CONTAINER:0:12}"
+
+    # Create namespace
+    if [ -z `sudo ip netns list | grep "$NAMESPACE"` ]; then
+         sudo ip netns add "$NAMESPACE"
+    fi
+
+    # Create a veth pair in namespace.
+    sudo ip netns exec "$NAMESPACE" ip link add "$NAMESPACE_IF" type veth peer \
+       name "$CONTAINER_IF"
+    sudo ip netns exec "$NAMESPACE" ip link set dev "$NAMESPACE_IF" up
+
+    # Move one side to container namespace.
+    sudo ip netns exec "$NAMESPACE" ip link set dev "$CONTAINER_IF" netns "$PID"
+    sudo ip netns exec "$PID" ip link set dev "$CONTAINER_IF" up
+
+    # And put it in integration bridge
+    d_ovs_vsctl "$CONTAINER" add-port br-int "$CONTAINER_IF"
+
+    if [ -n "$ADDRESS" ]; then
+        sudo ip netns exec "$NAMESPACE" ip addr add "$ADDRESS" dev "$NAMESPACE_IF"
+    fi
+
+    if [ -n "$MACADDRESS" ]; then
+        sudo ip netns exec "$NAMESPACE" ip link set dev "$NAMESPACE_IF" \
+           address "$MACADDRESS"
+    fi
+
+    delete_netns_link
+}
+
+spawn_node () {
+    NODE="$1"
+    TUN="$2"
+
+    if [ -z `sudo docker images | awk '/^ovs-docker/ {print $1}'` ]; then
+        echo "$UTIL: Docker image ovs-docker does not exist, creating..."
+        sudo docker build -t ovs-docker .
+    fi
+
+    CONTAINER=`sudo docker run -itd --privileged --cap-add ALL --name=ovs-node-"$NODE" ovs-docker`
+
+    if [ $? -ne 0 ]; then
+       echo >&2 "$UTIL: Failed to start container $NODE"
+       exit 1
+    fi
+
+    STATUS=""
+    while [ "$STATUS" != "EXITED" ]; do
+       STATUS=`sudo docker exec "$CONTAINER" supervisorctl status configure-ovs |\
+          awk '{print $2}'`
+    done
+    CONTAINER_GW=`sudo docker inspect -f '{{ .NetworkSettings.Gateway }}' "$CONTAINER"`
+    CONTAINER_IP=`sudo docker inspect -f '{{ .NetworkSettings.IPAddress }}' "$CONTAINER"`
+
+    # Create a container bridge as integration for all guests
+    if d_ovs_vsctl "$CONTAINER" br-exists br-int; then :; else
+        d_ovs_vsctl "$CONTAINER" add-br br-int
+        d_ovs_vsctl "$CONTAINER" add-port br-int patch-tun -- \
+           set interface patch-tun type=patch option:peer=patch-int
+    fi
+
+
+    # Create a container bridge as endpoint for all tunnels
+    if d_ovs_vsctl "$CONTAINER" br-exists br-tun; then :; else
+        d_ovs_vsctl "$CONTAINER" add-br br-tun
+        d_ovs_vsctl "$CONTAINER" add-port br-tun patch-int -- \
+           set interface patch-int type=patch option:peer=patch-tun
+    fi
+
+    # Setup the tunnel
+    if [ "$TUN" == "vxlan" ]; then
+        TUN_OPT="type=vxlan"
+    elif [ "$TUN" == "vxlan-gpe" ]; then
+        TUN_OPT="type=vxlan option:exts=gpe"
+    else
+        TUN_OPT=""
+    fi
+
+    if [ -z "$TUN" ]; then :; else
+        ovs_vsctl add-port br-tun vtep-node-"$NODE" -- \
+            set interface vtep-node-"$NODE" $TUN_OPT \
+            option:remote_ip="$CONTAINER_IP" ofport_request="$NODE"
+        d_ovs_vsctl "$CONTAINER" add-port br-tun vtep -- \
+            set interface vtep $TUN_OPT \
+            option:remote_ip="$CONTAINER_GW" ofport_request=10
+    fi
+
+    if [ -z "$ODL" ]; then :; else
+        d_ovs_vsctl "$CONTAINER" set-manager "tcp:${ODL}:6640"
+        d_ovs_vsctl "$CONTAINER" set-controller br-tun "tcp:${ODL}:6633"
+        d_ovs_vsctl "$CONTAINER" set-controller br-int "tcp:${ODL}:6633"
+    fi
+
+    DO_GUEST="$GUESTS"
+    until [ $DO_GUEST -eq 0 ]; do
+        ADDRESS="10.0.${NODE}.${DO_GUEST}/16"
+        connect_namespace_to_container "ovsnsn${NODE}g$DO_GUEST" "$CONTAINER" \
+           --ipaddress="$ADDRESS"
+        let DO_GUEST-=1
+    done
+}
+
+spawn_nodes_and_guests () {
+
+    while [ $# -ne 0 ]; do
+        case $1 in
+            --nodes=*)
+                NODES=`expr X"$1" : 'X[^=]*=\(.*\)'`
+                shift
+                ;;
+            --guests=*)
+                GUESTS=`expr X"$1" : 'X[^=]*=\(.*\)'`
+                shift
+                ;;
+            --tun=*)
+                TUN=`expr X"$1" : 'X[^=]*=\(.*\)'`
+                shift
+                ;;
+            --odl=*)
+                ODL=`expr X"$1" : 'X[^=]*=\(.*\)'`
+                shift
+                ;;
+            *)
+                echo >&2 "$UTIL spawn: unknown option \"$1\""
+                exit 1
+                ;;
+        esac
+    done
+
+    NUM_REGEX="[0-9]+"
+    TUN_REGEX="vxlan|vxlan-gpe|^$"
+    IP_REGEX="^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
+
+    if [[ $NODES =~ $NUM_REGEX ]]; then :; else
+         echo >&2 "$UTIL: NODES has to be a number"
+         exit 1
+    fi
+
+    if [ $NODES -gt 256 ]; then
+         echo >&2 "$UTIL: NODES has to be less than 256"
+         exit 1
+    fi
+
+    if [[ $GUESTS =~ $NUM_REGEX ]]; then :; else
+         echo >&2 "$UTIL: GUESTS has to be a number"
+         exit 1
+    fi
+
+    if [ $GUESTS -gt 256 ]; then
+         echo >&2 "$UTIL: GUESTS has to be less than 256"
+         exit 1
+    fi
+
+    if [[ $TUN =~ $TUN_REGEX ]]; then :; else
+         echo >&2 "$UTIL: TYPE has to be vxlan or vxlan-gpe"
+         exit 1
+    fi
+
+    if [[ $ODL =~ $IP_REGEX ]]; then :; else
+         echo >&2 "$UTIL: IP has to be a valid ip address"
+         exit 1
+    fi
+
+    # Create a host bridge as end point for all tunnels
+    if ovs_vsctl br-exists br-tun; then :; else
+        ovs_vsctl add-br br-tun
+        if [ -z "$ODL" ]; then :; else
+            ovs_vsctl set-manager "tcp:${ODL}:6640"
+            ovs_vsctl set-controller br-tun "tcp:${ODL}:6633"
+        fi
+    fi
+
+    DO_NODE="$NODES"
+    until [ $DO_NODE -eq 0 ]; do
+       spawn_node "$DO_NODE" "$TUN"
+       let DO_NODE-=1
+    done
+}
+
+clean() {
+
+     for ID in `sudo docker ps -a | awk '/ovs-node-[0-9]+$/ {print $1}'`; do
+         sudo docker stop "$ID"
+         sudo docker rm "$ID"
+     done
+
+     for NS in `sudo ip netns list | grep ovsns`; do
+         sudo ip netns del "$NS"
+     done
+
+     ovs_vsctl del-br br-tun
+     ovs_vsctl del-manager
+}
+
+
+usage() {
+    cat << EOF
+${UTIL}: Perform various tasks related with docker-ovs container.
+usage: ${UTIL} COMMAND
+
+Commands:
+  spawn --nodes=NODES --guests=GUESTS --tun=TYPE --odl=IP
+                    Runs NODES number of docker-ovs instances and attaches
+                    GUESTS number of namespaces to each instance. If tun
+                    option is specified, tunnel of such type will be configured
+                    between the nodes and a host bridge. Types supported are
+                    vxlan or vxlan-gpe
+  clean
+                    Stops containers and deletes namespaces
+Options:
+  -h, --help        display this help message.
+EOF
+}
+
+UTIL=$(basename $0)
+search_path ovs-vsctl
+search_path docker
+
+#if [[ $EUID -ne 0 ]]; then
+#   echo "This script must be run as root" 1>&2
+#   exit 1
+#fi
+
+if (sudo ip netns) > /dev/null 2>&1; then :; else
+    echo >&2 "$UTIL: ip utility not found (or it does not support netns),"\
+             "cannot proceed"
+    exit 1
+fi
+
+if [ $# -eq 0 ]; then
+    usage
+    exit 0
+fi
+
+case $1 in
+    "spawn")
+        shift
+        spawn_nodes_and_guests "$@"
+        exit 0
+        ;;
+    "clean")
+        shift
+        clean
+        exit 0
+        ;;
+    -h | --help)
+        usage
+        exit 0
+        ;;
+    *)
+        echo >&2 "$UTIL: unknown command \"$1\" (use --help for help)"
+        exit 1
+        ;;
+esac
+
diff --git a/csit/suites/sfc/Full_Deploy/setup-docker-image.sh b/csit/suites/sfc/Full_Deploy/setup-docker-image.sh
new file mode 100755 (executable)
index 0000000..1b2f31f
--- /dev/null
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+set -o xtrace
+set -o nounset #Don't allow for unset variables
+#set -e #Exit script if a command fails
+
+# bootstrap_centos
+WORK_DIR=`pwd`
+if sudo yum install -y "kernel-devel-uname-r == $(uname -r)"; then
+   echo "Kernel-devel installed correctly"
+else
+   echo "Warning: Errors issued when installing kernel-devel"
+fi
+
+APT="sudo yum install -y git kernel-debug-devel kernel-headers python-devel vim autoconf automake libtool systemd-units rpm-build openssl openssl-devel groff graphviz selinux-policy-devel python python-twisted-core python-zope-interface python-twisted-web PyQt4 python-six desktop-file-utils procps-ng"
+if $APT; then
+  echo "Pacakges installed correctly"
+else
+  echo "Installation of packages failed"
+  exit 1
+fi
+
+cd $WORK_DIR
+[ -e configure-ovs.sh ] || \
+   wget https://raw.githubusercontent.com/socketplane/docker-ovs/master/configure-ovs.sh
+chmod a+x configure-ovs.sh
+[ -e supervisord.conf ] || \
+   wget https://raw.githubusercontent.com/socketplane/docker-ovs/master/supervisord.conf
+
+[ -e ovs_nsh_patches ] || \
+   git clone https://github.com/yyang13/ovs_nsh_patches.git
+[ -e ovs ] || \
+   git clone https://github.com/openvswitch/ovs.git
+
+cd ovs
+git reset --hard 7d433ae57ebb90cd68e8fa948a096f619ac4e2d8
+cp ../ovs_nsh_patches/*.patch ./
+git apply *.patch
+
+#compile ovs
+./boot.sh
+./configure --with-linux=/lib/modules/`uname -r`/build --prefix=/usr/local
+make rpm-fedora RPMBUILD_OPT="--without check --without libcapng"
+make DESTDIR=$WORK_DIR/ovs_install/openvswitch_2.5.90-1 install
+
+#copy rpms and installation
+mkdir -p $WORK_DIR/ovs_package
+find . -name "*.rpm"|xargs -I[] cp [] $WORK_DIR/ovs_package
+tar cvzf $WORK_DIR/ovs_package/openvswitch_2.5.90-1.tgz -C $WORK_DIR/ovs_install .
+
+# install_ovs
+cd $WORK_DIR/ovs_package
+CMD='sudo yum list installed openvswitch'
+if $CMD; then
+  echo "openvswitch already installed"
+else
+  sudo yum --nogpgcheck -y install `find . -regex "\./openvswitch-[0-9,.,-].*"`
+fi
+
+#start ovs
+sudo /sbin/service openvswitch start
+
+#prepare libraries for docker image in busybox
+cd $WORK_DIR
+cp /usr/lib64/libcrypto.so.10 .
+cp /usr/lib64/libssl.so.10 .
+cp /usr/lib64/libgssapi_krb5.so.2 .
+cp /usr/lib64/libkrb5.so.3 .
+cp /usr/lib64/libcom_err.so.2 .
+cp /usr/lib64/libk5crypto.so.3 .
+cp /usr/lib64/libkrb5support.so.0 .
+cp /usr/lib64/libkeyutils.so.1 .
+cp /usr/lib64/libselinux.so.1 .
+cp /usr/lib64/libpcre.so.1 .
+cp /usr/lib64/liblzma.so.5 .
+
+# build_ovs_docker
+cd $WORK_DIR
+if [ -z `sudo docker images | awk '/^ovs-docker / {print $1}'` ];
+ then
+   sudo docker build -t ovs-docker .
+fi
+
+
+
diff --git a/csit/testplans/sfc-full-deploy.txt b/csit/testplans/sfc-full-deploy.txt
new file mode 100644 (file)
index 0000000..9ae5e3f
--- /dev/null
@@ -0,0 +1,2 @@
+# Place the suites in run order:
+integration/test/csit/suites/sfc/Full_Deploy/010__sfc_full_deploy.robot
diff --git a/csit/variables/sfc/Variables.robot b/csit/variables/sfc/Variables.robot
new file mode 100644 (file)
index 0000000..3bcd1f7
--- /dev/null
@@ -0,0 +1,15 @@
+*** Variables ***
+# Generic Service Chains and Function URIs
+${SERVICE_FUNCTIONS_URI}    /restconf/config/service-function:service-functions/
+${SERVICE_FORWARDERS_URI}    /restconf/config/service-function-forwarder:service-function-forwarders/
+${SERVICE_NODES_URI}    /restconf/config/service-node:service-nodes/
+${SERVICE_CHAINS_URI}    /restconf/config/service-function-chain:service-function-chains/
+${SERVICE_FUNCTION_PATHS_URI}    /restconf/config/service-function-path:service-function-paths/
+${SERVICE_SCHED_TYPES_URI}    /restconf/config/service-function-scheduler-type:service-function-scheduler-types/
+${SERVICE_SCHED_TYPE_URI_BASE}    SERVICE_SCHED_TYPES_URI+'service-function-scheduler-type/service-function-scheduler-type:'
+${SERVICE_RANDOM_SCHED_TYPE_URI}    SERVICE_SCHED_TYPE_URI_BASE+'random'
+${SERVICE_ROUNDROBIN_SCHED_TYPE_URI}    SERVICE_SCHED_TYPE_URI_BASE+'round-robin'
+${OPERATIONAL_RSPS_URI}    /restconf/operational/rendered-service-path:rendered-service-paths/
+${OPERATIONS_CREATE_RSP_URI}    /restconf/operations/rendered-service-path:create-rendered-path/
+${OPERATIONS_DELETE_RSP_URI}    /restconf/operations/rendered-service-path:delete-rendered-path/
+
diff --git a/csit/variables/sfc/master/full-deploy/service-function-chains.json b/csit/variables/sfc/master/full-deploy/service-function-chains.json
new file mode 100644 (file)
index 0000000..24fc153
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "service-function-chains": {
+    "service-function-chain": [
+      {
+        "name": "SFC1",
+        "sfc-service-function": [
+          {
+            "name": "dpi-abstract1",
+            "type": "dpi",
+            "order" : 0
+          },
+          {
+            "name": "napt44-abstract1",
+            "type": "napt44",
+            "order" : 1
+          }
+        ]
+      }
+    ]
+  }
+}
diff --git a/csit/variables/sfc/master/full-deploy/service-function-forwarders.json b/csit/variables/sfc/master/full-deploy/service-function-forwarders.json
new file mode 100644 (file)
index 0000000..e8beb20
--- /dev/null
@@ -0,0 +1,100 @@
+{
+  "service-function-forwarders": {
+    "service-function-forwarder": [
+      {
+        "name": "SFF-1",
+        "service-node": "SFF-1",
+        "rest-uri": "http://localhost:5000",
+        "service-function-forwarder-ovs:ovs-bridge": {
+                    "bridge-name": "br-sfc"
+        },
+        "sff-data-plane-locator": [
+          {
+            "name": "SFF-1-DPL",
+            "data-plane-locator": {
+              "port": 5000,
+              "ip": "172.17.0.3",
+              "transport": "service-locator:vxlan-gpe"
+            },
+            "service-function-forwarder-ovs:ovs-options": {
+                "remote-ip": "flow",
+                "dst-port": "6633",
+                "key": "flow",
+                "nsp": "flow",
+                "nsi": "flow",
+                "nshc1": "flow",
+                "nshc2": "flow",
+                "nshc3": "flow",
+                "nshc4": "flow"
+            }
+          }
+        ],
+        "service-function-dictionary": [
+          {
+            "sff-sf-data-plane-locator": {
+              "sf-dpl-name": "SF-1-DPL",
+              "sff-dpl-name": "SFF-1-DPL"
+            },
+            "name": "SF1"
+          }
+        ],
+        "connected-sff-dictionary": [
+          {
+            "sff-sff-data-plane-locator": {
+              "port": 5000,
+              "ip": "172.17.0.5"
+            },
+            "name": "SFF-2"
+          }
+        ]
+      },
+      {
+        "name": "SFF-2",
+        "service-node": "SFF-2",
+        "service-function-forwarder-ovs:ovs-bridge": {
+                    "bridge-name": "br-sfc"
+        },
+        "rest-uri": "http://localhost:5000",
+        "sff-data-plane-locator": [
+          {
+            "name": "SFF-2-DPL",
+            "data-plane-locator": {
+              "port": 5000,
+              "ip": "172.17.0.5",
+              "transport": "service-locator:vxlan-gpe"
+            },
+            "service-function-forwarder-ovs:ovs-options": {
+                "remote-ip": "flow",
+                "dst-port": "6633",
+                "key": "flow",
+                "nsp": "flow",
+                "nsi": "flow",
+                "nshc1": "flow",
+                "nshc2": "flow",
+                "nshc3": "flow",
+                "nshc4": "flow"
+            }
+          }
+        ],
+        "service-function-dictionary": [
+          {
+            "sff-sf-data-plane-locator": {
+              "sf-dpl-name": "SF-2-DPL",
+              "sff-dpl-name": "SFF-2-DPL"
+            },
+            "name": "SF2"
+          }
+        ],
+        "connected-sff-dictionary": [
+          {
+            "sff-sff-data-plane-locator": {
+              "port": 5000,
+              "ip": "172.17.0.3"
+            },
+            "name": "SFF-1"
+          }
+        ]
+      }
+    ]
+  }
+}
diff --git a/csit/variables/sfc/master/full-deploy/service-function-paths.json b/csit/variables/sfc/master/full-deploy/service-function-paths.json
new file mode 100644 (file)
index 0000000..a2619a4
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "service-function-paths": {
+    "service-function-path": [
+      {
+        "name": "SFP-1",
+        "service-chain-name": "SFC1"
+      }
+    ]
+  }
+}
diff --git a/csit/variables/sfc/master/full-deploy/service-functions.json b/csit/variables/sfc/master/full-deploy/service-functions.json
new file mode 100644 (file)
index 0000000..3a328ef
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  "service-functions": {
+    "service-function": [
+      {
+        "rest-uri": "http://localhost:10002",
+        "ip-mgmt-address": "172.17.0.4",
+        "sf-data-plane-locator": [
+          {
+            "name": "SF-1-DPL",
+            "port": 10002,
+            "ip": "172.17.0.4",
+            "service-function-forwarder": "SFF-1"
+          }
+        ],
+        "name": "dpi-102-2",
+        "type": "dpi",
+        "nsh-aware": true
+      },
+      {
+        "rest-uri": "http://localhost:10001",
+        "ip-mgmt-address": "172.17.0.6",
+        "sf-data-plane-locator": [
+          {
+            "name": "SF-2-DPL",
+            "port": 10001,
+            "ip": "172.17.0.6",
+            "service-function-forwarder": "SFF-2"
+          }
+        ],
+        "name": "napt44-103-2",
+        "type": "napt44",
+        "nsh-aware": true
+      }
+   ]
+  }
+}
diff --git a/csit/variables/sfc/master/full-deploy/service-nodes.json b/csit/variables/sfc/master/full-deploy/service-nodes.json
new file mode 100644 (file)
index 0000000..a03977e
--- /dev/null
@@ -0,0 +1,44 @@
+{
+    "service-nodes": {
+        "service-node": [
+            {
+                "name": "SF-1",
+                "service-function": [
+                    "dpi-102-2"
+                ],
+                "ip-mgmt-address": "172.17.0.4"
+            },
+            {
+                "name": "SF-2",
+                "service-function": [
+                    "napt-44-103-2"
+                ],
+                "ip-mgmt-address": "172.17.0.6"
+            },
+            {
+                "name": "SFF-1",
+                "service-function": [
+                ],
+                "ip-mgmt-address": "172.17.0.3"
+            },
+            {
+                "name": "SFF-2",
+                "service-function": [
+                ],
+                "ip-mgmt-address": "172.17.0.5"
+            },
+            {
+                "name": "classifier-1",
+                "service-function": [
+                ],
+                "ip-mgmt-address": "172.17.0.2"
+            },
+            {
+                "name": "classifier-2",
+                "service-function": [
+                ],
+                "ip-mgmt-address": "172.17.0.7"
+            }
+       ]
+    }
+}
diff --git a/csit/variables/sfc/master/full-deploy/service-random-schedule-type.json b/csit/variables/sfc/master/full-deploy/service-random-schedule-type.json
new file mode 100644 (file)
index 0000000..63b413c
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "service-function-scheduler-type": [
+        {
+            "type": "service-function-scheduler-type:random",
+            "enabled": true,
+            "name": "random"
+        }
+    ]
+}
diff --git a/csit/variables/sfc/master/full-deploy/service-roundrobin-schedule-type.json b/csit/variables/sfc/master/full-deploy/service-roundrobin-schedule-type.json
new file mode 100644 (file)
index 0000000..c716838
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "service-function-scheduler-type": [
+        {
+            "type": "service-function-scheduler-type:round-robin",
+            "enabled": true,
+            "name": "round-robin"
+        }
+    ]
+}