From: tierno Date: Mon, 21 Nov 2016 13:58:05 +0000 (+0100) Subject: Merge branch v1.0 (commit fb1987b) into master X-Git-Tag: v1.0.3~1^2~7 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=refs%2Fchanges%2F90%2F690%2F1;hp=eb7874615b74d3f5e7b0123c6e1dc667adff5681;p=osm%2FRO.git Merge branch v1.0 (commit fb1987b) into master Signed-off-by: tierno --- diff --git a/charms/.gitignore b/charms/.gitignore new file mode 100644 index 00000000..9f751ef9 --- /dev/null +++ b/charms/.gitignore @@ -0,0 +1,2 @@ +deps/ +builds/ diff --git a/charms/README.md b/charms/README.md new file mode 100644 index 00000000..69df3a93 --- /dev/null +++ b/charms/README.md @@ -0,0 +1,93 @@ +# Juju Charm(s) for deploying OpenMano + +## Overview +These are the charm layers used to build Juju charms for deploying OpenVIM components. These charms are also published to the [Juju Charm Store](https://jujucharms.com/) and can be deployed directly from there using the [etsi-osm](https://jujucharms.com/u/nfv/osm-r1), or they can be build from these layers and deployed locally. + +## Building the OpenVIM Charms + +To build these charms, you will need [charm-tools][]. You should also read +over the developer [Getting Started][] page for an overview of charms and +building them. Then, in any of the charm layer directories, use `charm build`. +For example: + + (setup environment to build from layers) + mkdir src + cd src + git clone https://github.com/nfvlabs/openvim.git + export JUJU_REPOSITORY=$HOME/src/openvim/charms + export INTERFACE_PATH=$JUJU_REPOSITORY/interfaces + export LAYER_PATH=$JUJU_REPOSITORY/layers + + cd $LAYER_PATH/openvim + charm build + + cd $LAYER_PATH/openvim-compute + charm build + +This will build the OpenVIM controller and OpenVIM compute charms, pulling in + the appropriate base and interface layers from [interfaces.juju.solutions][], and place the resulting charms into $JUJU_REPOSITORY/builds. + +You can also use the local version of a bundle: + + juju deploy openvim/charms/bundles/openmano.yaml + +To publish: + + # You will need an account on Launchpad, and have it added to the ~nfv + # namespace. Please contact foo@bar for these permissions. + $ charm login + + $ cd $JUJU_REPOSITORY/builds/openvim + + # `charm push` will upload the charm into the store and report the revision + # of the latest push. + $ charm push . cs:~nfv/openvim + blah blah cs:~nfv/openvim-4 + + # Release the charm so that it is publicly consumable + $ charm release cs:~nfv/openvim-4 + + $ cd $JUJU_REPOSITORY/builds/openvim-compute + + # `charm push` will upload the charm into the store and report the revision + # of the latest push. + $ charm push . cs:~nfv/openvim-compute + blah blah cs:~nfv/openvim-compute-4 + + # Release the charm so that it is publicly consumable + $ charm release cs:~nfv/openvim-compute-4 + + # Finally, update and publish the bundle to point to the latest revision(s): + + cd $JUJU_REPOSITORY/bundles/openmano + + # Edit the `README.md` to reflect any notable changes. + + # Edit the `bundle.yaml` with the new revision to be deployed, i.e., change cs:~nfv/openvim-3 to cs:~nfv/openvim-4 + + $ charm push . cs:~nfv/bundle/osm-r1 + blah blah cs:~nfv/bundle/osm-r1-4 + + $ charm release cs:~nfv/bundle/osm-r1-4 + +To deploy the published charms from the charm store: + + # The recommended method + $ charm deploy cs:~nfv/bundles/openmano + + - or - + + # The manual method + $ juju deploy cs:~nfv/openvim + $ juju deploy cs:~nfv/openvim-compute + $ juju deploy cs:~nfv/openmano + $ juju deploy cs:mariadb + + $ juju add-relation mariadb openvim + $ juju add-relation mariadb openmano + $ juju add-relation openvim openvim-compute + $ juju add-relation openvim openmano + +[charm-tools]: https://jujucharms.com/docs/stable/tools-charm-tools +[Getting Started]: https://jujucharms.com/docs/devel/developer-getting-started +[interfaces.juju.solutions]: http://interfaces.juju.solutions/ diff --git a/charms/layers/openmano/README.md b/charms/layers/openmano/README.md new file mode 100644 index 00000000..99b1fe55 --- /dev/null +++ b/charms/layers/openmano/README.md @@ -0,0 +1,3 @@ +# Overview + +Deploys OpenMANO. diff --git a/charms/layers/openmano/config.yaml b/charms/layers/openmano/config.yaml new file mode 100644 index 00000000..6c8e2508 --- /dev/null +++ b/charms/layers/openmano/config.yaml @@ -0,0 +1,9 @@ +options: + repository: + type: string + default: "https://osm.etsi.org/gerrit/osm/RO.git" + description: "The Git repository to install OpenMano from." + branch: + type: string + default: "master" + description: "The Git branch to install." diff --git a/charms/layers/openmano/icon.svg b/charms/layers/openmano/icon.svg new file mode 100644 index 00000000..3503615a --- /dev/null +++ b/charms/layers/openmano/icon.svg @@ -0,0 +1,281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/charms/layers/openmano/layer.yaml b/charms/layers/openmano/layer.yaml new file mode 100644 index 00000000..469e7f3e --- /dev/null +++ b/charms/layers/openmano/layer.yaml @@ -0,0 +1,26 @@ +includes: + - 'layer:basic' + - 'interface:mysql' + - 'interface:openvim' + - 'interface:http' + +options: + basic: + packages: + - python-yaml + - python-bottle + - python-mysqldb + - python-jsonschema + - python-paramiko + - python-argcomplete + - python-requests + - python3-git + + # These are for openstack as a VIM + # - python-novaclient + # - python-keystoneclient + # - python-glanceclient + # - python-neutronclient + + # mysql client needed to install database + - mariadb-client diff --git a/charms/layers/openmano/metadata.yaml b/charms/layers/openmano/metadata.yaml new file mode 100644 index 00000000..f8b5c99d --- /dev/null +++ b/charms/layers/openmano/metadata.yaml @@ -0,0 +1,21 @@ +name: openmano +summary: OpenMANO +maintainers: + - Adam Israel +description: | + Installs and configures OpenMANO +tags: + - nfv + - telco + - osm +series: + - xenial +subordinate: false +requires: + db: + interface: mysql + openvim-controller: + interface: openvim +provides: + openmano: + interface: http diff --git a/charms/layers/openmano/reactive/layer_openmano.py b/charms/layers/openmano/reactive/layer_openmano.py new file mode 100644 index 00000000..cc1b4741 --- /dev/null +++ b/charms/layers/openmano/reactive/layer_openmano.py @@ -0,0 +1,233 @@ +from git import Repo as gitrepo +from shutil import rmtree + +import os +import subprocess + +from charmhelpers.core import host +from charmhelpers.core import hookenv +from charmhelpers.core import templating +from charmhelpers.core.unitdata import kv +from charmhelpers.core.hookenv import ( + config, + log, + open_port, + status_set, +) + +from charmhelpers.core.host import ( + chownr, +) + +from charms.reactive import ( + when, + when_not, + set_state, + is_state, +) + +kvdb = kv() + +INSTALL_PATH = '/opt/openmano' +USER = 'openmanod' + + +@when('openmano.installed') +@when('openmano.available') +def openmano_available(openmano): + # TODO make this configurable via charm config + openmano.configure(port=9090) + + +@when('openmano.installed') +@when('db.available', 'db.installed') +@when('openvim-controller.available') +@when('openmano.running') +def openvim_available(openvim, db): + for service in openvim.services(): + for endpoint in service['hosts']: + host = endpoint['hostname'] + port = endpoint['port'] + user = endpoint['user'] + + openvim_uri = '{}:{}'.format(host, port) + if kvdb.get('openvim_uri') == openvim_uri: + return + + # TODO: encapsulate the logic in create-datacenter.sh into python + try: + cmd = './scripts/create-datacenter.sh {} {} {} {}'.format( + host, port, user, kvdb.get('openmano-tenant')) + out, err = _run(cmd) + except subprocess.CalledProcessError as e: + # Ignore the error if the datacenter already exists. + if e.returncode != 153: + raise + + kvdb.set('openvim_uri', openvim_uri) + if not is_state('db.available'): + status_set('waiting', 'Waiting for database') + break + break + + +@when('openmano.installed') +@when('db.available', 'db.installed') +@when('openvim-controller.available') +@when_not('openmano.running') +def start(*args): + # TODO: if the service fails to start, we should raise an error to the op + # Right now, it sets the state as running and the charm dies. Because + # service-openmano returns 0 when it fails. + cmd = "/home/{}/bin/service-openmano start".format(USER) + out, err = _run(cmd) + + if not kvdb.get('openmano-tenant'): + out, err = _run('./scripts/create-tenant.sh') + kvdb.set('openmano-tenant', out.strip()) + + status_set( + 'active', + 'Up on {host}:{port}'.format( + host=hookenv.unit_public_ip(), + port='9090')) + + set_state('openmano.running') + + +@when('openmano.installed') +@when('db.available') +@when_not('db.installed') +def setup_db(db): + """Setup the database + + """ + db_uri = 'mysql://{}:{}@{}:{}/{}'.format( + db.user(), + db.password(), + db.host(), + db.port(), + db.database(), + ) + + if kvdb.get('db_uri') == db_uri: + # We're already configured + return + + status_set('maintenance', 'Initializing database') + + try: + # HACK: use a packed version of init_mano_db until bug https://osm.etsi.org/bugzilla/show_bug.cgi?id=56 is fixed + # cmd = "{}/database_utils/init_mano_db.sh --createdb ".format(kvdb.get('repo')) + cmd = "./scripts//init_mano_db.sh --createdb " + cmd += "-u {} -p{} -h {} -d {} -P {}".format( + db.user(), + db.password(), + db.host(), + db.database(), + db.port(), + ) + output, err = _run(cmd) + except subprocess.CalledProcessError: + # Eat this. init_mano_db.sh will return error code 1 on success + pass + + context = { + 'user': db.user(), + 'password': db.password(), + 'host': db.host(), + 'database': db.database(), + 'port': db.port(), + } + templating.render( + 'openmanod.cfg', + os.path.join(kvdb.get('repo'), 'openmanod.cfg'), + context, + owner=USER, + group=USER, + ) + kvdb.set('db_uri', db_uri) + + status_set('active', 'Database installed.') + set_state('db.installed') + +@when_not('openvim-controller.available') +def need_openvim(): + status_set('waiting', 'Waiting for OpenVIM') + + +@when_not('db.available') +def need_db(): + status_set('waiting', 'Waiting for database') + + +@when_not('db.available') +@when_not('openvim-controller.available') +def need_everything(): + status_set('waiting', 'Waiting for database and OpenVIM') + + +@when_not('openmano.installed') +def install_layer_openmano(): + status_set('maintenance', 'Installing') + + cfg = config() + + # TODO change user home + # XXX security issue! + host.adduser(USER, password=USER) + + if os.path.isdir(INSTALL_PATH): + rmtree(INSTALL_PATH) + + gitrepo.clone_from( + cfg['repository'], + INSTALL_PATH, + branch=cfg['branch'], + ) + + chownr( + INSTALL_PATH, + owner=USER, + group=USER, + follow_links=False, + chowntopdir=True + ) + + os.mkdir(os.path.join(INSTALL_PATH, 'logs')) + chownr(INSTALL_PATH, USER, USER) + kvdb.set('repo', INSTALL_PATH) + + os.mkdir('/home/{}/bin'.format(USER)) + + os.symlink( + "{}/openmano".format(INSTALL_PATH), + "/home/{}/bin/openmano".format(USER)) + os.symlink( + "{}/scripts/openmano-report.sh".format(INSTALL_PATH), + "/home/{}/bin/openmano-report.sh".format(USER)) + os.symlink( + "{}/scripts/service-openmano.sh".format(INSTALL_PATH), + "/home/{}/bin/service-openmano".format(USER)) + + open_port(9090) + set_state('openmano.installed') + + +def _run(cmd, env=None): + if isinstance(cmd, str): + cmd = cmd.split() if ' ' in cmd else [cmd] + + log(cmd) + p = subprocess.Popen(cmd, + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + retcode = p.poll() + if retcode > 0: + raise subprocess.CalledProcessError( + returncode=retcode, + cmd=cmd, + output=stderr.decode("utf-8").strip()) + return (stdout.decode('utf-8'), stderr.decode('utf-8')) diff --git a/charms/layers/openmano/scripts/create-datacenter.sh b/charms/layers/openmano/scripts/create-datacenter.sh new file mode 100755 index 00000000..4b192e49 --- /dev/null +++ b/charms/layers/openmano/scripts/create-datacenter.sh @@ -0,0 +1,23 @@ +#!/bin/sh +HOME=/home/openmanod +OPENMANO=$HOME/bin/openmano +export OPENMANO_TENANT=$4 + +OPENMANO_DATACENTER=`$OPENMANO datacenter-list myov` +if [ $? -ne 0 ]; then + # Make sure the datacenter is deleted + $OPENMANO datacenter-delete myov + OPENMANO_DATACENTER=`$OPENMANO datacenter-create myov http://$1:$2/openvim` +fi +export OPENMANO_DATACENTER=`echo $OPENMANO_DATACENTER |gawk '{print $1}'` + +#export OPENMANO_DATACENTER=`$OPENMANO datacenter-create myov http://$1:$2/openvim |gawk '{print $1}'` +# FIXME: don't add this to .bashrc if it already exists. +if ! grep -q "^export OPENMANO_DATACENTER" $HOME/.bashrc +then + echo "export OPENMANO_DATACENTER=$OPENMANO_DATACENTER " >> $HOME/.bashrc +fi + +# TODO: Test idempotency. We may need to check and remove existing data +$OPENMANO datacenter-attach myov --vim-tenant-id $3 +$OPENMANO datacenter-netmap-import -f --datacenter $OPENMANO_DATACENTER diff --git a/charms/layers/openmano/scripts/create-tenant.sh b/charms/layers/openmano/scripts/create-tenant.sh new file mode 100755 index 00000000..1cb644c7 --- /dev/null +++ b/charms/layers/openmano/scripts/create-tenant.sh @@ -0,0 +1,7 @@ +#!/bin/sh +OPENMANO=/home/openmanod/bin/openmano +OPENMANO_TENANT=`$OPENMANO tenant-create mytenant --description=mytenant` +if [ $? -ne 0 ]; then + OPENMANO_TENANT=`$OPENMANO tenant-list mytenant` +fi +echo $OPENMANO_TENANT |gawk '{print $1}' diff --git a/charms/layers/openmano/scripts/init_mano_db.sh b/charms/layers/openmano/scripts/init_mano_db.sh new file mode 100755 index 00000000..9d8b1581 --- /dev/null +++ b/charms/layers/openmano/scripts/init_mano_db.sh @@ -0,0 +1,142 @@ +#!/bin/bash + +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openmano +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## + +DBUSER="mano" +DBPASS="" +DBHOST="localhost" +DBPORT="3306" +DBNAME="mano_db" +CREATEDB="" + +# Detect paths +MYSQL=$(which mysql) +AWK=$(which awk) +GREP=$(which grep) +#DIRNAME=`dirname $0` +DIRNAME=/opt/openmano/database_utils + +function usage(){ + echo -e "Usage: $0 OPTIONS" + echo -e " Inits openmano database; deletes previous one and loads from ${DBNAME}_structure.sql" + echo -e " OPTIONS" + echo -e " -u USER database user. '$DBUSER' by default. Prompts if DB access fails" + echo -e " -p PASS database password. 'No password' by default. Prompts if DB access fails" + echo -e " -P PORT database port. '$DBPORT' by default" + echo -e " -h HOST database host. '$DBHOST' by default" + echo -e " -d NAME database name. '$DBNAME' by default. Prompts if DB access fails" + echo -e " --help shows this help" + echo -e " --createdb forces the deletion and creation of the database" +} + +while getopts ":u:p:P:d:h:-:" o; do + case "${o}" in + u) + DBUSER="$OPTARG" + ;; + p) + DBPASS="$OPTARG" + ;; + P) + DBPORT="$OPTARG" + ;; + d) + DBNAME="$OPTARG" + ;; + h) + DBHOST="$OPTARG" + ;; + -) + if [ "${OPTARG}" == "help" ]; then + usage && exit 0 + elif [ "${OPTARG}" == "createdb" ]; then + CREATEDB="yes" + else + echo "Invalid option: --$OPTARG" >&2 && usage >&2 + exit 1 + fi + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 && usage >&2 + exit 1 + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 && usage >&2 + exit 1 + ;; + *) + usage >&2 + exit -1 + ;; + esac +done +shift $((OPTIND-1)) + +#check and ask for database user password +DBUSER_="-u$DBUSER" +DBPASS_="" +[ -n "$DBPASS" ] && DBPASS_="-p$DBPASS" +DBHOST_="-h$DBHOST" +DBPORT_="-P$DBPORT" + +TEMPFILE="$(mktemp -q --tmpdir "initmanodb.XXXXXX")" +trap 'rm -f "$TEMPFILE"' EXIT SIGINT SIGTERM +chmod 0600 "$TEMPFILE" +cat >"$TEMPFILE" </dev/null 2>&1 +do + [ -n "$logintry" ] && echo -e "\nInvalid database credentials!!!. Try again (Ctrl+c to abort)" + [ -z "$logintry" ] && echo -e "\nProvide database credentials" +# read -e -p "mysql database name($DBNAME): " KK +# [ -n "$KK" ] && DBNAME="$KK" + read -e -p "mysql user($DBUSER): " KK + [ -n "$KK" ] && DBUSER="$KK" + read -e -s -p "mysql password: " DBPASS + cat >"$TEMPFILE" <, "to":} entry +#e.g. from 9000 to 9005: [{"from":9000, "to":9005}], or also [9000,9001,9002,9003,9004,9005] +#e.g. from 9000 to 9100 apart from 9050,9053: [{"from":9000, "to":9049},9051,9052,{"from":9054, "to":9099}] +http_console_ports: [{"from":9096, "to":9110}] + +#Database parameters +db_host: {{host}} # by default localhost +db_user: {{user}} # DB user +db_passwd: {{password}} # DB password +db_name: {{database}} # Name of the MANO DB + +#other MANO parameters +# Folder where the VNF descriptors will be stored +# The folder will be created in the execution folder if it does not exist +vnf_repository: "./vnfrepo" # Use an absolute path to avoid misunderstandings diff --git a/charms/layers/openmano/tests/00-setup b/charms/layers/openmano/tests/00-setup new file mode 100755 index 00000000..f0616a56 --- /dev/null +++ b/charms/layers/openmano/tests/00-setup @@ -0,0 +1,5 @@ +#!/bin/bash + +sudo add-apt-repository ppa:juju/stable -y +sudo apt-get update +sudo apt-get install amulet python-requests -y diff --git a/charms/layers/openmano/tests/10-deploy b/charms/layers/openmano/tests/10-deploy new file mode 100755 index 00000000..7dce664c --- /dev/null +++ b/charms/layers/openmano/tests/10-deploy @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +import amulet +import requests +import unittest + + +class TestCharm(unittest.TestCase): + def setUp(self): + self.d = amulet.Deployment() + + self.d.add('layer-openmano') + self.d.expose('layer-openmano') + + self.d.setup(timeout=900) + self.d.sentry.wait() + + self.unit = self.d.sentry['layer-openmano'][0] + + def test_service(self): + # test we can access over http + page = requests.get('http://{}'.format(self.unit.info['public-address'])) + self.assertEqual(page.status_code, 200) + # Now you can use self.d.sentry[SERVICE][UNIT] to address each of the units and perform + # more in-depth steps. Each self.d.sentry[SERVICE][UNIT] has the following methods: + # - .info - An array of the information of that unit from Juju + # - .file(PATH) - Get the details of a file on that unit + # - .file_contents(PATH) - Get plain text output of PATH file from that unit + # - .directory(PATH) - Get details of directory + # - .directory_contents(PATH) - List files and folders in PATH on that unit + # - .relation(relation, service:rel) - Get relation data from return service diff --git a/database_utils/init_mano_db.sh b/database_utils/init_mano_db.sh index 224269bc..f7401a0f 100755 --- a/database_utils/init_mano_db.sh +++ b/database_utils/init_mano_db.sh @@ -129,7 +129,7 @@ if [ -n "${CREATEDB}" ]; then echo " deleting previous database ${DBNAME}" echo "DROP DATABASE IF EXISTS ${DBNAME}" | mysql $DEF_EXTRA_FILE_PARAM $DBHOST_ $DBPORT_ echo " creating database ${DBNAME}" - mysqladmin $DEF_EXTRA_FILE_PARAM -s create ${DBNAME} || exit 1 + mysqladmin $DEF_EXTRA_FILE_PARAM $DBHOST_ $DBPORT_ -s create ${DBNAME} || exit 1 fi echo " loading ${DIRNAME}/${DBNAME}_structure.sql" diff --git a/database_utils/migrate_mano_db.sh b/database_utils/migrate_mano_db.sh index ae1ef15c..e69d8a5a 100755 --- a/database_utils/migrate_mano_db.sh +++ b/database_utils/migrate_mano_db.sh @@ -43,7 +43,7 @@ function usage(){ echo -e " if openmano_version is not provided it tries to get from openmanod.py using relative path" echo -e " OPTIONS" echo -e " -u USER database user. '$DBUSER' by default. Prompts if DB access fails" - echo -e " -p PASS database password. 'No password' by default. Prompts if DB access fails" + echo -e " -p PASS database password. 'No password' or 'manopw' by default. Prompts if DB access fails" echo -e " -P PORT database port. '$DBPORT' by default" echo -e " -h HOST database host. '$DBHOST' by default" echo -e " -d NAME database name. '$DBNAME' by default. Prompts if DB access fails" @@ -113,20 +113,23 @@ OPENMANO_VER_NUM=`printf "%d%03d%03d" ${VERSION_1} ${VERSION_2} ${VERSION_3}` TEMPFILE="$(mktemp -q --tmpdir "migratemanodb.XXXXXX")" trap 'rm -f "$TEMPFILE"' EXIT chmod 0600 "$TEMPFILE" -cat >"$TEMPFILE" </dev/null 2>&1 +DEF_EXTRA_FILE_PARAM="--defaults-extra-file=$TEMPFILE" +if [ -z "${DBPASS}" ] +then + password_ok="" + echo -e "[client]\nuser='${DBUSER}'\npassword='manopw'" > "$TEMPFILE" + mysql "$DEF_EXTRA_FILE_PARAM" $DBHOST_ $DBPORT_ $DBNAME -e "quit" >/dev/null 2>&1 && DBPASS="manopw" + echo -e "[client]\nuser='${DBUSER}'\npassword=''" > "$TEMPFILE" + mysql "$DEF_EXTRA_FILE_PARAM" $DBHOST_ $DBPORT_ $DBNAME -e "quit" >/dev/null 2>&1 && DBPASS="" +fi +echo -e "[client]\nuser='${DBUSER}'\npassword='${DBPASS}'" > "$TEMPFILE" + +#check and ask for database user password +while ! mysql "$DEF_EXTRA_FILE_PARAM" $DBHOST_ $DBPORT_ $DBNAME -e "quit" >/dev/null 2>&1 do [ -n "$logintry" ] && echo -e "\nInvalid database credentials!!!. Try again (Ctrl+c to abort)" [ -z "$logintry" ] && echo -e "\nProvide database name and credentials" @@ -135,11 +138,7 @@ do read -e -p "mysql user($DBUSER): " KK [ -n "$KK" ] && DBUSER="$KK" read -e -s -p "mysql password: " DBPASS - cat >"$TEMPFILE" < "$TEMPFILE" logintry="yes" echo done @@ -184,6 +183,7 @@ DATABASE_TARGET_VER_NUM=0 [ $OPENMANO_VER_NUM -ge 4047 ] && DATABASE_TARGET_VER_NUM=13 #0.4.47=> 13 [ $OPENMANO_VER_NUM -ge 4057 ] && DATABASE_TARGET_VER_NUM=14 #0.4.57=> 14 [ $OPENMANO_VER_NUM -ge 4059 ] && DATABASE_TARGET_VER_NUM=15 #0.4.59=> 15 +[ $OPENMANO_VER_NUM -ge 5002 ] && DATABASE_TARGET_VER_NUM=16 #0.5.2 => 16 #TODO ... put next versions here @@ -665,6 +665,23 @@ function downgrade_from_15(){ echo "DELETE FROM schema_version WHERE version_int='15';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 } +function upgrade_to_16(){ + echo " upgrade database from version 0.15 to version 0.16" + echo " add column 'config' at table 'datacenter_tenants', enlarge 'vim_tenant_name/id'" + echo "ALTER TABLE datacenter_tenants ADD COLUMN config VARCHAR(4000) NULL DEFAULT NULL AFTER passwd;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "ALTER TABLE datacenter_tenants CHANGE COLUMN vim_tenant_name vim_tenant_name VARCHAR(256) NULL DEFAULT NULL AFTER datacenter_id;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "ALTER TABLE datacenter_tenants CHANGE COLUMN vim_tenant_id vim_tenant_id VARCHAR(256) NULL DEFAULT NULL COMMENT 'Tenant ID at VIM' AFTER vim_tenant_name;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) VALUES (16, '0.16', '0.5.2', 'enlarge vim_tenant_name and id. New config at datacenter_tenants', '2016-10-11');" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 +} +function downgrade_from_16(){ + echo " downgrade database from version 0.16 to version 0.15" + echo " remove column 'config' at table 'datacenter_tenants', restoring lenght 'vim_tenant_name/id'" + echo "ALTER TABLE datacenter_tenants DROP COLUMN config" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "ALTER TABLE datacenter_tenants CHANGE COLUMN vim_tenant_name vim_tenant_name VARCHAR(64) NULL DEFAULT NULL AFTER datacenter_id;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "ALTER TABLE datacenter_tenants CHANGE COLUMN vim_tenant_id vim_tenant_id VARCHAR(36) NULL DEFAULT NULL COMMENT 'Tenant ID at VIM' AFTER vim_tenant_name;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "DELETE FROM schema_version WHERE version_int='16';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 +} + function upgrade_to_X(){ echo " change 'datacenter_nets'" echo "ALTER TABLE datacenter_nets ADD COLUMN vim_tenant_id VARCHAR(36) NOT NULL AFTER datacenter_id, DROP INDEX name_datacenter_id, ADD UNIQUE INDEX name_datacenter_id (name, datacenter_id, vim_tenant_id);" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 diff --git a/db_base.py b/db_base.py index f6a5c59a..807c73d5 100644 --- a/db_base.py +++ b/db_base.py @@ -75,7 +75,7 @@ def _convert_datetime2str(var): for v in var: _convert_datetime2str(v) -def _convert_bandwidth(data, reverse=False): +def _convert_bandwidth(data, reverse=False, logger=None): '''Check the field bandwidth recursivelly and when found, it removes units and convert to number It assumes that bandwidth is well formed Attributes: @@ -87,7 +87,7 @@ def _convert_bandwidth(data, reverse=False): if type(data) is dict: for k in data.keys(): if type(data[k]) is dict or type(data[k]) is tuple or type(data[k]) is list: - _convert_bandwidth(data[k], reverse) + _convert_bandwidth(data[k], reverse, logger) if "bandwidth" in data: try: value=str(data["bandwidth"]) @@ -102,12 +102,13 @@ def _convert_bandwidth(data, reverse=False): if value % 1000 == 0: data["bandwidth"]=str(value/1000) + " Gbps" else: data["bandwidth"]=str(value) + " Mbps" except: - print "convert_bandwidth exception for type", type(data["bandwidth"]), " data", data["bandwidth"] + if logger: + logger.error("convert_bandwidth exception for type '%s' data '%s'", type(data["bandwidth"]), data["bandwidth"]) return if type(data) is tuple or type(data) is list: for k in data: if type(k) is dict or type(k) is tuple or type(k) is list: - _convert_bandwidth(k, reverse) + _convert_bandwidth(k, reverse, logger) def _convert_str2boolean(data, items): '''Check recursively the content of data, and if there is an key contained in items, convert value from string to boolean @@ -164,10 +165,11 @@ class db_base(): if database: self.database = database self.con = mdb.connect(self.host, self.user, self.passwd, self.database) - print "DB: connected to %s@%s -> %s" % (self.user, self.host, self.database) - except mdb.Error, e: - raise db_base_Exception("Cannot connect to DB {}@{} -> {} Error {}: {}".format(self.user, self.host, self.database, e.args[0], e.args[1]), - code = HTTP_Internal_Server_Error ) + self.logger.debug("DB: connected to '%s' at '%s@%s'", self.database, self.user, self.host) + except mdb.Error as e: + raise db_base_Exception("Cannot connect to DataBase '{}' at '{}@{}' Error {}: {}".format( + self.database, self.user, self.host, e.args[0], e.args[1]), + http_code = HTTP_Unauthorized ) def get_db_version(self): ''' Obtain the database schema version. diff --git a/httpserver.py b/httpserver.py index cd40882f..789e0224 100644 --- a/httpserver.py +++ b/httpserver.py @@ -450,7 +450,7 @@ def http_get_datacenter_id(tenant_id, datacenter_id): what = 'uuid' if utils.check_valid_uuid(datacenter_id) else 'name' where_={} where_[what] = datacenter_id - select_=['uuid', 'name','vim_url', 'vim_url_admin', 'type', 'config', 'description', 'd.created_at as created_at'] + select_=['uuid', 'name','vim_url', 'vim_url_admin', 'type', 'd.config as config', 'description', 'd.created_at as created_at'] if tenant_id != 'any': select_.append("datacenter_tenant_id") where_['td.nfvo_tenant_id']= tenant_id @@ -470,13 +470,22 @@ def http_get_datacenter_id(tenant_id, datacenter_id): if tenant_id != 'any': #get vim tenant info vim_tenants = mydb.get_rows( - SELECT=("vim_tenant_name", "vim_tenant_id", "user"), + SELECT=("vim_tenant_name", "vim_tenant_id", "user", "passwd", "config"), FROM="datacenter_tenants", WHERE={"uuid": datacenters[0]["datacenter_tenant_id"]}, ORDER_BY=("created", ) ) del datacenter["datacenter_tenant_id"] datacenter["vim_tenants"] = vim_tenants - + for vim_tenant in vim_tenants: + if vim_tenant["passwd"]: + vim_tenant["passwd"] = "******" + if vim_tenant['config'] != None: + try: + config_dict = yaml.load(vim_tenant['config']) + vim_tenant['config'] = config_dict + except Exception, e: + logger.error("Exception '%s' while trying to load config information", str(e)) + if datacenter['config'] != None: try: config_dict = yaml.load(datacenter['config']) @@ -719,8 +728,9 @@ def http_associate_datacenters(tenant_id, datacenter_id): http_content['datacenter'].get('vim_tenant'), http_content['datacenter'].get('vim_tenant_name'), http_content['datacenter'].get('vim_username'), - http_content['datacenter'].get('vim_password') - ) + http_content['datacenter'].get('vim_password'), + http_content['datacenter'].get('config') + ) return http_get_datacenter_id(tenant_id, id_) except (nfvo.NfvoException, db_base_Exception) as e: logger.error("http_associate_datacenters error {}: {}".format(e.http_code, str(e))) diff --git a/nfvo.py b/nfvo.py index 9f360ce1..e529d5f2 100644 --- a/nfvo.py +++ b/nfvo.py @@ -108,9 +108,9 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da if vim_tenant_name is not None: WHERE_dict['vim_tenant_name'] = vim_tenant_name if nfvo_tenant or vim_tenant or vim_tenant_name or datacenter_tenant_id: from_= 'tenants_datacenters as td join datacenters as d on td.datacenter_id=d.uuid join datacenter_tenants as dt on td.datacenter_tenant_id=dt.uuid' - select_ = ('type','config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name', + select_ = ('type','d.config as config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name', 'dt.uuid as datacenter_tenant_id','dt.vim_tenant_name as vim_tenant_name','dt.vim_tenant_id as vim_tenant_id', - 'user','passwd') + 'user','passwd', 'dt.config as dt_config') else: from_ = 'datacenters as d' select_ = ('type','config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name') @@ -119,8 +119,10 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da vim_dict={} for vim in vims: extra={'datacenter_tenant_id': vim.get('datacenter_tenant_id')} - if vim["config"] != None: + if vim["config"]: extra.update(yaml.load(vim["config"])) + if vim.get('dt_config'): + extra.update(yaml.load(vim["dt_config"])) if vim["type"] not in vimconn_imported: module_info=None try: @@ -2169,6 +2171,8 @@ def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenan has_mgmt_iface = True if vm_dict[vm_id]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface: vm_dict[vm_id]['status'] = "ACTIVE" + if vm_dict[vm_id].get('error_msg') and len(vm_dict[vm_id]['error_msg']) >= 1024: + vm_dict[vm_id]['error_msg'] = vm_dict[vm_id]['error_msg'][:516] + " ... " + vm_dict[vm_id]['error_msg'][-500:] if vm['status'] != vm_dict[vm_id]['status'] or vm.get('error_msg')!=vm_dict[vm_id].get('error_msg') or vm.get('vim_info')!=vm_dict[vm_id].get('vim_info'): vm['status'] = vm_dict[vm_id]['status'] vm['error_msg'] = vm_dict[vm_id].get('error_msg') @@ -2221,6 +2225,8 @@ def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenan # TODO: update nets inside a vnf for net in instanceDict['nets']: net_id = net['vim_net_id'] + if net_dict[net_id].get('error_msg') and len(net_dict[net_id]['error_msg']) >= 1024: + net_dict[net_id]['error_msg'] = net_dict[net_id]['error_msg'][:516] + " ... " + net_dict[vm_id]['error_msg'][-500:] if net['status'] != net_dict[net_id]['status'] or net.get('error_msg')!=net_dict[net_id].get('error_msg') or net.get('vim_info')!=net_dict[net_id].get('vim_info'): net['status'] = net_dict[net_id]['status'] net['error_msg'] = net_dict[net_id].get('error_msg') @@ -2409,7 +2415,7 @@ def delete_datacenter(mydb, datacenter): mydb.delete_row_by_id("datacenters", datacenter_dict['uuid']) return datacenter_dict['uuid'] + " " + datacenter_dict['name'] -def associate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter, vim_tenant_id=None, vim_tenant_name=None, vim_username=None, vim_password=None): +def associate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter, vim_tenant_id=None, vim_tenant_name=None, vim_username=None, vim_password=None, config=None): #get datacenter info datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter) datacenter_name=myvim["name"] @@ -2459,6 +2465,8 @@ def associate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter, vim_tenant_id= datacenter_tenants_dict["user"] = vim_username datacenter_tenants_dict["passwd"] = vim_password datacenter_tenants_dict["datacenter_id"] = datacenter_id + if config: + datacenter_tenants_dict["config"] = yaml.safe_dump(config, default_flow_style=True, width=256) id_ = mydb.new_row('datacenter_tenants', datacenter_tenants_dict, add_uuid=True) datacenter_tenants_dict["uuid"] = id_ diff --git a/nfvo_db.py b/nfvo_db.py index 1fa5d723..6ab73e95 100644 --- a/nfvo_db.py +++ b/nfvo_db.py @@ -81,7 +81,7 @@ class nfvo_db(db_base.db_base): dataifacesDict[vm['name']] = {} for numa in vm.get('numas', []): for dataiface in numa.get('interfaces',[]): - db_base._convert_bandwidth(dataiface) + db_base._convert_bandwidth(dataiface, logger=self.logger) dataifacesDict[vm['name']][dataiface['name']] = {} dataifacesDict[vm['name']][dataiface['name']]['vpci'] = dataiface['vpci'] dataifacesDict[vm['name']][dataiface['name']]['bw'] = dataiface['bandwidth'] @@ -93,7 +93,7 @@ class nfvo_db(db_base.db_base): if 'bridge-ifaces' in vm: bridgeInterfacesDict[vm['name']] = {} for bridgeiface in vm['bridge-ifaces']: - db_base._convert_bandwidth(bridgeiface) + db_base._convert_bandwidth(bridgeiface, logger=self.logger) bridgeInterfacesDict[vm['name']][bridgeiface['name']] = {} bridgeInterfacesDict[vm['name']][bridgeiface['name']]['vpci'] = bridgeiface.get('vpci',None) bridgeInterfacesDict[vm['name']][bridgeiface['name']]['mac'] = bridgeiface.get('mac_address',None) @@ -209,7 +209,7 @@ class nfvo_db(db_base.db_base): dataifacesDict[vm['name']] = {} for numa in vm.get('numas', []): for dataiface in numa.get('interfaces',[]): - db_base._convert_bandwidth(dataiface) + db_base._convert_bandwidth(dataiface, logger=self.logger) dataifacesDict[vm['name']][dataiface['name']] = {} dataifacesDict[vm['name']][dataiface['name']]['vpci'] = dataiface['vpci'] dataifacesDict[vm['name']][dataiface['name']]['bw'] = dataiface['bandwidth'] @@ -221,7 +221,7 @@ class nfvo_db(db_base.db_base): if 'bridge-ifaces' in vm: bridgeInterfacesDict[vm['name']] = {} for bridgeiface in vm['bridge-ifaces']: - db_base._convert_bandwidth(bridgeiface) + db_base._convert_bandwidth(bridgeiface, logger=self.logger) bridgeInterfacesDict[vm['name']][bridgeiface['name']] = {} bridgeInterfacesDict[vm['name']][bridgeiface['name']]['vpci'] = bridgeiface.get('vpci',None) bridgeInterfacesDict[vm['name']][bridgeiface['name']]['mac'] = bridgeiface.get('mac_address',None) diff --git a/openmano b/openmano index 818e7173..6c546c12 100755 --- a/openmano +++ b/openmano @@ -28,8 +28,8 @@ openmano client used to interact with openmano-server (openmanod) ''' __author__="Alfonso Tierno, Gerardo Garcia" __date__ ="$09-oct-2014 09:09:48$" -__version__="0.4.6-r500" -version_date="Sep 2016" +__version__="0.4.7-r511" +version_date="Oct 2016" from argcomplete.completers import FilesCompleter import os @@ -889,6 +889,8 @@ def datacenter_attach(args): datacenter_dict['vim_username'] = args.user if args.password != None: datacenter_dict['vim_password'] = args.password + if args.config!=None: + datacenter_dict["config"] = _load_file_or_yaml(args.config) payload_req = json.dumps( {"datacenter": datacenter_dict }) #print payload_req @@ -1335,6 +1337,7 @@ if __name__=="__main__": datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.") datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter") datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter") + datacenter_attach_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format") datacenter_attach_parser.set_defaults(func=datacenter_attach) datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant") diff --git a/openmano_schemas.py b/openmano_schemas.py index e1fc2bd7..ffbacd3a 100644 --- a/openmano_schemas.py +++ b/openmano_schemas.py @@ -275,10 +275,11 @@ datacenter_associate_schema={ "datacenter":{ "type":"object", "properties":{ - "vim_tenant": id_schema, - "vim_tenant_name": nameshort_schema, + "vim_tenant": name_schema, + "vim_tenant_name": name_schema, "vim_username": nameshort_schema, "vim_password": nameshort_schema, + "config": {"type": "object"} }, # "required": ["vim_tenant"], "additionalProperties": True diff --git a/openmanoconfig.py b/openmanoconfig.py new file mode 100755 index 00000000..07c5e247 --- /dev/null +++ b/openmanoconfig.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openmano +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## + + +""" +Read openmanod.cfg file and creates envioronment variables for openmano client +Call it wusing execution quotes, or copy paste the output to set your shell envioronment +It read database to look for a ninc tenant / datacenter +""" + +from __future__ import print_function +from os import environ +from openmanod import load_configuration +#from socket import gethostname +from db_base import db_base_Exception +import nfvo_db +import getopt +import sys + + +__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes" +__date__ ="$26-aug-2014 11:09:29$" +__version__="0.0.1-r509" +version_date="Oct 2016" +database_version="0.16" #expected database schema version + + +def usage(): + print("Usage: ", sys.argv[0], "[options]") + print(" -v|--version: prints current version") + print(" -c|--config [configuration_file]: loads the configuration file (default: openmanod.cfg)") + print(" -h|--help: shows this help") + return + + +if __name__ == "__main__": + # Read parameters and configuration file + try: + # load parameters and configuration + opts, args = getopt.getopt(sys.argv[1:], "vhc:", + ["config=", "help", "version"]) + config_file = 'openmanod.cfg' + + for o, a in opts: + if o in ("-v", "--version"): + print("openmanoconfig.py version " + __version__ + ' ' + version_date) + print("(c) Copyright Telefonica") + exit() + elif o in ("-h", "--help"): + usage() + exit() + elif o in ("-c", "--config"): + config_file = a + else: + assert False, "Unhandled option" + global_config = load_configuration(config_file) + if global_config["http_host"] == "0.0.0.0": + global_config["http_host"] = "localhost" #gethostname() + environ["OPENMANO_HOST"]=global_config["http_host"] + print("export OPENMANO_HOST='{}'".format(global_config["http_host"])) + environ["OPENMANO_PORT"] = str(global_config["http_port"]) + print("export OPENMANO_PORT={}".format(global_config["http_port"])) + + mydb = nfvo_db.nfvo_db(); + mydb.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name']) + try: + tenants = mydb.get_rows(FROM="nfvo_tenants") + if not tenants: + print("#No tenant found", file=sys.stderr) + elif len(tenants) > 1: + print("#Found several tenants export OPENMANO_TENANT=", file=sys.stderr, end="") + for tenant in tenants: + print(" '{}'".format(tenant["name"]), file=sys.stderr, end="") + print("") + else: + environ["OPENMANO_TENANT"] = tenants[0]["name"] + print("export OPENMANO_TENANT='{}'".format(tenants[0]["name"])) + + dcs = mydb.get_rows(FROM="datacenters") + if not dcs: + print("#No datacenter found", file=sys.stderr) + elif len(dcs) > 1: + print("#Found several datacenters export OPENMANO_DATACENTER=", file=sys.stderr, end="") + for dc in dcs: + print(" '{}'".format(dc["name"]), file=sys.stderr, end="") + print("") + else: + environ["OPENMANO_DATACENTER"] = dcs[0]["name"] + print("export OPENMANO_DATACENTER='{}'".format(dcs[0]["name"])) + + except db_base_Exception as e: + print("#DATABASE is not a MANO one or it is a '0.0' version. Try to upgrade to version '{}' with \ + './database_utils/migrate_mano_db.sh'".format(database_version), file=sys.stderr) + exit(-1) + + + + except db_base_Exception as e: + print("#"+str(e), file=sys.stderr) + exit(-1) + + except SystemExit: + pass diff --git a/openmanoconfig.sh b/openmanoconfig.sh deleted file mode 100755 index 696ad939..00000000 --- a/openmanoconfig.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -## -# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. -# This file is part of openmano -# 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. -# -# For those usages not covered by the Apache License, Version 2.0 please -# contact with: nfvlabs@tid.es -## - -export OPENMANO_HOST=localhost -export OPENMANO_PORT=9090 -export OPENMANO_TENANT=bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb #Use here the appropriate tenant id provided by openmano after creating the tenant -#Uncomment the following line in case that there are several datacenters and use the appropriate id -#export OPENMANO_DATACENTER=dddddddd-dddd-dddd-dddd-dddddddddddd - diff --git a/openmanod.py b/openmanod.py index 7d183eb7..bbbd7d30 100755 --- a/openmanod.py +++ b/openmanod.py @@ -33,9 +33,9 @@ It loads the configuration file and launches the http_server thread that will li ''' __author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes" __date__ ="$26-aug-2014 11:09:29$" -__version__="0.5.0-r507" +__version__="0.5.2-r510" version_date="Oct 2016" -database_version="0.15" #expected database schema version +database_version="0.16" #expected database schema version import httpserver import time @@ -45,6 +45,7 @@ import yaml import nfvo_db from jsonschema import validate as js_v, exceptions as js_e from openmano_schemas import config_schema +from db_base import db_base_Exception import nfvo import logging import logging.handlers as log_handlers @@ -236,7 +237,8 @@ if __name__=="__main__": raise LoadConfigurationException("Cannot open logging file '{}': {}. Check folder exist and permissions".format(global_config["log_file"], str(e)) ) #logging.basicConfig(level = getattr(logging, global_config.get('log_level',"debug"))) logger.setLevel(getattr(logging, global_config['log_level'])) - logger.critical("Starting openmano server command: '%s'", sys.argv[0]) + logger.critical("Starting openmano server version: '%s %s' command: '%s'", + __version__, version_date, " ".join(sys.argv)) for log_module in ("nfvo", "http", "vim", "db"): log_level_module = "log_level_" + log_module @@ -257,17 +259,19 @@ if __name__=="__main__": # Initialize DB connection mydb = nfvo_db.nfvo_db(); - if mydb.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name']) == -1: - logger.critical("Cannot connect to database %s at %s@%s", global_config['db_name'], global_config['db_user'], global_config['db_host']) + mydb.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name']) + try: + r = mydb.get_db_version() + if r[1] != database_version: + logger.critical("DATABASE wrong version '%s'. \ + Try to upgrade/downgrade to version '%s' with './database_utils/migrate_mano_db.sh'", + r[1], database_version) + exit(-1) + except db_base_Exception as e: + logger.critical("DATABASE is not a MANO one or it is a '0.0' version. Try to upgrade to version '%s' with \ + './database_utils/migrate_mano_db.sh'", database_version) exit(-1) - r = mydb.get_db_version() - if r[0]<0: - logger.critical("DATABASE is not a MANO one or it is a '0.0' version. Try to upgrade to version '%s' with './database_utils/migrate_mano_db.sh'", database_version) - exit(-1) - elif r[1]!=database_version: - logger.critical("DATABASE wrong version '%s'. Try to upgrade/downgrade to version '%s' with './database_utils/migrate_mano_db.sh'", r[1], database_version) - exit(-1) - + nfvo.global_config=global_config httpthread = httpserver.httpserver(mydb, False, global_config['http_host'], global_config['http_port']) @@ -305,4 +309,7 @@ if __name__=="__main__": except LoadConfigurationException as e: logger.critical(str(e)) exit(-1) + except db_base_Exception as e: + logger.critical(str(e)) + exit(-1) diff --git a/scripts/install-openmano-service.sh b/scripts/install-openmano-service.sh index dd840ce4..c5bccecc 100755 --- a/scripts/install-openmano-service.sh +++ b/scripts/install-openmano-service.sh @@ -36,20 +36,20 @@ function usage(){ } function uninstall(){ - service openmano stop - for file in /opt/openmano /etc/default/openmanod.cfg /var/log/openmano /etc/systemd/system/openmano.service /usr/sbin/openmano + echo "systemctl disable openmano.service " && systemctl disable openmano.service 2>/dev/null || echo " Already done" + echo "service openmano stop " && service openmano stop 2>/dev/null || echo " Already done" + for file in /opt/openmano /etc/default/openmanod.cfg /var/log/openmano /etc/systemd/system/openmano.service /usr/bin/openmano /usr/sbin/service-openmano /usr/bin/openmano-report do + echo rm $file rm -rf $file || ! echo "Can not delete '$file'. Needed root privileges?" >&2 || exit 1 done echo "Done" } -BAD_PATH_ERROR="Path '$FILE' does not contain a valid openmano distribution" GIT_URL=https://osm.etsi.org/gerrit/osm/RO.git USER_OWNER="root" QUIET_MODE="" FILE="" -DELETE="" while getopts ":u:f:hq-:" o; do case "${o}" in u) @@ -84,6 +84,7 @@ while getopts ":u:f:hq-:" o; do ;; esac done +BAD_PATH_ERROR="Path '$FILE' does not contain a valid openmano distribution" #check root privileges [ "$USER" != "root" ] && echo "Needed root privileges" >&2 && exit 1 @@ -109,27 +110,26 @@ else fi -if [[ -z $FILE ]] +if [[ -z "$FILE" ]] then - git clone $GIT_URL __temp__ || ! echo "Cannot get openmano source code from $GIT_URL" >&2 || exit 1 - #git checkout - FILE=./__temp__ - DELETE=y + FILE=__temp__${RANDOM} + git clone $GIT_URL $FILE || ! echo "Cannot get openmano source code from $GIT_URL" >&2 || exit 1 +else + [[ -d "$FILE" ]] || ! echo $BAD_PATH_ERROR >&2 || exit 1 fi #make idempotent -rm -rf /opt/openmano -rm -f /etc/default/openmanod.cfg -rm -f /var/log/openmano -cp -r $FILE /opt/openmano || ! echo $BAD_PATH_ERROR >&2 || exit 1 +uninstall +#copy files +cp -r "$FILE" /opt/openmano || ! echo $BAD_PATH_ERROR >&2 || exit 1 mkdir -p /opt/openmano/logs -rm -rf /usr/sbin/openmano -#cp ${FILE}/openmano /usr/sbin/ || ! echo $BAD_PATH_ERROR >&2 || exit 1 -ln -s /opt/openmano/openmanod.cfg /etc/default/openmanod.cfg || echo "warning cannot create link '/etc/default/openmanod.cfg'" -ln -s /opt/openmano/logs /var/log/openmano || echo "warning cannot create link '/var/log/openmano'" -ln -s /opt/openmano/openmano /usr/sbin/openmano +#makes links +ln -s -v /opt/openmano/openmanod.cfg /etc/default/openmanod.cfg || echo "warning cannot create link '/etc/default/openmanod.cfg'" +ln -s -v /opt/openmano/logs /var/log/openmano || echo "warning cannot create link '/var/log/openmano'" +ln -s -v /opt/openmano/openmano /usr/bin/openmano +ln -s -v /opt/openmano/scripts/service-openmano.sh /usr/sbin/service-openmano +ln -s -v /opt/openmano/scripts/openmano-report.sh /usr/bin/openmano-report -chown $USER_OWNER /opt/openmano/openmanod.cfg chown -R $USER_OWNER /opt/openmano mkdir -p /etc/systemd/system/ @@ -146,9 +146,10 @@ Restart=always WantedBy=multi-user.target EOF -[[ -n $DELETE ]] && rm -rf $FILE +rm -rf ${FILE} service openmano start +systemctl enable openmano.service echo Done exit diff --git a/scripts/install-openmano.sh b/scripts/install-openmano.sh index 85d3293b..f55851d4 100755 --- a/scripts/install-openmano.sh +++ b/scripts/install-openmano.sh @@ -35,7 +35,8 @@ function usage(){ echo -e " -q --quiet: install in unattended mode" echo -e " -h --help: show this help" echo -e " --develop: install last version for developers, and do not configure as a service" - echo -e " --forcedb: reinstall mano_db DB, deleting previous database and creating a new one" + echo -e " --forcedb: reinstall mano_db DB, deleting previous database if exists and creating a new one" + echo -e " --force: makes idenpotent, delete previous installations folders if needed" echo -e " --noclone: assumes that openmano was cloned previously and that this script is run from the local repo" echo -e " --no-install-packages: use this option to skip updating and installing the requires packages. This avoid wasting time if you are sure requires packages are present e.g. because of a previous installation" } @@ -75,6 +76,7 @@ DBPASSWD_PARAM="" QUIET_MODE="" DEVELOP="" FORCEDB="" +FORCE="" NOCLONE="" NO_PACKAGES="" while getopts ":u:p:hiq-:" o; do @@ -97,6 +99,7 @@ while getopts ":u:p:hiq-:" o; do [ "${OPTARG}" == "help" ] && usage && exit 0 [ "${OPTARG}" == "develop" ] && DEVELOP="y" && continue [ "${OPTARG}" == "forcedb" ] && FORCEDB="y" && continue + [ "${OPTARG}" == "force" ] && FORCEDB="y" && FORCE="y" && continue [ "${OPTARG}" == "noclone" ] && NOCLONE="y" && continue [ "${OPTARG}" == "quiet" ] && export QUIET_MODE=yes && export DEBIAN_FRONTEND=noninteractive && continue [ "${OPTARG}" == "no-install-packages" ] && export NO_PACKAGES=yes && continue @@ -165,6 +168,17 @@ else #[ "$_DISTRO" != "Ubuntu" -a "$_DISTRO" != "CentOS" -a "$_DISTRO" != "Red" [[ -z $QUIET_MODE ]] && [[ "$KK" != "y" ]] && [[ "$KK" != "yes" ]] && echo "Cancelled" && exit 1 fi +#check if installed as a service +INSTALL_AS_A_SERVICE="" +[[ "$_DISTRO" == "Ubuntu" ]] && [[ ${_RELEASE%%.*} == 16 ]] && [[ -z $DEVELOP ]] && INSTALL_AS_A_SERVICE="y" +#Next operations require knowing OPENMANO_BASEFOLDER +if [[ -z "$NOCLONE" ]]; then + OPENMANO_BASEFOLDER="${PWD}/openmano" + [[ -n "$FORCE" ]] && rm -rf $OPENMANO_BASEFOLDER #make idenpotent +else + HERE=$(realpath $(dirname $0)) + OPENMANO_BASEFOLDER=$(dirname $HERE) +fi if [[ -z "$NO_PACKAGES" ]] @@ -263,9 +277,9 @@ if [[ -z $NOCLONE ]]; then ################################################################# ##### DOWNLOAD SOURCE ##### #################################################################' - su $SUDO_USER -c 'git clone '"${GIT_URL}"' openmano' - su $SUDO_USER -c 'cp openmano/.gitignore-common openmano/.gitignore' - [[ -z $DEVELOP ]] && su $SUDO_USER -c 'git checkout tags/v1.0' + su $SUDO_USER -c "git clone ${GIT_URL} ${OPENMANO_BASEFOLDER}" + su $SUDO_USER -c "cp ${OPENMANO_BASEFOLDER}/.gitignore-common ${OPENMANO_BASEFOLDER}/.gitignore" + [[ -z $DEVELOP ]] && su $SUDO_USER -c "git -C ${OPENMANO_BASEFOLDER} checkout tags/v1.0.1" fi echo ' @@ -276,11 +290,7 @@ echo -e "\nCreating temporary file form MYSQL installation and initialization" TEMPFILE="$(mktemp -q --tmpdir "installopenmano.XXXXXX")" trap 'rm -f "$TEMPFILE"' EXIT chmod 0600 "$TEMPFILE" -cat >"$TEMPFILE" <"$TEMPFILE" if db_exists "mano_db" $TEMPFILE ; then if [[ -n $FORCEDB ]]; then @@ -306,20 +316,11 @@ else fi -#Next operations require knowing OPENMANO_BASEFOLDER -HERE=$(realpath $(dirname $0)) -if [[ -z $NOCLONE ]]; then - OPENMANO_BASEFOLDER="${HERE}/openmano" -else - OPENMANO_BASEFOLDER=$(dirname $HERE) -fi - - echo ' ################################################################# ##### INIT DATABASE ##### #################################################################' -su $SUDO_USER -c "${OPENMANO_BASEFOLDER}"'/database_utils/init_mano_db.sh -u mano -p manopw -d mano_db' || ! echo "Failed while initializing database" || exit 1 +su $SUDO_USER -c "${OPENMANO_BASEFOLDER}/database_utils/init_mano_db.sh -u mano -p manopw -d mano_db" || ! echo "Failed while initializing database" || exit 1 if [ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ] @@ -357,29 +358,32 @@ echo ' ################################################################# ##### CONFIGURE OPENMANO CLIENT ##### #################################################################' -#creates a link at ~/bin -su $SUDO_USER -c 'mkdir -p ${HOME}/bin' -su $SUDO_USER -c 'rm -f ${HOME}/bin/openmano' -su $SUDO_USER -c 'rm -f ${HOME}/bin/openmano-report' -su $SUDO_USER -c 'rm -f ${HOME}/bin/service-openmano' -su $SUDO_USER -c 'ln -s '${OPENMANO_BASEFOLDER}'/openmano ${HOME}/bin/openmano' -su $SUDO_USER -c 'ln -s '${OPENMANO_BASEFOLDER}'/scripts/openmano-report.sh ${HOME}/bin/openmano-report' -su $SUDO_USER -c 'ln -s '${OPENMANO_BASEFOLDER}'/scripts/service-openmano.sh ${HOME}/bin/service-openmano' - -#insert /home//bin in the PATH -#skiped because normally this is done authomatically when ~/bin exist -#if ! su $SUDO_USER -c 'echo $PATH' | grep -q "${HOME}/bin" -#then -# echo " inserting /home/$SUDO_USER/bin in the PATH at .bashrc" -# su $SUDO_USER -c 'echo "PATH=\$PATH:\${HOME}/bin" >> ~/.bashrc' -#fi -if [[ $SUDO_USER == root ]] +#creates a link at ~/bin if not configured as a service +if [[ -z "$INSTALL_AS_A_SERVICE" ]] then - if ! echo $PATH | grep -q "${HOME}/bin" + su $SUDO_USER -c 'mkdir -p ${HOME}/bin' + su $SUDO_USER -c 'rm -f ${HOME}/bin/openmano' + su $SUDO_USER -c 'rm -f ${HOME}/bin/openmano-report' + su $SUDO_USER -c 'rm -f ${HOME}/bin/service-openmano' + su $SUDO_USER -c 'ln -s '${OPENMANO_BASEFOLDER}'/openmano ${HOME}/bin/openmano' + su $SUDO_USER -c 'ln -s '${OPENMANO_BASEFOLDER}'/scripts/openmano-report.sh ${HOME}/bin/openmano-report' + su $SUDO_USER -c 'ln -s '${OPENMANO_BASEFOLDER}'/scripts/service-openmano.sh ${HOME}/bin/service-openmano' + + #insert /home//bin in the PATH + #skiped because normally this is done authomatically when ~/bin exist + #if ! su $SUDO_USER -c 'echo $PATH' | grep -q "${HOME}/bin" + #then + # echo " inserting /home/$SUDO_USER/bin in the PATH at .bashrc" + # su $SUDO_USER -c 'echo "PATH=\$PATH:\${HOME}/bin" >> ~/.bashrc' + #fi + if [[ $SUDO_USER == root ]] then - echo "PATH=\$PATH:\${HOME}/bin" >> ${HOME}/.bashrc - fi -fi + if ! echo $PATH | grep -q "${HOME}/bin" + then + echo "PATH=\$PATH:\${HOME}/bin" >> ${HOME}/.bashrc + fi + fi +fi #configure arg-autocomplete for this user #in case of minimal instalation this package is not installed by default @@ -395,7 +399,7 @@ fi -if [[ "$_DISTRO" == "Ubuntu" ]] && [[ ${_RELEASE%%.*} == 16 ]] && [[ -z $DEVELOP ]] +if [[ -n "$INSTALL_AS_A_SERVICE" ]] then echo ' ################################################################# @@ -403,19 +407,20 @@ echo ' #################################################################' ${OPENMANO_BASEFOLDER}/scripts/install-openmano-service.sh -f ${OPENMANO_BASEFOLDER} #-u $SUDO_USER +# rm -rf ${OPENMANO_BASEFOLDER} # alias service-openmano="service openmano" # echo 'alias service-openmano="service openmano"' >> ${HOME}/.bashrc echo - echo "Done! you may need to logout and login again for loading client configuration" - echo " Manage server with 'service openmano start|stop|status|...' " + echo "Done! installed at /opt/openmano" + echo " Manage server with 'sudo service openmano start|stop|status|...' " else echo echo "Done! you may need to logout and login again for loading client configuration" - echo " Run './openmano/scripts/service-openmano.sh start' for starting openmano in a screen" + echo " Run './${OPENMANO_BASEFOLDER}/scripts/service-openmano.sh start' for starting openmano in a screen" fi diff --git a/test/basictest.sh b/test/basictest.sh index 5b7dca54..ba6cd97a 100755 --- a/test/basictest.sh +++ b/test/basictest.sh @@ -72,7 +72,7 @@ action_list="" for argument in $params do - if [[ $argument == reset ]] || [[ $argument == create ]] || [[ $argument == delete ]] + if [[ $argument == reset ]] || [[ $argument == create ]] || [[ $argument == delete ]] || [[ -z "$argument" ]] then action_list="$action_list $argument" continue @@ -167,8 +167,8 @@ then [[ -z $OPENVIM_HOST ]] && OPENVIM_HOST=localhost [[ -z $OPENVIM_PORT ]] && OPENVIM_PORT=9080 URL_ADMIN_PARAM="" - [[ -n $OPENVIM_ADMIN_PORT ]] && URL_ADMIN_PARAM="--url_admin=http://${OPENVIM_HOST}:${OPENVIM_ADMIN_PORT}/openvim" - result=`${DIRmano}/openmano datacenter-create TEST-dc "http://${OPENVIM_HOST}:${OPENVIM_PORT}/openvim" --type=openvim $URL_ADMIN_PARAM` + [[ -n $OPENVIM_ADMIN_PORT ]] && URL_ADMIN_PARAM=" --url_admin=http://${OPENVIM_HOST}:${OPENVIM_ADMIN_PORT}/openvim" + result=`${DIRmano}/openmano datacenter-create TEST-dc "http://${OPENVIM_HOST}:${OPENVIM_PORT}/openvim" --type=openvim${URL_ADMIN_PARAM} --config="{test: no use just for test}"` datacenter=`echo $result |gawk '{print $1}'` #check a valid uuid is obtained ! is_valid_uuid $datacenter && echo "FAIL" && echo " $result" && $_exit 1 @@ -177,7 +177,7 @@ then [[ -n "$option_insert_bashrc" ]] && echo -e "\nexport OPENMANO_DATACENTER=$datacenter" >> ~/.bashrc printf "%-50s" "Attaching openmano tenant to the datacenter:" - result=`${DIRmano}/openmano datacenter-attach TEST-dc` + result=`${DIRmano}/openmano datacenter-attach TEST-dc --config="{test: no use just for test}"` [[ $? != 0 ]] && echo "FAIL" && echo " $result" && $_exit 1 echo OK diff --git a/vimconn.py b/vimconn.py index cd529de8..b5f8b070 100644 --- a/vimconn.py +++ b/vimconn.py @@ -83,6 +83,17 @@ class vimconnector(): and all these methods ''' def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None, config={}): + """Constructor of VIM + "uuid": id asigned to this VIM + "name": name assigned to this VIM, can be used for logging + "tenant_id", tenant_name: VIM tenant to be used + "url_admin": optional, url used for administrative tasks + "user", "passwd": credentials of the VIM user + "log_level": if must use a different log_level than the general one + "config": dictionary with extra VIM information. This contains a consolidate version of general VIM config at create + and particular VIM config at attach + Returns can raise an exception if some check is done and fails + """ self.id = uuid self.name = name self.url = url @@ -141,33 +152,45 @@ class vimconnector(): raise KeyError("Invalid key '%s'" %str(index)) def new_tenant(self,tenant_name,tenant_description): - '''Adds a new tenant to VIM with this name and description, - returns the tenant identifier''' + """Adds a new tenant to VIM with this name and description, this is done using admin_url if provided + "tenant_name": string max lenght 64 + "tenant_description": string max length 256 + returns the tenant identifier or raise exception + """ raise vimconnNotImplemented( "Should have implemented this" ) def delete_tenant(self,tenant_id,): - '''Delete a tenant from VIM''' - '''Returns the tenant identifier''' + """Delete a tenant from VIM + tenant_id: returned VIM tenant_id on "new_tenant" + Returns None on success. Raises and exception of failure. If tenant is not found raises vimconnNotFoundException + """ raise vimconnNotImplemented( "Should have implemented this" ) def get_tenant_list(self, filter_dict={}): '''Obtain tenants of VIM - filter_dict can contain the following keys: + filter_dict dictionary that can contain the following keys: name: filter by tenant name id: filter by tenant uuid/id - Returns the tenant list of dictionaries: + Returns the tenant list of dictionaries, and empty list if no tenant match all the filers: [{'name':', 'id':', ...}, ...] ''' raise vimconnNotImplemented( "Should have implemented this" ) def new_network(self,net_name, net_type, ip_profile=None, shared=False): - '''Adds a tenant network to VIM + """Adds a tenant network to VIM net_name is the name net_type can be 'bridge','data'.'ptp'. TODO: this need to be revised - ip_profile is a dict containing the IP parameters of the network + ip_profile is a dict containing the IP parameters of the network + "ip-version": {"type":"string", "enum":["IPv4","IPv6"]}, + "subnet-address": ip_prefix_schema, + "gateway-address": ip_schema, + "dns-address": ip_schema, + "dhcp": dhcp_schema + shared is a boolean - Returns the network identifier''' + Returns the network identifier on success or raises and exeption on failure + """ raise vimconnNotImplemented( "Should have implemented this" ) def get_network_list(self, filter_dict={}):