Merge branch 'branchfrom--juju-charms'
authorAdmin <Admin@etsi.org>
Fri, 23 Jun 2017 08:34:14 +0000 (10:34 +0200)
committerAdmin <Admin@etsi.org>
Fri, 23 Jun 2017 08:34:14 +0000 (10:34 +0200)
65 files changed:
.gitignore [new file with mode: 0644]
README [new file with mode: 0644]
installers/README [new file with mode: 0644]
installers/export_ips [new file with mode: 0644]
installers/install_osm.sh [new file with mode: 0755]
installers/nat_osm [new file with mode: 0755]
jenkins/README [new file with mode: 0644]
jenkins/RO/SETTINGS [new file with mode: 0644]
jenkins/RO/install [new file with mode: 0755]
jenkins/RO/start_build [new file with mode: 0755]
jenkins/SETTINGS [new file with mode: 0644]
jenkins/SO/SETTINGS [new file with mode: 0644]
jenkins/SO/install [new file with mode: 0755]
jenkins/SO/start_build [new file with mode: 0755]
jenkins/UI/SETTINGS [new file with mode: 0644]
jenkins/UI/install [new file with mode: 0755]
jenkins/UI/start_build [new file with mode: 0755]
jenkins/VCA/SETTINGS [new file with mode: 0644]
jenkins/VCA/start_build [new file with mode: 0755]
jenkins/VCA/update-lxd-image.sh [new file with mode: 0755]
jenkins/common/all_funcs [new file with mode: 0644]
jenkins/common/config [new file with mode: 0644]
jenkins/common/container [new file with mode: 0644]
jenkins/common/git_functions [new file with mode: 0644]
jenkins/common/install_common [new file with mode: 0755]
jenkins/common/logging [new file with mode: 0644]
jenkins/host/clean_container [new file with mode: 0755]
jenkins/host/install [new file with mode: 0755]
jenkins/host/start_build [new file with mode: 0755]
jenkins/osmclient/SETTINGS [new file with mode: 0644]
jenkins/osmclient/start_build [new file with mode: 0755]
jenkins/release/delete-tag.sh [new file with mode: 0755]
jenkins/release/new-tag.sh [new file with mode: 0755]
jenkins/system/Jenkinsfile [new file with mode: 0644]
jenkins/system/SETTINGS [new file with mode: 0644]
jenkins/system/delete_old_containers.sh [new file with mode: 0755]
jenkins/system/start_build [new file with mode: 0755]
jenkins/template/SETTINGS [new file with mode: 0644]
jenkins/template/start_build [new file with mode: 0755]
systest/.gitignore [new file with mode: 0644]
systest/Dockerfile [new file with mode: 0644]
systest/Jenkinsfile [new file with mode: 0644]
systest/Makefile [new file with mode: 0644]
systest/conftest.py [new file with mode: 0644]
systest/lib/__init__.py [new file with mode: 0644]
systest/lib/openstack/__init__.py [new file with mode: 0644]
systest/lib/openstack/fixtures.py [new file with mode: 0644]
systest/lib/openstack/openstack.py [new file with mode: 0644]
systest/lib/osm/__init__.py [new file with mode: 0644]
systest/lib/osm/fixtures.py [new file with mode: 0644]
systest/lib/osm/osm.py [new file with mode: 0644]
systest/lib/vim/__init__.py [new file with mode: 0644]
systest/lib/vim/fixtures.py [new file with mode: 0644]
systest/lib/vim/vim.py [new file with mode: 0644]
systest/testcases/conftest.py [new file with mode: 0644]
systest/testcases/smoke/test_smoke.py [new file with mode: 0644]
systest/testcases/vim/test_vim.py [new file with mode: 0644]
systest/testcases/vnfs/test_vnfs.py [new file with mode: 0644]
test/certs.py [new file with mode: 0644]
test/conftest.py [new file with mode: 0644]
test/example/config.yaml [new file with mode: 0644]
test/example/conftest.py [new file with mode: 0644]
test/example/test_strings.py [new file with mode: 0644]
test/test_cirros.py [new file with mode: 0644]
test/test_pingpong_osm.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d9a3498
--- /dev/null
@@ -0,0 +1,2 @@
+*.pyc
+.cache
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..df4b345
--- /dev/null
+++ b/README
@@ -0,0 +1,24 @@
+#   Copyright 2016 RIFT.IO Inc
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+
+
+README for https://osm.etsi.org/gerrit/osm/devops.git
+
+subdirectories:
+    jenkins -- scripts executed by jenkins on the container host and some initial scripts executed inside the container to start a build
+               see jenkins/README for more
+    installers -- scripts to be executed to install OSM from source, builds or packages
+               see installers/README for more
+
diff --git a/installers/README b/installers/README
new file mode 100644 (file)
index 0000000..43662cd
--- /dev/null
@@ -0,0 +1,17 @@
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+
+This directory holds the scripts and tools needed to install OSM
+
+
diff --git a/installers/export_ips b/installers/export_ips
new file mode 100644 (file)
index 0000000..d651b28
--- /dev/null
@@ -0,0 +1,25 @@
+# This file is meant to be SOURCED
+#
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+#
+# 23 Sept 2016 -- Gerardo Garcia -- Genesis
+
+#Get IP addresses
+DEFAULT_IF=`route -n |awk '$1~/^0.0.0.0/ {print $8}'`
+export DEFAULT_IP=`ip -o -4 a |grep ${DEFAULT_IF}|awk '{split($4,a,"/"); print a[1]}'`
+export VCA_CONTAINER_IP=`lxc list VCA -c 4|grep eth0 |awk '{print $2}'`
+export SO_CONTAINER_IP=`lxc list SO-ub -c 4|grep eth0 |awk '{print $2}'`
+export RO_CONTAINER_IP=`lxc list RO -c 4|grep eth0 |awk '{print $2}'`
+
diff --git a/installers/install_osm.sh b/installers/install_osm.sh
new file mode 100755 (executable)
index 0000000..f39eb41
--- /dev/null
@@ -0,0 +1,393 @@
+#!/bin/bash
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+
+function usage(){
+    echo -e "usage: $0 [OPTIONS]"
+    echo -e "Install OSM from binaries or source code (by default, from binaries)"
+    echo -e "  OPTIONS"
+    echo -e "     --uninstall:   uninstall OSM: remove the containers and delete NAT rules"
+    echo -e "     --source:      install OSM from source code using the latest stable tag"
+    echo -e "     -r <repo>:      use specified repository name for osm packages"
+    echo -e "     -R <release>:   use specified release for osm packages"
+    echo -e "     -u <repo base>: use specified repository url for osm packages"
+    echo -e "     -k <repo key>:  use specified repository public key url"
+    echo -e "     -b <refspec>:  install OSM from source code using a specific branch (master, v2.0, ...) or tag"
+    echo -e "                    -b master          (main dev branch)"
+    echo -e "                    -b v2.0            (v2.0 branch)"
+    echo -e "                    -b tags/v1.1.0     (a specific tag)"
+    echo -e "                    ..."
+    echo -e "     --develop:     (deprecated, use '-b master') install OSM from source code using the master branch"
+    echo -e "     --nat:         install only NAT rules"
+#    echo -e "     --update:      update to the latest stable release or to the latest commit if using a specific branch"
+    echo -e "     --showopts:    print chosen options and exit (only for debugging)"
+    echo -e "     -y:            do not prompt for confirmation, assumes yes"
+    echo -e "     -h / --help:   print this help"
+}
+
+#Uninstall OSM: remove containers
+function uninstall(){
+    echo -e "\nUninstalling OSM"
+    if [ $RC_CLONE ] || [ -n "$TEST_INSTALLER" ]; then
+        $OSM_DEVOPS/jenkins/host/clean_container RO
+        $OSM_DEVOPS/jenkins/host/clean_container VCA
+        $OSM_DEVOPS/jenkins/host/clean_container SO
+        #$OSM_DEVOPS/jenkins/host/clean_container UI
+    else
+        lxc stop RO && lxc delete RO
+        lxc stop VCA && lxc delete VCA
+        lxc stop SO-ub && lxc delete SO-ub
+    fi
+}
+
+#Configure NAT rules, based on the current IP addresses of containers
+function nat(){
+    echo -e "\nChecking required packages: iptables-persistent"
+    dpkg -l iptables-persistent &>/dev/null || ! echo -e "    Not installed.\nInstalling iptables-persistent requires root privileges" || \
+    sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install iptables-persistent
+    echo -e "\nConfiguring NAT rules"
+    echo -e "   Required root privileges"
+    sudo $OSM_DEVOPS/installers/nat_osm
+}
+
+#Update RO, SO and UI:
+function update(){
+    echo -e "\nUpdating components"
+
+    echo -e "     Updating RO"
+    CONTAINER="RO"
+    MDG="RO"
+    INSTALL_FOLDER="/opt/openmano"
+    echo -e "     Fetching the repo"
+    lxc exec $CONTAINER -- git -C $INSTALL_FOLDER fetch --all
+    BRANCH=""
+    BRANCH=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER status -sb | head -n1 | sed -n 's/^## \(.*\).*/\1/p'|awk '{print $1}' |sed 's/\(.*\)\.\.\..*/\1/'`
+    [ -z "$BRANCH" ] && FATAL "Could not find the current branch in use in the '$MDG'"
+    CURRENT=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER status |head -n1`
+    CURRENT_COMMIT_ID=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER rev-parse HEAD`
+    echo "         FROM: $CURRENT ($CURRENT_COMMIT_ID)"
+    # COMMIT_ID either was  previously set with -b option, or is an empty string
+    CHECKOUT_ID=$COMMIT_ID
+    [ -z "$CHECKOUT_ID" ] && [ "$BRANCH" == "HEAD" ] && CHECKOUT_ID="tags/$LATEST_STABLE_DEVOPS"
+    [ -z "$CHECKOUT_ID" ] && [ "$BRANCH" != "HEAD" ] && CHECKOUT_ID="$BRANCH"
+    if [[ $CHECKOUT_ID == "tags/"* ]]; then
+        REMOTE_COMMIT_ID=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER rev-list -n 1 $CHECKOUT_ID`
+    else
+        REMOTE_COMMIT_ID=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER rev-parse origin/$CHECKOUT_ID`
+    fi
+    echo "         TO: $CHECKOUT_ID ($REMOTE_COMMIT_ID)"
+    if [ "$CURRENT_COMMIT_ID" == "$REMOTE_COMMIT_ID" ]; then
+        echo "         Nothing to be done."
+    else
+        echo "         Update required."
+        lxc exec $CONTAINER -- service osm-ro stop
+        lxc exec $CONTAINER -- git -C /opt/openmano stash
+        lxc exec $CONTAINER -- git -C /opt/openmano pull --rebase
+        lxc exec $CONTAINER -- git -C /opt/openmano checkout $CHECKOUT_ID
+        lxc exec $CONTAINER -- git -C /opt/openmano stash pop
+        lxc exec $CONTAINER -- /opt/openmano/database_utils/migrate_mano_db.sh
+        lxc exec $CONTAINER -- service osm-ro start
+    fi
+    echo
+
+    echo -e "     Updating SO and UI"
+    CONTAINER="SO-ub"
+    MDG="SO"
+    INSTALL_FOLDER=""   # To be filled in
+    echo -e "     Fetching the repo"
+    lxc exec $CONTAINER -- git -C $INSTALL_FOLDER fetch --all
+    BRANCH=""
+    BRANCH=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER status -sb | head -n1 | sed -n 's/^## \(.*\).*/\1/p'|awk '{print $1}' |sed 's/\(.*\)\.\.\..*/\1/'`
+    [ -z "$BRANCH" ] && FATAL "Could not find the current branch in use in the '$MDG'"
+    CURRENT=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER status |head -n1`
+    CURRENT_COMMIT_ID=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER rev-parse HEAD`
+    echo "         FROM: $CURRENT ($CURRENT_COMMIT_ID)"
+    # COMMIT_ID either was  previously set with -b option, or is an empty string
+    CHECKOUT_ID=$COMMIT_ID
+    [ -z "$CHECKOUT_ID" ] && [ "$BRANCH" == "HEAD" ] && CHECKOUT_ID="tags/$LATEST_STABLE_DEVOPS"
+    [ -z "$CHECKOUT_ID" ] && [ "$BRANCH" != "HEAD" ] && CHECKOUT_ID="$BRANCH"
+    if [[ $CHECKOUT_ID == "tags/"* ]]; then
+        REMOTE_COMMIT_ID=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER rev-list -n 1 $CHECKOUT_ID`
+    else
+        REMOTE_COMMIT_ID=`lxc exec $CONTAINER -- git -C $INSTALL_FOLDER rev-parse origin/$CHECKOUT_ID`
+    fi
+    echo "         TO: $CHECKOUT_ID ($REMOTE_COMMIT_ID)"
+    if [ "$CURRENT_COMMIT_ID" == "$REMOTE_COMMIT_ID" ]; then
+        echo "         Nothing to be done."
+    else
+        echo "         Update required."
+        # Instructions to be added
+        # lxc exec SO-ub -- ...
+    fi
+    echo
+}
+
+function so_is_up(){
+    SO_IP=$1
+    time=0
+    step=5
+    timelength=300
+    while [ $time -le $timelength ]
+    do
+        curl -k https://$SO_IP:8008/api/operational/vcs/info \
+              --header 'accept: application/vnd.yang.data+json' \
+              --header 'authorization: Basic YWRtaW46YWRtaW4=' \
+              --header 'cache-control: no-cache' \
+              --header 'content-type: application/vnd.yang.data+json' &> /dev/null
+        RET=$?
+        if [ "$RET" == 0 ]; then
+            break
+        fi
+        sleep $step
+        echo -n "."
+        time=$((time+step))
+    done
+    if [ "$RET" != 0 ]; then
+        FATAL "OSM Failed to startup"
+    fi
+    echo
+}
+
+#Configure VCA, SO and RO with the initial configuration:
+#  RO -> tenant:osm, logs to be sent to SO
+#  VCA -> juju-password
+#  SO -> route to Juju Controller, add RO account, add VCA account
+function configure(){
+    #Configure components
+    echo -e "\nConfiguring components"
+    . $OSM_DEVOPS/installers/export_ips
+
+    echo -e "       Configuring RO"
+    lxc exec RO -- sed -i -e "s/^\#\?log_socket_host:.*/log_socket_host: $SO_CONTAINER_IP/g" /etc/osm/openmanod.cfg
+    lxc exec RO -- service osm-ro restart
+
+    time=0; step=2; timelength=20; while [ $time -le $timelength ]; do sleep $step; echo -n "."; time=$((time+step)); done; echo
+
+    lxc exec RO -- openmano tenant-delete -f osm >/dev/null
+    RO_TENANT_ID=`lxc exec RO -- openmano tenant-create osm |awk '{print $1}'`
+    lxc exec RO -- sed -i '/export OPENMANO_TENANT=osm/d' .bashrc 
+    lxc exec RO -- sed -i '$ i export OPENMANO_TENANT=osm' .bashrc
+    #lxc exec RO -- sh -c 'echo "export OPENMANO_TENANT=osm" >> .bashrc'
+
+    echo -e "       Configuring VCA"
+    JUJU_PASSWD=`date +%s | sha256sum | base64 | head -c 32`
+    echo -e "$JUJU_PASSWD\n$JUJU_PASSWD" | lxc exec VCA -- juju change-user-password
+    JUJU_CONTROLLER_IP=`lxc exec VCA -- lxc list -c 4 |grep eth0 |awk '{print $2}'`
+
+    echo -e "       Configuring SO"
+    sudo route add -host $JUJU_CONTROLLER_IP gw $VCA_CONTAINER_IP
+    sudo sed -i "$ i route add -host $JUJU_CONTROLLER_IP gw $VCA_CONTAINER_IP" /etc/rc.local
+    lxc exec SO-ub -- systemctl restart launchpad
+
+    so_is_up $SO_CONTAINER_IP
+
+    #delete existing config agent (could be there on reconfigure)
+    curl -k --request DELETE \
+      --url https://$SO_CONTAINER_IP:8008/api/config/config-agent/account/osmjuju \
+      --header 'accept: application/vnd.yang.data+json' \
+      --header 'authorization: Basic YWRtaW46YWRtaW4=' \
+      --header 'cache-control: no-cache' \
+      --header 'content-type: application/vnd.yang.data+json' &> /dev/null
+
+    result=$(curl -k --request POST \
+      --url https://$SO_CONTAINER_IP:8008/api/config/config-agent \
+      --header 'accept: application/vnd.yang.data+json' \
+      --header 'authorization: Basic YWRtaW46YWRtaW4=' \
+      --header 'cache-control: no-cache' \
+      --header 'content-type: application/vnd.yang.data+json' \
+      --data '{"account": [ { "name": "osmjuju", "account-type": "juju", "juju": { "ip-address": "'$JUJU_CONTROLLER_IP'", "port": "17070", "user": "admin", "secret": "'$JUJU_PASSWD'" }  }  ]}')
+    [[ $result =~ .*success.* ]] || FATAL "Failed config-agent configuration: $result"
+
+    result=$(curl -k --request PUT \
+      --url https://$SO_CONTAINER_IP:8008/api/config/resource-orchestrator \
+      --header 'accept: application/vnd.yang.data+json' \
+      --header 'authorization: Basic YWRtaW46YWRtaW4=' \
+      --header 'cache-control: no-cache' \
+      --header 'content-type: application/vnd.yang.data+json' \
+      --data '{ "openmano": { "host": "'$RO_CONTAINER_IP'", "port": "9090", "tenant-id": "'$RO_TENANT_ID'" }, "name": "osmopenmano", "account-type": "openmano" }')
+    [[ $result =~ .*success.* ]] || FATAL "Failed resource-orchestrator configuration: $result"
+}
+
+function install_lxd() {
+    lxd init --auto
+    lxd waitready
+    systemctl stop lxd-bridge
+    systemctl --system daemon-reload
+    systemctl enable lxd-bridge
+    systemctl start lxd-bridge
+}
+
+function ask_user(){
+    # ask to the user and parse a response among 'y', 'yes', 'n' or 'no'. Case insensitive
+    # Params: $1 text to ask;   $2 Action by default, can be 'y' for yes, 'n' for no, other or empty for not allowed
+    # Return: true(0) if user type 'yes'; false (1) if user type 'no'
+    read -e -p "$1" USER_CONFIRMATION
+    while true ; do
+        [ -z "$USER_CONFIRMATION" ] && [ "$2" == 'y' ] && return 0
+        [ -z "$USER_CONFIRMATION" ] && [ "$2" == 'n' ] && return 1
+        [ "${USER_CONFIRMATION,,}" == "yes" ] || [ "${USER_CONFIRMATION,,}" == "y" ] && return 0
+        [ "${USER_CONFIRMATION,,}" == "no" ]  || [ "${USER_CONFIRMATION,,}" == "n" ] && return 1
+        read -e -p "Please type 'yes' or 'no': " USER_CONFIRMATION
+    done
+}
+
+UNINSTALL=""
+DEVELOP=""
+NAT=""
+UPDATE=""
+RECONFIGURE=""
+TEST_INSTALLER=""
+LXD=""
+SHOWOPTS=""
+COMMIT_ID=""
+ASSUME_YES=""
+INSTALL_FROM_SOURCE=""
+
+while getopts ":hy-:b:r:k:u:R:" o; do
+    case "${o}" in
+        h)
+            usage && exit 0
+            ;;
+        b)
+            COMMIT_ID=${OPTARG}
+            ;;
+        r)
+            REPOSITORY="-r ${OPTARG}"
+            ;;
+        R)
+            RELEASE="-R ${OPTARG}"
+            ;;
+        k)
+            REPOSITORY_KEY="-k ${OPTARG}"
+            ;;
+        u)
+            REPOSITORY_BASE="-u ${OPTARG}"
+            ;;
+        -)
+            [ "${OPTARG}" == "help" ] && usage && exit 0
+            [ "${OPTARG}" == "source" ] && INSTALL_FROM_SOURCE="y" && continue
+            [ "${OPTARG}" == "develop" ] && DEVELOP="y" && continue
+            [ "${OPTARG}" == "uninstall" ] && UNINSTALL="y" && continue
+            [ "${OPTARG}" == "nat" ] && NAT="y" && continue
+            [ "${OPTARG}" == "update" ] && UPDATE="y" && continue
+            [ "${OPTARG}" == "reconfigure" ] && RECONFIGURE="y" && continue
+            [ "${OPTARG}" == "test" ] && TEST_INSTALLER="y" && continue
+            [ "${OPTARG}" == "lxd" ] && LXD="y" && continue
+            [ "${OPTARG}" == "showopts" ] && SHOWOPTS="y" && continue
+            echo -e "Invalid option: '--$OPTARG'\n" >&2
+            usage && exit 1
+            ;;
+        \?)
+            echo -e "Invalid option: '-$OPTARG'\n" >&2
+            usage && exit 1
+            ;;
+        y)
+            ASSUME_YES="y"
+            ;;
+        *)
+            usage && exit 1
+            ;;
+    esac
+done
+
+if [ -n "$SHOWOPTS" ]; then
+    echo "DEVELOP=$DEVELOP"
+    echo "INSTALL_FROM_SOURCE=$INSTALL_FROM_SOURCE"
+    echo "UNINSTALL=$UNINSTALL"
+    echo "NAT=$NAT"
+    echo "UPDATE=$UPDATE"
+    echo "RECONFIGURE=$RECONFIGURE"
+    echo "TEST_INSTALLER=$TEST_INSTALLER"
+    echo "LXD=$LXD"
+    echo "SHOWOPTS=$SHOWOPTS"
+    echo "Install from specific refspec (-b): $COMMIT_ID"
+    exit 0
+fi
+
+# if develop, we force master
+[ -z "$COMMIT_ID" ] && [ -n "$DEVELOP" ] && COMMIT_ID="master"
+
+# if master, force install from source
+[ -n "$COMMIT_ID" ] && [ "$COMMIT_ID" == "master" ] && INSTALL_FROM_SOURCE="y"
+
+if [ -n "$TEST_INSTALLER" ]; then
+    echo -e "\nUsing local devops repo for OSM installation"
+    TEMPDIR="$(dirname $(realpath $(dirname $0)))"
+else
+    echo -e "\nCreating temporary dir for OSM installation"
+    TEMPDIR="$(mktemp -d -q --tmpdir "installosm.XXXXXX")"
+    trap 'rm -rf "$TEMPDIR"' EXIT
+fi
+
+echo -e "Checking required packages: git"
+dpkg -l git &>/dev/null || ! echo -e "     git not installed.\nInstalling git requires root privileges" || sudo apt-get install -y git
+if [ -z "$TEST_INSTALLER" ]; then
+    echo -e "\nCloning devops repo temporarily"
+    git clone https://osm.etsi.org/gerrit/osm/devops.git $TEMPDIR
+    RC_CLONE=$?
+fi
+
+echo -e "\nGuessing the current stable release"
+LATEST_STABLE_DEVOPS=`git -C $TEMPDIR tag -l v[0-9].* | tail -n1`
+[ -z "$COMMIT_ID" ] && [ -z "$LATEST_STABLE_DEVOPS" ] && echo "Could not find the current latest stable release" && exit 0
+echo "Latest tag in devops repo: $LATEST_STABLE_DEVOPS"
+[ -z "$COMMIT_ID" ] && [ -n "$LATEST_STABLE_DEVOPS" ] && COMMIT_ID="tags/$LATEST_STABLE_DEVOPS"
+[ -z "$TEST_INSTALLER" ] && git -C $TEMPDIR checkout tags/$LATEST_STABLE_DEVOPS
+
+OSM_DEVOPS=$TEMPDIR
+OSM_JENKINS="$TEMPDIR/jenkins"
+. $OSM_JENKINS/common/all_funcs
+
+[ -n "$UNINSTALL" ] && uninstall && echo -e "\nDONE" && exit 0
+[ -n "$NAT" ] && nat && echo -e "\nDONE" && exit 0
+[ -n "$UPDATE" ] && update && echo -e "\nDONE" && exit 0
+[ -n "$RECONFIGURE" ] && configure && echo -e "\nDONE" && exit 0
+
+#Installation starts here
+echo -e "\nInstalling OSM from refspec: $COMMIT_ID"
+if [ -n "$INSTALL_FROM_SOURCE" ] && [ -z "$ASSUME_YES" ]; then 
+    ! ask_user "The installation will take about 75-90 minutes. Continue (Y/n)? " y && echo "Cancelled!" && exit 1
+fi
+
+echo -e "\nChecking required packages: wget, curl, tar"
+dpkg -l wget curl tar &>/dev/null || ! echo -e "    One or several packages are not installed.\nInstalling required packages\n     Root privileges are required" || sudo apt-get install -y wget curl tar
+
+echo -e "Checking required packages: lxd"
+lxd --version &>/dev/null || FATAL "lxd not present, exiting."
+[ -n "$LXD" ] && echo -e "\nConfiguring lxd" && install_lxd
+
+wget -q -O- https://osm-download.etsi.org/ftp/osm-2.0-two/README.txt &> /dev/null
+
+if [ -z "$INSTALL_FROM_SOURCE" ]; then
+    echo -e "\nCreating the containers and installing from binaries ..."
+    $OSM_DEVOPS/jenkins/host/install RO $REPOSITORY $RELEASE $REPOSITORY_KEY $REPOSITORY_BASE || FATAL "RO install failed"
+    $OSM_DEVOPS/jenkins/host/start_build VCA || FATAL "VCA install failed"
+    $OSM_DEVOPS/jenkins/host/install SO $REPOSITORY $RELEASE $REPOSITORY_KEY $REPOSITORY_BASE || FATAL "SO install failed"
+    $OSM_DEVOPS/jenkins/host/install UI $REPOSITORY $RELEASE $REPOSITORY_KEY $REPOSITORY_BASE || FATAL "UI install failed"
+else #install from source
+    echo -e "\nCreating the containers and building from source ..."
+    $OSM_DEVOPS/jenkins/host/start_build RO --notest checkout $COMMIT_ID || FATAL "RO container build failed (refspec: '$COMMIT_ID')"
+    $OSM_DEVOPS/jenkins/host/start_build VCA || FATAL "VCA container build failed"
+    $OSM_DEVOPS/jenkins/host/start_build SO checkout $COMMIT_ID || FATAL "SO container build failed (refspec: '$COMMIT_ID')"
+    $OSM_DEVOPS/jenkins/host/start_build UI checkout $COMMIT_ID || FATAL "UI container build failed (refspec: '$COMMIT_ID')"
+fi
+
+#Install iptables-persistent and configure NAT rules
+nat
+
+#Configure components
+configure
+
+wget -q -O- https://osm-download.etsi.org/ftp/osm-2.0-two/README2.txt &> /dev/null
+echo -e "\nDONE"
diff --git a/installers/nat_osm b/installers/nat_osm
new file mode 100755 (executable)
index 0000000..0ff4f61
--- /dev/null
@@ -0,0 +1,180 @@
+#!/bin/bash
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+
+############
+# Functions
+############
+usage(){
+    echo -e "usage: $0 [OPTIONS]"
+    echo -e "Install NAT rules for OSM"
+    echo -e "  OPTIONS"
+    echo -e "     -u:  UI/SO (rift) IP address"
+    echo -e "     -r:  RO (openmano) IP address"
+    echo -e "     -v:  VCA (juju) IP address"
+    echo -e "     -h:  show this help"
+}
+
+###################
+# End of functions
+###################
+
+#Check root privileges
+[ "$USER" != "root" ] && echo "Needed root privileges (run with sudo)" >&2 && exit 1
+
+HERE=$(realpath $(dirname $0))
+OSM_DEVOPS=$(dirname $HERE)
+OSM_JENKINS="$OSM_DEVOPS/jenkins"
+. $OSM_JENKINS/common/all_funcs
+
+#Get default IP address
+. $OSM_DEVOPS/installers/export_ips
+
+UI_IP=$DEFAULT_IP
+RO_IP=$DEFAULT_IP
+VCA_IP=$DEFAULT_IP
+
+#read input options
+while getopts ":u:r:v:h-:" o; do
+    case "${o}" in
+        u)
+            export UI_IP="$OPTARG"
+            ;;
+        r)
+            export RO_IP="$OPTARG"
+            ;;
+        v)
+            export VCA_IP="$OPTARG"
+            ;;
+        h)
+            usage && exit 0
+            ;;
+        -)
+            [ "${OPTARG}" == "help" ] && usage && exit 0
+            echo -e "Invalid option: '--$OPTARG'\nTry $0 --help for more information" >&2
+            exit 1
+            ;;
+        \?)
+            echo -e "Invalid option: '-$OPTARG'\nTry $0 --help for more information" >&2
+            exit 1
+            ;;
+        :)
+            echo -e "Option '-$OPTARG' requires an argument\nTry $0 --help for more information" >&2
+            exit 1
+            ;;
+        *)
+            usage >&2
+            exit -1
+            ;;
+    esac
+done
+
+#############
+# NAT port forwarding configuration
+#############
+echo
+echo "*** Configuring iptables rules ***"
+
+awk -v RO_IP="$RO_IP" -v VCA_IP="$VCA_IP" -v UI_IP="$UI_IP" -v openmano_ip="$RO_CONTAINER_IP" -v rift_ip="$SO_CONTAINER_IP" -v juju_ip="$VCA_CONTAINER_IP" '
+BEGIN {innat=0; innatpre=0; osmpre=0; donepre=0; innatpost=0; osmpost=0; donepost=0}
+/^\*nat/ {
+    innat=1;
+    print;
+    next
+}
+innat==1 && /\:PREROUTING/ {
+    innatpre=1;
+    print;
+    next;
+}
+innatpre==1 && /\#Autogenerated by nat_osm/ {
+    osmpre=1;
+    next;
+}
+osmpre==1 && /#End autogeneration by nat_osm/ {
+    print "#Autogenerated by nat_osm"
+    print "-A PREROUTING -d "RO_IP" -p tcp -m tcp --dport 9090 -j DNAT --to-destination "openmano_ip
+    print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 8000 -j DNAT --to-destination "rift_ip
+    print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 4567 -j DNAT --to-destination "rift_ip
+    print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 8443 -j DNAT --to-destination "rift_ip
+    print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 8008 -j DNAT --to-destination "rift_ip
+    print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 80 -j DNAT --to-destination "rift_ip
+    #print "-A PREROUTING -d "VCA_IP" -p tcp -m tcp --dport 443 -j DNAT --to-destination "juju_ip
+    #print "-A PREROUTING -d "VCA_IP" -p tcp -m tcp --dport 17070 -j DNAT --to-destination "juju_ip
+    print "#End autogeneration by nat_osm"
+    osmpre=0;
+    donepre=1;
+    next;
+}
+osmpre==1 {next;}
+innatpre==1 && /\:INPUT/ {
+    innatpre=0;
+    if (donepre==0) {
+        print "#Autogenerated by nat_osm"
+        print "-A PREROUTING -d "RO_IP" -p tcp -m tcp --dport 9090 -j DNAT --to-destination "openmano_ip
+        print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 8000 -j DNAT --to-destination "rift_ip
+        print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 4567 -j DNAT --to-destination "rift_ip
+        print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 8443 -j DNAT --to-destination "rift_ip
+        print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 8008 -j DNAT --to-destination "rift_ip
+        print "-A PREROUTING -d "UI_IP" -p tcp -m tcp --dport 80 -j DNAT --to-destination "rift_ip
+        #print "-A PREROUTING -d "VCA_IP" -p tcp -m tcp --dport 443 -j DNAT --to-destination "juju_ip
+        #print "-A PREROUTING -d "VCA_IP" -p tcp -m tcp --dport 17070 -j DNAT --to-destination "juju_ip
+        print "#End autogeneration by nat_osm"
+        donepre=1;
+    }
+    print;
+    next;
+}
+
+innat==1 && /\:POSTROUTING/ {
+    innatpost=1;
+    print;
+    next;
+}
+innatpost==1 && /\#Autogenerated by nat_osm/ {
+    osmpost=1;
+    next;
+}
+osmpost==1 && /#End autogeneration by nat_osm/ {
+    print "#Autogenerated by nat_osm"
+    print "-A POSTROUTING -s "rift_ip"/24 -d "rift_ip" -p tcp --dport 8443 -j MASQUERADE"
+    #print "-A POSTROUTING -s "rift_ip" -p tcp -m tcp --dport 9090 -d "openmano_ip" -j SNAT --to "UI_IP
+    #print "-A POSTROUTING -s "rift_ip" -p tcp -m tcp --dport 17070 -d "juju_ip" -j SNAT --to "UI_IP
+    print "#End autogeneration by nat_osm"
+    osmpost=0;
+    donepost=1;
+    next;
+}
+osmpost==1 {next;}
+innatpost==1 && /COMMIT/ {
+    innatpost=0;
+    innat=0;
+    if (donepost==0) {
+        print "#Autogenerated by nat_osm"
+        print "-A POSTROUTING -s "rift_ip"/24 -d "rift_ip" -p tcp --dport 8443 -j MASQUERADE"
+        #print "-A POSTROUTING -s "rift_ip" -p tcp -m tcp --dport 9090 -d "openmano_ip" -j SNAT --to "UI_IP
+        #print "-A POSTROUTING -s "rift_ip" -p tcp -m tcp --dport 17070 -d "juju_ip" -j SNAT --to "UI_IP
+        print "#End autogeneration by nat_osm"
+        donepost=1;
+    }
+    print;
+    next;
+}
+{
+    print
+}
+' /etc/iptables/rules.v4 > testfile.tmp && mv testfile.tmp /etc/iptables/rules.v4
+
+service netfilter-persistent restart
+
diff --git a/jenkins/README b/jenkins/README
new file mode 100644 (file)
index 0000000..14e43b7
--- /dev/null
@@ -0,0 +1,24 @@
+#   Copyright 2016 RIFT.IO 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.
+
+This directory holds the scripts and tools needed by jenkins to run jobs
+
+The 'host' subdirectory is meant to be invoked directly by jenkins either in its own container or on the host.
+
+The 'template' subdirectory contains sample files needed to configure a new MDG
+
+The other subdirectories correspond to MDGs and contain the scripts that are run inside the container
+
+documentation is in the OSM wiki. See https://osm.etsi.org/wiki/index.php/Jenkins_Build_Scripts
+
diff --git a/jenkins/RO/SETTINGS b/jenkins/RO/SETTINGS
new file mode 100644 (file)
index 0000000..8c37f16
--- /dev/null
@@ -0,0 +1,28 @@
+#
+#   Copyright 2016 Telefónica Investigación y Desarrollo, S.A.U.
+#
+#   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.
+#
+# Authors:
+#    - Gerardo Garcia - gerardo.garciadeblas@telefonica.com
+#
+# this variable holds the name of the container image needed to build or run this product
+export OSM_BASE_IMAGE=ubuntu:16.04
+#
+# this variable holds the name of the container to be used to build a package
+# if this container already exists, the build process can skip the container build
+export OSM_BUILD_CONTAINER=RO
+#
+# this variable holds the name of the container to be used to run a package
+# if this container already exists, the run processes can skip the container build
+export OSM_RUNTIME_CONTAINER=RO
diff --git a/jenkins/RO/install b/jenkins/RO/install
new file mode 100755 (executable)
index 0000000..d2eaf58
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/bash
+#
+#   Copyright 2016 Telefónica Investigación y Desarrollo, S.A.U.
+#
+#   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.
+# 
+# Authors:
+#    - Gerardo Garcia - gerardo.garciadeblas@telefonica.com
+# 
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+# SET YOUR MDG repository name here
+export OSM_MDG=RO
+OSM_load_config
+
+. $OSM_JENKINS/common/install_common
+
+# Installation starts here
+
+#Release TWO
+
+apt-get update
+apt-get -y install python-lib-osm-openvim
+apt-get -y install python-osm-ro
+
+OSMLIBOVIM_PATH=`python -c 'import lib_osm_openvim; print lib_osm_openvim.__path__[0]'` || FATAL "lib-osm-openvim was not properly installed"
+OSMRO_PATH=`python -c 'import osm_ro; print osm_ro.__path__[0]'` || FATAL "osm-ro was not properly installed"
+sed -i "s/\${DIRNAME}\/\.\.\/openmanod\ -v/openmanod\ -v/g" /usr/lib/python2.7/dist-packages/osm_ro/database_utils/migrate_mano_db.sh
+systemctl disable osm-ro.service
+sed -i "/User=/d" /etc/systemd/system/osm-ro.service
+sed -i "s/ExecStart=openmanod/ExecStart=\/usr\/bin\/openmanod/" /etc/systemd/system/osm-ro.service
+systemctl enable osm-ro.service
+
+DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server
+
+${OSMRO_PATH}/database_utils/install-db-server.sh --updatedb --no-install-packages || FATAL "osm-ro db installation failed"
+${OSMLIBOVIM_PATH}/database_utils/install-db-server.sh -u mano -p manopw -d mano_vim_db --updatedb || FATAL "lib-osm-openvim db installation failed"
+service osm-ro restart
+
+RC=$?
+INFO "done, RC=$RC"
+exit $RC
+
+
diff --git a/jenkins/RO/start_build b/jenkins/RO/start_build
new file mode 100755 (executable)
index 0000000..01474ee
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/bash
+#
+#   Copyright 2016 Telefónica Investigación y Desarrollo, S.A.U.
+#
+#   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.
+# 
+# Authors:
+#    - Gerardo Garcia - gerardo.garciadeblas@telefonica.com
+# 
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+# SET YOU MDG repository name here
+export OSM_MDG=RO
+OSM_load_config
+
+NOTEST=""
+if [ "$1" = "--notest" ]; then
+    shift
+    NOTEST="y"
+fi
+
+OSM_git_checkout "$@"
+
+INFO "installing RO packages and dependencies from current repo (--noclone)"
+./scripts/install-openmano.sh --noclone --force -q
+RC=$?
+
+if [ -n "$NOTEST" ]; then
+    INFO "done, RC=$RC"
+    exit $RC
+fi
+
+INFO "starting build"
+
+INFO "  cleaning .pyc"
+rm -f *.pyc
+
+INFO "  compiling *.py"
+TEMPFILE="$(mktemp -q -p . "openmanolinker.XXXXXX.py")"
+trap 'rm -f "$TEMPFILE"' EXIT
+for i in `ls vimconn_*.py |sed "s/\.py//"`; do echo "import $i" >> $TEMPFILE; done
+
+python $TEMPFILE &&
+python -m py_compile *.py  # &&
+
+#INFO "  basic_test"         &&
+#./test/basictest.sh --force --insert-bashrc --install-openvim --init-openvim  #&&   #uncomment to add new tests
+# OTHER TESTS HERE
+
+RC=$?
+INFO "done, RC=$RC"
+exit $RC
+
+
diff --git a/jenkins/SETTINGS b/jenkins/SETTINGS
new file mode 100644 (file)
index 0000000..c0a2c1f
--- /dev/null
@@ -0,0 +1,30 @@
+#   Copyright 2016 RIFT.IO 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.
+# 
+# Settings that are global to this installation
+# MDG specific settings can be found in each MDG directory
+# 
+# 24 June 2016 -- Jeremy Mordkoff -- Genesis
+#
+# base url for all repositories
+OSM_GIT_URL=https://osm.etsi.org/gerrit/osm
+#
+# OSM_USE_LOCAL_DEVOPS
+#
+# this option disables the clone inside the
+# the container and instead copies this directory tree
+# into the container. Very useful for testing
+# default is false
+#
+# OSM_USE_LOCAL_DEVOPS=true
diff --git a/jenkins/SO/SETTINGS b/jenkins/SO/SETTINGS
new file mode 100644 (file)
index 0000000..995e01d
--- /dev/null
@@ -0,0 +1,37 @@
+#   Copyright 2016 RIFT.IO 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.
+#
+# sample SETTINGS file
+#
+# 24 June 2016 -- Jeremy Mordkoff -- Genesis 
+#
+# this variable holds the name of the container image needed to build or run this product
+export OSM_BASE_IMAGE=ubuntu:16.04
+#
+# this variable holds the name of the container to be used to build a package
+# if this container already exists, the build process can skip the container build
+export OSM_BUILD_CONTAINER=SO-ub
+#
+# this variable must be set to allow creating the build container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+#export OSM_BUILD_CONTAINER_PRIVILEGED=yes
+#
+# this variable holds the name of the container to be used to run a package
+# if this container already exists, the run processes can skip the container build
+export OSM_RUNTIME_CONTAINER=SO-ub
+#
+# this variable must be set to allow creating the runtime container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+#export OSM_RUNTIME_CONTAINER_PRIVILEGED=yes
+
diff --git a/jenkins/SO/install b/jenkins/SO/install
new file mode 100755 (executable)
index 0000000..d881a42
--- /dev/null
@@ -0,0 +1,133 @@
+#!/usr/bin/env bash
+#
+#   Copyright 2017 RIFT.IO 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.
+#
+# Author(s): Jeremy Mordkoff
+# Creation Date: 26 April 2017
+#
+#
+
+# INSTALL.sh
+# install launchpad SO and all of its dependencies
+#
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/install_common
+
+# Defensive bash programming flags
+set -o errexit    # Exit on any error
+trap 'echo ERROR: Command failed: \"$BASH_COMMAND\"' ERR
+set -o nounset    # Expanding an unset variable is an error.  Variables must be
+                  # set before they can be used.
+
+###############################################################################
+# Set up repo and version
+PLATFORM_REPOSITORY=OSM
+PLATFORM_VERSION=4.4.2.1.61839
+
+while getopts ":P:V:h" o; do
+    case "${o}" in
+        P)
+            PLATFORM_REPOSITORY=${OPTARG}
+            ;;
+        V)
+            PLATFORM_VERSION=${OPTARG}
+            ;;
+        h)
+            usage
+            exit 0
+            ;;
+        *)
+            usage
+            exit 1
+            ;;
+    esac
+done
+
+function usage() {
+    echo
+    echo "NAME:"
+    echo "  $0"
+    echo
+    echo "SYNOPSIS:"
+    echo "  $0 -h|--help"
+    echo "  $0 -P <PLATFORM_REPOSITORY> -V <PLATFORM_VERSION>"
+    echo
+    echo "DESCRIPTION:"
+    echo "  Prepare current system to run SO and UI."
+    echo
+    echo "  PLATFORM_REPOSITORY (optional): name of the RIFT.ware repository."
+    echo "  PLATFORM_VERSION (optional): version of the platform packages to be installed."
+    echo
+}
+
+
+###############################################################################
+# Main block
+
+# enable the right repos
+curl http://repos.riftio.com/public/xenial-riftware-public-key | apt-key add -
+curl -o /etc/apt/sources.list.d/RIFT.list http://buildtracker.riftio.com/repo_file/ub16/${PLATFORM_REPOSITORY}/
+
+# Make the Rift repo a higher priority to work around version conflicts.
+cat <<EOF > /etc/apt/preferences.d/rift
+Package: *
+Pin: origin repos.riftio.com
+Pin-Priority: 600
+EOF
+
+apt-get update
+
+# and install the tools
+apt remove -y rw.toolchain-rwbase tcpdump
+apt-get install -y --allow-downgrades rw.tools-container-tools=${PLATFORM_VERSION} rw.tools-scripts=${PLATFORM_VERSION} python
+/usr/rift/container_tools/mkcontainer --modes ext --modes platform --rw-version ${PLATFORM_VERSION}
+pip3 install lxml==3.4.0
+
+chmod 777 /usr/rift /usr/rift/usr/share
+
+# now disable the RIFT OSM repo so that we'll get MANO from
+# the OSM repos
+rm -f /etc/apt/sources.list.d/RIFT.list
+
+apt-get update
+
+apt-get install -y \
+            rw.core.mano-rwcal_yang_ylib-1.0 \
+            rw.core.mano-rwconfig_agent_yang_ylib-1.0 \
+            rw.core.mano-rwlaunchpad_yang_ylib-1.0 \
+            rw.core.mano-mano_yang_ylib-1.0 \
+            rw.core.mano-common-1.0 \
+            rw.core.mano-rwsdn_yang_ylib-1.0 \
+            rw.core.mano-rwsdnal_yang_ylib-1.0 \
+            rw.core.mano-mano-types_yang_ylib-1.0 \
+            rw.core.mano-rwcal-cloudsim-1.0 \
+            rw.core.mano-rwcal-1.0 \
+            rw.core.mano-rw_conman_yang_ylib-1.0 \
+            rw.core.mano-rwcalproxytasklet-1.0 \
+            rw.core.mano-rwlaunchpad-1.0 \
+            rw.core.mano-rwcal-openmano-vimconnector-1.0 \
+            rw.core.mano-lpmocklet_yang_ylib-1.0 \
+            rw.core.mano-rwmon-1.0 \
+            rw.core.mano-rwcloud_yang_ylib-1.0 \
+            rw.core.mano-rwcal-openstack-1.0 \
+            rw.core.mano-rw.core.mano_foss \
+            rw.core.mano-rwmon_yang_ylib-1.0 \
+            rw.core.mano-rwcm-1.0 \
+            rw.core.mano-rwcal-mock-1.0 \
+            rw.core.mano-rwcal-cloudsimproxy-1.0 \
+            rw.core.mano-models-1.0 \
+            rw.core.mano-rwcal-aws-1.0
diff --git a/jenkins/SO/start_build b/jenkins/SO/start_build
new file mode 100755 (executable)
index 0000000..a672e14
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/bash
+#   Copyright 2016 RIFT.IO 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.
+# 
+# TEMPLATE script to start a build. This is run inside a container
+#
+# 6 July 2016 -- Jeremy.Mordkoff@riftio.com -- adapted from the riftware version
+# 
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+# SET YOU MDG repository name here
+export OSM_MDG=SO
+OSM_load_config
+OSM_git_checkout "$@"
+
+trap 'WARNING "INTERRUPT"; exit 1' INT
+
+INFO "starting build"
+make clean || FATAL "make clean failed"
+./BUILD.sh
+
+RC=$?
+
+INFO "done, RC=$RC"
+exit $RC
+
+
diff --git a/jenkins/UI/SETTINGS b/jenkins/UI/SETTINGS
new file mode 100644 (file)
index 0000000..995e01d
--- /dev/null
@@ -0,0 +1,37 @@
+#   Copyright 2016 RIFT.IO 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.
+#
+# sample SETTINGS file
+#
+# 24 June 2016 -- Jeremy Mordkoff -- Genesis 
+#
+# this variable holds the name of the container image needed to build or run this product
+export OSM_BASE_IMAGE=ubuntu:16.04
+#
+# this variable holds the name of the container to be used to build a package
+# if this container already exists, the build process can skip the container build
+export OSM_BUILD_CONTAINER=SO-ub
+#
+# this variable must be set to allow creating the build container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+#export OSM_BUILD_CONTAINER_PRIVILEGED=yes
+#
+# this variable holds the name of the container to be used to run a package
+# if this container already exists, the run processes can skip the container build
+export OSM_RUNTIME_CONTAINER=SO-ub
+#
+# this variable must be set to allow creating the runtime container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+#export OSM_RUNTIME_CONTAINER_PRIVILEGED=yes
+
diff --git a/jenkins/UI/install b/jenkins/UI/install
new file mode 100755 (executable)
index 0000000..4ba7123
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+# 
+#   Copyright 2017 RIFT.IO 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.
+#
+# Author(s): Jeremy Mordkoff
+# Creation Date: 26 April 2017
+# 
+#
+
+# INSTALL.sh
+# install launchpad UI and create the service
+#
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/install_common
+
+rm -f /etc/apt/sources.list.d/RIFT.list 
+apt-get update
+
+apt-get install -y rw.ui-skyquake
+
+echo "Creating Service ...."
+/usr/rift/bin/create_launchpad_service
+
diff --git a/jenkins/UI/start_build b/jenkins/UI/start_build
new file mode 100755 (executable)
index 0000000..50b2e06
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/bash
+#   Copyright 2016 RIFT.IO 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.
+# 
+# TEMPLATE script to start a build. This is run inside a container
+#
+# 6 July 2016 -- Jeremy.Mordkoff@riftio.com -- adapted from the riftware version
+# 
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+# SET YOU MDG repository name here
+export OSM_MDG=UI
+OSM_load_config
+OSM_git_checkout "$@"
+
+
+INFO "starting build"
+make clean || FATAL "Make clean failed"
+make -j16 || FATAL "Make failed"
+sudo make install || FATAL "Make install Failed"
+
+INFO "build done"
+exit 0
+
+
diff --git a/jenkins/VCA/SETTINGS b/jenkins/VCA/SETTINGS
new file mode 100644 (file)
index 0000000..ded5043
--- /dev/null
@@ -0,0 +1,44 @@
+#   Copyright 2016 Telefónica Investigación y Desarrollo, S.A.U.
+#
+#   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.
+#
+# sample SETTINGS file
+#
+# Authors:
+#     - Gerardo Garcia
+#
+# this variable holds the name of the container image needed to build or run this product
+export OSM_BASE_IMAGE=ubuntu:16.04
+#
+# this variable holds the name of the container to be used to build a package
+# if this container already exists, the build process can skip the container build
+export OSM_BUILD_CONTAINER=VCA
+#
+# this variable must be set to allow creating the build container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+export OSM_BUILD_CONTAINER_PRIVILEGED=yes
+#
+# this variable must be set to allow ensted containers in the build container
+export OSM_BUILD_CONTAINER_ALLOW_NESTED=yes
+#
+# this variable holds the name of the container to be used to run a package
+# if this container already exists, the run processes can skip the container build
+export OSM_RUNTIME_CONTAINER=VCA
+#
+# this variable must be set to allow creating the runtime container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+export OSM_RUNTIME_CONTAINER_PRIVILEGED=yes
+#
+# this variable must be set to allow ensted containers in the build container
+export OSM_RUNTIME_CONTAINER_ALLOW_NESTED=yes
+#
diff --git a/jenkins/VCA/start_build b/jenkins/VCA/start_build
new file mode 100755 (executable)
index 0000000..d6ccfd8
--- /dev/null
@@ -0,0 +1,87 @@
+#!/bin/bash
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+#
+# 20 Sep 2016 -- Gerardo Garcia -- adapted from template
+#
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+INFO "Installing packages"
+add-apt-repository -y ppa:juju/stable
+apt-get update
+apt-get install -y juju lxd squid-deb-proxy
+
+echo 'streams.canonical' > /etc/squid-deb-proxy/mirror-dstdomain.acl.d/20-juju-streams
+service squid-deb-proxy reload
+
+INFO "Configuring LXD"
+# ZFS doesn't work inside a nested container. ZFS should be configured in the host LXD.
+lxd init --auto
+lxd waitready
+systemctl stop lxd-bridge
+systemctl --system daemon-reload
+cat <<EOF > /etc/default/lxd-bridge
+USE_LXD_BRIDGE="true"
+LXD_BRIDGE="lxdbr0"
+UPDATE_PROFILE="true"
+LXD_CONFILE=""
+LXD_DOMAIN="lxd"
+LXD_IPV4_ADDR="10.44.127.1"
+LXD_IPV4_NETMASK="255.255.255.0"
+LXD_IPV4_NETWORK="10.44.127.1/24"
+LXD_IPV4_DHCP_RANGE="10.44.127.2,10.44.127.254"
+LXD_IPV4_DHCP_MAX="252"
+LXD_IPV4_NAT="true"
+LXD_IPV6_ADDR=""
+LXD_IPV6_MASK=""
+LXD_IPV6_NETWORK=""
+LXD_IPV6_NAT="false"
+LXD_IPV6_PROXY="false"
+EOF
+
+systemctl enable lxd-bridge
+systemctl start lxd-bridge
+
+DEFAULT_INTERFACE=$(route -n | awk '$1~/^0.0.0.0/ {print $8}')
+DEFAULT_MTU=$( ip addr show $DEFAULT_INTERFACE | perl -ne 'if (/mtu\s(\d+)/) {print $1;}')
+
+INFO "Setting lxdbr0 MTU to $DEFAULT_MTU"
+ifconfig lxdbr0 mtu $DEFAULT_MTU
+
+# Make the MTU change persistent between reboots
+sed -i '/ifconfig lxdbr0 mtu/d' /etc/rc.local
+sed -i "$ i ifconfig lxdbr0 mtu $DEFAULT_MTU" /etc/rc.local
+
+INFO "Pre-caching Ubuntu:16.04 image (this may take several minutes)..."
+
+# Setup a daily cron to update the cached image
+cp $HERE/update-lxd-image.sh /etc/cron.daily
+
+# Run it for the first time
+/etc/cron.daily/update-lxd-image.sh xenial
+
+INFO "Bootstrapping VCA"
+juju bootstrap localhost osm \
+--config default-series=xenial \
+--config enable-os-refresh-update=false \
+--config enable-os-upgrade=false \
+--config apt-http-proxy=http://10.44.127.1:8000
+
+RC=0
+
+INFO "done, RC=$RC"
+exit $RC
diff --git a/jenkins/VCA/update-lxd-image.sh b/jenkins/VCA/update-lxd-image.sh
new file mode 100755 (executable)
index 0000000..182a33c
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# This script will create xenial and trusty lxd images that will be used by the
+# lxd provider in juju 2.1+ It is for use with the lxd provider for local
+# development and preinstalls a common set of production packages.
+#
+# This dramatically speeds up the install hooks for lxd deploys by
+# pre-installing common packages. It is intended to run daily as part of
+# a cron job.
+set -eux
+
+# The basic charm layer also installs all the things. 47 packages.
+LAYER_BASIC="gcc build-essential python3-pip python3-setuptools python3-yaml"
+
+# the basic layer also installs virtualenv, but the name changed in xenial.
+TRUSTY_PACKAGES="python-virtualenv"
+XENIAL_PACKAGES="virtualenv"
+
+# Predownload common packages used by your charms in development
+DOWNLOAD_PACKAGES=""
+
+PACKAGES="$LAYER_BASIC $DOWNLOAD_PACKAGES"
+
+function cache() {
+    series=$1
+    container=juju-${series}-base
+    alias=juju/$series/amd64
+
+    lxc delete $container -f || true
+    lxc launch ubuntu:$series $container
+
+    # Wait for the container to get an IP address
+    lxc exec $container -- bash -c "for i in {1..60}; do sleep 1; ping -c1 10.44.127.1 &> /dev/null && break; done"
+
+    lxc exec $container -- apt-get update -y
+    lxc exec $container -- apt-get upgrade -y
+    lxc exec $container -- apt-get install -y $PACKAGES $2
+    lxc stop $container
+
+    lxc image delete $alias || true
+    lxc publish $container --alias $alias description="$series juju dev image ($(date +%Y%m%d))"
+
+    lxc delete $container -f || true
+}
+
+cache trusty "$TRUSTY_PACKAGES"
+cache xenial "$XENIAL_PACKAGES"
diff --git a/jenkins/common/all_funcs b/jenkins/common/all_funcs
new file mode 100644 (file)
index 0000000..a847108
--- /dev/null
@@ -0,0 +1,28 @@
+# this file is meant to be sourced
+#
+#   Copyright 2016 RIFT.IO 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.
+#
+# import all functions
+#
+# 24 June 2016 -- Jeremy Mordkoff -- Genesis
+
+if [ -z "$OSM_JENKINS" ]; then
+       export OSM_JENKINS=$(realpath $(dirname ${BASH_SOURCE[0]} ))
+fi
+
+for file in logging config container git_functions; do
+       . ${OSM_JENKINS}/common/$file
+       INFO "$file sourced"
+done
diff --git a/jenkins/common/config b/jenkins/common/config
new file mode 100644 (file)
index 0000000..7f49381
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/bash
+# This file is meant to be SOURCED
+#
+#   Copyright 2016 RIFT.IO 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.
+#
+#  config functions
+# 24 June 2016 -- Jeremy Mordkoff -- Genesis
+
+
+OSM_load_config() { 
+       OSM_load_config_file ${OSM_JENKINS}/SETTINGS
+       if [ -z "$OSM_MDG" ]; then
+               WARNING "OSM_MDG not set" 
+       else 
+               OSM_load_config_file ${OSM_JENKINS}/${OSM_MDG}/SETTINGS
+       fi
+}
+
+OSM_load_config_file() { 
+       [ $# -eq 1 ] || FATAL "arg is filename"
+       if [ -f "$1" ]; then
+               . "$1"
+               INFO "config file $1 loaded"
+       else
+               WARNING "$1 not found"
+       fi
+}
+               
diff --git a/jenkins/common/container b/jenkins/common/container
new file mode 100644 (file)
index 0000000..e29d5eb
--- /dev/null
@@ -0,0 +1,89 @@
+# This file is meant to be SOURCED
+#
+#   Copyright 2016 RIFT.IO Inc
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+#
+# container_funcs
+# 24 June 2016 -- Jeremy Mordkoff -- Genesis
+#              -- Gerardo García
+
+container_exists() { 
+       if [ $# -ne 1 ]; then
+               FATAL "arg is container name"
+       fi
+       lxc config show $1 >/dev/null 2>&1
+       if [ $? -eq 0 ]; then
+               DEBUG "container $1 exists"
+               return 0
+       else
+               DEBUG "container $1 not found"
+               return 1
+       fi
+}
+
+create_container() { 
+       if [ $# -lt 2 ]; then
+               FATAL "args are image container [options]"
+       fi
+       INFO "creating container $2 using image $1"
+       image=$1
+       container=$2
+       shift 2
+       DEBUG "lxc launch $image $container $*"
+       lxc launch "$image" "$container" $*
+}
+
+container_exec() { 
+       container="$1"
+       shift
+       DEBUG "exec in $container \"$*\""
+       lxc exec "$container" -- $*
+}
+
+container_exec_stderr() { 
+       container="$1"
+       shift
+       DEBUG "exec in $container \"$*\""
+       lxc exec "$container" -- $* 2>&1
+}
+
+wait_container_up() {
+    [ $# -eq 1 ] || FATAL "arg is container name got $# args - $*"
+    RE="200"
+    ct=0
+    while [ $ct -lt 10 ]; do
+        let ct=ct+1
+        output=$(container_exec_stderr "$1" curl -sL -w "%{http_code}\\n" "http://www.google.com/" -o /dev/null)
+        if [[ $output =~ $RE ]]; then
+            DEBUG "$1 is up"
+            return
+        fi
+        INFO "waiting for container $1 to start"
+        DEBUG "expected '$RE' in $output"
+        sleep 5
+    done
+    FATAL "container $1 did not start"
+}
+container_push_tree() { 
+    # create a tarball locally, pipe it into the container and unpack it there
+       [ $# -eq 3 ] || FATAL "args are container dir_from dir_to (dir_to MUST exist)"
+    tar -C "$2" -c . -f - | container_exec $1 tar -C "$3" -x -f -
+}
+
+container_push_devops() { 
+       [ $# -eq 1 ] || FATAL "arg is container name got $# args - $*"
+    container_exec "$1" mkdir -p /root/devops
+    container_push_tree "$1" "$(dirname $OSM_JENKINS)" "/root/devops"
+}
diff --git a/jenkins/common/git_functions b/jenkins/common/git_functions
new file mode 100644 (file)
index 0000000..e5b7984
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+
+GIT() {
+    CMD git "$@"
+}
+
+
+OSM_git_checkout() {
+
+    # Updates all the branches in the local repo (clones if it does not exist)
+    if [ -d $OSM_MDG ]; then
+        INFO "reusing existing workspace"
+        cd $OSM_MDG
+        GIT fetch --all --tags
+        #git checkout master  #to make sure that we are in the right branch before pulling the code
+        #git pull
+    else
+        INFO "cloning MDG $OSM_MDG from $OSM_GIT_URL/$OSM_MDG"
+        GIT clone $OSM_GIT_URL/$OSM_MDG
+        cd $OSM_MDG
+        for remote in `git branch -r |grep -v /HEAD`; do GIT branch --track ${remote#origin/} $remote; done
+    fi
+    
+    if [ $# -gt 0 ]; then
+        if [ "$1" = "checkout" ]; then
+            INFO "Code to compile: '$2'"
+            GIT checkout $2
+        else
+            INFO "Code to compile: gerrit refspec '$1', commit-id: '$2'"
+            GIT fetch origin $1 || FATAL "git fetch origin '$1' didn't work"
+            GIT checkout -f $2 || FATAL "git checkout -f '$2' didn't work"
+        fi
+    else
+        INFO "Code to compile: master"
+        GIT checkout master
+    fi
+
+}
+
diff --git a/jenkins/common/install_common b/jenkins/common/install_common
new file mode 100755 (executable)
index 0000000..d844bdd
--- /dev/null
@@ -0,0 +1,48 @@
+# this file is meant to be sourced
+#
+#   Copyright 2017 Sandvine
+#
+#   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.
+#
+#
+
+RELEASE="ReleaseTWO"
+REPOSITORY_KEY="OSM%20ETSI%20Release%20Key.gpg"
+REPOSITORY="stable"
+REPOSITORY_BASE="http://osm-download.etsi.org/repository/osm/debian"
+
+while getopts ":r:k:u:R:" o; do
+    case "${o}" in
+        r)
+            REPOSITORY=${OPTARG}
+            ;;
+        R)
+            RELEASE=${OPTARG}
+            ;;
+        k)
+            REPOSITORY_KEY=${OPTARG}
+            ;;
+        u)
+            REPOSITORY_BASE=${OPTARG}
+            ;;
+        *)
+            exit 1
+            ;;
+    esac
+done
+
+key_location=$REPOSITORY_BASE/$RELEASE/$REPOSITORY_KEY
+
+curl $key_location | apt-key add -
+
+apt update && add-apt-repository -y "deb $REPOSITORY_BASE/$RELEASE $REPOSITORY SO UI RO osmclient openvim"
diff --git a/jenkins/common/logging b/jenkins/common/logging
new file mode 100644 (file)
index 0000000..a95b563
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/bash
+# This file is meant to be SOURCED
+#
+#   Copyright 2016 RIFT.IO 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.
+#
+# container_funcs
+# 24 June 2016 -- Jeremy Mordkoff -- Genesis
+
+print_stack() {
+   local i
+   local stack_size=${#FUNCNAME[1]}
+   echo  "BACKTRACE:" >&2
+   for (( i=1; i<$stack_size ; i++ )); do
+      local func="${FUNCNAME[$i]}"
+      [ x$func = x ] && func=MAIN
+      local linen="${BASH_LINENO[(( i - 1 ))]}"
+      local src="${BASH_SOURCE[$i]}"
+      [ x"$src" = x ] && src=non_file_source
+      echo "### $func $src $linen" >&2
+   done
+   echo "-------" >&2
+}
+
+
+FATAL() { 
+       echo -e "\n### $(date) ${FUNCNAME[1]}: FATAL error: $*" >&2
+       print_stack
+       exit 1
+}
+       
+WARNING() { 
+       echo -e "\n### $(date) ${FUNCNAME[1]}: WARNING error: $*" >&2
+}
+
+INFO() { 
+       echo "##  $(date) ${FUNCNAME[1]}: $*" >&2
+}
+
+DEBUG() { 
+       echo "#   $(date) ${FUNCNAME[1]}: $*" >&2
+}
+
+CMD() {
+       echo "# executing '$*' ..."
+       "$@"
+       rc=$?
+       echo "# .... '$*' done RC was $rc"
+       return $rc
+}
diff --git a/jenkins/host/clean_container b/jenkins/host/clean_container
new file mode 100755 (executable)
index 0000000..601e6b8
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/bash
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+#
+# clean_container is run on a host to clean an MDG container
+#
+# 20 Sept 2016 -- Gerardo Garcia -- Genesis
+#
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+[ $# -lt 1 ] && FATAL "arg is MDG name"
+
+export OSM_MDG=$1
+OSM_load_config
+
+if container_exists $OSM_BUILD_CONTAINER; then
+       INFO "Container exists. Deleting ..."
+       lxc stop $OSM_BUILD_CONTAINER
+       lxc delete $OSM_BUILD_CONTAINER
+       INFO "$OSM_BUILD_CONTAINER container deleted."
+else
+       INFO "Container does not exist. Nothing to be done."
+fi
+
+INFO "$OSM_MDG clean-container DONE."
+exit 0
+
diff --git a/jenkins/host/install b/jenkins/host/install
new file mode 100755 (executable)
index 0000000..dfdbe59
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+#   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.
+#
+# install is run on a host to install a MDG from binaries
+#
+
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+[ $# -lt 1 ] && FATAL "arg is MDG name"
+
+export OSM_MDG=$1
+shift
+OSM_load_config
+
+if ! container_exists $OSM_BUILD_CONTAINER; then
+       CONTAINER_OPTS=""
+       [[ "$OSM_BUILD_CONTAINER_PRIVILEGED" == yes ]] && CONTAINER_OPTS="$CONTAINER_OPTS -c security.privileged=true"
+       [[ "$OSM_BUILD_CONTAINER_ALLOW_NESTED" == yes ]] && CONTAINER_OPTS="$CONTAINER_OPTS -c security.nesting=true"
+       create_container $OSM_BASE_IMAGE $OSM_BUILD_CONTAINER $CONTAINER_OPTS
+       wait_container_up $OSM_BUILD_CONTAINER
+       if [ ${OSM_USE_LOCAL_DEVOPS:-false} != false ]; then
+               container_push_devops $OSM_BUILD_CONTAINER
+       else
+               container_exec $OSM_BUILD_CONTAINER git clone ${OSM_GIT_URL}/devops
+       fi
+else
+       if [ ${OSM_USE_LOCAL_DEVOPS:-false} != false ]; then
+               container_push_devops $OSM_BUILD_CONTAINER
+       else
+               container_exec $OSM_BUILD_CONTAINER git -C devops pull
+       fi
+fi
+
+container_exec $OSM_BUILD_CONTAINER ./devops/jenkins/$OSM_MDG/install $*
+RC=$?
+INFO "$OSM_MDG install complete. Return code was $RC"
+exit $RC
+
diff --git a/jenkins/host/start_build b/jenkins/host/start_build
new file mode 100755 (executable)
index 0000000..02bfcc2
--- /dev/null
@@ -0,0 +1,70 @@
+#!/bin/bash
+#   Copyright 2016 RIFT.IO Inc
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+#
+# start-build is run on a host to start a MDG build
+#
+# 24 June 2016 -- Jeremy Mordkoff -- Genesis
+#              -- Gerardo Garcia
+
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+[ $# -lt 1 ] && FATAL "arg is MDG name"
+
+export OSM_MDG=$1
+shift
+OSM_load_config
+
+if [ "$1" = "--build-container" ]; then
+    shift
+    [ $# -lt 1 ] && FATAL "missing container name with option --build-container"
+    export OSM_BUILD_CONTAINER=$1
+    shift
+fi
+
+if ! container_exists $OSM_BUILD_CONTAINER; then
+       CONTAINER_OPTS=""
+       [[ "$OSM_BUILD_CONTAINER_PRIVILEGED" == yes ]] && CONTAINER_OPTS="$CONTAINER_OPTS -c security.privileged=true"
+       [[ "$OSM_BUILD_CONTAINER_ALLOW_NESTED" == yes ]] && CONTAINER_OPTS="$CONTAINER_OPTS -c security.nesting=true"
+       [[ "$OSM_BUILD_CONTAINER_ALLOW_DOCKER" == yes ]] && CONTAINER_OPTS="$CONTAINER_OPTS -p docker -p default"
+       create_container $OSM_BASE_IMAGE $OSM_BUILD_CONTAINER $CONTAINER_OPTS
+       wait_container_up $OSM_BUILD_CONTAINER
+       RE="fedora|fc[0-9]"
+       if [[ $OSM_BASE_IMAGE =~ $RE ]]; then
+               container_exec $OSM_BUILD_CONTAINER yum -y install git tar make sudo
+       else
+               container_exec $OSM_BUILD_CONTAINER apt -y install git realpath make sudo 
+       fi
+       if [ ${OSM_USE_LOCAL_DEVOPS:-false} ]; then
+               container_push_devops $OSM_BUILD_CONTAINER
+       else
+               container_exec $OSM_BUILD_CONTAINER git clone ${OSM_GIT_URL}/devops
+       fi
+else
+       if [ ${OSM_USE_LOCAL_DEVOPS:-false} ]; then
+               container_push_devops $OSM_BUILD_CONTAINER
+       else
+               container_exec $OSM_BUILD_CONTAINER git -C devops pull
+       fi
+fi
+
+container_exec $OSM_BUILD_CONTAINER ./devops/jenkins/$OSM_MDG/start_build $*
+RC=$?
+INFO "$OSM_MDG build complete. Return code was $RC"
+exit $RC
+
diff --git a/jenkins/osmclient/SETTINGS b/jenkins/osmclient/SETTINGS
new file mode 100644 (file)
index 0000000..36e5015
--- /dev/null
@@ -0,0 +1,28 @@
+#
+#   Copyright 2017 Sandvine
+#
+#   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.
+#
+#
+# this variable holds the name of the container image needed to build or run this product
+export OSM_BASE_IMAGE=ubuntu:16.04
+#
+# this variable holds the name of the container to be used to build a package
+# if this container already exists, the build process can skip the container build
+export OSM_BUILD_CONTAINER=osmclient
+#
+# this variable holds the name of the container to be used to run a package
+# if this container already exists, the run processes can skip the container build
+export OSM_RUNTIME_CONTAINER=osmclient
+
+export OSM_BUILD_CONTAINER_ALLOW_DOCKER=yes
diff --git a/jenkins/osmclient/start_build b/jenkins/osmclient/start_build
new file mode 100755 (executable)
index 0000000..2206a1a
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/bash
+#
+#   Copyright 2017 Sandvine
+#
+#   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.
+# 
+# Authors:
+#    - Michael Marchetti - mmarchetti@sandvine.com
+# 
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+# SET YOU MDG repository name here
+export OSM_MDG=osmclient
+OSM_load_config
+
+NOTEST=""
+if [ "$1" = "--notest" ]; then
+    shift
+    NOTEST="y"
+fi
+
+OSM_git_checkout "$@"
+
+apt update
+apt install -y docker.io
+
+# cleanup all pre-existing builds.
+# deb pkg build fails if previous build image is present
+rm -rf deb_dist dist
+
+docker build -t $OSM_MDG .
+DOCKER_ARGS="-v $(pwd):$(pwd) -w $(pwd) -u $(id -u):$(id -g) $OSM_MDG"
+
+if [ -n "$NOTEST" ]; then
+    docker run $DOCKER_ARGS /bin/bash -c "./docker_command.sh $(id -u -n) $(id -g -n) tox"
+fi
+
+docker run $DOCKER_ARGS /bin/bash -c "./docker_command.sh $(id -u -n) $(id -g -n) tox -e build"
+
+RC=$?
+INFO "done, RC=$RC"
+exit $RC
diff --git a/jenkins/release/delete-tag.sh b/jenkins/release/delete-tag.sh
new file mode 100755 (executable)
index 0000000..358d680
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/bash
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+echo $OSM_JENKINS
+. $OSM_JENKINS/common/all_funcs
+
+[ $# -ne 1 ] && FATAL "arg1 is tag to be deleted"
+
+TAG="$1"
+
+TEMPDIR="$(mktemp -q -d --tmpdir "tagosm.XXXXXX")"
+trap 'rm -rf "$TEMPDIR"' EXIT
+
+list="juju-charms devops descriptor-packages openvim RO SO UI"
+for i in $list; do
+    REPO_FOLDER="$TEMPDIR/$i"
+    echo
+    echo "Cloning $i"
+    #git -C $TEMPDIR clone ssh://garciadeblas@osm.etsi.org:29418/osm/$i
+    git -C $REPO_FOLDER tag -d $TAG
+    git -C $REPO_FOLDER push origin :refs/tags/$TAG
+    sleep 2
+    rm -rf $REPO_FOLDER
+done
+
diff --git a/jenkins/release/new-tag.sh b/jenkins/release/new-tag.sh
new file mode 100755 (executable)
index 0000000..37c5193
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/bash
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+echo $OSM_JENKINS
+. $OSM_JENKINS/common/all_funcs
+
+[ $# -ne 2 ] && FATAL "arg1 is branch, arg2 is new tag"
+
+#CURRENT_BRANCH="v1.1"
+#TAG="v1.1.0"
+CURRENT_BRANCH="$1"
+TAG="$2"
+
+#tag_header="OSM Release ONE:"
+tag_header="OSM"
+tag_message="$tag_header version $TAG"
+
+TEMPDIR="$(mktemp -q -d --tmpdir "tagosm.XXXXXX")"
+trap 'rm -rf "$TEMPDIR"' EXIT
+#chmod 0600 "$TEMPDIR"
+
+#juju-charms and devops repos have no vx.y branch yet
+list="juju-charms devops"
+for i in $list; do
+    REPO_FOLDER="$TEMPDIR/$i"
+    echo
+    echo "Cloning and tagging $i"
+    #git -C $TEMPDIR clone ssh://garciadeblas@osm.etsi.org:29418/osm/$i
+    git -C $REPO_FOLDER checkout master
+    git -C $REPO_FOLDER tag -a $TAG -m"$tag_message"
+    git -C $REPO_FOLDER push origin $TAG --follow-tags
+    sleep 2
+    rm -rf $REPO_FOLDER
+done
+
+list="descriptor-packages openvim RO SO UI"
+for i in $list; do
+    REPO_FOLDER="$TEMPDIR/$i"
+    echo
+    echo "Cloning and tagging $i"
+    #git -C $TEMPDIR clone ssh://garciadeblas@osm.etsi.org:29418/osm/$i
+    git -C $REPO_FOLDER checkout $CURRENT_BRANCH
+    git -C $REPO_FOLDER tag -a $TAG -m"$tag_message"
+    git -C $REPO_FOLDER push origin $TAG --follow-tags
+    sleep 2
+    rm -rf $REPO_FOLDER
+done
+
diff --git a/jenkins/system/Jenkinsfile b/jenkins/system/Jenkinsfile
new file mode 100644 (file)
index 0000000..8a04f23
--- /dev/null
@@ -0,0 +1,85 @@
+// input parameters:
+//   boolean: BUILD_FROM_SOURCE
+//   boolean: REPO_DISTRO
+//   boolean: COMMIT_ID
+//   boolean: UPSTREAM_SUFFIX
+//   string:  NODE
+//   string: RSYNC_DESTINATION
+//   string: REPO_BASE_URL
+//   string: REPO_KEY_NAME
+//   string: RELEASE
+
+node("${params.NODE}") {
+
+    stage("Setup") {
+        tag_or_branch = params.COMMIT_ID.replaceAll(/\./,"")
+        container_name_prefix = "osm-${tag_or_branch}"
+        container_name = "${container_name_prefix}-${BUILD_NUMBER}"
+    }
+
+    stage("Checkout") {
+        checkout scm
+    }
+
+    // Copy the artifacts from the upstream jobs
+    stage("Copy Artifacts") {
+        // cleanup any previous repo
+        sh 'rm -rf repo'
+
+        dir('repo') {
+            // grab all stable upstream builds based on the
+            // given target UPSTREAM_SUFFIX
+
+            def list = ["SO", "UI", "RO", "openvim", "osmclient"]
+            for (component in list) {
+                step ([$class: 'CopyArtifact',
+                       projectName: "${component}_${params.UPSTREAM_SUFFIX}"])
+                sh "dpkg-sig --sign builder -k dpkg1 pool/${component}/*"
+                // cleanup any prevously defined dists
+                sh "rm -rf dists"
+            }
+
+            // now create the distro
+            for (component in list) {
+                sh "mkdir -p dists/${params.REPO_DISTRO}/${component}/binary-amd64/"
+                sh "apt-ftparchive packages pool/${component} > dists/${params.REPO_DISTRO}/${component}/binary-amd64/Packages"
+                sh "gzip -9fk dists/${params.REPO_DISTRO}/${component}/binary-amd64/Packages"
+            }
+
+            // create and sign the release file
+            sh "apt-ftparchive release dists/${params.REPO_DISTRO} > dists/${params.REPO_DISTRO}/Release"
+            sh "gpg --yes -abs -u dpkg1 -o dists/${params.REPO_DISTRO}/Release.gpg dists/${params.REPO_DISTRO}/Release"
+            sh "rsync -avz . ${params.RSYNC_DESTINATION}/${params.RELEASE}"
+        }
+    }
+
+    stage("Cleanup") {
+        // check for previous containers and clean them up
+        sh "jenkins/system/delete_old_containers.sh ${container_name_prefix}"
+    }
+
+    stage("Build") {
+        from_source = ''
+        if ( params.BUILD_FROM_SOURCE )
+        {
+            from_source = '--source'
+        }
+        sh """
+            export OSM_USE_LOCAL_DEVOPS=true
+            jenkins/host/start_build system --build-container ${container_name} \
+                                            -b ${params.COMMIT_ID} \
+                                            -r ${params.REPO_DISTRO} \
+                                            -u ${params.REPO_BASE_URL} \
+                                            -k ${params.REPO_KEY_NAME} \
+                                            -R ${params.RELEASE} \
+                                            ${from_source}
+           """
+    }
+
+    stage("Archive Artifacts") {
+        sh "echo ${container_name} > build_version.txt"
+        sh "tar -zcvf repo.tar.gz repo"
+        archiveArtifacts artifacts: "build_version.txt, repo.tar.gz", fingerprint: true
+    }
+}
diff --git a/jenkins/system/SETTINGS b/jenkins/system/SETTINGS
new file mode 100644 (file)
index 0000000..912799c
--- /dev/null
@@ -0,0 +1,39 @@
+#   Copyright 2016 Telefónica Investigación y Desarrollo, S.A.U.
+#
+#   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.
+#
+# sample SETTINGS file
+#
+# Authors:
+#     - Gerardo Garcia
+#
+# this variable holds the name of the container image needed to build or run this product
+export OSM_BASE_IMAGE=ubuntu:16.04
+#
+# this variable must be set to allow creating the build container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+export OSM_BUILD_CONTAINER_PRIVILEGED=yes
+#
+# this variable must be set to allow ensted containers in the build container
+export OSM_BUILD_CONTAINER_ALLOW_NESTED=yes
+#
+# this variable must be set to allow creating the runtime container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+export OSM_RUNTIME_CONTAINER_PRIVILEGED=yes
+#
+# this variable must be set to allow ensted containers in the build container
+export OSM_RUNTIME_CONTAINER_ALLOW_NESTED=yes
+#
+#
+export OSM_BUILD_CONTAINER=osm
+export OSM_RUNTIME_CONTAINER=osm
diff --git a/jenkins/system/delete_old_containers.sh b/jenkins/system/delete_old_containers.sh
new file mode 100755 (executable)
index 0000000..13c6df4
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+#   Copyright 2017 Sandvine
+#
+#   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.
+#
+# A helper routine that cleans up old container images based
+# on an input prefix to check. Jenkins builds will add an incrementing
+# build suffix  (build number) to the prefix
+#
+#$1 container prefix name
+
+keep_number=1
+prefix=$1
+
+# keep the first build
+keep=$(lxc list | grep $prefix | awk '{print $2}' | sort -rn | head -n$keep_number)
+for container in $(lxc list | grep $prefix | awk '{print $2}' | sort -rn); do
+    if [ "$container" != "$keep" ]; then
+        echo "deleting old container $container"
+        lxc delete $container --force
+    fi
+done
diff --git a/jenkins/system/start_build b/jenkins/system/start_build
new file mode 100755 (executable)
index 0000000..7f259c7
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/bash
+#   Copyright 2017
+#
+#   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.
+#
+# 01 May 2017 -- Michael Marchetti -- adapted from template
+#
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+INFO "Installing packages"
+apt-get update
+
+INFO "Configuring LXD"
+# ZFS doesn't work inside a nested container. ZFS should be configured in the host LXD.
+lxd init --auto
+lxd waitready
+systemctl stop lxd-bridge
+systemctl --system daemon-reload
+cat <<EOF > /etc/default/lxd-bridge
+USE_LXD_BRIDGE="true"
+LXD_BRIDGE="lxdbr0"
+UPDATE_PROFILE="true"
+LXD_CONFILE=""
+LXD_DOMAIN="lxd"
+LXD_IPV4_ADDR="10.44.126.1"
+LXD_IPV4_NETMASK="255.255.255.0"
+LXD_IPV4_NETWORK="10.44.126.1/24"
+LXD_IPV4_DHCP_RANGE="10.44.126.2,10.44.126.254"
+LXD_IPV4_DHCP_MAX="252"
+LXD_IPV4_NAT="true"
+LXD_IPV6_ADDR=""
+LXD_IPV6_MASK=""
+LXD_IPV6_NETWORK=""
+LXD_IPV6_NAT="false"
+LXD_IPV6_PROXY="false"
+EOF
+
+systemctl enable lxd-bridge
+systemctl start lxd-bridge
+
+apt-get install -y python-pip python python-pycurl charm-tools python-pytest
+
+# TODO: use package when available on osm repo
+git clone https://osm.etsi.org/gerrit/osm/osmclient
+pip install osmclient/.
+
+export OSM_USE_LOCAL_DEVOPS=true
+devops/installers/install_osm.sh --test $*
+RC=$?
+
+# workaround.  for upload packages, lxdbr0 needs to be promiscuous
+# as the upload calls back to the UI server so the lxdbr0 needs
+# to operate as a bridge
+ifconfig lxdbr0 promisc
+
+if [ $RC == 0 ]; then
+   # success. find all the resulting containers
+   . devops/installers/export_ips
+
+   TO_ADD="export OSM_HOSTNAME=$SO_CONTAINER_IP"
+   grep -q OSM_HOSTNAME ~/.bashrc && sed -i "s/.*OSM_HOSTNAME.*/$TO_ADD/" ~/.bashrc || echo -e "$TO_ADD\n$(cat ~/.bashrc)" > ~/.bashrc
+fi
+
+INFO "done, RC=$RC"
+exit $RC
diff --git a/jenkins/template/SETTINGS b/jenkins/template/SETTINGS
new file mode 100644 (file)
index 0000000..94154f3
--- /dev/null
@@ -0,0 +1,46 @@
+#   Copyright 2016 RIFT.IO Inc
+#   Copyright 2016 Telefónica Investigación y Desarrollo, S.A.U.
+#
+#   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.
+#
+# sample SETTINGS file
+#
+# Authors:
+#         24 June 2016 -- Jeremy Mordkoff -- Genesis 
+#                      -- Gerardo Garcia
+#
+# this variable holds the name of the container image needed to build or run this product
+export OSM_BASE_IMAGE=ubuntu:16.04
+#
+# this variable holds the name of the container to be used to build a package
+# if this container already exists, the build process can skip the container build
+export OSM_BUILD_CONTAINER=container_name-build
+#
+# this variable must be set to allow creating the build container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+#export OSM_BUILD_CONTAINER_PRIVILEGED=yes
+#
+# this variable must be set to allow ensted containers in the build container
+#export OSM_BUILD_CONTAINER_ALLOW_NESTED=yes
+#
+# this variable holds the name of the container to be used to run a package
+# if this container already exists, the run processes can skip the container build
+export OSM_RUNTIME_CONTAINER=container_name-runtime
+#
+# this variable must be set to allow creating the runtime container in privileged mode
+# this variable should be removed in the future when no privileged mode is required
+#export OSM_RUNTIME_CONTAINER_PRIVILEGED=yes
+#
+# this variable must be set to allow ensted containers in the build container
+#export OSM_RUNTIME_CONTAINER_ALLOW_NESTED=yes
+#
diff --git a/jenkins/template/start_build b/jenkins/template/start_build
new file mode 100755 (executable)
index 0000000..43ef161
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+#   Copyright 2016 RIFT.IO 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.
+# 
+# TEMPLATE script to start a build. This is run inside a container
+#
+# 6 July 2016 -- Jeremy.Mordkoff@riftio.com -- adapted from the riftware version
+# 
+
+HERE=$(realpath $(dirname $0))
+OSM_JENKINS=$(dirname $HERE)
+. $OSM_JENKINS/common/all_funcs
+
+# SET YOU MDG repository name here
+export OSM_MDG=XXXX
+OSM_load_config
+OSM_git_checkout "$@"
+
+INFO "starting build"
+### for start_build
+### put your commands here to 
+### build, test and produce coverage reports
+# E.G.
+#make clean || FATAL "make clean failed"
+#make || FATAL "make failed"
+#sudo make install || FATAL "make install failed"
+
+RC=0
+
+INFO "done, RC=$RC"
+exit $RC
+
+
diff --git a/systest/.gitignore b/systest/.gitignore
new file mode 100644 (file)
index 0000000..97f7edd
--- /dev/null
@@ -0,0 +1,5 @@
+pytest-output.xml
+*.pyc
+.cache
+descriptor-packages/
+*.xml
diff --git a/systest/Dockerfile b/systest/Dockerfile
new file mode 100644 (file)
index 0000000..ec30486
--- /dev/null
@@ -0,0 +1,6 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get -y install python \
+    libcurl4-gnutls-dev libgnutls-dev \
+    python-setuptools python-pip git python-pytest \
+    charm-tools
diff --git a/systest/Jenkinsfile b/systest/Jenkinsfile
new file mode 100644 (file)
index 0000000..8e290e8
--- /dev/null
@@ -0,0 +1,59 @@
+// input parameters:
+//   string:  UPSTREAM_PROJECT
+//   string:  NODE
+//
+//   OpenStack VIM Credentials
+//   string:  OS_AUTH_URL
+//   string:  OS_USERNAME
+//   string:  OS_PASSWORD
+//   string:  OS_PROJECT_NAME
+
+node("${params.NODE}") {
+
+    // grab the upstream artifact name
+    step ([$class: 'CopyArtifact',
+          projectName: params.UPSTREAM_PROJECT])
+
+    container_name = sh(returnStdout: true, script: 'cat build_version.txt').trim()
+
+    stage("get osm") {
+        // get the IP of the osm container
+        OSM_IP = sh(returnStdout: true, script: "lxc list ${container_name} -c 4|grep eth0 |awk '{print \$2}'").trim()
+    }
+
+    stage("checkout") {
+        checkout scm
+    }
+
+    // build the pytest container
+    stage("build-docker") {
+        sh 'docker build -t osmclient systest/.'
+    }
+
+    os_credentials = "OS_AUTH_URL=${params.OS_AUTH_URL} OS_USERNAME=${params.OS_USERNAME} OS_PASSWORD=${params.OS_PASSWORD} OS_PROJECT_NAME=${params.OS_PROJECT_NAME}"
+
+    // now run the built container.
+    withDockerContainer('osmclient') {
+
+        // install the osmclient
+        stage("install-osmclient") {
+            sh 'pip install git+https://osm.etsi.org/gerrit/osm/osmclient'
+        }
+
+        stage("build-descriptors") {
+            sh "make -C systest descriptors"
+        }
+
+        stage("smoke-test") {
+            sh "make -C systest OSM_HOSTNAME=${OSM_IP} smoke"
+            junit 'systest/reports/pytest-smoke.xml'
+        }
+
+        stage("cirros-test") {
+            sh """
+               make -C systest OSM_HOSTNAME=${OSM_IP} ${os_credentials} cirros
+               """
+            junit 'systest/reports/pytest-cirros.xml'
+        }
+    }
+}
diff --git a/systest/Makefile b/systest/Makefile
new file mode 100644 (file)
index 0000000..7f5a542
--- /dev/null
@@ -0,0 +1,142 @@
+# Copyright 2017 Sandvine
+# All Rights Reserved.
+# 
+#    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.
+
+#
+# These variables need to be defined in environment or passed in
+# the make invocation.
+# eg. 
+#    export OSM_HOSTNAME=1.2.3.4:8008
+#    export OS_AUTH_URL=https://<keystoneserver>:5000/v2.0
+#    export OS_USERNAME=admin
+#    export OS_PASSWORD=admin
+#    export OS_PROJECT_NAME=admin
+OSM_HOSTNAME ?=
+OS_AUTH_URL ?=
+OS_USERNAME ?=
+OS_PASSWORD_NAME ?=
+OS_PROJECT_NAME ?=
+
+ifdef OS_AUTH_URL
+    OPTION_OS_AUTH_URL=--os-url $(OS_AUTH_URL)
+endif
+ifdef OS_USERNAME
+    OPTION_OS_USERNAME=--os-username $(OS_USERNAME)
+endif
+ifdef OS_PASSWORD
+    OPTION_OS_PASSWORD=--os-password $(OS_PASSWORD)
+endif
+ifdef OS_PROJECT_NAME
+    OPTION_OS_PROJECT_NAME=--os-project-name $(OS_PROJECT_NAME)
+endif
+
+ifdef TEST_VNFD_DESCRIPTORS
+    OPTION_TEST_VNFD_DESCRIPTORS=--osm-vnfd-descriptor-packages $(TEST_VNFD_DESCRIPTORS)
+endif
+ifdef TEST_NSD_DESCRIPTORS
+    OPTION_TEST_NSD_DESCRIPTORS=--osm-nsd-descriptor-packages $(TEST_NSD_DESCRIPTORS)
+endif
+
+DESCRIPTOR_REPO_NAME = descriptor-packages
+DESCRIPTOR_REPO_DIR ?= $(shell pwd)/descriptor-packages
+DESCRIPTOR_BUILD_DIR := $(DESCRIPTOR_REPO_DIR)/build
+OPTION_DESCRIPTOR_BUILD_DIR=--osm-descriptor-packages $(DESCRIPTOR_BUILD_DIR)
+
+TEST_OSM_NS_NAME_PREFIX=pytest-$(shell date +%D-%T)-
+OPTION_TEST_OSM_NS_NAME_PREFIX=--osm-ns-name-prefix $(TEST_OSM_NS_NAME_PREFIX)
+
+JUNITXML_DIR = reports
+
+JUNITXML ?= pytest-output.xml
+
+PYTEST_OPTIONS=
+Q=@
+
+DESCRIPTOR_REPO ?= https://osm.etsi.org/gerrit/osm/$(DESCRIPTOR_REPO_NAME)
+
+
+TEST_VNFD_DESCRIPTORS ?= None
+TEST_NSD_DESCRIPTORS  ?= None
+
+.NOTPARALLEL:
+all: smoke cirros ping_pong
+
+define check_env_var
+       $(Q)if [ -z "$($(1))" ]; then echo "error: $(1) not set"; exit 1; fi
+endef
+
+check_OSM_HOSTNAME:
+       $(call check_env_var,OSM_HOSTNAME)
+
+check_openstack_env:
+       $(call check_env_var,OS_AUTH_URL)
+       $(call check_env_var,OS_USERNAME)
+       $(call check_env_var,OS_PASSWORD)
+       $(call check_env_var,OS_PROJECT_NAME)
+
+.PHONY: check_openstack_env check_OSM_HOSTNAME
+
+descriptors:
+       test -e $(DESCRIPTOR_REPO_NAME) || git clone $(DESCRIPTOR_REPO)
+       $(MAKE) -C $(DESCRIPTOR_REPO_NAME)
+
+report_dir:
+       @mkdir -p reports
+
+_run_test: report_dir
+       $(Q)py.test \
+        --osmhost $(OSM_HOSTNAME) \
+        $(OPTION_OS_AUTH_URL) \
+        $(OPTION_OS_USERNAME) \
+        $(OPTION_OS_PASSWORD) \
+        $(OPTION_OS_PROJECT_NAME) \
+        $(OPTION_TEST_VNFD_DESCRIPTORS) \
+        $(OPTION_TEST_NSD_DESCRIPTORS) \
+        $(OPTION_DESCRIPTOR_BUILD_DIR) \
+        $(OPTION_TEST_OSM_NS_NAME_PREFIX) \
+        --junitxml $(JUNITXML_DIR)/$(JUNITXML) \
+        $(PYTEST_OPTIONS)
+
+cirros: check_OSM_HOSTNAME check_openstack_env
+       $(Q)$(MAKE) \
+        TEST_VNFD_DESCRIPTORS=$(DESCRIPTOR_BUILD_DIR)/vnfd_pkgs/cirros_vnf.tar.gz \
+        TEST_NSD_DESCRIPTORS=$(DESCRIPTOR_BUILD_DIR)/nsd_pkgs/cirros_ns.tar.gz \
+        JUNITXML=pytest-$@.xml \
+        PYTEST_OPTIONS="$(PYTEST_OPTIONS) -m vnf" _run_test
+
+ns_scale: check_OSM_HOSTNAME check_openstack_env
+       $(Q)$(MAKE) \
+        TEST_VNFD_DESCRIPTORS=$(DESCRIPTOR_BUILD_DIR)/vnfd_pkgs/cirros_vnf.tar.gz \
+        TEST_NSD_DESCRIPTORS=$(DESCRIPTOR_BUILD_DIR)/nsd_pkgs/cirros_ns.tar.gz \
+        JUNITXML=pytest-$@.xml \
+        PYTEST_OPTIONS="$(PYTEST_OPTIONS) -m ns_scale" _run_test
+
+smoke: check_OSM_HOSTNAME
+       $(Q)$(MAKE) \
+        JUNITXML=pytest-$@.xml \
+        PYTEST_OPTIONS="$(PYTEST_OPTIONS) -m smoke" _run_test
+
+vim: check_OSM_HOSTNAME check_openstack_env
+       $(Q)$(MAKE) \
+        JUNITXML=pytest-$@.xml \
+        PYTEST_OPTIONS="$(PYTEST_OPTIONS) -m vim" _run_test
+
+ping_pong: check_OSM_HOSTNAME check_openstack_env
+       $(Q)$(MAKE) \
+        TEST_VNFD_DESCRIPTORS="$(DESCRIPTOR_BUILD_DIR)/vnfd_pkgs/ping_vnf.tar.gz,$(DESCRIPTOR_BUILD_DIR)/vnfd_pkgs/pong_vnf.tar.gz" \
+        TEST_NSD_DESCRIPTORS="$(DESCRIPTOR_BUILD_DIR)/nsd_pkgs/ping_pong_ns.tar.gz" \
+        JUNITXML=pytest-$@.xml \
+        PYTEST_OPTIONS="$(PYTEST_OPTIONS) -m vnf" _run_test
+
+.PHONY: report_dir cirros vim smoke ping_pong
diff --git a/systest/conftest.py b/systest/conftest.py
new file mode 100644 (file)
index 0000000..2032002
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+from lib.osm.fixtures import osm_add_options
+from lib.openstack.fixtures import openstack_add_options
+from lib.vim.fixtures import vim_add_options
+
+def pytest_addoption(parser):
+    osm_add_options(parser)
+    openstack_add_options(parser)
+    vim_add_options(parser)
diff --git a/systest/lib/__init__.py b/systest/lib/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/systest/lib/openstack/__init__.py b/systest/lib/openstack/__init__.py
new file mode 100644 (file)
index 0000000..2bf7fed
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
diff --git a/systest/lib/openstack/fixtures.py b/systest/lib/openstack/fixtures.py
new file mode 100644 (file)
index 0000000..7c1ec7f
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+import pytest
+import json
+
+
+def openstack_add_options(parser):
+    parser.addoption("--os-url", default="", help="openstack identity url")
+    parser.addoption("--os-username", default="", help="openstack username")
+    parser.addoption("--os-password", default="", help="openstack password")
+    parser.addoption("--os-project-name", default="", help="openstack project name")
+
+@pytest.fixture
+def openstack(request):
+    from lib.openstack import openstack
+    access = {}
+    access['os-url'] = request.config.getoption("--os-url")
+    access['os-username'] = request.config.getoption("--os-username")
+    access['os-password'] = request.config.getoption("--os-password")
+    access['os-project-name'] = request.config.getoption("--os-project-name")
+    access['vim-type'] = 'openstack'
+    access['description'] = 'pytest system test'
+
+    return openstack.Openstack(access)
diff --git a/systest/lib/openstack/openstack.py b/systest/lib/openstack/openstack.py
new file mode 100644 (file)
index 0000000..9f5c304
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+
+class Openstack():
+    def __init__(self,access):
+        self._os_access = access
+
+    def get_access(self):
+        return self._os_access
diff --git a/systest/lib/osm/__init__.py b/systest/lib/osm/__init__.py
new file mode 100644 (file)
index 0000000..2bf7fed
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
diff --git a/systest/lib/osm/fixtures.py b/systest/lib/osm/fixtures.py
new file mode 100644 (file)
index 0000000..edfc076
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+import pytest
+import json
+
+
+def osm_add_options(parser):
+    parser.addoption("--osmhost", default="", help="osm hostname")
+    parser.addoption("--osm-descriptor-packages", default="", help="location of descriptor packages")
+    parser.addoption("--osm-vnfd-descriptor-packages", default="", help="vnfd packages to test")
+    parser.addoption("--osm-nsd-descriptor-packages", default="", help="nsd package to test")
+    parser.addoption("--osmfile", action="store", default="", help="osm json data file")
+    parser.addoption("--osm-ns-name-prefix", action="store", default="", help="ns name prefix to apply")
+
+'''
+@pytest.fixture
+def osm(request):
+    from osmclient.common import OsmAPI
+    with open(request.config.getoption("--osm")) as json_data:
+        osmdict=json.load(json_data)
+        return OsmAPI.OsmAPI(osmdict['ip'])
+
+'''
+
+@pytest.fixture
+def osm(request):
+    from lib.osm import osm
+    osmhost=request.config.getoption("--osmhost")
+    descriptors_dir=request.config.getoption("--osm-descriptor-packages")
+    vnfd_descriptors_list=request.config.getoption("--osm-vnfd-descriptor-packages").split(',')
+    nsd_descriptors_list=request.config.getoption("--osm-nsd-descriptor-packages").split(',')
+    ns_name_prefix=request.config.getoption("--osm-ns-name-prefix")
+    return osm.Osm(osmhost,
+                   descriptors_dir=descriptors_dir,
+                   vnfd_descriptors_list=vnfd_descriptors_list,
+                   nsd_descriptors_list=nsd_descriptors_list,
+                   ns_name_prefix=ns_name_prefix)
diff --git a/systest/lib/osm/osm.py b/systest/lib/osm/osm.py
new file mode 100644 (file)
index 0000000..8798be8
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+
+from osmclient.client import client
+
+class Osm():
+    def __init__(self,osmhost,descriptors_dir=None,vnfd_descriptors_list=None,nsd_descriptors_list=None,ns_name_prefix=None):
+        self._OsmApi=client.Client(host=osmhost)
+        self._descriptors_dir = descriptors_dir
+        self.vnfd_descriptors_list = vnfd_descriptors_list
+        self.nsd_descriptors_list  = nsd_descriptors_list 
+        self.ns_name_prefix = ns_name_prefix
+
+    def get_api(self):
+        return self._OsmApi
+
+    def get_descriptors_dir(self):
+        return self._descriptors_dir
diff --git a/systest/lib/vim/__init__.py b/systest/lib/vim/__init__.py
new file mode 100644 (file)
index 0000000..2bf7fed
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
diff --git a/systest/lib/vim/fixtures.py b/systest/lib/vim/fixtures.py
new file mode 100644 (file)
index 0000000..e552bbc
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+import pytest
+import json
+
+
+def vim_add_options(parser):
+    pass
+
+@pytest.fixture
+def vim(request,osm,openstack):
+    from lib.vim import vim 
+    return vim.Vim(osm,openstack)
diff --git a/systest/lib/vim/vim.py b/systest/lib/vim/vim.py
new file mode 100644 (file)
index 0000000..98bda38
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+from osmclient.common.exceptions import ClientException
+
+
+class Vim():
+    def __init__(self,osm,openstack):
+        self.vim_name='pytest'
+        try:
+            osm.get_api().vim.get(self.vim_name)
+        except ClientException:
+            osm.get_api().vim.create(self.vim_name,openstack.get_access())
diff --git a/systest/testcases/conftest.py b/systest/testcases/conftest.py
new file mode 100644 (file)
index 0000000..9f8be17
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+from lib.osm.fixtures import osm
+from lib.openstack.fixtures import openstack
+from lib.vim.fixtures import vim
diff --git a/systest/testcases/smoke/test_smoke.py b/systest/testcases/smoke/test_smoke.py
new file mode 100644 (file)
index 0000000..e915e23
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+import pytest
+import pprint
+import time
+
+
+@pytest.mark.smoke
+class TestClass(object):
+
+    def test_empty_vnf(self,osm):
+        assert not osm.get_api().vnf.list()
+
+    def test_empty_vnf_catalog(self,osm):
+        assert not osm.get_api().vnfd.list()
+
+    def test_empty_ns(self,osm):
+        assert not osm.get_api().ns.list()
+
+    def test_empty_ns_catalog(self,osm):
+        assert not osm.get_api().nsd.list()
diff --git a/systest/testcases/vim/test_vim.py b/systest/testcases/vim/test_vim.py
new file mode 100644 (file)
index 0000000..5ea7077
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+import pytest
+import time
+
+
+@pytest.mark.vim
+@pytest.mark.openstack
+class TestClass(object):
+
+    def test_empty_vim(self,osm):
+        assert not osm.get_api().vim.list()
+
+    @pytest.fixture(scope='function')
+    def cleanup_test_add_vim_account(self,osm,request):
+        def teardown():
+            try:
+                osm.get_api().vim.delete('pytest')
+            except:
+                pass
+        request.addfinalizer(teardown)
+    @pytest.mark.openstack
+    def test_add_vim_account(self,osm,openstack,cleanup_test_add_vim_account):
+        os_access=openstack.get_access()
+        assert not osm.get_api().vim.create('pytest',os_access)
+
+        resp=osm.get_api().vim.get('pytest')
+        assert resp['name'] == 'pytest'
+        assert resp['type'] == 'openstack'
+        assert resp['vim_url'] == os_access['os-url']
+        assert resp['vim_url_admin'] == os_access['os-url']
+        assert resp['vim_tenants'][0]['user'] == os_access['os-username']
+        assert resp['vim_tenants'][0]['vim_tenant_name'] == os_access['os-project-name']
+
+        assert not osm.get_api().vim.delete('pytest')
diff --git a/systest/testcases/vnfs/test_vnfs.py b/systest/testcases/vnfs/test_vnfs.py
new file mode 100644 (file)
index 0000000..efbfb10
--- /dev/null
@@ -0,0 +1,130 @@
+# Copyright 2017 Sandvine
+#
+# All Rights Reserved.
+#
+#    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.
+
+import pytest
+import pprint
+import time
+from osmclient.common import utils
+
+
+class TestClass(object):
+
+    @pytest.fixture(scope='function')
+    def cleanup_test_vnf(self,osm,request):
+        vnfd_file_list = osm.vnfd_descriptors_list
+        nsd_file_list = osm.nsd_descriptors_list
+
+        # cleanup all ns/packages that might have been left around
+        def teardown():
+
+            # first delete all nsd's
+            for file in nsd_file_list:
+                try:
+                    desc = osm.get_api().package.get_key_val_from_pkg(file)
+                    ns_name=osm.ns_name_prefix+nsd_desc['name']
+                    osm.get_api().ns.delete(ns_name)
+                except:
+                    pass
+
+            # delete all nsd packages
+            for file in nsd_file_list:
+                try:
+                    desc = osm.get_api().package.get_key_val_from_pkg(file)
+                    osm.get_api().nsd.delete(desc['name'])
+                except: 
+                    pass
+
+            # delete all vnfd packages
+            for file in vnfd_file_list:
+                try:
+                    desc = osm.get_api().package.get_key_val_from_pkg(file)
+                    osm.get_api().vnfd.delete(desc['name'])
+                except: 
+                    pass
+
+        request.addfinalizer(teardown)
+
+    def vnf_upload_packages(self, osm, vnfd_file_list, nsd_file_list ):
+        vnfd_descriptors=[]
+        for file in vnfd_file_list:
+            assert not osm.get_api().package.upload(file)
+            assert not osm.get_api().package.wait_for_upload(file)
+            desc = osm.get_api().package.get_key_val_from_pkg(file)
+            assert desc
+            vnfd_descriptors.append(desc)
+
+        nsd_descriptors=[]
+        for file in nsd_file_list:
+            assert not osm.get_api().package.upload(file)
+            assert not osm.get_api().package.wait_for_upload(file)
+            desc = osm.get_api().package.get_key_val_from_pkg(file)
+            assert desc
+            nsd_descriptors.append(desc)
+        # TODO/HACK: need to figure out why this is necessary. 
+        # vnfd/nsd is there (seen on ping_pong), but the ns fails that nsd is not there, 
+        # another way to check if the nsd is really ready via API?
+        time.sleep(5)
+
+    def vnf_test(self,osm, openstack, vim, vnfd_file_list, nsd_file_list, ns_scale=False):
+        for file in nsd_file_list:
+            nsd_desc = osm.get_api().package.get_key_val_from_pkg(file)
+
+            ns_name=osm.ns_name_prefix+nsd_desc['name']
+
+            assert not osm.get_api().ns.create(nsd_desc['name'],ns_name,vim.vim_name)
+
+            assert utils.wait_for_value(lambda: osm.get_api().ns.get_field(ns_name,'operational-status'),result='init')
+
+            # make sure ns is running
+            assert utils.wait_for_value(lambda: osm.get_api().ns.get_field(ns_name,'operational-status'),result='running',wait_time=120)
+
+            if ns_scale:
+                # for each descriptor, scale it
+                for scale in nsd_desc['scaling-group-descriptor']:
+                    # scale it.
+                    assert not osm.get_api().ns.scale(ns_name, scale['name'], 1)
+
+                    # ensure ns is scaling-out
+                    assert utils.wait_for_value(lambda: osm.get_api().ns.get_field(ns_name,'operational-status'),result='scaling-out',wait_time=120)
+
+                    # wait for ns to be in running-state
+                    assert utils.wait_for_value(lambda: osm.get_api().ns.get_field(ns_name,'operational-status'),result='running',wait_time=120)
+
+            assert not osm.get_api().ns.delete(ns_name)
+
+            assert not osm.get_api().nsd.delete(nsd_desc['name'])
+
+        for file in vnfd_file_list:
+            vnfd_desc = osm.get_api().package.get_key_val_from_pkg(file)
+            assert not osm.get_api().vnfd.delete(vnfd_desc['name'])
+
+    @pytest.mark.openstack
+    @pytest.mark.vnf
+    def test_vnf(self,osm, vim, openstack, cleanup_test_vnf):
+        vnfd_file_list = osm.vnfd_descriptors_list
+        nsd_file_list = osm.nsd_descriptors_list
+
+        self.vnf_upload_packages(osm, vnfd_file_list, nsd_file_list )
+        self.vnf_test(osm,openstack, vim, vnfd_file_list, nsd_file_list)
+
+    @pytest.mark.openstack
+    @pytest.mark.ns_scale
+    def test_scale_vnf(self,osm, vim, openstack, cleanup_test_vnf):
+        vnfd_file_list = osm.vnfd_descriptors_list
+        nsd_file_list = osm.nsd_descriptors_list
+
+        self.vnf_upload_packages(osm, vnfd_file_list, nsd_file_list )
+        self.vnf_test(osm,openstack, vim, vnfd_file_list, nsd_file_list, ns_scale=True)
diff --git a/test/certs.py b/test/certs.py
new file mode 100644 (file)
index 0000000..e33a536
--- /dev/null
@@ -0,0 +1,43 @@
+#   Copyright 2016 RIFT.IO Inc
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+
+import os
+
+class BootstrapSslMissingException(Exception):
+    pass
+
+# True if the environment variable is unset, otherwise False
+USE_SSL = os.environ.get("RIFT_BOOT_WITHOUT_HTTPS", None) is None
+
+def get_bootstrap_cert_and_key():
+    '''
+    Lookup the bootstrap certificate and key and return their paths
+    '''
+
+    user_cert = os.path.join("/", "etc", "ssl", "current.cert")
+    user_key = os.path.join("/", "etc", "ssl", "current.key")
+
+    if os.path.isfile(user_cert) and os.path.isfile(user_key):
+        return USE_SSL, user_cert, user_key
+
+    rift_install = os.environ["RIFT_INSTALL"]
+    rift_cert = os.path.join(rift_install, "etc", "ssl", "current.cert")
+    rift_key = os.path.join(rift_install, "etc", "ssl", "current.key")
+
+    if os.path.isfile(rift_cert) and os.path.isfile(rift_key):
+        return USE_SSL, rift_cert, rift_key
+
+    raise BootstrapSslMissingException()
+
diff --git a/test/conftest.py b/test/conftest.py
new file mode 100644 (file)
index 0000000..eb49b79
--- /dev/null
@@ -0,0 +1,64 @@
+import pytest
+
+def pytest_addoption(parser):
+    parser.addoption('--so-host', action='store', default='127.0.0.1')
+    parser.addoption('--so-port', action='store', default='8008')
+    parser.addoption('--so-user', action='store', default='admin')
+    parser.addoption('--so-pass', action='store', default='admin')
+    parser.addoption('--vim-type', action='store')
+    parser.addoption('--vim-host', action='store')
+    parser.addoption('--vim-user', action='store')
+    parser.addoption('--vim-tenant', action='store')
+    parser.addoption('--vim-pass', action='store')
+    parser.addoption('--package-location', action='store')
+    return parser
+
+@pytest.fixture(scope='session')
+def so_host(request):
+    """Fixture that returns --so-host option value"""
+    return request.config.getoption("--so-host")
+
+@pytest.fixture(scope='session')
+def so_port(request):
+    """Fixture that returns --so-port option value"""
+    return request.config.getoption("--so-port")
+@pytest.fixture(scope='session')
+def so_user(request):
+    """Fixture that returns --so-user option value"""
+    return request.config.getoption("--so-user")
+
+@pytest.fixture(scope='session')
+def so_pass(request):
+    """Fixture that returns --so-pass option value"""
+    return request.config.getoption("--so-pass")
+@pytest.fixture(scope='session')
+def vim_type(request):
+    """Fixture that returns --vim-type option value"""
+    return request.config.getoption("--vim-type")
+    
+@pytest.fixture(scope='session')
+def vim_host(request):
+    """Fixture that returns --vim-host option value"""
+    return request.config.getoption("--vim-host")
+    
+@pytest.fixture(scope='session')
+def vim_user(request):
+    """Fixture that returns --vim-user option value"""
+    return request.config.getoption("--vim-user")
+
+@pytest.fixture(scope='session')
+def vim_pass(request):
+    """Fixture that returns --vim-pass option value"""
+    return request.config.getoption("--vim-pass")
+
+@pytest.fixture(scope='session')
+def vim_tenant(request):
+    """Fixture that returns --vim-tenant option value"""
+    return request.config.getoption("--vim-tenant")
+
+@pytest.fixture(scope='session')
+def package_location(request):
+    """Fixture that returns --package-location option value"""
+    return request.config.getoption("--package-location")
diff --git a/test/example/config.yaml b/test/example/config.yaml
new file mode 100644 (file)
index 0000000..b6b6176
--- /dev/null
@@ -0,0 +1,8 @@
+so_host:
+    type: 'string'
+    default: '127.0.0.1'
+    description: 'Host name or ip of the SO'
+so_port:
+    type: int
+    default: 80
+    description: 'Port'
diff --git a/test/example/conftest.py b/test/example/conftest.py
new file mode 100644 (file)
index 0000000..3798a15
--- /dev/null
@@ -0,0 +1,22 @@
+import yaml
+
+
+config = None
+with open('config.yaml') as f:
+    config = yaml.load(f)
+
+
+def pytest_addoption(parser):
+    for param in config:
+        parser.addoption("--{}".format(param),
+                         action="store",
+                         type="{}".format(config[param]["type"]),
+                         default="{}".format(config[param]["default"]),
+                         help="{}".format(config[param]["description"])
+                         )
+
+
+def pytest_generate_tests(metafunc):
+    for param in config:
+        if param in metafunc.fixturenames:
+            metafunc.parametrize(param, [metafunc.config.getoption(param)])
diff --git a/test/example/test_strings.py b/test/example/test_strings.py
new file mode 100644 (file)
index 0000000..c156dc9
--- /dev/null
@@ -0,0 +1,9 @@
+
+
+def test_host(so_host):
+    assert so_host == '127.0.0.1'
+
+
+def test_port(so_host, so_port):
+    assert so_host == '127.0.0.1'
+    assert so_port == 80
diff --git a/test/test_cirros.py b/test/test_cirros.py
new file mode 100644 (file)
index 0000000..1451d11
--- /dev/null
@@ -0,0 +1,185 @@
+#!/usr/bin/env python3
+#   Copyright 2016 RIFT.IO Inc
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+
+import json
+import logging
+import pytest
+import requests
+import subprocess
+import time
+import yaml
+import certs
+
+logger = logging.getLogger(__name__)
+
+
+def chomp_json(string):
+    return ''.join([line.strip() for line in string.splitlines()])
+
+
+@pytest.fixture(scope='session')
+def session(request, so_user, so_pass):
+    client_session = requests.session()
+    client_session.auth = (so_user, so_pass)
+    client_session.headers = {
+        "Accept": "application/vnd.yang.data+json",
+        "Content-Type": "application/vnd.yang.data+json",
+    }
+    client_session.verify = False
+    _, cert, key = certs.get_bootstrap_cert_and_key()
+    client_session.cert = (cert, key)
+    return client_session
+
+
+@pytest.fixture(scope='session')
+def fetch_packages():
+    """ Fetch NSD/VNFD packages"""
+    wget_command = 'wget --no-parent -r https://osm-download.etsi.org/ftp/osm-1.0-one/vnf-packages'
+    subprocess.check_call(wget_command, shell=True)
+
+
+@pytest.fixture(scope='session')
+def rest_endpoint(so_host, so_port):
+    return 'https://{host}:{port}'.format(host=so_host, port=so_port)
+
+
+def test_so_started(session, rest_endpoint):
+    ''' Get contents of /vcs/info/components and verify all components have started successfully
+    '''
+    uri = "{endpoint}/api/operational/vcs/info/components".format(endpoint=rest_endpoint)
+    response = session.request("GET", uri)
+    vcs_info = json.loads(response.text)
+    for component in vcs_info['rw-base:components']['component_info']:
+        assert component['state'] == 'RUNNING'
+
+
+@pytest.fixture(scope='session')
+def cirros_vnfd_pkg(package_location):
+    '''cirros vnfd package location'''
+    return "%s/cirros_vnf.tar.gz" % (package_location)
+
+
+@pytest.fixture(scope='session')
+def cirros_nsd_pkg(package_location):
+    '''cirros  nsd package location'''
+    return "%s/cirros_2vnf_ns.tar.gz" % (package_location)
+
+
+def test_onboard_cirros_descriptors(session, so_host, cirros_vnfd_pkg,
+                                    cirros_nsd_pkg, rest_endpoint):
+    ''' Onboard Cirros NSD/VNFD descriptors
+    '''
+    onboard_command = 'onboard_pkg -s {host} -u {cirros_vnfd_pkg}'.format(
+        host=so_host,
+        cirros_vnfd_pkg=cirros_vnfd_pkg,
+    )
+    subprocess.check_call(onboard_command, shell=True)
+
+    onboard_command = 'onboard_pkg -s {host} -u {cirros_nsd_pkg}'.format(
+        host=so_host,
+        cirros_nsd_pkg=cirros_nsd_pkg,
+    )
+    subprocess.check_call(onboard_command, shell=True)
+
+
+def test_instantiate_cirros(session, so_host, data_center_id, rest_endpoint):
+    ''' Instantiate an instance of cirros from descriptors
+    '''
+    uri = "{endpoint}/api/operational/nsd-catalog".format(endpoint=rest_endpoint)
+    response = session.request("GET", uri)
+    catalog = json.loads(response.text)
+    cirros_nsd = None
+    for nsd in catalog['nsd:nsd-catalog']['nsd']:
+        if nsd['name'] == 'cirros_2vnf_nsd':
+            cirros_nsd = nsd
+            break
+    assert cirros_nsd is not None
+
+    instantiate_command = 'onboard_pkg -s {host} -i instance-0 -d {nsd_id} -D {data_center_id}'.format(
+        host=so_host,
+        nsd_id=cirros_nsd['id'],
+        data_center_id=data_center_id
+    )
+    subprocess.check_call(instantiate_command, shell=True)
+
+    def wait_for_cirros_ns(instance_name, timeout=600, retry_interval=5):
+        start_time = time.time()
+        while True:
+            uri = "{endpoint}/api/operational/ns-instance-opdata".format(endpoint=rest_endpoint)
+            response = session.request("GET", uri)
+            print(response, response.text)
+            opdata = json.loads(response.text)
+
+            nsr = None
+            for instance in opdata['nsr:ns-instance-opdata']['nsr']:
+                if instance['name-ref'] == instance_name:
+                    nsr = instance
+
+            assert nsr is not None, response.text
+            assert nsr['operational-status'] not in ['failed']
+            assert nsr['config-status'] not in ['failed']
+
+            if nsr['operational-status'] in ['running'] and nsr['config-status'] in ['configured']:
+                break
+
+            time_elapsed = time.time() - start_time
+            time_remaining = timeout - time_elapsed
+            assert time_remaining > 0
+            time.sleep(min(time_remaining, retry_interval))
+
+    wait_for_cirros_ns('instance-0')
+
+
+@pytest.fixture(scope='session')
+def test_add_datacenter(name, url, vim_type, tenant_id=None, tenant_name=None, user=None, password=None,
+                        description=None, config=None):
+    ''' Add a datacenter to RO
+    '''
+    onboard_command = \
+        'lxc exec RO --env OPENMANO_TENANT=osm -- openmano datacenter-create "{name}" "{url}" --type={vimtype}'.format(
+            name=name, url=url, vimtype=vim_type)
+    if description:
+        onboard_command += ' --description="{}"'.format(description)
+    out = subprocess.check_output(onboard_command, shell=True)
+    assert out
+    datacenter_id = out.split()[0]
+
+    onboard_command = 'lxc exec RO --env OPENMANO_TENANT=osm -- openmano datacenter-attach {id}'.format(
+        id=datacenter_id)
+    if tenant_id:
+        onboard_command += " --vim_tenant_id=" + tenant_id
+    if tenant_name:
+        onboard_command += " --vim_tenant_name=" + tenant_name
+    if user:
+        onboard_command += " --user=" + user
+    if password:
+        onboard_command += " --password=" + password
+    if config:
+        onboard_command += " --config=" + yaml.safe_dump(config)
+
+    subprocess.check_call(onboard_command, shell=True)
+    return datacenter_id
+
+@pytest.fixture(scope='session')
+def get_datacenter_id(name):
+    ''' Get the id of a datacenter
+    '''
+    onboard_command = \
+        'lxc exec RO --env OPENMANO_TENANT=osm -- openmano datacenter-list {name}'.format(name=name)
+    out = subprocess.check_output(onboard_command, shell=True)
+    assert(out)
+    datacenter_id = out.split()[0]
+    return datacenter_id
diff --git a/test/test_pingpong_osm.py b/test/test_pingpong_osm.py
new file mode 100644 (file)
index 0000000..ca4ba09
--- /dev/null
@@ -0,0 +1,182 @@
+#   Copyright 2016 RIFT.IO Inc
+#   Copyright 2016 Telefónica Investigación y Desarrollo S.A.U.
+#
+#   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.
+
+#!/usr/bin/env python3
+
+import json
+import logging
+import os
+import pytest
+import requests
+import requests_toolbelt
+import subprocess
+import time
+
+import certs
+
+logger = logging.getLogger(__name__)
+
+def chomp_json(string):
+    return ''.join([line.strip() for line in string.splitlines()])
+
+@pytest.fixture(scope='session')
+def session(request, so_user, so_pass):
+    client_session = requests.session()
+    client_session.auth = (so_user, so_pass)
+    client_session.headers = {
+        "Accept" : "application/vnd.yang.data+json",
+        "Content-Type" : "application/vnd.yang.data+json",
+    }
+    client_session.verify = False
+    _, cert, key = certs.get_bootstrap_cert_and_key()
+    client_session.cert = (cert, key)
+    return client_session
+
+@pytest.fixture(scope='session')
+def rest_endpoint(so_host, so_port):
+    return 'https://{host}:{port}'.format(host=so_host, port=so_port)
+
+def test_so_started(session, rest_endpoint):
+    ''' Get contents of /vcs/info/components and verify all components have started successfully
+    '''
+    uri = "{endpoint}/api/operational/vcs/info/components".format(endpoint=rest_endpoint)
+    response = session.request("GET", uri)
+    vcs_info = json.loads(response.text)
+    for component in vcs_info['rw-base:components']['component_info']:
+        assert component['state'] == 'RUNNING'
+
+def test_configure_vim_account(session, rest_endpoint, vim_type, vim_host, vim_user, vim_tenant, vim_pass):
+    ''' Configure an openstack vim account
+    '''
+    uri = "{endpoint}/api/config/cloud/account".format(
+        endpoint=rest_endpoint,
+    )
+    account = '''
+    {
+        "account":{
+            "name":"vim-0",
+            "account-type":"openstack",
+            "openstack":{
+                "admin":"True",
+                "key": "%s",
+                "secret": "%s",
+                "auth_url": "http://%s:5000/v3/",
+                "tenant": "%s",
+                "mgmt-network": "private"
+            }
+        }
+    }
+    ''' % (vim_user, vim_pass, vim_host, vim_tenant)
+    response = session.request("POST", uri, data=chomp_json(account))
+
+    uri = "{endpoint}/api/operational/cloud/account".format(endpoint=rest_endpoint)
+    response = session.request("GET", uri)
+    assert 'error' not in response.text
+    vim_accounts = json.loads(response.text)
+    assert vim_accounts
+
+    found_account = False
+    for account in vim_accounts['rw-cloud:account']:
+        if account['name'] == 'vim-0':
+            found_account = True
+            break
+    assert found_account == True
+
+
+@pytest.fixture(scope='session')
+def ping_pkg(package_location):
+    '''ping vnfd package location'''
+    return "%s/ping_vnfd.tar.gz" % (package_location)
+
+
+@pytest.fixture(scope='session')
+def pong_pkg(package_location):
+    '''pong vnfd package location'''
+    return "%s/pong_vnfd.tar.gz" % (package_location)
+
+
+@pytest.fixture(scope='session')
+def ping_pong_pkg(package_location):
+    '''ping pong nsd package location'''
+    return "%s/ping_pong_nsd.tar.gz" % (package_location)
+
+
+def test_onboard_pingpong_descriptors(session, so_host, ping_pkg, pong_pkg, ping_pong_pkg, rest_endpoint):
+    ''' Onboard ping_pong descriptors
+    '''
+    onboard_command = 'onboard_pkg -s {host} -u {ping_pkg}'.format(
+        host=so_host,
+        ping_pkg=ping_pkg,
+    )
+    subprocess.check_call(onboard_command, shell=True)
+
+    onboard_command = 'onboard_pkg -s {host} -u {pong_pkg}'.format(
+        host=so_host,
+        pong_pkg=pong_pkg,
+    )
+    subprocess.check_call(onboard_command, shell=True)
+
+    onboard_command = 'onboard_pkg -s {host} -u {ping_pong_pkg}'.format(
+        host=so_host,
+        ping_pong_pkg=ping_pong_pkg,
+    )
+    subprocess.check_call(onboard_command, shell=True)
+
+
+def test_instantiate_ping_pong(session, so_host, rest_endpoint):
+    ''' Instantiate an instance of ping pong from descriptors
+    '''
+    uri = "{endpoint}/api/operational/nsd-catalog".format(endpoint=rest_endpoint)
+    response = session.request("GET", uri)
+    catalog = json.loads(response.text)
+    ping_pong_nsd = None
+    for nsd in catalog['nsd:nsd-catalog']['nsd']:
+        if nsd['name'] == 'ping_pong_nsd':
+            ping_pong_nsd = nsd
+            break
+    assert ping_pong_nsd is not None
+
+    instantiate_command = 'onboard_pkg -s {host} -i instance-0 -d {nsd_id} -c vim-0'.format(
+        host=so_host,
+        nsd_id=ping_pong_nsd['id']
+    )
+    subprocess.check_call(instantiate_command, shell=True)
+
+    def wait_for_ping_pong(instance_name, timeout=600, retry_interval=5):
+        start_time = time.time()
+        while True:
+            uri = "{endpoint}/api/operational/ns-instance-opdata".format(endpoint=rest_endpoint)
+            response = session.request("GET", uri)
+            print(response, response.text)
+            opdata = json.loads(response.text)
+
+            nsr = None
+            for instance in opdata['nsr:ns-instance-opdata']['nsr']:
+                if instance['name-ref'] == instance_name:
+                    nsr = instance
+
+            assert nsr is not None, response.text
+            assert nsr['operational-status'] not in ['failed']
+            assert nsr['config-status'] not in ['failed']
+
+            if nsr['operational-status'] in ['running'] and nsr['config-status'] in ['configured']:
+                break
+
+            time_elapsed = time.time() - start_time
+            time_remaining = timeout - time_elapsed
+            assert time_remaining > 0
+            time.sleep(min(time_remaining, retry_interval))
+
+    wait_for_ping_pong('instance-0')