Restructuring code in osm_ro folder, and setup based on MANIFEST 11/1511/1
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Thu, 6 Apr 2017 01:12:51 +0000 (03:12 +0200)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Thu, 6 Apr 2017 01:13:10 +0000 (03:13 +0200)
Also updated Makefile and service-openmano.sh

Change-Id: I60cf49013315efafd73de377452e38faf2f2f1e0
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
38 files changed:
MANIFEST.in [new file with mode: 0644]
Makefile
console_proxy_thread.py [deleted file]
db_base.py [deleted file]
httpserver.py [deleted file]
nfvo.py [deleted file]
nfvo_db.py [deleted file]
openmano.service [deleted file]
openmano_schemas.py [deleted file]
openmanoclient.py [deleted file]
openmanod.py
osm-ro.service [new file with mode: 0644]
osm_ro/console_proxy_thread.py [new file with mode: 0644]
osm_ro/db_base.py [new file with mode: 0644]
osm_ro/httpserver.py [new file with mode: 0644]
osm_ro/nfvo.py [new file with mode: 0644]
osm_ro/nfvo_db.py [new file with mode: 0644]
osm_ro/openmano_schemas.py [new file with mode: 0644]
osm_ro/openmanoclient.py [new file with mode: 0644]
osm_ro/utils.py [new file with mode: 0644]
osm_ro/vim_thread.py [new file with mode: 0644]
osm_ro/vimconn.py [new file with mode: 0644]
osm_ro/vimconn_openstack.py [new file with mode: 0644]
osm_ro/vimconn_openvim.py [new file with mode: 0644]
osm_ro/vimconn_vmware.py [new file with mode: 0644]
osm_ro/vmwarecli.py [new file with mode: 0755]
osm_ro/vmwarerecli.py [new file with mode: 0755]
requirements.txt
scripts/service-openmano.sh
setup.py
utils.py [deleted file]
vim_thread.py [deleted file]
vimconn.py [deleted file]
vimconn_openstack.py [deleted file]
vimconn_openvim.py [deleted file]
vimconn_vmware.py [deleted file]
vmwarecli.py [deleted file]
vmwarerecli.py [deleted file]

diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644 (file)
index 0000000..154ea27
--- /dev/null
@@ -0,0 +1,9 @@
+#include MANIFEST.in
+#include requirements.txt
+include README.rst
+include openmano
+include openmanod.py
+include openmanod.cfg
+include osm-ro.service
+recursive-include osm_ro *
+
index b5e6960..76a2990 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,42 +2,47 @@ SHELL := /bin/bash
 all: pypackage debpackage
 
 prepare:
-       mkdir -p build
-       cp *.py build/
-       #cd build; mv openmanod.py openmanod
-       cp openmano build/
-       cp openmanod.cfg build/
+       mkdir -p build/
+       cp MANIFEST.in build/
        cp requirements.txt build/
        cp README.rst build/
-       cp openmano.service build/
-       cp -r vnfs build/
-       cp -r scenarios build/
-       cp -r instance-scenarios build/
-       cp -r scripts build/
-       cd build/scripts; mv service-openmano.sh service-openmano; mv openmano-report.sh openmano-report
-       cp -r database_utils build/
+       cp setup.py build/
+       cp -r osm_ro build/
+       cp openmano build/
+       cp openmanod.py build/
+       cp openmanod.cfg build/
+       cp osm-ro.service build/
+       cp -r vnfs build/osm_ro
+       cp -r scenarios build/osm_ro
+       cp -r instance-scenarios build/osm_ro
+       cp -r scripts build/osm_ro
+       cp -r database_utils build/osm_ro
 
 connectors: prepare
        # python-novaclient is required for that
-       rm -f build/openmanolinkervimconn.py
-       cd build; for i in `ls vimconn_*.py |sed "s/\.py//"` ; do echo "import $$i" >> openmanolinkervimconn.py; done
-       python build/openmanolinkervimconn.py
-       rm -f build/openmanolinkervimconn.py
+       rm -f build/osm_ro/openmanolinkervimconn.py
+       cd build/osm_ro; for i in `ls vimconn_*.py |sed "s/\.py//"` ; do echo "import $$i" >> openmanolinkervimconn.py; done
+       python build/osm_ro/openmanolinkervimconn.py
+       rm -f build/osm_ro/openmanolinkervimconn.py
 
-build: prepare
-       python -m py_compile build/*.py
+build: connectors prepare
+       python -m py_compile build/osm_ro/*.py
 
-pypackage: build
+pypackage: prepare
        cd build; ./setup.py sdist
-       #cp build/dist/* /root/artifacts/...
+       cd build; ./setup.py bdist_wheel
 
-debpackage: build
-       echo "Nothing to be done yet"
+debpackage: prepare
+       echo "Nothing to be done"
+       #cd build; ./setup.py --command-packages=stdeb.command bdist_deb
        #fpm -s python -t deb build/setup.py
 
 snappackage:
        echo "Nothing to be done yet"
 
+sync:
+       #cp build/dist/* /root/artifacts/...
+
 test:
        ./test/basictest.sh --force --insert-bashrc --install-openvim --init-openvim
 
diff --git a/console_proxy_thread.py b/console_proxy_thread.py
deleted file mode 100644 (file)
index 460a4aa..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-# -*- 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
-##
-
-'''
-Implement like a proxy for TCP/IP in a separated thread.
-It creates two sockets to bypass the TCP/IP packets among the fix console 
-server specified at class construction (console_host, console_port)
-and a client that connect against the (host, port) specified also at construction
-
-                ---------------------           -------------------------------
-                |       OPENMANO     |          |         VIM                  |
-client 1  ----> | ConsoleProxyThread | ------>  |  Console server              |
-client 2  ----> |  (host, port)      | ------>  |(console_host, console_server)|
-   ...           --------------------            ------------------------------
-'''
-__author__="Alfonso Tierno"
-__date__ ="$19-nov-2015 09:07:15$"
-
-import socket
-import select
-import threading
-import logging
-
-
-class ConsoleProxyException(Exception):
-    '''raise when an exception has found''' 
-class ConsoleProxyExceptionPortUsed(ConsoleProxyException):
-    '''raise when the port is used''' 
-
-class ConsoleProxyThread(threading.Thread):
-    buffer_size = 4096
-    check_finish = 1 #frequency to check if requested to end in seconds
-
-    def __init__(self, host, port, console_host, console_port, log_level=None):
-        try:
-            threading.Thread.__init__(self)
-            self.console_host = console_host
-            self.console_port = console_port
-            self.host = host
-            self.port = port
-            self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-            self.server.bind((host, port))
-            self.server.listen(200)
-            #TODO timeout in a lock section can be used to autoterminate the thread
-            #when inactivity and timeout<time : set timeout=0 and terminate
-            #from outside, close class when timeout==0; set timeout=time+120 when adding a new console on this thread
-            #set self.timeout = time.time() + 120 at init
-            self.name = "ConsoleProxy " + console_host + ":" + str(console_port)
-            self.input_list = [self.server]
-            self.channel = {}
-            self.terminate = False #put at True from outside to force termination
-            self.logger = logging.getLogger('openmano.console')
-            if log_level:
-                self.logger.setLevel( getattr(logging, log_level) )
-
-        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
-            if e is socket.error and e.errno==98:
-                raise ConsoleProxyExceptionPortUsed("socket.error " + str(e))
-            raise ConsoleProxyException(type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0])) )
-        
-    def run(self):
-        while 1:
-            try:
-                inputready, _, _ = select.select(self.input_list, [], [], self.check_finish)
-            except select.error as e:
-                self.logger.error("Exception on select %s: %s", type(e).__name__, str(e) )
-                self.on_terminate()
-
-            if self.terminate:
-                self.on_terminate()
-                self.logger.debug("Terminate because commanded")
-                break
-            
-            for sock in inputready:
-                if sock == self.server:
-                    self.on_accept()
-                else:
-                    self.on_recv(sock)
-                    
-    def on_terminate(self):
-        while self.input_list:
-            if self.input_list[0] is self.server:
-                self.server.close()
-                del self.input_list[0]
-            else:
-                self.on_close(self.input_list[0], "Terminating thread")
-
-    def on_accept(self):
-        #accept
-        try:
-            clientsock, clientaddr = self.server.accept()
-        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
-            self.logger.error("Exception on_accept %s: %s", type(e).__name__, str(e) )
-            return False
-        #print self.name, ": Accept new client ", clientaddr
-
-        #connect
-        try:
-            forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            forward.connect((self.console_host, self.console_port))
-            name = "%s:%d => (%s:%d => %s:%d) => %s:%d" %\
-                (clientsock.getpeername() + clientsock.getsockname()  + forward.getsockname() + forward.getpeername() )
-            self.logger.warn("new connection " + name)
-                
-            self.input_list.append(clientsock)
-            self.input_list.append(forward)
-            info = { "name": name,
-                    "clientsock" : clientsock,
-                    "serversock" : forward
-                    }
-            self.channel[clientsock] = info
-            self.channel[forward] = info
-            return True
-        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
-            self.logger.error("Exception on_connect to server %s:%d; %s: %s  Close client side %s",
-                self.console_host, self.console_port, type(e).__name__, str(e), str(clientaddr) )
-            clientsock.close()
-            return False
-
-    def on_close(self, sock, cause):
-        if sock not in self.channel:
-            return  #can happen if there is data ready to received at both sides and the channel has been deleted. QUITE IMPROBABLE but just in case
-        info = self.channel[sock]
-        #debug info
-        sockname = "client" if sock is info["clientsock"] else "server"
-        self.logger.warn("del connection %s %s at %s side", info["name"], str(cause), str(sockname) )
-        #close sockets
-        try:
-            # close the connection with client
-            info["clientsock"].close()  # equivalent to do self.s.close()
-        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
-            self.logger.error("Exception on_close client socket %s: %s", type(e).__name__, str(e) )
-        try:
-            # close the connection with remote server
-            info["serversock"].close()
-        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
-            self.logger.error("Exception on_close server socket %s: %s", type(e).__name__, str(e) )
-        
-        #remove objects from input_list
-        self.input_list.remove(info["clientsock"])
-        self.input_list.remove(info["serversock"])
-        # delete both objects from channel dict
-        del self.channel[info["clientsock"]]
-        del self.channel[info["serversock"]]
-
-    def on_recv(self, sock):
-        if sock not in self.channel:
-            return  #can happen if there is data ready to received at both sides and the channel has been deleted. QUITE IMPROBABLE but just in case
-        info = self.channel[sock]
-        peersock = info["serversock"] if sock is info["clientsock"] else info["clientsock"]
-        try:
-            data = sock.recv(self.buffer_size)
-            if len(data) == 0:
-                self.on_close(sock, "peer closed")
-            else:
-                #print self.data
-                sock = peersock
-                peersock.send(data)
-        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
-            #print self.name, ": Exception %s: %s" % (type(e).__name__, str(e) )
-            self.on_close(sock, "Exception %s: %s" % (type(e).__name__, str(e) ))
-
-        
-
-    #def start_timeout(self):
-    #    self.timeout = time.time() + 120
-        
diff --git a/db_base.py b/db_base.py
deleted file mode 100644 (file)
index 10f9404..0000000
+++ /dev/null
@@ -1,656 +0,0 @@
-# -*- 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
-##
-
-'''
-Base class for openmano database manipulation
-'''
-__author__="Alfonso Tierno"
-__date__ ="$4-Apr-2016 10:05:01$"
-
-import MySQLdb as mdb
-import uuid as myUuid
-import  utils as af
-import json
-#import yaml
-import time
-import logging
-import datetime
-from jsonschema import validate as js_v, exceptions as js_e
-
-HTTP_Bad_Request = 400
-HTTP_Unauthorized = 401 
-HTTP_Not_Found = 404 
-HTTP_Method_Not_Allowed = 405 
-HTTP_Request_Timeout = 408
-HTTP_Conflict = 409
-HTTP_Service_Unavailable = 503 
-HTTP_Internal_Server_Error = 500 
-
-def _check_valid_uuid(uuid):
-    id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
-    id_schema2 = {"type" : "string", "pattern": "^[a-fA-F0-9]{32}$"}
-    try:
-        js_v(uuid, id_schema)
-        return True
-    except js_e.ValidationError:
-        try:
-            js_v(uuid, id_schema2)
-            return True
-        except js_e.ValidationError:
-            return False
-    return False
-
-def _convert_datetime2str(var):
-    '''Converts a datetime variable to a string with the format '%Y-%m-%dT%H:%i:%s'
-    It enters recursively in the dict var finding this kind of variables
-    '''
-    if type(var) is dict:
-        for k,v in var.items():
-            if type(v) is datetime.datetime:
-                var[k]= v.strftime('%Y-%m-%dT%H:%M:%S')
-            elif type(v) is dict or type(v) is list or type(v) is tuple: 
-                _convert_datetime2str(v)
-        if len(var) == 0: return True
-    elif type(var) is list or type(var) is tuple:
-        for v in var:
-            _convert_datetime2str(v)
-
-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:
-        'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
-        'reverse': by default convert form str to int (Mbps), if True it convert from number to units
-    Return:
-        None
-    '''
-    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, logger)
-        if "bandwidth" in data:
-            try:
-                value=str(data["bandwidth"])
-                if not reverse:
-                    pos = value.find("bps")
-                    if pos>0:
-                        if value[pos-1]=="G": data["bandwidth"] =  int(data["bandwidth"][:pos-1]) * 1000
-                        elif value[pos-1]=="k": data["bandwidth"]= int(data["bandwidth"][:pos-1]) / 1000
-                        else: data["bandwidth"]= int(data["bandwidth"][:pos-1])
-                else:
-                    value = int(data["bandwidth"])
-                    if value % 1000 == 0: data["bandwidth"]=str(value/1000) + " Gbps"
-                    else: data["bandwidth"]=str(value) + " Mbps"
-            except:
-                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, 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 
-    Done recursively
-    Attributes:
-        'data': dictionary variable to be checked. None or empty is considered valid
-        'items': tuple of keys to convert
-    Return:
-        None
-    '''
-    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_str2boolean(data[k], items)
-            if k in items:
-                if type(data[k]) is str:
-                    if   data[k]=="false" or data[k]=="False" or data[k]=="0": data[k]=False
-                    elif data[k]=="true"  or data[k]=="True" or data[k]=="1":  data[k]=True
-                elif type(data[k]) is int:
-                    if   data[k]==0: data[k]=False
-                    elif  data[k]==1:  data[k]=True
-    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_str2boolean(k, items)
-
-class db_base_Exception(Exception):
-    '''Common Exception for all database exceptions'''
-    
-    def __init__(self, message, http_code=HTTP_Bad_Request):
-        Exception.__init__(self, message)
-        self.http_code = http_code
-
-class db_base():
-    tables_with_created_field=()
-    
-    def __init__(self, host=None, user=None, passwd=None, database=None, log_name='db', log_level=None):
-        self.host = host
-        self.user = user
-        self.passwd = passwd
-        self.database = database
-        self.con = None
-        self.log_level=log_level
-        self.logger = logging.getLogger(log_name)
-        if self.log_level:
-            self.logger.setLevel( getattr(logging, log_level) )
-        
-    def connect(self, host=None, user=None, passwd=None, database=None):
-        '''Connect to specific data base. 
-        The first time a valid host, user, passwd and database must be provided,
-        Following calls can skip this parameters
-        '''
-        try:
-            if host:        self.host = host
-            if user:        self.user = user
-            if passwd:      self.passwd = passwd
-            if database:    self.database = database
-
-            self.con = mdb.connect(self.host, self.user, self.passwd, self.database)
-            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.
-        Return: (negative, text) if error or version 0.0 where schema_version table is missing
-                (version_int, version_text) if ok
-        '''
-        cmd = "SELECT version_int,version FROM schema_version"
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor()
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    rows = self.cur.fetchall()
-                    highest_version_int=0
-                    highest_version=""
-                    for row in rows: #look for the latest version
-                        if row[0]>highest_version_int:
-                            highest_version_int, highest_version = row[0:2]
-                    return highest_version_int, highest_version
-            except (mdb.Error, AttributeError) as e:
-                #self.logger.error("get_db_version DB Exception %d: %s. Command %s",e.args[0], e.args[1], cmd)
-                self._format_error(e, tries)
-            tries -= 1
-
-    def disconnect(self):
-        '''disconnect from specific data base'''
-        try:
-            self.con.close()
-            self.con = None
-        except mdb.Error as e:
-            self.logger.error("while disconnecting from DB: Error %d: %s",e.args[0], e.args[1])
-            return
-        except AttributeError as e: #self.con not defined
-            if e[0][-5:] == "'con'":
-                self.logger.warn("while disconnecting from DB: Error %d: %s",e.args[0], e.args[1])
-                return
-            else: 
-                raise
-
-    def _format_error(self, e, tries=1, command=None, extra=None): 
-        '''Creates a text error base on the produced exception
-            Params:
-                e: mdb exception
-                retry: in case of timeout, if reconnecting to database and retry, or raise and exception
-                cmd: database command that produce the exception
-                command: if the intention is update or delete
-                extra: extra information to add to some commands
-            Return
-                HTTP error in negative, formatted error text
-        '''
-        if isinstance(e,AttributeError ):
-            raise db_base_Exception("DB Exception " + str(e), HTTP_Internal_Server_Error)
-        if e.args[0]==2006 or e.args[0]==2013 : #MySQL server has gone away (((or)))    Exception 2013: Lost connection to MySQL server during query
-            if tries>1:
-                self.logger.warn("DB Exception '%s'. Retry", str(e))
-                #reconnect
-                self.connect()
-                return
-            else:
-                raise db_base_Exception("Database connection timeout Try Again", HTTP_Request_Timeout)
-        
-        fk=e.args[1].find("foreign key constraint fails")
-        if fk>=0:
-            if command=="update":
-                raise db_base_Exception("tenant_id '{}' not found.".format(extra), HTTP_Not_Found)
-            elif command=="delete":
-                raise db_base_Exception("Resource is not free. There are {} that prevent deleting it.".format(extra), HTTP_Conflict)
-        de = e.args[1].find("Duplicate entry")
-        fk = e.args[1].find("for key")
-        uk = e.args[1].find("Unknown column")
-        wc = e.args[1].find("in 'where clause'")
-        fl = e.args[1].find("in 'field list'")
-        #print de, fk, uk, wc,fl
-        if de>=0:
-            if fk>=0: #error 1062
-                raise db_base_Exception("Value {} already in use for {}".format(e.args[1][de+15:fk], e.args[1][fk+7:]), HTTP_Conflict)
-        if uk>=0:
-            if wc>=0:
-                raise db_base_Exception("Field {} can not be used for filtering".format(e.args[1][uk+14:wc]), HTTP_Bad_Request)
-            if fl>=0:
-                raise db_base_Exception("Field {} does not exist".format(e.args[1][uk+14:wc]), HTTP_Bad_Request)
-        raise db_base_Exception("Database internal Error {}: {}".format(e.args[0], e.args[1]), HTTP_Internal_Server_Error)
-    
-    def __str2db_format(self, data):
-        '''Convert string data to database format. 
-        If data is None it returns the 'Null' text,
-        otherwise it returns the text surrounded by quotes ensuring internal quotes are escaped.
-        '''
-        if data==None:
-            return 'Null'
-        else:
-            return json.dumps(str(data))
-    
-    def __tuple2db_format_set(self, data):
-        '''Compose the needed text for a SQL SET, parameter 'data' is a pair tuple (A,B),
-        and it returns the text 'A="B"', where A is a field of a table and B is the value 
-        If B is None it returns the 'A=Null' text, without surrounding Null by quotes
-        If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
-        and it ensures internal quotes of B are escaped.
-        '''
-        if data[1]==None:
-            return str(data[0]) + "=Null"
-        else:
-            return str(data[0]) + '=' + json.dumps(str(data[1]))
-    
-    def __tuple2db_format_where(self, data):
-        '''Compose the needed text for a SQL WHERE, parameter 'data' is a pair tuple (A,B),
-        and it returns the text 'A="B"', where A is a field of a table and B is the value 
-        If B is None it returns the 'A is Null' text, without surrounding Null by quotes
-        If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
-        and it ensures internal quotes of B are escaped.
-        '''
-        if data[1]==None:
-            return str(data[0]) + " is Null"
-        
-#         if type(data[1]) is tuple:  #this can only happen in a WHERE_OR clause
-#             text =[]
-#             for d in data[1]:
-#                 if d==None:
-#                     text.append(str(data[0]) + " is Null")
-#                     continue
-#                 out=str(d)
-#                 if "'" not in out:
-#                     text.append( str(data[0]) + "='" + out + "'" )
-#                 elif '"' not in out:
-#                     text.append( str(data[0]) + '="' + out + '"' )
-#                 else:
-#                     text.append( str(data[0]) + '=' + json.dumps(out) )
-#             return " OR ".join(text)
-
-        out=str(data[1])
-        return str(data[0]) + '=' + json.dumps(out)
-
-    def __tuple2db_format_where_not(self, data):
-        '''Compose the needed text for a SQL WHERE(not). parameter 'data' is a pair tuple (A,B),
-        and it returns the text 'A<>"B"', where A is a field of a table and B is the value 
-        If B is None it returns the 'A is not Null' text, without surrounding Null by quotes
-        If B is not None it returns the text "A<>'B'" or 'A<>"B"' where B is surrounded by quotes,
-        and it ensures internal quotes of B are escaped.
-        '''
-        if data[1]==None:
-            return str(data[0]) + " is not Null"
-        out=str(data[1])
-        return str(data[0]) + '<>' + json.dumps(out)
-    
-    def __remove_quotes(self, data):
-        '''remove single quotes ' of any string content of data dictionary'''
-        for k,v in data.items():
-            if type(v) == str:
-                if "'" in v: 
-                    data[k] = data[k].replace("'","_")
-    
-    def _update_rows(self, table, UPDATE, WHERE, modified_time=0):
-        ''' Update one or several rows into a table.
-        Atributes
-            UPDATE: dictionary with the key: value to change
-            table: table where to update
-            WHERE: dictionary of elements to update
-        Return: the number of updated rows, exception if error
-        '''
-                #gettting uuid 
-        values = ",".join(map(self.__tuple2db_format_set, UPDATE.iteritems() ))
-        if modified_time:
-            values += ",modified_at={:f}".format(modified_time)
-        cmd= "UPDATE " + table +" SET " + values +\
-            " WHERE " + " and ".join(map(self.__tuple2db_format_where, WHERE.iteritems() ))
-        self.logger.debug(cmd)
-        self.cur.execute(cmd) 
-        return self.cur.rowcount
-    
-    def _new_row_internal(self, table, INSERT, add_uuid=False, root_uuid=None, created_time=0):
-        ''' Add one row into a table. It DOES NOT begin or end the transaction, so self.con.cursor must be created
-        Attribute 
-            INSERT: dictionary with the key:value to insert
-            table: table where to insert
-            add_uuid: if True, it will create an uuid key entry at INSERT if not provided
-            created_time: time to add to the created_time column
-        It checks presence of uuid and add one automatically otherwise
-        Return: uuid
-        '''
-
-        if add_uuid:
-            #create uuid if not provided
-            if 'uuid' not in INSERT:
-                uuid = INSERT['uuid'] = str(myUuid.uuid1()) # create_uuid
-            else: 
-                uuid = str(INSERT['uuid'])
-        else:
-            uuid=None
-        if add_uuid:
-            #defining root_uuid if not provided
-            if root_uuid is None:
-                root_uuid = uuid
-            if created_time:
-                created_at = created_time
-            else:
-                created_at=time.time()
-            #inserting new uuid
-            cmd = "INSERT INTO uuids (uuid, root_uuid, used_at, created_at) VALUES ('{:s}','{:s}','{:s}', {:f})".format(uuid, root_uuid, table, created_at)
-            self.logger.debug(cmd)
-            self.cur.execute(cmd)
-        #insertion
-        cmd= "INSERT INTO " + table +" SET " + \
-            ",".join(map(self.__tuple2db_format_set, INSERT.iteritems() )) 
-        if created_time:
-            cmd += ",created_at=%f" % created_time
-        self.logger.debug(cmd)
-        self.cur.execute(cmd)
-        self.cur.rowcount
-        return uuid
-
-    def _get_rows(self,table,uuid):
-        cmd = "SELECT * FROM {} WHERE uuid='{}'".format(str(table), str(uuid))
-        self.logger.debug(cmd)
-        self.cur.execute(cmd)
-        rows = self.cur.fetchall()
-        return rows
-    
-    def new_row(self, table, INSERT, add_uuid=False, created_time=0):
-        ''' Add one row into a table.
-        Attribute 
-            INSERT: dictionary with the key: value to insert
-            table: table where to insert
-            tenant_id: only useful for logs. If provided, logs will use this tenant_id
-            add_uuid: if True, it will create an uuid key entry at INSERT if not provided
-        It checks presence of uuid and add one automatically otherwise
-        Return: (result, uuid) where result can be 0 if error, or 1 if ok
-        '''
-        if table in self.tables_with_created_field and created_time==0:
-            created_time=time.time()
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor()
-                    return self._new_row_internal(table, INSERT, add_uuid, None, created_time)
-                    
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-    def update_rows(self, table, UPDATE, WHERE, modified_time=0):
-        ''' Update one or several rows into a table.
-        Atributes
-            UPDATE: dictionary with the key: value to change
-            table: table where to update
-            WHERE: dictionary of elements to update
-        Return: (result, descriptive text) where result indicates the number of updated files
-        '''
-        if table in self.tables_with_created_field and modified_time==0:
-            modified_time=time.time()
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor()
-                    return self._update_rows(table, UPDATE, WHERE)
-                    
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-    def delete_row_by_id(self, table, uuid):
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    #delete host
-                    self.cur = self.con.cursor()
-                    cmd = "DELETE FROM {} WHERE uuid = '{}'".format(table, uuid)
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    deleted = self.cur.rowcount
-                    if deleted:
-                        #delete uuid
-                        self.cur = self.con.cursor()
-                        cmd = "DELETE FROM uuids WHERE root_uuid = '{}'".format(uuid)
-                        self.logger.debug(cmd)
-                        self.cur.execute(cmd)
-                return deleted
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries, "delete", "dependencies")
-            tries -= 1
-
-    def delete_row(self, **sql_dict):
-        ''' Deletes rows from a table.
-        Attribute sql_dir: dictionary with the following key: value
-            'FROM': string of table name (Mandatory)
-            'WHERE': dict of key:values, translated to key=value AND ... (Optional)
-            'WHERE_NOT': dict of key:values, translated to key<>value AND ... (Optional) 
-                if value is None, it is translated to key is not null
-            'LIMIT': limit of number of rows (Optional)
-        Return: the number of deleted or exception if error
-        '''
-        #print sql_dict
-        from_  = "FROM " + str(sql_dict['FROM'])
-        #print 'from_', from_
-        if 'WHERE' in sql_dict and len(sql_dict['WHERE']) > 0:
-            w=sql_dict['WHERE']
-            where_ = "WHERE " + " AND ".join(map(self.__tuple2db_format_where, w.iteritems())) 
-        else: where_ = ""
-        if 'WHERE_NOT' in sql_dict and len(sql_dict['WHERE_NOT']) > 0: 
-            w=sql_dict['WHERE_NOT']
-            where_2 = " AND ".join(map(self.__tuple2db_format_where_not, w.iteritems()))
-            if len(where_)==0:   where_ = "WHERE " + where_2
-            else:                where_ = where_ + " AND " + where_2
-        #print 'where_', where_
-        limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
-        #print 'limit_', limit_
-        cmd =  " ".join( ("DELETE", from_, where_, limit_) )
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor()
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    deleted = self.cur.rowcount
-                return deleted
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-    def get_rows_by_id(self, table, uuid):
-        '''get row from a table based on uuid'''
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
-                    cmd="SELECT * FROM {} where uuid='{}'".format(str(table), str(uuid))
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    rows = self.cur.fetchall()
-                    return rows
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-    
-    def get_rows(self, **sql_dict):
-        ''' Obtain rows from a table.
-        Attribute sql_dir: dictionary with the following key: value
-            'SELECT':    list or tuple of fields to retrieve) (by default all)
-            'FROM':      string of table name (Mandatory)
-            'WHERE':     dict of key:values, translated to key=value (key is null) AND ... (Optional)
-            'WHERE_NOT': dict of key:values, translated to key<>value (key is not null) AND ... (Optional)
-            'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
-            'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional)
-            'LIMIT':     limit of number of rows (Optional)
-            'ORDER_BY':  list or tuple of fields to order
-        Return: a list with dictionaries at each row
-        '''
-        #print sql_dict
-        select_= "SELECT " + ("*" if 'SELECT' not in sql_dict else ",".join(map(str,sql_dict['SELECT'])) )
-        #print 'select_', select_
-        from_  = "FROM " + str(sql_dict['FROM'])
-        #print 'from_', from_
-        where_and = ""
-        where_or = ""
-        w=sql_dict.get('WHERE')
-        if w:
-            where_and = " AND ".join(map(self.__tuple2db_format_where, w.iteritems() ))
-        w=sql_dict.get('WHERE_NOT')
-        if w: 
-            if where_and: where_and += " AND "
-            where_and += " AND ".join(map(self.__tuple2db_format_where_not, w.iteritems() ) )
-        w=sql_dict.get('WHERE_OR')
-        if w:
-            where_or =  " OR ".join(map(self.__tuple2db_format_where, w.iteritems() ))
-        if where_and and where_or:
-            if sql_dict.get("WHERE_AND_OR") == "AND":
-                where_ = "WHERE " + where_and + " AND (" + where_or + ")"
-            else:
-                where_ = "WHERE (" + where_and + ") OR " + where_or
-        elif where_and and not where_or:
-            where_ = "WHERE " + where_and
-        elif not where_and and where_or:
-            where_ = "WHERE " + where_or
-        else:
-            where_ = ""
-        #print 'where_', where_
-        limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
-        order_ = "ORDER BY " + ",".join(map(str,sql_dict['SELECT'])) if 'ORDER_BY' in sql_dict else ""
-        
-        #print 'limit_', limit_
-        cmd =  " ".join( (select_, from_, where_, limit_, order_) )
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    rows = self.cur.fetchall()
-                    return rows
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-    def get_table_by_uuid_name(self, table, uuid_name, error_item_text=None, allow_serveral=False, WHERE_OR={}, WHERE_AND_OR="OR"):
-        ''' Obtain One row from a table based on name or uuid.
-        Attribute:
-            table: string of table name
-            uuid_name: name or uuid. If not uuid format is found, it is considered a name
-            allow_severeral: if False return ERROR if more than one row are founded 
-            error_item_text: in case of error it identifies the 'item' name for a proper output text 
-            'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
-            'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional  
-        Return: if allow_several==False, a dictionary with this row, or error if no item is found or more than one is found
-                if allow_several==True, a list of dictionaries with the row or rows, error if no item is found
-        '''
-
-        if error_item_text==None:
-            error_item_text = table
-        what = 'uuid' if af.check_valid_uuid(uuid_name) else 'name'
-        cmd =  " SELECT * FROM {} WHERE {}='{}'".format(table, what, uuid_name)
-        if WHERE_OR:
-            where_or =  " OR ".join(map(self.__tuple2db_format_where, WHERE_OR.iteritems() ))
-            if WHERE_AND_OR == "AND":
-                cmd += " AND (" + where_or + ")"
-            else:
-                cmd += " OR " + where_or
-
-        
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    number = self.cur.rowcount
-                    if number==0:
-                        return -HTTP_Not_Found, "No %s found with %s '%s'" %(error_item_text, what, uuid_name)
-                    elif number>1 and not allow_serveral: 
-                        return -HTTP_Bad_Request, "More than one %s found with %s '%s'" %(error_item_text, what, uuid_name)
-                    if allow_serveral:
-                        rows = self.cur.fetchall()
-                    else:
-                        rows = self.cur.fetchone()
-                    return rows
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-    def get_uuid(self, uuid):
-        '''check in the database if this uuid is already present'''
-        for retry_ in range(0,2):
-            try:
-                with self.con:
-                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
-                    self.cur.execute("SELECT * FROM uuids where uuid='" + str(uuid) + "'")
-                    rows = self.cur.fetchall()
-                    return self.cur.rowcount, rows
-            except (mdb.Error, AttributeError) as e:
-                print "nfvo_db.get_uuid DB Exception %d: %s" % (e.args[0], e.args[1])
-                r,c = self._format_error(e)
-                if r!=-HTTP_Request_Timeout or retry_==1: return r,c
-
-    def get_uuid_from_name(self, table, name):
-        '''Searchs in table the name and returns the uuid
-        ''' 
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
-                    where_text = "name='" + name +"'"
-                    self.cur.execute("SELECT * FROM " + table + " WHERE "+ where_text)
-                    rows = self.cur.fetchall()
-                    if self.cur.rowcount==0:
-                        return 0, "Name %s not found in table %s" %(name, table)
-                    elif self.cur.rowcount>1:
-                        return self.cur.rowcount, "More than one VNF with name %s found in table %s" %(name, table)
-                    return self.cur.rowcount, rows[0]["uuid"]
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
diff --git a/httpserver.py b/httpserver.py
deleted file mode 100644 (file)
index a0216e1..0000000
+++ /dev/null
@@ -1,1267 +0,0 @@
-# -*- 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
-##
-
-'''
-HTTP server implementing the openmano API. It will answer to POST, PUT, GET methods in the appropriate URLs
-and will use the nfvo.py module to run the appropriate method.
-Every YAML/JSON file is checked against a schema in openmano_schemas.py module.  
-'''
-__author__="Alfonso Tierno, Gerardo Garcia"
-__date__ ="$17-sep-2014 09:07:15$"
-
-import bottle
-import yaml
-import json
-import threading
-import time
-import logging
-
-from jsonschema import validate as js_v, exceptions as js_e
-from openmano_schemas import vnfd_schema_v01, vnfd_schema_v02, \
-                            nsd_schema_v01, nsd_schema_v02, nsd_schema_v03, scenario_edit_schema, \
-                            scenario_action_schema, instance_scenario_action_schema, instance_scenario_create_schema_v01, \
-                            tenant_schema, tenant_edit_schema,\
-                            datacenter_schema, datacenter_edit_schema, datacenter_action_schema, datacenter_associate_schema,\
-                            object_schema, netmap_new_schema, netmap_edit_schema
-import nfvo
-import utils
-from db_base import db_base_Exception
-from functools import wraps
-
-global mydb
-global url_base
-global logger
-url_base="/openmano"
-logger = None
-
-HTTP_Bad_Request =          400
-HTTP_Unauthorized =         401 
-HTTP_Not_Found =            404 
-HTTP_Forbidden =            403
-HTTP_Method_Not_Allowed =   405 
-HTTP_Not_Acceptable =       406
-HTTP_Service_Unavailable =  503 
-HTTP_Internal_Server_Error= 500 
-
-def delete_nulls(var):
-    if type(var) is dict:
-        for k in var.keys():
-            if var[k] is None: del var[k]
-            elif type(var[k]) is dict or type(var[k]) is list or type(var[k]) is tuple: 
-                if delete_nulls(var[k]): del var[k]
-        if len(var) == 0: return True
-    elif type(var) is list or type(var) is tuple:
-        for k in var:
-            if type(k) is dict: delete_nulls(k)
-        if len(var) == 0: return True
-    return False
-
-def convert_datetime2str(var):
-    '''Converts a datetime variable to a string with the format '%Y-%m-%dT%H:%i:%s'
-    It enters recursively in the dict var finding this kind of variables
-    '''
-    if type(var) is dict:
-        for k,v in var.items():
-            if type(v) is float and k in ("created_at", "modified_at"):
-                var[k] = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(v) )
-            elif type(v) is dict or type(v) is list or type(v) is tuple: 
-                convert_datetime2str(v)
-        if len(var) == 0: return True
-    elif type(var) is list or type(var) is tuple:
-        for v in var:
-            convert_datetime2str(v)
-
-def log_to_logger(fn):
-    '''
-    Wrap a Bottle request so that a log line is emitted after it's handled.
-    (This decorator can be extended to take the desired logger as a param.)
-    '''
-    @wraps(fn)
-    def _log_to_logger(*args, **kwargs):
-        actual_response = fn(*args, **kwargs)
-        # modify this to log exactly what you need:
-        logger.info('FROM %s %s %s %s' % (bottle.request.remote_addr,
-                                        bottle.request.method,
-                                        bottle.request.url,
-                                        bottle.response.status))
-        return actual_response
-    return _log_to_logger
-
-class httpserver(threading.Thread):
-    def __init__(self, db, admin=False, host='localhost', port=9090):
-        #global url_base
-        global mydb
-        global logger
-        #initialization
-        if not logger:
-            logger = logging.getLogger('openmano.http')
-        threading.Thread.__init__(self)
-        self.host = host
-        self.port = port   #Port where the listen service must be started
-        if admin==True:
-            self.name = "http_admin"
-        else:
-            self.name = "http"
-            #self.url_preffix = 'http://' + host + ':' + str(port) + url_base
-            mydb = db
-        #self.first_usable_connection_index = 10
-        #self.next_connection_index = self.first_usable_connection_index #The next connection index to be used 
-        #Ensure that when the main program exits the thread will also exit
-        self.daemon = True
-        self.setDaemon(True)
-         
-    def run(self):
-        bottle.install(log_to_logger)
-        bottle.run(host=self.host, port=self.port, debug=False, quiet=True)
-           
-def run_bottle(db, host_='localhost', port_=9090):
-    '''used for launching in main thread, so that it can be debugged'''
-    global mydb
-    mydb = db
-    bottle.run(host=host_, port=port_, debug=True) #quiet=True
-    
-
-@bottle.route(url_base + '/', method='GET')
-def http_get():
-    #print 
-    return 'works' #TODO: to be completed
-
-#
-# Util functions
-#
-
-def change_keys_http2db(data, http_db, reverse=False):
-    '''Change keys of dictionary data acording to the key_dict values
-    This allow change from http interface names to database names.
-    When reverse is True, the change is otherwise
-    Attributes:
-        data: can be a dictionary or a list
-        http_db: is a dictionary with hhtp names as keys and database names as value
-        reverse: by default change is done from http api to database. If True change is done otherwise
-    Return: None, but data is modified'''
-    if type(data) is tuple or type(data) is list:
-        for d in data:
-            change_keys_http2db(d, http_db, reverse)
-    elif type(data) is dict or type(data) is bottle.FormsDict:
-        if reverse:
-            for k,v in http_db.items():
-                if v in data: data[k]=data.pop(v)
-        else:
-            for k,v in http_db.items():
-                if k in data: data[v]=data.pop(k)
-
-def format_out(data):
-    '''return string of dictionary data according to requested json, yaml, xml. By default json'''
-    logger.debug("OUT: " + yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) )
-    if 'application/yaml' in bottle.request.headers.get('Accept'):
-        bottle.response.content_type='application/yaml'
-        return yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) #, canonical=True, default_style='"'
-    else: #by default json
-        bottle.response.content_type='application/json'
-        #return data #json no style
-        return json.dumps(data, indent=4) + "\n"
-
-def format_in(default_schema, version_fields=None, version_dict_schema=None):
-    ''' Parse the content of HTTP request against a json_schema
-        Parameters
-            default_schema: The schema to be parsed by default if no version field is found in the client data
-            version_fields: If provided it contains a tuple or list with the fields to iterate across the client data to obtain the version
-            version_dict_schema: It contains a dictionary with the version as key, and json schema to apply as value
-                It can contain a None as key, and this is apply if the client data version does not match any key 
-        Return:
-            user_data, used_schema: if the data is successfully decoded and matches the schema
-            launch a bottle abort if fails
-    '''
-    #print "HEADERS :" + str(bottle.request.headers.items())
-    try:
-        error_text = "Invalid header format "
-        format_type = bottle.request.headers.get('Content-Type', 'application/json')
-        if 'application/json' in format_type:
-            error_text = "Invalid json format "
-            #Use the json decoder instead of bottle decoder because it informs about the location of error formats with a ValueError exception
-            client_data = json.load(bottle.request.body)
-            #client_data = bottle.request.json()
-        elif 'application/yaml' in format_type:
-            error_text = "Invalid yaml format "
-            client_data = yaml.load(bottle.request.body)
-        elif 'application/xml' in format_type:
-            bottle.abort(501, "Content-Type: application/xml not supported yet.")
-        else:
-            logger.warning('Content-Type ' + str(format_type) + ' not supported.')
-            bottle.abort(HTTP_Not_Acceptable, 'Content-Type ' + str(format_type) + ' not supported.')
-            return
-        #if client_data == None:
-        #    bottle.abort(HTTP_Bad_Request, "Content error, empty")
-        #    return
-
-        logger.debug('IN: %s', yaml.safe_dump(client_data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) )
-        #look for the client provider version
-        error_text = "Invalid content "
-        client_version = None
-        used_schema = None
-        if version_fields != None:
-            client_version = client_data
-            for field in version_fields:
-                if field in client_version:
-                    client_version = client_version[field]
-                else:
-                    client_version=None
-                    break
-        if client_version==None:
-            used_schema=default_schema
-        elif version_dict_schema!=None:
-            if client_version in version_dict_schema:
-                used_schema = version_dict_schema[client_version]
-            elif None in version_dict_schema:
-                used_schema = version_dict_schema[None]
-        if used_schema==None:
-            bottle.abort(HTTP_Bad_Request, "Invalid schema version or missing version field")
-            
-        js_v(client_data, used_schema)
-        return client_data, used_schema
-    except (ValueError, yaml.YAMLError) as exc:
-        error_text += str(exc)
-        logger.error(error_text) 
-        bottle.abort(HTTP_Bad_Request, error_text)
-    except js_e.ValidationError as exc:
-        logger.error("validate_in error, jsonschema exception at '%s' '%s' ", str(exc.path), str(exc.message))
-        error_pos = ""
-        if len(exc.path)>0: error_pos=" at " + ":".join(map(json.dumps, exc.path))
-        bottle.abort(HTTP_Bad_Request, error_text + exc.message + error_pos)
-    #except:
-    #    bottle.abort(HTTP_Bad_Request, "Content error: Failed to parse Content-Type",  error_pos)
-    #    raise
-
-def filter_query_string(qs, http2db, allowed):
-    '''Process query string (qs) checking that contains only valid tokens for avoiding SQL injection
-    Attributes:
-        'qs': bottle.FormsDict variable to be processed. None or empty is considered valid
-        'http2db': dictionary with change from http API naming (dictionary key) to database naming(dictionary value)
-        'allowed': list of allowed string tokens (API http naming). All the keys of 'qs' must be one of 'allowed'
-    Return: A tuple with the (select,where,limit) to be use in a database query. All of then transformed to the database naming
-        select: list of items to retrieve, filtered by query string 'field=token'. If no 'field' is present, allowed list is returned
-        where: dictionary with key, value, taken from the query string token=value. Empty if nothing is provided
-        limit: limit dictated by user with the query string 'limit'. 100 by default
-    abort if not permited, using bottel.abort
-    '''
-    where={}
-    limit=100
-    select=[]
-    #if type(qs) is not bottle.FormsDict:
-    #    bottle.abort(HTTP_Internal_Server_Error, '!!!!!!!!!!!!!!invalid query string not a dictionary')
-    #    #bottle.abort(HTTP_Internal_Server_Error, "call programmer")
-    for k in qs:
-        if k=='field':
-            select += qs.getall(k)
-            for v in select:
-                if v not in allowed:
-                    bottle.abort(HTTP_Bad_Request, "Invalid query string at 'field="+v+"'")
-        elif k=='limit':
-            try:
-                limit=int(qs[k])
-            except:
-                bottle.abort(HTTP_Bad_Request, "Invalid query string at 'limit="+qs[k]+"'")
-        else:
-            if k not in allowed:
-                bottle.abort(HTTP_Bad_Request, "Invalid query string at '"+k+"="+qs[k]+"'")
-            if qs[k]!="null":  where[k]=qs[k]
-            else: where[k]=None 
-    if len(select)==0: select += allowed
-    #change from http api to database naming
-    for i in range(0,len(select)):
-        k=select[i]
-        if http2db and k in http2db: 
-            select[i] = http2db[k]
-    if http2db:
-        change_keys_http2db(where, http2db)
-    #print "filter_query_string", select,where,limit
-    
-    return select,where,limit
-
-@bottle.hook('after_request')
-def enable_cors():
-    '''Don't know yet if really needed. Keep it just in case'''
-    bottle.response.headers['Access-Control-Allow-Origin'] = '*'
-
-#
-# VNFs
-#
-
-@bottle.route(url_base + '/tenants', method='GET')
-def http_get_tenants():
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    select_,where_,limit_ = filter_query_string(bottle.request.query, None,
-            ('uuid','name','description','created_at') )
-    try:
-        tenants = mydb.get_rows(FROM='nfvo_tenants', SELECT=select_,WHERE=where_,LIMIT=limit_)
-        #change_keys_http2db(content, http2db_tenant, reverse=True)
-        convert_datetime2str(tenants)
-        data={'tenants' : tenants}
-        return format_out(data)
-    except db_base_Exception as e:
-        logger.error("http_get_tenants error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/tenants/<tenant_id>', method='GET')
-def http_get_tenant_id(tenant_id):
-    '''get tenant details, can use both uuid or name'''
-    #obtain data
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        tenant = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id, "tenant") 
-        #change_keys_http2db(content, http2db_tenant, reverse=True)
-        convert_datetime2str(tenant)
-        data={'tenant' : tenant}
-        return format_out(data)
-    except db_base_Exception as e:
-        logger.error("http_get_tenant_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/tenants', method='POST')
-def http_post_tenants():
-    '''insert a tenant into the catalogue. '''
-    #parse input data
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    http_content,_ = format_in( tenant_schema )
-    r = utils.remove_extra_items(http_content, tenant_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    try: 
-        data = nfvo.new_tenant(mydb, http_content['tenant'])
-        return http_get_tenant_id(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_tenants error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/tenants/<tenant_id>', method='PUT')
-def http_edit_tenant_id(tenant_id):
-    '''edit tenant details, can use both uuid or name'''
-    #parse input data
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    http_content,_ = format_in( tenant_edit_schema )
-    r = utils.remove_extra_items(http_content, tenant_edit_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    
-    #obtain data, check that only one exist
-    try: 
-        tenant = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id)
-        #edit data 
-        tenant_id = tenant['uuid']
-        where={'uuid': tenant['uuid']}
-        mydb.update_rows('nfvo_tenants', http_content['tenant'], where)
-        return http_get_tenant_id(tenant_id)
-    except db_base_Exception as e:
-        logger.error("http_edit_tenant_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/tenants/<tenant_id>', method='DELETE')
-def http_delete_tenant_id(tenant_id):
-    '''delete a tenant from database, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        data = nfvo.delete_tenant(mydb, tenant_id)
-        return format_out({"result":"tenant " + data + " deleted"})
-    except db_base_Exception as e:
-        logger.error("http_delete_tenant_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/datacenters', method='GET')
-def http_get_datacenters(tenant_id):
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        if tenant_id != 'any':
-            #check valid tenant_id
-            nfvo.check_tenant(mydb, tenant_id)
-        select_,where_,limit_ = filter_query_string(bottle.request.query, None,
-                ('uuid','name','vim_url','type','created_at') )
-        if tenant_id != 'any':
-            where_['nfvo_tenant_id'] = tenant_id
-            if 'created_at' in select_:
-                select_[ select_.index('created_at') ] = 'd.created_at as created_at'
-            if 'created_at' in where_:
-                where_['d.created_at'] = where_.pop('created_at')
-            datacenters = mydb.get_rows(FROM='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id',
-                                          SELECT=select_,WHERE=where_,LIMIT=limit_)
-        else:
-            datacenters = mydb.get_rows(FROM='datacenters',
-                                          SELECT=select_,WHERE=where_,LIMIT=limit_)
-        #change_keys_http2db(content, http2db_tenant, reverse=True)
-        convert_datetime2str(datacenters)
-        data={'datacenters' : datacenters}
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_datacenters error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='GET')
-def http_get_datacenter_id(tenant_id, datacenter_id):
-    '''get datacenter details, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        if tenant_id != 'any':
-            #check valid tenant_id
-            nfvo.check_tenant(mydb, tenant_id)
-        #obtain data
-        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', '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
-            from_='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id'
-        else:
-            from_='datacenters as d'
-        datacenters = mydb.get_rows(
-                    SELECT=select_,
-                    FROM=from_,
-                    WHERE=where_)
-    
-        if len(datacenters)==0:
-            bottle.abort( HTTP_Not_Found, "No datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
-        elif len(datacenters)>1: 
-            bottle.abort( HTTP_Bad_Request, "More than one datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
-        datacenter = datacenters[0]
-        if tenant_id != 'any':
-            #get vim tenant info
-            vim_tenants = mydb.get_rows(
-                    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 as e:
-                        logger.error("Exception '%s' while trying to load config information", str(e))
-
-        if datacenter['config'] != None:
-            try:
-                config_dict = yaml.load(datacenter['config'])
-                datacenter['config'] = config_dict
-            except Exception as e:
-                logger.error("Exception '%s' while trying to load config information", str(e))
-        #change_keys_http2db(content, http2db_datacenter, reverse=True)
-        convert_datetime2str(datacenter)
-        data={'datacenter' : datacenter}
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_datacenter_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/datacenters', method='POST')
-def http_post_datacenters():
-    '''insert a tenant into the catalogue. '''
-    #parse input data
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    http_content,_ = format_in( datacenter_schema )
-    r = utils.remove_extra_items(http_content, datacenter_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    try:
-        data = nfvo.new_datacenter(mydb, http_content['datacenter'])
-        return http_get_datacenter_id('any', data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_datacenters error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/datacenters/<datacenter_id_name>', method='PUT')
-def http_edit_datacenter_id(datacenter_id_name):
-    '''edit datacenter details, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #parse input data
-    http_content,_ = format_in( datacenter_edit_schema )
-    r = utils.remove_extra_items(http_content, datacenter_edit_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    
-    try:
-        datacenter_id = nfvo.edit_datacenter(mydb, datacenter_id_name, http_content['datacenter'])
-        return http_get_datacenter_id('any', datacenter_id)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_edit_datacenter_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/networks', method='GET')  #deprecated
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='GET')
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='GET')
-def http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
-    '''get datacenter networks, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #obtain data
-    try:
-        datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter") 
-        where_= {"datacenter_id":datacenter_dict['uuid']}
-        if netmap_id:
-            if utils.check_valid_uuid(netmap_id):
-                where_["uuid"] = netmap_id
-            else:
-                where_["name"] = netmap_id
-        netmaps =mydb.get_rows(FROM='datacenter_nets',
-                                        SELECT=('name','vim_net_id as vim_id', 'uuid', 'type','multipoint','shared','description', 'created_at'),
-                                        WHERE=where_ ) 
-        convert_datetime2str(netmaps)
-        utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
-        if netmap_id and len(netmaps)==1:
-            data={'netmap' : netmaps[0]}
-        elif netmap_id and len(netmaps)==0:
-            bottle.abort(HTTP_Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
-            return 
-        else:
-            data={'netmaps' : netmaps}
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_getnetwork_datacenter_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='DELETE')
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='DELETE')
-def http_delnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
-    '''get datacenter networks, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #obtain data
-    try:
-        datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter") 
-        where_= {"datacenter_id":datacenter_dict['uuid']}
-        if netmap_id:
-            if utils.check_valid_uuid(netmap_id):
-                where_["uuid"] = netmap_id
-            else:
-                where_["name"] = netmap_id
-        #change_keys_http2db(content, http2db_tenant, reverse=True)
-        deleted = mydb.delete_row(FROM='datacenter_nets', WHERE= where_) 
-        if deleted == 0 and netmap_id :
-            bottle.abort(HTTP_Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
-        if netmap_id:
-            return format_out({"result": "netmap %s deleted" % netmap_id})
-        else:
-            return format_out({"result": "%d netmap deleted" % deleted})
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_delnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/upload', method='POST')
-def http_uploadnetmap_datacenter_id(tenant_id, datacenter_id):
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, None)
-        convert_datetime2str(netmaps)
-        utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
-        data={'netmaps' : netmaps}
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_uploadnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='POST')
-def http_postnetmap_datacenter_id(tenant_id, datacenter_id):
-    '''creates a new netmap'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #parse input data
-    http_content,_ = format_in( netmap_new_schema )
-    r = utils.remove_extra_items(http_content, netmap_new_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    try:
-        #obtain data, check that only one exist
-        netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, http_content)
-        convert_datetime2str(netmaps)
-        utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
-        data={'netmaps' : netmaps}
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_postnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='PUT')
-def http_putnettmap_datacenter_id(tenant_id, datacenter_id, netmap_id):
-    '''edit a  netmap'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #parse input data
-    http_content,_ = format_in( netmap_edit_schema )
-    r = utils.remove_extra_items(http_content, netmap_edit_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    
-    #obtain data, check that only one exist
-    try:
-        nfvo.datacenter_edit_netmap(mydb, tenant_id, datacenter_id, netmap_id, http_content)
-        return http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_putnettmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-    
-
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/action', method='POST')
-def http_action_datacenter_id(tenant_id, datacenter_id):
-    '''perform an action over datacenter, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #parse input data
-    http_content,_ = format_in( datacenter_action_schema )
-    r = utils.remove_extra_items(http_content, datacenter_action_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    try:
-        #obtain data, check that only one exist
-        result = nfvo.datacenter_action(mydb, tenant_id, datacenter_id, http_content)
-        if 'net-update' in http_content:
-            return http_getnetmap_datacenter_id(datacenter_id)
-        else:
-            return format_out(result)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_action_datacenter_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/datacenters/<datacenter_id>', method='DELETE')
-def http_delete_datacenter_id( datacenter_id):
-    '''delete a tenant from database, can use both uuid or name'''
-    
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        data = nfvo.delete_datacenter(mydb, datacenter_id)
-        return format_out({"result":"datacenter '" + data + "' deleted"})
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_delete_datacenter_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='POST')
-def http_associate_datacenters(tenant_id, datacenter_id):
-    '''associate an existing datacenter to a this tenant. '''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #parse input data
-    http_content,_ = format_in( datacenter_associate_schema )
-    r = utils.remove_extra_items(http_content, datacenter_associate_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    try:
-        id_ = nfvo.associate_datacenter_to_tenant(mydb, 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('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)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='DELETE')
-def http_deassociate_datacenters(tenant_id, datacenter_id):
-    '''deassociate an existing datacenter to a this tenant. '''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        data = nfvo.deassociate_datacenter_to_tenant(mydb, tenant_id, datacenter_id)
-        return format_out({"result": data})
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_deassociate_datacenters error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-       
-@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='GET')
-@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='GET')
-def http_get_vim_items(tenant_id, datacenter_id, item, name=None):
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        data = nfvo.vim_action_get(mydb, tenant_id, datacenter_id, item, name)
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_vim_items error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='DELETE')
-def http_del_vim_items(tenant_id, datacenter_id, item, name):
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        data = nfvo.vim_action_delete(mydb, tenant_id, datacenter_id, item, name)
-        return format_out({"result":data})
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_del_vim_items error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='POST')
-def http_post_vim_items(tenant_id, datacenter_id, item):
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    http_content,_ = format_in( object_schema )
-    try:
-        data = nfvo.vim_action_create(mydb, tenant_id, datacenter_id, item, http_content)
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_vim_items error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/vnfs', method='GET')
-def http_get_vnfs(tenant_id):
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        if tenant_id != 'any':
-            #check valid tenant_id
-            nfvo.check_tenant(mydb, tenant_id)
-        select_,where_,limit_ = filter_query_string(bottle.request.query, None,
-                ('uuid','name','description','public', "tenant_id", "created_at") )
-        where_or = {}
-        if tenant_id != "any":
-            where_or["tenant_id"] = tenant_id
-            where_or["public"] = True
-        vnfs = mydb.get_rows(FROM='vnfs', SELECT=select_,WHERE=where_,WHERE_OR=where_or, WHERE_AND_OR="AND",LIMIT=limit_)
-        #change_keys_http2db(content, http2db_vnf, reverse=True)
-        utils.convert_str2boolean(vnfs, ('public',))
-        convert_datetime2str(vnfs)
-        data={'vnfs' : vnfs}
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_vnfs error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='GET')
-def http_get_vnf_id(tenant_id,vnf_id):
-    '''get vnf details, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        vnf = nfvo.get_vnf_id(mydb,tenant_id,vnf_id)
-        utils.convert_str2boolean(vnf, ('public',))
-        convert_datetime2str(vnf)
-        return format_out(vnf)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_vnf_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/vnfs', method='POST')
-def http_post_vnfs(tenant_id):
-    '''insert a vnf into the catalogue. Creates the flavor and images in the VIM, and creates the VNF and its internal structure in the OPENMANO DB'''
-    #print "Parsing the YAML file of the VNF"
-    #parse input data
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    http_content, used_schema = format_in( vnfd_schema_v01, ("schema_version",), {"0.2": vnfd_schema_v02})
-    r = utils.remove_extra_items(http_content, used_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    try:
-        if used_schema == vnfd_schema_v01:
-            vnf_id = nfvo.new_vnf(mydb,tenant_id,http_content)
-        elif used_schema == vnfd_schema_v02:
-            vnf_id = nfvo.new_vnf_v02(mydb,tenant_id,http_content)
-        else:
-            logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
-            bottle.abort(HTTP_Bad_Request, "Invalid schema version")
-        return http_get_vnf_id(tenant_id, vnf_id)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_vnfs error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-            
-@bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='DELETE')
-def http_delete_vnf_id(tenant_id,vnf_id):
-    '''delete a vnf from database, and images and flavors in VIM when appropriate, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #check valid tenant_id and deletes the vnf, including images, 
-    try:
-        data = nfvo.delete_vnf(mydb,tenant_id,vnf_id)
-        #print json.dumps(data, indent=4)
-        return format_out({"result":"VNF " + data + " deleted"})
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_delete_vnf_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-#@bottle.route(url_base + '/<tenant_id>/hosts/topology', method='GET')
-#@bottle.route(url_base + '/<tenant_id>/physicalview/Madrid-Alcantara', method='GET')
-@bottle.route(url_base + '/<tenant_id>/physicalview/<datacenter>', method='GET')
-def http_get_hosts(tenant_id, datacenter):
-    '''get the tidvim host hopology from the vim.'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #print "http_get_hosts received by tenant " + tenant_id + ' datacenter ' + datacenter
-    try:
-        if datacenter == 'treeview':
-            data = nfvo.get_hosts(mydb, tenant_id)
-        else:
-            #openmano-gui is using a hardcoded value for the datacenter
-            result, data = nfvo.get_hosts_info(mydb, tenant_id) #, datacenter)
-        
-        if result < 0:
-            #print "http_get_hosts error %d %s" % (-result, data)
-            bottle.abort(-result, data)
-        else:
-            convert_datetime2str(data)
-            #print json.dumps(data, indent=4)
-            return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_hosts error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<path:path>', method='OPTIONS')
-def http_options_deploy(path):
-    '''For some reason GUI web ask for OPTIONS that must be responded'''
-    #TODO: check correct path, and correct headers request
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    bottle.response.set_header('Access-Control-Allow-Methods','POST, GET, PUT, DELETE, OPTIONS')
-    bottle.response.set_header('Accept','application/yaml,application/json')
-    bottle.response.set_header('Content-Type','application/yaml,application/json')
-    bottle.response.set_header('Access-Control-Allow-Headers','content-type')
-    bottle.response.set_header('Access-Control-Allow-Origin','*')
-    return
-
-@bottle.route(url_base + '/<tenant_id>/topology/deploy', method='POST')
-def http_post_deploy(tenant_id):
-    '''post topology deploy.'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-
-    http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02})
-    #r = utils.remove_extra_items(http_content, used_schema)
-    #if r is not None: print "http_post_deploy: Warning: remove extra items ", r
-    #print "http_post_deploy input: ",  http_content
-    
-    try:
-        scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
-        instance = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['name'], http_content['name'])
-        #print json.dumps(data, indent=4)
-        return format_out(instance)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_deploy error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/topology/verify', method='POST')
-def http_post_verify(tenant_id):
-    #TODO:
-#    '''post topology verify'''
-#    print "http_post_verify by tenant " + tenant_id + ' datacenter ' + datacenter
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    return 
-
-#
-# SCENARIOS
-#
-
-@bottle.route(url_base + '/<tenant_id>/scenarios', method='POST')
-def http_post_scenarios(tenant_id):
-    '''add a scenario into the catalogue. Creates the scenario and its internal structure in the OPENMANO DB'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02, "0.3": nsd_schema_v03})
-    #r = utils.remove_extra_items(http_content, used_schema)
-    #if r is not None: print "http_post_scenarios: Warning: remove extra items ", r
-    #print "http_post_scenarios input: ",  http_content
-    try:
-        if used_schema == nsd_schema_v01:
-            scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
-        elif used_schema == nsd_schema_v02:
-            scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content, "0.2")
-        elif used_schema == nsd_schema_v03:
-            scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content, "0.3")
-        else:
-            logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
-            bottle.abort(HTTP_Bad_Request, "Invalid schema version")
-        #print json.dumps(data, indent=4)
-        #return format_out(data)
-        return http_get_scenario_id(tenant_id, scenario_id)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_scenarios error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>/action', method='POST')
-def http_post_scenario_action(tenant_id, scenario_id):
-    '''take an action over a scenario'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    # parse input data
-    http_content, _ = format_in(scenario_action_schema)
-    r = utils.remove_extra_items(http_content, scenario_action_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    try:
-        # check valid tenant_id
-        nfvo.check_tenant(mydb, tenant_id)
-        if "start" in http_content:
-            data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['start']['instance_name'], \
-                        http_content['start'].get('description',http_content['start']['instance_name']),
-                        http_content['start'].get('datacenter') )
-            return format_out(data)
-        elif "deploy" in http_content:   #Equivalent to start
-            data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['deploy']['instance_name'],
-                        http_content['deploy'].get('description',http_content['deploy']['instance_name']),
-                        http_content['deploy'].get('datacenter') )
-            return format_out(data)
-        elif "reserve" in http_content:   #Reserve resources
-            data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['reserve']['instance_name'],
-                        http_content['reserve'].get('description',http_content['reserve']['instance_name']),
-                        http_content['reserve'].get('datacenter'),  startvms=False )
-            return format_out(data)
-        elif "verify" in http_content:   #Equivalent to start and then delete
-            data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['verify']['instance_name'],
-                        http_content['verify'].get('description',http_content['verify']['instance_name']),
-                        http_content['verify'].get('datacenter'), startvms=False )
-            instance_id = data['uuid']
-            nfvo.delete_instance(mydb, tenant_id,instance_id)
-            return format_out({"result":"Verify OK"})
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_scenario_action error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/scenarios', method='GET')
-def http_get_scenarios(tenant_id):
-    '''get scenarios list'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        #check valid tenant_id
-        if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
-        #obtain data
-        s,w,l=filter_query_string(bottle.request.query, None, ('uuid', 'name', 'description', 'tenant_id', 'created_at', 'public'))
-        where_or={}
-        if tenant_id != "any":
-            where_or["tenant_id"] = tenant_id
-            where_or["public"] = True
-        scenarios = mydb.get_rows(SELECT=s, WHERE=w, WHERE_OR=where_or, WHERE_AND_OR="AND", LIMIT=l, FROM='scenarios')
-        convert_datetime2str(scenarios)
-        utils.convert_str2boolean(scenarios, ('public',) )
-        data={'scenarios':scenarios}
-        #print json.dumps(scenarios, indent=4)
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_scenarios error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='GET')
-def http_get_scenario_id(tenant_id, scenario_id):
-    '''get scenario details, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        #check valid tenant_id
-        if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
-        #obtain data
-        scenario = mydb.get_scenario(scenario_id, tenant_id)
-        convert_datetime2str(scenario)
-        data={'scenario' : scenario}
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_scenarios error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='DELETE')
-def http_delete_scenario_id(tenant_id, scenario_id):
-    '''delete a scenario from database, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        #check valid tenant_id
-        if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id)
-        #obtain data
-        data = mydb.delete_scenario(scenario_id, tenant_id)
-        #print json.dumps(data, indent=4)
-        return format_out({"result":"scenario " + data + " deleted"})
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_delete_scenario_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='PUT')
-def http_put_scenario_id(tenant_id, scenario_id):
-    '''edit an existing scenario id'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    http_content,_ = format_in( scenario_edit_schema )
-    #r = utils.remove_extra_items(http_content, scenario_edit_schema)
-    #if r is not None: print "http_put_scenario_id: Warning: remove extra items ", r
-    #print "http_put_scenario_id input: ",  http_content
-    try:
-        nfvo.edit_scenario(mydb, tenant_id, scenario_id, http_content)
-        #print json.dumps(data, indent=4)
-        #return format_out(data)
-        return http_get_scenario_id(tenant_id, scenario_id)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_put_scenario_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-@bottle.route(url_base + '/<tenant_id>/instances', method='POST')
-def http_post_instances(tenant_id):
-    '''create an instance-scenario'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    # parse input data
-    http_content, used_schema = format_in(instance_scenario_create_schema_v01)
-    r = utils.remove_extra_items(http_content, used_schema)
-    if r is not None:
-        logger.warning("http_post_instances: Warning: remove extra items %s", str(r))
-    try:
-        #check valid tenant_id
-        if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
-        data = nfvo.create_instance(mydb, tenant_id, http_content["instance"])
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_instances error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-#
-# INSTANCES
-#
-@bottle.route(url_base + '/<tenant_id>/instances', method='GET')
-def http_get_instances(tenant_id):
-    '''get instance list'''
-    try:
-        #check valid tenant_id
-        if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
-        #obtain data
-        s,w,l=filter_query_string(bottle.request.query, None, ('uuid', 'name', 'scenario_id', 'tenant_id', 'description', 'created_at'))
-        if tenant_id != "any":
-            w['tenant_id'] = tenant_id
-        instances = mydb.get_rows(SELECT=s, WHERE=w, LIMIT=l, FROM='instance_scenarios')
-        convert_datetime2str(instances)
-        utils.convert_str2boolean(instances, ('public',) )
-        data={'instances':instances}
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_instances error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='GET')
-def http_get_instance_id(tenant_id, instance_id):
-    '''get instances details, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        #check valid tenant_id
-        if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
-        if tenant_id == "any":
-            tenant_id = None
-        #obtain data (first time is only to check that the instance exists)
-        instance_dict = mydb.get_instance_scenario(instance_id, tenant_id, verbose=True)
-        try:
-            nfvo.refresh_instance(mydb, tenant_id, instance_dict)
-        except (nfvo.NfvoException, db_base_Exception) as e:
-            logger.warn("nfvo.refresh_instance couldn't refresh the status of the instance: %s" % str(e))
-        #obtain data with results upated
-        instance = mydb.get_instance_scenario(instance_id, tenant_id)
-        convert_datetime2str(instance)
-        #print json.dumps(instance, indent=4)
-        return format_out(instance)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_get_instance_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='DELETE')
-def http_delete_instance_id(tenant_id, instance_id):
-    '''delete instance from VIM and from database, can use both uuid or name'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    try:
-        #check valid tenant_id
-        if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
-        if tenant_id == "any":
-            tenant_id = None
-        #obtain data
-        message = nfvo.delete_instance(mydb, tenant_id,instance_id)
-        return format_out({"result":message})
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_delete_instance_id error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action', method='POST')
-def http_post_instance_scenario_action(tenant_id, instance_id):
-    '''take an action over a scenario instance'''
-    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    # parse input data
-    http_content, _ = format_in(instance_scenario_action_schema)
-    r = utils.remove_extra_items(http_content, instance_scenario_action_schema)
-    if r:
-        logger.debug("Remove received extra items %s", str(r))
-    try:
-        #check valid tenant_id
-        if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
-
-        #print "http_post_instance_scenario_action input: ", http_content
-        #obtain data
-        instance = mydb.get_instance_scenario(instance_id, tenant_id)
-        instance_id = instance["uuid"]
-        
-        data = nfvo.instance_action(mydb, tenant_id, instance_id, http_content)
-        return format_out(data)
-    except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_instance_scenario_action error {}: {}".format(e.http_code, str(e)))
-        bottle.abort(e.http_code, str(e))
-    except Exception as e:
-        logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-
-@bottle.error(400)
-@bottle.error(401) 
-@bottle.error(404) 
-@bottle.error(403)
-@bottle.error(405) 
-@bottle.error(406)
-@bottle.error(409)
-@bottle.error(503) 
-@bottle.error(500)
-def error400(error):
-    e={"error":{"code":error.status_code, "type":error.status, "description":error.body}}
-    bottle.response.headers['Access-Control-Allow-Origin'] = '*'
-    return format_out(e)
-
diff --git a/nfvo.py b/nfvo.py
deleted file mode 100644 (file)
index 14ec54f..0000000
--- a/nfvo.py
+++ /dev/null
@@ -1,3056 +0,0 @@
-# -*- 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
-##
-
-'''
-NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances
-'''
-__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
-__date__ ="$16-sep-2014 22:05:01$"
-
-import imp
-#import json
-import yaml
-import utils
-import vim_thread
-from db_base import HTTP_Unauthorized, HTTP_Bad_Request, HTTP_Internal_Server_Error, HTTP_Not_Found,\
-    HTTP_Conflict, HTTP_Method_Not_Allowed
-import console_proxy_thread as cli
-import vimconn
-import logging
-import collections
-from db_base import db_base_Exception
-import nfvo_db
-from threading import Lock
-from time import time
-
-global global_config
-global vimconn_imported
-global logger
-global default_volume_size
-default_volume_size = '5' #size in GB
-
-
-vimconn_imported = {}   # dictionary with VIM type as key, loaded module as value
-vim_threads = {"running":{}, "deleting": {}, "names": []}      # threads running for attached-VIMs
-vim_persistent_info = {}
-logger = logging.getLogger('openmano.nfvo')
-task_lock = Lock()
-task_dict = {}
-last_task_id = 0.0
-db=None
-db_lock=Lock()
-
-class NfvoException(Exception):
-    def __init__(self, message, http_code):
-        self.http_code = http_code
-        Exception.__init__(self, message)
-
-
-def get_task_id():
-    global last_task_id
-    task_id = time()
-    if task_id <= last_task_id:
-        task_id = last_task_id + 0.000001
-    last_task_id = task_id
-    return "TASK.{:.6f}".format(task_id)
-
-
-def new_task(name, params, store=True, depends=None):
-    task_id = get_task_id()
-    task = {"status": "enqueued", "id": task_id, "name": name, "params": params}
-    if depends:
-        task["depends"] = depends
-    if store:
-        task_dict[task_id] = task
-    return task
-
-
-def is_task_id(id):
-    return True if id[:5] == "TASK." else False
-
-
-def get_non_used_vim_name(datacenter_name, datacenter_id, tenant_name, tenant_id):
-    name = datacenter_name[:16]
-    if name not in vim_threads["names"]:
-        vim_threads["names"].append(name)
-        return name
-    name = datacenter_name[:16] + "." + tenant_name[:16]
-    if name not in vim_threads["names"]:
-        vim_threads["names"].append(name)
-        return name
-    name = datacenter_id + "-" + tenant_id
-    vim_threads["names"].append(name)
-    return name
-
-
-def start_service(mydb):
-    global db, global_config
-    db = nfvo_db.nfvo_db()
-    db.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name'])
-    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','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', 'dt.config as dt_config', 'nfvo_tenant_id')
-    try:
-        vims = mydb.get_rows(FROM=from_, SELECT=select_)
-        for vim in vims:
-            extra={'datacenter_tenant_id': vim.get('datacenter_tenant_id')}
-            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:
-                    module = "vimconn_" + vim["type"]
-                    module_info = imp.find_module(module)
-                    vim_conn = imp.load_module(vim["type"], *module_info)
-                    vimconn_imported[vim["type"]] = vim_conn
-                except (IOError, ImportError) as e:
-                    if module_info and module_info[0]:
-                        file.close(module_info[0])
-                    raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
-                        vim["type"], module, type(e).__name__, str(e)), HTTP_Bad_Request)
-
-            thread_id = vim["datacenter_id"] + "." + vim['nfvo_tenant_id']
-            vim_persistent_info[thread_id] = {}
-            try:
-                #if not tenant:
-                #    return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
-                myvim = vimconn_imported[ vim["type"] ].vimconnector(
-                    uuid=vim['datacenter_id'], name=vim['datacenter_name'],
-                    tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
-                    url=vim['vim_url'], url_admin=vim['vim_url_admin'],
-                    user=vim['user'], passwd=vim['passwd'],
-                    config=extra, persistent_info=vim_persistent_info[thread_id]
-                )
-            except Exception as e:
-                raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), HTTP_Internal_Server_Error)
-            thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['vim_tenant_id'], vim['vim_tenant_name'], vim['vim_tenant_id'])
-            new_thread = vim_thread.vim_thread(myvim, task_lock, thread_name, vim['datacenter_name'],
-                                               vim.get('datacenter_tenant_id'), db=db, db_lock=db_lock)
-            new_thread.start()
-            vim_threads["running"][thread_id] = new_thread
-    except db_base_Exception as e:
-        raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
-
-
-def stop_service():
-    for thread_id,thread in vim_threads["running"].items():
-        thread.insert_task(new_task("exit", None, store=False))
-        vim_threads["deleting"][thread_id] = thread
-    vim_threads["running"] = {}
-
-
-def get_flavorlist(mydb, vnf_id, nfvo_tenant=None):
-    '''Obtain flavorList
-    return result, content:
-        <0, error_text upon error
-        nb_records, flavor_list on success
-    '''
-    WHERE_dict={}
-    WHERE_dict['vnf_id'] = vnf_id
-    if nfvo_tenant is not None:
-        WHERE_dict['nfvo_tenant_id'] = nfvo_tenant
-
-    #result, content = mydb.get_table(FROM='vms join vnfs on vms.vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
-    #result, content = mydb.get_table(FROM='vms',SELECT=('vim_flavor_id',),WHERE=WHERE_dict )
-    flavors = mydb.get_rows(FROM='vms join flavors on vms.flavor_id=flavors.uuid',SELECT=('flavor_id',),WHERE=WHERE_dict )
-    #print "get_flavor_list result:", result
-    #print "get_flavor_list content:", content
-    flavorList=[]
-    for flavor in flavors:
-        flavorList.append(flavor['flavor_id'])
-    return flavorList
-
-
-def get_imagelist(mydb, vnf_id, nfvo_tenant=None):
-    '''Obtain imageList
-    return result, content:
-        <0, error_text upon error
-        nb_records, flavor_list on success
-    '''
-    WHERE_dict={}
-    WHERE_dict['vnf_id'] = vnf_id
-    if nfvo_tenant is not None:
-        WHERE_dict['nfvo_tenant_id'] = nfvo_tenant
-
-    #result, content = mydb.get_table(FROM='vms join vnfs on vms-vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
-    images = mydb.get_rows(FROM='vms join images on vms.image_id=images.uuid',SELECT=('image_id',),WHERE=WHERE_dict )
-    imageList=[]
-    for image in images:
-        imageList.append(image['image_id'])
-    return imageList
-
-
-def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, datacenter_tenant_id=None,
-            vim_tenant=None, vim_tenant_name=None, vim_user=None, vim_passwd=None):
-    '''Obtain a dictionary of VIM (datacenter) classes with some of the input parameters
-    return dictionary with {datacenter_id: vim_class, ... }. vim_class contain:
-            'nfvo_tenant_id','datacenter_id','vim_tenant_id','vim_url','vim_url_admin','datacenter_name','type','user','passwd'
-        raise exception upon error
-    '''
-    WHERE_dict={}
-    if nfvo_tenant     is not None:  WHERE_dict['nfvo_tenant_id'] = nfvo_tenant
-    if datacenter_id   is not None:  WHERE_dict['d.uuid']  = datacenter_id
-    if datacenter_tenant_id is not None:  WHERE_dict['datacenter_tenant_id']  = datacenter_tenant_id
-    if datacenter_name is not None:  WHERE_dict['d.name']  = datacenter_name
-    if vim_tenant      is not None:  WHERE_dict['dt.vim_tenant_id']  = vim_tenant
-    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','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', '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')
-    try:
-        vims = mydb.get_rows(FROM=from_, SELECT=select_, WHERE=WHERE_dict )
-        vim_dict={}
-        for vim in vims:
-            extra={'datacenter_tenant_id': vim.get('datacenter_tenant_id')}
-            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:
-                    module = "vimconn_" + vim["type"]
-                    module_info = imp.find_module(module)
-                    vim_conn = imp.load_module(vim["type"], *module_info)
-                    vimconn_imported[vim["type"]] = vim_conn
-                except (IOError, ImportError) as e:
-                    if module_info and module_info[0]:
-                        file.close(module_info[0])
-                    raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
-                                            vim["type"], module, type(e).__name__, str(e)), HTTP_Bad_Request)
-
-            try:
-                if 'nfvo_tenant_id' in vim:
-                    thread_id = vim["datacenter_id"] + "." + vim['nfvo_tenant_id']
-                    if thread_id not in vim_persistent_info:
-                        vim_persistent_info[thread_id] = {}
-                    persistent_info = vim_persistent_info[thread_id]
-                else:
-                    persistent_info = {}
-                #if not tenant:
-                #    return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
-                vim_dict[ vim['datacenter_id'] ] = vimconn_imported[ vim["type"] ].vimconnector(
-                                uuid=vim['datacenter_id'], name=vim['datacenter_name'],
-                                tenant_id=vim.get('vim_tenant_id',vim_tenant),
-                                tenant_name=vim.get('vim_tenant_name',vim_tenant_name),
-                                url=vim['vim_url'], url_admin=vim['vim_url_admin'],
-                                user=vim.get('user',vim_user), passwd=vim.get('passwd',vim_passwd),
-                                config=extra, persistent_info=persistent_info
-                        )
-            except Exception as e:
-                raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), HTTP_Internal_Server_Error)
-        return vim_dict
-    except db_base_Exception as e:
-        raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
-
-
-def rollback(mydb,  vims, rollback_list):
-    undeleted_items=[]
-    #delete things by reverse order
-    for i in range(len(rollback_list)-1, -1, -1):
-        item = rollback_list[i]
-        if item["where"]=="vim":
-            if item["vim_id"] not in vims:
-                continue
-            vim=vims[ item["vim_id"] ]
-            try:
-                if item["what"]=="image":
-                    vim.delete_image(item["uuid"])
-                    mydb.delete_row(FROM="datacenters_images", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]})
-                elif item["what"]=="flavor":
-                    vim.delete_flavor(item["uuid"])
-                    mydb.delete_row(FROM="datacenters_flavors", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]})
-                elif item["what"]=="network":
-                    vim.delete_network(item["uuid"])
-                elif item["what"]=="vm":
-                    vim.delete_vminstance(item["uuid"])
-            except vimconn.vimconnException as e:
-                logger.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item['what'], item["uuid"], str(e))
-                undeleted_items.append("{} {} from VIM {}".format(item['what'], item["uuid"], vim["name"]))
-            except db_base_Exception as e:
-                logger.error("Error in rollback. Not possible to delete %s '%s' from DB.datacenters Message: %s", item['what'], item["uuid"], str(e))
-
-        else: # where==mano
-            try:
-                if item["what"]=="image":
-                    mydb.delete_row(FROM="images", WHERE={"uuid": item["uuid"]})
-                elif item["what"]=="flavor":
-                    mydb.delete_row(FROM="flavors", WHERE={"uuid": item["uuid"]})
-            except db_base_Exception as e:
-                logger.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item['what'], item["uuid"], str(e))
-                undeleted_items.append("{} '{}'".format(item['what'], item["uuid"]))
-    if len(undeleted_items)==0:
-        return True," Rollback successful."
-    else:
-        return False," Rollback fails to delete: " + str(undeleted_items)
-
-
-def check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1):
-    global global_config
-    #create a dictionary with vnfc-name: vnfc:interface-list  key:values pairs
-    vnfc_interfaces={}
-    for vnfc in vnf_descriptor["vnf"]["VNFC"]:
-        name_dict = {}
-        #dataplane interfaces
-        for numa in vnfc.get("numas",() ):
-            for interface in numa.get("interfaces",()):
-                if interface["name"] in name_dict:
-                    raise NfvoException(
-                        "Error at vnf:VNFC[name:'{}']:numas:interfaces:name, interface name '{}' already used in this VNFC".format(
-                            vnfc["name"], interface["name"]),
-                        HTTP_Bad_Request)
-                name_dict[ interface["name"] ] = "underlay"
-        #bridge interfaces
-        for interface in vnfc.get("bridge-ifaces",() ):
-            if interface["name"] in name_dict:
-                raise NfvoException(
-                    "Error at vnf:VNFC[name:'{}']:bridge-ifaces:name, interface name '{}' already used in this VNFC".format(
-                        vnfc["name"], interface["name"]),
-                    HTTP_Bad_Request)
-            name_dict[ interface["name"] ] = "overlay"
-        vnfc_interfaces[ vnfc["name"] ] = name_dict
-        # check bood-data info
-        if "boot-data" in vnfc:
-            # check that user-data is incompatible with users and config-files
-            if (vnfc["boot-data"].get("users") or vnfc["boot-data"].get("config-files")) and vnfc["boot-data"].get("user-data"):
-                raise NfvoException(
-                    "Error at vnf:VNFC:boot-data, fields 'users' and 'config-files' are not compatible with 'user-data'",
-                    HTTP_Bad_Request)
-
-    #check if the info in external_connections matches with the one in the vnfcs
-    name_list=[]
-    for external_connection in vnf_descriptor["vnf"].get("external-connections",() ):
-        if external_connection["name"] in name_list:
-            raise NfvoException(
-                "Error at vnf:external-connections:name, value '{}' already used as an external-connection".format(
-                    external_connection["name"]),
-                HTTP_Bad_Request)
-        name_list.append(external_connection["name"])
-        if external_connection["VNFC"] not in vnfc_interfaces:
-            raise NfvoException(
-                "Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC".format(
-                    external_connection["name"], external_connection["VNFC"]),
-                HTTP_Bad_Request)
-
-        if external_connection["local_iface_name"] not in vnfc_interfaces[ external_connection["VNFC"] ]:
-            raise NfvoException(
-                "Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC".format(
-                    external_connection["name"],
-                    external_connection["local_iface_name"]),
-                HTTP_Bad_Request )
-
-    #check if the info in internal_connections matches with the one in the vnfcs
-    name_list=[]
-    for internal_connection in vnf_descriptor["vnf"].get("internal-connections",() ):
-        if internal_connection["name"] in name_list:
-            raise NfvoException(
-                "Error at vnf:internal-connections:name, value '%s' already used as an internal-connection".format(
-                    internal_connection["name"]),
-                HTTP_Bad_Request)
-        name_list.append(internal_connection["name"])
-        #We should check that internal-connections of type "ptp" have only 2 elements
-
-        if len(internal_connection["elements"])>2 and (internal_connection.get("type") == "ptp" or internal_connection.get("type") == "e-line"):
-            raise NfvoException(
-                "Error at 'vnf:internal-connections[name:'{}']:elements', size must be 2 for a '{}' type. Consider change it to '{}' type".format(
-                    internal_connection["name"],
-                    'ptp' if vnf_descriptor_version==1 else 'e-line',
-                    'data' if vnf_descriptor_version==1 else "e-lan"),
-                HTTP_Bad_Request)
-        for port in internal_connection["elements"]:
-            vnf = port["VNFC"]
-            iface = port["local_iface_name"]
-            if vnf not in vnfc_interfaces:
-                raise NfvoException(
-                    "Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC".format(
-                        internal_connection["name"], vnf),
-                    HTTP_Bad_Request)
-            if iface not in vnfc_interfaces[ vnf ]:
-                raise NfvoException(
-                    "Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC".format(
-                        internal_connection["name"], iface),
-                    HTTP_Bad_Request)
-                return -HTTP_Bad_Request,
-            if vnf_descriptor_version==1 and "type" not in internal_connection:
-                if vnfc_interfaces[vnf][iface] == "overlay":
-                    internal_connection["type"] = "bridge"
-                else:
-                    internal_connection["type"] = "data"
-            if vnf_descriptor_version==2 and "implementation" not in internal_connection:
-                if vnfc_interfaces[vnf][iface] == "overlay":
-                    internal_connection["implementation"] = "overlay"
-                else:
-                    internal_connection["implementation"] = "underlay"
-            if (internal_connection.get("type") == "data" or internal_connection.get("type") == "ptp" or \
-                internal_connection.get("implementation") == "underlay") and vnfc_interfaces[vnf][iface] == "overlay":
-                raise NfvoException(
-                    "Error at vnf:internal-connections[name:'{}']:elements[]:{}, interface of type {} connected to an {} network".format(
-                        internal_connection["name"],
-                        iface, 'bridge' if vnf_descriptor_version==1 else 'overlay',
-                        'data' if vnf_descriptor_version==1 else 'underlay'),
-                    HTTP_Bad_Request)
-            if (internal_connection.get("type") == "bridge" or internal_connection.get("implementation") == "overlay") and \
-                vnfc_interfaces[vnf][iface] == "underlay":
-                raise NfvoException(
-                    "Error at vnf:internal-connections[name:'{}']:elements[]:{}, interface of type {} connected to an {} network".format(
-                        internal_connection["name"], iface,
-                        'data' if vnf_descriptor_version==1 else 'underlay',
-                        'bridge' if vnf_descriptor_version==1 else 'overlay'),
-                    HTTP_Bad_Request)
-
-
-def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=False, return_on_error = None):
-    #look if image exist
-    if only_create_at_vim:
-        image_mano_id = image_dict['uuid']
-        if return_on_error == None:
-            return_on_error = True
-    else:
-        if image_dict['location']:
-            images = mydb.get_rows(FROM="images", WHERE={'location':image_dict['location'], 'metadata':image_dict['metadata']})
-        else:
-            images = mydb.get_rows(FROM="images", WHERE={'universal_name':image_dict['universal_name'], 'checksum':image_dict['checksum']})
-        if len(images)>=1:
-            image_mano_id = images[0]['uuid']
-        else:
-            #create image in MANO DB
-            temp_image_dict={'name':image_dict['name'],         'description':image_dict.get('description',None),
-                            'location':image_dict['location'],  'metadata':image_dict.get('metadata',None),
-                            'universal_name':image_dict['universal_name'] , 'checksum':image_dict['checksum']
-                            }
-            #temp_image_dict['location'] = image_dict.get('new_location') if image_dict['location'] is None
-            image_mano_id = mydb.new_row('images', temp_image_dict, add_uuid=True)
-            rollback_list.append({"where":"mano", "what":"image","uuid":image_mano_id})
-    #create image at every vim
-    for vim_id,vim in vims.iteritems():
-        image_created="false"
-        #look at database
-        image_db = mydb.get_rows(FROM="datacenters_images", WHERE={'datacenter_id':vim_id, 'image_id':image_mano_id})
-        #look at VIM if this image exist
-        try:
-            if image_dict['location'] is not None:
-                image_vim_id = vim.get_image_id_from_path(image_dict['location'])
-            else:
-                filter_dict = {}
-                filter_dict['name'] = image_dict['universal_name']
-                if image_dict.get('checksum') != None:
-                    filter_dict['checksum'] = image_dict['checksum']
-                #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
-                vim_images = vim.get_image_list(filter_dict)
-                #logger.debug('>>>>>>>> VIM images: %s', str(vim_images))
-                if len(vim_images) > 1:
-                    raise vimconn.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict)), HTTP_Conflict)
-                elif len(vim_images) == 0:
-                    raise vimconn.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict)))
-                else:
-                    #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0]))
-                    image_vim_id = vim_images[0]['id']
-
-        except vimconn.vimconnNotFoundException as e:
-            #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None
-            try:
-                #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None
-                if image_dict['location']:
-                    image_vim_id = vim.new_image(image_dict)
-                    rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"image","uuid":image_vim_id})
-                    image_created="true"
-                else:
-                    #If we reach this point, then the image has image name, and optionally checksum, and could not be found
-                    raise vimconn.vimconnException(str(e))
-            except vimconn.vimconnException as e:
-                if return_on_error:
-                    logger.error("Error creating image at VIM '%s': %s", vim["name"], str(e))
-                    raise
-                image_vim_id = None
-                logger.warn("Error creating image at VIM '%s': %s", vim["name"], str(e))
-                continue
-        except vimconn.vimconnException as e:
-            if return_on_error:
-                logger.error("Error contacting VIM to know if the image exists at VIM: %s", str(e))
-                raise
-            logger.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e))
-            image_vim_id = None
-            continue
-        #if we reach here, the image has been created or existed
-        if len(image_db)==0:
-            #add new vim_id at datacenters_images
-            mydb.new_row('datacenters_images', {'datacenter_id':vim_id, 'image_id':image_mano_id, 'vim_id': image_vim_id, 'created':image_created})
-        elif image_db[0]["vim_id"]!=image_vim_id:
-            #modify existing vim_id at datacenters_images
-            mydb.update_rows('datacenters_images', UPDATE={'vim_id':image_vim_id}, WHERE={'datacenter_id':vim_id, 'image_id':image_mano_id})
-
-    return image_vim_id if only_create_at_vim else image_mano_id
-
-
-def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_vim=False, return_on_error = None):
-    temp_flavor_dict= {'disk':flavor_dict.get('disk',1),
-            'ram':flavor_dict.get('ram'),
-            'vcpus':flavor_dict.get('vcpus'),
-        }
-    if 'extended' in flavor_dict and flavor_dict['extended']==None:
-        del flavor_dict['extended']
-    if 'extended' in flavor_dict:
-        temp_flavor_dict['extended']=yaml.safe_dump(flavor_dict['extended'],default_flow_style=True,width=256)
-
-    #look if flavor exist
-    if only_create_at_vim:
-        flavor_mano_id = flavor_dict['uuid']
-        if return_on_error == None:
-            return_on_error = True
-    else:
-        flavors = mydb.get_rows(FROM="flavors", WHERE=temp_flavor_dict)
-        if len(flavors)>=1:
-            flavor_mano_id = flavors[0]['uuid']
-        else:
-            #create flavor
-            #create one by one the images of aditional disks
-            dev_image_list=[] #list of images
-            if 'extended' in flavor_dict and flavor_dict['extended']!=None:
-                dev_nb=0
-                for device in flavor_dict['extended'].get('devices',[]):
-                    if "image" not in device and "image name" not in device:
-                        continue
-                    image_dict={}
-                    image_dict['name']=device.get('image name',flavor_dict['name']+str(dev_nb)+"-img")
-                    image_dict['universal_name']=device.get('image name')
-                    image_dict['description']=flavor_dict['name']+str(dev_nb)+"-img"
-                    image_dict['location']=device.get('image')
-                    #image_dict['new_location']=vnfc.get('image location')
-                    image_dict['checksum']=device.get('image checksum')
-                    image_metadata_dict = device.get('image metadata', None)
-                    image_metadata_str = None
-                    if image_metadata_dict != None:
-                        image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
-                    image_dict['metadata']=image_metadata_str
-                    image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
-                    #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
-                    dev_image_list.append(image_id)
-                    dev_nb += 1
-            temp_flavor_dict['name'] = flavor_dict['name']
-            temp_flavor_dict['description'] = flavor_dict.get('description',None)
-            content = mydb.new_row('flavors', temp_flavor_dict, add_uuid=True)
-            flavor_mano_id= content
-            rollback_list.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id})
-    #create flavor at every vim
-    if 'uuid' in flavor_dict:
-        del flavor_dict['uuid']
-    flavor_vim_id=None
-    for vim_id,vim in vims.items():
-        flavor_created="false"
-        #look at database
-        flavor_db = mydb.get_rows(FROM="datacenters_flavors", WHERE={'datacenter_id':vim_id, 'flavor_id':flavor_mano_id})
-        #look at VIM if this flavor exist  SKIPPED
-        #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
-        #if res_vim < 0:
-        #    print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
-        #    continue
-        #elif res_vim==0:
-
-        #Create the flavor in VIM
-        #Translate images at devices from MANO id to VIM id
-        disk_list = []
-        if 'extended' in flavor_dict and flavor_dict['extended']!=None and "devices" in flavor_dict['extended']:
-            #make a copy of original devices
-            devices_original=[]
-
-            for device in flavor_dict["extended"].get("devices",[]):
-                dev={}
-                dev.update(device)
-                devices_original.append(dev)
-                if 'image' in device:
-                    del device['image']
-                if 'image metadata' in device:
-                    del device['image metadata']
-            dev_nb=0
-            for index in range(0,len(devices_original)) :
-                device=devices_original[index]
-                if "image" not in device and "image name" not in device:
-                    if 'size' in device:
-                        disk_list.append({'size': device.get('size', default_volume_size)})
-                    continue
-                image_dict={}
-                image_dict['name']=device.get('image name',flavor_dict['name']+str(dev_nb)+"-img")
-                image_dict['universal_name']=device.get('image name')
-                image_dict['description']=flavor_dict['name']+str(dev_nb)+"-img"
-                image_dict['location']=device.get('image')
-                #image_dict['new_location']=device.get('image location')
-                image_dict['checksum']=device.get('image checksum')
-                image_metadata_dict = device.get('image metadata', None)
-                image_metadata_str = None
-                if image_metadata_dict != None:
-                    image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
-                image_dict['metadata']=image_metadata_str
-                image_mano_id=create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=False, return_on_error=return_on_error )
-                image_dict["uuid"]=image_mano_id
-                image_vim_id=create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=True, return_on_error=return_on_error)
-
-                #save disk information (image must be based on and size
-                disk_list.append({'image_id': image_vim_id, 'size': device.get('size', default_volume_size)})
-
-                flavor_dict["extended"]["devices"][index]['imageRef']=image_vim_id
-                dev_nb += 1
-        if len(flavor_db)>0:
-            #check that this vim_id exist in VIM, if not create
-            flavor_vim_id=flavor_db[0]["vim_id"]
-            try:
-                vim.get_flavor(flavor_vim_id)
-                continue #flavor exist
-            except vimconn.vimconnException:
-                pass
-        #create flavor at vim
-        logger.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim["name"])
-        try:
-            flavor_vim_id = None
-            flavor_vim_id=vim.get_flavor_id_from_data(flavor_dict)
-            flavor_create="false"
-        except vimconn.vimconnException as e:
-            pass
-        try:
-            if not flavor_vim_id:
-                flavor_vim_id = vim.new_flavor(flavor_dict)
-                rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"flavor","uuid":flavor_vim_id})
-                flavor_created="true"
-        except vimconn.vimconnException as e:
-            if return_on_error:
-                logger.error("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
-                raise
-            logger.warn("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
-            flavor_vim_id = None
-            continue
-        #if reach here the flavor has been create or exist
-        if len(flavor_db)==0:
-            #add new vim_id at datacenters_flavors
-            extended_devices_yaml = None
-            if len(disk_list) > 0:
-                extended_devices = dict()
-                extended_devices['disks'] = disk_list
-                extended_devices_yaml = yaml.safe_dump(extended_devices,default_flow_style=True,width=256)
-            mydb.new_row('datacenters_flavors',
-                        {'datacenter_id':vim_id, 'flavor_id':flavor_mano_id, 'vim_id': flavor_vim_id,
-                        'created':flavor_created,'extended': extended_devices_yaml})
-        elif flavor_db[0]["vim_id"]!=flavor_vim_id:
-            #modify existing vim_id at datacenters_flavors
-            mydb.update_rows('datacenters_flavors', UPDATE={'vim_id':flavor_vim_id}, WHERE={'datacenter_id':vim_id, 'flavor_id':flavor_mano_id})
-
-    return flavor_vim_id if only_create_at_vim else flavor_mano_id
-
-
-def new_vnf(mydb, tenant_id, vnf_descriptor):
-    global global_config
-
-    # Step 1. Check the VNF descriptor
-    check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1)
-    # Step 2. Check tenant exist
-    vims = {}
-    if tenant_id != "any":
-        check_tenant(mydb, tenant_id)
-        if "tenant_id" in vnf_descriptor["vnf"]:
-            if vnf_descriptor["vnf"]["tenant_id"] != tenant_id:
-                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor["vnf"]["tenant_id"], tenant_id),
-                                    HTTP_Unauthorized)
-        else:
-            vnf_descriptor['vnf']['tenant_id'] = tenant_id
-        # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
-        if global_config["auto_push_VNF_to_VIMs"]:
-            vims = get_vim(mydb, tenant_id)
-
-    # Step 4. Review the descriptor and add missing  fields
-    #print vnf_descriptor
-    #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
-    vnf_name = vnf_descriptor['vnf']['name']
-    vnf_descriptor['vnf']['description'] = vnf_descriptor['vnf'].get("description", vnf_name)
-    if "physical" in vnf_descriptor['vnf']:
-        del vnf_descriptor['vnf']['physical']
-    #print vnf_descriptor
-
-    # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
-    logger.debug('BEGIN creation of VNF "%s"' % vnf_name)
-    logger.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name,len(vnf_descriptor['vnf']['VNFC'])))
-
-    #For each VNFC, we add it to the VNFCDict and we  create a flavor.
-    VNFCDict = {}     # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
-    rollback_list = []    # It will contain the new images created in mano. It is used for rollback
-    try:
-        logger.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
-        for vnfc in vnf_descriptor['vnf']['VNFC']:
-            VNFCitem={}
-            VNFCitem["name"] = vnfc['name']
-            VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name))
-
-            #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
-
-            myflavorDict = {}
-            myflavorDict["name"] = vnfc['name']+"-flv"   #Maybe we could rename the flavor by using the field "image name" if exists
-            myflavorDict["description"] = VNFCitem["description"]
-            myflavorDict["ram"] = vnfc.get("ram", 0)
-            myflavorDict["vcpus"] = vnfc.get("vcpus", 0)
-            myflavorDict["disk"] = vnfc.get("disk", 1)
-            myflavorDict["extended"] = {}
-
-            devices = vnfc.get("devices")
-            if devices != None:
-                myflavorDict["extended"]["devices"] = devices
-
-            # TODO:
-            # Mapping from processor models to rankings should be available somehow in the NFVO. They could be taken from VIM or directly from a new database table
-            # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
-
-            # Previous code has been commented
-            #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
-            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 200
-            #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
-            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 300
-            #else:
-            #    result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
-            #    if result2:
-            #        print "Error creating flavor: unknown processor model. Rollback successful."
-            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
-            #    else:
-            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
-            myflavorDict['extended']['processor_ranking'] = 100  #Hardcoded value, while we decide when the mapping is done
-
-            if 'numas' in vnfc and len(vnfc['numas'])>0:
-                myflavorDict['extended']['numas'] = vnfc['numas']
-
-            #print myflavorDict
-
-            # Step 6.2 New flavors are created in the VIM
-            flavor_id = create_or_use_flavor(mydb, vims, myflavorDict, rollback_list)
-
-            #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
-            VNFCitem["flavor_id"] = flavor_id
-            VNFCDict[vnfc['name']] = VNFCitem
-
-        logger.debug("Creating new images in the VIM for each VNFC")
-        # Step 6.3 New images are created in the VIM
-        #For each VNFC, we must create the appropriate image.
-        #This "for" loop might be integrated with the previous one
-        #In case this integration is made, the VNFCDict might become a VNFClist.
-        for vnfc in vnf_descriptor['vnf']['VNFC']:
-            #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
-            image_dict={}
-            image_dict['name']=vnfc.get('image name',vnf_name+"-"+vnfc['name']+"-img")
-            image_dict['universal_name']=vnfc.get('image name')
-            image_dict['description']=vnfc.get('image name', VNFCDict[vnfc['name']]['description'])
-            image_dict['location']=vnfc.get('VNFC image')
-            #image_dict['new_location']=vnfc.get('image location')
-            image_dict['checksum']=vnfc.get('image checksum')
-            image_metadata_dict = vnfc.get('image metadata', None)
-            image_metadata_str = None
-            if image_metadata_dict is not None:
-                image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
-            image_dict['metadata']=image_metadata_str
-            #print "create_or_use_image", mydb, vims, image_dict, rollback_list
-            image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
-            #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
-            VNFCDict[vnfc['name']]["image_id"] = image_id
-            VNFCDict[vnfc['name']]["image_path"] = vnfc.get('VNFC image')
-            if vnfc.get("boot-data"):
-                VNFCDict[vnfc['name']]["boot_data"] = yaml.safe_dump(vnfc["boot-data"], default_flow_style=True, width=256)
-
-
-        # Step 7. Storing the VNF descriptor in the repository
-        if "descriptor" not in vnf_descriptor["vnf"]:
-            vnf_descriptor["vnf"]["descriptor"] = yaml.safe_dump(vnf_descriptor, indent=4, explicit_start=True, default_flow_style=False)
-
-        # Step 8. Adding the VNF to the NFVO DB
-        vnf_id = mydb.new_vnf_as_a_whole(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
-        return vnf_id
-    except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
-        _, message = rollback(mydb, vims, rollback_list)
-        if isinstance(e, db_base_Exception):
-            error_text = "Exception at database"
-        elif isinstance(e, KeyError):
-            error_text = "KeyError exception "
-            e.http_code = HTTP_Internal_Server_Error
-        else:
-            error_text = "Exception at VIM"
-        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
-        #logger.error("start_scenario %s", error_text)
-        raise NfvoException(error_text, e.http_code)
-
-
-def new_vnf_v02(mydb, tenant_id, vnf_descriptor):
-    global global_config
-
-    # Step 1. Check the VNF descriptor
-    check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=2)
-    # Step 2. Check tenant exist
-    vims = {}
-    if tenant_id != "any":
-        check_tenant(mydb, tenant_id)
-        if "tenant_id" in vnf_descriptor["vnf"]:
-            if vnf_descriptor["vnf"]["tenant_id"] != tenant_id:
-                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor["vnf"]["tenant_id"], tenant_id),
-                                    HTTP_Unauthorized)
-        else:
-            vnf_descriptor['vnf']['tenant_id'] = tenant_id
-        # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
-        if global_config["auto_push_VNF_to_VIMs"]:
-            vims = get_vim(mydb, tenant_id)
-
-    # Step 4. Review the descriptor and add missing  fields
-    #print vnf_descriptor
-    #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
-    vnf_name = vnf_descriptor['vnf']['name']
-    vnf_descriptor['vnf']['description'] = vnf_descriptor['vnf'].get("description", vnf_name)
-    if "physical" in vnf_descriptor['vnf']:
-        del vnf_descriptor['vnf']['physical']
-    #print vnf_descriptor
-
-    # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
-    logger.debug('BEGIN creation of VNF "%s"' % vnf_name)
-    logger.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name,len(vnf_descriptor['vnf']['VNFC'])))
-
-    #For each VNFC, we add it to the VNFCDict and we  create a flavor.
-    VNFCDict = {}     # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
-    rollback_list = []    # It will contain the new images created in mano. It is used for rollback
-    try:
-        logger.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
-        for vnfc in vnf_descriptor['vnf']['VNFC']:
-            VNFCitem={}
-            VNFCitem["name"] = vnfc['name']
-            VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name))
-
-            #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
-
-            myflavorDict = {}
-            myflavorDict["name"] = vnfc['name']+"-flv"   #Maybe we could rename the flavor by using the field "image name" if exists
-            myflavorDict["description"] = VNFCitem["description"]
-            myflavorDict["ram"] = vnfc.get("ram", 0)
-            myflavorDict["vcpus"] = vnfc.get("vcpus", 0)
-            myflavorDict["disk"] = vnfc.get("disk", 1)
-            myflavorDict["extended"] = {}
-
-            devices = vnfc.get("devices")
-            if devices != None:
-                myflavorDict["extended"]["devices"] = devices
-
-            # TODO:
-            # Mapping from processor models to rankings should be available somehow in the NFVO. They could be taken from VIM or directly from a new database table
-            # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
-
-            # Previous code has been commented
-            #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
-            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 200
-            #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
-            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 300
-            #else:
-            #    result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
-            #    if result2:
-            #        print "Error creating flavor: unknown processor model. Rollback successful."
-            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
-            #    else:
-            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
-            myflavorDict['extended']['processor_ranking'] = 100  #Hardcoded value, while we decide when the mapping is done
-
-            if 'numas' in vnfc and len(vnfc['numas'])>0:
-                myflavorDict['extended']['numas'] = vnfc['numas']
-
-            #print myflavorDict
-
-            # Step 6.2 New flavors are created in the VIM
-            flavor_id = create_or_use_flavor(mydb, vims, myflavorDict, rollback_list)
-
-            #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
-            VNFCitem["flavor_id"] = flavor_id
-            VNFCDict[vnfc['name']] = VNFCitem
-
-        logger.debug("Creating new images in the VIM for each VNFC")
-        # Step 6.3 New images are created in the VIM
-        #For each VNFC, we must create the appropriate image.
-        #This "for" loop might be integrated with the previous one
-        #In case this integration is made, the VNFCDict might become a VNFClist.
-        for vnfc in vnf_descriptor['vnf']['VNFC']:
-            #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
-            image_dict={}
-            image_dict['name']=vnfc.get('image name',vnf_name+"-"+vnfc['name']+"-img")
-            image_dict['universal_name']=vnfc.get('image name')
-            image_dict['description']=vnfc.get('image name', VNFCDict[vnfc['name']]['description'])
-            image_dict['location']=vnfc.get('VNFC image')
-            #image_dict['new_location']=vnfc.get('image location')
-            image_dict['checksum']=vnfc.get('image checksum')
-            image_metadata_dict = vnfc.get('image metadata', None)
-            image_metadata_str = None
-            if image_metadata_dict is not None:
-                image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
-            image_dict['metadata']=image_metadata_str
-            #print "create_or_use_image", mydb, vims, image_dict, rollback_list
-            image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
-            #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
-            VNFCDict[vnfc['name']]["image_id"] = image_id
-            VNFCDict[vnfc['name']]["image_path"] = vnfc.get('VNFC image')
-            if vnfc.get("boot-data"):
-                VNFCDict[vnfc['name']]["boot_data"] = yaml.safe_dump(vnfc["boot-data"], default_flow_style=True, width=256)
-
-        # Step 7. Storing the VNF descriptor in the repository
-        if "descriptor" not in vnf_descriptor["vnf"]:
-            vnf_descriptor["vnf"]["descriptor"] = yaml.safe_dump(vnf_descriptor, indent=4, explicit_start=True, default_flow_style=False)
-
-        # Step 8. Adding the VNF to the NFVO DB
-        vnf_id = mydb.new_vnf_as_a_whole2(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
-        return vnf_id
-    except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
-        _, message = rollback(mydb, vims, rollback_list)
-        if isinstance(e, db_base_Exception):
-            error_text = "Exception at database"
-        elif isinstance(e, KeyError):
-            error_text = "KeyError exception "
-            e.http_code = HTTP_Internal_Server_Error
-        else:
-            error_text = "Exception at VIM"
-        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
-        #logger.error("start_scenario %s", error_text)
-        raise NfvoException(error_text, e.http_code)
-
-
-def get_vnf_id(mydb, tenant_id, vnf_id):
-    #check valid tenant_id
-    check_tenant(mydb, tenant_id)
-    #obtain data
-    where_or = {}
-    if tenant_id != "any":
-        where_or["tenant_id"] = tenant_id
-        where_or["public"] = True
-    vnf = mydb.get_table_by_uuid_name('vnfs', vnf_id, "VNF", WHERE_OR=where_or, WHERE_AND_OR="AND")
-
-    vnf_id=vnf["uuid"]
-    filter_keys = ('uuid','name','description','public', "tenant_id", "created_at")
-    filtered_content = dict( (k,v) for k,v in vnf.iteritems() if k in filter_keys )
-    #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
-    data={'vnf' : filtered_content}
-    #GET VM
-    content = mydb.get_rows(FROM='vnfs join vms on vnfs.uuid=vms.vnf_id',
-            SELECT=('vms.uuid as uuid','vms.name as name', 'vms.description as description', 'boot_data'),
-            WHERE={'vnfs.uuid': vnf_id} )
-    if len(content)==0:
-        raise NfvoException("vnf '{}' not found".format(vnf_id), HTTP_Not_Found)
-    # change boot_data into boot-data
-    for vm in content:
-        if vm.get("boot_data"):
-            vm["boot-data"] = yaml.safe_load(vm["boot_data"])
-            del vm["boot_data"]
-
-    data['vnf']['VNFC'] = content
-    #TODO: GET all the information from a VNFC and include it in the output.
-
-    #GET NET
-    content = mydb.get_rows(FROM='vnfs join nets on vnfs.uuid=nets.vnf_id',
-                                    SELECT=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
-                                    WHERE={'vnfs.uuid': vnf_id} )
-    data['vnf']['nets'] = content
-
-    #GET ip-profile for each net
-    for net in data['vnf']['nets']:
-        ipprofiles = mydb.get_rows(FROM='ip_profiles',
-                                   SELECT=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
-                                   WHERE={'net_id': net["uuid"]} )
-        if len(ipprofiles)==1:
-            net["ip_profile"] = ipprofiles[0]
-        elif len(ipprofiles)>1:
-            raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net['uuid']), HTTP_Bad_Request)
-
-
-    #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
-
-    #GET External Interfaces
-    content = mydb.get_rows(FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
-                                    SELECT=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
-                                            'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
-                                    WHERE={'vnfs.uuid': vnf_id},
-                                    WHERE_NOT={'interfaces.external_name': None} )
-    #print content
-    data['vnf']['external-connections'] = content
-
-    return data
-
-
-def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None):
-    # Check tenant exist
-    if tenant_id != "any":
-        check_tenant(mydb, tenant_id)
-        # Get the URL of the VIM from the nfvo_tenant and the datacenter
-        vims = get_vim(mydb, tenant_id)
-    else:
-        vims={}
-
-    # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
-    where_or = {}
-    if tenant_id != "any":
-        where_or["tenant_id"] = tenant_id
-        where_or["public"] = True
-    vnf = mydb.get_table_by_uuid_name('vnfs', vnf_id, "VNF", WHERE_OR=where_or, WHERE_AND_OR="AND")
-    vnf_id = vnf["uuid"]
-
-    # "Getting the list of flavors and tenants of the VNF"
-    flavorList = get_flavorlist(mydb, vnf_id)
-    if len(flavorList)==0:
-        logger.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id)
-
-    imageList = get_imagelist(mydb, vnf_id)
-    if len(imageList)==0:
-        logger.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id)
-
-    deleted = mydb.delete_row_by_id('vnfs', vnf_id)
-    if deleted == 0:
-        raise NfvoException("vnf '{}' not found".format(vnf_id), HTTP_Not_Found)
-
-    undeletedItems = []
-    for flavor in flavorList:
-        #check if flavor is used by other vnf
-        try:
-            c = mydb.get_rows(FROM='vms', WHERE={'flavor_id':flavor} )
-            if len(c) > 0:
-                logger.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor)
-                continue
-            #flavor not used, must be deleted
-            #delelte at VIM
-            c = mydb.get_rows(FROM='datacenters_flavors', WHERE={'flavor_id':flavor})
-            for flavor_vim in c:
-                if flavor_vim["datacenter_id"] not in vims:
-                    continue
-                if flavor_vim['created']=='false': #skip this flavor because not created by openmano
-                    continue
-                myvim=vims[ flavor_vim["datacenter_id"] ]
-                try:
-                    myvim.delete_flavor(flavor_vim["vim_id"])
-                except vimconn.vimconnNotFoundException as e:
-                    logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"], flavor_vim["datacenter_id"] )
-                except vimconn.vimconnException as e:
-                    logger.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
-                            flavor_vim["vim_id"], flavor_vim["datacenter_id"], type(e).__name__, str(e))
-                    undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"], flavor_vim["datacenter_id"] ))
-            #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
-            mydb.delete_row_by_id('flavors', flavor)
-        except db_base_Exception as e:
-            logger.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor, str(e))
-            undeletedItems.append("flavor %s" % flavor)
-
-
-    for image in imageList:
-        try:
-            #check if image is used by other vnf
-            c = mydb.get_rows(FROM='vms', WHERE={'image_id':image} )
-            if len(c) > 0:
-                logger.debug("Image '%s' not deleted because it is being used by another VNF", image)
-                continue
-            #image not used, must be deleted
-            #delelte at VIM
-            c = mydb.get_rows(FROM='datacenters_images', WHERE={'image_id':image})
-            for image_vim in c:
-                if image_vim["datacenter_id"] not in vims:
-                    continue
-                if image_vim['created']=='false': #skip this image because not created by openmano
-                    continue
-                myvim=vims[ image_vim["datacenter_id"] ]
-                try:
-                    myvim.delete_image(image_vim["vim_id"])
-                except vimconn.vimconnNotFoundException as e:
-                    logger.warn("VIM image %s not exist at datacenter %s", image_vim["vim_id"], image_vim["datacenter_id"] )
-                except vimconn.vimconnException as e:
-                    logger.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
-                            image_vim["vim_id"], image_vim["datacenter_id"], type(e).__name__, str(e))
-                    undeletedItems.append("image {} from VIM {}".format(image_vim["vim_id"], image_vim["datacenter_id"] ))
-            #delete image from Database, using table images and with cascade foreign key also at datacenters_images
-            mydb.delete_row_by_id('images', image)
-        except db_base_Exception as e:
-            logger.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image, str(e))
-            undeletedItems.append("image %s" % image)
-
-    return vnf_id + " " + vnf["name"]
-    #if undeletedItems:
-    #    return "delete_vnf. Undeleted: %s" %(undeletedItems)
-
-
-def get_hosts_info(mydb, nfvo_tenant_id, datacenter_name=None):
-    result, vims = get_vim(mydb, nfvo_tenant_id, None, datacenter_name)
-    if result < 0:
-        return result, vims
-    elif result == 0:
-        return -HTTP_Not_Found, "datacenter '%s' not found" % datacenter_name
-    myvim = vims.values()[0]
-    result,servers =  myvim.get_hosts_info()
-    if result < 0:
-        return result, servers
-    topology = {'name':myvim['name'] , 'servers': servers}
-    return result, topology
-
-
-def get_hosts(mydb, nfvo_tenant_id):
-    vims = get_vim(mydb, nfvo_tenant_id)
-    if len(vims) == 0:
-        raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id)), HTTP_Not_Found)
-    elif len(vims)>1:
-        #print "nfvo.datacenter_action() error. Several datacenters found"
-        raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
-    myvim = vims.values()[0]
-    try:
-        hosts =  myvim.get_hosts()
-        logger.debug('VIM hosts response: '+ yaml.safe_dump(hosts, indent=4, default_flow_style=False))
-
-        datacenter = {'Datacenters': [ {'name':myvim['name'],'servers':[]} ] }
-        for host in hosts:
-            server={'name':host['name'], 'vms':[]}
-            for vm in host['instances']:
-                #get internal name and model
-                try:
-                    c = mydb.get_rows(SELECT=('name',), FROM='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
-                        WHERE={'vim_vm_id':vm['id']} )
-                    if len(c) == 0:
-                        logger.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm['id']))
-                        continue
-                    server['vms'].append( {'name':vm['name'] , 'model':c[0]['name']} )
-
-                except db_base_Exception as e:
-                    logger.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm['id'], str(e)))
-            datacenter['Datacenters'][0]['servers'].append(server)
-        #return -400, "en construccion"
-
-        #print 'datacenters '+ json.dumps(datacenter, indent=4)
-        return datacenter
-    except vimconn.vimconnException as e:
-        raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e)), e.http_code)
-
-
-def new_scenario(mydb, tenant_id, topo):
-
-#    result, vims = get_vim(mydb, tenant_id)
-#    if result < 0:
-#        return result, vims
-#1: parse input
-    if tenant_id != "any":
-        check_tenant(mydb, tenant_id)
-        if "tenant_id" in topo:
-            if topo["tenant_id"] != tenant_id:
-                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo["tenant_id"], tenant_id),
-                                    HTTP_Unauthorized)
-    else:
-        tenant_id=None
-
-#1.1: get VNFs and external_networks (other_nets).
-    vnfs={}
-    other_nets={}  #external_networks, bridge_networks and data_networkds
-    nodes = topo['topology']['nodes']
-    for k in nodes.keys():
-        if nodes[k]['type'] == 'VNF':
-            vnfs[k] = nodes[k]
-            vnfs[k]['ifaces'] = {}
-        elif nodes[k]['type'] == 'other_network' or nodes[k]['type'] == 'external_network':
-            other_nets[k] = nodes[k]
-            other_nets[k]['external']=True
-        elif nodes[k]['type'] == 'network':
-            other_nets[k] = nodes[k]
-            other_nets[k]['external']=False
-
-
-#1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
-    for name,vnf in vnfs.items():
-        where={}
-        where_or={"tenant_id": tenant_id, 'public': "true"}
-        error_text = ""
-        error_pos = "'topology':'nodes':'" + name + "'"
-        if 'vnf_id' in vnf:
-            error_text += " 'vnf_id' " +  vnf['vnf_id']
-            where['uuid'] = vnf['vnf_id']
-        if 'VNF model' in vnf:
-            error_text += " 'VNF model' " +  vnf['VNF model']
-            where['name'] = vnf['VNF model']
-        if len(where) == 0:
-            raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos, HTTP_Bad_Request)
-
-        vnf_db = mydb.get_rows(SELECT=('uuid','name','description'),
-                               FROM='vnfs',
-                               WHERE=where,
-                               WHERE_OR=where_or,
-                               WHERE_AND_OR="AND")
-        if len(vnf_db)==0:
-            raise NfvoException("unknown" + error_text + " at " + error_pos, HTTP_Not_Found)
-        elif len(vnf_db)>1:
-            raise NfvoException("more than one" + error_text + " at " + error_pos + " Concrete with 'vnf_id'", HTTP_Conflict)
-        vnf['uuid']=vnf_db[0]['uuid']
-        vnf['description']=vnf_db[0]['description']
-        #get external interfaces
-        ext_ifaces = mydb.get_rows(SELECT=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
-            FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
-            WHERE={'vnfs.uuid':vnf['uuid']}, WHERE_NOT={'external_name':None} )
-        for ext_iface in ext_ifaces:
-            vnf['ifaces'][ ext_iface['name'] ] = {'uuid':ext_iface['iface_uuid'], 'type':ext_iface['type']}
-
-#1.4 get list of connections
-    conections = topo['topology']['connections']
-    conections_list = []
-    conections_list_name = []
-    for k in conections.keys():
-        if type(conections[k]['nodes'])==dict: #dict with node:iface pairs
-            ifaces_list = conections[k]['nodes'].items()
-        elif type(conections[k]['nodes'])==list: #list with dictionary
-            ifaces_list=[]
-            conection_pair_list = map(lambda x: x.items(), conections[k]['nodes'] )
-            for k2 in conection_pair_list:
-                ifaces_list += k2
-
-        con_type = conections[k].get("type", "link")
-        if con_type != "link":
-            if k in other_nets:
-                raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k)), HTTP_Bad_Request)
-            other_nets[k] = {'external': False}
-            if conections[k].get("graph"):
-                other_nets[k]["graph"] =   conections[k]["graph"]
-            ifaces_list.append( (k, None) )
-
-
-        if con_type == "external_network":
-            other_nets[k]['external'] = True
-            if conections[k].get("model"):
-                other_nets[k]["model"] =   conections[k]["model"]
-            else:
-                other_nets[k]["model"] =   k
-        if con_type == "dataplane_net" or con_type == "bridge_net":
-            other_nets[k]["model"] = con_type
-
-        conections_list_name.append(k)
-        conections_list.append(set(ifaces_list)) #from list to set to operate as a set (this conversion removes elements that are repeated in a list)
-        #print set(ifaces_list)
-    #check valid VNF and iface names
-        for iface in ifaces_list:
-            if iface[0] not in vnfs and iface[0] not in other_nets :
-                raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
-                                                                                        str(k), iface[0]), HTTP_Not_Found)
-            if iface[0] in vnfs and iface[1] not in vnfs[ iface[0] ]['ifaces']:
-                raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
-                                                                                        str(k), iface[0], iface[1]), HTTP_Not_Found)
-
-#1.5 unify connections from the pair list to a consolidated list
-    index=0
-    while index < len(conections_list):
-        index2 = index+1
-        while index2 < len(conections_list):
-            if len(conections_list[index] & conections_list[index2])>0: #common interface, join nets
-                conections_list[index] |= conections_list[index2]
-                del conections_list[index2]
-                del conections_list_name[index2]
-            else:
-                index2 += 1
-        conections_list[index] = list(conections_list[index])  # from set to list again
-        index += 1
-    #for k in conections_list:
-    #    print k
-
-
-
-#1.6 Delete non external nets
-#    for k in other_nets.keys():
-#        if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
-#            for con in conections_list:
-#                delete_indexes=[]
-#                for index in range(0,len(con)):
-#                    if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
-#                for index in delete_indexes:
-#                    del con[index]
-#            del other_nets[k]
-#1.7: Check external_ports are present at database table datacenter_nets
-    for k,net in other_nets.items():
-        error_pos = "'topology':'nodes':'" + k + "'"
-        if net['external']==False:
-            if 'name' not in net:
-                net['name']=k
-            if 'model' not in net:
-                raise NfvoException("needed a 'model' at " + error_pos, HTTP_Bad_Request)
-            if net['model']=='bridge_net':
-                net['type']='bridge';
-            elif net['model']=='dataplane_net':
-                net['type']='data';
-            else:
-                raise NfvoException("unknown 'model' '"+ net['model'] +"' at " + error_pos, HTTP_Not_Found)
-        else: #external
-#IF we do not want to check that external network exist at datacenter
-            pass
-#ELSE
-#             error_text = ""
-#             WHERE_={}
-#             if 'net_id' in net:
-#                 error_text += " 'net_id' " +  net['net_id']
-#                 WHERE_['uuid'] = net['net_id']
-#             if 'model' in net:
-#                 error_text += " 'model' " +  net['model']
-#                 WHERE_['name'] = net['model']
-#             if len(WHERE_) == 0:
-#                 return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
-#             r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
-#                 FROM='datacenter_nets', WHERE=WHERE_ )
-#             if r<0:
-#                 print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
-#             elif r==0:
-#                 print "nfvo.new_scenario Error" +error_text+ " is not present at database"
-#                 return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
-#             elif r>1:
-#                 print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
-#                 return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
-#             other_nets[k].update(net_db[0])
-#ENDIF
-    net_list={}
-    net_nb=0  #Number of nets
-    for con in conections_list:
-        #check if this is connected to a external net
-        other_net_index=-1
-        #print
-        #print "con", con
-        for index in range(0,len(con)):
-            #check if this is connected to a external net
-            for net_key in other_nets.keys():
-                if con[index][0]==net_key:
-                    if other_net_index>=0:
-                        error_text="There is some interface connected both to net '%s' and net '%s'" % (con[other_net_index][0], net_key)
-                        #print "nfvo.new_scenario " + error_text
-                        raise NfvoException(error_text, HTTP_Bad_Request)
-                    else:
-                        other_net_index = index
-                        net_target = net_key
-                    break
-        #print "other_net_index", other_net_index
-        try:
-            if other_net_index>=0:
-                del con[other_net_index]
-#IF we do not want to check that external network exist at datacenter
-                if other_nets[net_target]['external'] :
-                    if "name" not in other_nets[net_target]:
-                        other_nets[net_target]['name'] =  other_nets[net_target]['model']
-                    if other_nets[net_target]["type"] == "external_network":
-                        if vnfs[ con[0][0] ]['ifaces'][ con[0][1] ]["type"] == "data":
-                            other_nets[net_target]["type"] =  "data"
-                        else:
-                            other_nets[net_target]["type"] =  "bridge"
-#ELSE
-#                 if other_nets[net_target]['external'] :
-#                     type_='data' if len(con)>1 else 'ptp'  #an external net is connected to a external port, so it is ptp if only one connection is done to this net
-#                     if type_=='data' and other_nets[net_target]['type']=="ptp":
-#                         error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
-#                         print "nfvo.new_scenario " + error_text
-#                         return -HTTP_Bad_Request, error_text
-#ENDIF
-                for iface in con:
-                    vnfs[ iface[0] ]['ifaces'][ iface[1] ]['net_key'] = net_target
-            else:
-                #create a net
-                net_type_bridge=False
-                net_type_data=False
-                net_target = "__-__net"+str(net_nb)
-                net_list[net_target] = {'name': conections_list_name[net_nb],  #"net-"+str(net_nb),
-                    'description':"net-%s in scenario %s" %(net_nb,topo['name']),
-                    'external':False}
-                for iface in con:
-                    vnfs[ iface[0] ]['ifaces'][ iface[1] ]['net_key'] = net_target
-                    iface_type = vnfs[ iface[0] ]['ifaces'][ iface[1] ]['type']
-                    if iface_type=='mgmt' or iface_type=='bridge':
-                        net_type_bridge = True
-                    else:
-                        net_type_data = True
-                if net_type_bridge and net_type_data:
-                    error_text = "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface[0], iface[1])
-                    #print "nfvo.new_scenario " + error_text
-                    raise NfvoException(error_text, HTTP_Bad_Request)
-                elif net_type_bridge:
-                    type_='bridge'
-                else:
-                    type_='data' if len(con)>2 else 'ptp'
-                net_list[net_target]['type'] = type_
-                net_nb+=1
-        except Exception:
-            error_text = "Error connection node %s : %s does not match any VNF or interface" % (iface[0], iface[1])
-            #print "nfvo.new_scenario " + error_text
-            #raise e
-            raise NfvoException(error_text, HTTP_Bad_Request)
-
-#1.8: Connect to management net all not already connected interfaces of type 'mgmt'
-    #1.8.1 obtain management net
-    mgmt_net = mydb.get_rows(SELECT=('uuid','name','description','type','shared'),
-        FROM='datacenter_nets', WHERE={'name':'mgmt'} )
-    #1.8.2 check all interfaces from all vnfs
-    if len(mgmt_net)>0:
-        add_mgmt_net = False
-        for vnf in vnfs.values():
-            for iface in vnf['ifaces'].values():
-                if iface['type']=='mgmt' and 'net_key' not in iface:
-                    #iface not connected
-                    iface['net_key'] = 'mgmt'
-                    add_mgmt_net = True
-        if add_mgmt_net and 'mgmt' not in net_list:
-            net_list['mgmt']=mgmt_net[0]
-            net_list['mgmt']['external']=True
-            net_list['mgmt']['graph']={'visible':False}
-
-    net_list.update(other_nets)
-    #print
-    #print 'net_list', net_list
-    #print
-    #print 'vnfs', vnfs
-    #print
-
-#2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
-    c = mydb.new_scenario( { 'vnfs':vnfs, 'nets':net_list,
-        'tenant_id':tenant_id, 'name':topo['name'],
-         'description':topo.get('description',topo['name']),
-         'public': topo.get('public', False)
-         })
-
-    return c
-
-
-def new_scenario_v02(mydb, tenant_id, scenario_dict, version):
-    """ This creates a new scenario for version 0.2 and 0.3"""
-    scenario = scenario_dict["scenario"]
-    if tenant_id != "any":
-        check_tenant(mydb, tenant_id)
-        if "tenant_id" in scenario:
-            if scenario["tenant_id"] != tenant_id:
-                # print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
-                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
-                                                    scenario["tenant_id"], tenant_id), HTTP_Unauthorized)
-    else:
-        tenant_id=None
-
-    # 1: Check that VNF are present at database table vnfs and update content into scenario dict
-    for name,vnf in scenario["vnfs"].iteritems():
-        where={}
-        where_or={"tenant_id": tenant_id, 'public': "true"}
-        error_text = ""
-        error_pos = "'scenario':'vnfs':'" + name + "'"
-        if 'vnf_id' in vnf:
-            error_text += " 'vnf_id' " + vnf['vnf_id']
-            where['uuid'] = vnf['vnf_id']
-        if 'vnf_name' in vnf:
-            error_text += " 'vnf_name' " + vnf['vnf_name']
-            where['name'] = vnf['vnf_name']
-        if len(where) == 0:
-            raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos, HTTP_Bad_Request)
-        vnf_db = mydb.get_rows(SELECT=('uuid', 'name', 'description'),
-                               FROM='vnfs',
-                               WHERE=where,
-                               WHERE_OR=where_or,
-                               WHERE_AND_OR="AND")
-        if len(vnf_db) == 0:
-            raise NfvoException("Unknown" + error_text + " at " + error_pos, HTTP_Not_Found)
-        elif len(vnf_db) > 1:
-            raise NfvoException("More than one" + error_text + " at " + error_pos + " Concrete with 'vnf_id'", HTTP_Conflict)
-        vnf['uuid'] = vnf_db[0]['uuid']
-        vnf['description'] = vnf_db[0]['description']
-        vnf['ifaces'] = {}
-        # get external interfaces
-        ext_ifaces = mydb.get_rows(SELECT=('external_name as name', 'i.uuid as iface_uuid', 'i.type as type'),
-                                   FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
-                                   WHERE={'vnfs.uuid':vnf['uuid']}, WHERE_NOT={'external_name': None} )
-        for ext_iface in ext_ifaces:
-            vnf['ifaces'][ ext_iface['name'] ] = {'uuid':ext_iface['iface_uuid'], 'type': ext_iface['type']}
-        # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
-
-    # 2: Insert net_key and ip_address at every vnf interface
-    for net_name, net in scenario["networks"].items():
-        net_type_bridge = False
-        net_type_data = False
-        for iface_dict in net["interfaces"]:
-            if version == "0.2":
-                temp_dict = iface_dict
-                ip_address = None
-            elif version == "0.3":
-                temp_dict = {iface_dict["vnf"] : iface_dict["vnf_interface"]}
-                ip_address = iface_dict.get('ip_address', None)
-            for vnf, iface in temp_dict.items():
-                if vnf not in scenario["vnfs"]:
-                    error_text = "Error at 'networks':'{}':'interfaces' VNF '{}' not match any VNF at 'vnfs'".format(
-                        net_name, vnf)
-                    # logger.debug("nfvo.new_scenario_v02 " + error_text)
-                    raise NfvoException(error_text, HTTP_Not_Found)
-                if iface not in scenario["vnfs"][vnf]['ifaces']:
-                    error_text = "Error at 'networks':'{}':'interfaces':'{}' interface not match any VNF interface"\
-                        .format(net_name, iface)
-                    # logger.debug("nfvo.new_scenario_v02 " + error_text)
-                    raise NfvoException(error_text, HTTP_Bad_Request)
-                if "net_key" in scenario["vnfs"][vnf]['ifaces'][iface]:
-                    error_text = "Error at 'networks':'{}':'interfaces':'{}' interface already connected at network"\
-                                 "'{}'".format(net_name, iface,scenario["vnfs"][vnf]['ifaces'][iface]['net_key'])
-                    # logger.debug("nfvo.new_scenario_v02 " + error_text)
-                    raise NfvoException(error_text, HTTP_Bad_Request)
-                scenario["vnfs"][vnf]['ifaces'][ iface ]['net_key'] = net_name
-                scenario["vnfs"][vnf]['ifaces'][iface]['ip_address'] = ip_address
-                iface_type = scenario["vnfs"][vnf]['ifaces'][iface]['type']
-                if iface_type == 'mgmt' or iface_type == 'bridge':
-                    net_type_bridge = True
-                else:
-                    net_type_data = True
-
-        if net_type_bridge and net_type_data:
-            error_text = "Error connection interfaces of 'bridge' type and 'data' type at 'networks':'{}':'interfaces'"\
-                .format(net_name)
-            # logger.debug("nfvo.new_scenario " + error_text)
-            raise NfvoException(error_text, HTTP_Bad_Request)
-        elif net_type_bridge:
-            type_ = 'bridge'
-        else:
-            type_ = 'data' if len(net["interfaces"]) > 2 else 'ptp'
-
-        if net.get("implementation"):     # for v0.3
-            if type_ == "bridge" and net["implementation"] == "underlay":
-                error_text = "Error connecting interfaces of data type to a network declared as 'underlay' at "\
-                             "'network':'{}'".format(net_name)
-                # logger.debug(error_text)
-                raise NfvoException(error_text, HTTP_Bad_Request)
-            elif type_ != "bridge" and net["implementation"] == "overlay":
-                error_text = "Error connecting interfaces of data type to a network declared as 'overlay' at "\
-                             "'network':'{}'".format(net_name)
-                # logger.debug(error_text)
-                raise NfvoException(error_text, HTTP_Bad_Request)
-            net.pop("implementation")
-        if "type" in net and version == "0.3":   # for v0.3
-            if type_ == "data" and net["type"] == "e-line":
-                error_text = "Error connecting more than 2 interfaces of data type to a network declared as type "\
-                             "'e-line' at 'network':'{}'".format(net_name)
-                # logger.debug(error_text)
-                raise NfvoException(error_text, HTTP_Bad_Request)
-            elif type_ == "ptp" and net["type"] == "e-lan":
-                type_ = "data"
-
-        net['type'] = type_
-        net['name'] = net_name
-        net['external'] = net.get('external', False)
-
-    # 3: insert at database
-    scenario["nets"] = scenario["networks"]
-    scenario['tenant_id'] = tenant_id
-    scenario_id = mydb.new_scenario(scenario)
-    return scenario_id
-
-
-def edit_scenario(mydb, tenant_id, scenario_id, data):
-    data["uuid"] = scenario_id
-    data["tenant_id"] = tenant_id
-    c = mydb.edit_scenario( data )
-    return c
-
-
-def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instance_scenario_description, datacenter=None,vim_tenant=None, startvms=True):
-    #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
-    datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter, vim_tenant=vim_tenant)
-    vims = {datacenter_id: myvim}
-    myvim_tenant = myvim['tenant_id']
-    datacenter_name = myvim['name']
-
-    rollbackList=[]
-    try:
-        #print "Checking that the scenario_id exists and getting the scenario dictionary"
-        scenarioDict = mydb.get_scenario(scenario_id, tenant_id, datacenter_id)
-        scenarioDict['datacenter2tenant'] = { datacenter_id: myvim['config']['datacenter_tenant_id'] }
-        scenarioDict['datacenter_id'] = datacenter_id
-        #print '================scenarioDict======================='
-        #print json.dumps(scenarioDict, indent=4)
-        #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
-
-        logger.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict['name'],len(scenarioDict['vnfs']))
-        #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
-
-        auxNetDict = {}   #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
-        auxNetDict['scenario'] = {}
-
-        logger.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
-        for sce_net in scenarioDict['nets']:
-            #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
-
-            myNetName = "%s.%s" % (instance_scenario_name, sce_net['name'])
-            myNetName = myNetName[0:255] #limit length
-            myNetType = sce_net['type']
-            myNetDict = {}
-            myNetDict["name"] = myNetName
-            myNetDict["type"] = myNetType
-            myNetDict["tenant_id"] = myvim_tenant
-            myNetIPProfile = sce_net.get('ip_profile', None)
-            #TODO:
-            #We should use the dictionary as input parameter for new_network
-            #print myNetDict
-            if not sce_net["external"]:
-                network_id = myvim.new_network(myNetName, myNetType, myNetIPProfile)
-                #print "New VIM network created for scenario %s. Network id:  %s" % (scenarioDict['name'],network_id)
-                sce_net['vim_id'] = network_id
-                auxNetDict['scenario'][sce_net['uuid']] = network_id
-                rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':network_id})
-                sce_net["created"] = True
-            else:
-                if sce_net['vim_id'] == None:
-                    error_text = "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name, sce_net['name'])
-                    _, message = rollback(mydb, vims, rollbackList)
-                    logger.error("nfvo.start_scenario: %s", error_text)
-                    raise NfvoException(error_text, HTTP_Bad_Request)
-                logger.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict['name'],sce_net['vim_id'])
-                auxNetDict['scenario'][sce_net['uuid']] = sce_net['vim_id']
-
-        logger.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
-        #For each vnf net, we create it and we add it to instanceNetlist.
-        for sce_vnf in scenarioDict['vnfs']:
-            for net in sce_vnf['nets']:
-                #print "Net name: %s. Description: %s" % (net["name"], net["description"])
-
-                myNetName = "%s.%s" % (instance_scenario_name,net['name'])
-                myNetName = myNetName[0:255] #limit length
-                myNetType = net['type']
-                myNetDict = {}
-                myNetDict["name"] = myNetName
-                myNetDict["type"] = myNetType
-                myNetDict["tenant_id"] = myvim_tenant
-                myNetIPProfile = net.get('ip_profile', None)
-                #print myNetDict
-                #TODO:
-                #We should use the dictionary as input parameter for new_network
-                network_id = myvim.new_network(myNetName, myNetType, myNetIPProfile)
-                #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
-                net['vim_id'] = network_id
-                if sce_vnf['uuid'] not in auxNetDict:
-                    auxNetDict[sce_vnf['uuid']] = {}
-                auxNetDict[sce_vnf['uuid']][net['uuid']] = network_id
-                rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':network_id})
-                net["created"] = True
-
-        #print "auxNetDict:"
-        #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
-
-        logger.debug("start_scenario 3. Creating new vm instances in the VIM")
-        #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
-        i = 0
-        for sce_vnf in scenarioDict['vnfs']:
-            for vm in sce_vnf['vms']:
-                i += 1
-                myVMDict = {}
-                #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
-                myVMDict['name'] = "{}.{}.{}".format(instance_scenario_name,sce_vnf['name'],chr(96+i))
-                #myVMDict['description'] = vm['description']
-                myVMDict['description'] = myVMDict['name'][0:99]
-                if not startvms:
-                    myVMDict['start'] = "no"
-                myVMDict['name'] = myVMDict['name'][0:255] #limit name length
-                #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
-
-                #create image at vim in case it not exist
-                image_dict = mydb.get_table_by_uuid_name("images", vm['image_id'])
-                image_id = create_or_use_image(mydb, vims, image_dict, [], True)
-                vm['vim_image_id'] = image_id
-
-                #create flavor at vim in case it not exist
-                flavor_dict = mydb.get_table_by_uuid_name("flavors", vm['flavor_id'])
-                if flavor_dict['extended']!=None:
-                    flavor_dict['extended']= yaml.load(flavor_dict['extended'])
-                flavor_id = create_or_use_flavor(mydb, vims, flavor_dict, [], True)
-                vm['vim_flavor_id'] = flavor_id
-
-
-                myVMDict['imageRef'] = vm['vim_image_id']
-                myVMDict['flavorRef'] = vm['vim_flavor_id']
-                myVMDict['networks'] = []
-                for iface in vm['interfaces']:
-                    netDict = {}
-                    if iface['type']=="data":
-                        netDict['type'] = iface['model']
-                    elif "model" in iface and iface["model"]!=None:
-                        netDict['model']=iface['model']
-                    #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
-                    #discover type of interface looking at flavor
-                    for numa in flavor_dict.get('extended',{}).get('numas',[]):
-                        for flavor_iface in numa.get('interfaces',[]):
-                            if flavor_iface.get('name') == iface['internal_name']:
-                                if flavor_iface['dedicated'] == 'yes':
-                                    netDict['type']="PF"    #passthrough
-                                elif flavor_iface['dedicated'] == 'no':
-                                    netDict['type']="VF"    #siov
-                                elif flavor_iface['dedicated'] == 'yes:sriov':
-                                    netDict['type']="VFnotShared"   #sriov but only one sriov on the PF
-                                netDict["mac_address"] = flavor_iface.get("mac_address")
-                                break;
-                    netDict["use"]=iface['type']
-                    if netDict["use"]=="data" and not netDict.get("type"):
-                        #print "netDict", netDict
-                        #print "iface", iface
-                        e_text = "Cannot determine the interface type PF or VF of VNF '%s' VM '%s' iface '%s'" %(sce_vnf['name'], vm['name'], iface['internal_name'])
-                        if flavor_dict.get('extended')==None:
-                            raise NfvoException(e_text  + "After database migration some information is not available. \
-                                    Try to delete and create the scenarios and VNFs again", HTTP_Conflict)
-                        else:
-                            raise NfvoException(e_text, HTTP_Internal_Server_Error)
-                    if netDict["use"]=="mgmt" or netDict["use"]=="bridge":
-                        netDict["type"]="virtual"
-                    if "vpci" in iface and iface["vpci"] is not None:
-                        netDict['vpci'] = iface['vpci']
-                    if "mac" in iface and iface["mac"] is not None:
-                        netDict['mac_address'] = iface['mac']
-                    if "port-security" in iface and iface["port-security"] is not None:
-                        netDict['port_security'] = iface['port-security']
-                    if "floating-ip" in iface and iface["floating-ip"] is not None:
-                        netDict['floating_ip'] = iface['floating-ip']
-                    netDict['name'] = iface['internal_name']
-                    if iface['net_id'] is None:
-                        for vnf_iface in sce_vnf["interfaces"]:
-                            #print iface
-                            #print vnf_iface
-                            if vnf_iface['interface_id']==iface['uuid']:
-                                netDict['net_id'] = auxNetDict['scenario'][ vnf_iface['sce_net_id'] ]
-                                break
-                    else:
-                        netDict['net_id'] = auxNetDict[ sce_vnf['uuid'] ][ iface['net_id'] ]
-                    #skip bridge ifaces not connected to any net
-                    #if 'net_id' not in netDict or netDict['net_id']==None:
-                    #    continue
-                    myVMDict['networks'].append(netDict)
-                #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
-                #print myVMDict['name']
-                #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
-                #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
-                #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
-                vm_id = myvim.new_vminstance(myVMDict['name'],myVMDict['description'],myVMDict.get('start', None),
-                        myVMDict['imageRef'],myVMDict['flavorRef'],myVMDict['networks'])
-                #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
-                vm['vim_id'] = vm_id
-                rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id})
-                #put interface uuid back to scenario[vnfs][vms[[interfaces]
-                for net in myVMDict['networks']:
-                    if "vim_id" in net:
-                        for iface in vm['interfaces']:
-                            if net["name"]==iface["internal_name"]:
-                                iface["vim_id"]=net["vim_id"]
-                                break
-
-        logger.debug("start scenario Deployment done")
-        #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
-        #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
-        instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_scenario_name, instance_scenario_description, scenarioDict)
-        return mydb.get_instance_scenario(instance_id)
-
-    except (db_base_Exception, vimconn.vimconnException) as e:
-        _, message = rollback(mydb, vims, rollbackList)
-        if isinstance(e, db_base_Exception):
-            error_text = "Exception at database"
-        else:
-            error_text = "Exception at VIM"
-        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
-        #logger.error("start_scenario %s", error_text)
-        raise NfvoException(error_text, e.http_code)
-
-
-def unify_cloud_config(cloud_config_preserve, cloud_config):
-    ''' join the cloud config information into cloud_config_preserve.
-    In case of conflict cloud_config_preserve preserves
-    None is admited
-    '''
-    if not cloud_config_preserve and not cloud_config:
-        return None
-
-    new_cloud_config = {"key-pairs":[], "users":[]}
-    # key-pairs
-    if cloud_config_preserve:
-        for key in cloud_config_preserve.get("key-pairs", () ):
-            if key not in new_cloud_config["key-pairs"]:
-                new_cloud_config["key-pairs"].append(key)
-    if cloud_config:
-        for key in cloud_config.get("key-pairs", () ):
-            if key not in new_cloud_config["key-pairs"]:
-                new_cloud_config["key-pairs"].append(key)
-    if not new_cloud_config["key-pairs"]:
-        del new_cloud_config["key-pairs"]
-
-    # users
-    if cloud_config:
-        new_cloud_config["users"] += cloud_config.get("users", () )
-    if cloud_config_preserve:
-        new_cloud_config["users"] += cloud_config_preserve.get("users", () )
-    index_to_delete = []
-    users = new_cloud_config.get("users", [])
-    for index0 in range(0,len(users)):
-        if index0 in index_to_delete:
-            continue
-        for index1 in range(index0+1,len(users)):
-            if index1 in index_to_delete:
-                continue
-            if users[index0]["name"] == users[index1]["name"]:
-                index_to_delete.append(index1)
-                for key in users[index1].get("key-pairs",()):
-                    if "key-pairs" not in users[index0]:
-                        users[index0]["key-pairs"] = [key]
-                    elif key not in users[index0]["key-pairs"]:
-                        users[index0]["key-pairs"].append(key)
-    index_to_delete.sort(reverse=True)
-    for index in index_to_delete:
-        del users[index]
-    if not new_cloud_config["users"]:
-        del new_cloud_config["users"]
-
-    #boot-data-drive
-    if cloud_config and cloud_config.get("boot-data-drive") != None:
-        new_cloud_config["boot-data-drive"] = cloud_config["boot-data-drive"]
-    if cloud_config_preserve and cloud_config_preserve.get("boot-data-drive") != None:
-        new_cloud_config["boot-data-drive"] = cloud_config_preserve["boot-data-drive"]
-
-    # user-data
-    if cloud_config and cloud_config.get("user-data") != None:
-        new_cloud_config["user-data"] = cloud_config["user-data"]
-    if cloud_config_preserve and cloud_config_preserve.get("user-data") != None:
-        new_cloud_config["user-data"] = cloud_config_preserve["user-data"]
-
-    # config files
-    new_cloud_config["config-files"] = []
-    if cloud_config and cloud_config.get("config-files") != None:
-        new_cloud_config["config-files"] += cloud_config["config-files"]
-    if cloud_config_preserve:
-        for file in cloud_config_preserve.get("config-files", ()):
-            for index in range(0, len(new_cloud_config["config-files"])):
-                if new_cloud_config["config-files"][index]["dest"] == file["dest"]:
-                    new_cloud_config["config-files"][index] = file
-                    break
-            else:
-                new_cloud_config["config-files"].append(file)
-    if not new_cloud_config["config-files"]:
-        del new_cloud_config["config-files"]
-    return new_cloud_config
-
-
-def get_vim_thread(tenant_id, datacenter_id_name=None, datacenter_tenant_id=None):
-    datacenter_id = None
-    datacenter_name = None
-    thread = None
-    if datacenter_id_name:
-        if utils.check_valid_uuid(datacenter_id_name):
-            datacenter_id = datacenter_id_name
-        else:
-            datacenter_name = datacenter_id_name
-    if datacenter_id:
-        thread = vim_threads["running"].get(datacenter_id + "." + tenant_id)
-    else:
-        for k, v in vim_threads["running"].items():
-            datacenter_tenant = k.split(".")
-            if datacenter_tenant[0] == datacenter_id and datacenter_tenant[1] == tenant_id:
-                if thread:
-                    raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
-                thread = v
-            elif not datacenter_id and datacenter_tenant[1] == tenant_id:
-                if thread.datacenter_name == datacenter_name:
-                    if thread:
-                        raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
-                    thread = v
-    if not thread:
-        raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), HTTP_Not_Found)
-    return thread
-
-
-def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None, **extra_filter):
-    datacenter_id = None
-    datacenter_name = None
-    if datacenter_id_name:
-        if utils.check_valid_uuid(datacenter_id_name):
-            datacenter_id = datacenter_id_name
-        else:
-            datacenter_name = datacenter_id_name
-    vims = get_vim(mydb, tenant_id, datacenter_id, datacenter_name, **extra_filter)
-    if len(vims) == 0:
-        raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), HTTP_Not_Found)
-    elif len(vims)>1:
-        #print "nfvo.datacenter_action() error. Several datacenters found"
-        raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
-    return vims.keys()[0], vims.values()[0]
-
-
-def update(d, u):
-    '''Takes dict d and updates it with the values in dict u.'''
-    '''It merges all depth levels'''
-    for k, v in u.iteritems():
-        if isinstance(v, collections.Mapping):
-            r = update(d.get(k, {}), v)
-            d[k] = r
-        else:
-            d[k] = u[k]
-    return d
-
-
-def create_instance(mydb, tenant_id, instance_dict):
-    # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
-    # logger.debug("Creating instance...")
-    scenario = instance_dict["scenario"]
-
-    #find main datacenter
-    myvims = {}
-    myvim_threads = {}
-    datacenter2tenant = {}
-    datacenter = instance_dict.get("datacenter")
-    default_datacenter_id, vim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
-    myvims[default_datacenter_id] = vim
-    myvim_threads[default_datacenter_id] = get_vim_thread(tenant_id, default_datacenter_id)
-    datacenter2tenant[default_datacenter_id] = vim['config']['datacenter_tenant_id']
-    #myvim_tenant = myvim['tenant_id']
-#    default_datacenter_name = vim['name']
-    rollbackList=[]
-
-    #print "Checking that the scenario exists and getting the scenario dictionary"
-    scenarioDict = mydb.get_scenario(scenario, tenant_id, default_datacenter_id)
-
-    #logger.debug(">>>>>>> Dictionaries before merging")
-    #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
-    #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
-
-    scenarioDict['datacenter_id'] = default_datacenter_id
-
-    auxNetDict = {}   #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
-    auxNetDict['scenario'] = {}
-
-    logger.debug("Creating instance from scenario-dict:\n%s", yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))  #TODO remove
-    instance_name = instance_dict["name"]
-    instance_description = instance_dict.get("description")
-    instance_tasks={}
-    try:
-        # 0 check correct parameters
-        for net_name, net_instance_desc in instance_dict.get("networks",{}).iteritems():
-            found = False
-            for scenario_net in scenarioDict['nets']:
-                if net_name == scenario_net["name"]:
-                    found = True
-                    break
-            if not found:
-                raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name), HTTP_Bad_Request)
-            if "sites" not in net_instance_desc:
-                net_instance_desc["sites"] = [ {} ]
-            site_without_datacenter_field = False
-            for site in net_instance_desc["sites"]:
-                if site.get("datacenter"):
-                    if site["datacenter"] not in myvims:
-                        #Add this datacenter to myvims
-                        d, v = get_datacenter_by_name_uuid(mydb, tenant_id, site["datacenter"])
-                        myvims[d] = v
-                        myvim_threads[d] = get_vim_thread(tenant_id, site["datacenter"])
-                        datacenter2tenant[d] = v['config']['datacenter_tenant_id']
-                        site["datacenter"] = d #change name to id
-                else:
-                    if site_without_datacenter_field:
-                        raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name), HTTP_Bad_Request)
-                    site_without_datacenter_field = True
-                    site["datacenter"] = default_datacenter_id #change name to id
-
-        for vnf_name, vnf_instance_desc in instance_dict.get("vnfs",{}).iteritems():
-            found=False
-            for scenario_vnf in scenarioDict['vnfs']:
-                if vnf_name == scenario_vnf['name']:
-                    found = True
-                    break
-            if not found:
-                raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc), HTTP_Bad_Request)
-            if "datacenter" in vnf_instance_desc:
-            # Add this datacenter to myvims
-                if vnf_instance_desc["datacenter"] not in myvims:
-                    d, v = get_datacenter_by_name_uuid(mydb, tenant_id, vnf_instance_desc["datacenter"])
-                    myvims[d] = v
-                    myvim_threads[d] = get_vim_thread(tenant_id, vnf_instance_desc["datacenter"])
-                    datacenter2tenant[d] = v['config']['datacenter_tenant_id']
-                scenario_vnf["datacenter"] = vnf_instance_desc["datacenter"]
-
-    #0.1 parse cloud-config parameters
-        cloud_config = unify_cloud_config(instance_dict.get("cloud-config"), scenarioDict.get("cloud-config"))
-
-    #0.2 merge instance information into scenario
-        #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
-        #However, this is not possible yet.
-        for net_name, net_instance_desc in instance_dict.get("networks",{}).iteritems():
-            for scenario_net in scenarioDict['nets']:
-                if net_name == scenario_net["name"]:
-                    if 'ip-profile' in net_instance_desc:
-                        ipprofile = net_instance_desc['ip-profile']
-                        ipprofile['subnet_address'] = ipprofile.pop('subnet-address',None)
-                        ipprofile['ip_version'] = ipprofile.pop('ip-version','IPv4')
-                        ipprofile['gateway_address'] = ipprofile.pop('gateway-address',None)
-                        ipprofile['dns_address'] = ipprofile.pop('dns-address',None)
-                        if 'dhcp' in ipprofile:
-                            ipprofile['dhcp_start_address'] = ipprofile['dhcp'].get('start-address',None)
-                            ipprofile['dhcp_enabled'] = ipprofile['dhcp'].get('enabled',True)
-                            ipprofile['dhcp_count'] = ipprofile['dhcp'].get('count',None)
-                            del ipprofile['dhcp']
-                        if 'ip_profile' not in scenario_net:
-                            scenario_net['ip_profile'] = ipprofile
-                        else:
-                            update(scenario_net['ip_profile'],ipprofile)
-            for interface in net_instance_desc.get('interfaces', () ):
-                if 'ip_address' in interface:
-                    for vnf in scenarioDict['vnfs']:
-                        if interface['vnf'] == vnf['name']:
-                            for vnf_interface in vnf['interfaces']:
-                                if interface['vnf_interface'] == vnf_interface['external_name']:
-                                    vnf_interface['ip_address']=interface['ip_address']
-
-        #logger.debug(">>>>>>>> Merged dictionary")
-        logger.debug("Creating instance scenario-dict MERGED:\n%s", yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))
-
-
-        # 1. Creating new nets (sce_nets) in the VIM"
-        for sce_net in scenarioDict['nets']:
-            sce_net["vim_id_sites"]={}
-            descriptor_net =  instance_dict.get("networks",{}).get(sce_net["name"],{})
-            net_name = descriptor_net.get("vim-network-name")
-            auxNetDict['scenario'][sce_net['uuid']] = {}
-
-            sites = descriptor_net.get("sites", [ {} ])
-            for site in sites:
-                if site.get("datacenter"):
-                    vim = myvims[ site["datacenter"] ]
-                    datacenter_id = site["datacenter"]
-                    myvim_thread = myvim_threads[ site["datacenter"] ]
-                else:
-                    vim = myvims[ default_datacenter_id ]
-                    datacenter_id = default_datacenter_id
-                    myvim_thread = myvim_threads[default_datacenter_id]
-                net_type = sce_net['type']
-                lookfor_filter = {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
-                if sce_net["external"]:
-                    if not net_name:
-                        net_name = sce_net["name"]
-                    if "netmap-use" in site or "netmap-create" in site:
-                        create_network = False
-                        lookfor_network = False
-                        if "netmap-use" in site:
-                            lookfor_network = True
-                            if utils.check_valid_uuid(site["netmap-use"]):
-                                filter_text = "scenario id '%s'" % site["netmap-use"]
-                                lookfor_filter["id"] = site["netmap-use"]
-                            else:
-                                filter_text = "scenario name '%s'" % site["netmap-use"]
-                                lookfor_filter["name"] = site["netmap-use"]
-                        if "netmap-create" in site:
-                            create_network = True
-                            net_vim_name = net_name
-                            if site["netmap-create"]:
-                                net_vim_name = site["netmap-create"]
-
-                    elif sce_net['vim_id'] != None:
-                        #there is a netmap at datacenter_nets database   #TODO REVISE!!!!
-                        create_network = False
-                        lookfor_network = True
-                        lookfor_filter["id"] = sce_net['vim_id']
-                        filter_text = "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net['vim_id'], sce_net["name"])
-                        #look for network at datacenter and return error
-                    else:
-                        #There is not a netmap, look at datacenter for a net with this name and create if not found
-                        create_network = True
-                        lookfor_network = True
-                        lookfor_filter["name"] = sce_net["name"]
-                        net_vim_name = sce_net["name"]
-                        filter_text = "scenario name '%s'" % sce_net["name"]
-                else:
-                    if not net_name:
-                        net_name = "%s.%s" %(instance_name, sce_net["name"])
-                        net_name = net_name[:255]     #limit length
-                    net_vim_name = net_name
-                    create_network = True
-                    lookfor_network = False
-
-                if lookfor_network:
-                    vim_nets = vim.get_network_list(filter_dict=lookfor_filter)
-                    if len(vim_nets) > 1:
-                        raise NfvoException("More than one candidate VIM network found for " + filter_text, HTTP_Bad_Request )
-                    elif len(vim_nets) == 0:
-                        if not create_network:
-                            raise NfvoException("No candidate VIM network found for " + filter_text, HTTP_Bad_Request )
-                    else:
-                        sce_net["vim_id_sites"][datacenter_id] = vim_nets[0]['id']
-                        auxNetDict['scenario'][sce_net['uuid']][datacenter_id] = vim_nets[0]['id']
-                        create_network = False
-                if create_network:
-                    #if network is not external
-                    task = new_task("new-net", (net_vim_name, net_type, sce_net.get('ip_profile',None)))
-                    task_id = myvim_thread.insert_task(task)
-                    instance_tasks[task_id] = task
-                    #network_id = vim.new_network(net_vim_name, net_type, sce_net.get('ip_profile',None))
-                    sce_net["vim_id_sites"][datacenter_id] = task_id
-                    auxNetDict['scenario'][sce_net['uuid']][datacenter_id] = task_id
-                    rollbackList.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id, 'uuid':task_id})
-                    sce_net["created"] = True
-
-        # 2. Creating new nets (vnf internal nets) in the VIM"
-        #For each vnf net, we create it and we add it to instanceNetlist.
-        for sce_vnf in scenarioDict['vnfs']:
-            for net in sce_vnf['nets']:
-                if sce_vnf.get("datacenter"):
-                    vim = myvims[ sce_vnf["datacenter"] ]
-                    datacenter_id = sce_vnf["datacenter"]
-                    myvim_thread = myvim_threads[ sce_vnf["datacenter"]]
-                else:
-                    vim = myvims[ default_datacenter_id ]
-                    datacenter_id = default_datacenter_id
-                    myvim_thread = myvim_threads[default_datacenter_id]
-                descriptor_net =  instance_dict.get("vnfs",{}).get(sce_vnf["name"],{})
-                net_name = descriptor_net.get("name")
-                if not net_name:
-                    net_name = "%s.%s" %(instance_name, net["name"])
-                    net_name = net_name[:255]     #limit length
-                net_type = net['type']
-                task = new_task("new-net", (net_name, net_type, net.get('ip_profile',None)))
-                task_id = myvim_thread.insert_task(task)
-                instance_tasks[task_id] = task
-                # network_id = vim.new_network(net_name, net_type, net.get('ip_profile',None))
-                net['vim_id'] = task_id
-                if sce_vnf['uuid'] not in auxNetDict:
-                    auxNetDict[sce_vnf['uuid']] = {}
-                auxNetDict[sce_vnf['uuid']][net['uuid']] = task_id
-                rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':task_id})
-                net["created"] = True
-
-
-        #print "auxNetDict:"
-        #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
-
-        # 3. Creating new vm instances in the VIM
-        #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
-        for sce_vnf in scenarioDict['vnfs']:
-            if sce_vnf.get("datacenter"):
-                vim = myvims[ sce_vnf["datacenter"] ]
-                myvim_thread = myvim_threads[ sce_vnf["datacenter"] ]
-                datacenter_id = sce_vnf["datacenter"]
-            else:
-                vim = myvims[ default_datacenter_id ]
-                myvim_thread = myvim_threads[ default_datacenter_id ]
-                datacenter_id = default_datacenter_id
-            sce_vnf["datacenter_id"] =  datacenter_id
-            i = 0
-            for vm in sce_vnf['vms']:
-                i += 1
-                myVMDict = {}
-                myVMDict['name'] = "{}.{}.{}".format(instance_name,sce_vnf['name'],chr(96+i))
-                myVMDict['description'] = myVMDict['name'][0:99]
-#                if not startvms:
-#                    myVMDict['start'] = "no"
-                myVMDict['name'] = myVMDict['name'][0:255] #limit name length
-                #create image at vim in case it not exist
-                image_dict = mydb.get_table_by_uuid_name("images", vm['image_id'])
-                image_id = create_or_use_image(mydb, {datacenter_id: vim}, image_dict, [], True)
-                vm['vim_image_id'] = image_id
-
-                #create flavor at vim in case it not exist
-                flavor_dict = mydb.get_table_by_uuid_name("flavors", vm['flavor_id'])
-                if flavor_dict['extended']!=None:
-                    flavor_dict['extended']= yaml.load(flavor_dict['extended'])
-                flavor_id = create_or_use_flavor(mydb, {datacenter_id: vim}, flavor_dict, rollbackList, True)
-
-                #Obtain information for additional disks
-                extended_flavor_dict = mydb.get_rows(FROM='datacenters_flavors', SELECT=('extended',), WHERE={'vim_id': flavor_id})
-                if not extended_flavor_dict:
-                    raise NfvoException("flavor '{}' not found".format(flavor_id), HTTP_Not_Found)
-                    return
-
-                #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
-                myVMDict['disks'] = None
-                extended_info = extended_flavor_dict[0]['extended']
-                if extended_info != None:
-                    extended_flavor_dict_yaml = yaml.load(extended_info)
-                    if 'disks' in extended_flavor_dict_yaml:
-                        myVMDict['disks'] = extended_flavor_dict_yaml['disks']
-
-                vm['vim_flavor_id'] = flavor_id
-                myVMDict['imageRef'] = vm['vim_image_id']
-                myVMDict['flavorRef'] = vm['vim_flavor_id']
-                myVMDict['networks'] = []
-                task_depends = {}
-                #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
-                for iface in vm['interfaces']:
-                    netDict = {}
-                    if iface['type']=="data":
-                        netDict['type'] = iface['model']
-                    elif "model" in iface and iface["model"]!=None:
-                        netDict['model']=iface['model']
-                    #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
-                    #discover type of interface looking at flavor
-                    for numa in flavor_dict.get('extended',{}).get('numas',[]):
-                        for flavor_iface in numa.get('interfaces',[]):
-                            if flavor_iface.get('name') == iface['internal_name']:
-                                if flavor_iface['dedicated'] == 'yes':
-                                    netDict['type']="PF"    #passthrough
-                                elif flavor_iface['dedicated'] == 'no':
-                                    netDict['type']="VF"    #siov
-                                elif flavor_iface['dedicated'] == 'yes:sriov':
-                                    netDict['type']="VFnotShared"   #sriov but only one sriov on the PF
-                                netDict["mac_address"] = flavor_iface.get("mac_address")
-                                break;
-                    netDict["use"]=iface['type']
-                    if netDict["use"]=="data" and not netDict.get("type"):
-                        #print "netDict", netDict
-                        #print "iface", iface
-                        e_text = "Cannot determine the interface type PF or VF of VNF '%s' VM '%s' iface '%s'" %(sce_vnf['name'], vm['name'], iface['internal_name'])
-                        if flavor_dict.get('extended')==None:
-                            raise NfvoException(e_text + "After database migration some information is not available. \
-                                    Try to delete and create the scenarios and VNFs again", HTTP_Conflict)
-                        else:
-                            raise NfvoException(e_text, HTTP_Internal_Server_Error)
-                    if netDict["use"]=="mgmt" or netDict["use"]=="bridge":
-                        netDict["type"]="virtual"
-                    if "vpci" in iface and iface["vpci"] is not None:
-                        netDict['vpci'] = iface['vpci']
-                    if "mac" in iface and iface["mac"] is not None:
-                        netDict['mac_address'] = iface['mac']
-                    if "port-security" in iface and iface["port-security"] is not None:
-                        netDict['port_security'] = iface['port-security']
-                    if "floating-ip" in iface and iface["floating-ip"] is not None:
-                        netDict['floating_ip'] = iface['floating-ip']
-                    netDict['name'] = iface['internal_name']
-                    if iface['net_id'] is None:
-                        for vnf_iface in sce_vnf["interfaces"]:
-                            #print iface
-                            #print vnf_iface
-                            if vnf_iface['interface_id']==iface['uuid']:
-                                netDict['net_id'] = auxNetDict['scenario'][ vnf_iface['sce_net_id'] ][datacenter_id]
-                                break
-                    else:
-                        netDict['net_id'] = auxNetDict[ sce_vnf['uuid'] ][ iface['net_id'] ]
-                    if is_task_id(netDict['net_id']):
-                        task_depends[netDict['net_id']] = instance_tasks[netDict['net_id']]
-                    #skip bridge ifaces not connected to any net
-                    #if 'net_id' not in netDict or netDict['net_id']==None:
-                    #    continue
-                    myVMDict['networks'].append(netDict)
-                #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
-                #print myVMDict['name']
-                #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
-                #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
-                #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
-                if vm.get("boot_data"):
-                    cloud_config_vm = unify_cloud_config(vm["boot_data"], cloud_config)
-                else:
-                    cloud_config_vm = cloud_config
-                task = new_task("new-vm", (myVMDict['name'], myVMDict['description'], myVMDict.get('start', None),
-                                           myVMDict['imageRef'], myVMDict['flavorRef'], myVMDict['networks'],
-                                           cloud_config_vm, myVMDict['disks']), depends=task_depends)
-                vm_id = myvim_thread.insert_task(task)
-                instance_tasks[vm_id] = task
-
-                vm['vim_id'] = vm_id
-                rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id})
-                #put interface uuid back to scenario[vnfs][vms[[interfaces]
-                for net in myVMDict['networks']:
-                    if "vim_id" in net:
-                        for iface in vm['interfaces']:
-                            if net["name"]==iface["internal_name"]:
-                                iface["vim_id"]=net["vim_id"]
-                                break
-        scenarioDict["datacenter2tenant"] = datacenter2tenant
-        logger.debug("create_instance Deployment done scenarioDict: %s",
-                    yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False) )
-        instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_name, instance_description, scenarioDict)
-        # Update database with those ended tasks
-        for task in instance_tasks.values():
-            if task["status"] == "ok":
-                if task["name"] == "new-vm":
-                    mydb.update_rows("instance_vms", UPDATE={"vim_vm_id": task["result"]},
-                                     WHERE={"vim_vm_id": task["id"]})
-                elif task["name"] == "new-net":
-                    mydb.update_rows("instance_nets", UPDATE={"vim_net_id": task["result"]},
-                                     WHERE={"vim_net_id": task["id"]})
-        return mydb.get_instance_scenario(instance_id)
-    except (NfvoException, vimconn.vimconnException,db_base_Exception)  as e:
-        message = rollback(mydb, myvims, rollbackList)
-        if isinstance(e, db_base_Exception):
-            error_text = "database Exception"
-        elif isinstance(e, vimconn.vimconnException):
-            error_text = "VIM Exception"
-        else:
-            error_text = "Exception"
-        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
-        #logger.error("create_instance: %s", error_text)
-        raise NfvoException(error_text, e.http_code)
-
-
-def delete_instance(mydb, tenant_id, instance_id):
-    #print "Checking that the instance_id exists and getting the instance dictionary"
-    instanceDict = mydb.get_instance_scenario(instance_id, tenant_id)
-    #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
-    tenant_id = instanceDict["tenant_id"]
-    #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
-
-    #1. Delete from Database
-    message = mydb.delete_instance_scenario(instance_id, tenant_id)
-
-    #2. delete from VIM
-    error_msg = ""
-    myvims = {}
-    myvim_threads = {}
-
-    #2.1 deleting VMs
-    #vm_fail_list=[]
-    for sce_vnf in instanceDict['vnfs']:
-        datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
-        if datacenter_key not in myvims:
-            try:
-                myvim_thread = get_vim_thread(tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
-            except NfvoException as e:
-                logger.error(str(e))
-                myvim_thread = None
-            myvim_threads[datacenter_key] = myvim_thread
-            vims = get_vim(mydb, tenant_id, datacenter_id=sce_vnf["datacenter_id"],
-                       datacenter_tenant_id=sce_vnf["datacenter_tenant_id"])
-            if len(vims) == 0:
-                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"],
-                                                                                        sce_vnf["datacenter_tenant_id"]))
-                myvims[datacenter_key] = None
-            else:
-                myvims[datacenter_key] = vims.values()[0]
-        myvim = myvims[datacenter_key]
-        myvim_thread = myvim_threads[datacenter_key]
-        for vm in sce_vnf['vms']:
-            if not myvim:
-                error_msg += "\n    VM id={} cannot be deleted because datacenter={} not found".format(vm['vim_vm_id'], sce_vnf["datacenter_id"])
-                continue
-            try:
-                task=None
-                if is_task_id(vm['vim_vm_id']):
-                    task_id = vm['vim_vm_id']
-                    old_task = task_dict.get(task_id)
-                    if not old_task:
-                        error_msg += "\n    VM was scheduled for create, but task {} is not found".format(task_id)
-                        continue
-                    with task_lock:
-                        if old_task["status"] == "enqueued":
-                            old_task["status"] = "deleted"
-                        elif old_task["status"] == "error":
-                            continue
-                        elif old_task["status"] == "processing":
-                            task = new_task("del-vm", task_id, depends={task_id: old_task})
-                        else: #ok
-                            task = new_task("del-vm", old_task["result"])
-                else:
-                    task = new_task("del-vm", vm['vim_vm_id'], store=False)
-                if task:
-                    myvim_thread.insert_task(task)
-            except vimconn.vimconnNotFoundException as e:
-                error_msg+="\n    VM VIM_id={} not found at datacenter={}".format(vm['vim_vm_id'], sce_vnf["datacenter_id"])
-                logger.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
-                    vm['name'], vm['uuid'], vm['vim_vm_id'], sce_vnf['vnf_id'])
-            except vimconn.vimconnException as e:
-                error_msg+="\n    VM VIM_id={} at datacenter={} Error: {} {}".format(vm['vim_vm_id'], sce_vnf["datacenter_id"], e.http_code, str(e))
-                logger.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
-                    e.http_code, vm['name'], vm['uuid'], vm['vim_vm_id'], sce_vnf['vnf_id'], str(e))
-
-    #2.2 deleting NETS
-    #net_fail_list=[]
-    for net in instanceDict['nets']:
-        if not net['created']:
-            continue #skip not created nets
-        datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"])
-        if datacenter_key not in myvims:
-            try:
-                myvim_thread = get_vim_thread(tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
-            except NfvoException as e:
-                logger.error(str(e))
-                myvim_thread = None
-            myvim_threads[datacenter_key] = myvim_thread
-            vims = get_vim(mydb, tenant_id, datacenter_id=net["datacenter_id"],
-                           datacenter_tenant_id=net["datacenter_tenant_id"])
-            if len(vims) == 0:
-                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
-                myvims[datacenter_key] = None
-            else:
-                myvims[datacenter_key] = vims.values()[0]
-        myvim = myvims[datacenter_key]
-        myvim_thread = myvim_threads[datacenter_key]
-
-        if not myvim:
-            error_msg += "\n    Net VIM_id={} cannot be deleted because datacenter={} not found".format(net['vim_net_id'], net["datacenter_id"])
-            continue
-        try:
-            task = None
-            if is_task_id(net['vim_net_id']):
-                task_id = net['vim_net_id']
-                old_task = task_dict.get(task_id)
-                if not old_task:
-                    error_msg += "\n    NET was scheduled for create, but task {} is not found".format(task_id)
-                    continue
-                with task_lock:
-                    if old_task["status"] == "enqueued":
-                        old_task["status"] = "deleted"
-                    elif old_task["status"] == "error":
-                        continue
-                    elif old_task["status"] == "processing":
-                        task = new_task("del-net", task_id, depends={task_id: old_task})
-                    else:  # ok
-                        task = new_task("del-net", old_task["result"])
-            else:
-                task = new_task("del-net", net['vim_net_id'], store=False)
-            if task:
-                myvim_thread.insert_task(task)
-        except vimconn.vimconnNotFoundException as e:
-            error_msg += "\n    NET VIM_id={} not found at datacenter={}".format(net['vim_net_id'], net["datacenter_id"])
-            logger.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
-                        net['uuid'], net['vim_net_id'], str(net['vnf_net_id']))
-        except vimconn.vimconnException as e:
-            error_msg += "\n    NET VIM_id={} at datacenter={} Error: {} {}".format(net['vim_net_id'],
-                                                                                    net["datacenter_id"],
-                                                                                    e.http_code, str(e))
-            logger.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
-                         e.http_code, net['uuid'], net['vim_net_id'], str(net['vnf_net_id']), str(e))
-    if len(error_msg) > 0:
-        return 'instance ' + message + ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
-    else:
-        return 'instance ' + message + ' deleted'
-
-
-def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenant=None):
-    '''Refreshes a scenario instance. It modifies instanceDict'''
-    '''Returns:
-         - result: <0 if there is any unexpected error, n>=0 if no errors where n is the number of vms and nets that couldn't be updated in the database
-         - error_msg
-    '''
-    # Assumption: nfvo_tenant and instance_id were checked before entering into this function
-    #print "nfvo.refresh_instance begins"
-    #print json.dumps(instanceDict, indent=4)
-
-    #print "Getting the VIM URL and the VIM tenant_id"
-    myvims={}
-
-    # 1. Getting VIM vm and net list
-    vms_updated = [] #List of VM instance uuids in openmano that were updated
-    vms_notupdated=[]
-    vm_list = {}
-    for sce_vnf in instanceDict['vnfs']:
-        datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
-        if datacenter_key not in vm_list:
-            vm_list[datacenter_key] = []
-        if datacenter_key not in myvims:
-            vims = get_vim(mydb, nfvo_tenant, datacenter_id=sce_vnf["datacenter_id"],
-                           datacenter_tenant_id=sce_vnf["datacenter_tenant_id"])
-            if len(vims) == 0:
-                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"]))
-                myvims[datacenter_key] = None
-            else:
-                myvims[datacenter_key] = vims.values()[0]
-        for vm in sce_vnf['vms']:
-            vm_list[datacenter_key].append(vm['vim_vm_id'])
-            vms_notupdated.append(vm["uuid"])
-
-    nets_updated = [] #List of VM instance uuids in openmano that were updated
-    nets_notupdated=[]
-    net_list = {}
-    for net in instanceDict['nets']:
-        datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"])
-        if datacenter_key not in net_list:
-            net_list[datacenter_key] = []
-        if datacenter_key not in myvims:
-            vims = get_vim(mydb, nfvo_tenant, datacenter_id=net["datacenter_id"],
-                           datacenter_tenant_id=net["datacenter_tenant_id"])
-            if len(vims) == 0:
-                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
-                myvims[datacenter_key] = None
-            else:
-                myvims[datacenter_key] = vims.values()[0]
-
-        net_list[datacenter_key].append(net['vim_net_id'])
-        nets_notupdated.append(net["uuid"])
-
-    # 1. Getting the status of all VMs
-    vm_dict={}
-    for datacenter_key in myvims:
-        if not vm_list.get(datacenter_key):
-            continue
-        failed = True
-        failed_message=""
-        if not myvims[datacenter_key]:
-            failed_message = "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"])
-        else:
-            try:
-                vm_dict.update(myvims[datacenter_key].refresh_vms_status(vm_list[datacenter_key]) )
-                failed = False
-            except vimconn.vimconnException as e:
-                logger.error("VIM exception %s %s", type(e).__name__, str(e))
-                failed_message = str(e)
-        if failed:
-            for vm in vm_list[datacenter_key]:
-                vm_dict[vm] = {'status': "VIM_ERROR", 'error_msg': failed_message}
-
-    # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
-    for sce_vnf in instanceDict['vnfs']:
-        for vm in sce_vnf['vms']:
-            vm_id = vm['vim_vm_id']
-            interfaces = vm_dict[vm_id].pop('interfaces', [])
-            #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
-            has_mgmt_iface = False
-            for iface in vm["interfaces"]:
-                if iface["type"]=="mgmt":
-                    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')
-                vm['vim_info']  = vm_dict[vm_id].get('vim_info')
-                # 2.1. Update in openmano DB the VMs whose status changed
-                try:
-                    updates = mydb.update_rows('instance_vms', UPDATE=vm_dict[vm_id], WHERE={'uuid':vm["uuid"]})
-                    vms_notupdated.remove(vm["uuid"])
-                    if updates>0:
-                        vms_updated.append(vm["uuid"])
-                except db_base_Exception as e:
-                    logger.error("nfvo.refresh_instance error database update: %s", str(e))
-            # 2.2. Update in openmano DB the interface VMs
-            for interface in interfaces:
-                #translate from vim_net_id to instance_net_id
-                network_id_list=[]
-                for net in instanceDict['nets']:
-                    if net["vim_net_id"] == interface["vim_net_id"]:
-                        network_id_list.append(net["uuid"])
-                if not network_id_list:
-                    continue
-                del interface["vim_net_id"]
-                try:
-                    for network_id in network_id_list:
-                        mydb.update_rows('instance_interfaces', UPDATE=interface, WHERE={'instance_vm_id':vm["uuid"], "instance_net_id":network_id})
-                except db_base_Exception as e:
-                    logger.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm["uuid"], network_id)
-
-    # 3. Getting the status of all nets
-    net_dict = {}
-    for datacenter_key in myvims:
-        if not net_list.get(datacenter_key):
-            continue
-        failed = True
-        failed_message = ""
-        if not myvims[datacenter_key]:
-            failed_message = "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"])
-        else:
-            try:
-                net_dict.update(myvims[datacenter_key].refresh_nets_status(net_list[datacenter_key]) )
-                failed = False
-            except vimconn.vimconnException as e:
-                logger.error("VIM exception %s %s", type(e).__name__, str(e))
-                failed_message = str(e)
-        if failed:
-            for net in net_list[datacenter_key]:
-                net_dict[net] = {'status': "VIM_ERROR", 'error_msg': failed_message}
-
-    # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
-    # 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')
-            net['vim_info']  = net_dict[net_id].get('vim_info')
-            # 5.1. Update in openmano DB the nets whose status changed
-            try:
-                updated = mydb.update_rows('instance_nets', UPDATE=net_dict[net_id], WHERE={'uuid':net["uuid"]})
-                nets_notupdated.remove(net["uuid"])
-                if updated>0:
-                    nets_updated.append(net["uuid"])
-            except db_base_Exception as e:
-                logger.error("nfvo.refresh_instance error database update: %s", str(e))
-
-    # Returns appropriate output
-    #print "nfvo.refresh_instance finishes"
-    logger.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
-                str(vms_updated), str(nets_updated), str(vms_notupdated), str(nets_notupdated))
-    instance_id = instanceDict['uuid']
-    if len(vms_notupdated)+len(nets_notupdated)>0:
-        error_msg = "VMs not updated: " + str(vms_notupdated) + "; nets not updated: " + str(nets_notupdated)
-        return len(vms_notupdated)+len(nets_notupdated), 'Scenario instance ' + instance_id + ' refreshed but some elements could not be updated in the database: ' + error_msg
-
-    return 0, 'Scenario instance ' + instance_id + ' refreshed.'
-
-
-def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
-    #print "Checking that the instance_id exists and getting the instance dictionary"
-    instanceDict = mydb.get_instance_scenario(instance_id, nfvo_tenant)
-    #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
-
-    #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
-    vims = get_vim(mydb, nfvo_tenant, instanceDict['datacenter_id'])
-    if len(vims) == 0:
-        raise NfvoException("datacenter '{}' not found".format(str(instanceDict['datacenter_id'])), HTTP_Not_Found)
-    myvim = vims.values()[0]
-
-
-    input_vnfs = action_dict.pop("vnfs", [])
-    input_vms = action_dict.pop("vms", [])
-    action_over_all = True if len(input_vnfs)==0 and len (input_vms)==0 else False
-    vm_result = {}
-    vm_error = 0
-    vm_ok = 0
-    for sce_vnf in instanceDict['vnfs']:
-        for vm in sce_vnf['vms']:
-            if not action_over_all:
-                if sce_vnf['uuid'] not in input_vnfs and sce_vnf['vnf_name'] not in input_vnfs and \
-                    vm['uuid'] not in input_vms and vm['name'] not in input_vms:
-                    continue
-            try:
-                data = myvim.action_vminstance(vm['vim_vm_id'], action_dict)
-                if "console" in action_dict:
-                    if not global_config["http_console_proxy"]:
-                        vm_result[ vm['uuid'] ] = {"vim_result": 200,
-                                                   "description": "{protocol}//{ip}:{port}/{suffix}".format(
-                                                                                protocol=data["protocol"],
-                                                                                ip = data["server"],
-                                                                                port = data["port"],
-                                                                                suffix = data["suffix"]),
-                                                   "name":vm['name']
-                                                }
-                        vm_ok +=1
-                    elif data["server"]=="127.0.0.1" or data["server"]=="localhost":
-                        vm_result[ vm['uuid'] ] = {"vim_result": -HTTP_Unauthorized,
-                                                   "description": "this console is only reachable by local interface",
-                                                   "name":vm['name']
-                                                }
-                        vm_error+=1
-                    else:
-                    #print "console data", data
-                        try:
-                            console_thread = create_or_use_console_proxy_thread(data["server"], data["port"])
-                            vm_result[ vm['uuid'] ] = {"vim_result": 200,
-                                                       "description": "{protocol}//{ip}:{port}/{suffix}".format(
-                                                                                    protocol=data["protocol"],
-                                                                                    ip = global_config["http_console_host"],
-                                                                                    port = console_thread.port,
-                                                                                    suffix = data["suffix"]),
-                                                       "name":vm['name']
-                                                    }
-                            vm_ok +=1
-                        except NfvoException as e:
-                            vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
-                            vm_error+=1
-
-                else:
-                    vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']}
-                    vm_ok +=1
-            except vimconn.vimconnException as e:
-                vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
-                vm_error+=1
-
-    if vm_ok==0: #all goes wrong
-        return vm_result
-    else:
-        return vm_result
-
-
-def create_or_use_console_proxy_thread(console_server, console_port):
-    #look for a non-used port
-    console_thread_key = console_server + ":" + str(console_port)
-    if console_thread_key in global_config["console_thread"]:
-        #global_config["console_thread"][console_thread_key].start_timeout()
-        return global_config["console_thread"][console_thread_key]
-
-    for port in  global_config["console_port_iterator"]():
-        #print "create_or_use_console_proxy_thread() port:", port
-        if port in global_config["console_ports"]:
-            continue
-        try:
-            clithread = cli.ConsoleProxyThread(global_config['http_host'], port, console_server, console_port)
-            clithread.start()
-            global_config["console_thread"][console_thread_key] = clithread
-            global_config["console_ports"][port] = console_thread_key
-            return clithread
-        except cli.ConsoleProxyExceptionPortUsed as e:
-            #port used, try with onoher
-            continue
-        except cli.ConsoleProxyException as e:
-            raise NfvoException(str(e), HTTP_Bad_Request)
-    raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict)
-
-
-def check_tenant(mydb, tenant_id):
-    '''check that tenant exists at database'''
-    tenant = mydb.get_rows(FROM='nfvo_tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id})
-    if not tenant:
-        raise NfvoException("tenant '{}' not found".format(tenant_id), HTTP_Not_Found)
-    return
-
-
-def new_tenant(mydb, tenant_dict):
-    tenant_id = mydb.new_row("nfvo_tenants", tenant_dict, add_uuid=True)
-    return tenant_id
-
-
-def delete_tenant(mydb, tenant):
-    #get nfvo_tenant info
-
-    tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', tenant, 'tenant')
-    mydb.delete_row_by_id("nfvo_tenants", tenant_dict['uuid'])
-    return tenant_dict['uuid'] + " " + tenant_dict["name"]
-
-
-def new_datacenter(mydb, datacenter_descriptor):
-    if "config" in datacenter_descriptor:
-        datacenter_descriptor["config"]=yaml.safe_dump(datacenter_descriptor["config"],default_flow_style=True,width=256)
-    #Check that datacenter-type is correct
-    datacenter_type = datacenter_descriptor.get("type", "openvim");
-    module_info = None
-    try:
-        module = "vimconn_" + datacenter_type
-        module_info = imp.find_module(module)
-    except (IOError, ImportError):
-        if module_info and module_info[0]:
-            file.close(module_info[0])
-        raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type, module), HTTP_Bad_Request)
-
-    datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True)
-    return datacenter_id
-
-
-def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor):
-    #obtain data, check that only one exist
-    datacenter = mydb.get_table_by_uuid_name('datacenters', datacenter_id_name)
-    #edit data
-    datacenter_id = datacenter['uuid']
-    where={'uuid': datacenter['uuid']}
-    if "config" in datacenter_descriptor:
-        if datacenter_descriptor['config']!=None:
-            try:
-                new_config_dict = datacenter_descriptor["config"]
-                #delete null fields
-                to_delete=[]
-                for k in new_config_dict:
-                    if new_config_dict[k]==None:
-                        to_delete.append(k)
-
-                config_dict = yaml.load(datacenter["config"])
-                config_dict.update(new_config_dict)
-                #delete null fields
-                for k in to_delete:
-                    del config_dict[k]
-            except Exception as e:
-                raise NfvoException("Bad format at datacenter:config " + str(e), HTTP_Bad_Request)
-        datacenter_descriptor["config"]= yaml.safe_dump(config_dict,default_flow_style=True,width=256) if len(config_dict)>0 else None
-    mydb.update_rows('datacenters', datacenter_descriptor, where)
-    return datacenter_id
-
-
-def delete_datacenter(mydb, datacenter):
-    #get nfvo_tenant info
-    datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter, '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, config=None):
-    #get datacenter info
-    datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter)
-    datacenter_name = myvim["name"]
-
-    create_vim_tenant = True if not vim_tenant_id and not vim_tenant_name else False
-
-    # get nfvo_tenant info
-    tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant)
-    if vim_tenant_name==None:
-        vim_tenant_name=tenant_dict['name']
-
-    #check that this association does not exist before
-    tenants_datacenter_dict={"nfvo_tenant_id":tenant_dict['uuid'], "datacenter_id":datacenter_id }
-    tenants_datacenters = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
-    if len(tenants_datacenters)>0:
-        raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id, tenant_dict['uuid']), HTTP_Conflict)
-
-    vim_tenant_id_exist_atdb=False
-    if not create_vim_tenant:
-        where_={"datacenter_id": datacenter_id}
-        if vim_tenant_id!=None:
-            where_["vim_tenant_id"] = vim_tenant_id
-        if vim_tenant_name!=None:
-            where_["vim_tenant_name"] = vim_tenant_name
-        #check if vim_tenant_id is already at database
-        datacenter_tenants_dict = mydb.get_rows(FROM='datacenter_tenants', WHERE=where_)
-        if len(datacenter_tenants_dict)>=1:
-            datacenter_tenants_dict = datacenter_tenants_dict[0]
-            vim_tenant_id_exist_atdb=True
-            #TODO check if a field has changed and edit entry at datacenter_tenants at DB
-        else: #result=0
-            datacenter_tenants_dict = {}
-            #insert at table datacenter_tenants
-    else: #if vim_tenant_id==None:
-        #create tenant at VIM if not provided
-        try:
-            vim_tenant_id = myvim.new_tenant(vim_tenant_name, "created by openmano for datacenter "+datacenter_name)
-        except vimconn.vimconnException as e:
-            raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id, str(e)), HTTP_Internal_Server_Error)
-        datacenter_tenants_dict = {}
-        datacenter_tenants_dict["created"]="true"
-
-    #fill datacenter_tenants table
-    if not vim_tenant_id_exist_atdb:
-        datacenter_tenants_dict["vim_tenant_id"] = vim_tenant_id
-        datacenter_tenants_dict["vim_tenant_name"] = vim_tenant_name
-        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_
-
-    #fill tenants_datacenters table
-    tenants_datacenter_dict["datacenter_tenant_id"]=datacenter_tenants_dict["uuid"]
-    mydb.new_row('tenants_datacenters', tenants_datacenter_dict)
-    # create thread
-    datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_dict['uuid'], datacenter_id)  # reload data
-    thread_name = get_non_used_vim_name(datacenter_name, datacenter_id, tenant_dict['name'], tenant_dict['uuid'])
-    new_thread = vim_thread.vim_thread(myvim, task_lock, thread_name, datacenter_name, db=db, db_lock=db_lock)
-    new_thread.start()
-    thread_id = datacenter_id + "." + tenant_dict['uuid']
-    vim_threads["running"][thread_id] = new_thread
-    return datacenter_id
-
-
-def deassociate_datacenter_to_tenant(mydb, tenant_id, datacenter, vim_tenant_id=None):
-    #get datacenter info
-    datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter)
-
-    #get nfvo_tenant info
-    if not tenant_id or tenant_id=="any":
-        tenant_uuid = None
-    else:
-        tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id)
-        tenant_uuid = tenant_dict['uuid']
-
-    #check that this association exist before
-    tenants_datacenter_dict={"datacenter_id":datacenter_id }
-    if tenant_uuid:
-        tenants_datacenter_dict["nfvo_tenant_id"] = tenant_uuid
-    tenant_datacenter_list = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
-    if len(tenant_datacenter_list)==0 and tenant_uuid:
-        raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id, tenant_dict['uuid']), HTTP_Not_Found)
-
-    #delete this association
-    mydb.delete_row(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
-
-    #get vim_tenant info and deletes
-    warning=''
-    for tenant_datacenter_item in tenant_datacenter_list:
-        vim_tenant_dict = mydb.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item['datacenter_tenant_id'])
-        #try to delete vim:tenant
-        try:
-            mydb.delete_row_by_id('datacenter_tenants', tenant_datacenter_item['datacenter_tenant_id'])
-            if vim_tenant_dict['created']=='true':
-                #delete tenant at VIM if created by NFVO
-                try:
-                    myvim.delete_tenant(vim_tenant_dict['vim_tenant_id'])
-                except vimconn.vimconnException as e:
-                    warning = "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict['vim_tenant_id'], str(e))
-                    logger.warn(warning)
-        except db_base_Exception as e:
-            logger.error("Cannot delete datacenter_tenants " + str(e))
-            pass  # the error will be caused because dependencies, vim_tenant can not be deleted
-        thread_id = datacenter_id + "." + tenant_datacenter_item["nfvo_tenant_id"]
-        thread = vim_threads["running"][thread_id]
-        thread.insert_task(new_task("exit", None, store=False))
-        vim_threads["deleting"][thread_id] = thread
-    return "datacenter {} detached. {}".format(datacenter_id, warning)
-
-
-def datacenter_action(mydb, tenant_id, datacenter, action_dict):
-    #DEPRECATED
-    #get datacenter info
-    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
-
-    if 'net-update' in action_dict:
-        try:
-            nets = myvim.get_network_list(filter_dict={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
-            #print content
-        except vimconn.vimconnException as e:
-            #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
-            raise NfvoException(str(e), HTTP_Internal_Server_Error)
-        #update nets Change from VIM format to NFVO format
-        net_list=[]
-        for net in nets:
-            net_nfvo={'datacenter_id': datacenter_id}
-            net_nfvo['name']       = net['name']
-            #net_nfvo['description']= net['name']
-            net_nfvo['vim_net_id'] = net['id']
-            net_nfvo['type']       = net['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man')  to ('bridge','data','ptp')
-            net_nfvo['shared']     = net['shared']
-            net_nfvo['multipoint'] = False if net['type']=='ptp' else True
-            net_list.append(net_nfvo)
-        inserted, deleted = mydb.update_datacenter_nets(datacenter_id, net_list)
-        logger.info("Inserted %d nets, deleted %d old nets", inserted, deleted)
-        return inserted
-    elif 'net-edit' in action_dict:
-        net = action_dict['net-edit'].pop('net')
-        what = 'vim_net_id' if utils.check_valid_uuid(net) else 'name'
-        result = mydb.update_rows('datacenter_nets', action_dict['net-edit'],
-                                WHERE={'datacenter_id':datacenter_id, what: net})
-        return result
-    elif 'net-delete' in action_dict:
-        net = action_dict['net-deelte'].get('net')
-        what = 'vim_net_id' if utils.check_valid_uuid(net) else 'name'
-        result = mydb.delete_row(FROM='datacenter_nets',
-                                WHERE={'datacenter_id':datacenter_id, what: net})
-        return result
-
-    else:
-        raise NfvoException("Unknown action " + str(action_dict), HTTP_Bad_Request)
-
-
-def datacenter_edit_netmap(mydb, tenant_id, datacenter, netmap, action_dict):
-    #get datacenter info
-    datacenter_id, _  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
-
-    what = 'uuid' if utils.check_valid_uuid(netmap) else 'name'
-    result = mydb.update_rows('datacenter_nets', action_dict['netmap'],
-                            WHERE={'datacenter_id':datacenter_id, what: netmap})
-    return result
-
-
-def datacenter_new_netmap(mydb, tenant_id, datacenter, action_dict=None):
-    #get datacenter info
-    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
-    filter_dict={}
-    if action_dict:
-        action_dict = action_dict["netmap"]
-        if 'vim_id' in action_dict:
-            filter_dict["id"] = action_dict['vim_id']
-        if 'vim_name' in action_dict:
-            filter_dict["name"] = action_dict['vim_name']
-    else:
-        filter_dict["shared"] = True
-
-    try:
-        vim_nets = myvim.get_network_list(filter_dict=filter_dict)
-    except vimconn.vimconnException as e:
-        #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
-        raise NfvoException(str(e), HTTP_Internal_Server_Error)
-    if len(vim_nets)>1 and action_dict:
-        raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict)
-    elif len(vim_nets)==0: # and action_dict:
-        raise NfvoException("Not found a network at VIM with " + str(filter_dict), HTTP_Not_Found)
-    net_list=[]
-    for net in vim_nets:
-        net_nfvo={'datacenter_id': datacenter_id}
-        if action_dict and "name" in action_dict:
-            net_nfvo['name']       = action_dict['name']
-        else:
-            net_nfvo['name']       = net['name']
-        #net_nfvo['description']= net['name']
-        net_nfvo['vim_net_id'] = net['id']
-        net_nfvo['type']       = net['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man')  to ('bridge','data','ptp')
-        net_nfvo['shared']     = net['shared']
-        net_nfvo['multipoint'] = False if net['type']=='ptp' else True
-        try:
-            net_id = mydb.new_row("datacenter_nets", net_nfvo, add_uuid=True)
-            net_nfvo["status"] = "OK"
-            net_nfvo["uuid"] = net_id
-        except db_base_Exception as e:
-            if action_dict:
-                raise
-            else:
-                net_nfvo["status"] = "FAIL: " + str(e)
-        net_list.append(net_nfvo)
-    return net_list
-
-
-def vim_action_get(mydb, tenant_id, datacenter, item, name):
-    #get datacenter info
-    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
-    filter_dict={}
-    if name:
-        if utils.check_valid_uuid(name):
-            filter_dict["id"] = name
-        else:
-            filter_dict["name"] = name
-    try:
-        if item=="networks":
-            #filter_dict['tenant_id'] = myvim['tenant_id']
-            content = myvim.get_network_list(filter_dict=filter_dict)
-        elif item=="tenants":
-            content = myvim.get_tenant_list(filter_dict=filter_dict)
-        elif item == "images":
-            content = myvim.get_image_list(filter_dict=filter_dict)
-        else:
-            raise NfvoException(item + "?", HTTP_Method_Not_Allowed)
-        logger.debug("vim_action response %s", content) #update nets Change from VIM format to NFVO format
-        if name and len(content)==1:
-            return {item[:-1]: content[0]}
-        elif name and len(content)==0:
-            raise NfvoException("No {} found with ".format(item[:-1]) + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), filter_dict.iteritems())),
-                 datacenter)
-        else:
-            return {item: content}
-    except vimconn.vimconnException as e:
-        print "vim_action Not possible to get_%s_list from VIM: %s " % (item, str(e))
-        raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code)
-
-
-def vim_action_delete(mydb, tenant_id, datacenter, item, name):
-    #get datacenter info
-    if tenant_id == "any":
-        tenant_id=None
-
-    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
-    #get uuid name
-    content = vim_action_get(mydb, tenant_id, datacenter, item, name)
-    logger.debug("vim_action_delete vim response: " + str(content))
-    items = content.values()[0]
-    if type(items)==list and len(items)==0:
-        raise NfvoException("Not found " + item, HTTP_Not_Found)
-    elif type(items)==list and len(items)>1:
-        raise NfvoException("Found more than one {} with this name. Use uuid.".format(item), HTTP_Not_Found)
-    else: # it is a dict
-        item_id = items["id"]
-        item_name = str(items.get("name"))
-
-    try:
-        if item=="networks":
-            content = myvim.delete_network(item_id)
-        elif item=="tenants":
-            content = myvim.delete_tenant(item_id)
-        elif item == "images":
-            content = myvim.delete_image(item_id)
-        else:
-            raise NfvoException(item + "?", HTTP_Method_Not_Allowed)
-    except vimconn.vimconnException as e:
-        #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
-        raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item, name, str(e)), e.http_code)
-
-    return "{} {} {} deleted".format(item[:-1], item_id,item_name)
-
-
-def vim_action_create(mydb, tenant_id, datacenter, item, descriptor):
-    #get datacenter info
-    logger.debug("vim_action_create descriptor %s", str(descriptor))
-    if tenant_id == "any":
-        tenant_id=None
-    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
-    try:
-        if item=="networks":
-            net = descriptor["network"]
-            net_name = net.pop("name")
-            net_type = net.pop("type", "bridge")
-            net_public = net.pop("shared", False)
-            net_ipprofile = net.pop("ip_profile", None)
-            net_vlan = net.pop("vlan", None)
-            content = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, vlan=net_vlan) #, **net)
-        elif item=="tenants":
-            tenant = descriptor["tenant"]
-            content = myvim.new_tenant(tenant["name"], tenant.get("description"))
-        else:
-            raise NfvoException(item + "?", HTTP_Method_Not_Allowed)
-    except vimconn.vimconnException as e:
-        raise NfvoException("Not possible to create {} at VIM: {}".format(item, str(e)), e.http_code)
-
-    return vim_action_get(mydb, tenant_id, datacenter, item, content)
diff --git a/nfvo_db.py b/nfvo_db.py
deleted file mode 100644 (file)
index b5ec9a0..0000000
+++ /dev/null
@@ -1,1052 +0,0 @@
-# -*- 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
-##
-
-'''
-NFVO DB engine. It implements all the methods to interact with the Openmano Database
-'''
-__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
-__date__ ="$28-aug-2014 10:05:01$"
-
-import db_base
-import MySQLdb as mdb
-import json
-import yaml
-import time
-#import sys, os
-
-tables_with_createdat_field=["datacenters","instance_nets","instance_scenarios","instance_vms","instance_vnfs",
-                           "interfaces","nets","nfvo_tenants","scenarios","sce_interfaces","sce_nets",
-                           "sce_vnfs","tenants_datacenters","datacenter_tenants","vms","vnfs", "datacenter_nets"]
-
-class nfvo_db(db_base.db_base):
-    def __init__(self, host=None, user=None, passwd=None, database=None, log_name='openmano.db', log_level=None):
-        db_base.db_base.__init__(self, host, user, passwd, database, log_name, log_level)
-        db_base.db_base.tables_with_created_field=tables_with_createdat_field
-        return
-
-    def new_vnf_as_a_whole(self,nfvo_tenant,vnf_name,vnf_descriptor,VNFCDict):
-        self.logger.debug("Adding new vnf to the NFVO database")
-        tries = 2
-        while tries:
-            created_time = time.time()
-            try:
-                with self.con:
-            
-                    myVNFDict = {}
-                    myVNFDict["name"] = vnf_name
-                    myVNFDict["descriptor"] = vnf_descriptor['vnf'].get('descriptor')
-                    myVNFDict["public"] = vnf_descriptor['vnf'].get('public', "false")
-                    myVNFDict["description"] = vnf_descriptor['vnf']['description']
-                    myVNFDict["class"] = vnf_descriptor['vnf'].get('class',"MISC")
-                    myVNFDict["tenant_id"] = vnf_descriptor['vnf'].get("tenant_id")
-                    
-                    vnf_id = self._new_row_internal('vnfs', myVNFDict, add_uuid=True, root_uuid=None, created_time=created_time)
-                    #print "Adding new vms to the NFVO database"
-                    #For each vm, we must create the appropriate vm in the NFVO database.
-                    vmDict = {}
-                    for _,vm in VNFCDict.iteritems():
-                        #This code could make the name of the vms grow and grow.
-                        #If we agree to follow this convention, we should check with a regex that the vnfc name is not including yet the vnf name  
-                        #vm['name'] = "%s-%s" % (vnf_name,vm['name'])
-                        #print "VM name: %s. Description: %s" % (vm['name'], vm['description'])
-                        vm["vnf_id"] = vnf_id
-                        created_time += 0.00001
-                        vm_id = self._new_row_internal('vms', vm, add_uuid=True, root_uuid=vnf_id, created_time=created_time) 
-                        #print "Internal vm id in NFVO DB: %s" % vm_id
-                        vmDict[vm['name']] = vm_id
-                
-                    #Collect the bridge interfaces of each VM/VNFC under the 'bridge-ifaces' field
-                    bridgeInterfacesDict = {}
-                    for vm in vnf_descriptor['vnf']['VNFC']:
-                        if 'bridge-ifaces' in  vm:
-                            bridgeInterfacesDict[vm['name']] = {}
-                            for bridgeiface in vm['bridge-ifaces']:
-                                created_time += 0.00001
-                                if 'port-security' in bridgeiface:
-                                    bridgeiface['port_security'] = bridgeiface.pop('port-security')
-                                if 'floating-ip' in bridgeiface:
-                                    bridgeiface['floating_ip'] = bridgeiface.pop('floating-ip')
-                                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)
-                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['bw'] = bridgeiface.get('bandwidth', None)
-                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['model'] = bridgeiface.get('model', None)
-                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['port_security'] = \
-                                    int(bridgeiface.get('port_security', True))
-                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['floating_ip'] = \
-                                    int(bridgeiface.get('floating_ip', False))
-                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['created_time'] = created_time
-
-                    # Collect the data interfaces of each VM/VNFC under the 'numas' field
-                    dataifacesDict = {}
-                    for vm in vnf_descriptor['vnf']['VNFC']:
-                        dataifacesDict[vm['name']] = {}
-                        for numa in vm.get('numas', []):
-                            for dataiface in numa.get('interfaces', []):
-                                created_time += 0.00001
-                                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']
-                                dataifacesDict[vm['name']][dataiface['name']]['model'] = "PF" if dataiface[
-                                                                                                     'dedicated'] == "yes" else (
-                                "VF" if dataiface['dedicated'] == "no" else "VFnotShared")
-                                dataifacesDict[vm['name']][dataiface['name']]['created_time'] = created_time
-
-                    #For each internal connection, we add it to the interfaceDict and we  create the appropriate net in the NFVO database.
-                    #print "Adding new nets (VNF internal nets) to the NFVO database (if any)"
-                    internalconnList = []
-                    if 'internal-connections' in vnf_descriptor['vnf']:
-                        for net in vnf_descriptor['vnf']['internal-connections']:
-                            #print "Net name: %s. Description: %s" % (net['name'], net['description'])
-                            
-                            myNetDict = {}
-                            myNetDict["name"] = net['name']
-                            myNetDict["description"] = net['description']
-                            myNetDict["type"] = net['type']
-                            myNetDict["vnf_id"] = vnf_id
-                            
-                            created_time += 0.00001
-                            net_id = self._new_row_internal('nets', myNetDict, add_uuid=True, root_uuid=vnf_id, created_time=created_time)
-                                
-                            for element in net['elements']:
-                                ifaceItem = {}
-                                #ifaceItem["internal_name"] = "%s-%s-%s" % (net['name'],element['VNFC'], element['local_iface_name'])  
-                                ifaceItem["internal_name"] = element['local_iface_name']
-                                #ifaceItem["vm_id"] = vmDict["%s-%s" % (vnf_name,element['VNFC'])]
-                                ifaceItem["vm_id"] = vmDict[element['VNFC']]
-                                ifaceItem["net_id"] = net_id
-                                ifaceItem["type"] = net['type']
-                                if ifaceItem ["type"] == "data":
-                                    dataiface = dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]
-                                    ifaceItem["vpci"] =  dataiface['vpci']
-                                    ifaceItem["bw"] =    dataiface['bw']
-                                    ifaceItem["model"] = dataiface['model']
-                                    created_time_iface = dataiface['created_time']
-                                else:
-                                    bridgeiface =  bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]
-                                    ifaceItem["vpci"]          = bridgeiface['vpci']
-                                    ifaceItem["mac"]           = bridgeiface['mac']
-                                    ifaceItem["bw"]            = bridgeiface['bw']
-                                    ifaceItem["model"]         = bridgeiface['model']
-                                    ifaceItem["port_security"] = bridgeiface['port_security']
-                                    ifaceItem["floating_ip"]   = bridgeiface['floating_ip']
-                                    created_time_iface = bridgeiface['created_time']
-                                internalconnList.append(ifaceItem)
-                            #print "Internal net id in NFVO DB: %s" % net_id
-                    
-                    #print "Adding internal interfaces to the NFVO database (if any)"
-                    for iface in internalconnList:
-                        #print "Iface name: %s" % iface['internal_name']
-                        iface_id = self._new_row_internal('interfaces', iface, add_uuid=True, root_uuid=vnf_id, created_time = created_time_iface)
-                        #print "Iface id in NFVO DB: %s" % iface_id
-                    
-                    #print "Adding external interfaces to the NFVO database"
-                    for iface in vnf_descriptor['vnf']['external-connections']:
-                        myIfaceDict = {}
-                        #myIfaceDict["internal_name"] = "%s-%s-%s" % (vnf_name,iface['VNFC'], iface['local_iface_name'])  
-                        myIfaceDict["internal_name"] = iface['local_iface_name']
-                        #myIfaceDict["vm_id"] = vmDict["%s-%s" % (vnf_name,iface['VNFC'])]
-                        myIfaceDict["vm_id"] = vmDict[iface['VNFC']]
-                        myIfaceDict["external_name"] = iface['name']
-                        myIfaceDict["type"] = iface['type']
-                        if iface["type"] == "data":
-                            dataiface = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]
-                            myIfaceDict["vpci"]         = dataiface['vpci']
-                            myIfaceDict["bw"]           = dataiface['bw']
-                            myIfaceDict["model"]        = dataiface['model']
-                            created_time_iface = dataiface['created_time']
-                        else:
-                            bridgeiface = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]
-                            myIfaceDict["vpci"]         = bridgeiface['vpci']
-                            myIfaceDict["bw"]           = bridgeiface['bw']
-                            myIfaceDict["model"]        = bridgeiface['model']
-                            myIfaceDict["mac"]          = bridgeiface['mac']
-                            myIfaceDict["port_security"]= bridgeiface['port_security']
-                            myIfaceDict["floating_ip"]  = bridgeiface['floating_ip']
-                            created_time_iface = bridgeiface['created_time']
-                        #print "Iface name: %s" % iface['name']
-                        iface_id = self._new_row_internal('interfaces', myIfaceDict, add_uuid=True, root_uuid=vnf_id, created_time = created_time_iface)
-                        #print "Iface id in NFVO DB: %s" % iface_id
-                    
-                    return vnf_id
-                
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-        
-    def new_vnf_as_a_whole2(self,nfvo_tenant,vnf_name,vnf_descriptor,VNFCDict):
-        self.logger.debug("Adding new vnf to the NFVO database")
-        tries = 2
-        while tries:
-            created_time = time.time()
-            try:
-                with self.con:
-                     
-                    myVNFDict = {}
-                    myVNFDict["name"] = vnf_name
-                    myVNFDict["descriptor"] = vnf_descriptor['vnf'].get('descriptor')
-                    myVNFDict["public"] = vnf_descriptor['vnf'].get('public', "false")
-                    myVNFDict["description"] = vnf_descriptor['vnf']['description']
-                    myVNFDict["class"] = vnf_descriptor['vnf'].get('class',"MISC")
-                    myVNFDict["tenant_id"] = vnf_descriptor['vnf'].get("tenant_id")
-                    
-                    vnf_id = self._new_row_internal('vnfs', myVNFDict, add_uuid=True, root_uuid=None, created_time=created_time)
-                    #print "Adding new vms to the NFVO database"
-                    #For each vm, we must create the appropriate vm in the NFVO database.
-                    vmDict = {}
-                    for _,vm in VNFCDict.iteritems():
-                        #This code could make the name of the vms grow and grow.
-                        #If we agree to follow this convention, we should check with a regex that the vnfc name is not including yet the vnf name  
-                        #vm['name'] = "%s-%s" % (vnf_name,vm['name'])
-                        #print "VM name: %s. Description: %s" % (vm['name'], vm['description'])
-                        vm["vnf_id"] = vnf_id
-                        created_time += 0.00001
-                        vm_id = self._new_row_internal('vms', vm, add_uuid=True, root_uuid=vnf_id, created_time=created_time) 
-                        #print "Internal vm id in NFVO DB: %s" % vm_id
-                        vmDict[vm['name']] = vm_id
-                     
-                    #Collect the bridge interfaces of each VM/VNFC under the 'bridge-ifaces' field
-                    bridgeInterfacesDict = {}
-                    for vm in vnf_descriptor['vnf']['VNFC']:
-                        if 'bridge-ifaces' in  vm:
-                            bridgeInterfacesDict[vm['name']] = {}
-                            for bridgeiface in vm['bridge-ifaces']:
-                                created_time += 0.00001
-                                db_base._convert_bandwidth(bridgeiface, logger=self.logger)
-                                if 'port-security' in bridgeiface:
-                                    bridgeiface['port_security'] = bridgeiface.pop('port-security')
-                                if 'floating-ip' in bridgeiface:
-                                    bridgeiface['floating_ip'] = bridgeiface.pop('floating-ip')
-                                ifaceDict = {}
-                                ifaceDict['vpci'] = bridgeiface.get('vpci',None)
-                                ifaceDict['mac'] = bridgeiface.get('mac_address',None)
-                                ifaceDict['bw'] = bridgeiface.get('bandwidth', None)
-                                ifaceDict['model'] = bridgeiface.get('model', None)
-                                ifaceDict['port_security'] = int(bridgeiface.get('port_security', True))
-                                ifaceDict['floating_ip'] = int(bridgeiface.get('floating_ip', False))
-                                ifaceDict['created_time'] = created_time
-                                bridgeInterfacesDict[vm['name']][bridgeiface['name']] = ifaceDict
-
-                    # Collect the data interfaces of each VM/VNFC under the 'numas' field
-                    dataifacesDict = {}
-                    for vm in vnf_descriptor['vnf']['VNFC']:
-                        dataifacesDict[vm['name']] = {}
-                        for numa in vm.get('numas', []):
-                            for dataiface in numa.get('interfaces', []):
-                                created_time += 0.00001
-                                db_base._convert_bandwidth(dataiface, logger=self.logger)
-                                ifaceDict = {}
-                                ifaceDict['vpci'] = dataiface['vpci']
-                                ifaceDict['bw'] = dataiface['bandwidth']
-                                ifaceDict['model'] = "PF" if dataiface['dedicated'] == "yes" else \
-                                    ("VF" if dataiface['dedicated'] == "no" else "VFnotShared")
-                                ifaceDict['created_time'] = created_time
-                                dataifacesDict[vm['name']][dataiface['name']] = ifaceDict
-
-                    #For each internal connection, we add it to the interfaceDict and we  create the appropriate net in the NFVO database.
-                    #print "Adding new nets (VNF internal nets) to the NFVO database (if any)"
-                    if 'internal-connections' in vnf_descriptor['vnf']:
-                        for net in vnf_descriptor['vnf']['internal-connections']:
-                            #print "Net name: %s. Description: %s" % (net['name'], net['description'])
-                            
-                            myNetDict = {}
-                            myNetDict["name"] = net['name']
-                            myNetDict["description"] = net['description']
-                            if (net["implementation"] == "overlay"):
-                                net["type"] = "bridge"
-                                #It should give an error if the type is e-line. For the moment, we consider it as a bridge 
-                            elif (net["implementation"] == "underlay"):
-                                if (net["type"] == "e-line"):
-                                    net["type"] = "ptp"
-                                elif (net["type"] == "e-lan"):
-                                    net["type"] = "data"
-                            net.pop("implementation")
-                            myNetDict["type"] = net['type']
-                            myNetDict["vnf_id"] = vnf_id
-                            
-                            created_time += 0.00001
-                            net_id = self._new_row_internal('nets', myNetDict, add_uuid=True, root_uuid=vnf_id, created_time=created_time)
-                            
-                            if "ip-profile" in net:
-                                ip_profile = net["ip-profile"]
-                                myIPProfileDict = {}
-                                myIPProfileDict["net_id"] = net_id
-                                myIPProfileDict["ip_version"] = ip_profile.get('ip-version',"IPv4")
-                                myIPProfileDict["subnet_address"] = ip_profile.get('subnet-address',None)
-                                myIPProfileDict["gateway_address"] = ip_profile.get('gateway-address',None)
-                                myIPProfileDict["dns_address"] = ip_profile.get('dns-address',None)
-                                if ("dhcp" in ip_profile):
-                                    myIPProfileDict["dhcp_enabled"] = ip_profile["dhcp"].get('enabled',"true")
-                                    myIPProfileDict["dhcp_start_address"] = ip_profile["dhcp"].get('start-address',None)
-                                    myIPProfileDict["dhcp_count"] = ip_profile["dhcp"].get('count',None)
-                                
-                                created_time += 0.00001
-                                ip_profile_id = self._new_row_internal('ip_profiles', myIPProfileDict)
-                                
-                            for element in net['elements']:
-                                ifaceItem = {}
-                                #ifaceItem["internal_name"] = "%s-%s-%s" % (net['name'],element['VNFC'], element['local_iface_name'])  
-                                ifaceItem["internal_name"] = element['local_iface_name']
-                                #ifaceItem["vm_id"] = vmDict["%s-%s" % (vnf_name,element['VNFC'])]
-                                ifaceItem["vm_id"] = vmDict[element['VNFC']]
-                                ifaceItem["net_id"] = net_id
-                                ifaceItem["type"] = net['type']
-                                ifaceItem["ip_address"] = element.get('ip_address',None)
-                                if ifaceItem ["type"] == "data":
-                                    ifaceDict = dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]
-                                    ifaceItem["vpci"] =  ifaceDict['vpci']
-                                    ifaceItem["bw"] =    ifaceDict['bw']
-                                    ifaceItem["model"] = ifaceDict['model']
-                                else:
-                                    ifaceDict = bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]
-                                    ifaceItem["vpci"] =  ifaceDict['vpci']
-                                    ifaceItem["mac"] =  ifaceDict['mac']
-                                    ifaceItem["bw"] =    ifaceDict['bw']
-                                    ifaceItem["model"] = ifaceDict['model']
-                                    ifaceItem["port_security"] = ifaceDict['port_security']
-                                    ifaceItem["floating_ip"] = ifaceDict['floating_ip']
-                                created_time_iface = ifaceDict["created_time"]
-                                #print "Iface name: %s" % iface['internal_name']
-                                iface_id = self._new_row_internal('interfaces', ifaceItem, add_uuid=True, root_uuid=vnf_id, created_time=created_time_iface)
-                                #print "Iface id in NFVO DB: %s" % iface_id
-                    
-                    #print "Adding external interfaces to the NFVO database"
-                    for iface in vnf_descriptor['vnf']['external-connections']:
-                        myIfaceDict = {}
-                        #myIfaceDict["internal_name"] = "%s-%s-%s" % (vnf_name,iface['VNFC'], iface['local_iface_name'])  
-                        myIfaceDict["internal_name"] = iface['local_iface_name']
-                        #myIfaceDict["vm_id"] = vmDict["%s-%s" % (vnf_name,iface['VNFC'])]
-                        myIfaceDict["vm_id"] = vmDict[iface['VNFC']]
-                        myIfaceDict["external_name"] = iface['name']
-                        myIfaceDict["type"] = iface['type']
-                        if iface["type"] == "data":
-                            myIfaceDict["vpci"]  = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['vpci']
-                            myIfaceDict["bw"]    = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['bw']
-                            myIfaceDict["model"] = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['model']
-                            created_time_iface = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['created_time']
-                        else:
-                            myIfaceDict["vpci"]  = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['vpci']
-                            myIfaceDict["bw"]    = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['bw']
-                            myIfaceDict["model"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['model']
-                            myIfaceDict["mac"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['mac']
-                            myIfaceDict["port_security"] = \
-                                bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['port_security']
-                            myIfaceDict["floating_ip"] = \
-                                bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['floating_ip']
-                            created_time_iface = bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['created_time']
-                        #print "Iface name: %s" % iface['name']
-                        iface_id = self._new_row_internal('interfaces', myIfaceDict, add_uuid=True, root_uuid=vnf_id, created_time=created_time_iface)
-                        #print "Iface id in NFVO DB: %s" % iface_id
-                    
-                    return vnf_id
-                
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-#             except KeyError as e2:
-#                 exc_type, exc_obj, exc_tb = sys.exc_info()
-#                 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
-#                 self.logger.debug("Exception type: %s; Filename: %s; Line number: %s", exc_type, fname, exc_tb.tb_lineno)
-#                 raise KeyError
-            tries -= 1
-
-    def new_scenario(self, scenario_dict):
-        tries = 2
-        while tries:
-            created_time = time.time()
-            try:
-                with self.con:
-                    self.cur = self.con.cursor()
-                    tenant_id = scenario_dict.get('tenant_id')
-                    #scenario
-                    INSERT_={'tenant_id': tenant_id,
-                             'name': scenario_dict['name'],
-                             'description': scenario_dict['description'],
-                             'public': scenario_dict.get('public', "false")}
-                    
-                    scenario_uuid =  self._new_row_internal('scenarios', INSERT_, add_uuid=True, root_uuid=None, created_time=created_time)
-                    #sce_nets
-                    for net in scenario_dict['nets'].values():
-                        net_dict={'scenario_id': scenario_uuid}
-                        net_dict["name"] = net["name"]
-                        net_dict["type"] = net["type"]
-                        net_dict["description"] = net.get("description")
-                        net_dict["external"] = net.get("external", False)
-                        if "graph" in net:
-                            #net["graph"]=yaml.safe_dump(net["graph"],default_flow_style=True,width=256)
-                            #TODO, must be json because of the GUI, change to yaml
-                            net_dict["graph"]=json.dumps(net["graph"])
-                        created_time += 0.00001
-                        net_uuid =  self._new_row_internal('sce_nets', net_dict, add_uuid=True, root_uuid=scenario_uuid, created_time=created_time)
-                        net['uuid']=net_uuid
-
-                        if net.get("ip-profile"):
-                            ip_profile = net["ip-profile"]
-                            myIPProfileDict = {
-                                "sce_net_id": net_uuid,
-                                "ip_version": ip_profile.get('ip-version', "IPv4"),
-                                "subnet_address": ip_profile.get('subnet-address'),
-                                "gateway_address": ip_profile.get('gateway-address'),
-                                "dns_address": ip_profile.get('dns-address')}
-                            if "dhcp" in ip_profile:
-                                myIPProfileDict["dhcp_enabled"] = ip_profile["dhcp"].get('enabled', "true")
-                                myIPProfileDict["dhcp_start_address"] = ip_profile["dhcp"].get('start-address')
-                                myIPProfileDict["dhcp_count"] = ip_profile["dhcp"].get('count')
-                            self._new_row_internal('ip_profiles', myIPProfileDict)
-
-                    # sce_vnfs
-                    for k, vnf in scenario_dict['vnfs'].items():
-                        INSERT_ = {'scenario_id': scenario_uuid,
-                                   'name': k,
-                                   'vnf_id': vnf['uuid'],
-                                   # 'description': scenario_dict['name']
-                                   'description': vnf['description']}
-                        if "graph" in vnf:
-                            #I NSERT_["graph"]=yaml.safe_dump(vnf["graph"],default_flow_style=True,width=256)
-                            # TODO, must be json because of the GUI, change to yaml
-                            INSERT_["graph"] = json.dumps(vnf["graph"])
-                        created_time += 0.00001
-                        scn_vnf_uuid = self._new_row_internal('sce_vnfs', INSERT_, add_uuid=True,
-                                                              root_uuid=scenario_uuid, created_time=created_time)
-                        vnf['scn_vnf_uuid']=scn_vnf_uuid
-                        # sce_interfaces
-                        for iface in vnf['ifaces'].values():
-                            # print 'iface', iface
-                            if 'net_key' not in iface:
-                                continue
-                            iface['net_id'] = scenario_dict['nets'][ iface['net_key'] ]['uuid']
-                            INSERT_={'sce_vnf_id': scn_vnf_uuid,
-                                     'sce_net_id': iface['net_id'],
-                                     'interface_id':  iface['uuid'],
-                                     'ip_address': iface.get('ip_address')}
-                            created_time += 0.00001
-                            iface_uuid = self._new_row_internal('sce_interfaces', INSERT_, add_uuid=True,
-                                                                 root_uuid=scenario_uuid, created_time=created_time)
-                            
-                    return scenario_uuid
-                    
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-    def edit_scenario(self, scenario_dict):
-        tries = 2
-        while tries:
-            modified_time = time.time()
-            item_changed=0
-            try:
-                with self.con:
-                    self.cur = self.con.cursor()
-                    #check that scenario exist
-                    tenant_id = scenario_dict.get('tenant_id')
-                    scenario_uuid = scenario_dict['uuid']
-                    
-                    where_text = "uuid='{}'".format(scenario_uuid)
-                    if not tenant_id and tenant_id != "any":
-                        where_text += " AND (tenant_id='{}' OR public='True')".format(tenant_id)
-                    cmd = "SELECT * FROM scenarios WHERE "+ where_text
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    self.cur.fetchall()
-                    if self.cur.rowcount==0:
-                        raise db_base.db_base_Exception("No scenario found with this criteria " + where_text, db_base.HTTP_Bad_Request)
-                    elif self.cur.rowcount>1:
-                        raise db_base.db_base_Exception("More than one scenario found with this criteria " + where_text, db_base.HTTP_Bad_Request)
-
-                    #scenario
-                    nodes = {}
-                    topology = scenario_dict.pop("topology", None)
-                    if topology != None and "nodes" in topology:
-                        nodes = topology.get("nodes",{})
-                    UPDATE_ = {}
-                    if "name" in scenario_dict:        UPDATE_["name"] = scenario_dict["name"]
-                    if "description" in scenario_dict: UPDATE_["description"] = scenario_dict["description"]
-                    if len(UPDATE_)>0:
-                        WHERE_={'tenant_id': tenant_id, 'uuid': scenario_uuid}
-                        item_changed += self._update_rows('scenarios', UPDATE_, WHERE_, modified_time=modified_time)
-                    #sce_nets
-                    for node_id, node in nodes.items():
-                        if "graph" in node:
-                            #node["graph"] = yaml.safe_dump(node["graph"],default_flow_style=True,width=256)
-                            #TODO, must be json because of the GUI, change to yaml
-                            node["graph"] = json.dumps(node["graph"])
-                        WHERE_={'scenario_id': scenario_uuid, 'uuid': node_id}
-                        #Try to change at sce_nets(version 0 API backward compatibility and sce_vnfs)
-                        item_changed += self._update_rows('sce_nets', node, WHERE_)
-                        item_changed += self._update_rows('sce_vnfs', node, WHERE_, modified_time=modified_time)
-                    return item_changed
-                    
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-#     def get_instance_scenario(self, instance_scenario_id, tenant_id=None):
-#         '''Obtain the scenario instance information, filtering by one or serveral of the tenant, uuid or name
-#         instance_scenario_id is the uuid or the name if it is not a valid uuid format
-#         Only one scenario isntance must mutch the filtering or an error is returned
-#         ''' 
-#         print "1******************************************************************"
-#         try:
-#             with self.con:
-#                 self.cur = self.con.cursor(mdb.cursors.DictCursor)
-#                 #scenario table
-#                 where_list=[]
-#                 if tenant_id is not None: where_list.append( "tenant_id='" + tenant_id +"'" )
-#                 if db_base._check_valid_uuid(instance_scenario_id):
-#                     where_list.append( "uuid='" + instance_scenario_id +"'" )
-#                 else:
-#                     where_list.append( "name='" + instance_scenario_id +"'" )
-#                 where_text = " AND ".join(where_list)
-#                 self.cur.execute("SELECT * FROM instance_scenarios WHERE "+ where_text)
-#                 rows = self.cur.fetchall()
-#                 if self.cur.rowcount==0:
-#                     return -HTTP_Bad_Request, "No scenario instance found with this criteria " + where_text
-#                 elif self.cur.rowcount>1:
-#                     return -HTTP_Bad_Request, "More than one scenario instance found with this criteria " + where_text
-#                 instance_scenario_dict = rows[0]
-#                 
-#                 #instance_vnfs
-#                 self.cur.execute("SELECT uuid,vnf_id FROM instance_vnfs WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
-#                 instance_scenario_dict['instance_vnfs'] = self.cur.fetchall()
-#                 for vnf in instance_scenario_dict['instance_vnfs']:
-#                     #instance_vms
-#                     self.cur.execute("SELECT uuid, vim_vm_id "+
-#                                 "FROM instance_vms  "+
-#                                 "WHERE instance_vnf_id='" + vnf['uuid'] +"'"  
-#                                 )
-#                     vnf['instance_vms'] = self.cur.fetchall()
-#                 #instance_nets
-#                 self.cur.execute("SELECT uuid, vim_net_id FROM instance_nets WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
-#                 instance_scenario_dict['instance_nets'] = self.cur.fetchall()
-#                 
-#                 #instance_interfaces
-#                 self.cur.execute("SELECT uuid, vim_interface_id, instance_vm_id, instance_net_id FROM instance_interfaces WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
-#                 instance_scenario_dict['instance_interfaces'] = self.cur.fetchall()
-#                 
-#                 db_base._convert_datetime2str(instance_scenario_dict)
-#                 db_base._convert_str2boolean(instance_scenario_dict, ('public','shared','external') )
-#                 print "2******************************************************************"
-#                 return 1, instance_scenario_dict
-#         except (mdb.Error, AttributeError) as e:
-#             print "nfvo_db.get_instance_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
-#             return self._format_error(e)
-
-    def get_scenario(self, scenario_id, tenant_id=None, datacenter_id=None):
-        '''Obtain the scenario information, filtering by one or serveral of the tenant, uuid or name
-        scenario_id is the uuid or the name if it is not a valid uuid format
-        if datacenter_id is provided, it supply aditional vim_id fields with the matching vim uuid 
-        Only one scenario must mutch the filtering or an error is returned
-        ''' 
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
-                    where_text = "uuid='{}'".format(scenario_id)
-                    if not tenant_id and tenant_id != "any":
-                        where_text += " AND (tenant_id='{}' OR public='True')".format(tenant_id)
-                    cmd = "SELECT * FROM scenarios WHERE " + where_text
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    rows = self.cur.fetchall()
-                    if self.cur.rowcount==0:
-                        raise db_base.db_base_Exception("No scenario found with this criteria " + where_text, db_base.HTTP_Bad_Request)
-                    elif self.cur.rowcount>1:
-                        raise db_base.db_base_Exception("More than one scenario found with this criteria " + where_text, db_base.HTTP_Bad_Request)
-                    scenario_dict = rows[0]
-                    if scenario_dict["cloud_config"]:
-                        scenario_dict["cloud-config"] = yaml.load(scenario_dict["cloud_config"])
-                    del scenario_dict["cloud_config"]
-                    #sce_vnfs
-                    cmd = "SELECT uuid,name,vnf_id,description FROM sce_vnfs WHERE scenario_id='{}' ORDER BY created_at".format(scenario_dict['uuid'])
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    scenario_dict['vnfs'] = self.cur.fetchall()
-                    for vnf in scenario_dict['vnfs']:
-                        #sce_interfaces
-                        cmd = "SELECT scei.uuid,scei.sce_net_id,scei.interface_id,i.external_name,scei.ip_address FROM sce_interfaces as scei join interfaces as i on scei.interface_id=i.uuid WHERE scei.sce_vnf_id='{}' ORDER BY scei.created_at".format(vnf['uuid'])
-                        self.logger.debug(cmd)
-                        self.cur.execute(cmd)
-                        vnf['interfaces'] = self.cur.fetchall()
-                        #vms
-                        cmd = "SELECT vms.uuid as uuid, flavor_id, image_id, vms.name as name, vms.description as description, vms.boot_data as boot_data " \
-                                " FROM vnfs join vms on vnfs.uuid=vms.vnf_id " \
-                                " WHERE vnfs.uuid='" + vnf['vnf_id'] +"'"  \
-                                " ORDER BY vms.created_at"
-                        self.logger.debug(cmd)
-                        self.cur.execute(cmd)
-                        vnf['vms'] = self.cur.fetchall()
-                        for vm in vnf['vms']:
-                            if vm["boot_data"]:
-                                vm["boot_data"] = yaml.safe_load(vm["boot_data"])
-                            else:
-                                del vm["boot_data"]
-                            if datacenter_id!=None:
-                                cmd = "SELECT vim_id FROM datacenters_images WHERE image_id='{}' AND datacenter_id='{}'".format(vm['image_id'],datacenter_id)
-                                self.logger.debug(cmd)
-                                self.cur.execute(cmd) 
-                                if self.cur.rowcount==1:
-                                    vim_image_dict = self.cur.fetchone()
-                                    vm['vim_image_id']=vim_image_dict['vim_id']
-                                cmd = "SELECT vim_id FROM datacenters_flavors WHERE flavor_id='{}' AND datacenter_id='{}'".format(vm['flavor_id'],datacenter_id)
-                                self.logger.debug(cmd)
-                                self.cur.execute(cmd) 
-                                if self.cur.rowcount==1:
-                                    vim_flavor_dict = self.cur.fetchone()
-                                    vm['vim_flavor_id']=vim_flavor_dict['vim_id']
-                                
-                            #interfaces
-                            cmd = "SELECT uuid,internal_name,external_name,net_id,type,vpci,mac,bw,model,ip_address," \
-                                  "floating_ip, port_security" \
-                                    " FROM interfaces" \
-                                    " WHERE vm_id='{}'" \
-                                    " ORDER BY created_at".format(vm['uuid'])
-                            self.logger.debug(cmd)
-                            self.cur.execute(cmd)
-                            vm['interfaces'] = self.cur.fetchall()
-                            for index in range(0,len(vm['interfaces'])):
-                                vm['interfaces'][index]['port-security'] = vm['interfaces'][index].pop("port_security")
-                                vm['interfaces'][index]['floating-ip'] = vm['interfaces'][index].pop("floating_ip")
-                        #nets    every net of a vms
-                        cmd = "SELECT uuid,name,type,description FROM nets WHERE vnf_id='{}'".format(vnf['vnf_id'])  
-                        self.logger.debug(cmd)
-                        self.cur.execute(cmd)
-                        vnf['nets'] = self.cur.fetchall()
-                        for vnf_net in vnf['nets']:
-                            SELECT_ = "ip_version,subnet_address,gateway_address,dns_address,dhcp_enabled,dhcp_start_address,dhcp_count"
-                            cmd = "SELECT {} FROM ip_profiles WHERE net_id='{}'".format(SELECT_,vnf_net['uuid'])  
-                            self.logger.debug(cmd)
-                            self.cur.execute(cmd)
-                            ipprofiles = self.cur.fetchall()
-                            if self.cur.rowcount==1:
-                                vnf_net["ip_profile"] = ipprofiles[0]
-                            elif self.cur.rowcount>1:
-                                raise db_base.db_base_Exception("More than one ip-profile found with this criteria: net_id='{}'".format(vnf_net['uuid']), db_base.HTTP_Bad_Request)
-                            
-                    #sce_nets
-                    cmd = "SELECT uuid,name,type,external,description" \
-                          " FROM sce_nets  WHERE scenario_id='{}'" \
-                          " ORDER BY created_at ".format(scenario_dict['uuid'])
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    scenario_dict['nets'] = self.cur.fetchall()
-                    #datacenter_nets
-                    for net in scenario_dict['nets']:
-                        if str(net['external']) == 'false':
-                            SELECT_ = "ip_version,subnet_address,gateway_address,dns_address,dhcp_enabled,dhcp_start_address,dhcp_count"
-                            cmd = "SELECT {} FROM ip_profiles WHERE sce_net_id='{}'".format(SELECT_,net['uuid'])  
-                            self.logger.debug(cmd)
-                            self.cur.execute(cmd)
-                            ipprofiles = self.cur.fetchall()
-                            if self.cur.rowcount==1:
-                                net["ip_profile"] = ipprofiles[0]
-                            elif self.cur.rowcount>1:
-                                raise db_base.db_base_Exception("More than one ip-profile found with this criteria: sce_net_id='{}'".format(net['uuid']), db_base.HTTP_Bad_Request)
-                            continue
-                        WHERE_=" WHERE name='{}'".format(net['name'])
-                        if datacenter_id!=None:
-                            WHERE_ += " AND datacenter_id='{}'".format(datacenter_id)
-                        cmd = "SELECT vim_net_id FROM datacenter_nets" + WHERE_
-                        self.logger.debug(cmd)
-                        self.cur.execute(cmd) 
-                        d_net = self.cur.fetchone()
-                        if d_net==None or datacenter_id==None:
-                            #print "nfvo_db.get_scenario() WARNING external net %s not found"  % net['name']
-                            net['vim_id']=None
-                        else:
-                            net['vim_id']=d_net['vim_net_id']
-                    
-                    db_base._convert_datetime2str(scenario_dict)
-                    db_base._convert_str2boolean(scenario_dict, ('public','shared','external','port-security','floating-ip') )
-                    return scenario_dict
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-    def delete_scenario(self, scenario_id, tenant_id=None):
-        '''Deletes a scenario, filtering by one or several of the tenant, uuid or name
-        scenario_id is the uuid or the name if it is not a valid uuid format
-        Only one scenario must mutch the filtering or an error is returned
-        ''' 
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
-    
-                    #scenario table
-                    where_text = "uuid='{}'".format(scenario_id)
-                    if not tenant_id and tenant_id != "any":
-                        where_text += " AND (tenant_id='{}' OR public='True')".format(tenant_id)
-                    cmd = "SELECT * FROM scenarios WHERE "+ where_text
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    rows = self.cur.fetchall()
-                    if self.cur.rowcount==0:
-                        raise db_base.db_base_Exception("No scenario found where " + where_text, db_base.HTTP_Bad_Request)
-                    elif self.cur.rowcount>1:
-                        raise db_base.db_base_Exception("More than one scenario found where " + where_text, db_base.HTTP_Bad_Request)
-                    scenario_uuid = rows[0]["uuid"]
-                    scenario_name = rows[0]["name"]
-                    
-                    #sce_vnfs
-                    cmd = "DELETE FROM scenarios WHERE uuid='{}'".format(scenario_uuid)
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-    
-                    return scenario_uuid + " " + scenario_name
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries, "delete", "instances running")
-            tries -= 1
-
-    def new_instance_scenario_as_a_whole(self,tenant_id,instance_scenario_name,instance_scenario_description,scenarioDict):
-        tries = 2
-        while tries:
-            created_time = time.time()
-            try:
-                with self.con:
-                    self.cur = self.con.cursor()
-                    #instance_scenarios
-                    datacenter_id = scenarioDict['datacenter_id']
-                    INSERT_={'tenant_id': tenant_id,
-                        'datacenter_tenant_id': scenarioDict["datacenter2tenant"][datacenter_id],
-                        'name': instance_scenario_name,
-                        'description': instance_scenario_description,
-                        'scenario_id' : scenarioDict['uuid'],
-                        'datacenter_id': datacenter_id
-                    }
-                    if scenarioDict.get("cloud-config"):
-                        INSERT_["cloud_config"] = yaml.safe_dump(scenarioDict["cloud-config"], default_flow_style=True, width=256)
-
-                    instance_uuid = self._new_row_internal('instance_scenarios', INSERT_, add_uuid=True, root_uuid=None, created_time=created_time)
-                    
-                    net_scene2instance={}
-                    #instance_nets   #nets interVNF
-                    for net in scenarioDict['nets']:
-                        net_scene2instance[ net['uuid'] ] ={}
-                        datacenter_site_id = net.get('datacenter_id', datacenter_id)
-                        if not "vim_id_sites" in net:
-                            net["vim_id_sites"] ={datacenter_site_id: net['vim_id']}
-                            net["vim_id_sites"]["datacenter_site_id"] = {datacenter_site_id: net['vim_id']}
-                        sce_net_id = net.get("uuid")
-                        
-                        for datacenter_site_id,vim_id in net["vim_id_sites"].iteritems():
-                            INSERT_={'vim_net_id': vim_id, 'created': net.get('created', False), 'instance_scenario_id':instance_uuid } #,  'type': net['type']
-                            INSERT_['datacenter_id'] = datacenter_site_id 
-                            INSERT_['datacenter_tenant_id'] = scenarioDict["datacenter2tenant"][datacenter_site_id]
-                            if sce_net_id:
-                                INSERT_['sce_net_id'] = sce_net_id
-                            created_time += 0.00001
-                            instance_net_uuid =  self._new_row_internal('instance_nets', INSERT_, True, instance_uuid, created_time)
-                            net_scene2instance[ sce_net_id ][datacenter_site_id] = instance_net_uuid
-                            net['uuid'] = instance_net_uuid  #overwrite scnario uuid by instance uuid
-                        
-                        if 'ip_profile' in net:
-                            net['ip_profile']['net_id'] = None
-                            net['ip_profile']['sce_net_id'] = None
-                            net['ip_profile']['instance_net_id'] = instance_net_uuid
-                            created_time += 0.00001
-                            ip_profile_id = self._new_row_internal('ip_profiles', net['ip_profile'])
-                    
-                    #instance_vnfs
-                    for vnf in scenarioDict['vnfs']:
-                        datacenter_site_id = vnf.get('datacenter_id', datacenter_id)
-                        INSERT_={'instance_scenario_id': instance_uuid,  'vnf_id': vnf['vnf_id']  }
-                        INSERT_['datacenter_id'] = datacenter_site_id 
-                        INSERT_['datacenter_tenant_id'] = scenarioDict["datacenter2tenant"][datacenter_site_id]
-                        if vnf.get("uuid"):
-                            INSERT_['sce_vnf_id'] = vnf['uuid']
-                        created_time += 0.00001
-                        instance_vnf_uuid =  self._new_row_internal('instance_vnfs', INSERT_, True, instance_uuid, created_time)
-                        vnf['uuid'] = instance_vnf_uuid  #overwrite scnario uuid by instance uuid
-                        
-                        #instance_nets   #nets intraVNF
-                        for net in vnf['nets']:
-                            net_scene2instance[ net['uuid'] ] = {}
-                            INSERT_={'vim_net_id': net['vim_id'], 'created': net.get('created', False), 'instance_scenario_id':instance_uuid  } #,  'type': net['type']
-                            INSERT_['datacenter_id'] = net.get('datacenter_id', datacenter_site_id) 
-                            INSERT_['datacenter_tenant_id'] = scenarioDict["datacenter2tenant"][datacenter_id]
-                            if net.get("uuid"):
-                                INSERT_['net_id'] = net['uuid']
-                            created_time += 0.00001
-                            instance_net_uuid =  self._new_row_internal('instance_nets', INSERT_, True, instance_uuid, created_time)
-                            net_scene2instance[ net['uuid'] ][datacenter_site_id] = instance_net_uuid
-                            net['uuid'] = instance_net_uuid  #overwrite scnario uuid by instance uuid
-                            
-                            if 'ip_profile' in net:
-                                net['ip_profile']['net_id'] = None
-                                net['ip_profile']['sce_net_id'] = None
-                                net['ip_profile']['instance_net_id'] = instance_net_uuid
-                                created_time += 0.00001
-                                ip_profile_id = self._new_row_internal('ip_profiles', net['ip_profile'])
-
-                        #instance_vms
-                        for vm in vnf['vms']:
-                            INSERT_={'instance_vnf_id': instance_vnf_uuid,  'vm_id': vm['uuid'], 'vim_vm_id': vm['vim_id']  }
-                            created_time += 0.00001
-                            instance_vm_uuid =  self._new_row_internal('instance_vms', INSERT_, True, instance_uuid, created_time)
-                            vm['uuid'] = instance_vm_uuid  #overwrite scnario uuid by instance uuid
-                            
-                            #instance_interfaces
-                            for interface in vm['interfaces']:
-                                net_id = interface.get('net_id', None)
-                                if net_id is None:
-                                    #check if is connected to a inter VNFs net
-                                    for iface in vnf['interfaces']:
-                                        if iface['interface_id'] == interface['uuid']:
-                                            if 'ip_address' in iface:
-                                                interface['ip_address'] = iface['ip_address']
-                                            net_id = iface.get('sce_net_id', None)
-                                            break
-                                if net_id is None:
-                                    continue
-                                interface_type='external' if interface['external_name'] is not None else 'internal'
-                                INSERT_={'instance_vm_id': instance_vm_uuid,  'instance_net_id': net_scene2instance[net_id][datacenter_site_id],
-                                    'interface_id': interface['uuid'], 'vim_interface_id': interface.get('vim_id'), 'type':  interface_type,
-                                    'ip_address': interface.get('ip_address'), 'floating_ip': int(interface.get('floating-ip',False)),
-                                    'port_security': int(interface.get('port-security',True))}
-                                #created_time += 0.00001
-                                interface_uuid =  self._new_row_internal('instance_interfaces', INSERT_, True, instance_uuid) #, created_time)
-                                interface['uuid'] = interface_uuid  #overwrite scnario uuid by instance uuid
-                return instance_uuid
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-    def get_instance_scenario(self, instance_id, tenant_id=None, verbose=False):
-        '''Obtain the instance information, filtering by one or several of the tenant, uuid or name
-        instance_id is the uuid or the name if it is not a valid uuid format
-        Only one instance must mutch the filtering or an error is returned
-        ''' 
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
-                    #instance table
-                    where_list=[]
-                    if tenant_id is not None: where_list.append( "inst.tenant_id='" + tenant_id +"'" )
-                    if db_base._check_valid_uuid(instance_id):
-                        where_list.append( "inst.uuid='" + instance_id +"'" )
-                    else:
-                        where_list.append( "inst.name='" + instance_id +"'" )
-                    where_text = " AND ".join(where_list)
-                    cmd = "SELECT inst.uuid as uuid,inst.name as name,inst.scenario_id as scenario_id, datacenter_id" +\
-                                " ,datacenter_tenant_id, s.name as scenario_name,inst.tenant_id as tenant_id" + \
-                                " ,inst.description as description,inst.created_at as created_at" +\
-                                " ,inst.cloud_config as 'cloud_config'" +\
-                            " FROM instance_scenarios as inst join scenarios as s on inst.scenario_id=s.uuid"+\
-                            " WHERE " + where_text
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    rows = self.cur.fetchall()
-                    
-                    if self.cur.rowcount==0:
-                        raise db_base.db_base_Exception("No instance found where " + where_text, db_base.HTTP_Not_Found)
-                    elif self.cur.rowcount>1:
-                        raise db_base.db_base_Exception("More than one instance found where " + where_text, db_base.HTTP_Bad_Request)
-                    instance_dict = rows[0]
-                    if instance_dict["cloud_config"]:
-                        instance_dict["cloud-config"] = yaml.load(instance_dict["cloud_config"])
-                    del instance_dict["cloud_config"]
-                    
-                    #instance_vnfs
-                    cmd = "SELECT iv.uuid as uuid,sv.vnf_id as vnf_id,sv.name as vnf_name, sce_vnf_id, datacenter_id, datacenter_tenant_id"\
-                            " FROM instance_vnfs as iv join sce_vnfs as sv on iv.sce_vnf_id=sv.uuid" \
-                            " WHERE iv.instance_scenario_id='{}'" \
-                            " ORDER BY iv.created_at ".format(instance_dict['uuid'])
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    instance_dict['vnfs'] = self.cur.fetchall()
-                    for vnf in instance_dict['vnfs']:
-                        vnf_manage_iface_list=[]
-                        #instance vms
-                        cmd = "SELECT iv.uuid as uuid, vim_vm_id, status, error_msg, vim_info, iv.created_at as created_at, name "\
-                                " FROM instance_vms as iv join vms on iv.vm_id=vms.uuid "\
-                                " WHERE instance_vnf_id='{}' ORDER BY iv.created_at".format(vnf['uuid'])
-                        self.logger.debug(cmd)
-                        self.cur.execute(cmd)
-                        vnf['vms'] = self.cur.fetchall()
-                        for vm in vnf['vms']:
-                            vm_manage_iface_list=[]
-                            #instance_interfaces
-                            cmd = "SELECT vim_interface_id, instance_net_id, internal_name,external_name, mac_address,"\
-                                  " ii.ip_address as ip_address, vim_info, i.type as type"\
-                                  " FROM instance_interfaces as ii join interfaces as i on ii.interface_id=i.uuid"\
-                                  " WHERE instance_vm_id='{}' ORDER BY created_at".format(vm['uuid'])
-                            self.logger.debug(cmd)
-                            self.cur.execute(cmd )
-                            vm['interfaces'] = self.cur.fetchall()
-                            for iface in vm['interfaces']:
-                                if iface["type"] == "mgmt" and iface["ip_address"]:
-                                    vnf_manage_iface_list.append(iface["ip_address"])
-                                    vm_manage_iface_list.append(iface["ip_address"])
-                                if not verbose:
-                                    del iface["type"]
-                            if vm_manage_iface_list: vm["ip_address"] = ",".join(vm_manage_iface_list)
-                        if vnf_manage_iface_list: vnf["ip_address"] = ",".join(vnf_manage_iface_list)
-                        
-                    #instance_nets
-                    #select_text = "instance_nets.uuid as uuid,sce_nets.name as net_name,instance_nets.vim_net_id as net_id,instance_nets.status as status,instance_nets.external as external" 
-                    #from_text = "instance_nets join instance_scenarios on instance_nets.instance_scenario_id=instance_scenarios.uuid " + \
-                    #            "join sce_nets on instance_scenarios.scenario_id=sce_nets.scenario_id"
-                    #where_text = "instance_nets.instance_scenario_id='"+ instance_dict['uuid'] + "'"
-                    cmd = "SELECT uuid,vim_net_id,status,error_msg,vim_info,created, sce_net_id, net_id as vnf_net_id, datacenter_id, datacenter_tenant_id"\
-                            " FROM instance_nets" \
-                            " WHERE instance_scenario_id='{}' ORDER BY created_at".format(instance_dict['uuid'])
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    instance_dict['nets'] = self.cur.fetchall()
-                    
-                    db_base._convert_datetime2str(instance_dict)
-                    db_base._convert_str2boolean(instance_dict, ('public','shared','created') )
-                    return instance_dict
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-        
-    def delete_instance_scenario(self, instance_id, tenant_id=None):
-        '''Deletes a instance_Scenario, filtering by one or serveral of the tenant, uuid or name
-        instance_id is the uuid or the name if it is not a valid uuid format
-        Only one instance_scenario must mutch the filtering or an error is returned
-        ''' 
-        tries = 2
-        while tries:
-            try:
-                with self.con:
-                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
-    
-                    #instance table
-                    where_list=[]
-                    if tenant_id is not None: where_list.append( "tenant_id='" + tenant_id +"'" )
-                    if db_base._check_valid_uuid(instance_id):
-                        where_list.append( "uuid='" + instance_id +"'" )
-                    else:
-                        where_list.append( "name='" + instance_id +"'" )
-                    where_text = " AND ".join(where_list)
-                    cmd = "SELECT * FROM instance_scenarios WHERE "+ where_text
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    rows = self.cur.fetchall()
-                    
-                    if self.cur.rowcount==0:
-                        raise db_base.db_base_Exception("No instance found where " + where_text, db_base.HTTP_Bad_Request)
-                    elif self.cur.rowcount>1:
-                        raise db_base.db_base_Exception("More than one instance found where " + where_text, db_base.HTTP_Bad_Request)
-                    instance_uuid = rows[0]["uuid"]
-                    instance_name = rows[0]["name"]
-                    
-                    #sce_vnfs
-                    cmd = "DELETE FROM instance_scenarios WHERE uuid='{}'".format(instance_uuid)
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-    
-                    return instance_uuid + " " + instance_name
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries, "delete", "No dependences can avoid deleting!!!!")
-            tries -= 1
-    
-    def new_instance_scenario(self, instance_scenario_dict, tenant_id):
-        #return self.new_row('vnfs', vnf_dict, None, tenant_id, True, True)
-        return self._new_row_internal('instance_scenarios', instance_scenario_dict, tenant_id, add_uuid=True, root_uuid=None, log=True)
-
-    def update_instance_scenario(self, instance_scenario_dict):
-        #TODO:
-        return
-
-    def new_instance_vnf(self, instance_vnf_dict, tenant_id, instance_scenario_id = None):
-        #return self.new_row('vms', vm_dict, tenant_id, True, True)
-        return self._new_row_internal('instance_vnfs', instance_vnf_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
-
-    def update_instance_vnf(self, instance_vnf_dict):
-        #TODO:
-        return
-    
-    def delete_instance_vnf(self, instance_vnf_id):
-        #TODO:
-        return
-
-    def new_instance_vm(self, instance_vm_dict, tenant_id, instance_scenario_id = None):
-        #return self.new_row('vms', vm_dict, tenant_id, True, True)
-        return self._new_row_internal('instance_vms', instance_vm_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
-
-    def update_instance_vm(self, instance_vm_dict):
-        #TODO:
-        return
-    
-    def delete_instance_vm(self, instance_vm_id):
-        #TODO:
-        return
-
-    def new_instance_net(self, instance_net_dict, tenant_id, instance_scenario_id = None):
-        return self._new_row_internal('instance_nets', instance_net_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
-    
-    def update_instance_net(self, instance_net_dict):
-        #TODO:
-        return
-
-    def delete_instance_net(self, instance_net_id):
-        #TODO:
-        return
-    
-    def new_instance_interface(self, instance_interface_dict, tenant_id, instance_scenario_id = None):
-        return self._new_row_internal('instance_interfaces', instance_interface_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
-
-    def update_instance_interface(self, instance_interface_dict):
-        #TODO:
-        return
-
-    def delete_instance_interface(self, instance_interface_dict):
-        #TODO:
-        return
-
-    def update_datacenter_nets(self, datacenter_id, new_net_list=[]):
-        ''' Removes the old and adds the new net list at datacenter list for one datacenter.
-        Attribute 
-            datacenter_id: uuid of the datacenter to act upon
-            table: table where to insert
-            new_net_list: the new values to be inserted. If empty it only deletes the existing nets
-        Return: (Inserted items, Deleted items) if OK, (-Error, text) if error
-        '''
-        tries = 2
-        while tries:
-            created_time = time.time()
-            try:
-                with self.con:
-                    self.cur = self.con.cursor()
-                    cmd="DELETE FROM datacenter_nets WHERE datacenter_id='{}'".format(datacenter_id)
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    deleted = self.cur.rowcount
-                    inserted = 0
-                    for new_net in new_net_list:
-                        created_time += 0.00001
-                        self._new_row_internal('datacenter_nets', new_net, add_uuid=True, created_time=created_time)
-                        inserted += 1
-                    return inserted, deleted
-            except (mdb.Error, AttributeError) as e:
-                self._format_error(e, tries)
-            tries -= 1
-
-        
diff --git a/openmano.service b/openmano.service
deleted file mode 100644 (file)
index cc8966c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-[Unit]
-Description=openmano server (OSM RO)
-
-[Service]
-User=${USER_OWNER}
-ExecStart=openmanod -c /etc/osm/openmanod.cfg --log-file=/var/log/osm/openmano.log
-Restart=always
-
-[Install]
-WantedBy=multi-user.target
-
diff --git a/openmano_schemas.py b/openmano_schemas.py
deleted file mode 100644 (file)
index 1ea64f6..0000000
+++ /dev/null
@@ -1,1097 +0,0 @@
-# -*- 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
-##
-
-'''
-JSON schemas used by openmano httpserver.py module to parse the different files and messages sent through the API 
-'''
-__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
-__date__ ="$09-oct-2014 09:09:48$"
-
-#Basis schemas
-patern_name="^[ -~]+$"
-passwd_schema={"type" : "string", "minLength":1, "maxLength":60}
-nameshort_schema={"type" : "string", "minLength":1, "maxLength":60, "pattern" : "^[^,;()'\"]+$"}
-name_schema={"type" : "string", "minLength":1, "maxLength":255, "pattern" : "^[^,;()'\"]+$"}
-xml_text_schema={"type" : "string", "minLength":1, "maxLength":1000, "pattern" : "^[^']+$"}
-description_schema={"type" : ["string","null"], "maxLength":255, "pattern" : "^[^'\"]+$"}
-id_schema_fake = {"type" : "string", "minLength":2, "maxLength":36 }  #"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"
-id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
-pci_schema={"type":"string", "pattern":"^[0-9a-fA-F]{4}(:[0-9a-fA-F]{2}){2}\.[0-9a-fA-F]$"}
-http_schema={"type":"string", "pattern":"^https?://[^'\"=]+$"}
-bandwidth_schema={"type":"string", "pattern" : "^[0-9]+ *([MG]bps)?$"}
-memory_schema={"type":"string", "pattern" : "^[0-9]+ *([MG]i?[Bb])?$"}
-integer0_schema={"type":"integer","minimum":0}
-integer1_schema={"type":"integer","minimum":1}
-path_schema={"type":"string", "pattern":"^(\.){0,2}(/[^/\"':{}\(\)]+)+$"}
-vlan_schema={"type":"integer","minimum":1,"maximum":4095}
-vlan1000_schema={"type":"integer","minimum":1000,"maximum":4095}
-mac_schema={"type":"string", "pattern":"^[0-9a-fA-F][02468aceACE](:[0-9a-fA-F]{2}){5}$"}  #must be unicast LSB bit of MSB byte ==0 
-#mac_schema={"type":"string", "pattern":"^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$"}
-ip_schema={"type":"string","pattern":"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"}
-ip_prefix_schema={"type":"string","pattern":"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/(30|[12]?[0-9])$"}
-port_schema={"type":"integer","minimum":1,"maximum":65534}
-object_schema={"type":"object"}
-schema_version_2={"type":"integer","minimum":2,"maximum":2}
-#schema_version_string={"type":"string","enum": ["0.1", "2", "0.2", "3", "0.3"]}
-log_level_schema={"type":"string", "enum":["DEBUG", "INFO", "WARNING","ERROR","CRITICAL"]}
-checksum_schema={"type":"string", "pattern":"^[0-9a-fA-F]{32}$"}
-size_schema={"type":"integer","minimum":1,"maximum":100}
-
-metadata_schema={
-    "type":"object",
-    "properties":{
-        "architecture": {"type":"string"},
-        "use_incremental": {"type":"string","enum":["yes","no"]},
-        "vpci": pci_schema,
-        "os_distro": {"type":"string"},
-        "os_type": {"type":"string"},
-        "os_version": {"type":"string"},
-        "bus": {"type":"string"},
-        "topology": {"type":"string", "enum": ["oneSocket"]}
-    }
-}
-
-#Schema for the configuration file
-config_schema = {
-    "title":"configuration response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "http_port": port_schema,
-        "http_admin_port": port_schema,
-        "http_host": nameshort_schema,
-        "auto_push_VNF_to_VIMs": {"type":"boolean"},
-        "vnf_repository": path_schema,
-        "db_host": nameshort_schema,
-        "db_user": nameshort_schema,
-        "db_passwd": {"type":"string"},
-        "db_name": nameshort_schema,
-        # Next fields will disappear once the MANO API includes appropriate primitives
-        "vim_url": http_schema,
-        "vim_url_admin": http_schema,
-        "vim_name": nameshort_schema,
-        "vim_tenant_name": nameshort_schema,
-        "mano_tenant_name": nameshort_schema,
-        "mano_tenant_id": id_schema, 
-        "http_console_proxy": {"type":"boolean"},
-        "http_console_host": nameshort_schema,
-        "http_console_ports": {
-            "type": "array", 
-            "items": {"OneOf" : [
-                port_schema, 
-                {"type":"object", "properties":{"from": port_schema, "to": port_schema}, "required": ["from","to"]} 
-            ]}
-        },
-        "log_level": log_level_schema,
-        "log_socket_level": log_level_schema,
-        "log_level_db": log_level_schema,
-        "log_level_vim": log_level_schema,
-        "log_level_nfvo": log_level_schema,
-        "log_level_http": log_level_schema,
-        "log_level_console": log_level_schema,
-        "log_file_db": path_schema,
-        "log_file_vim": path_schema,
-        "log_file_nfvo": path_schema,
-        "log_file_http": path_schema,
-        "log_file_console": path_schema,
-        "log_socket_host": nameshort_schema,
-        "log_socket_port": port_schema,
-        "log_file": path_schema,
-    },
-    "required": ['db_host', 'db_user', 'db_passwd', 'db_name'],
-    "additionalProperties": False
-}
-
-tenant_schema = {
-    "title":"tenant information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "tenant":{
-            "type":"object",
-            "properties":{
-                "name": nameshort_schema,
-                "description": description_schema,
-            },
-            "required": ["name"],
-            "additionalProperties": True
-        }
-    },
-    "required": ["tenant"],
-    "additionalProperties": False
-}
-
-tenant_edit_schema = {
-    "title":"tenant edit information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "tenant":{
-            "type":"object",
-            "properties":{
-                "name": name_schema,
-                "description": description_schema,
-            },
-            "additionalProperties": False
-        }
-    },
-    "required": ["tenant"],
-    "additionalProperties": False
-}
-
-datacenter_schema_properties={
-    "name": name_schema,
-    "description": description_schema,
-    "type": nameshort_schema, #currently "openvim" or "openstack", can be enlarged with plugins
-    "vim_url": description_schema,
-    "vim_url_admin": description_schema,
-    "config": { "type":"object" }
-}
-
-datacenter_schema = {
-    "title":"datacenter information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "datacenter":{
-            "type":"object",
-            "properties":datacenter_schema_properties,
-            "required": ["name", "vim_url"],
-            "additionalProperties": True
-        }
-    },
-    "required": ["datacenter"],
-    "additionalProperties": False
-}
-
-
-datacenter_edit_schema = {
-    "title":"datacenter edit nformation schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "datacenter":{
-            "type":"object",
-            "properties":datacenter_schema_properties,
-            "additionalProperties": False
-        }
-    },
-    "required": ["datacenter"],
-    "additionalProperties": False
-}
-
-
-netmap_new_schema = {
-    "title":"netmap new information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "netmap":{   #delete from datacenter
-            "type":"object",
-            "properties":{
-                "name": name_schema,  #name or uuid of net to change
-                "vim_id": id_schema,
-                "vim_name": name_schema
-            },
-            "minProperties": 1,
-            "additionalProperties": False
-        },
-    },
-    "required": ["netmap"],
-    "additionalProperties": False
-}
-
-netmap_edit_schema = {
-    "title":"netmap edit information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "netmap":{   #delete from datacenter
-            "type":"object",
-            "properties":{
-                "name": name_schema,  #name or uuid of net to change
-            },
-            "minProperties": 1,
-            "additionalProperties": False
-        },
-    },
-    "required": ["netmap"],
-    "additionalProperties": False
-}
-
-datacenter_action_schema = {
-    "title":"datacenter action information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "net-update":{"type":"null",},
-        "net-edit":{
-            "type":"object",
-            "properties":{
-                "net": name_schema,  #name or uuid of net to change
-                "name": name_schema,
-                "description": description_schema,
-                "shared": {"type": "boolean"}
-            },
-            "minProperties": 1,
-            "additionalProperties": False
-        },
-        "net-delete":{
-            "type":"object",
-            "properties":{
-                "net": name_schema,  #name or uuid of net to change
-            },
-            "required": ["net"],
-            "additionalProperties": False
-        },
-    },
-    "minProperties": 1,
-    "maxProperties": 1,
-    "additionalProperties": False
-}
-
-
-datacenter_associate_schema={
-    "title":"datacenter associate information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "datacenter":{
-            "type":"object",
-            "properties":{
-                "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
-        }
-    },
-    "required": ["datacenter"],
-    "additionalProperties": False
-}
-
-dhcp_schema = {
-    "title":"DHCP schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "enabled": {"type": "boolean"},
-        "start-address": ip_schema,
-        "count": integer1_schema
-    },
-    "required": ["enabled", "start-address", "count"],
-}
-
-ip_profile_schema = {
-    "title":"IP profile schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "ip-version": {"type":"string", "enum":["IPv4","IPv6"]},
-        "subnet-address": ip_prefix_schema,
-        "gateway-address": ip_schema,
-        "dns-address": ip_schema,
-        "dhcp": dhcp_schema
-    },
-}
-
-key_pair_schema = {
-    "title": "Key-pair schema for cloud-init configuration schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "name": name_schema,
-        "key": {"type":"string"}
-    },
-    "required": ["key"],
-    "additionalProperties": False
-}
-
-cloud_config_user_schema = {
-    "title": "User schema for cloud-init configuration schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "name": nameshort_schema,
-        "user-info": {"type":"string"},
-        #"key-pairs": {"type" : "array", "items": key_pair_schema}
-        "key-pairs": {"type" : "array", "items": {"type":"string"}}
-    },
-    "required": ["name"],
-    "additionalProperties": False
-}
-
-cloud_config_schema = {
-    "title": "Cloud-init configuration schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        #"key-pairs": {"type" : "array", "items": key_pair_schema},
-        "key-pairs": {"type" : "array", "items": {"type":"string"}},
-        "users": {"type" : "array", "items": cloud_config_user_schema}
-    },
-    "additionalProperties": False
-}
-
-internal_connection_element_schema = {
-    "type":"object",
-    "properties":{
-        "VNFC": name_schema,
-        "local_iface_name": name_schema
-    }
-}
-
-internal_connection_element_schema_v02 = {
-    "type":"object",
-    "properties":{
-        "VNFC": name_schema,
-        "local_iface_name": name_schema,
-        "ip_address": ip_schema
-    }
-}
-
-internal_connection_schema = {
-    "type":"object",
-    "properties":{
-        "name": name_schema,
-        "description":description_schema,
-        "type":{"type":"string", "enum":["bridge","data","ptp"]},
-        "elements": {"type" : "array", "items": internal_connection_element_schema, "minItems":2}
-    },
-    "required": ["name", "type", "elements"],
-    "additionalProperties": False
-}
-
-internal_connection_schema_v02 = {
-    "type":"object",
-    "properties":{
-        "name": name_schema,
-        "description":description_schema,
-        "type": {"type": "string", "enum":["e-line", "e-lan"]},
-        "implementation": {"type": "string", "enum":["overlay", "underlay"]},
-        "ip-profile": ip_profile_schema,
-        "elements": {"type" : "array", "items": internal_connection_element_schema_v02, "minItems":2}
-    },
-    "required": ["name", "type", "implementation", "elements"],
-    "additionalProperties": False
-}
-
-external_connection_schema = {
-    "type":"object",
-    "properties":{
-        "name": name_schema,
-        "type":{"type":"string", "enum":["mgmt","bridge","data"]},
-        "VNFC": name_schema,
-        "local_iface_name": name_schema ,
-        "description":description_schema
-    },
-    "required": ["name", "type", "VNFC", "local_iface_name"],
-    "additionalProperties": False
-}
-
-#Not yet used
-external_connection_schema_v02 = {
-    "type":"object",
-    "properties":{
-        "name": name_schema,
-        "mgmt": {"type":"boolean"},
-        "type": {"type": "string", "enum":["e-line", "e-lan"]}, 
-        "implementation": {"type": "string", "enum":["overlay", "underlay"]},
-        "VNFC": name_schema,
-        "local_iface_name": name_schema ,
-        "description":description_schema
-    },
-    "required": ["name", "type", "VNFC", "local_iface_name"],
-    "additionalProperties": False
-}
-
-interfaces_schema={
-    "type":"array",
-    "items":{
-        "type":"object",
-        "properties":{
-            "name":name_schema,
-            "dedicated":{"type":"string","enum":["yes","no","yes:sriov"]},
-            "bandwidth":bandwidth_schema,
-            "vpci":pci_schema,
-            "mac_address": mac_schema
-        },
-        "additionalProperties": False,
-        "required": ["name","dedicated", "bandwidth"]
-    }
-}
-
-bridge_interfaces_schema={
-    "type":"array",
-    "items":{
-        "type":"object",
-        "properties":{
-            "name": name_schema,
-            "bandwidth":bandwidth_schema,
-            "vpci":pci_schema,
-            "mac_address": mac_schema,
-            "model": {"type":"string", "enum":["virtio","e1000","ne2k_pci","pcnet","rtl8139"]},
-            "port-security": {"type" : "boolean"},
-            "floating-ip": {"type" : "boolean"}
-        },
-        "additionalProperties": False,
-        "required": ["name"]
-    }
-}
-
-devices_schema={
-    "type":"array",
-    "items":{
-        "type":"object",
-        "properties":{
-            "type":{"type":"string", "enum":["disk","cdrom","xml"] },
-            "image": path_schema,
-            "image name": name_schema,
-            "image checksum": checksum_schema,
-            "image metadata": metadata_schema,
-            "size": size_schema,
-            "vpci":pci_schema,
-            "xml":xml_text_schema,
-        },
-        "additionalProperties": False,
-        "required": ["type"]
-    }
-}
-
-
-numa_schema = {
-    "type": "object",
-    "properties": {
-        "memory":integer1_schema,
-        "cores":integer1_schema,
-        "paired-threads":integer1_schema,
-        "threads":integer1_schema,
-        "cores-id":{"type":"array","items":integer0_schema},
-        "paired-threads-id":{"type":"array","items":{"type":"array","minItems":2,"maxItems":2,"items":integer0_schema}},
-        "threads-id":{"type":"array","items":integer0_schema},
-        "interfaces":interfaces_schema
-    },
-    "additionalProperties": False,
-    #"required": ["memory"]
-}
-
-config_files_schema = {
-    "title": "Config files for cloud init schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type": "object",
-    "properties": {
-        "dest": path_schema,
-        "encoding": {"type": "string", "enum": ["b64", "base64", "gz", "gz+b64", "gz+base64", "gzip+b64", "gzip+base64"]},  #by default text
-        "content": {"type": "string"},
-        "permissions": {"type": "string"}, # tiypically octal notation '0644'
-        "owner": {"type": "string"},  # format:   owner:group
-
-    },
-    "additionalProperties": False,
-    "required": ["dest", "content"],
-}
-
-boot_data_vdu_schema  = {
-    "title": "Boot data (Cloud-init) configuration schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type": "object",
-    "properties":{
-        "key-pairs": {"type" : "array", "items": {"type":"string"}},
-        "users": {"type" : "array", "items": cloud_config_user_schema},
-        "user-data": {"type" : "string"},  # scrip to run
-        "config-files": {"type": "array", "items": config_files_schema},
-        # NOTE: “user-data” are mutually exclusive with users and config-files because user/files are injected using user-data
-        "boot-data-drive": {"type": "boolean"},
-    },
-    "additionalProperties": False,
-}
-
-vnfc_schema = {
-    "type":"object",
-    "properties":{
-        "name": name_schema,
-        "description": description_schema,
-        "VNFC image": {"oneOf": [path_schema, http_schema]},
-        "image name": name_schema,
-        "image checksum": checksum_schema,
-        "image metadata": metadata_schema, 
-        #"cloud-config": cloud_config_schema, #common for all vnfs in the scenario
-        "processor": {
-            "type":"object",
-            "properties":{
-                "model":description_schema,
-                "features":{"type":"array","items":nameshort_schema}
-            },
-            "required": ["model"],
-            "additionalProperties": False
-        },
-        "hypervisor": {
-            "type":"object",
-            "properties":{
-                "type":nameshort_schema,
-                "version":description_schema
-            },
-        },
-        "ram":integer0_schema,
-        "vcpus":integer0_schema,
-        "disk": integer1_schema,
-        "numas": {
-            "type": "array",
-            "items": numa_schema
-        },
-        "bridge-ifaces": bridge_interfaces_schema,
-        "devices": devices_schema,
-        "boot-data" : boot_data_vdu_schema
-        
-    },
-    "required": ["name"],
-    "oneOf": [
-        {"required": ["VNFC image"]},
-        {"required": ["image name"]}
-    ],
-    "additionalProperties": False
-}
-
-vnfd_schema_v01 = {
-    "title":"vnfd information schema v0.1",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "vnf":{
-            "type":"object",
-            "properties":{
-                "name": name_schema,
-                "description": description_schema,
-                "class": nameshort_schema,
-                "public": {"type" : "boolean"},
-                "physical": {"type" : "boolean"},
-                "tenant_id": id_schema, #only valid for admin
-                "external-connections": {"type" : "array", "items": external_connection_schema, "minItems":1},
-                "internal-connections": {"type" : "array", "items": internal_connection_schema, "minItems":1},
-                "VNFC":{"type" : "array", "items": vnfc_schema, "minItems":1}
-            },
-            "required": ["name","external-connections"],
-            "additionalProperties": True
-        }
-    },
-    "required": ["vnf"],
-    "additionalProperties": False
-}
-
-#VNFD schema for OSM R1 
-vnfd_schema_v02 = {
-    "title":"vnfd information schema v0.2",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "schema_version": {"type": "string", "enum": ["0.2"]},
-        "vnf":{
-            "type":"object",
-            "properties":{
-                "name": name_schema,
-                "description": description_schema,
-                "class": nameshort_schema,
-                "public": {"type" : "boolean"},
-                "physical": {"type" : "boolean"},
-                "tenant_id": id_schema, #only valid for admin
-                "external-connections": {"type" : "array", "items": external_connection_schema, "minItems":1},
-                "internal-connections": {"type" : "array", "items": internal_connection_schema_v02, "minItems":1},
-                # "cloud-config": cloud_config_schema, #common for all vnfcs
-                "VNFC":{"type" : "array", "items": vnfc_schema, "minItems":1}
-            },
-            "required": ["name"],
-            "additionalProperties": True
-        }
-    },
-    "required": ["vnf", "schema_version"],
-    "additionalProperties": False
-}
-
-#vnfd_schema = vnfd_schema_v01
-#{
-#    "title":"vnfd information schema v0.2",
-#    "$schema": "http://json-schema.org/draft-04/schema#",
-#    "oneOf": [vnfd_schema_v01, vnfd_schema_v02]
-#}
-
-graph_schema = {
-    "title":"graphical scenario descriptor information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "x":      integer0_schema,
-        "y":      integer0_schema,
-        "ifaces": {
-            "type":"object",
-            "properties":{
-                "left": {"type":"array"},
-                "right": {"type":"array"},
-                "bottom": {"type":"array"},
-            }
-        }
-    },
-    "required": ["x","y"]
-}
-
-nsd_schema_v01 = {
-    "title":"network scenario descriptor information schema v0.1",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "name":name_schema,
-        "description": description_schema,
-        "tenant_id": id_schema, #only valid for admin
-        "public": {"type": "boolean"},
-        "topology":{
-            "type":"object",
-            "properties":{
-                "nodes": {
-                    "type":"object",
-                    "patternProperties":{
-                        ".": {
-                            "type": "object",
-                            "properties":{
-                                "type":{"type":"string", "enum":["VNF", "other_network", "network", "external_network"]},
-                                "vnf_id": id_schema,
-                                "graph": graph_schema,
-                            },
-                            "patternProperties":{
-                                "^(VNF )?model$": {"type": "string"}
-                            },
-                            "required": ["type"]
-                        }
-                    }
-                },
-                "connections": {
-                    "type":"object",
-                    "patternProperties":{
-                        ".": {
-                            "type": "object",
-                            "properties":{
-                                "nodes":{"oneOf":[{"type":"object", "minProperties":2}, {"type":"array", "minLength":1}]},
-                                "type": {"type": "string", "enum":["link", "external_network", "dataplane_net", "bridge_net"]},
-                                "graph": graph_schema
-                            },
-                            "required": ["nodes"]
-                        },
-                    }
-                }
-            },
-            "required": ["nodes"],
-            "additionalProperties": False
-        }
-    },
-    "required": ["name","topology"],
-    "additionalProperties": False
-}
-
-nsd_schema_v02 = {
-    "title":"network scenario descriptor information schema v0.2",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "schema_version": schema_version_2,
-        "scenario":{
-            "type":"object",
-            "properties":{
-                "name": name_schema,
-                "description": description_schema,
-                "tenant_id": id_schema, #only valid for admin
-                "public": {"type": "boolean"},
-                "vnfs": {
-                    "type":"object",
-                    "patternProperties":{
-                        ".": {
-                            "type": "object",
-                            "properties":{
-                                "vnf_id": id_schema,
-                                "graph": graph_schema,
-                                "vnf_name": name_schema,
-                            },
-                        }
-                    },
-                    "minProperties": 1
-                },
-                "networks": {
-                    "type":"object",
-                    "patternProperties":{
-                        ".": {
-                            "type": "object",
-                            "properties":{
-                                "interfaces":{"type":"array", "minLength":1},
-                                "type": {"type": "string", "enum":["dataplane", "bridge"]},
-                                "external" : {"type": "boolean"},
-                                "graph": graph_schema
-                            },
-                            "required": ["interfaces"]
-                        },
-                    }
-                },
-            
-            },
-            "required": ["vnfs", "name"],
-            "additionalProperties": False
-        }
-    },
-    "required": ["scenario","schema_version"],
-    "additionalProperties": False
-}
-
-#NSD schema for OSM R1
-nsd_schema_v03 = {
-    "title":"network scenario descriptor information schema v0.3",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "schema_version": {"type": "string", "enum": ["0.3"]},
-        "scenario":{
-            "type":"object",
-            "properties":{
-                "name": name_schema,
-                "description": description_schema,
-                "tenant_id": id_schema, #only valid for admin
-                "public": {"type": "boolean"},
-                "cloud-config": cloud_config_schema, #common for all vnfs in the scenario
-                #"datacenter": name_schema,
-                "vnfs": {
-                    "type":"object",
-                    "patternProperties":{
-                        ".": {
-                            "type": "object",
-                            "properties":{
-                                "vnf_id": id_schema,
-                                "graph": graph_schema,
-                                "vnf_name": name_schema,
-                                #"cloud-config": cloud_config_schema, #particular for a vnf
-                                #"datacenter": name_schema,
-                                "internal-connections": {
-                                    "type": "object",
-                                    "patternProperties": {
-                                        ".": {
-                                            "type": "object",
-                                            "properties": {
-                                                "ip-profile": ip_profile_schema,
-                                                "elements": {
-                                                    "type" : "array",
-                                                    "items":{
-                                                        "type":"object",
-                                                        "properties":{
-                                                            "VNFC": name_schema,
-                                                            "local_iface_name": name_schema,
-                                                            "ip_address": ip_schema
-                                                        },
-                                                        "required": ["VNFC", "local_iface_name"],
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            },
-                        }
-                    },
-                    "minProperties": 1
-                },
-                "networks": {
-                    "type":"object",
-                    "patternProperties":{
-                        ".": {
-                            "type": "object",
-                            "properties":{
-                                "interfaces":{
-                                    "type":"array",
-                                    "minLength":1,
-                                    "items":{
-                                        "type":"object",
-                                        "properties":{
-                                            "vnf": name_schema,
-                                            "vnf_interface": name_schema,
-                                            "ip_address": ip_schema
-                                        },
-                                        "required": ["vnf", "vnf_interface"],
-                                    }
-                                },
-                                "type": {"type": "string", "enum":["e-line", "e-lan"]},
-                                "implementation": {"type": "string", "enum":["overlay", "underlay"]},
-                                "external" : {"type": "boolean"},
-                                "graph": graph_schema,
-                                "ip-profile": ip_profile_schema
-                            },
-                            "required": ["interfaces"]
-                        },
-                    }
-                },
-            
-            },
-            "required": ["vnfs", "networks","name"],
-            "additionalProperties": False
-        }
-    },
-    "required": ["scenario","schema_version"],
-    "additionalProperties": False
-}
-
-#scenario_new_schema = {
-#    "title":"new scenario information schema",
-#    "$schema": "http://json-schema.org/draft-04/schema#",
-#    #"oneOf": [nsd_schema_v01, nsd_schema_v02]
-#    "oneOf": [nsd_schema_v01]
-#}
-
-scenario_edit_schema = {
-    "title":"edit scenario information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "name":name_schema,
-        "description": description_schema,
-        "topology":{
-            "type":"object",
-            "properties":{
-                "nodes": {
-                    "type":"object",
-                    "patternProperties":{
-                        "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$": {
-                            "type":"object",
-                            "properties":{
-                                "graph":{
-                                    "type": "object",
-                                    "properties":{
-                                        "x": integer0_schema,
-                                        "y": integer0_schema,
-                                        "ifaces":{ "type": "object"}
-                                    }
-                                },
-                                "description": description_schema,
-                                "name": name_schema
-                            }
-                        }
-                    }
-                }
-            },
-            "required": ["nodes"],
-            "additionalProperties": False
-        }
-    },
-    "additionalProperties": False
-}
-
-scenario_action_schema = {
-    "title":"scenario action information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "start":{
-            "type": "object",
-            "properties": {
-                "instance_name":name_schema,
-                "description":description_schema,
-                "datacenter": {"type": "string"}
-            },
-            "required": ["instance_name"]
-        },
-        "deploy":{
-            "type": "object",
-            "properties": {
-                "instance_name":name_schema,
-                "description":description_schema,
-                "datacenter": {"type": "string"}
-            },
-            "required": ["instance_name"]
-        },
-        "reserve":{
-            "type": "object",
-            "properties": {
-                "instance_name":name_schema,
-                "description":description_schema,
-                "datacenter": {"type": "string"}
-            },
-            "required": ["instance_name"]
-        },
-        "verify":{
-            "type": "object",
-            "properties": {
-                "instance_name":name_schema,
-                "description":description_schema,
-                "datacenter": {"type": "string"}
-            },
-            "required": ["instance_name"]
-        }
-    },
-    "minProperties": 1,
-    "maxProperties": 1,
-    "additionalProperties": False
-}
-
-instance_scenario_create_schema_v01 = {
-    "title":"instance scenario create information schema v0.1",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "schema_version": {"type": "string", "enum": ["0.1"]},
-        "instance":{
-            "type":"object",
-            "properties":{
-                "name":name_schema,
-                "description":description_schema,
-                "datacenter": name_schema,
-                "scenario" : name_schema, #can be an UUID or name
-                "action":{"enum": ["deploy","reserve","verify" ]},
-                "connect_mgmt_interfaces": {"oneOf": [{"type":"boolean"}, {"type":"object"}]},# can be true or a dict with datacenter: net_name
-                "cloud-config": cloud_config_schema, #common to all vnfs in the instance scenario
-                "vnfs":{             #mapping from scenario to datacenter
-                    "type": "object",
-                    "patternProperties":{
-                        ".": {
-                            "type": "object",
-                            "properties":{
-                                "name": name_schema, #override vnf name
-                                "datacenter": name_schema,
-                                #"metadata": {"type": "object"},
-                                #"user_data": {"type": "string"}
-                                #"cloud-config": cloud_config_schema, #particular for a vnf
-                                "external-connections": {
-                                    "type": "object",
-                                    "patternProperties": {
-                                        ".": {
-                                            "type": "object",
-                                            "properties": {
-                                                "vim-network-name": name_schema,
-                                                "ip_address": ip_schema
-                                            } 
-                                        }
-                                    }
-                                },
-                                "internal-connections": {
-                                    "type": "object",
-                                    "patternProperties": {
-                                        ".": {
-                                            "type": "object",
-                                            "properties": {
-                                                "ip-profile": ip_profile_schema,
-                                                "elements": {
-                                                    "type" : "array",
-                                                    "items":{
-                                                        "type":"object",
-                                                        "properties":{
-                                                            "VNFC": name_schema,
-                                                            "local_iface_name": name_schema,
-                                                            "ip_address": ip_schema
-                                                        },
-                                                        "required": ["VNFC", "local_iface_name"],
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    },
-                },
-                "networks":{             #mapping from scenario to datacenter
-                    "type": "object",
-                    "patternProperties":{
-                        ".": {
-                            "type": "object",
-                            "properties":{
-                                "interfaces":{
-                                    "type":"array",
-                                    "minLength":1,
-                                    "items":{
-                                        "type":"object",
-                                        "properties":{
-                                            "ip_address": ip_schema,
-                                            "datacenter": name_schema,
-                                            "vim-network-name": name_schema
-                                        },
-                                        "patternProperties":{
-                                            ".": {"type": "string"}
-                                        }
-                                    }
-                                },
-                                "ip-profile": ip_profile_schema,
-                                #if the network connects VNFs deployed at different sites, you must specify one entry per site that this network connect to 
-                                "sites": {
-                                    "type":"array",
-                                    "minLength":1,
-                                    "items":{
-                                        "type":"object",
-                                        "properties":{
-                                            # By default for an scenario 'external' network openmano looks for an existing VIM network to map this external scenario network,
-                                            # for other networks openamno creates at VIM
-                                            # Use netmap-create to force to create an external scenario network  
-                                            "netmap-create": {"oneOf":[name_schema,{"type": "null"}]}, #datacenter network to use. Null if must be created as an internal net
-                                            #netmap-use:   Indicates an existing VIM network that must be used for this scenario network. 
-                                            #Can use both the VIM network name (if it is not ambiguous) or the VIM net UUID
-                                            #If both 'netmap-create' and 'netmap-use'are supplied, netmap-use precedes, but if fails openmano follows the netmap-create
-                                            #In oder words, it is the same as 'try to map to the VIM network (netmap-use) if exist, and if not create the network (netmap-create)
-                                            "netmap-use": name_schema, # 
-                                            "vim-network-name": name_schema, #override network name
-                                            #"ip-profile": ip_profile_schema,
-                                            "datacenter": name_schema,                                        
-                                        }
-                                    }
-                                },
-                                
-
-
-                            }
-                        }
-                    },
-                },
-            },
-            "additionalProperties": False,
-            "required": ["name"]
-        },
-    },
-    "required": ["instance"],
-    "additionalProperties": False
-}
-
-instance_scenario_action_schema = {
-    "title":"instance scenario action information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "start":{"type": "null"},
-        "pause":{"type": "null"},
-        "resume":{"type": "null"},
-        "shutoff":{"type": "null"},
-        "shutdown":{"type": "null"},
-        "forceOff":{"type": "null"},
-        "rebuild":{"type": "null"},
-        "reboot":{
-            "type": ["object","null"],
-        },
-        "console": {"type": ["string", "null"], "enum": ["novnc", "xvpvnc", "rdp-html5", "spice-html5", None]},
-        "vnfs":{"type": "array", "items":{"type":"string"}},
-        "vms":{"type": "array", "items":{"type":"string"}}
-    },
-    "minProperties": 1,
-    #"maxProperties": 1,
-    "additionalProperties": False
-}
diff --git a/openmanoclient.py b/openmanoclient.py
deleted file mode 100644 (file)
index c11f747..0000000
+++ /dev/null
@@ -1,916 +0,0 @@
-#!/usr/bin/env python3
-# -*- 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
-##
-
-'''
-openmano python client used to interact with openmano-server  
-'''
-__author__="Alfonso Tierno"
-__date__ ="$09-Mar-2016 09:09:48$"
-__version__="0.0.1-r467"
-version_date="Mar 2016"
-
-import requests
-import json
-import yaml
-import logging
-import sys
-if  sys.version_info.major == 3:
-    from urllib.parse import quote
-elif sys.version_info.major == 2:
-    from urllib import quote
-
-class OpenmanoException(Exception):
-    '''Common Exception for all openmano client exceptions'''
-
-class OpenmanoBadParamsException(OpenmanoException):
-    '''Bad or missing input parameters'''
-
-class OpenmanoResponseException(OpenmanoException):
-    '''Unexpected response from openmano server'''
-
-class OpenmanoNotFoundException(OpenmanoException):
-    '''Not found at server'''
-
-# class vnf():
-#     def __init__(self, message):
-#         print "Error: %s" %message
-#         print
-#         self.print_usage()
-#         #self.print_help()
-#         print
-#         print "Type 'openmano -h' for help"
-
-class openmanoclient():
-    headers_req = {'Accept': 'application/yaml', 'content-type': 'application/yaml'}
-    
-    def __init__(self, **kwargs):
-        self.username = kwargs.get("username")
-        self.password = kwargs.get("password")
-        self.endpoint_url = kwargs.get("endpoint_url")
-        self.tenant_id = kwargs.get("tenant_id")
-        self.tenant_name = kwargs.get("tenant_name")
-        self.tenant = None
-        self.datacenter_id = kwargs.get("datacenter_id")
-        self.datacenter_name = kwargs.get("datacenter_name")
-        self.datacenter = None
-        self.logger = logging.getLogger(kwargs.get('logger','manoclient'))
-        if kwargs.get("debug"):
-            self.logger.setLevel(logging.DEBUG)
-        
-    def __getitem__(self, index):
-        if index=='tenant_name':
-            return self.tenant_name
-        elif index=='tenant_id':
-            return self.tenant_id
-        elif index=='datacenter_name':
-            return self.datacenter_name
-        elif index=='datacenter_id':
-            return self.datacenter_id
-        elif index=='username':
-            return self.username
-        elif index=='password':
-            return self.password
-        elif index=='endpoint_url':
-            return self.endpoint_url
-        else:
-            raise KeyError("Invalid key '%s'" %str(index))
-        
-    def __setitem__(self,index, value):
-        if index=='tenant_name':
-            self.tenant_name = value
-        elif index=='tenant_id':
-            self.tenant_id = value
-        elif index=='datacenter_name':
-            self.datacenter_name = value
-        elif index=='datacenter_id':
-            self.datacenter_id = value
-        elif index=='username':
-            self.username = value
-        elif index=='password':
-            self.password = value
-        elif index=='endpoint_url':
-            self.endpoint_url = value
-        else:
-            raise KeyError("Invalid key '%s'" %str(index)) 
-        self.tenant = None # force to reload tenant with different credentials
-        self.datacenter = None # force to reload datacenter with different credentials
-    
-    def _parse(self, descriptor, descriptor_format, response=False):
-        #try yaml
-        if descriptor_format and descriptor_format != "json" and descriptor_format != "yaml":
-            raise  OpenmanoBadParamsException("'descriptor_format' must be a 'json' or 'yaml' text")
-        if descriptor_format != "json":
-            try:
-                return yaml.load(descriptor)
-            except yaml.YAMLError as exc:
-                error_pos = ""
-                if hasattr(exc, 'problem_mark'):
-                    mark = exc.problem_mark
-                    error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1)
-                error_text = "yaml format error" + error_pos
-        elif descriptor_format != "yaml":
-            try:
-                return json.loads(descriptor) 
-            except Exception as e:
-                if response:
-                    error_text = "json format error" + str(e)
-
-        if response:
-            raise OpenmanoResponseException(error_text)
-        raise  OpenmanoBadParamsException(error_text)
-    
-    def _parse_yaml(self, descriptor, response=False):
-        try:
-            return yaml.load(descriptor)
-        except yaml.YAMLError as exc:
-            error_pos = ""
-            if hasattr(exc, 'problem_mark'):
-                mark = exc.problem_mark
-                error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1)
-            error_text = "yaml format error" + error_pos
-            if response:
-                raise OpenmanoResponseException(error_text)
-            raise  OpenmanoBadParamsException(error_text)
-
-    
-    def _get_item_uuid(self, item, item_id=None, item_name=None, all_tenants=False):
-        if all_tenants == None:
-            tenant_text = ""
-        elif all_tenants == False:
-            tenant_text = "/" + self.tenant
-        else:
-            tenant_text = "/any"
-        URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
-        self.logger.debug("GET %s", URLrequest )
-        mano_response = requests.get(URLrequest, headers=self.headers_req)
-        self.logger.debug("openmano response: %s", mano_response.text )
-        content = self._parse_yaml(mano_response.text, response=True)
-        #print content
-        found = 0
-        if not item_id and not item_name:
-            raise OpenmanoResponseException("Missing either {0}_name or {0}_id".format(item[:-1]))
-        for i in content[item]:
-            if item_id and i["uuid"] == item_id:
-                return item_id
-            elif item_name and i["name"] == item_name:
-                uuid = i["uuid"]
-                found += 1
-            
-        if found == 0:
-            if item_id:
-                raise OpenmanoNotFoundException("No {} found with id '{}'".format(item[:-1], item_id))
-            else:
-                #print(item, item_name)
-                raise OpenmanoNotFoundException("No {} found with name '{}'".format(item[:-1], item_name) )
-        elif found > 1:
-            raise OpenmanoNotFoundException("{} {} found with name '{}'. uuid must be used".format(found, item, item_name))
-        return uuid
-
-    def _get_item(self, item, uuid=None, name=None, all_tenants=False):
-        if all_tenants:
-            tenant_text = "/any"
-        elif all_tenants==None:
-            tenant_text = ""
-        else:
-            tenant_text = "/"+self._get_tenant()
-        if not uuid:
-            #check that exist
-            uuid = self._get_item_uuid(item, uuid, name, all_tenants)
-        
-        URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
-        self.logger.debug("GET %s", URLrequest )
-        mano_response = requests.get(URLrequest, headers=self.headers_req)
-        self.logger.debug("openmano response: %s", mano_response.text )
-    
-        content = self._parse_yaml(mano_response.text, response=True)
-        if mano_response.status_code==200:
-            return content
-        else:
-            raise OpenmanoResponseException(str(content))        
-
-    def _get_tenant(self):
-        if not self.tenant:
-            self.tenant = self._get_item_uuid("tenants", self.tenant_id, self.tenant_name, None)
-        return self.tenant
-    
-    def _get_datacenter(self):
-        if not self.tenant:
-            self._get_tenant()
-        if not self.datacenter:
-            self.datacenter = self._get_item_uuid("datacenters", self.datacenter_id, self.datacenter_name, False)
-        return self.datacenter
-
-    def _create_item(self, item, descriptor, all_tenants=False):
-        if all_tenants:
-            tenant_text = "/any"
-        elif all_tenants==None:
-            tenant_text = ""
-        else:
-            tenant_text = "/"+self._get_tenant()
-        payload_req = yaml.safe_dump(descriptor)
-            
-        #print payload_req
-            
-        URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
-        self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
-        mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
-        self.logger.debug("openmano response: %s", mano_response.text )
-    
-        content = self._parse_yaml(mano_response.text, response=True)
-        if mano_response.status_code==200:
-            return content
-        else:
-            raise OpenmanoResponseException(str(content))        
-
-    def _del_item(self, item, uuid=None, name=None, all_tenants=False):
-        if all_tenants:
-            tenant_text = "/any"
-        elif all_tenants==None:
-            tenant_text = ""
-        else:
-            tenant_text = "/"+self._get_tenant()
-        if not uuid:
-            #check that exist
-            uuid = self._get_item_uuid(item, uuid, name, all_tenants)
-        
-        URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
-        self.logger.debug("DELETE %s", URLrequest )
-        mano_response = requests.delete(URLrequest, headers = self.headers_req)
-        self.logger.debug("openmano response: %s", mano_response.text )
-    
-        content = self._parse_yaml(mano_response.text, response=True)
-        if mano_response.status_code==200:
-            return content
-        else:
-            raise OpenmanoResponseException(str(content))        
-    
-    def _list_item(self, item, all_tenants=False, filter_dict=None):
-        if all_tenants:
-            tenant_text = "/any"
-        elif all_tenants==None:
-            tenant_text = ""
-        else:
-            tenant_text = "/"+self._get_tenant()
-        
-        URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
-        separator="?"
-        if filter_dict:
-            for k in filter_dict:
-                URLrequest += separator + quote(str(k)) + "=" + quote(str(filter_dict[k])) 
-                separator = "&"
-        self.logger.debug("openmano GET %s", URLrequest)
-        mano_response = requests.get(URLrequest, headers=self.headers_req)
-        self.logger.debug("openmano response: %s", mano_response.text )
-    
-        content = self._parse_yaml(mano_response.text, response=True)
-        if mano_response.status_code==200:
-            return content
-        else:
-            raise OpenmanoResponseException(str(content))        
-
-    def _edit_item(self, item, descriptor, uuid=None, name=None, all_tenants=False):
-        if all_tenants:
-            tenant_text = "/any"
-        elif all_tenants==None:
-            tenant_text = ""
-        else:
-            tenant_text = "/"+self._get_tenant()
-
-        if not uuid:
-            #check that exist
-            uuid = self._get_item_uuid("tenants", uuid, name, all_tenants)
-        
-        payload_req = yaml.safe_dump(descriptor)
-            
-        #print payload_req
-            
-        URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
-        self.logger.debug("openmano PUT %s %s", URLrequest, payload_req)
-        mano_response = requests.put(URLrequest, headers = self.headers_req, data=payload_req)
-        self.logger.debug("openmano response: %s", mano_response.text )
-    
-        content = self._parse_yaml(mano_response.text, response=True)
-        if mano_response.status_code==200:
-            return content
-        else:
-            raise OpenmanoResponseException(str(content))        
-
-    #TENANTS
-    def list_tenants(self, **kwargs):
-        '''Obtain a list of tenants
-        Params: can be filtered by 'uuid','name','description'
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'tenants':[{tenant1_info},{tenant2_info},...]}}
-        '''
-        return self._list_item("tenants", all_tenants=None, filter_dict=kwargs)
-
-    def get_tenant(self, uuid=None, name=None):
-        '''Obtain the information of a tenant
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several
-                Obtain a dictionary with format {'tenant':{tenant_info}}
-        '''
-        return self._get_item("tenants", uuid, name, all_tenants=None)
-
-    def delete_tenant(self, uuid=None, name=None):
-        '''Delete a tenant
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several
-                Obtain a dictionary with format {'result': text indicating deleted}
-        '''
-        return self._del_item("tenants", uuid, name, all_tenants=None)
-
-    def create_tenant(self, descriptor=None, descriptor_format=None, name=None, description=None):
-        '''Creates a tenant
-        Params: must supply a descriptor or/and just a name
-            descriptor: with format {'tenant':{new_tenant_info}}
-                newtenant_info must contain 'name', and optionally 'description'
-                must be a dictionary or a json/yaml text.
-            name: the tenant name. Overwrite descriptor name if any
-            description: tenant descriptor.. Overwrite descriptor description if any
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'tenant':{new_tenant_info}}
-        '''
-        if isinstance(descriptor, str):
-            descriptor = self._parse(descriptor, descriptor_format)
-        elif descriptor:
-            pass
-        elif name:
-            descriptor={"tenant": {"name": name}}
-        else:
-            raise OpenmanoBadParamsException("Missing descriptor")
-
-        if 'tenant' not in descriptor or len(descriptor)!=1:
-            raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
-        if name:
-            descriptor['tenant']['name'] = name
-        if description:
-            descriptor['tenant']['description'] = description
-
-        return self._create_item("tenants", descriptor, all_tenants=None)
-
-    def edit_tenant(self, uuid=None, name=None, descriptor=None, descriptor_format=None, new_name=None, new_description=None):
-        '''Edit the parameters of a tenant
-        Params: must supply a descriptor or/and a new_name or new_description
-            uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-            descriptor: with format {'tenant':{params to change info}}
-                must be a dictionary or a json/yaml text.
-            name: the tenant name. Overwrite descriptor name if any
-            description: tenant descriptor.. Overwrite descriptor description if any
-        Return: Raises an exception on error, not found or found several
-                Obtain a dictionary with format {'tenant':{newtenant_info}}
-        '''
-
-        if isinstance(descriptor, str):
-            descriptor = self.parse(descriptor, descriptor_format)
-        elif descriptor:
-            pass
-        elif new_name or new_description:
-            descriptor={"tenant": {}}
-        else:
-            raise OpenmanoBadParamsException("Missing descriptor")
-
-        if 'tenant' not in descriptor or len(descriptor)!=1:
-            raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
-        if new_name:
-            descriptor['tenant']['name'] = new_name
-        if new_description:
-            descriptor['tenant']['description'] = new_description
-
-        return self._edit_item("tenants", descriptor, uuid, name, all_tenants=None)
-
-    #DATACENTERS
-
-    def list_datacenters(self, all_tenants=False, **kwargs):
-        '''Obtain a list of datacenters, that are the VIM information at openmano
-        Params: can be filtered by 'uuid','name','vim_url','type'
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'datacenters':[{datacenter1_info},{datacenter2_info},...]}}
-        '''
-        return self._list_item("datacenters", all_tenants, filter_dict=kwargs)
-
-    def get_datacenter(self, uuid=None, name=None, all_tenants=False):
-        '''Obtain the information of a datacenter
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several
-                Obtain a dictionary with format {'datacenter':{datacenter_info}}
-        '''
-        return self._get_item("datacenters", uuid, name, all_tenants)
-
-    def delete_datacenter(self, uuid=None, name=None):
-        '''Delete a datacenter
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several, not free
-                Obtain a dictionary with format {'result': text indicating deleted}
-        '''
-        if not uuid:
-            # check that exist
-            uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=True)
-        return self._del_item("datacenters", uuid, name, all_tenants=None)
-
-    def create_datacenter(self, descriptor=None, descriptor_format=None, name=None, vim_url=None, **kwargs):
-#, type="openvim", public=False, description=None):
-        '''Creates a datacenter
-        Params: must supply a descriptor or/and just a name and vim_url
-            descriptor: with format {'datacenter':{new_datacenter_info}}
-                newdatacenter_info must contain 'name', 'vim_url', and optionally 'description'
-                must be a dictionary or a json/yaml text.
-            name: the datacenter name. Overwrite descriptor name if any
-            vim_url: the datacenter URL. Overwrite descriptor vim_url if any
-            vim_url_admin: the datacenter URL for administrative issues. Overwrite descriptor vim_url if any
-            vim_type: the datacenter type, can be openstack or openvim. Overwrite descriptor type if any
-            public: boolean, by default not public
-            description: datacenter description. Overwrite descriptor description if any
-            config: dictionary with extra configuration for the concrete datacenter
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
-        '''
-        if isinstance(descriptor, str):
-            descriptor = self.parse(descriptor, descriptor_format)
-        elif descriptor:
-            pass
-        elif name and vim_url:
-            descriptor={"datacenter": {"name": name, "vim_url": vim_url}}
-        else:
-            raise OpenmanoBadParamsException("Missing descriptor, or name and vim_url")
-        
-        if 'datacenter' not in descriptor or len(descriptor)!=1:
-            raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
-        if name:
-            descriptor['datacenter']['name'] = name
-        if vim_url:
-            descriptor['datacenter']['vim_url'] = vim_url
-        for param in kwargs:
-            descriptor['datacenter'][param] = kwargs[param]
-
-        return self._create_item("datacenters", descriptor, all_tenants=None)
-
-    def edit_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
-        '''Edit the parameters of a datacenter
-        Params: must supply a descriptor or/and a parameter to change
-            uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-            descriptor: with format {'datacenter':{params to change info}}
-                must be a dictionary or a json/yaml text.
-            parameters to change can be supplyied by the descriptor or as parameters:
-                new_name: the datacenter name
-                vim_url: the datacenter URL
-                vim_url_admin: the datacenter URL for administrative issues
-                vim_type: the datacenter type, can be openstack or openvim.
-                public: boolean, available to other tenants
-                description: datacenter description
-        Return: Raises an exception on error, not found or found several
-                Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
-        '''
-
-        if isinstance(descriptor, str):
-            descriptor = self.parse(descriptor, descriptor_format)
-        elif descriptor:
-            pass
-        elif kwargs:
-            descriptor={"datacenter": {}}
-        else:
-            raise OpenmanoBadParamsException("Missing descriptor")
-
-        if 'datacenter' not in descriptor or len(descriptor)!=1:
-            raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
-        for param in kwargs:
-            if param=='new_name':
-                descriptor['datacenter']['name'] = kwargs[param]
-            else:
-                descriptor['datacenter'][param] = kwargs[param]
-        return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None)
-    
-    def attach_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None,  vim_user=None, vim_password=None, vim_tenant_name=None, vim_tenant_id=None):
-        #check that exist
-        uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=True)
-        tenant_text = "/"+self._get_tenant()
-
-        if isinstance(descriptor, str):
-            descriptor = self.parse(descriptor, descriptor_format)
-        elif descriptor:
-            pass
-        elif vim_user or vim_password or vim_tenant_name or vim_tenant_id:
-            descriptor={"datacenter": {}}
-        else:
-            raise OpenmanoBadParamsException("Missing descriptor or params")
-        
-        if vim_user or vim_password or vim_tenant_name or vim_tenant_id:
-            #print args.name
-            try:
-                if vim_user:
-                    descriptor['datacenter']['vim_user'] = vim_user
-                if vim_password:
-                    descriptor['datacenter']['vim_password'] = vim_password
-                if vim_tenant_name:
-                    descriptor['datacenter']['vim_tenant_name'] = vim_tenant_name
-                if vim_tenant_id:
-                    descriptor['datacenter']['vim_tenant'] = vim_tenant_id
-            except (KeyError, TypeError) as e:
-                if str(e)=='datacenter':           error_pos= "missing field 'datacenter'"
-                else:                       error_pos="wrong format"
-                raise OpenmanoBadParamsException("Wrong datacenter descriptor: " + error_pos)
-
-        payload_req = yaml.safe_dump(descriptor)
-        #print payload_req
-        URLrequest = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid)
-        self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
-        mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
-        self.logger.debug("openmano response: %s", mano_response.text )
-    
-        content = self._parse_yaml(mano_response.text, response=True)
-        if mano_response.status_code==200:
-            return content
-        else:
-            raise OpenmanoResponseException(str(content))        
-
-    def detach_datacenter(self, uuid=None, name=None):
-        if not uuid:
-            #check that exist
-            uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=False)
-        tenant_text = "/"+self._get_tenant()
-        URLrequest = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid)
-        self.logger.debug("openmano DELETE %s", URLrequest)
-        mano_response = requests.delete(URLrequest, headers = self.headers_req)
-        self.logger.debug("openmano response: %s", mano_response.text )
-    
-        content = self._parse_yaml(mano_response.text, response=True)
-        if mano_response.status_code==200:
-            return content
-        else:
-            raise OpenmanoResponseException(str(content))        
-
-    #VNFS
-    def list_vnfs(self, all_tenants=False, **kwargs):
-        '''Obtain a list of vnfs
-        Params: can be filtered by 'uuid','name','description','public', "tenant_id"
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'vnfs':[{vnf1_info},{vnf2_info},...]}}
-        '''
-        return self._list_item("vnfs", all_tenants, kwargs)
-
-    def get_vnf(self, uuid=None, name=None, all_tenants=False):
-        '''Obtain the information of a vnf
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several
-                Obtain a dictionary with format {'vnf':{vnf_info}}
-        '''
-        return self._get_item("vnfs", uuid, name, all_tenants)
-
-    def delete_vnf(self, uuid=None, name=None, all_tenants=False):
-        '''Delete a vnf
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several, not free
-                Obtain a dictionary with format {'result': text indicating deleted}
-        '''
-        return self._del_item("vnfs", uuid, name, all_tenants)
-
-    def create_vnf(self, descriptor=None, descriptor_format=None, **kwargs):
-        '''Creates a vnf
-        Params: must supply a descriptor
-            descriptor: with format {'vnf':{new_vnf_info}}
-                must be a dictionary or a json/yaml text.
-                must be a dictionary or a json/yaml text.
-            Other parameters can be:
-                name: the vnf name. Overwrite descriptor name if any
-                image_path: Can be a string or a string list. Overwrite the image_path at descriptor
-                description: vnf descriptor.. Overwrite descriptor description if any
-                public: boolean, available to other tenants
-                class: user text for vnf classification
-                tenant_id: Propietary tenant
-                ...
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'vnf':{new_vnf_info}}
-        '''
-        if isinstance(descriptor, str):
-            descriptor = self.parse(descriptor, descriptor_format)
-        elif descriptor:
-            pass
-        else:
-            raise OpenmanoBadParamsException("Missing descriptor")
-        
-        if 'vnf' not in descriptor or len(descriptor)>2:
-            raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field, and an optional version")
-        for param in kwargs:
-            if param == 'image_path':
-                #print args.name
-                try:
-                    if isinstance(kwargs[param], str):
-                        descriptor['vnf']['VNFC'][0]['VNFC image']=kwargs[param]
-                    elif isinstance(kwargs[param], tuple) or isinstance(kwargs[param], list):
-                        index=0
-                        for image_path_ in kwargs[param]:
-                            #print "image-path", image_path_
-                            descriptor['vnf']['VNFC'][index]['VNFC image']=image_path_
-                            index=index+1
-                    else:
-                        raise OpenmanoBadParamsException("Wrong image_path type. Expected text or a text list")
-                except (KeyError, TypeError) as e:
-                    if str(e)=='vnf':           error_pos= "missing field 'vnf'"
-                    elif str(e)=='VNFC':        error_pos= "missing field  'vnf':'VNFC'"
-                    elif str(e)==str(index):    error_pos= "field  'vnf':'VNFC' must be an array"
-                    elif str(e)=='VNFC image':  error_pos= "missing field 'vnf':'VNFC'['VNFC image']"
-                    else:                       error_pos="wrong format"
-                    raise OpenmanoBadParamsException("Wrong VNF descriptor: " + error_pos)
-            else:
-                descriptor['vnf'][param] = kwargs[param]
-        return self._create_item("vnfs", descriptor)
-
-#     def edit_vnf(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
-#         '''Edit the parameters of a vnf
-#         Params: must supply a descriptor or/and a parameters to change
-#             uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-#             descriptor: with format {'vnf':{params to change info}}
-#             parameters to change can be supplyied by the descriptor or as parameters:
-#                 new_name: the vnf name
-#                 vim_url: the vnf URL
-#                 vim_url_admin: the vnf URL for administrative issues
-#                 vim_type: the vnf type, can be openstack or openvim.
-#                 public: boolean, available to other tenants
-#                 description: vnf description
-#         Return: Raises an exception on error, not found or found several
-#                 Obtain a dictionary with format {'vnf':{new_vnf_info}}
-#         '''
-# 
-#        if isinstance(descriptor, str):
-#            descriptor = self.parse(descriptor, descriptor_format)
-#        elif descriptor:
-#            pass
-#         elif kwargs:
-#             descriptor={"vnf": {}}
-#         else:
-#             raise OpenmanoBadParamsException("Missing descriptor")
-# 
-#         if 'vnf' not in descriptor or len(descriptor)>2:
-#             raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field")
-#         for param in kwargs:
-#             if param=='new_name':
-#                 descriptor['vnf']['name'] = kwargs[param]
-#             else:
-#                 descriptor['vnf'][param] = kwargs[param]
-#         return self._edit_item("vnfs", descriptor, uuid, name, all_tenants=None)
-
-    #SCENARIOS
-    def list_scenarios(self, all_tenants=False, **kwargs):
-        '''Obtain a list of scenarios
-        Params: can be filtered by 'uuid','name','description','public', "tenant_id"
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'scenarios':[{scenario1_info},{scenario2_info},...]}}
-        '''
-        return self._list_item("scenarios", all_tenants, kwargs)
-
-    def get_scenario(self, uuid=None, name=None, all_tenants=False):
-        '''Obtain the information of a scenario
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several
-                Obtain a dictionary with format {'scenario':{scenario_info}}
-        '''
-        return self._get_item("scenarios", uuid, name, all_tenants)
-
-    def delete_scenario(self, uuid=None, name=None, all_tenants=False):
-        '''Delete a scenario
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several, not free
-                Obtain a dictionary with format {'result': text indicating deleted}
-        '''
-        return self._del_item("scenarios", uuid, name, all_tenants)
-
-    def create_scenario(self, descriptor=None, descriptor_format=None, **kwargs):
-        '''Creates a scenario
-        Params: must supply a descriptor
-            descriptor: with format {'scenario':{new_scenario_info}}
-                must be a dictionary or a json/yaml text.
-            Other parameters can be:
-                name: the scenario name. Overwrite descriptor name if any
-                description: scenario descriptor.. Overwrite descriptor description if any
-                public: boolean, available to other tenants
-                tenant_id. Propietary tenant
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'scenario':{new_scenario_info}}
-        '''
-        if isinstance(descriptor, str):
-            descriptor = self.parse(descriptor, descriptor_format)
-        elif descriptor:
-            pass
-        else:
-            raise OpenmanoBadParamsException("Missing descriptor")
-        
-        if 'scenario' not in descriptor or len(descriptor)>2:
-            raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field, and an optional version")
-        for param in kwargs:
-            descriptor['scenario'][param] = kwargs[param]
-        return self._create_item("scenarios", descriptor)
-
-    def edit_scenario(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
-        '''Edit the parameters of a scenario
-        Params: must supply a descriptor or/and a parameters to change
-            uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-            descriptor: with format {'scenario':{params to change info}}
-                must be a dictionary or a json/yaml text.
-            parameters to change can be supplyied by the descriptor or as parameters:
-                new_name: the scenario name
-                public: boolean, available to other tenants
-                description: scenario description
-                tenant_id. Propietary tenant
-        Return: Raises an exception on error, not found or found several
-                Obtain a dictionary with format {'scenario':{new_scenario_info}}
-        '''
-        if isinstance(descriptor, str):
-            descriptor = self.parse(descriptor, descriptor_format)
-        elif descriptor:
-            pass
-        elif kwargs:
-            descriptor={"scenario": {}}
-        else:
-            raise OpenmanoBadParamsException("Missing descriptor")
-        if 'scenario' not in descriptor or len(descriptor)>2:
-            raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field")
-        for param in kwargs:
-            if param=='new_name':
-                descriptor['scenario']['name'] = kwargs[param]
-            else:
-                descriptor['scenario'][param] = kwargs[param]
-        return self._edit_item("scenarios", descriptor, uuid, name, all_tenants=None)
-
-
-    #INSTANCE-SCENARIOS
-    def list_instances(self, all_tenants=False, **kwargs):
-        '''Obtain a list of instances
-        Params: can be filtered by 'uuid','name','description','scenario_id', "tenant_id"
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'instances':[{instance1_info},{instance2_info},...]}}
-        '''
-        return self._list_item("instances", all_tenants, kwargs)
-
-    def get_instance(self, uuid=None, name=None, all_tenants=False):
-        '''Obtain the information of a instance
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several
-                Obtain a dictionary with format {'instance':{instance_info}}
-        '''
-        return self._get_item("instances", uuid, name, all_tenants)
-
-    def delete_instance(self, uuid=None, name=None, all_tenants=False):
-        '''Delete a instance
-        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
-        Return: Raises an exception on error, not found, found several, not free
-                Obtain a dictionary with format {'result': text indicating deleted}
-        '''
-        return self._del_item("instances", uuid, name, all_tenants)
-
-    def create_instance(self, descriptor=None, descriptor_format=None, name=None, **kwargs):
-        '''Creates a instance
-        Params: must supply a descriptor or/and a name and scenario
-            descriptor: with format {'instance':{new_instance_info}}
-                must be a dictionary or a json/yaml text.
-            name: the instance name. Overwrite descriptor name if any
-            Other parameters can be:
-                description: instance descriptor.. Overwrite descriptor description if any
-                datacenter_name, datacenter_id: datacenter  where to be deployed
-                scenario_name, scenario_id: Scenario this instance is based on
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'instance':{new_instance_info}}
-        '''
-        if isinstance(descriptor, str):
-            descriptor = self.parse(descriptor, descriptor_format)
-        elif descriptor:
-            pass
-        elif name and ("scenario_name" in kwargs or "scenario_id" in kwargs):
-            descriptor = {"instance":{"name": name}}
-        else:
-            raise OpenmanoBadParamsException("Missing descriptor")
-        
-        if 'instance' not in descriptor or len(descriptor)>2:
-            raise OpenmanoBadParamsException("Descriptor must contain only one 'instance' field, and an optional version")
-        if name:
-            descriptor['instance']["name"] = name
-        if "scenario_name" in kwargs or "scenario_id" in kwargs:
-            descriptor['instance']["scenario"] = self._get_item_uuid("scenarios", kwargs.get("scenario_id"), kwargs.get("scenario_name"))
-        if "datacenter_name" in kwargs or "datacenter_id" in kwargs:
-            descriptor['instance']["datacenter"] = self._get_item_uuid("datacenters", kwargs.get("datacenter_id"), kwargs.get("datacenter_name"))
-        if "description" in kwargs:
-            descriptor['instance']["description"] = kwargs.get("description")
-        #for param in kwargs:
-        #    descriptor['instance'][param] = kwargs[param]
-        if "datacenter" not in descriptor['instance']:
-            descriptor['instance']["datacenter"] = self._get_datacenter()
-        return self._create_item("instances", descriptor)
-
-    #VIM ACTIONS
-    def vim_action(self, action, item, uuid=None, all_tenants=False, **kwargs):
-        '''Perform an action over a vim
-        Params: 
-            action: can be 'list', 'get'/'show', 'delete' or 'create'
-            item: can be 'tenants' or 'networks'
-            uuid: uuid of the tenant/net to show or to delete. Ignore otherwise
-            other parameters:
-                datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter 
-                descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str 
-                    must be a dictionary or a json/yaml text.
-                name: for created tenant/net Overwrite descriptor name if any
-                description: tenant descriptor. Overwrite descriptor description if any
-                
-        Return: Raises an exception on error
-                Obtain a dictionary with format {'tenant':{new_tenant_info}}
-        '''
-        if item not in ("tenants", "networks", "images"):
-            raise OpenmanoBadParamsException("Unknown value for item '{}', must be 'tenants', 'nets' or "
-                                             "images".format(str(item)))
-
-        image_actions = ['list','get','show','delete']
-        if item == "images" and action not in image_actions:
-            raise OpenmanoBadParamsException("Only available actions for item '{}' are {}\n"
-                                             "Requested action was '{}'".format(item, ', '.join(image_actions), action))
-        if all_tenants:
-            tenant_text = "/any"
-        else:
-            tenant_text = "/"+self._get_tenant()
-        
-        if "datacenter_id" in kwargs or "datacenter_name" in kwargs:
-            datacenter = self._get_item_uuid("datacenters", kwargs.get("datacenter_id"), kwargs.get("datacenter_name"), all_tenants=all_tenants)
-        else:
-            datacenter = self._get_datacenter()
-
-        if action=="list":
-            URLrequest = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
-            self.logger.debug("GET %s", URLrequest )
-            mano_response = requests.get(URLrequest, headers=self.headers_req)
-            self.logger.debug("openmano response: %s", mano_response.text )
-            content = self._parse_yaml(mano_response.text, response=True)            
-            if mano_response.status_code==200:
-                return content
-            else:
-                raise OpenmanoResponseException(str(content))        
-        elif action=="get" or action=="show":
-            URLrequest = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
-            self.logger.debug("GET %s", URLrequest )
-            mano_response = requests.get(URLrequest, headers=self.headers_req)
-            self.logger.debug("openmano response: %s", mano_response.text )
-            content = self._parse_yaml(mano_response.text, response=True)            
-            if mano_response.status_code==200:
-                return content
-            else:
-                raise OpenmanoResponseException(str(content))        
-        elif action=="delete":
-            URLrequest = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
-            self.logger.debug("DELETE %s", URLrequest )
-            mano_response = requests.delete(URLrequest, headers=self.headers_req)
-            self.logger.debug("openmano response: %s", mano_response.text )
-            content = self._parse_yaml(mano_response.text, response=True)            
-            if mano_response.status_code==200:
-                return content
-            else:
-                raise OpenmanoResponseException(str(content))        
-        elif action=="create":
-            if "descriptor" in kwargs:
-                if isinstance(kwargs["descriptor"], str):
-                    descriptor = self._parse(kwargs["descriptor"], kwargs.get("descriptor_format") )
-                else:
-                    descriptor = kwargs["descriptor"]
-            elif "name" in kwargs:
-                descriptor={item[:-1]: {"name": kwargs["name"]}}
-            else:
-                raise OpenmanoResponseException("Missing descriptor")
-        
-            if item[:-1] not in descriptor or len(descriptor)!=1:
-                raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
-            if "name" in kwargs:
-                descriptor[ item[:-1] ]['name'] = kwargs["name"]
-            if "description" in kwargs:
-                descriptor[ item[:-1] ]['description'] = kwargs["description"]
-            payload_req = yaml.safe_dump(descriptor)
-            #print payload_req
-            URLrequest = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
-            self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
-            mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
-            self.logger.debug("openmano response: %s", mano_response.text )
-            content = self._parse_yaml(mano_response.text, response=True)
-            if mano_response.status_code==200:
-                return content
-            else:
-                raise OpenmanoResponseException(str(content))
-        else:
-            raise OpenmanoBadParamsException("Unknown value for action '{}".format(str(action))) 
-
index 03901c3..bb32339 100755 (executable)
@@ -37,19 +37,17 @@ __version__="0.5.8-r518"
 version_date="Jan 2017"
 database_version="0.19"      #expected database schema version
 
-import httpserver
 import time
 import sys
 import getopt
 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
 import socket
+from osm_ro import httpserver, nfvo, nfvo_db
+from osm_ro.openmano_schemas import config_schema
+from osm_ro.db_base import db_base_Exception
 
 global global_config
 global logger
diff --git a/osm-ro.service b/osm-ro.service
new file mode 100644 (file)
index 0000000..155150b
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=openmano server (OSM RO)
+
+[Service]
+User=${USER_OWNER}
+ExecStart=openmanod.py -c /etc/osm/openmanod.cfg --log-file=/var/log/osm/openmano.log
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/osm_ro/console_proxy_thread.py b/osm_ro/console_proxy_thread.py
new file mode 100644 (file)
index 0000000..460a4aa
--- /dev/null
@@ -0,0 +1,188 @@
+# -*- 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
+##
+
+'''
+Implement like a proxy for TCP/IP in a separated thread.
+It creates two sockets to bypass the TCP/IP packets among the fix console 
+server specified at class construction (console_host, console_port)
+and a client that connect against the (host, port) specified also at construction
+
+                ---------------------           -------------------------------
+                |       OPENMANO     |          |         VIM                  |
+client 1  ----> | ConsoleProxyThread | ------>  |  Console server              |
+client 2  ----> |  (host, port)      | ------>  |(console_host, console_server)|
+   ...           --------------------            ------------------------------
+'''
+__author__="Alfonso Tierno"
+__date__ ="$19-nov-2015 09:07:15$"
+
+import socket
+import select
+import threading
+import logging
+
+
+class ConsoleProxyException(Exception):
+    '''raise when an exception has found''' 
+class ConsoleProxyExceptionPortUsed(ConsoleProxyException):
+    '''raise when the port is used''' 
+
+class ConsoleProxyThread(threading.Thread):
+    buffer_size = 4096
+    check_finish = 1 #frequency to check if requested to end in seconds
+
+    def __init__(self, host, port, console_host, console_port, log_level=None):
+        try:
+            threading.Thread.__init__(self)
+            self.console_host = console_host
+            self.console_port = console_port
+            self.host = host
+            self.port = port
+            self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            self.server.bind((host, port))
+            self.server.listen(200)
+            #TODO timeout in a lock section can be used to autoterminate the thread
+            #when inactivity and timeout<time : set timeout=0 and terminate
+            #from outside, close class when timeout==0; set timeout=time+120 when adding a new console on this thread
+            #set self.timeout = time.time() + 120 at init
+            self.name = "ConsoleProxy " + console_host + ":" + str(console_port)
+            self.input_list = [self.server]
+            self.channel = {}
+            self.terminate = False #put at True from outside to force termination
+            self.logger = logging.getLogger('openmano.console')
+            if log_level:
+                self.logger.setLevel( getattr(logging, log_level) )
+
+        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
+            if e is socket.error and e.errno==98:
+                raise ConsoleProxyExceptionPortUsed("socket.error " + str(e))
+            raise ConsoleProxyException(type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0])) )
+        
+    def run(self):
+        while 1:
+            try:
+                inputready, _, _ = select.select(self.input_list, [], [], self.check_finish)
+            except select.error as e:
+                self.logger.error("Exception on select %s: %s", type(e).__name__, str(e) )
+                self.on_terminate()
+
+            if self.terminate:
+                self.on_terminate()
+                self.logger.debug("Terminate because commanded")
+                break
+            
+            for sock in inputready:
+                if sock == self.server:
+                    self.on_accept()
+                else:
+                    self.on_recv(sock)
+                    
+    def on_terminate(self):
+        while self.input_list:
+            if self.input_list[0] is self.server:
+                self.server.close()
+                del self.input_list[0]
+            else:
+                self.on_close(self.input_list[0], "Terminating thread")
+
+    def on_accept(self):
+        #accept
+        try:
+            clientsock, clientaddr = self.server.accept()
+        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
+            self.logger.error("Exception on_accept %s: %s", type(e).__name__, str(e) )
+            return False
+        #print self.name, ": Accept new client ", clientaddr
+
+        #connect
+        try:
+            forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            forward.connect((self.console_host, self.console_port))
+            name = "%s:%d => (%s:%d => %s:%d) => %s:%d" %\
+                (clientsock.getpeername() + clientsock.getsockname()  + forward.getsockname() + forward.getpeername() )
+            self.logger.warn("new connection " + name)
+                
+            self.input_list.append(clientsock)
+            self.input_list.append(forward)
+            info = { "name": name,
+                    "clientsock" : clientsock,
+                    "serversock" : forward
+                    }
+            self.channel[clientsock] = info
+            self.channel[forward] = info
+            return True
+        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
+            self.logger.error("Exception on_connect to server %s:%d; %s: %s  Close client side %s",
+                self.console_host, self.console_port, type(e).__name__, str(e), str(clientaddr) )
+            clientsock.close()
+            return False
+
+    def on_close(self, sock, cause):
+        if sock not in self.channel:
+            return  #can happen if there is data ready to received at both sides and the channel has been deleted. QUITE IMPROBABLE but just in case
+        info = self.channel[sock]
+        #debug info
+        sockname = "client" if sock is info["clientsock"] else "server"
+        self.logger.warn("del connection %s %s at %s side", info["name"], str(cause), str(sockname) )
+        #close sockets
+        try:
+            # close the connection with client
+            info["clientsock"].close()  # equivalent to do self.s.close()
+        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
+            self.logger.error("Exception on_close client socket %s: %s", type(e).__name__, str(e) )
+        try:
+            # close the connection with remote server
+            info["serversock"].close()
+        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
+            self.logger.error("Exception on_close server socket %s: %s", type(e).__name__, str(e) )
+        
+        #remove objects from input_list
+        self.input_list.remove(info["clientsock"])
+        self.input_list.remove(info["serversock"])
+        # delete both objects from channel dict
+        del self.channel[info["clientsock"]]
+        del self.channel[info["serversock"]]
+
+    def on_recv(self, sock):
+        if sock not in self.channel:
+            return  #can happen if there is data ready to received at both sides and the channel has been deleted. QUITE IMPROBABLE but just in case
+        info = self.channel[sock]
+        peersock = info["serversock"] if sock is info["clientsock"] else info["clientsock"]
+        try:
+            data = sock.recv(self.buffer_size)
+            if len(data) == 0:
+                self.on_close(sock, "peer closed")
+            else:
+                #print self.data
+                sock = peersock
+                peersock.send(data)
+        except (socket.error, socket.herror, socket.gaierror, socket.timeout) as e:
+            #print self.name, ": Exception %s: %s" % (type(e).__name__, str(e) )
+            self.on_close(sock, "Exception %s: %s" % (type(e).__name__, str(e) ))
+
+        
+
+    #def start_timeout(self):
+    #    self.timeout = time.time() + 120
+        
diff --git a/osm_ro/db_base.py b/osm_ro/db_base.py
new file mode 100644 (file)
index 0000000..10f9404
--- /dev/null
@@ -0,0 +1,656 @@
+# -*- 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
+##
+
+'''
+Base class for openmano database manipulation
+'''
+__author__="Alfonso Tierno"
+__date__ ="$4-Apr-2016 10:05:01$"
+
+import MySQLdb as mdb
+import uuid as myUuid
+import  utils as af
+import json
+#import yaml
+import time
+import logging
+import datetime
+from jsonschema import validate as js_v, exceptions as js_e
+
+HTTP_Bad_Request = 400
+HTTP_Unauthorized = 401 
+HTTP_Not_Found = 404 
+HTTP_Method_Not_Allowed = 405 
+HTTP_Request_Timeout = 408
+HTTP_Conflict = 409
+HTTP_Service_Unavailable = 503 
+HTTP_Internal_Server_Error = 500 
+
+def _check_valid_uuid(uuid):
+    id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
+    id_schema2 = {"type" : "string", "pattern": "^[a-fA-F0-9]{32}$"}
+    try:
+        js_v(uuid, id_schema)
+        return True
+    except js_e.ValidationError:
+        try:
+            js_v(uuid, id_schema2)
+            return True
+        except js_e.ValidationError:
+            return False
+    return False
+
+def _convert_datetime2str(var):
+    '''Converts a datetime variable to a string with the format '%Y-%m-%dT%H:%i:%s'
+    It enters recursively in the dict var finding this kind of variables
+    '''
+    if type(var) is dict:
+        for k,v in var.items():
+            if type(v) is datetime.datetime:
+                var[k]= v.strftime('%Y-%m-%dT%H:%M:%S')
+            elif type(v) is dict or type(v) is list or type(v) is tuple: 
+                _convert_datetime2str(v)
+        if len(var) == 0: return True
+    elif type(var) is list or type(var) is tuple:
+        for v in var:
+            _convert_datetime2str(v)
+
+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:
+        'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
+        'reverse': by default convert form str to int (Mbps), if True it convert from number to units
+    Return:
+        None
+    '''
+    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, logger)
+        if "bandwidth" in data:
+            try:
+                value=str(data["bandwidth"])
+                if not reverse:
+                    pos = value.find("bps")
+                    if pos>0:
+                        if value[pos-1]=="G": data["bandwidth"] =  int(data["bandwidth"][:pos-1]) * 1000
+                        elif value[pos-1]=="k": data["bandwidth"]= int(data["bandwidth"][:pos-1]) / 1000
+                        else: data["bandwidth"]= int(data["bandwidth"][:pos-1])
+                else:
+                    value = int(data["bandwidth"])
+                    if value % 1000 == 0: data["bandwidth"]=str(value/1000) + " Gbps"
+                    else: data["bandwidth"]=str(value) + " Mbps"
+            except:
+                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, 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 
+    Done recursively
+    Attributes:
+        'data': dictionary variable to be checked. None or empty is considered valid
+        'items': tuple of keys to convert
+    Return:
+        None
+    '''
+    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_str2boolean(data[k], items)
+            if k in items:
+                if type(data[k]) is str:
+                    if   data[k]=="false" or data[k]=="False" or data[k]=="0": data[k]=False
+                    elif data[k]=="true"  or data[k]=="True" or data[k]=="1":  data[k]=True
+                elif type(data[k]) is int:
+                    if   data[k]==0: data[k]=False
+                    elif  data[k]==1:  data[k]=True
+    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_str2boolean(k, items)
+
+class db_base_Exception(Exception):
+    '''Common Exception for all database exceptions'''
+    
+    def __init__(self, message, http_code=HTTP_Bad_Request):
+        Exception.__init__(self, message)
+        self.http_code = http_code
+
+class db_base():
+    tables_with_created_field=()
+    
+    def __init__(self, host=None, user=None, passwd=None, database=None, log_name='db', log_level=None):
+        self.host = host
+        self.user = user
+        self.passwd = passwd
+        self.database = database
+        self.con = None
+        self.log_level=log_level
+        self.logger = logging.getLogger(log_name)
+        if self.log_level:
+            self.logger.setLevel( getattr(logging, log_level) )
+        
+    def connect(self, host=None, user=None, passwd=None, database=None):
+        '''Connect to specific data base. 
+        The first time a valid host, user, passwd and database must be provided,
+        Following calls can skip this parameters
+        '''
+        try:
+            if host:        self.host = host
+            if user:        self.user = user
+            if passwd:      self.passwd = passwd
+            if database:    self.database = database
+
+            self.con = mdb.connect(self.host, self.user, self.passwd, self.database)
+            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.
+        Return: (negative, text) if error or version 0.0 where schema_version table is missing
+                (version_int, version_text) if ok
+        '''
+        cmd = "SELECT version_int,version FROM schema_version"
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor()
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    rows = self.cur.fetchall()
+                    highest_version_int=0
+                    highest_version=""
+                    for row in rows: #look for the latest version
+                        if row[0]>highest_version_int:
+                            highest_version_int, highest_version = row[0:2]
+                    return highest_version_int, highest_version
+            except (mdb.Error, AttributeError) as e:
+                #self.logger.error("get_db_version DB Exception %d: %s. Command %s",e.args[0], e.args[1], cmd)
+                self._format_error(e, tries)
+            tries -= 1
+
+    def disconnect(self):
+        '''disconnect from specific data base'''
+        try:
+            self.con.close()
+            self.con = None
+        except mdb.Error as e:
+            self.logger.error("while disconnecting from DB: Error %d: %s",e.args[0], e.args[1])
+            return
+        except AttributeError as e: #self.con not defined
+            if e[0][-5:] == "'con'":
+                self.logger.warn("while disconnecting from DB: Error %d: %s",e.args[0], e.args[1])
+                return
+            else: 
+                raise
+
+    def _format_error(self, e, tries=1, command=None, extra=None): 
+        '''Creates a text error base on the produced exception
+            Params:
+                e: mdb exception
+                retry: in case of timeout, if reconnecting to database and retry, or raise and exception
+                cmd: database command that produce the exception
+                command: if the intention is update or delete
+                extra: extra information to add to some commands
+            Return
+                HTTP error in negative, formatted error text
+        '''
+        if isinstance(e,AttributeError ):
+            raise db_base_Exception("DB Exception " + str(e), HTTP_Internal_Server_Error)
+        if e.args[0]==2006 or e.args[0]==2013 : #MySQL server has gone away (((or)))    Exception 2013: Lost connection to MySQL server during query
+            if tries>1:
+                self.logger.warn("DB Exception '%s'. Retry", str(e))
+                #reconnect
+                self.connect()
+                return
+            else:
+                raise db_base_Exception("Database connection timeout Try Again", HTTP_Request_Timeout)
+        
+        fk=e.args[1].find("foreign key constraint fails")
+        if fk>=0:
+            if command=="update":
+                raise db_base_Exception("tenant_id '{}' not found.".format(extra), HTTP_Not_Found)
+            elif command=="delete":
+                raise db_base_Exception("Resource is not free. There are {} that prevent deleting it.".format(extra), HTTP_Conflict)
+        de = e.args[1].find("Duplicate entry")
+        fk = e.args[1].find("for key")
+        uk = e.args[1].find("Unknown column")
+        wc = e.args[1].find("in 'where clause'")
+        fl = e.args[1].find("in 'field list'")
+        #print de, fk, uk, wc,fl
+        if de>=0:
+            if fk>=0: #error 1062
+                raise db_base_Exception("Value {} already in use for {}".format(e.args[1][de+15:fk], e.args[1][fk+7:]), HTTP_Conflict)
+        if uk>=0:
+            if wc>=0:
+                raise db_base_Exception("Field {} can not be used for filtering".format(e.args[1][uk+14:wc]), HTTP_Bad_Request)
+            if fl>=0:
+                raise db_base_Exception("Field {} does not exist".format(e.args[1][uk+14:wc]), HTTP_Bad_Request)
+        raise db_base_Exception("Database internal Error {}: {}".format(e.args[0], e.args[1]), HTTP_Internal_Server_Error)
+    
+    def __str2db_format(self, data):
+        '''Convert string data to database format. 
+        If data is None it returns the 'Null' text,
+        otherwise it returns the text surrounded by quotes ensuring internal quotes are escaped.
+        '''
+        if data==None:
+            return 'Null'
+        else:
+            return json.dumps(str(data))
+    
+    def __tuple2db_format_set(self, data):
+        '''Compose the needed text for a SQL SET, parameter 'data' is a pair tuple (A,B),
+        and it returns the text 'A="B"', where A is a field of a table and B is the value 
+        If B is None it returns the 'A=Null' text, without surrounding Null by quotes
+        If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
+        and it ensures internal quotes of B are escaped.
+        '''
+        if data[1]==None:
+            return str(data[0]) + "=Null"
+        else:
+            return str(data[0]) + '=' + json.dumps(str(data[1]))
+    
+    def __tuple2db_format_where(self, data):
+        '''Compose the needed text for a SQL WHERE, parameter 'data' is a pair tuple (A,B),
+        and it returns the text 'A="B"', where A is a field of a table and B is the value 
+        If B is None it returns the 'A is Null' text, without surrounding Null by quotes
+        If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
+        and it ensures internal quotes of B are escaped.
+        '''
+        if data[1]==None:
+            return str(data[0]) + " is Null"
+        
+#         if type(data[1]) is tuple:  #this can only happen in a WHERE_OR clause
+#             text =[]
+#             for d in data[1]:
+#                 if d==None:
+#                     text.append(str(data[0]) + " is Null")
+#                     continue
+#                 out=str(d)
+#                 if "'" not in out:
+#                     text.append( str(data[0]) + "='" + out + "'" )
+#                 elif '"' not in out:
+#                     text.append( str(data[0]) + '="' + out + '"' )
+#                 else:
+#                     text.append( str(data[0]) + '=' + json.dumps(out) )
+#             return " OR ".join(text)
+
+        out=str(data[1])
+        return str(data[0]) + '=' + json.dumps(out)
+
+    def __tuple2db_format_where_not(self, data):
+        '''Compose the needed text for a SQL WHERE(not). parameter 'data' is a pair tuple (A,B),
+        and it returns the text 'A<>"B"', where A is a field of a table and B is the value 
+        If B is None it returns the 'A is not Null' text, without surrounding Null by quotes
+        If B is not None it returns the text "A<>'B'" or 'A<>"B"' where B is surrounded by quotes,
+        and it ensures internal quotes of B are escaped.
+        '''
+        if data[1]==None:
+            return str(data[0]) + " is not Null"
+        out=str(data[1])
+        return str(data[0]) + '<>' + json.dumps(out)
+    
+    def __remove_quotes(self, data):
+        '''remove single quotes ' of any string content of data dictionary'''
+        for k,v in data.items():
+            if type(v) == str:
+                if "'" in v: 
+                    data[k] = data[k].replace("'","_")
+    
+    def _update_rows(self, table, UPDATE, WHERE, modified_time=0):
+        ''' Update one or several rows into a table.
+        Atributes
+            UPDATE: dictionary with the key: value to change
+            table: table where to update
+            WHERE: dictionary of elements to update
+        Return: the number of updated rows, exception if error
+        '''
+                #gettting uuid 
+        values = ",".join(map(self.__tuple2db_format_set, UPDATE.iteritems() ))
+        if modified_time:
+            values += ",modified_at={:f}".format(modified_time)
+        cmd= "UPDATE " + table +" SET " + values +\
+            " WHERE " + " and ".join(map(self.__tuple2db_format_where, WHERE.iteritems() ))
+        self.logger.debug(cmd)
+        self.cur.execute(cmd) 
+        return self.cur.rowcount
+    
+    def _new_row_internal(self, table, INSERT, add_uuid=False, root_uuid=None, created_time=0):
+        ''' Add one row into a table. It DOES NOT begin or end the transaction, so self.con.cursor must be created
+        Attribute 
+            INSERT: dictionary with the key:value to insert
+            table: table where to insert
+            add_uuid: if True, it will create an uuid key entry at INSERT if not provided
+            created_time: time to add to the created_time column
+        It checks presence of uuid and add one automatically otherwise
+        Return: uuid
+        '''
+
+        if add_uuid:
+            #create uuid if not provided
+            if 'uuid' not in INSERT:
+                uuid = INSERT['uuid'] = str(myUuid.uuid1()) # create_uuid
+            else: 
+                uuid = str(INSERT['uuid'])
+        else:
+            uuid=None
+        if add_uuid:
+            #defining root_uuid if not provided
+            if root_uuid is None:
+                root_uuid = uuid
+            if created_time:
+                created_at = created_time
+            else:
+                created_at=time.time()
+            #inserting new uuid
+            cmd = "INSERT INTO uuids (uuid, root_uuid, used_at, created_at) VALUES ('{:s}','{:s}','{:s}', {:f})".format(uuid, root_uuid, table, created_at)
+            self.logger.debug(cmd)
+            self.cur.execute(cmd)
+        #insertion
+        cmd= "INSERT INTO " + table +" SET " + \
+            ",".join(map(self.__tuple2db_format_set, INSERT.iteritems() )) 
+        if created_time:
+            cmd += ",created_at=%f" % created_time
+        self.logger.debug(cmd)
+        self.cur.execute(cmd)
+        self.cur.rowcount
+        return uuid
+
+    def _get_rows(self,table,uuid):
+        cmd = "SELECT * FROM {} WHERE uuid='{}'".format(str(table), str(uuid))
+        self.logger.debug(cmd)
+        self.cur.execute(cmd)
+        rows = self.cur.fetchall()
+        return rows
+    
+    def new_row(self, table, INSERT, add_uuid=False, created_time=0):
+        ''' Add one row into a table.
+        Attribute 
+            INSERT: dictionary with the key: value to insert
+            table: table where to insert
+            tenant_id: only useful for logs. If provided, logs will use this tenant_id
+            add_uuid: if True, it will create an uuid key entry at INSERT if not provided
+        It checks presence of uuid and add one automatically otherwise
+        Return: (result, uuid) where result can be 0 if error, or 1 if ok
+        '''
+        if table in self.tables_with_created_field and created_time==0:
+            created_time=time.time()
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor()
+                    return self._new_row_internal(table, INSERT, add_uuid, None, created_time)
+                    
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+    def update_rows(self, table, UPDATE, WHERE, modified_time=0):
+        ''' Update one or several rows into a table.
+        Atributes
+            UPDATE: dictionary with the key: value to change
+            table: table where to update
+            WHERE: dictionary of elements to update
+        Return: (result, descriptive text) where result indicates the number of updated files
+        '''
+        if table in self.tables_with_created_field and modified_time==0:
+            modified_time=time.time()
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor()
+                    return self._update_rows(table, UPDATE, WHERE)
+                    
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+    def delete_row_by_id(self, table, uuid):
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    #delete host
+                    self.cur = self.con.cursor()
+                    cmd = "DELETE FROM {} WHERE uuid = '{}'".format(table, uuid)
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    deleted = self.cur.rowcount
+                    if deleted:
+                        #delete uuid
+                        self.cur = self.con.cursor()
+                        cmd = "DELETE FROM uuids WHERE root_uuid = '{}'".format(uuid)
+                        self.logger.debug(cmd)
+                        self.cur.execute(cmd)
+                return deleted
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries, "delete", "dependencies")
+            tries -= 1
+
+    def delete_row(self, **sql_dict):
+        ''' Deletes rows from a table.
+        Attribute sql_dir: dictionary with the following key: value
+            'FROM': string of table name (Mandatory)
+            'WHERE': dict of key:values, translated to key=value AND ... (Optional)
+            'WHERE_NOT': dict of key:values, translated to key<>value AND ... (Optional) 
+                if value is None, it is translated to key is not null
+            'LIMIT': limit of number of rows (Optional)
+        Return: the number of deleted or exception if error
+        '''
+        #print sql_dict
+        from_  = "FROM " + str(sql_dict['FROM'])
+        #print 'from_', from_
+        if 'WHERE' in sql_dict and len(sql_dict['WHERE']) > 0:
+            w=sql_dict['WHERE']
+            where_ = "WHERE " + " AND ".join(map(self.__tuple2db_format_where, w.iteritems())) 
+        else: where_ = ""
+        if 'WHERE_NOT' in sql_dict and len(sql_dict['WHERE_NOT']) > 0: 
+            w=sql_dict['WHERE_NOT']
+            where_2 = " AND ".join(map(self.__tuple2db_format_where_not, w.iteritems()))
+            if len(where_)==0:   where_ = "WHERE " + where_2
+            else:                where_ = where_ + " AND " + where_2
+        #print 'where_', where_
+        limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
+        #print 'limit_', limit_
+        cmd =  " ".join( ("DELETE", from_, where_, limit_) )
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor()
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    deleted = self.cur.rowcount
+                return deleted
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+    def get_rows_by_id(self, table, uuid):
+        '''get row from a table based on uuid'''
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
+                    cmd="SELECT * FROM {} where uuid='{}'".format(str(table), str(uuid))
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    rows = self.cur.fetchall()
+                    return rows
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+    
+    def get_rows(self, **sql_dict):
+        ''' Obtain rows from a table.
+        Attribute sql_dir: dictionary with the following key: value
+            'SELECT':    list or tuple of fields to retrieve) (by default all)
+            'FROM':      string of table name (Mandatory)
+            'WHERE':     dict of key:values, translated to key=value (key is null) AND ... (Optional)
+            'WHERE_NOT': dict of key:values, translated to key<>value (key is not null) AND ... (Optional)
+            'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
+            'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional)
+            'LIMIT':     limit of number of rows (Optional)
+            'ORDER_BY':  list or tuple of fields to order
+        Return: a list with dictionaries at each row
+        '''
+        #print sql_dict
+        select_= "SELECT " + ("*" if 'SELECT' not in sql_dict else ",".join(map(str,sql_dict['SELECT'])) )
+        #print 'select_', select_
+        from_  = "FROM " + str(sql_dict['FROM'])
+        #print 'from_', from_
+        where_and = ""
+        where_or = ""
+        w=sql_dict.get('WHERE')
+        if w:
+            where_and = " AND ".join(map(self.__tuple2db_format_where, w.iteritems() ))
+        w=sql_dict.get('WHERE_NOT')
+        if w: 
+            if where_and: where_and += " AND "
+            where_and += " AND ".join(map(self.__tuple2db_format_where_not, w.iteritems() ) )
+        w=sql_dict.get('WHERE_OR')
+        if w:
+            where_or =  " OR ".join(map(self.__tuple2db_format_where, w.iteritems() ))
+        if where_and and where_or:
+            if sql_dict.get("WHERE_AND_OR") == "AND":
+                where_ = "WHERE " + where_and + " AND (" + where_or + ")"
+            else:
+                where_ = "WHERE (" + where_and + ") OR " + where_or
+        elif where_and and not where_or:
+            where_ = "WHERE " + where_and
+        elif not where_and and where_or:
+            where_ = "WHERE " + where_or
+        else:
+            where_ = ""
+        #print 'where_', where_
+        limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
+        order_ = "ORDER BY " + ",".join(map(str,sql_dict['SELECT'])) if 'ORDER_BY' in sql_dict else ""
+        
+        #print 'limit_', limit_
+        cmd =  " ".join( (select_, from_, where_, limit_, order_) )
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    rows = self.cur.fetchall()
+                    return rows
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+    def get_table_by_uuid_name(self, table, uuid_name, error_item_text=None, allow_serveral=False, WHERE_OR={}, WHERE_AND_OR="OR"):
+        ''' Obtain One row from a table based on name or uuid.
+        Attribute:
+            table: string of table name
+            uuid_name: name or uuid. If not uuid format is found, it is considered a name
+            allow_severeral: if False return ERROR if more than one row are founded 
+            error_item_text: in case of error it identifies the 'item' name for a proper output text 
+            'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
+            'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional  
+        Return: if allow_several==False, a dictionary with this row, or error if no item is found or more than one is found
+                if allow_several==True, a list of dictionaries with the row or rows, error if no item is found
+        '''
+
+        if error_item_text==None:
+            error_item_text = table
+        what = 'uuid' if af.check_valid_uuid(uuid_name) else 'name'
+        cmd =  " SELECT * FROM {} WHERE {}='{}'".format(table, what, uuid_name)
+        if WHERE_OR:
+            where_or =  " OR ".join(map(self.__tuple2db_format_where, WHERE_OR.iteritems() ))
+            if WHERE_AND_OR == "AND":
+                cmd += " AND (" + where_or + ")"
+            else:
+                cmd += " OR " + where_or
+
+        
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    number = self.cur.rowcount
+                    if number==0:
+                        return -HTTP_Not_Found, "No %s found with %s '%s'" %(error_item_text, what, uuid_name)
+                    elif number>1 and not allow_serveral: 
+                        return -HTTP_Bad_Request, "More than one %s found with %s '%s'" %(error_item_text, what, uuid_name)
+                    if allow_serveral:
+                        rows = self.cur.fetchall()
+                    else:
+                        rows = self.cur.fetchone()
+                    return rows
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+    def get_uuid(self, uuid):
+        '''check in the database if this uuid is already present'''
+        for retry_ in range(0,2):
+            try:
+                with self.con:
+                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
+                    self.cur.execute("SELECT * FROM uuids where uuid='" + str(uuid) + "'")
+                    rows = self.cur.fetchall()
+                    return self.cur.rowcount, rows
+            except (mdb.Error, AttributeError) as e:
+                print "nfvo_db.get_uuid DB Exception %d: %s" % (e.args[0], e.args[1])
+                r,c = self._format_error(e)
+                if r!=-HTTP_Request_Timeout or retry_==1: return r,c
+
+    def get_uuid_from_name(self, table, name):
+        '''Searchs in table the name and returns the uuid
+        ''' 
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
+                    where_text = "name='" + name +"'"
+                    self.cur.execute("SELECT * FROM " + table + " WHERE "+ where_text)
+                    rows = self.cur.fetchall()
+                    if self.cur.rowcount==0:
+                        return 0, "Name %s not found in table %s" %(name, table)
+                    elif self.cur.rowcount>1:
+                        return self.cur.rowcount, "More than one VNF with name %s found in table %s" %(name, table)
+                    return self.cur.rowcount, rows[0]["uuid"]
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
diff --git a/osm_ro/httpserver.py b/osm_ro/httpserver.py
new file mode 100644 (file)
index 0000000..a0216e1
--- /dev/null
@@ -0,0 +1,1267 @@
+# -*- 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
+##
+
+'''
+HTTP server implementing the openmano API. It will answer to POST, PUT, GET methods in the appropriate URLs
+and will use the nfvo.py module to run the appropriate method.
+Every YAML/JSON file is checked against a schema in openmano_schemas.py module.  
+'''
+__author__="Alfonso Tierno, Gerardo Garcia"
+__date__ ="$17-sep-2014 09:07:15$"
+
+import bottle
+import yaml
+import json
+import threading
+import time
+import logging
+
+from jsonschema import validate as js_v, exceptions as js_e
+from openmano_schemas import vnfd_schema_v01, vnfd_schema_v02, \
+                            nsd_schema_v01, nsd_schema_v02, nsd_schema_v03, scenario_edit_schema, \
+                            scenario_action_schema, instance_scenario_action_schema, instance_scenario_create_schema_v01, \
+                            tenant_schema, tenant_edit_schema,\
+                            datacenter_schema, datacenter_edit_schema, datacenter_action_schema, datacenter_associate_schema,\
+                            object_schema, netmap_new_schema, netmap_edit_schema
+import nfvo
+import utils
+from db_base import db_base_Exception
+from functools import wraps
+
+global mydb
+global url_base
+global logger
+url_base="/openmano"
+logger = None
+
+HTTP_Bad_Request =          400
+HTTP_Unauthorized =         401 
+HTTP_Not_Found =            404 
+HTTP_Forbidden =            403
+HTTP_Method_Not_Allowed =   405 
+HTTP_Not_Acceptable =       406
+HTTP_Service_Unavailable =  503 
+HTTP_Internal_Server_Error= 500 
+
+def delete_nulls(var):
+    if type(var) is dict:
+        for k in var.keys():
+            if var[k] is None: del var[k]
+            elif type(var[k]) is dict or type(var[k]) is list or type(var[k]) is tuple: 
+                if delete_nulls(var[k]): del var[k]
+        if len(var) == 0: return True
+    elif type(var) is list or type(var) is tuple:
+        for k in var:
+            if type(k) is dict: delete_nulls(k)
+        if len(var) == 0: return True
+    return False
+
+def convert_datetime2str(var):
+    '''Converts a datetime variable to a string with the format '%Y-%m-%dT%H:%i:%s'
+    It enters recursively in the dict var finding this kind of variables
+    '''
+    if type(var) is dict:
+        for k,v in var.items():
+            if type(v) is float and k in ("created_at", "modified_at"):
+                var[k] = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(v) )
+            elif type(v) is dict or type(v) is list or type(v) is tuple: 
+                convert_datetime2str(v)
+        if len(var) == 0: return True
+    elif type(var) is list or type(var) is tuple:
+        for v in var:
+            convert_datetime2str(v)
+
+def log_to_logger(fn):
+    '''
+    Wrap a Bottle request so that a log line is emitted after it's handled.
+    (This decorator can be extended to take the desired logger as a param.)
+    '''
+    @wraps(fn)
+    def _log_to_logger(*args, **kwargs):
+        actual_response = fn(*args, **kwargs)
+        # modify this to log exactly what you need:
+        logger.info('FROM %s %s %s %s' % (bottle.request.remote_addr,
+                                        bottle.request.method,
+                                        bottle.request.url,
+                                        bottle.response.status))
+        return actual_response
+    return _log_to_logger
+
+class httpserver(threading.Thread):
+    def __init__(self, db, admin=False, host='localhost', port=9090):
+        #global url_base
+        global mydb
+        global logger
+        #initialization
+        if not logger:
+            logger = logging.getLogger('openmano.http')
+        threading.Thread.__init__(self)
+        self.host = host
+        self.port = port   #Port where the listen service must be started
+        if admin==True:
+            self.name = "http_admin"
+        else:
+            self.name = "http"
+            #self.url_preffix = 'http://' + host + ':' + str(port) + url_base
+            mydb = db
+        #self.first_usable_connection_index = 10
+        #self.next_connection_index = self.first_usable_connection_index #The next connection index to be used 
+        #Ensure that when the main program exits the thread will also exit
+        self.daemon = True
+        self.setDaemon(True)
+         
+    def run(self):
+        bottle.install(log_to_logger)
+        bottle.run(host=self.host, port=self.port, debug=False, quiet=True)
+           
+def run_bottle(db, host_='localhost', port_=9090):
+    '''used for launching in main thread, so that it can be debugged'''
+    global mydb
+    mydb = db
+    bottle.run(host=host_, port=port_, debug=True) #quiet=True
+    
+
+@bottle.route(url_base + '/', method='GET')
+def http_get():
+    #print 
+    return 'works' #TODO: to be completed
+
+#
+# Util functions
+#
+
+def change_keys_http2db(data, http_db, reverse=False):
+    '''Change keys of dictionary data acording to the key_dict values
+    This allow change from http interface names to database names.
+    When reverse is True, the change is otherwise
+    Attributes:
+        data: can be a dictionary or a list
+        http_db: is a dictionary with hhtp names as keys and database names as value
+        reverse: by default change is done from http api to database. If True change is done otherwise
+    Return: None, but data is modified'''
+    if type(data) is tuple or type(data) is list:
+        for d in data:
+            change_keys_http2db(d, http_db, reverse)
+    elif type(data) is dict or type(data) is bottle.FormsDict:
+        if reverse:
+            for k,v in http_db.items():
+                if v in data: data[k]=data.pop(v)
+        else:
+            for k,v in http_db.items():
+                if k in data: data[v]=data.pop(k)
+
+def format_out(data):
+    '''return string of dictionary data according to requested json, yaml, xml. By default json'''
+    logger.debug("OUT: " + yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) )
+    if 'application/yaml' in bottle.request.headers.get('Accept'):
+        bottle.response.content_type='application/yaml'
+        return yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) #, canonical=True, default_style='"'
+    else: #by default json
+        bottle.response.content_type='application/json'
+        #return data #json no style
+        return json.dumps(data, indent=4) + "\n"
+
+def format_in(default_schema, version_fields=None, version_dict_schema=None):
+    ''' Parse the content of HTTP request against a json_schema
+        Parameters
+            default_schema: The schema to be parsed by default if no version field is found in the client data
+            version_fields: If provided it contains a tuple or list with the fields to iterate across the client data to obtain the version
+            version_dict_schema: It contains a dictionary with the version as key, and json schema to apply as value
+                It can contain a None as key, and this is apply if the client data version does not match any key 
+        Return:
+            user_data, used_schema: if the data is successfully decoded and matches the schema
+            launch a bottle abort if fails
+    '''
+    #print "HEADERS :" + str(bottle.request.headers.items())
+    try:
+        error_text = "Invalid header format "
+        format_type = bottle.request.headers.get('Content-Type', 'application/json')
+        if 'application/json' in format_type:
+            error_text = "Invalid json format "
+            #Use the json decoder instead of bottle decoder because it informs about the location of error formats with a ValueError exception
+            client_data = json.load(bottle.request.body)
+            #client_data = bottle.request.json()
+        elif 'application/yaml' in format_type:
+            error_text = "Invalid yaml format "
+            client_data = yaml.load(bottle.request.body)
+        elif 'application/xml' in format_type:
+            bottle.abort(501, "Content-Type: application/xml not supported yet.")
+        else:
+            logger.warning('Content-Type ' + str(format_type) + ' not supported.')
+            bottle.abort(HTTP_Not_Acceptable, 'Content-Type ' + str(format_type) + ' not supported.')
+            return
+        #if client_data == None:
+        #    bottle.abort(HTTP_Bad_Request, "Content error, empty")
+        #    return
+
+        logger.debug('IN: %s', yaml.safe_dump(client_data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) )
+        #look for the client provider version
+        error_text = "Invalid content "
+        client_version = None
+        used_schema = None
+        if version_fields != None:
+            client_version = client_data
+            for field in version_fields:
+                if field in client_version:
+                    client_version = client_version[field]
+                else:
+                    client_version=None
+                    break
+        if client_version==None:
+            used_schema=default_schema
+        elif version_dict_schema!=None:
+            if client_version in version_dict_schema:
+                used_schema = version_dict_schema[client_version]
+            elif None in version_dict_schema:
+                used_schema = version_dict_schema[None]
+        if used_schema==None:
+            bottle.abort(HTTP_Bad_Request, "Invalid schema version or missing version field")
+            
+        js_v(client_data, used_schema)
+        return client_data, used_schema
+    except (ValueError, yaml.YAMLError) as exc:
+        error_text += str(exc)
+        logger.error(error_text) 
+        bottle.abort(HTTP_Bad_Request, error_text)
+    except js_e.ValidationError as exc:
+        logger.error("validate_in error, jsonschema exception at '%s' '%s' ", str(exc.path), str(exc.message))
+        error_pos = ""
+        if len(exc.path)>0: error_pos=" at " + ":".join(map(json.dumps, exc.path))
+        bottle.abort(HTTP_Bad_Request, error_text + exc.message + error_pos)
+    #except:
+    #    bottle.abort(HTTP_Bad_Request, "Content error: Failed to parse Content-Type",  error_pos)
+    #    raise
+
+def filter_query_string(qs, http2db, allowed):
+    '''Process query string (qs) checking that contains only valid tokens for avoiding SQL injection
+    Attributes:
+        'qs': bottle.FormsDict variable to be processed. None or empty is considered valid
+        'http2db': dictionary with change from http API naming (dictionary key) to database naming(dictionary value)
+        'allowed': list of allowed string tokens (API http naming). All the keys of 'qs' must be one of 'allowed'
+    Return: A tuple with the (select,where,limit) to be use in a database query. All of then transformed to the database naming
+        select: list of items to retrieve, filtered by query string 'field=token'. If no 'field' is present, allowed list is returned
+        where: dictionary with key, value, taken from the query string token=value. Empty if nothing is provided
+        limit: limit dictated by user with the query string 'limit'. 100 by default
+    abort if not permited, using bottel.abort
+    '''
+    where={}
+    limit=100
+    select=[]
+    #if type(qs) is not bottle.FormsDict:
+    #    bottle.abort(HTTP_Internal_Server_Error, '!!!!!!!!!!!!!!invalid query string not a dictionary')
+    #    #bottle.abort(HTTP_Internal_Server_Error, "call programmer")
+    for k in qs:
+        if k=='field':
+            select += qs.getall(k)
+            for v in select:
+                if v not in allowed:
+                    bottle.abort(HTTP_Bad_Request, "Invalid query string at 'field="+v+"'")
+        elif k=='limit':
+            try:
+                limit=int(qs[k])
+            except:
+                bottle.abort(HTTP_Bad_Request, "Invalid query string at 'limit="+qs[k]+"'")
+        else:
+            if k not in allowed:
+                bottle.abort(HTTP_Bad_Request, "Invalid query string at '"+k+"="+qs[k]+"'")
+            if qs[k]!="null":  where[k]=qs[k]
+            else: where[k]=None 
+    if len(select)==0: select += allowed
+    #change from http api to database naming
+    for i in range(0,len(select)):
+        k=select[i]
+        if http2db and k in http2db: 
+            select[i] = http2db[k]
+    if http2db:
+        change_keys_http2db(where, http2db)
+    #print "filter_query_string", select,where,limit
+    
+    return select,where,limit
+
+@bottle.hook('after_request')
+def enable_cors():
+    '''Don't know yet if really needed. Keep it just in case'''
+    bottle.response.headers['Access-Control-Allow-Origin'] = '*'
+
+#
+# VNFs
+#
+
+@bottle.route(url_base + '/tenants', method='GET')
+def http_get_tenants():
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    select_,where_,limit_ = filter_query_string(bottle.request.query, None,
+            ('uuid','name','description','created_at') )
+    try:
+        tenants = mydb.get_rows(FROM='nfvo_tenants', SELECT=select_,WHERE=where_,LIMIT=limit_)
+        #change_keys_http2db(content, http2db_tenant, reverse=True)
+        convert_datetime2str(tenants)
+        data={'tenants' : tenants}
+        return format_out(data)
+    except db_base_Exception as e:
+        logger.error("http_get_tenants error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/tenants/<tenant_id>', method='GET')
+def http_get_tenant_id(tenant_id):
+    '''get tenant details, can use both uuid or name'''
+    #obtain data
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        tenant = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id, "tenant") 
+        #change_keys_http2db(content, http2db_tenant, reverse=True)
+        convert_datetime2str(tenant)
+        data={'tenant' : tenant}
+        return format_out(data)
+    except db_base_Exception as e:
+        logger.error("http_get_tenant_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/tenants', method='POST')
+def http_post_tenants():
+    '''insert a tenant into the catalogue. '''
+    #parse input data
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    http_content,_ = format_in( tenant_schema )
+    r = utils.remove_extra_items(http_content, tenant_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    try: 
+        data = nfvo.new_tenant(mydb, http_content['tenant'])
+        return http_get_tenant_id(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_post_tenants error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/tenants/<tenant_id>', method='PUT')
+def http_edit_tenant_id(tenant_id):
+    '''edit tenant details, can use both uuid or name'''
+    #parse input data
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    http_content,_ = format_in( tenant_edit_schema )
+    r = utils.remove_extra_items(http_content, tenant_edit_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    
+    #obtain data, check that only one exist
+    try: 
+        tenant = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id)
+        #edit data 
+        tenant_id = tenant['uuid']
+        where={'uuid': tenant['uuid']}
+        mydb.update_rows('nfvo_tenants', http_content['tenant'], where)
+        return http_get_tenant_id(tenant_id)
+    except db_base_Exception as e:
+        logger.error("http_edit_tenant_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/tenants/<tenant_id>', method='DELETE')
+def http_delete_tenant_id(tenant_id):
+    '''delete a tenant from database, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        data = nfvo.delete_tenant(mydb, tenant_id)
+        return format_out({"result":"tenant " + data + " deleted"})
+    except db_base_Exception as e:
+        logger.error("http_delete_tenant_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/datacenters', method='GET')
+def http_get_datacenters(tenant_id):
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        if tenant_id != 'any':
+            #check valid tenant_id
+            nfvo.check_tenant(mydb, tenant_id)
+        select_,where_,limit_ = filter_query_string(bottle.request.query, None,
+                ('uuid','name','vim_url','type','created_at') )
+        if tenant_id != 'any':
+            where_['nfvo_tenant_id'] = tenant_id
+            if 'created_at' in select_:
+                select_[ select_.index('created_at') ] = 'd.created_at as created_at'
+            if 'created_at' in where_:
+                where_['d.created_at'] = where_.pop('created_at')
+            datacenters = mydb.get_rows(FROM='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id',
+                                          SELECT=select_,WHERE=where_,LIMIT=limit_)
+        else:
+            datacenters = mydb.get_rows(FROM='datacenters',
+                                          SELECT=select_,WHERE=where_,LIMIT=limit_)
+        #change_keys_http2db(content, http2db_tenant, reverse=True)
+        convert_datetime2str(datacenters)
+        data={'datacenters' : datacenters}
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_datacenters error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='GET')
+def http_get_datacenter_id(tenant_id, datacenter_id):
+    '''get datacenter details, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        if tenant_id != 'any':
+            #check valid tenant_id
+            nfvo.check_tenant(mydb, tenant_id)
+        #obtain data
+        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', '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
+            from_='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id'
+        else:
+            from_='datacenters as d'
+        datacenters = mydb.get_rows(
+                    SELECT=select_,
+                    FROM=from_,
+                    WHERE=where_)
+    
+        if len(datacenters)==0:
+            bottle.abort( HTTP_Not_Found, "No datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
+        elif len(datacenters)>1: 
+            bottle.abort( HTTP_Bad_Request, "More than one datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
+        datacenter = datacenters[0]
+        if tenant_id != 'any':
+            #get vim tenant info
+            vim_tenants = mydb.get_rows(
+                    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 as e:
+                        logger.error("Exception '%s' while trying to load config information", str(e))
+
+        if datacenter['config'] != None:
+            try:
+                config_dict = yaml.load(datacenter['config'])
+                datacenter['config'] = config_dict
+            except Exception as e:
+                logger.error("Exception '%s' while trying to load config information", str(e))
+        #change_keys_http2db(content, http2db_datacenter, reverse=True)
+        convert_datetime2str(datacenter)
+        data={'datacenter' : datacenter}
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_datacenter_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/datacenters', method='POST')
+def http_post_datacenters():
+    '''insert a tenant into the catalogue. '''
+    #parse input data
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    http_content,_ = format_in( datacenter_schema )
+    r = utils.remove_extra_items(http_content, datacenter_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    try:
+        data = nfvo.new_datacenter(mydb, http_content['datacenter'])
+        return http_get_datacenter_id('any', data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_post_datacenters error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/datacenters/<datacenter_id_name>', method='PUT')
+def http_edit_datacenter_id(datacenter_id_name):
+    '''edit datacenter details, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    #parse input data
+    http_content,_ = format_in( datacenter_edit_schema )
+    r = utils.remove_extra_items(http_content, datacenter_edit_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    
+    try:
+        datacenter_id = nfvo.edit_datacenter(mydb, datacenter_id_name, http_content['datacenter'])
+        return http_get_datacenter_id('any', datacenter_id)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_edit_datacenter_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/networks', method='GET')  #deprecated
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='GET')
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='GET')
+def http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
+    '''get datacenter networks, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    #obtain data
+    try:
+        datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter") 
+        where_= {"datacenter_id":datacenter_dict['uuid']}
+        if netmap_id:
+            if utils.check_valid_uuid(netmap_id):
+                where_["uuid"] = netmap_id
+            else:
+                where_["name"] = netmap_id
+        netmaps =mydb.get_rows(FROM='datacenter_nets',
+                                        SELECT=('name','vim_net_id as vim_id', 'uuid', 'type','multipoint','shared','description', 'created_at'),
+                                        WHERE=where_ ) 
+        convert_datetime2str(netmaps)
+        utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
+        if netmap_id and len(netmaps)==1:
+            data={'netmap' : netmaps[0]}
+        elif netmap_id and len(netmaps)==0:
+            bottle.abort(HTTP_Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
+            return 
+        else:
+            data={'netmaps' : netmaps}
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_getnetwork_datacenter_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='DELETE')
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='DELETE')
+def http_delnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
+    '''get datacenter networks, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    #obtain data
+    try:
+        datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter") 
+        where_= {"datacenter_id":datacenter_dict['uuid']}
+        if netmap_id:
+            if utils.check_valid_uuid(netmap_id):
+                where_["uuid"] = netmap_id
+            else:
+                where_["name"] = netmap_id
+        #change_keys_http2db(content, http2db_tenant, reverse=True)
+        deleted = mydb.delete_row(FROM='datacenter_nets', WHERE= where_) 
+        if deleted == 0 and netmap_id :
+            bottle.abort(HTTP_Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
+        if netmap_id:
+            return format_out({"result": "netmap %s deleted" % netmap_id})
+        else:
+            return format_out({"result": "%d netmap deleted" % deleted})
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_delnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/upload', method='POST')
+def http_uploadnetmap_datacenter_id(tenant_id, datacenter_id):
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, None)
+        convert_datetime2str(netmaps)
+        utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
+        data={'netmaps' : netmaps}
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_uploadnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='POST')
+def http_postnetmap_datacenter_id(tenant_id, datacenter_id):
+    '''creates a new netmap'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    #parse input data
+    http_content,_ = format_in( netmap_new_schema )
+    r = utils.remove_extra_items(http_content, netmap_new_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    try:
+        #obtain data, check that only one exist
+        netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, http_content)
+        convert_datetime2str(netmaps)
+        utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
+        data={'netmaps' : netmaps}
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_postnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='PUT')
+def http_putnettmap_datacenter_id(tenant_id, datacenter_id, netmap_id):
+    '''edit a  netmap'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    #parse input data
+    http_content,_ = format_in( netmap_edit_schema )
+    r = utils.remove_extra_items(http_content, netmap_edit_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    
+    #obtain data, check that only one exist
+    try:
+        nfvo.datacenter_edit_netmap(mydb, tenant_id, datacenter_id, netmap_id, http_content)
+        return http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_putnettmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+    
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/action', method='POST')
+def http_action_datacenter_id(tenant_id, datacenter_id):
+    '''perform an action over datacenter, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    #parse input data
+    http_content,_ = format_in( datacenter_action_schema )
+    r = utils.remove_extra_items(http_content, datacenter_action_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    try:
+        #obtain data, check that only one exist
+        result = nfvo.datacenter_action(mydb, tenant_id, datacenter_id, http_content)
+        if 'net-update' in http_content:
+            return http_getnetmap_datacenter_id(datacenter_id)
+        else:
+            return format_out(result)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_action_datacenter_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/datacenters/<datacenter_id>', method='DELETE')
+def http_delete_datacenter_id( datacenter_id):
+    '''delete a tenant from database, can use both uuid or name'''
+    
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        data = nfvo.delete_datacenter(mydb, datacenter_id)
+        return format_out({"result":"datacenter '" + data + "' deleted"})
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_delete_datacenter_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='POST')
+def http_associate_datacenters(tenant_id, datacenter_id):
+    '''associate an existing datacenter to a this tenant. '''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    #parse input data
+    http_content,_ = format_in( datacenter_associate_schema )
+    r = utils.remove_extra_items(http_content, datacenter_associate_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    try:
+        id_ = nfvo.associate_datacenter_to_tenant(mydb, 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('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)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='DELETE')
+def http_deassociate_datacenters(tenant_id, datacenter_id):
+    '''deassociate an existing datacenter to a this tenant. '''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        data = nfvo.deassociate_datacenter_to_tenant(mydb, tenant_id, datacenter_id)
+        return format_out({"result": data})
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_deassociate_datacenters error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+       
+@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='GET')
+@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='GET')
+def http_get_vim_items(tenant_id, datacenter_id, item, name=None):
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        data = nfvo.vim_action_get(mydb, tenant_id, datacenter_id, item, name)
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_vim_items error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='DELETE')
+def http_del_vim_items(tenant_id, datacenter_id, item, name):
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        data = nfvo.vim_action_delete(mydb, tenant_id, datacenter_id, item, name)
+        return format_out({"result":data})
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_del_vim_items error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='POST')
+def http_post_vim_items(tenant_id, datacenter_id, item):
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    http_content,_ = format_in( object_schema )
+    try:
+        data = nfvo.vim_action_create(mydb, tenant_id, datacenter_id, item, http_content)
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_post_vim_items error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/vnfs', method='GET')
+def http_get_vnfs(tenant_id):
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        if tenant_id != 'any':
+            #check valid tenant_id
+            nfvo.check_tenant(mydb, tenant_id)
+        select_,where_,limit_ = filter_query_string(bottle.request.query, None,
+                ('uuid','name','description','public', "tenant_id", "created_at") )
+        where_or = {}
+        if tenant_id != "any":
+            where_or["tenant_id"] = tenant_id
+            where_or["public"] = True
+        vnfs = mydb.get_rows(FROM='vnfs', SELECT=select_,WHERE=where_,WHERE_OR=where_or, WHERE_AND_OR="AND",LIMIT=limit_)
+        #change_keys_http2db(content, http2db_vnf, reverse=True)
+        utils.convert_str2boolean(vnfs, ('public',))
+        convert_datetime2str(vnfs)
+        data={'vnfs' : vnfs}
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_vnfs error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='GET')
+def http_get_vnf_id(tenant_id,vnf_id):
+    '''get vnf details, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        vnf = nfvo.get_vnf_id(mydb,tenant_id,vnf_id)
+        utils.convert_str2boolean(vnf, ('public',))
+        convert_datetime2str(vnf)
+        return format_out(vnf)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_vnf_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/vnfs', method='POST')
+def http_post_vnfs(tenant_id):
+    '''insert a vnf into the catalogue. Creates the flavor and images in the VIM, and creates the VNF and its internal structure in the OPENMANO DB'''
+    #print "Parsing the YAML file of the VNF"
+    #parse input data
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    http_content, used_schema = format_in( vnfd_schema_v01, ("schema_version",), {"0.2": vnfd_schema_v02})
+    r = utils.remove_extra_items(http_content, used_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    try:
+        if used_schema == vnfd_schema_v01:
+            vnf_id = nfvo.new_vnf(mydb,tenant_id,http_content)
+        elif used_schema == vnfd_schema_v02:
+            vnf_id = nfvo.new_vnf_v02(mydb,tenant_id,http_content)
+        else:
+            logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
+            bottle.abort(HTTP_Bad_Request, "Invalid schema version")
+        return http_get_vnf_id(tenant_id, vnf_id)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_post_vnfs error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+            
+@bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='DELETE')
+def http_delete_vnf_id(tenant_id,vnf_id):
+    '''delete a vnf from database, and images and flavors in VIM when appropriate, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    #check valid tenant_id and deletes the vnf, including images, 
+    try:
+        data = nfvo.delete_vnf(mydb,tenant_id,vnf_id)
+        #print json.dumps(data, indent=4)
+        return format_out({"result":"VNF " + data + " deleted"})
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_delete_vnf_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+#@bottle.route(url_base + '/<tenant_id>/hosts/topology', method='GET')
+#@bottle.route(url_base + '/<tenant_id>/physicalview/Madrid-Alcantara', method='GET')
+@bottle.route(url_base + '/<tenant_id>/physicalview/<datacenter>', method='GET')
+def http_get_hosts(tenant_id, datacenter):
+    '''get the tidvim host hopology from the vim.'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    #print "http_get_hosts received by tenant " + tenant_id + ' datacenter ' + datacenter
+    try:
+        if datacenter == 'treeview':
+            data = nfvo.get_hosts(mydb, tenant_id)
+        else:
+            #openmano-gui is using a hardcoded value for the datacenter
+            result, data = nfvo.get_hosts_info(mydb, tenant_id) #, datacenter)
+        
+        if result < 0:
+            #print "http_get_hosts error %d %s" % (-result, data)
+            bottle.abort(-result, data)
+        else:
+            convert_datetime2str(data)
+            #print json.dumps(data, indent=4)
+            return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_hosts error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<path:path>', method='OPTIONS')
+def http_options_deploy(path):
+    '''For some reason GUI web ask for OPTIONS that must be responded'''
+    #TODO: check correct path, and correct headers request
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    bottle.response.set_header('Access-Control-Allow-Methods','POST, GET, PUT, DELETE, OPTIONS')
+    bottle.response.set_header('Accept','application/yaml,application/json')
+    bottle.response.set_header('Content-Type','application/yaml,application/json')
+    bottle.response.set_header('Access-Control-Allow-Headers','content-type')
+    bottle.response.set_header('Access-Control-Allow-Origin','*')
+    return
+
+@bottle.route(url_base + '/<tenant_id>/topology/deploy', method='POST')
+def http_post_deploy(tenant_id):
+    '''post topology deploy.'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+
+    http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02})
+    #r = utils.remove_extra_items(http_content, used_schema)
+    #if r is not None: print "http_post_deploy: Warning: remove extra items ", r
+    #print "http_post_deploy input: ",  http_content
+    
+    try:
+        scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
+        instance = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['name'], http_content['name'])
+        #print json.dumps(data, indent=4)
+        return format_out(instance)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_post_deploy error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/topology/verify', method='POST')
+def http_post_verify(tenant_id):
+    #TODO:
+#    '''post topology verify'''
+#    print "http_post_verify by tenant " + tenant_id + ' datacenter ' + datacenter
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    return 
+
+#
+# SCENARIOS
+#
+
+@bottle.route(url_base + '/<tenant_id>/scenarios', method='POST')
+def http_post_scenarios(tenant_id):
+    '''add a scenario into the catalogue. Creates the scenario and its internal structure in the OPENMANO DB'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02, "0.3": nsd_schema_v03})
+    #r = utils.remove_extra_items(http_content, used_schema)
+    #if r is not None: print "http_post_scenarios: Warning: remove extra items ", r
+    #print "http_post_scenarios input: ",  http_content
+    try:
+        if used_schema == nsd_schema_v01:
+            scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
+        elif used_schema == nsd_schema_v02:
+            scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content, "0.2")
+        elif used_schema == nsd_schema_v03:
+            scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content, "0.3")
+        else:
+            logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
+            bottle.abort(HTTP_Bad_Request, "Invalid schema version")
+        #print json.dumps(data, indent=4)
+        #return format_out(data)
+        return http_get_scenario_id(tenant_id, scenario_id)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_post_scenarios error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>/action', method='POST')
+def http_post_scenario_action(tenant_id, scenario_id):
+    '''take an action over a scenario'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    # parse input data
+    http_content, _ = format_in(scenario_action_schema)
+    r = utils.remove_extra_items(http_content, scenario_action_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    try:
+        # check valid tenant_id
+        nfvo.check_tenant(mydb, tenant_id)
+        if "start" in http_content:
+            data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['start']['instance_name'], \
+                        http_content['start'].get('description',http_content['start']['instance_name']),
+                        http_content['start'].get('datacenter') )
+            return format_out(data)
+        elif "deploy" in http_content:   #Equivalent to start
+            data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['deploy']['instance_name'],
+                        http_content['deploy'].get('description',http_content['deploy']['instance_name']),
+                        http_content['deploy'].get('datacenter') )
+            return format_out(data)
+        elif "reserve" in http_content:   #Reserve resources
+            data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['reserve']['instance_name'],
+                        http_content['reserve'].get('description',http_content['reserve']['instance_name']),
+                        http_content['reserve'].get('datacenter'),  startvms=False )
+            return format_out(data)
+        elif "verify" in http_content:   #Equivalent to start and then delete
+            data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['verify']['instance_name'],
+                        http_content['verify'].get('description',http_content['verify']['instance_name']),
+                        http_content['verify'].get('datacenter'), startvms=False )
+            instance_id = data['uuid']
+            nfvo.delete_instance(mydb, tenant_id,instance_id)
+            return format_out({"result":"Verify OK"})
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_post_scenario_action error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/scenarios', method='GET')
+def http_get_scenarios(tenant_id):
+    '''get scenarios list'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        #check valid tenant_id
+        if tenant_id != "any":
+            nfvo.check_tenant(mydb, tenant_id) 
+        #obtain data
+        s,w,l=filter_query_string(bottle.request.query, None, ('uuid', 'name', 'description', 'tenant_id', 'created_at', 'public'))
+        where_or={}
+        if tenant_id != "any":
+            where_or["tenant_id"] = tenant_id
+            where_or["public"] = True
+        scenarios = mydb.get_rows(SELECT=s, WHERE=w, WHERE_OR=where_or, WHERE_AND_OR="AND", LIMIT=l, FROM='scenarios')
+        convert_datetime2str(scenarios)
+        utils.convert_str2boolean(scenarios, ('public',) )
+        data={'scenarios':scenarios}
+        #print json.dumps(scenarios, indent=4)
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_scenarios error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='GET')
+def http_get_scenario_id(tenant_id, scenario_id):
+    '''get scenario details, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        #check valid tenant_id
+        if tenant_id != "any":
+            nfvo.check_tenant(mydb, tenant_id) 
+        #obtain data
+        scenario = mydb.get_scenario(scenario_id, tenant_id)
+        convert_datetime2str(scenario)
+        data={'scenario' : scenario}
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_scenarios error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='DELETE')
+def http_delete_scenario_id(tenant_id, scenario_id):
+    '''delete a scenario from database, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        #check valid tenant_id
+        if tenant_id != "any":
+            nfvo.check_tenant(mydb, tenant_id)
+        #obtain data
+        data = mydb.delete_scenario(scenario_id, tenant_id)
+        #print json.dumps(data, indent=4)
+        return format_out({"result":"scenario " + data + " deleted"})
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_delete_scenario_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='PUT')
+def http_put_scenario_id(tenant_id, scenario_id):
+    '''edit an existing scenario id'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    http_content,_ = format_in( scenario_edit_schema )
+    #r = utils.remove_extra_items(http_content, scenario_edit_schema)
+    #if r is not None: print "http_put_scenario_id: Warning: remove extra items ", r
+    #print "http_put_scenario_id input: ",  http_content
+    try:
+        nfvo.edit_scenario(mydb, tenant_id, scenario_id, http_content)
+        #print json.dumps(data, indent=4)
+        #return format_out(data)
+        return http_get_scenario_id(tenant_id, scenario_id)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_put_scenario_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+@bottle.route(url_base + '/<tenant_id>/instances', method='POST')
+def http_post_instances(tenant_id):
+    '''create an instance-scenario'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    # parse input data
+    http_content, used_schema = format_in(instance_scenario_create_schema_v01)
+    r = utils.remove_extra_items(http_content, used_schema)
+    if r is not None:
+        logger.warning("http_post_instances: Warning: remove extra items %s", str(r))
+    try:
+        #check valid tenant_id
+        if tenant_id != "any":
+            nfvo.check_tenant(mydb, tenant_id) 
+        data = nfvo.create_instance(mydb, tenant_id, http_content["instance"])
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_post_instances error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+#
+# INSTANCES
+#
+@bottle.route(url_base + '/<tenant_id>/instances', method='GET')
+def http_get_instances(tenant_id):
+    '''get instance list'''
+    try:
+        #check valid tenant_id
+        if tenant_id != "any":
+            nfvo.check_tenant(mydb, tenant_id) 
+        #obtain data
+        s,w,l=filter_query_string(bottle.request.query, None, ('uuid', 'name', 'scenario_id', 'tenant_id', 'description', 'created_at'))
+        if tenant_id != "any":
+            w['tenant_id'] = tenant_id
+        instances = mydb.get_rows(SELECT=s, WHERE=w, LIMIT=l, FROM='instance_scenarios')
+        convert_datetime2str(instances)
+        utils.convert_str2boolean(instances, ('public',) )
+        data={'instances':instances}
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_instances error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='GET')
+def http_get_instance_id(tenant_id, instance_id):
+    '''get instances details, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        #check valid tenant_id
+        if tenant_id != "any":
+            nfvo.check_tenant(mydb, tenant_id) 
+        if tenant_id == "any":
+            tenant_id = None
+        #obtain data (first time is only to check that the instance exists)
+        instance_dict = mydb.get_instance_scenario(instance_id, tenant_id, verbose=True)
+        try:
+            nfvo.refresh_instance(mydb, tenant_id, instance_dict)
+        except (nfvo.NfvoException, db_base_Exception) as e:
+            logger.warn("nfvo.refresh_instance couldn't refresh the status of the instance: %s" % str(e))
+        #obtain data with results upated
+        instance = mydb.get_instance_scenario(instance_id, tenant_id)
+        convert_datetime2str(instance)
+        #print json.dumps(instance, indent=4)
+        return format_out(instance)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_get_instance_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='DELETE')
+def http_delete_instance_id(tenant_id, instance_id):
+    '''delete instance from VIM and from database, can use both uuid or name'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    try:
+        #check valid tenant_id
+        if tenant_id != "any":
+            nfvo.check_tenant(mydb, tenant_id) 
+        if tenant_id == "any":
+            tenant_id = None
+        #obtain data
+        message = nfvo.delete_instance(mydb, tenant_id,instance_id)
+        return format_out({"result":message})
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_delete_instance_id error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action', method='POST')
+def http_post_instance_scenario_action(tenant_id, instance_id):
+    '''take an action over a scenario instance'''
+    logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+    # parse input data
+    http_content, _ = format_in(instance_scenario_action_schema)
+    r = utils.remove_extra_items(http_content, instance_scenario_action_schema)
+    if r:
+        logger.debug("Remove received extra items %s", str(r))
+    try:
+        #check valid tenant_id
+        if tenant_id != "any":
+            nfvo.check_tenant(mydb, tenant_id) 
+
+        #print "http_post_instance_scenario_action input: ", http_content
+        #obtain data
+        instance = mydb.get_instance_scenario(instance_id, tenant_id)
+        instance_id = instance["uuid"]
+        
+        data = nfvo.instance_action(mydb, tenant_id, instance_id, http_content)
+        return format_out(data)
+    except (nfvo.NfvoException, db_base_Exception) as e:
+        logger.error("http_post_instance_scenario_action error {}: {}".format(e.http_code, str(e)))
+        bottle.abort(e.http_code, str(e))
+    except Exception as e:
+        logger.error("Unexpected exception: ", exc_info=True)
+        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+
+@bottle.error(400)
+@bottle.error(401) 
+@bottle.error(404) 
+@bottle.error(403)
+@bottle.error(405) 
+@bottle.error(406)
+@bottle.error(409)
+@bottle.error(503) 
+@bottle.error(500)
+def error400(error):
+    e={"error":{"code":error.status_code, "type":error.status, "description":error.body}}
+    bottle.response.headers['Access-Control-Allow-Origin'] = '*'
+    return format_out(e)
+
diff --git a/osm_ro/nfvo.py b/osm_ro/nfvo.py
new file mode 100644 (file)
index 0000000..14ec54f
--- /dev/null
@@ -0,0 +1,3056 @@
+# -*- 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
+##
+
+'''
+NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances
+'''
+__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
+__date__ ="$16-sep-2014 22:05:01$"
+
+import imp
+#import json
+import yaml
+import utils
+import vim_thread
+from db_base import HTTP_Unauthorized, HTTP_Bad_Request, HTTP_Internal_Server_Error, HTTP_Not_Found,\
+    HTTP_Conflict, HTTP_Method_Not_Allowed
+import console_proxy_thread as cli
+import vimconn
+import logging
+import collections
+from db_base import db_base_Exception
+import nfvo_db
+from threading import Lock
+from time import time
+
+global global_config
+global vimconn_imported
+global logger
+global default_volume_size
+default_volume_size = '5' #size in GB
+
+
+vimconn_imported = {}   # dictionary with VIM type as key, loaded module as value
+vim_threads = {"running":{}, "deleting": {}, "names": []}      # threads running for attached-VIMs
+vim_persistent_info = {}
+logger = logging.getLogger('openmano.nfvo')
+task_lock = Lock()
+task_dict = {}
+last_task_id = 0.0
+db=None
+db_lock=Lock()
+
+class NfvoException(Exception):
+    def __init__(self, message, http_code):
+        self.http_code = http_code
+        Exception.__init__(self, message)
+
+
+def get_task_id():
+    global last_task_id
+    task_id = time()
+    if task_id <= last_task_id:
+        task_id = last_task_id + 0.000001
+    last_task_id = task_id
+    return "TASK.{:.6f}".format(task_id)
+
+
+def new_task(name, params, store=True, depends=None):
+    task_id = get_task_id()
+    task = {"status": "enqueued", "id": task_id, "name": name, "params": params}
+    if depends:
+        task["depends"] = depends
+    if store:
+        task_dict[task_id] = task
+    return task
+
+
+def is_task_id(id):
+    return True if id[:5] == "TASK." else False
+
+
+def get_non_used_vim_name(datacenter_name, datacenter_id, tenant_name, tenant_id):
+    name = datacenter_name[:16]
+    if name not in vim_threads["names"]:
+        vim_threads["names"].append(name)
+        return name
+    name = datacenter_name[:16] + "." + tenant_name[:16]
+    if name not in vim_threads["names"]:
+        vim_threads["names"].append(name)
+        return name
+    name = datacenter_id + "-" + tenant_id
+    vim_threads["names"].append(name)
+    return name
+
+
+def start_service(mydb):
+    global db, global_config
+    db = nfvo_db.nfvo_db()
+    db.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name'])
+    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','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', 'dt.config as dt_config', 'nfvo_tenant_id')
+    try:
+        vims = mydb.get_rows(FROM=from_, SELECT=select_)
+        for vim in vims:
+            extra={'datacenter_tenant_id': vim.get('datacenter_tenant_id')}
+            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:
+                    module = "vimconn_" + vim["type"]
+                    module_info = imp.find_module(module)
+                    vim_conn = imp.load_module(vim["type"], *module_info)
+                    vimconn_imported[vim["type"]] = vim_conn
+                except (IOError, ImportError) as e:
+                    if module_info and module_info[0]:
+                        file.close(module_info[0])
+                    raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
+                        vim["type"], module, type(e).__name__, str(e)), HTTP_Bad_Request)
+
+            thread_id = vim["datacenter_id"] + "." + vim['nfvo_tenant_id']
+            vim_persistent_info[thread_id] = {}
+            try:
+                #if not tenant:
+                #    return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
+                myvim = vimconn_imported[ vim["type"] ].vimconnector(
+                    uuid=vim['datacenter_id'], name=vim['datacenter_name'],
+                    tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
+                    url=vim['vim_url'], url_admin=vim['vim_url_admin'],
+                    user=vim['user'], passwd=vim['passwd'],
+                    config=extra, persistent_info=vim_persistent_info[thread_id]
+                )
+            except Exception as e:
+                raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), HTTP_Internal_Server_Error)
+            thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['vim_tenant_id'], vim['vim_tenant_name'], vim['vim_tenant_id'])
+            new_thread = vim_thread.vim_thread(myvim, task_lock, thread_name, vim['datacenter_name'],
+                                               vim.get('datacenter_tenant_id'), db=db, db_lock=db_lock)
+            new_thread.start()
+            vim_threads["running"][thread_id] = new_thread
+    except db_base_Exception as e:
+        raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
+
+
+def stop_service():
+    for thread_id,thread in vim_threads["running"].items():
+        thread.insert_task(new_task("exit", None, store=False))
+        vim_threads["deleting"][thread_id] = thread
+    vim_threads["running"] = {}
+
+
+def get_flavorlist(mydb, vnf_id, nfvo_tenant=None):
+    '''Obtain flavorList
+    return result, content:
+        <0, error_text upon error
+        nb_records, flavor_list on success
+    '''
+    WHERE_dict={}
+    WHERE_dict['vnf_id'] = vnf_id
+    if nfvo_tenant is not None:
+        WHERE_dict['nfvo_tenant_id'] = nfvo_tenant
+
+    #result, content = mydb.get_table(FROM='vms join vnfs on vms.vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
+    #result, content = mydb.get_table(FROM='vms',SELECT=('vim_flavor_id',),WHERE=WHERE_dict )
+    flavors = mydb.get_rows(FROM='vms join flavors on vms.flavor_id=flavors.uuid',SELECT=('flavor_id',),WHERE=WHERE_dict )
+    #print "get_flavor_list result:", result
+    #print "get_flavor_list content:", content
+    flavorList=[]
+    for flavor in flavors:
+        flavorList.append(flavor['flavor_id'])
+    return flavorList
+
+
+def get_imagelist(mydb, vnf_id, nfvo_tenant=None):
+    '''Obtain imageList
+    return result, content:
+        <0, error_text upon error
+        nb_records, flavor_list on success
+    '''
+    WHERE_dict={}
+    WHERE_dict['vnf_id'] = vnf_id
+    if nfvo_tenant is not None:
+        WHERE_dict['nfvo_tenant_id'] = nfvo_tenant
+
+    #result, content = mydb.get_table(FROM='vms join vnfs on vms-vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
+    images = mydb.get_rows(FROM='vms join images on vms.image_id=images.uuid',SELECT=('image_id',),WHERE=WHERE_dict )
+    imageList=[]
+    for image in images:
+        imageList.append(image['image_id'])
+    return imageList
+
+
+def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, datacenter_tenant_id=None,
+            vim_tenant=None, vim_tenant_name=None, vim_user=None, vim_passwd=None):
+    '''Obtain a dictionary of VIM (datacenter) classes with some of the input parameters
+    return dictionary with {datacenter_id: vim_class, ... }. vim_class contain:
+            'nfvo_tenant_id','datacenter_id','vim_tenant_id','vim_url','vim_url_admin','datacenter_name','type','user','passwd'
+        raise exception upon error
+    '''
+    WHERE_dict={}
+    if nfvo_tenant     is not None:  WHERE_dict['nfvo_tenant_id'] = nfvo_tenant
+    if datacenter_id   is not None:  WHERE_dict['d.uuid']  = datacenter_id
+    if datacenter_tenant_id is not None:  WHERE_dict['datacenter_tenant_id']  = datacenter_tenant_id
+    if datacenter_name is not None:  WHERE_dict['d.name']  = datacenter_name
+    if vim_tenant      is not None:  WHERE_dict['dt.vim_tenant_id']  = vim_tenant
+    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','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', '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')
+    try:
+        vims = mydb.get_rows(FROM=from_, SELECT=select_, WHERE=WHERE_dict )
+        vim_dict={}
+        for vim in vims:
+            extra={'datacenter_tenant_id': vim.get('datacenter_tenant_id')}
+            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:
+                    module = "vimconn_" + vim["type"]
+                    module_info = imp.find_module(module)
+                    vim_conn = imp.load_module(vim["type"], *module_info)
+                    vimconn_imported[vim["type"]] = vim_conn
+                except (IOError, ImportError) as e:
+                    if module_info and module_info[0]:
+                        file.close(module_info[0])
+                    raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
+                                            vim["type"], module, type(e).__name__, str(e)), HTTP_Bad_Request)
+
+            try:
+                if 'nfvo_tenant_id' in vim:
+                    thread_id = vim["datacenter_id"] + "." + vim['nfvo_tenant_id']
+                    if thread_id not in vim_persistent_info:
+                        vim_persistent_info[thread_id] = {}
+                    persistent_info = vim_persistent_info[thread_id]
+                else:
+                    persistent_info = {}
+                #if not tenant:
+                #    return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
+                vim_dict[ vim['datacenter_id'] ] = vimconn_imported[ vim["type"] ].vimconnector(
+                                uuid=vim['datacenter_id'], name=vim['datacenter_name'],
+                                tenant_id=vim.get('vim_tenant_id',vim_tenant),
+                                tenant_name=vim.get('vim_tenant_name',vim_tenant_name),
+                                url=vim['vim_url'], url_admin=vim['vim_url_admin'],
+                                user=vim.get('user',vim_user), passwd=vim.get('passwd',vim_passwd),
+                                config=extra, persistent_info=persistent_info
+                        )
+            except Exception as e:
+                raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), HTTP_Internal_Server_Error)
+        return vim_dict
+    except db_base_Exception as e:
+        raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
+
+
+def rollback(mydb,  vims, rollback_list):
+    undeleted_items=[]
+    #delete things by reverse order
+    for i in range(len(rollback_list)-1, -1, -1):
+        item = rollback_list[i]
+        if item["where"]=="vim":
+            if item["vim_id"] not in vims:
+                continue
+            vim=vims[ item["vim_id"] ]
+            try:
+                if item["what"]=="image":
+                    vim.delete_image(item["uuid"])
+                    mydb.delete_row(FROM="datacenters_images", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]})
+                elif item["what"]=="flavor":
+                    vim.delete_flavor(item["uuid"])
+                    mydb.delete_row(FROM="datacenters_flavors", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]})
+                elif item["what"]=="network":
+                    vim.delete_network(item["uuid"])
+                elif item["what"]=="vm":
+                    vim.delete_vminstance(item["uuid"])
+            except vimconn.vimconnException as e:
+                logger.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item['what'], item["uuid"], str(e))
+                undeleted_items.append("{} {} from VIM {}".format(item['what'], item["uuid"], vim["name"]))
+            except db_base_Exception as e:
+                logger.error("Error in rollback. Not possible to delete %s '%s' from DB.datacenters Message: %s", item['what'], item["uuid"], str(e))
+
+        else: # where==mano
+            try:
+                if item["what"]=="image":
+                    mydb.delete_row(FROM="images", WHERE={"uuid": item["uuid"]})
+                elif item["what"]=="flavor":
+                    mydb.delete_row(FROM="flavors", WHERE={"uuid": item["uuid"]})
+            except db_base_Exception as e:
+                logger.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item['what'], item["uuid"], str(e))
+                undeleted_items.append("{} '{}'".format(item['what'], item["uuid"]))
+    if len(undeleted_items)==0:
+        return True," Rollback successful."
+    else:
+        return False," Rollback fails to delete: " + str(undeleted_items)
+
+
+def check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1):
+    global global_config
+    #create a dictionary with vnfc-name: vnfc:interface-list  key:values pairs
+    vnfc_interfaces={}
+    for vnfc in vnf_descriptor["vnf"]["VNFC"]:
+        name_dict = {}
+        #dataplane interfaces
+        for numa in vnfc.get("numas",() ):
+            for interface in numa.get("interfaces",()):
+                if interface["name"] in name_dict:
+                    raise NfvoException(
+                        "Error at vnf:VNFC[name:'{}']:numas:interfaces:name, interface name '{}' already used in this VNFC".format(
+                            vnfc["name"], interface["name"]),
+                        HTTP_Bad_Request)
+                name_dict[ interface["name"] ] = "underlay"
+        #bridge interfaces
+        for interface in vnfc.get("bridge-ifaces",() ):
+            if interface["name"] in name_dict:
+                raise NfvoException(
+                    "Error at vnf:VNFC[name:'{}']:bridge-ifaces:name, interface name '{}' already used in this VNFC".format(
+                        vnfc["name"], interface["name"]),
+                    HTTP_Bad_Request)
+            name_dict[ interface["name"] ] = "overlay"
+        vnfc_interfaces[ vnfc["name"] ] = name_dict
+        # check bood-data info
+        if "boot-data" in vnfc:
+            # check that user-data is incompatible with users and config-files
+            if (vnfc["boot-data"].get("users") or vnfc["boot-data"].get("config-files")) and vnfc["boot-data"].get("user-data"):
+                raise NfvoException(
+                    "Error at vnf:VNFC:boot-data, fields 'users' and 'config-files' are not compatible with 'user-data'",
+                    HTTP_Bad_Request)
+
+    #check if the info in external_connections matches with the one in the vnfcs
+    name_list=[]
+    for external_connection in vnf_descriptor["vnf"].get("external-connections",() ):
+        if external_connection["name"] in name_list:
+            raise NfvoException(
+                "Error at vnf:external-connections:name, value '{}' already used as an external-connection".format(
+                    external_connection["name"]),
+                HTTP_Bad_Request)
+        name_list.append(external_connection["name"])
+        if external_connection["VNFC"] not in vnfc_interfaces:
+            raise NfvoException(
+                "Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC".format(
+                    external_connection["name"], external_connection["VNFC"]),
+                HTTP_Bad_Request)
+
+        if external_connection["local_iface_name"] not in vnfc_interfaces[ external_connection["VNFC"] ]:
+            raise NfvoException(
+                "Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC".format(
+                    external_connection["name"],
+                    external_connection["local_iface_name"]),
+                HTTP_Bad_Request )
+
+    #check if the info in internal_connections matches with the one in the vnfcs
+    name_list=[]
+    for internal_connection in vnf_descriptor["vnf"].get("internal-connections",() ):
+        if internal_connection["name"] in name_list:
+            raise NfvoException(
+                "Error at vnf:internal-connections:name, value '%s' already used as an internal-connection".format(
+                    internal_connection["name"]),
+                HTTP_Bad_Request)
+        name_list.append(internal_connection["name"])
+        #We should check that internal-connections of type "ptp" have only 2 elements
+
+        if len(internal_connection["elements"])>2 and (internal_connection.get("type") == "ptp" or internal_connection.get("type") == "e-line"):
+            raise NfvoException(
+                "Error at 'vnf:internal-connections[name:'{}']:elements', size must be 2 for a '{}' type. Consider change it to '{}' type".format(
+                    internal_connection["name"],
+                    'ptp' if vnf_descriptor_version==1 else 'e-line',
+                    'data' if vnf_descriptor_version==1 else "e-lan"),
+                HTTP_Bad_Request)
+        for port in internal_connection["elements"]:
+            vnf = port["VNFC"]
+            iface = port["local_iface_name"]
+            if vnf not in vnfc_interfaces:
+                raise NfvoException(
+                    "Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC".format(
+                        internal_connection["name"], vnf),
+                    HTTP_Bad_Request)
+            if iface not in vnfc_interfaces[ vnf ]:
+                raise NfvoException(
+                    "Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC".format(
+                        internal_connection["name"], iface),
+                    HTTP_Bad_Request)
+                return -HTTP_Bad_Request,
+            if vnf_descriptor_version==1 and "type" not in internal_connection:
+                if vnfc_interfaces[vnf][iface] == "overlay":
+                    internal_connection["type"] = "bridge"
+                else:
+                    internal_connection["type"] = "data"
+            if vnf_descriptor_version==2 and "implementation" not in internal_connection:
+                if vnfc_interfaces[vnf][iface] == "overlay":
+                    internal_connection["implementation"] = "overlay"
+                else:
+                    internal_connection["implementation"] = "underlay"
+            if (internal_connection.get("type") == "data" or internal_connection.get("type") == "ptp" or \
+                internal_connection.get("implementation") == "underlay") and vnfc_interfaces[vnf][iface] == "overlay":
+                raise NfvoException(
+                    "Error at vnf:internal-connections[name:'{}']:elements[]:{}, interface of type {} connected to an {} network".format(
+                        internal_connection["name"],
+                        iface, 'bridge' if vnf_descriptor_version==1 else 'overlay',
+                        'data' if vnf_descriptor_version==1 else 'underlay'),
+                    HTTP_Bad_Request)
+            if (internal_connection.get("type") == "bridge" or internal_connection.get("implementation") == "overlay") and \
+                vnfc_interfaces[vnf][iface] == "underlay":
+                raise NfvoException(
+                    "Error at vnf:internal-connections[name:'{}']:elements[]:{}, interface of type {} connected to an {} network".format(
+                        internal_connection["name"], iface,
+                        'data' if vnf_descriptor_version==1 else 'underlay',
+                        'bridge' if vnf_descriptor_version==1 else 'overlay'),
+                    HTTP_Bad_Request)
+
+
+def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=False, return_on_error = None):
+    #look if image exist
+    if only_create_at_vim:
+        image_mano_id = image_dict['uuid']
+        if return_on_error == None:
+            return_on_error = True
+    else:
+        if image_dict['location']:
+            images = mydb.get_rows(FROM="images", WHERE={'location':image_dict['location'], 'metadata':image_dict['metadata']})
+        else:
+            images = mydb.get_rows(FROM="images", WHERE={'universal_name':image_dict['universal_name'], 'checksum':image_dict['checksum']})
+        if len(images)>=1:
+            image_mano_id = images[0]['uuid']
+        else:
+            #create image in MANO DB
+            temp_image_dict={'name':image_dict['name'],         'description':image_dict.get('description',None),
+                            'location':image_dict['location'],  'metadata':image_dict.get('metadata',None),
+                            'universal_name':image_dict['universal_name'] , 'checksum':image_dict['checksum']
+                            }
+            #temp_image_dict['location'] = image_dict.get('new_location') if image_dict['location'] is None
+            image_mano_id = mydb.new_row('images', temp_image_dict, add_uuid=True)
+            rollback_list.append({"where":"mano", "what":"image","uuid":image_mano_id})
+    #create image at every vim
+    for vim_id,vim in vims.iteritems():
+        image_created="false"
+        #look at database
+        image_db = mydb.get_rows(FROM="datacenters_images", WHERE={'datacenter_id':vim_id, 'image_id':image_mano_id})
+        #look at VIM if this image exist
+        try:
+            if image_dict['location'] is not None:
+                image_vim_id = vim.get_image_id_from_path(image_dict['location'])
+            else:
+                filter_dict = {}
+                filter_dict['name'] = image_dict['universal_name']
+                if image_dict.get('checksum') != None:
+                    filter_dict['checksum'] = image_dict['checksum']
+                #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
+                vim_images = vim.get_image_list(filter_dict)
+                #logger.debug('>>>>>>>> VIM images: %s', str(vim_images))
+                if len(vim_images) > 1:
+                    raise vimconn.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict)), HTTP_Conflict)
+                elif len(vim_images) == 0:
+                    raise vimconn.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict)))
+                else:
+                    #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0]))
+                    image_vim_id = vim_images[0]['id']
+
+        except vimconn.vimconnNotFoundException as e:
+            #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None
+            try:
+                #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None
+                if image_dict['location']:
+                    image_vim_id = vim.new_image(image_dict)
+                    rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"image","uuid":image_vim_id})
+                    image_created="true"
+                else:
+                    #If we reach this point, then the image has image name, and optionally checksum, and could not be found
+                    raise vimconn.vimconnException(str(e))
+            except vimconn.vimconnException as e:
+                if return_on_error:
+                    logger.error("Error creating image at VIM '%s': %s", vim["name"], str(e))
+                    raise
+                image_vim_id = None
+                logger.warn("Error creating image at VIM '%s': %s", vim["name"], str(e))
+                continue
+        except vimconn.vimconnException as e:
+            if return_on_error:
+                logger.error("Error contacting VIM to know if the image exists at VIM: %s", str(e))
+                raise
+            logger.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e))
+            image_vim_id = None
+            continue
+        #if we reach here, the image has been created or existed
+        if len(image_db)==0:
+            #add new vim_id at datacenters_images
+            mydb.new_row('datacenters_images', {'datacenter_id':vim_id, 'image_id':image_mano_id, 'vim_id': image_vim_id, 'created':image_created})
+        elif image_db[0]["vim_id"]!=image_vim_id:
+            #modify existing vim_id at datacenters_images
+            mydb.update_rows('datacenters_images', UPDATE={'vim_id':image_vim_id}, WHERE={'datacenter_id':vim_id, 'image_id':image_mano_id})
+
+    return image_vim_id if only_create_at_vim else image_mano_id
+
+
+def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_vim=False, return_on_error = None):
+    temp_flavor_dict= {'disk':flavor_dict.get('disk',1),
+            'ram':flavor_dict.get('ram'),
+            'vcpus':flavor_dict.get('vcpus'),
+        }
+    if 'extended' in flavor_dict and flavor_dict['extended']==None:
+        del flavor_dict['extended']
+    if 'extended' in flavor_dict:
+        temp_flavor_dict['extended']=yaml.safe_dump(flavor_dict['extended'],default_flow_style=True,width=256)
+
+    #look if flavor exist
+    if only_create_at_vim:
+        flavor_mano_id = flavor_dict['uuid']
+        if return_on_error == None:
+            return_on_error = True
+    else:
+        flavors = mydb.get_rows(FROM="flavors", WHERE=temp_flavor_dict)
+        if len(flavors)>=1:
+            flavor_mano_id = flavors[0]['uuid']
+        else:
+            #create flavor
+            #create one by one the images of aditional disks
+            dev_image_list=[] #list of images
+            if 'extended' in flavor_dict and flavor_dict['extended']!=None:
+                dev_nb=0
+                for device in flavor_dict['extended'].get('devices',[]):
+                    if "image" not in device and "image name" not in device:
+                        continue
+                    image_dict={}
+                    image_dict['name']=device.get('image name',flavor_dict['name']+str(dev_nb)+"-img")
+                    image_dict['universal_name']=device.get('image name')
+                    image_dict['description']=flavor_dict['name']+str(dev_nb)+"-img"
+                    image_dict['location']=device.get('image')
+                    #image_dict['new_location']=vnfc.get('image location')
+                    image_dict['checksum']=device.get('image checksum')
+                    image_metadata_dict = device.get('image metadata', None)
+                    image_metadata_str = None
+                    if image_metadata_dict != None:
+                        image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
+                    image_dict['metadata']=image_metadata_str
+                    image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
+                    #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
+                    dev_image_list.append(image_id)
+                    dev_nb += 1
+            temp_flavor_dict['name'] = flavor_dict['name']
+            temp_flavor_dict['description'] = flavor_dict.get('description',None)
+            content = mydb.new_row('flavors', temp_flavor_dict, add_uuid=True)
+            flavor_mano_id= content
+            rollback_list.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id})
+    #create flavor at every vim
+    if 'uuid' in flavor_dict:
+        del flavor_dict['uuid']
+    flavor_vim_id=None
+    for vim_id,vim in vims.items():
+        flavor_created="false"
+        #look at database
+        flavor_db = mydb.get_rows(FROM="datacenters_flavors", WHERE={'datacenter_id':vim_id, 'flavor_id':flavor_mano_id})
+        #look at VIM if this flavor exist  SKIPPED
+        #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
+        #if res_vim < 0:
+        #    print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
+        #    continue
+        #elif res_vim==0:
+
+        #Create the flavor in VIM
+        #Translate images at devices from MANO id to VIM id
+        disk_list = []
+        if 'extended' in flavor_dict and flavor_dict['extended']!=None and "devices" in flavor_dict['extended']:
+            #make a copy of original devices
+            devices_original=[]
+
+            for device in flavor_dict["extended"].get("devices",[]):
+                dev={}
+                dev.update(device)
+                devices_original.append(dev)
+                if 'image' in device:
+                    del device['image']
+                if 'image metadata' in device:
+                    del device['image metadata']
+            dev_nb=0
+            for index in range(0,len(devices_original)) :
+                device=devices_original[index]
+                if "image" not in device and "image name" not in device:
+                    if 'size' in device:
+                        disk_list.append({'size': device.get('size', default_volume_size)})
+                    continue
+                image_dict={}
+                image_dict['name']=device.get('image name',flavor_dict['name']+str(dev_nb)+"-img")
+                image_dict['universal_name']=device.get('image name')
+                image_dict['description']=flavor_dict['name']+str(dev_nb)+"-img"
+                image_dict['location']=device.get('image')
+                #image_dict['new_location']=device.get('image location')
+                image_dict['checksum']=device.get('image checksum')
+                image_metadata_dict = device.get('image metadata', None)
+                image_metadata_str = None
+                if image_metadata_dict != None:
+                    image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
+                image_dict['metadata']=image_metadata_str
+                image_mano_id=create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=False, return_on_error=return_on_error )
+                image_dict["uuid"]=image_mano_id
+                image_vim_id=create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=True, return_on_error=return_on_error)
+
+                #save disk information (image must be based on and size
+                disk_list.append({'image_id': image_vim_id, 'size': device.get('size', default_volume_size)})
+
+                flavor_dict["extended"]["devices"][index]['imageRef']=image_vim_id
+                dev_nb += 1
+        if len(flavor_db)>0:
+            #check that this vim_id exist in VIM, if not create
+            flavor_vim_id=flavor_db[0]["vim_id"]
+            try:
+                vim.get_flavor(flavor_vim_id)
+                continue #flavor exist
+            except vimconn.vimconnException:
+                pass
+        #create flavor at vim
+        logger.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim["name"])
+        try:
+            flavor_vim_id = None
+            flavor_vim_id=vim.get_flavor_id_from_data(flavor_dict)
+            flavor_create="false"
+        except vimconn.vimconnException as e:
+            pass
+        try:
+            if not flavor_vim_id:
+                flavor_vim_id = vim.new_flavor(flavor_dict)
+                rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"flavor","uuid":flavor_vim_id})
+                flavor_created="true"
+        except vimconn.vimconnException as e:
+            if return_on_error:
+                logger.error("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
+                raise
+            logger.warn("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
+            flavor_vim_id = None
+            continue
+        #if reach here the flavor has been create or exist
+        if len(flavor_db)==0:
+            #add new vim_id at datacenters_flavors
+            extended_devices_yaml = None
+            if len(disk_list) > 0:
+                extended_devices = dict()
+                extended_devices['disks'] = disk_list
+                extended_devices_yaml = yaml.safe_dump(extended_devices,default_flow_style=True,width=256)
+            mydb.new_row('datacenters_flavors',
+                        {'datacenter_id':vim_id, 'flavor_id':flavor_mano_id, 'vim_id': flavor_vim_id,
+                        'created':flavor_created,'extended': extended_devices_yaml})
+        elif flavor_db[0]["vim_id"]!=flavor_vim_id:
+            #modify existing vim_id at datacenters_flavors
+            mydb.update_rows('datacenters_flavors', UPDATE={'vim_id':flavor_vim_id}, WHERE={'datacenter_id':vim_id, 'flavor_id':flavor_mano_id})
+
+    return flavor_vim_id if only_create_at_vim else flavor_mano_id
+
+
+def new_vnf(mydb, tenant_id, vnf_descriptor):
+    global global_config
+
+    # Step 1. Check the VNF descriptor
+    check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1)
+    # Step 2. Check tenant exist
+    vims = {}
+    if tenant_id != "any":
+        check_tenant(mydb, tenant_id)
+        if "tenant_id" in vnf_descriptor["vnf"]:
+            if vnf_descriptor["vnf"]["tenant_id"] != tenant_id:
+                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor["vnf"]["tenant_id"], tenant_id),
+                                    HTTP_Unauthorized)
+        else:
+            vnf_descriptor['vnf']['tenant_id'] = tenant_id
+        # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
+        if global_config["auto_push_VNF_to_VIMs"]:
+            vims = get_vim(mydb, tenant_id)
+
+    # Step 4. Review the descriptor and add missing  fields
+    #print vnf_descriptor
+    #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
+    vnf_name = vnf_descriptor['vnf']['name']
+    vnf_descriptor['vnf']['description'] = vnf_descriptor['vnf'].get("description", vnf_name)
+    if "physical" in vnf_descriptor['vnf']:
+        del vnf_descriptor['vnf']['physical']
+    #print vnf_descriptor
+
+    # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
+    logger.debug('BEGIN creation of VNF "%s"' % vnf_name)
+    logger.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name,len(vnf_descriptor['vnf']['VNFC'])))
+
+    #For each VNFC, we add it to the VNFCDict and we  create a flavor.
+    VNFCDict = {}     # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
+    rollback_list = []    # It will contain the new images created in mano. It is used for rollback
+    try:
+        logger.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
+        for vnfc in vnf_descriptor['vnf']['VNFC']:
+            VNFCitem={}
+            VNFCitem["name"] = vnfc['name']
+            VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name))
+
+            #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
+
+            myflavorDict = {}
+            myflavorDict["name"] = vnfc['name']+"-flv"   #Maybe we could rename the flavor by using the field "image name" if exists
+            myflavorDict["description"] = VNFCitem["description"]
+            myflavorDict["ram"] = vnfc.get("ram", 0)
+            myflavorDict["vcpus"] = vnfc.get("vcpus", 0)
+            myflavorDict["disk"] = vnfc.get("disk", 1)
+            myflavorDict["extended"] = {}
+
+            devices = vnfc.get("devices")
+            if devices != None:
+                myflavorDict["extended"]["devices"] = devices
+
+            # TODO:
+            # Mapping from processor models to rankings should be available somehow in the NFVO. They could be taken from VIM or directly from a new database table
+            # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
+
+            # Previous code has been commented
+            #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
+            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 200
+            #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
+            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 300
+            #else:
+            #    result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
+            #    if result2:
+            #        print "Error creating flavor: unknown processor model. Rollback successful."
+            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
+            #    else:
+            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
+            myflavorDict['extended']['processor_ranking'] = 100  #Hardcoded value, while we decide when the mapping is done
+
+            if 'numas' in vnfc and len(vnfc['numas'])>0:
+                myflavorDict['extended']['numas'] = vnfc['numas']
+
+            #print myflavorDict
+
+            # Step 6.2 New flavors are created in the VIM
+            flavor_id = create_or_use_flavor(mydb, vims, myflavorDict, rollback_list)
+
+            #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
+            VNFCitem["flavor_id"] = flavor_id
+            VNFCDict[vnfc['name']] = VNFCitem
+
+        logger.debug("Creating new images in the VIM for each VNFC")
+        # Step 6.3 New images are created in the VIM
+        #For each VNFC, we must create the appropriate image.
+        #This "for" loop might be integrated with the previous one
+        #In case this integration is made, the VNFCDict might become a VNFClist.
+        for vnfc in vnf_descriptor['vnf']['VNFC']:
+            #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
+            image_dict={}
+            image_dict['name']=vnfc.get('image name',vnf_name+"-"+vnfc['name']+"-img")
+            image_dict['universal_name']=vnfc.get('image name')
+            image_dict['description']=vnfc.get('image name', VNFCDict[vnfc['name']]['description'])
+            image_dict['location']=vnfc.get('VNFC image')
+            #image_dict['new_location']=vnfc.get('image location')
+            image_dict['checksum']=vnfc.get('image checksum')
+            image_metadata_dict = vnfc.get('image metadata', None)
+            image_metadata_str = None
+            if image_metadata_dict is not None:
+                image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
+            image_dict['metadata']=image_metadata_str
+            #print "create_or_use_image", mydb, vims, image_dict, rollback_list
+            image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
+            #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
+            VNFCDict[vnfc['name']]["image_id"] = image_id
+            VNFCDict[vnfc['name']]["image_path"] = vnfc.get('VNFC image')
+            if vnfc.get("boot-data"):
+                VNFCDict[vnfc['name']]["boot_data"] = yaml.safe_dump(vnfc["boot-data"], default_flow_style=True, width=256)
+
+
+        # Step 7. Storing the VNF descriptor in the repository
+        if "descriptor" not in vnf_descriptor["vnf"]:
+            vnf_descriptor["vnf"]["descriptor"] = yaml.safe_dump(vnf_descriptor, indent=4, explicit_start=True, default_flow_style=False)
+
+        # Step 8. Adding the VNF to the NFVO DB
+        vnf_id = mydb.new_vnf_as_a_whole(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
+        return vnf_id
+    except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
+        _, message = rollback(mydb, vims, rollback_list)
+        if isinstance(e, db_base_Exception):
+            error_text = "Exception at database"
+        elif isinstance(e, KeyError):
+            error_text = "KeyError exception "
+            e.http_code = HTTP_Internal_Server_Error
+        else:
+            error_text = "Exception at VIM"
+        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
+        #logger.error("start_scenario %s", error_text)
+        raise NfvoException(error_text, e.http_code)
+
+
+def new_vnf_v02(mydb, tenant_id, vnf_descriptor):
+    global global_config
+
+    # Step 1. Check the VNF descriptor
+    check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=2)
+    # Step 2. Check tenant exist
+    vims = {}
+    if tenant_id != "any":
+        check_tenant(mydb, tenant_id)
+        if "tenant_id" in vnf_descriptor["vnf"]:
+            if vnf_descriptor["vnf"]["tenant_id"] != tenant_id:
+                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor["vnf"]["tenant_id"], tenant_id),
+                                    HTTP_Unauthorized)
+        else:
+            vnf_descriptor['vnf']['tenant_id'] = tenant_id
+        # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
+        if global_config["auto_push_VNF_to_VIMs"]:
+            vims = get_vim(mydb, tenant_id)
+
+    # Step 4. Review the descriptor and add missing  fields
+    #print vnf_descriptor
+    #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
+    vnf_name = vnf_descriptor['vnf']['name']
+    vnf_descriptor['vnf']['description'] = vnf_descriptor['vnf'].get("description", vnf_name)
+    if "physical" in vnf_descriptor['vnf']:
+        del vnf_descriptor['vnf']['physical']
+    #print vnf_descriptor
+
+    # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
+    logger.debug('BEGIN creation of VNF "%s"' % vnf_name)
+    logger.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name,len(vnf_descriptor['vnf']['VNFC'])))
+
+    #For each VNFC, we add it to the VNFCDict and we  create a flavor.
+    VNFCDict = {}     # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
+    rollback_list = []    # It will contain the new images created in mano. It is used for rollback
+    try:
+        logger.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
+        for vnfc in vnf_descriptor['vnf']['VNFC']:
+            VNFCitem={}
+            VNFCitem["name"] = vnfc['name']
+            VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name))
+
+            #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
+
+            myflavorDict = {}
+            myflavorDict["name"] = vnfc['name']+"-flv"   #Maybe we could rename the flavor by using the field "image name" if exists
+            myflavorDict["description"] = VNFCitem["description"]
+            myflavorDict["ram"] = vnfc.get("ram", 0)
+            myflavorDict["vcpus"] = vnfc.get("vcpus", 0)
+            myflavorDict["disk"] = vnfc.get("disk", 1)
+            myflavorDict["extended"] = {}
+
+            devices = vnfc.get("devices")
+            if devices != None:
+                myflavorDict["extended"]["devices"] = devices
+
+            # TODO:
+            # Mapping from processor models to rankings should be available somehow in the NFVO. They could be taken from VIM or directly from a new database table
+            # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
+
+            # Previous code has been commented
+            #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
+            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 200
+            #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
+            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 300
+            #else:
+            #    result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
+            #    if result2:
+            #        print "Error creating flavor: unknown processor model. Rollback successful."
+            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
+            #    else:
+            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
+            myflavorDict['extended']['processor_ranking'] = 100  #Hardcoded value, while we decide when the mapping is done
+
+            if 'numas' in vnfc and len(vnfc['numas'])>0:
+                myflavorDict['extended']['numas'] = vnfc['numas']
+
+            #print myflavorDict
+
+            # Step 6.2 New flavors are created in the VIM
+            flavor_id = create_or_use_flavor(mydb, vims, myflavorDict, rollback_list)
+
+            #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
+            VNFCitem["flavor_id"] = flavor_id
+            VNFCDict[vnfc['name']] = VNFCitem
+
+        logger.debug("Creating new images in the VIM for each VNFC")
+        # Step 6.3 New images are created in the VIM
+        #For each VNFC, we must create the appropriate image.
+        #This "for" loop might be integrated with the previous one
+        #In case this integration is made, the VNFCDict might become a VNFClist.
+        for vnfc in vnf_descriptor['vnf']['VNFC']:
+            #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
+            image_dict={}
+            image_dict['name']=vnfc.get('image name',vnf_name+"-"+vnfc['name']+"-img")
+            image_dict['universal_name']=vnfc.get('image name')
+            image_dict['description']=vnfc.get('image name', VNFCDict[vnfc['name']]['description'])
+            image_dict['location']=vnfc.get('VNFC image')
+            #image_dict['new_location']=vnfc.get('image location')
+            image_dict['checksum']=vnfc.get('image checksum')
+            image_metadata_dict = vnfc.get('image metadata', None)
+            image_metadata_str = None
+            if image_metadata_dict is not None:
+                image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
+            image_dict['metadata']=image_metadata_str
+            #print "create_or_use_image", mydb, vims, image_dict, rollback_list
+            image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
+            #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
+            VNFCDict[vnfc['name']]["image_id"] = image_id
+            VNFCDict[vnfc['name']]["image_path"] = vnfc.get('VNFC image')
+            if vnfc.get("boot-data"):
+                VNFCDict[vnfc['name']]["boot_data"] = yaml.safe_dump(vnfc["boot-data"], default_flow_style=True, width=256)
+
+        # Step 7. Storing the VNF descriptor in the repository
+        if "descriptor" not in vnf_descriptor["vnf"]:
+            vnf_descriptor["vnf"]["descriptor"] = yaml.safe_dump(vnf_descriptor, indent=4, explicit_start=True, default_flow_style=False)
+
+        # Step 8. Adding the VNF to the NFVO DB
+        vnf_id = mydb.new_vnf_as_a_whole2(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
+        return vnf_id
+    except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
+        _, message = rollback(mydb, vims, rollback_list)
+        if isinstance(e, db_base_Exception):
+            error_text = "Exception at database"
+        elif isinstance(e, KeyError):
+            error_text = "KeyError exception "
+            e.http_code = HTTP_Internal_Server_Error
+        else:
+            error_text = "Exception at VIM"
+        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
+        #logger.error("start_scenario %s", error_text)
+        raise NfvoException(error_text, e.http_code)
+
+
+def get_vnf_id(mydb, tenant_id, vnf_id):
+    #check valid tenant_id
+    check_tenant(mydb, tenant_id)
+    #obtain data
+    where_or = {}
+    if tenant_id != "any":
+        where_or["tenant_id"] = tenant_id
+        where_or["public"] = True
+    vnf = mydb.get_table_by_uuid_name('vnfs', vnf_id, "VNF", WHERE_OR=where_or, WHERE_AND_OR="AND")
+
+    vnf_id=vnf["uuid"]
+    filter_keys = ('uuid','name','description','public', "tenant_id", "created_at")
+    filtered_content = dict( (k,v) for k,v in vnf.iteritems() if k in filter_keys )
+    #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
+    data={'vnf' : filtered_content}
+    #GET VM
+    content = mydb.get_rows(FROM='vnfs join vms on vnfs.uuid=vms.vnf_id',
+            SELECT=('vms.uuid as uuid','vms.name as name', 'vms.description as description', 'boot_data'),
+            WHERE={'vnfs.uuid': vnf_id} )
+    if len(content)==0:
+        raise NfvoException("vnf '{}' not found".format(vnf_id), HTTP_Not_Found)
+    # change boot_data into boot-data
+    for vm in content:
+        if vm.get("boot_data"):
+            vm["boot-data"] = yaml.safe_load(vm["boot_data"])
+            del vm["boot_data"]
+
+    data['vnf']['VNFC'] = content
+    #TODO: GET all the information from a VNFC and include it in the output.
+
+    #GET NET
+    content = mydb.get_rows(FROM='vnfs join nets on vnfs.uuid=nets.vnf_id',
+                                    SELECT=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
+                                    WHERE={'vnfs.uuid': vnf_id} )
+    data['vnf']['nets'] = content
+
+    #GET ip-profile for each net
+    for net in data['vnf']['nets']:
+        ipprofiles = mydb.get_rows(FROM='ip_profiles',
+                                   SELECT=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
+                                   WHERE={'net_id': net["uuid"]} )
+        if len(ipprofiles)==1:
+            net["ip_profile"] = ipprofiles[0]
+        elif len(ipprofiles)>1:
+            raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net['uuid']), HTTP_Bad_Request)
+
+
+    #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
+
+    #GET External Interfaces
+    content = mydb.get_rows(FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
+                                    SELECT=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
+                                            'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
+                                    WHERE={'vnfs.uuid': vnf_id},
+                                    WHERE_NOT={'interfaces.external_name': None} )
+    #print content
+    data['vnf']['external-connections'] = content
+
+    return data
+
+
+def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None):
+    # Check tenant exist
+    if tenant_id != "any":
+        check_tenant(mydb, tenant_id)
+        # Get the URL of the VIM from the nfvo_tenant and the datacenter
+        vims = get_vim(mydb, tenant_id)
+    else:
+        vims={}
+
+    # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
+    where_or = {}
+    if tenant_id != "any":
+        where_or["tenant_id"] = tenant_id
+        where_or["public"] = True
+    vnf = mydb.get_table_by_uuid_name('vnfs', vnf_id, "VNF", WHERE_OR=where_or, WHERE_AND_OR="AND")
+    vnf_id = vnf["uuid"]
+
+    # "Getting the list of flavors and tenants of the VNF"
+    flavorList = get_flavorlist(mydb, vnf_id)
+    if len(flavorList)==0:
+        logger.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id)
+
+    imageList = get_imagelist(mydb, vnf_id)
+    if len(imageList)==0:
+        logger.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id)
+
+    deleted = mydb.delete_row_by_id('vnfs', vnf_id)
+    if deleted == 0:
+        raise NfvoException("vnf '{}' not found".format(vnf_id), HTTP_Not_Found)
+
+    undeletedItems = []
+    for flavor in flavorList:
+        #check if flavor is used by other vnf
+        try:
+            c = mydb.get_rows(FROM='vms', WHERE={'flavor_id':flavor} )
+            if len(c) > 0:
+                logger.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor)
+                continue
+            #flavor not used, must be deleted
+            #delelte at VIM
+            c = mydb.get_rows(FROM='datacenters_flavors', WHERE={'flavor_id':flavor})
+            for flavor_vim in c:
+                if flavor_vim["datacenter_id"] not in vims:
+                    continue
+                if flavor_vim['created']=='false': #skip this flavor because not created by openmano
+                    continue
+                myvim=vims[ flavor_vim["datacenter_id"] ]
+                try:
+                    myvim.delete_flavor(flavor_vim["vim_id"])
+                except vimconn.vimconnNotFoundException as e:
+                    logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"], flavor_vim["datacenter_id"] )
+                except vimconn.vimconnException as e:
+                    logger.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
+                            flavor_vim["vim_id"], flavor_vim["datacenter_id"], type(e).__name__, str(e))
+                    undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"], flavor_vim["datacenter_id"] ))
+            #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
+            mydb.delete_row_by_id('flavors', flavor)
+        except db_base_Exception as e:
+            logger.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor, str(e))
+            undeletedItems.append("flavor %s" % flavor)
+
+
+    for image in imageList:
+        try:
+            #check if image is used by other vnf
+            c = mydb.get_rows(FROM='vms', WHERE={'image_id':image} )
+            if len(c) > 0:
+                logger.debug("Image '%s' not deleted because it is being used by another VNF", image)
+                continue
+            #image not used, must be deleted
+            #delelte at VIM
+            c = mydb.get_rows(FROM='datacenters_images', WHERE={'image_id':image})
+            for image_vim in c:
+                if image_vim["datacenter_id"] not in vims:
+                    continue
+                if image_vim['created']=='false': #skip this image because not created by openmano
+                    continue
+                myvim=vims[ image_vim["datacenter_id"] ]
+                try:
+                    myvim.delete_image(image_vim["vim_id"])
+                except vimconn.vimconnNotFoundException as e:
+                    logger.warn("VIM image %s not exist at datacenter %s", image_vim["vim_id"], image_vim["datacenter_id"] )
+                except vimconn.vimconnException as e:
+                    logger.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
+                            image_vim["vim_id"], image_vim["datacenter_id"], type(e).__name__, str(e))
+                    undeletedItems.append("image {} from VIM {}".format(image_vim["vim_id"], image_vim["datacenter_id"] ))
+            #delete image from Database, using table images and with cascade foreign key also at datacenters_images
+            mydb.delete_row_by_id('images', image)
+        except db_base_Exception as e:
+            logger.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image, str(e))
+            undeletedItems.append("image %s" % image)
+
+    return vnf_id + " " + vnf["name"]
+    #if undeletedItems:
+    #    return "delete_vnf. Undeleted: %s" %(undeletedItems)
+
+
+def get_hosts_info(mydb, nfvo_tenant_id, datacenter_name=None):
+    result, vims = get_vim(mydb, nfvo_tenant_id, None, datacenter_name)
+    if result < 0:
+        return result, vims
+    elif result == 0:
+        return -HTTP_Not_Found, "datacenter '%s' not found" % datacenter_name
+    myvim = vims.values()[0]
+    result,servers =  myvim.get_hosts_info()
+    if result < 0:
+        return result, servers
+    topology = {'name':myvim['name'] , 'servers': servers}
+    return result, topology
+
+
+def get_hosts(mydb, nfvo_tenant_id):
+    vims = get_vim(mydb, nfvo_tenant_id)
+    if len(vims) == 0:
+        raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id)), HTTP_Not_Found)
+    elif len(vims)>1:
+        #print "nfvo.datacenter_action() error. Several datacenters found"
+        raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
+    myvim = vims.values()[0]
+    try:
+        hosts =  myvim.get_hosts()
+        logger.debug('VIM hosts response: '+ yaml.safe_dump(hosts, indent=4, default_flow_style=False))
+
+        datacenter = {'Datacenters': [ {'name':myvim['name'],'servers':[]} ] }
+        for host in hosts:
+            server={'name':host['name'], 'vms':[]}
+            for vm in host['instances']:
+                #get internal name and model
+                try:
+                    c = mydb.get_rows(SELECT=('name',), FROM='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
+                        WHERE={'vim_vm_id':vm['id']} )
+                    if len(c) == 0:
+                        logger.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm['id']))
+                        continue
+                    server['vms'].append( {'name':vm['name'] , 'model':c[0]['name']} )
+
+                except db_base_Exception as e:
+                    logger.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm['id'], str(e)))
+            datacenter['Datacenters'][0]['servers'].append(server)
+        #return -400, "en construccion"
+
+        #print 'datacenters '+ json.dumps(datacenter, indent=4)
+        return datacenter
+    except vimconn.vimconnException as e:
+        raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e)), e.http_code)
+
+
+def new_scenario(mydb, tenant_id, topo):
+
+#    result, vims = get_vim(mydb, tenant_id)
+#    if result < 0:
+#        return result, vims
+#1: parse input
+    if tenant_id != "any":
+        check_tenant(mydb, tenant_id)
+        if "tenant_id" in topo:
+            if topo["tenant_id"] != tenant_id:
+                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo["tenant_id"], tenant_id),
+                                    HTTP_Unauthorized)
+    else:
+        tenant_id=None
+
+#1.1: get VNFs and external_networks (other_nets).
+    vnfs={}
+    other_nets={}  #external_networks, bridge_networks and data_networkds
+    nodes = topo['topology']['nodes']
+    for k in nodes.keys():
+        if nodes[k]['type'] == 'VNF':
+            vnfs[k] = nodes[k]
+            vnfs[k]['ifaces'] = {}
+        elif nodes[k]['type'] == 'other_network' or nodes[k]['type'] == 'external_network':
+            other_nets[k] = nodes[k]
+            other_nets[k]['external']=True
+        elif nodes[k]['type'] == 'network':
+            other_nets[k] = nodes[k]
+            other_nets[k]['external']=False
+
+
+#1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
+    for name,vnf in vnfs.items():
+        where={}
+        where_or={"tenant_id": tenant_id, 'public': "true"}
+        error_text = ""
+        error_pos = "'topology':'nodes':'" + name + "'"
+        if 'vnf_id' in vnf:
+            error_text += " 'vnf_id' " +  vnf['vnf_id']
+            where['uuid'] = vnf['vnf_id']
+        if 'VNF model' in vnf:
+            error_text += " 'VNF model' " +  vnf['VNF model']
+            where['name'] = vnf['VNF model']
+        if len(where) == 0:
+            raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos, HTTP_Bad_Request)
+
+        vnf_db = mydb.get_rows(SELECT=('uuid','name','description'),
+                               FROM='vnfs',
+                               WHERE=where,
+                               WHERE_OR=where_or,
+                               WHERE_AND_OR="AND")
+        if len(vnf_db)==0:
+            raise NfvoException("unknown" + error_text + " at " + error_pos, HTTP_Not_Found)
+        elif len(vnf_db)>1:
+            raise NfvoException("more than one" + error_text + " at " + error_pos + " Concrete with 'vnf_id'", HTTP_Conflict)
+        vnf['uuid']=vnf_db[0]['uuid']
+        vnf['description']=vnf_db[0]['description']
+        #get external interfaces
+        ext_ifaces = mydb.get_rows(SELECT=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
+            FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
+            WHERE={'vnfs.uuid':vnf['uuid']}, WHERE_NOT={'external_name':None} )
+        for ext_iface in ext_ifaces:
+            vnf['ifaces'][ ext_iface['name'] ] = {'uuid':ext_iface['iface_uuid'], 'type':ext_iface['type']}
+
+#1.4 get list of connections
+    conections = topo['topology']['connections']
+    conections_list = []
+    conections_list_name = []
+    for k in conections.keys():
+        if type(conections[k]['nodes'])==dict: #dict with node:iface pairs
+            ifaces_list = conections[k]['nodes'].items()
+        elif type(conections[k]['nodes'])==list: #list with dictionary
+            ifaces_list=[]
+            conection_pair_list = map(lambda x: x.items(), conections[k]['nodes'] )
+            for k2 in conection_pair_list:
+                ifaces_list += k2
+
+        con_type = conections[k].get("type", "link")
+        if con_type != "link":
+            if k in other_nets:
+                raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k)), HTTP_Bad_Request)
+            other_nets[k] = {'external': False}
+            if conections[k].get("graph"):
+                other_nets[k]["graph"] =   conections[k]["graph"]
+            ifaces_list.append( (k, None) )
+
+
+        if con_type == "external_network":
+            other_nets[k]['external'] = True
+            if conections[k].get("model"):
+                other_nets[k]["model"] =   conections[k]["model"]
+            else:
+                other_nets[k]["model"] =   k
+        if con_type == "dataplane_net" or con_type == "bridge_net":
+            other_nets[k]["model"] = con_type
+
+        conections_list_name.append(k)
+        conections_list.append(set(ifaces_list)) #from list to set to operate as a set (this conversion removes elements that are repeated in a list)
+        #print set(ifaces_list)
+    #check valid VNF and iface names
+        for iface in ifaces_list:
+            if iface[0] not in vnfs and iface[0] not in other_nets :
+                raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
+                                                                                        str(k), iface[0]), HTTP_Not_Found)
+            if iface[0] in vnfs and iface[1] not in vnfs[ iface[0] ]['ifaces']:
+                raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
+                                                                                        str(k), iface[0], iface[1]), HTTP_Not_Found)
+
+#1.5 unify connections from the pair list to a consolidated list
+    index=0
+    while index < len(conections_list):
+        index2 = index+1
+        while index2 < len(conections_list):
+            if len(conections_list[index] & conections_list[index2])>0: #common interface, join nets
+                conections_list[index] |= conections_list[index2]
+                del conections_list[index2]
+                del conections_list_name[index2]
+            else:
+                index2 += 1
+        conections_list[index] = list(conections_list[index])  # from set to list again
+        index += 1
+    #for k in conections_list:
+    #    print k
+
+
+
+#1.6 Delete non external nets
+#    for k in other_nets.keys():
+#        if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
+#            for con in conections_list:
+#                delete_indexes=[]
+#                for index in range(0,len(con)):
+#                    if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
+#                for index in delete_indexes:
+#                    del con[index]
+#            del other_nets[k]
+#1.7: Check external_ports are present at database table datacenter_nets
+    for k,net in other_nets.items():
+        error_pos = "'topology':'nodes':'" + k + "'"
+        if net['external']==False:
+            if 'name' not in net:
+                net['name']=k
+            if 'model' not in net:
+                raise NfvoException("needed a 'model' at " + error_pos, HTTP_Bad_Request)
+            if net['model']=='bridge_net':
+                net['type']='bridge';
+            elif net['model']=='dataplane_net':
+                net['type']='data';
+            else:
+                raise NfvoException("unknown 'model' '"+ net['model'] +"' at " + error_pos, HTTP_Not_Found)
+        else: #external
+#IF we do not want to check that external network exist at datacenter
+            pass
+#ELSE
+#             error_text = ""
+#             WHERE_={}
+#             if 'net_id' in net:
+#                 error_text += " 'net_id' " +  net['net_id']
+#                 WHERE_['uuid'] = net['net_id']
+#             if 'model' in net:
+#                 error_text += " 'model' " +  net['model']
+#                 WHERE_['name'] = net['model']
+#             if len(WHERE_) == 0:
+#                 return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
+#             r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
+#                 FROM='datacenter_nets', WHERE=WHERE_ )
+#             if r<0:
+#                 print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
+#             elif r==0:
+#                 print "nfvo.new_scenario Error" +error_text+ " is not present at database"
+#                 return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
+#             elif r>1:
+#                 print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
+#                 return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
+#             other_nets[k].update(net_db[0])
+#ENDIF
+    net_list={}
+    net_nb=0  #Number of nets
+    for con in conections_list:
+        #check if this is connected to a external net
+        other_net_index=-1
+        #print
+        #print "con", con
+        for index in range(0,len(con)):
+            #check if this is connected to a external net
+            for net_key in other_nets.keys():
+                if con[index][0]==net_key:
+                    if other_net_index>=0:
+                        error_text="There is some interface connected both to net '%s' and net '%s'" % (con[other_net_index][0], net_key)
+                        #print "nfvo.new_scenario " + error_text
+                        raise NfvoException(error_text, HTTP_Bad_Request)
+                    else:
+                        other_net_index = index
+                        net_target = net_key
+                    break
+        #print "other_net_index", other_net_index
+        try:
+            if other_net_index>=0:
+                del con[other_net_index]
+#IF we do not want to check that external network exist at datacenter
+                if other_nets[net_target]['external'] :
+                    if "name" not in other_nets[net_target]:
+                        other_nets[net_target]['name'] =  other_nets[net_target]['model']
+                    if other_nets[net_target]["type"] == "external_network":
+                        if vnfs[ con[0][0] ]['ifaces'][ con[0][1] ]["type"] == "data":
+                            other_nets[net_target]["type"] =  "data"
+                        else:
+                            other_nets[net_target]["type"] =  "bridge"
+#ELSE
+#                 if other_nets[net_target]['external'] :
+#                     type_='data' if len(con)>1 else 'ptp'  #an external net is connected to a external port, so it is ptp if only one connection is done to this net
+#                     if type_=='data' and other_nets[net_target]['type']=="ptp":
+#                         error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
+#                         print "nfvo.new_scenario " + error_text
+#                         return -HTTP_Bad_Request, error_text
+#ENDIF
+                for iface in con:
+                    vnfs[ iface[0] ]['ifaces'][ iface[1] ]['net_key'] = net_target
+            else:
+                #create a net
+                net_type_bridge=False
+                net_type_data=False
+                net_target = "__-__net"+str(net_nb)
+                net_list[net_target] = {'name': conections_list_name[net_nb],  #"net-"+str(net_nb),
+                    'description':"net-%s in scenario %s" %(net_nb,topo['name']),
+                    'external':False}
+                for iface in con:
+                    vnfs[ iface[0] ]['ifaces'][ iface[1] ]['net_key'] = net_target
+                    iface_type = vnfs[ iface[0] ]['ifaces'][ iface[1] ]['type']
+                    if iface_type=='mgmt' or iface_type=='bridge':
+                        net_type_bridge = True
+                    else:
+                        net_type_data = True
+                if net_type_bridge and net_type_data:
+                    error_text = "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface[0], iface[1])
+                    #print "nfvo.new_scenario " + error_text
+                    raise NfvoException(error_text, HTTP_Bad_Request)
+                elif net_type_bridge:
+                    type_='bridge'
+                else:
+                    type_='data' if len(con)>2 else 'ptp'
+                net_list[net_target]['type'] = type_
+                net_nb+=1
+        except Exception:
+            error_text = "Error connection node %s : %s does not match any VNF or interface" % (iface[0], iface[1])
+            #print "nfvo.new_scenario " + error_text
+            #raise e
+            raise NfvoException(error_text, HTTP_Bad_Request)
+
+#1.8: Connect to management net all not already connected interfaces of type 'mgmt'
+    #1.8.1 obtain management net
+    mgmt_net = mydb.get_rows(SELECT=('uuid','name','description','type','shared'),
+        FROM='datacenter_nets', WHERE={'name':'mgmt'} )
+    #1.8.2 check all interfaces from all vnfs
+    if len(mgmt_net)>0:
+        add_mgmt_net = False
+        for vnf in vnfs.values():
+            for iface in vnf['ifaces'].values():
+                if iface['type']=='mgmt' and 'net_key' not in iface:
+                    #iface not connected
+                    iface['net_key'] = 'mgmt'
+                    add_mgmt_net = True
+        if add_mgmt_net and 'mgmt' not in net_list:
+            net_list['mgmt']=mgmt_net[0]
+            net_list['mgmt']['external']=True
+            net_list['mgmt']['graph']={'visible':False}
+
+    net_list.update(other_nets)
+    #print
+    #print 'net_list', net_list
+    #print
+    #print 'vnfs', vnfs
+    #print
+
+#2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
+    c = mydb.new_scenario( { 'vnfs':vnfs, 'nets':net_list,
+        'tenant_id':tenant_id, 'name':topo['name'],
+         'description':topo.get('description',topo['name']),
+         'public': topo.get('public', False)
+         })
+
+    return c
+
+
+def new_scenario_v02(mydb, tenant_id, scenario_dict, version):
+    """ This creates a new scenario for version 0.2 and 0.3"""
+    scenario = scenario_dict["scenario"]
+    if tenant_id != "any":
+        check_tenant(mydb, tenant_id)
+        if "tenant_id" in scenario:
+            if scenario["tenant_id"] != tenant_id:
+                # print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
+                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
+                                                    scenario["tenant_id"], tenant_id), HTTP_Unauthorized)
+    else:
+        tenant_id=None
+
+    # 1: Check that VNF are present at database table vnfs and update content into scenario dict
+    for name,vnf in scenario["vnfs"].iteritems():
+        where={}
+        where_or={"tenant_id": tenant_id, 'public': "true"}
+        error_text = ""
+        error_pos = "'scenario':'vnfs':'" + name + "'"
+        if 'vnf_id' in vnf:
+            error_text += " 'vnf_id' " + vnf['vnf_id']
+            where['uuid'] = vnf['vnf_id']
+        if 'vnf_name' in vnf:
+            error_text += " 'vnf_name' " + vnf['vnf_name']
+            where['name'] = vnf['vnf_name']
+        if len(where) == 0:
+            raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos, HTTP_Bad_Request)
+        vnf_db = mydb.get_rows(SELECT=('uuid', 'name', 'description'),
+                               FROM='vnfs',
+                               WHERE=where,
+                               WHERE_OR=where_or,
+                               WHERE_AND_OR="AND")
+        if len(vnf_db) == 0:
+            raise NfvoException("Unknown" + error_text + " at " + error_pos, HTTP_Not_Found)
+        elif len(vnf_db) > 1:
+            raise NfvoException("More than one" + error_text + " at " + error_pos + " Concrete with 'vnf_id'", HTTP_Conflict)
+        vnf['uuid'] = vnf_db[0]['uuid']
+        vnf['description'] = vnf_db[0]['description']
+        vnf['ifaces'] = {}
+        # get external interfaces
+        ext_ifaces = mydb.get_rows(SELECT=('external_name as name', 'i.uuid as iface_uuid', 'i.type as type'),
+                                   FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
+                                   WHERE={'vnfs.uuid':vnf['uuid']}, WHERE_NOT={'external_name': None} )
+        for ext_iface in ext_ifaces:
+            vnf['ifaces'][ ext_iface['name'] ] = {'uuid':ext_iface['iface_uuid'], 'type': ext_iface['type']}
+        # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
+
+    # 2: Insert net_key and ip_address at every vnf interface
+    for net_name, net in scenario["networks"].items():
+        net_type_bridge = False
+        net_type_data = False
+        for iface_dict in net["interfaces"]:
+            if version == "0.2":
+                temp_dict = iface_dict
+                ip_address = None
+            elif version == "0.3":
+                temp_dict = {iface_dict["vnf"] : iface_dict["vnf_interface"]}
+                ip_address = iface_dict.get('ip_address', None)
+            for vnf, iface in temp_dict.items():
+                if vnf not in scenario["vnfs"]:
+                    error_text = "Error at 'networks':'{}':'interfaces' VNF '{}' not match any VNF at 'vnfs'".format(
+                        net_name, vnf)
+                    # logger.debug("nfvo.new_scenario_v02 " + error_text)
+                    raise NfvoException(error_text, HTTP_Not_Found)
+                if iface not in scenario["vnfs"][vnf]['ifaces']:
+                    error_text = "Error at 'networks':'{}':'interfaces':'{}' interface not match any VNF interface"\
+                        .format(net_name, iface)
+                    # logger.debug("nfvo.new_scenario_v02 " + error_text)
+                    raise NfvoException(error_text, HTTP_Bad_Request)
+                if "net_key" in scenario["vnfs"][vnf]['ifaces'][iface]:
+                    error_text = "Error at 'networks':'{}':'interfaces':'{}' interface already connected at network"\
+                                 "'{}'".format(net_name, iface,scenario["vnfs"][vnf]['ifaces'][iface]['net_key'])
+                    # logger.debug("nfvo.new_scenario_v02 " + error_text)
+                    raise NfvoException(error_text, HTTP_Bad_Request)
+                scenario["vnfs"][vnf]['ifaces'][ iface ]['net_key'] = net_name
+                scenario["vnfs"][vnf]['ifaces'][iface]['ip_address'] = ip_address
+                iface_type = scenario["vnfs"][vnf]['ifaces'][iface]['type']
+                if iface_type == 'mgmt' or iface_type == 'bridge':
+                    net_type_bridge = True
+                else:
+                    net_type_data = True
+
+        if net_type_bridge and net_type_data:
+            error_text = "Error connection interfaces of 'bridge' type and 'data' type at 'networks':'{}':'interfaces'"\
+                .format(net_name)
+            # logger.debug("nfvo.new_scenario " + error_text)
+            raise NfvoException(error_text, HTTP_Bad_Request)
+        elif net_type_bridge:
+            type_ = 'bridge'
+        else:
+            type_ = 'data' if len(net["interfaces"]) > 2 else 'ptp'
+
+        if net.get("implementation"):     # for v0.3
+            if type_ == "bridge" and net["implementation"] == "underlay":
+                error_text = "Error connecting interfaces of data type to a network declared as 'underlay' at "\
+                             "'network':'{}'".format(net_name)
+                # logger.debug(error_text)
+                raise NfvoException(error_text, HTTP_Bad_Request)
+            elif type_ != "bridge" and net["implementation"] == "overlay":
+                error_text = "Error connecting interfaces of data type to a network declared as 'overlay' at "\
+                             "'network':'{}'".format(net_name)
+                # logger.debug(error_text)
+                raise NfvoException(error_text, HTTP_Bad_Request)
+            net.pop("implementation")
+        if "type" in net and version == "0.3":   # for v0.3
+            if type_ == "data" and net["type"] == "e-line":
+                error_text = "Error connecting more than 2 interfaces of data type to a network declared as type "\
+                             "'e-line' at 'network':'{}'".format(net_name)
+                # logger.debug(error_text)
+                raise NfvoException(error_text, HTTP_Bad_Request)
+            elif type_ == "ptp" and net["type"] == "e-lan":
+                type_ = "data"
+
+        net['type'] = type_
+        net['name'] = net_name
+        net['external'] = net.get('external', False)
+
+    # 3: insert at database
+    scenario["nets"] = scenario["networks"]
+    scenario['tenant_id'] = tenant_id
+    scenario_id = mydb.new_scenario(scenario)
+    return scenario_id
+
+
+def edit_scenario(mydb, tenant_id, scenario_id, data):
+    data["uuid"] = scenario_id
+    data["tenant_id"] = tenant_id
+    c = mydb.edit_scenario( data )
+    return c
+
+
+def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instance_scenario_description, datacenter=None,vim_tenant=None, startvms=True):
+    #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
+    datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter, vim_tenant=vim_tenant)
+    vims = {datacenter_id: myvim}
+    myvim_tenant = myvim['tenant_id']
+    datacenter_name = myvim['name']
+
+    rollbackList=[]
+    try:
+        #print "Checking that the scenario_id exists and getting the scenario dictionary"
+        scenarioDict = mydb.get_scenario(scenario_id, tenant_id, datacenter_id)
+        scenarioDict['datacenter2tenant'] = { datacenter_id: myvim['config']['datacenter_tenant_id'] }
+        scenarioDict['datacenter_id'] = datacenter_id
+        #print '================scenarioDict======================='
+        #print json.dumps(scenarioDict, indent=4)
+        #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
+
+        logger.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict['name'],len(scenarioDict['vnfs']))
+        #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
+
+        auxNetDict = {}   #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
+        auxNetDict['scenario'] = {}
+
+        logger.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
+        for sce_net in scenarioDict['nets']:
+            #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
+
+            myNetName = "%s.%s" % (instance_scenario_name, sce_net['name'])
+            myNetName = myNetName[0:255] #limit length
+            myNetType = sce_net['type']
+            myNetDict = {}
+            myNetDict["name"] = myNetName
+            myNetDict["type"] = myNetType
+            myNetDict["tenant_id"] = myvim_tenant
+            myNetIPProfile = sce_net.get('ip_profile', None)
+            #TODO:
+            #We should use the dictionary as input parameter for new_network
+            #print myNetDict
+            if not sce_net["external"]:
+                network_id = myvim.new_network(myNetName, myNetType, myNetIPProfile)
+                #print "New VIM network created for scenario %s. Network id:  %s" % (scenarioDict['name'],network_id)
+                sce_net['vim_id'] = network_id
+                auxNetDict['scenario'][sce_net['uuid']] = network_id
+                rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':network_id})
+                sce_net["created"] = True
+            else:
+                if sce_net['vim_id'] == None:
+                    error_text = "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name, sce_net['name'])
+                    _, message = rollback(mydb, vims, rollbackList)
+                    logger.error("nfvo.start_scenario: %s", error_text)
+                    raise NfvoException(error_text, HTTP_Bad_Request)
+                logger.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict['name'],sce_net['vim_id'])
+                auxNetDict['scenario'][sce_net['uuid']] = sce_net['vim_id']
+
+        logger.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
+        #For each vnf net, we create it and we add it to instanceNetlist.
+        for sce_vnf in scenarioDict['vnfs']:
+            for net in sce_vnf['nets']:
+                #print "Net name: %s. Description: %s" % (net["name"], net["description"])
+
+                myNetName = "%s.%s" % (instance_scenario_name,net['name'])
+                myNetName = myNetName[0:255] #limit length
+                myNetType = net['type']
+                myNetDict = {}
+                myNetDict["name"] = myNetName
+                myNetDict["type"] = myNetType
+                myNetDict["tenant_id"] = myvim_tenant
+                myNetIPProfile = net.get('ip_profile', None)
+                #print myNetDict
+                #TODO:
+                #We should use the dictionary as input parameter for new_network
+                network_id = myvim.new_network(myNetName, myNetType, myNetIPProfile)
+                #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
+                net['vim_id'] = network_id
+                if sce_vnf['uuid'] not in auxNetDict:
+                    auxNetDict[sce_vnf['uuid']] = {}
+                auxNetDict[sce_vnf['uuid']][net['uuid']] = network_id
+                rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':network_id})
+                net["created"] = True
+
+        #print "auxNetDict:"
+        #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
+
+        logger.debug("start_scenario 3. Creating new vm instances in the VIM")
+        #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
+        i = 0
+        for sce_vnf in scenarioDict['vnfs']:
+            for vm in sce_vnf['vms']:
+                i += 1
+                myVMDict = {}
+                #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
+                myVMDict['name'] = "{}.{}.{}".format(instance_scenario_name,sce_vnf['name'],chr(96+i))
+                #myVMDict['description'] = vm['description']
+                myVMDict['description'] = myVMDict['name'][0:99]
+                if not startvms:
+                    myVMDict['start'] = "no"
+                myVMDict['name'] = myVMDict['name'][0:255] #limit name length
+                #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
+
+                #create image at vim in case it not exist
+                image_dict = mydb.get_table_by_uuid_name("images", vm['image_id'])
+                image_id = create_or_use_image(mydb, vims, image_dict, [], True)
+                vm['vim_image_id'] = image_id
+
+                #create flavor at vim in case it not exist
+                flavor_dict = mydb.get_table_by_uuid_name("flavors", vm['flavor_id'])
+                if flavor_dict['extended']!=None:
+                    flavor_dict['extended']= yaml.load(flavor_dict['extended'])
+                flavor_id = create_or_use_flavor(mydb, vims, flavor_dict, [], True)
+                vm['vim_flavor_id'] = flavor_id
+
+
+                myVMDict['imageRef'] = vm['vim_image_id']
+                myVMDict['flavorRef'] = vm['vim_flavor_id']
+                myVMDict['networks'] = []
+                for iface in vm['interfaces']:
+                    netDict = {}
+                    if iface['type']=="data":
+                        netDict['type'] = iface['model']
+                    elif "model" in iface and iface["model"]!=None:
+                        netDict['model']=iface['model']
+                    #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
+                    #discover type of interface looking at flavor
+                    for numa in flavor_dict.get('extended',{}).get('numas',[]):
+                        for flavor_iface in numa.get('interfaces',[]):
+                            if flavor_iface.get('name') == iface['internal_name']:
+                                if flavor_iface['dedicated'] == 'yes':
+                                    netDict['type']="PF"    #passthrough
+                                elif flavor_iface['dedicated'] == 'no':
+                                    netDict['type']="VF"    #siov
+                                elif flavor_iface['dedicated'] == 'yes:sriov':
+                                    netDict['type']="VFnotShared"   #sriov but only one sriov on the PF
+                                netDict["mac_address"] = flavor_iface.get("mac_address")
+                                break;
+                    netDict["use"]=iface['type']
+                    if netDict["use"]=="data" and not netDict.get("type"):
+                        #print "netDict", netDict
+                        #print "iface", iface
+                        e_text = "Cannot determine the interface type PF or VF of VNF '%s' VM '%s' iface '%s'" %(sce_vnf['name'], vm['name'], iface['internal_name'])
+                        if flavor_dict.get('extended')==None:
+                            raise NfvoException(e_text  + "After database migration some information is not available. \
+                                    Try to delete and create the scenarios and VNFs again", HTTP_Conflict)
+                        else:
+                            raise NfvoException(e_text, HTTP_Internal_Server_Error)
+                    if netDict["use"]=="mgmt" or netDict["use"]=="bridge":
+                        netDict["type"]="virtual"
+                    if "vpci" in iface and iface["vpci"] is not None:
+                        netDict['vpci'] = iface['vpci']
+                    if "mac" in iface and iface["mac"] is not None:
+                        netDict['mac_address'] = iface['mac']
+                    if "port-security" in iface and iface["port-security"] is not None:
+                        netDict['port_security'] = iface['port-security']
+                    if "floating-ip" in iface and iface["floating-ip"] is not None:
+                        netDict['floating_ip'] = iface['floating-ip']
+                    netDict['name'] = iface['internal_name']
+                    if iface['net_id'] is None:
+                        for vnf_iface in sce_vnf["interfaces"]:
+                            #print iface
+                            #print vnf_iface
+                            if vnf_iface['interface_id']==iface['uuid']:
+                                netDict['net_id'] = auxNetDict['scenario'][ vnf_iface['sce_net_id'] ]
+                                break
+                    else:
+                        netDict['net_id'] = auxNetDict[ sce_vnf['uuid'] ][ iface['net_id'] ]
+                    #skip bridge ifaces not connected to any net
+                    #if 'net_id' not in netDict or netDict['net_id']==None:
+                    #    continue
+                    myVMDict['networks'].append(netDict)
+                #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
+                #print myVMDict['name']
+                #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
+                #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
+                #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
+                vm_id = myvim.new_vminstance(myVMDict['name'],myVMDict['description'],myVMDict.get('start', None),
+                        myVMDict['imageRef'],myVMDict['flavorRef'],myVMDict['networks'])
+                #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
+                vm['vim_id'] = vm_id
+                rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id})
+                #put interface uuid back to scenario[vnfs][vms[[interfaces]
+                for net in myVMDict['networks']:
+                    if "vim_id" in net:
+                        for iface in vm['interfaces']:
+                            if net["name"]==iface["internal_name"]:
+                                iface["vim_id"]=net["vim_id"]
+                                break
+
+        logger.debug("start scenario Deployment done")
+        #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
+        #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
+        instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_scenario_name, instance_scenario_description, scenarioDict)
+        return mydb.get_instance_scenario(instance_id)
+
+    except (db_base_Exception, vimconn.vimconnException) as e:
+        _, message = rollback(mydb, vims, rollbackList)
+        if isinstance(e, db_base_Exception):
+            error_text = "Exception at database"
+        else:
+            error_text = "Exception at VIM"
+        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
+        #logger.error("start_scenario %s", error_text)
+        raise NfvoException(error_text, e.http_code)
+
+
+def unify_cloud_config(cloud_config_preserve, cloud_config):
+    ''' join the cloud config information into cloud_config_preserve.
+    In case of conflict cloud_config_preserve preserves
+    None is admited
+    '''
+    if not cloud_config_preserve and not cloud_config:
+        return None
+
+    new_cloud_config = {"key-pairs":[], "users":[]}
+    # key-pairs
+    if cloud_config_preserve:
+        for key in cloud_config_preserve.get("key-pairs", () ):
+            if key not in new_cloud_config["key-pairs"]:
+                new_cloud_config["key-pairs"].append(key)
+    if cloud_config:
+        for key in cloud_config.get("key-pairs", () ):
+            if key not in new_cloud_config["key-pairs"]:
+                new_cloud_config["key-pairs"].append(key)
+    if not new_cloud_config["key-pairs"]:
+        del new_cloud_config["key-pairs"]
+
+    # users
+    if cloud_config:
+        new_cloud_config["users"] += cloud_config.get("users", () )
+    if cloud_config_preserve:
+        new_cloud_config["users"] += cloud_config_preserve.get("users", () )
+    index_to_delete = []
+    users = new_cloud_config.get("users", [])
+    for index0 in range(0,len(users)):
+        if index0 in index_to_delete:
+            continue
+        for index1 in range(index0+1,len(users)):
+            if index1 in index_to_delete:
+                continue
+            if users[index0]["name"] == users[index1]["name"]:
+                index_to_delete.append(index1)
+                for key in users[index1].get("key-pairs",()):
+                    if "key-pairs" not in users[index0]:
+                        users[index0]["key-pairs"] = [key]
+                    elif key not in users[index0]["key-pairs"]:
+                        users[index0]["key-pairs"].append(key)
+    index_to_delete.sort(reverse=True)
+    for index in index_to_delete:
+        del users[index]
+    if not new_cloud_config["users"]:
+        del new_cloud_config["users"]
+
+    #boot-data-drive
+    if cloud_config and cloud_config.get("boot-data-drive") != None:
+        new_cloud_config["boot-data-drive"] = cloud_config["boot-data-drive"]
+    if cloud_config_preserve and cloud_config_preserve.get("boot-data-drive") != None:
+        new_cloud_config["boot-data-drive"] = cloud_config_preserve["boot-data-drive"]
+
+    # user-data
+    if cloud_config and cloud_config.get("user-data") != None:
+        new_cloud_config["user-data"] = cloud_config["user-data"]
+    if cloud_config_preserve and cloud_config_preserve.get("user-data") != None:
+        new_cloud_config["user-data"] = cloud_config_preserve["user-data"]
+
+    # config files
+    new_cloud_config["config-files"] = []
+    if cloud_config and cloud_config.get("config-files") != None:
+        new_cloud_config["config-files"] += cloud_config["config-files"]
+    if cloud_config_preserve:
+        for file in cloud_config_preserve.get("config-files", ()):
+            for index in range(0, len(new_cloud_config["config-files"])):
+                if new_cloud_config["config-files"][index]["dest"] == file["dest"]:
+                    new_cloud_config["config-files"][index] = file
+                    break
+            else:
+                new_cloud_config["config-files"].append(file)
+    if not new_cloud_config["config-files"]:
+        del new_cloud_config["config-files"]
+    return new_cloud_config
+
+
+def get_vim_thread(tenant_id, datacenter_id_name=None, datacenter_tenant_id=None):
+    datacenter_id = None
+    datacenter_name = None
+    thread = None
+    if datacenter_id_name:
+        if utils.check_valid_uuid(datacenter_id_name):
+            datacenter_id = datacenter_id_name
+        else:
+            datacenter_name = datacenter_id_name
+    if datacenter_id:
+        thread = vim_threads["running"].get(datacenter_id + "." + tenant_id)
+    else:
+        for k, v in vim_threads["running"].items():
+            datacenter_tenant = k.split(".")
+            if datacenter_tenant[0] == datacenter_id and datacenter_tenant[1] == tenant_id:
+                if thread:
+                    raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
+                thread = v
+            elif not datacenter_id and datacenter_tenant[1] == tenant_id:
+                if thread.datacenter_name == datacenter_name:
+                    if thread:
+                        raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
+                    thread = v
+    if not thread:
+        raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), HTTP_Not_Found)
+    return thread
+
+
+def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None, **extra_filter):
+    datacenter_id = None
+    datacenter_name = None
+    if datacenter_id_name:
+        if utils.check_valid_uuid(datacenter_id_name):
+            datacenter_id = datacenter_id_name
+        else:
+            datacenter_name = datacenter_id_name
+    vims = get_vim(mydb, tenant_id, datacenter_id, datacenter_name, **extra_filter)
+    if len(vims) == 0:
+        raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), HTTP_Not_Found)
+    elif len(vims)>1:
+        #print "nfvo.datacenter_action() error. Several datacenters found"
+        raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
+    return vims.keys()[0], vims.values()[0]
+
+
+def update(d, u):
+    '''Takes dict d and updates it with the values in dict u.'''
+    '''It merges all depth levels'''
+    for k, v in u.iteritems():
+        if isinstance(v, collections.Mapping):
+            r = update(d.get(k, {}), v)
+            d[k] = r
+        else:
+            d[k] = u[k]
+    return d
+
+
+def create_instance(mydb, tenant_id, instance_dict):
+    # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
+    # logger.debug("Creating instance...")
+    scenario = instance_dict["scenario"]
+
+    #find main datacenter
+    myvims = {}
+    myvim_threads = {}
+    datacenter2tenant = {}
+    datacenter = instance_dict.get("datacenter")
+    default_datacenter_id, vim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
+    myvims[default_datacenter_id] = vim
+    myvim_threads[default_datacenter_id] = get_vim_thread(tenant_id, default_datacenter_id)
+    datacenter2tenant[default_datacenter_id] = vim['config']['datacenter_tenant_id']
+    #myvim_tenant = myvim['tenant_id']
+#    default_datacenter_name = vim['name']
+    rollbackList=[]
+
+    #print "Checking that the scenario exists and getting the scenario dictionary"
+    scenarioDict = mydb.get_scenario(scenario, tenant_id, default_datacenter_id)
+
+    #logger.debug(">>>>>>> Dictionaries before merging")
+    #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
+    #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
+
+    scenarioDict['datacenter_id'] = default_datacenter_id
+
+    auxNetDict = {}   #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
+    auxNetDict['scenario'] = {}
+
+    logger.debug("Creating instance from scenario-dict:\n%s", yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))  #TODO remove
+    instance_name = instance_dict["name"]
+    instance_description = instance_dict.get("description")
+    instance_tasks={}
+    try:
+        # 0 check correct parameters
+        for net_name, net_instance_desc in instance_dict.get("networks",{}).iteritems():
+            found = False
+            for scenario_net in scenarioDict['nets']:
+                if net_name == scenario_net["name"]:
+                    found = True
+                    break
+            if not found:
+                raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name), HTTP_Bad_Request)
+            if "sites" not in net_instance_desc:
+                net_instance_desc["sites"] = [ {} ]
+            site_without_datacenter_field = False
+            for site in net_instance_desc["sites"]:
+                if site.get("datacenter"):
+                    if site["datacenter"] not in myvims:
+                        #Add this datacenter to myvims
+                        d, v = get_datacenter_by_name_uuid(mydb, tenant_id, site["datacenter"])
+                        myvims[d] = v
+                        myvim_threads[d] = get_vim_thread(tenant_id, site["datacenter"])
+                        datacenter2tenant[d] = v['config']['datacenter_tenant_id']
+                        site["datacenter"] = d #change name to id
+                else:
+                    if site_without_datacenter_field:
+                        raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name), HTTP_Bad_Request)
+                    site_without_datacenter_field = True
+                    site["datacenter"] = default_datacenter_id #change name to id
+
+        for vnf_name, vnf_instance_desc in instance_dict.get("vnfs",{}).iteritems():
+            found=False
+            for scenario_vnf in scenarioDict['vnfs']:
+                if vnf_name == scenario_vnf['name']:
+                    found = True
+                    break
+            if not found:
+                raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc), HTTP_Bad_Request)
+            if "datacenter" in vnf_instance_desc:
+            # Add this datacenter to myvims
+                if vnf_instance_desc["datacenter"] not in myvims:
+                    d, v = get_datacenter_by_name_uuid(mydb, tenant_id, vnf_instance_desc["datacenter"])
+                    myvims[d] = v
+                    myvim_threads[d] = get_vim_thread(tenant_id, vnf_instance_desc["datacenter"])
+                    datacenter2tenant[d] = v['config']['datacenter_tenant_id']
+                scenario_vnf["datacenter"] = vnf_instance_desc["datacenter"]
+
+    #0.1 parse cloud-config parameters
+        cloud_config = unify_cloud_config(instance_dict.get("cloud-config"), scenarioDict.get("cloud-config"))
+
+    #0.2 merge instance information into scenario
+        #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
+        #However, this is not possible yet.
+        for net_name, net_instance_desc in instance_dict.get("networks",{}).iteritems():
+            for scenario_net in scenarioDict['nets']:
+                if net_name == scenario_net["name"]:
+                    if 'ip-profile' in net_instance_desc:
+                        ipprofile = net_instance_desc['ip-profile']
+                        ipprofile['subnet_address'] = ipprofile.pop('subnet-address',None)
+                        ipprofile['ip_version'] = ipprofile.pop('ip-version','IPv4')
+                        ipprofile['gateway_address'] = ipprofile.pop('gateway-address',None)
+                        ipprofile['dns_address'] = ipprofile.pop('dns-address',None)
+                        if 'dhcp' in ipprofile:
+                            ipprofile['dhcp_start_address'] = ipprofile['dhcp'].get('start-address',None)
+                            ipprofile['dhcp_enabled'] = ipprofile['dhcp'].get('enabled',True)
+                            ipprofile['dhcp_count'] = ipprofile['dhcp'].get('count',None)
+                            del ipprofile['dhcp']
+                        if 'ip_profile' not in scenario_net:
+                            scenario_net['ip_profile'] = ipprofile
+                        else:
+                            update(scenario_net['ip_profile'],ipprofile)
+            for interface in net_instance_desc.get('interfaces', () ):
+                if 'ip_address' in interface:
+                    for vnf in scenarioDict['vnfs']:
+                        if interface['vnf'] == vnf['name']:
+                            for vnf_interface in vnf['interfaces']:
+                                if interface['vnf_interface'] == vnf_interface['external_name']:
+                                    vnf_interface['ip_address']=interface['ip_address']
+
+        #logger.debug(">>>>>>>> Merged dictionary")
+        logger.debug("Creating instance scenario-dict MERGED:\n%s", yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))
+
+
+        # 1. Creating new nets (sce_nets) in the VIM"
+        for sce_net in scenarioDict['nets']:
+            sce_net["vim_id_sites"]={}
+            descriptor_net =  instance_dict.get("networks",{}).get(sce_net["name"],{})
+            net_name = descriptor_net.get("vim-network-name")
+            auxNetDict['scenario'][sce_net['uuid']] = {}
+
+            sites = descriptor_net.get("sites", [ {} ])
+            for site in sites:
+                if site.get("datacenter"):
+                    vim = myvims[ site["datacenter"] ]
+                    datacenter_id = site["datacenter"]
+                    myvim_thread = myvim_threads[ site["datacenter"] ]
+                else:
+                    vim = myvims[ default_datacenter_id ]
+                    datacenter_id = default_datacenter_id
+                    myvim_thread = myvim_threads[default_datacenter_id]
+                net_type = sce_net['type']
+                lookfor_filter = {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
+                if sce_net["external"]:
+                    if not net_name:
+                        net_name = sce_net["name"]
+                    if "netmap-use" in site or "netmap-create" in site:
+                        create_network = False
+                        lookfor_network = False
+                        if "netmap-use" in site:
+                            lookfor_network = True
+                            if utils.check_valid_uuid(site["netmap-use"]):
+                                filter_text = "scenario id '%s'" % site["netmap-use"]
+                                lookfor_filter["id"] = site["netmap-use"]
+                            else:
+                                filter_text = "scenario name '%s'" % site["netmap-use"]
+                                lookfor_filter["name"] = site["netmap-use"]
+                        if "netmap-create" in site:
+                            create_network = True
+                            net_vim_name = net_name
+                            if site["netmap-create"]:
+                                net_vim_name = site["netmap-create"]
+
+                    elif sce_net['vim_id'] != None:
+                        #there is a netmap at datacenter_nets database   #TODO REVISE!!!!
+                        create_network = False
+                        lookfor_network = True
+                        lookfor_filter["id"] = sce_net['vim_id']
+                        filter_text = "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net['vim_id'], sce_net["name"])
+                        #look for network at datacenter and return error
+                    else:
+                        #There is not a netmap, look at datacenter for a net with this name and create if not found
+                        create_network = True
+                        lookfor_network = True
+                        lookfor_filter["name"] = sce_net["name"]
+                        net_vim_name = sce_net["name"]
+                        filter_text = "scenario name '%s'" % sce_net["name"]
+                else:
+                    if not net_name:
+                        net_name = "%s.%s" %(instance_name, sce_net["name"])
+                        net_name = net_name[:255]     #limit length
+                    net_vim_name = net_name
+                    create_network = True
+                    lookfor_network = False
+
+                if lookfor_network:
+                    vim_nets = vim.get_network_list(filter_dict=lookfor_filter)
+                    if len(vim_nets) > 1:
+                        raise NfvoException("More than one candidate VIM network found for " + filter_text, HTTP_Bad_Request )
+                    elif len(vim_nets) == 0:
+                        if not create_network:
+                            raise NfvoException("No candidate VIM network found for " + filter_text, HTTP_Bad_Request )
+                    else:
+                        sce_net["vim_id_sites"][datacenter_id] = vim_nets[0]['id']
+                        auxNetDict['scenario'][sce_net['uuid']][datacenter_id] = vim_nets[0]['id']
+                        create_network = False
+                if create_network:
+                    #if network is not external
+                    task = new_task("new-net", (net_vim_name, net_type, sce_net.get('ip_profile',None)))
+                    task_id = myvim_thread.insert_task(task)
+                    instance_tasks[task_id] = task
+                    #network_id = vim.new_network(net_vim_name, net_type, sce_net.get('ip_profile',None))
+                    sce_net["vim_id_sites"][datacenter_id] = task_id
+                    auxNetDict['scenario'][sce_net['uuid']][datacenter_id] = task_id
+                    rollbackList.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id, 'uuid':task_id})
+                    sce_net["created"] = True
+
+        # 2. Creating new nets (vnf internal nets) in the VIM"
+        #For each vnf net, we create it and we add it to instanceNetlist.
+        for sce_vnf in scenarioDict['vnfs']:
+            for net in sce_vnf['nets']:
+                if sce_vnf.get("datacenter"):
+                    vim = myvims[ sce_vnf["datacenter"] ]
+                    datacenter_id = sce_vnf["datacenter"]
+                    myvim_thread = myvim_threads[ sce_vnf["datacenter"]]
+                else:
+                    vim = myvims[ default_datacenter_id ]
+                    datacenter_id = default_datacenter_id
+                    myvim_thread = myvim_threads[default_datacenter_id]
+                descriptor_net =  instance_dict.get("vnfs",{}).get(sce_vnf["name"],{})
+                net_name = descriptor_net.get("name")
+                if not net_name:
+                    net_name = "%s.%s" %(instance_name, net["name"])
+                    net_name = net_name[:255]     #limit length
+                net_type = net['type']
+                task = new_task("new-net", (net_name, net_type, net.get('ip_profile',None)))
+                task_id = myvim_thread.insert_task(task)
+                instance_tasks[task_id] = task
+                # network_id = vim.new_network(net_name, net_type, net.get('ip_profile',None))
+                net['vim_id'] = task_id
+                if sce_vnf['uuid'] not in auxNetDict:
+                    auxNetDict[sce_vnf['uuid']] = {}
+                auxNetDict[sce_vnf['uuid']][net['uuid']] = task_id
+                rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':task_id})
+                net["created"] = True
+
+
+        #print "auxNetDict:"
+        #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
+
+        # 3. Creating new vm instances in the VIM
+        #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
+        for sce_vnf in scenarioDict['vnfs']:
+            if sce_vnf.get("datacenter"):
+                vim = myvims[ sce_vnf["datacenter"] ]
+                myvim_thread = myvim_threads[ sce_vnf["datacenter"] ]
+                datacenter_id = sce_vnf["datacenter"]
+            else:
+                vim = myvims[ default_datacenter_id ]
+                myvim_thread = myvim_threads[ default_datacenter_id ]
+                datacenter_id = default_datacenter_id
+            sce_vnf["datacenter_id"] =  datacenter_id
+            i = 0
+            for vm in sce_vnf['vms']:
+                i += 1
+                myVMDict = {}
+                myVMDict['name'] = "{}.{}.{}".format(instance_name,sce_vnf['name'],chr(96+i))
+                myVMDict['description'] = myVMDict['name'][0:99]
+#                if not startvms:
+#                    myVMDict['start'] = "no"
+                myVMDict['name'] = myVMDict['name'][0:255] #limit name length
+                #create image at vim in case it not exist
+                image_dict = mydb.get_table_by_uuid_name("images", vm['image_id'])
+                image_id = create_or_use_image(mydb, {datacenter_id: vim}, image_dict, [], True)
+                vm['vim_image_id'] = image_id
+
+                #create flavor at vim in case it not exist
+                flavor_dict = mydb.get_table_by_uuid_name("flavors", vm['flavor_id'])
+                if flavor_dict['extended']!=None:
+                    flavor_dict['extended']= yaml.load(flavor_dict['extended'])
+                flavor_id = create_or_use_flavor(mydb, {datacenter_id: vim}, flavor_dict, rollbackList, True)
+
+                #Obtain information for additional disks
+                extended_flavor_dict = mydb.get_rows(FROM='datacenters_flavors', SELECT=('extended',), WHERE={'vim_id': flavor_id})
+                if not extended_flavor_dict:
+                    raise NfvoException("flavor '{}' not found".format(flavor_id), HTTP_Not_Found)
+                    return
+
+                #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
+                myVMDict['disks'] = None
+                extended_info = extended_flavor_dict[0]['extended']
+                if extended_info != None:
+                    extended_flavor_dict_yaml = yaml.load(extended_info)
+                    if 'disks' in extended_flavor_dict_yaml:
+                        myVMDict['disks'] = extended_flavor_dict_yaml['disks']
+
+                vm['vim_flavor_id'] = flavor_id
+                myVMDict['imageRef'] = vm['vim_image_id']
+                myVMDict['flavorRef'] = vm['vim_flavor_id']
+                myVMDict['networks'] = []
+                task_depends = {}
+                #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
+                for iface in vm['interfaces']:
+                    netDict = {}
+                    if iface['type']=="data":
+                        netDict['type'] = iface['model']
+                    elif "model" in iface and iface["model"]!=None:
+                        netDict['model']=iface['model']
+                    #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
+                    #discover type of interface looking at flavor
+                    for numa in flavor_dict.get('extended',{}).get('numas',[]):
+                        for flavor_iface in numa.get('interfaces',[]):
+                            if flavor_iface.get('name') == iface['internal_name']:
+                                if flavor_iface['dedicated'] == 'yes':
+                                    netDict['type']="PF"    #passthrough
+                                elif flavor_iface['dedicated'] == 'no':
+                                    netDict['type']="VF"    #siov
+                                elif flavor_iface['dedicated'] == 'yes:sriov':
+                                    netDict['type']="VFnotShared"   #sriov but only one sriov on the PF
+                                netDict["mac_address"] = flavor_iface.get("mac_address")
+                                break;
+                    netDict["use"]=iface['type']
+                    if netDict["use"]=="data" and not netDict.get("type"):
+                        #print "netDict", netDict
+                        #print "iface", iface
+                        e_text = "Cannot determine the interface type PF or VF of VNF '%s' VM '%s' iface '%s'" %(sce_vnf['name'], vm['name'], iface['internal_name'])
+                        if flavor_dict.get('extended')==None:
+                            raise NfvoException(e_text + "After database migration some information is not available. \
+                                    Try to delete and create the scenarios and VNFs again", HTTP_Conflict)
+                        else:
+                            raise NfvoException(e_text, HTTP_Internal_Server_Error)
+                    if netDict["use"]=="mgmt" or netDict["use"]=="bridge":
+                        netDict["type"]="virtual"
+                    if "vpci" in iface and iface["vpci"] is not None:
+                        netDict['vpci'] = iface['vpci']
+                    if "mac" in iface and iface["mac"] is not None:
+                        netDict['mac_address'] = iface['mac']
+                    if "port-security" in iface and iface["port-security"] is not None:
+                        netDict['port_security'] = iface['port-security']
+                    if "floating-ip" in iface and iface["floating-ip"] is not None:
+                        netDict['floating_ip'] = iface['floating-ip']
+                    netDict['name'] = iface['internal_name']
+                    if iface['net_id'] is None:
+                        for vnf_iface in sce_vnf["interfaces"]:
+                            #print iface
+                            #print vnf_iface
+                            if vnf_iface['interface_id']==iface['uuid']:
+                                netDict['net_id'] = auxNetDict['scenario'][ vnf_iface['sce_net_id'] ][datacenter_id]
+                                break
+                    else:
+                        netDict['net_id'] = auxNetDict[ sce_vnf['uuid'] ][ iface['net_id'] ]
+                    if is_task_id(netDict['net_id']):
+                        task_depends[netDict['net_id']] = instance_tasks[netDict['net_id']]
+                    #skip bridge ifaces not connected to any net
+                    #if 'net_id' not in netDict or netDict['net_id']==None:
+                    #    continue
+                    myVMDict['networks'].append(netDict)
+                #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
+                #print myVMDict['name']
+                #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
+                #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
+                #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
+                if vm.get("boot_data"):
+                    cloud_config_vm = unify_cloud_config(vm["boot_data"], cloud_config)
+                else:
+                    cloud_config_vm = cloud_config
+                task = new_task("new-vm", (myVMDict['name'], myVMDict['description'], myVMDict.get('start', None),
+                                           myVMDict['imageRef'], myVMDict['flavorRef'], myVMDict['networks'],
+                                           cloud_config_vm, myVMDict['disks']), depends=task_depends)
+                vm_id = myvim_thread.insert_task(task)
+                instance_tasks[vm_id] = task
+
+                vm['vim_id'] = vm_id
+                rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id})
+                #put interface uuid back to scenario[vnfs][vms[[interfaces]
+                for net in myVMDict['networks']:
+                    if "vim_id" in net:
+                        for iface in vm['interfaces']:
+                            if net["name"]==iface["internal_name"]:
+                                iface["vim_id"]=net["vim_id"]
+                                break
+        scenarioDict["datacenter2tenant"] = datacenter2tenant
+        logger.debug("create_instance Deployment done scenarioDict: %s",
+                    yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False) )
+        instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_name, instance_description, scenarioDict)
+        # Update database with those ended tasks
+        for task in instance_tasks.values():
+            if task["status"] == "ok":
+                if task["name"] == "new-vm":
+                    mydb.update_rows("instance_vms", UPDATE={"vim_vm_id": task["result"]},
+                                     WHERE={"vim_vm_id": task["id"]})
+                elif task["name"] == "new-net":
+                    mydb.update_rows("instance_nets", UPDATE={"vim_net_id": task["result"]},
+                                     WHERE={"vim_net_id": task["id"]})
+        return mydb.get_instance_scenario(instance_id)
+    except (NfvoException, vimconn.vimconnException,db_base_Exception)  as e:
+        message = rollback(mydb, myvims, rollbackList)
+        if isinstance(e, db_base_Exception):
+            error_text = "database Exception"
+        elif isinstance(e, vimconn.vimconnException):
+            error_text = "VIM Exception"
+        else:
+            error_text = "Exception"
+        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
+        #logger.error("create_instance: %s", error_text)
+        raise NfvoException(error_text, e.http_code)
+
+
+def delete_instance(mydb, tenant_id, instance_id):
+    #print "Checking that the instance_id exists and getting the instance dictionary"
+    instanceDict = mydb.get_instance_scenario(instance_id, tenant_id)
+    #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
+    tenant_id = instanceDict["tenant_id"]
+    #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
+
+    #1. Delete from Database
+    message = mydb.delete_instance_scenario(instance_id, tenant_id)
+
+    #2. delete from VIM
+    error_msg = ""
+    myvims = {}
+    myvim_threads = {}
+
+    #2.1 deleting VMs
+    #vm_fail_list=[]
+    for sce_vnf in instanceDict['vnfs']:
+        datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
+        if datacenter_key not in myvims:
+            try:
+                myvim_thread = get_vim_thread(tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
+            except NfvoException as e:
+                logger.error(str(e))
+                myvim_thread = None
+            myvim_threads[datacenter_key] = myvim_thread
+            vims = get_vim(mydb, tenant_id, datacenter_id=sce_vnf["datacenter_id"],
+                       datacenter_tenant_id=sce_vnf["datacenter_tenant_id"])
+            if len(vims) == 0:
+                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"],
+                                                                                        sce_vnf["datacenter_tenant_id"]))
+                myvims[datacenter_key] = None
+            else:
+                myvims[datacenter_key] = vims.values()[0]
+        myvim = myvims[datacenter_key]
+        myvim_thread = myvim_threads[datacenter_key]
+        for vm in sce_vnf['vms']:
+            if not myvim:
+                error_msg += "\n    VM id={} cannot be deleted because datacenter={} not found".format(vm['vim_vm_id'], sce_vnf["datacenter_id"])
+                continue
+            try:
+                task=None
+                if is_task_id(vm['vim_vm_id']):
+                    task_id = vm['vim_vm_id']
+                    old_task = task_dict.get(task_id)
+                    if not old_task:
+                        error_msg += "\n    VM was scheduled for create, but task {} is not found".format(task_id)
+                        continue
+                    with task_lock:
+                        if old_task["status"] == "enqueued":
+                            old_task["status"] = "deleted"
+                        elif old_task["status"] == "error":
+                            continue
+                        elif old_task["status"] == "processing":
+                            task = new_task("del-vm", task_id, depends={task_id: old_task})
+                        else: #ok
+                            task = new_task("del-vm", old_task["result"])
+                else:
+                    task = new_task("del-vm", vm['vim_vm_id'], store=False)
+                if task:
+                    myvim_thread.insert_task(task)
+            except vimconn.vimconnNotFoundException as e:
+                error_msg+="\n    VM VIM_id={} not found at datacenter={}".format(vm['vim_vm_id'], sce_vnf["datacenter_id"])
+                logger.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
+                    vm['name'], vm['uuid'], vm['vim_vm_id'], sce_vnf['vnf_id'])
+            except vimconn.vimconnException as e:
+                error_msg+="\n    VM VIM_id={} at datacenter={} Error: {} {}".format(vm['vim_vm_id'], sce_vnf["datacenter_id"], e.http_code, str(e))
+                logger.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
+                    e.http_code, vm['name'], vm['uuid'], vm['vim_vm_id'], sce_vnf['vnf_id'], str(e))
+
+    #2.2 deleting NETS
+    #net_fail_list=[]
+    for net in instanceDict['nets']:
+        if not net['created']:
+            continue #skip not created nets
+        datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"])
+        if datacenter_key not in myvims:
+            try:
+                myvim_thread = get_vim_thread(tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
+            except NfvoException as e:
+                logger.error(str(e))
+                myvim_thread = None
+            myvim_threads[datacenter_key] = myvim_thread
+            vims = get_vim(mydb, tenant_id, datacenter_id=net["datacenter_id"],
+                           datacenter_tenant_id=net["datacenter_tenant_id"])
+            if len(vims) == 0:
+                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
+                myvims[datacenter_key] = None
+            else:
+                myvims[datacenter_key] = vims.values()[0]
+        myvim = myvims[datacenter_key]
+        myvim_thread = myvim_threads[datacenter_key]
+
+        if not myvim:
+            error_msg += "\n    Net VIM_id={} cannot be deleted because datacenter={} not found".format(net['vim_net_id'], net["datacenter_id"])
+            continue
+        try:
+            task = None
+            if is_task_id(net['vim_net_id']):
+                task_id = net['vim_net_id']
+                old_task = task_dict.get(task_id)
+                if not old_task:
+                    error_msg += "\n    NET was scheduled for create, but task {} is not found".format(task_id)
+                    continue
+                with task_lock:
+                    if old_task["status"] == "enqueued":
+                        old_task["status"] = "deleted"
+                    elif old_task["status"] == "error":
+                        continue
+                    elif old_task["status"] == "processing":
+                        task = new_task("del-net", task_id, depends={task_id: old_task})
+                    else:  # ok
+                        task = new_task("del-net", old_task["result"])
+            else:
+                task = new_task("del-net", net['vim_net_id'], store=False)
+            if task:
+                myvim_thread.insert_task(task)
+        except vimconn.vimconnNotFoundException as e:
+            error_msg += "\n    NET VIM_id={} not found at datacenter={}".format(net['vim_net_id'], net["datacenter_id"])
+            logger.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
+                        net['uuid'], net['vim_net_id'], str(net['vnf_net_id']))
+        except vimconn.vimconnException as e:
+            error_msg += "\n    NET VIM_id={} at datacenter={} Error: {} {}".format(net['vim_net_id'],
+                                                                                    net["datacenter_id"],
+                                                                                    e.http_code, str(e))
+            logger.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
+                         e.http_code, net['uuid'], net['vim_net_id'], str(net['vnf_net_id']), str(e))
+    if len(error_msg) > 0:
+        return 'instance ' + message + ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
+    else:
+        return 'instance ' + message + ' deleted'
+
+
+def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenant=None):
+    '''Refreshes a scenario instance. It modifies instanceDict'''
+    '''Returns:
+         - result: <0 if there is any unexpected error, n>=0 if no errors where n is the number of vms and nets that couldn't be updated in the database
+         - error_msg
+    '''
+    # Assumption: nfvo_tenant and instance_id were checked before entering into this function
+    #print "nfvo.refresh_instance begins"
+    #print json.dumps(instanceDict, indent=4)
+
+    #print "Getting the VIM URL and the VIM tenant_id"
+    myvims={}
+
+    # 1. Getting VIM vm and net list
+    vms_updated = [] #List of VM instance uuids in openmano that were updated
+    vms_notupdated=[]
+    vm_list = {}
+    for sce_vnf in instanceDict['vnfs']:
+        datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
+        if datacenter_key not in vm_list:
+            vm_list[datacenter_key] = []
+        if datacenter_key not in myvims:
+            vims = get_vim(mydb, nfvo_tenant, datacenter_id=sce_vnf["datacenter_id"],
+                           datacenter_tenant_id=sce_vnf["datacenter_tenant_id"])
+            if len(vims) == 0:
+                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"]))
+                myvims[datacenter_key] = None
+            else:
+                myvims[datacenter_key] = vims.values()[0]
+        for vm in sce_vnf['vms']:
+            vm_list[datacenter_key].append(vm['vim_vm_id'])
+            vms_notupdated.append(vm["uuid"])
+
+    nets_updated = [] #List of VM instance uuids in openmano that were updated
+    nets_notupdated=[]
+    net_list = {}
+    for net in instanceDict['nets']:
+        datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"])
+        if datacenter_key not in net_list:
+            net_list[datacenter_key] = []
+        if datacenter_key not in myvims:
+            vims = get_vim(mydb, nfvo_tenant, datacenter_id=net["datacenter_id"],
+                           datacenter_tenant_id=net["datacenter_tenant_id"])
+            if len(vims) == 0:
+                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
+                myvims[datacenter_key] = None
+            else:
+                myvims[datacenter_key] = vims.values()[0]
+
+        net_list[datacenter_key].append(net['vim_net_id'])
+        nets_notupdated.append(net["uuid"])
+
+    # 1. Getting the status of all VMs
+    vm_dict={}
+    for datacenter_key in myvims:
+        if not vm_list.get(datacenter_key):
+            continue
+        failed = True
+        failed_message=""
+        if not myvims[datacenter_key]:
+            failed_message = "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"])
+        else:
+            try:
+                vm_dict.update(myvims[datacenter_key].refresh_vms_status(vm_list[datacenter_key]) )
+                failed = False
+            except vimconn.vimconnException as e:
+                logger.error("VIM exception %s %s", type(e).__name__, str(e))
+                failed_message = str(e)
+        if failed:
+            for vm in vm_list[datacenter_key]:
+                vm_dict[vm] = {'status': "VIM_ERROR", 'error_msg': failed_message}
+
+    # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
+    for sce_vnf in instanceDict['vnfs']:
+        for vm in sce_vnf['vms']:
+            vm_id = vm['vim_vm_id']
+            interfaces = vm_dict[vm_id].pop('interfaces', [])
+            #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
+            has_mgmt_iface = False
+            for iface in vm["interfaces"]:
+                if iface["type"]=="mgmt":
+                    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')
+                vm['vim_info']  = vm_dict[vm_id].get('vim_info')
+                # 2.1. Update in openmano DB the VMs whose status changed
+                try:
+                    updates = mydb.update_rows('instance_vms', UPDATE=vm_dict[vm_id], WHERE={'uuid':vm["uuid"]})
+                    vms_notupdated.remove(vm["uuid"])
+                    if updates>0:
+                        vms_updated.append(vm["uuid"])
+                except db_base_Exception as e:
+                    logger.error("nfvo.refresh_instance error database update: %s", str(e))
+            # 2.2. Update in openmano DB the interface VMs
+            for interface in interfaces:
+                #translate from vim_net_id to instance_net_id
+                network_id_list=[]
+                for net in instanceDict['nets']:
+                    if net["vim_net_id"] == interface["vim_net_id"]:
+                        network_id_list.append(net["uuid"])
+                if not network_id_list:
+                    continue
+                del interface["vim_net_id"]
+                try:
+                    for network_id in network_id_list:
+                        mydb.update_rows('instance_interfaces', UPDATE=interface, WHERE={'instance_vm_id':vm["uuid"], "instance_net_id":network_id})
+                except db_base_Exception as e:
+                    logger.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm["uuid"], network_id)
+
+    # 3. Getting the status of all nets
+    net_dict = {}
+    for datacenter_key in myvims:
+        if not net_list.get(datacenter_key):
+            continue
+        failed = True
+        failed_message = ""
+        if not myvims[datacenter_key]:
+            failed_message = "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"])
+        else:
+            try:
+                net_dict.update(myvims[datacenter_key].refresh_nets_status(net_list[datacenter_key]) )
+                failed = False
+            except vimconn.vimconnException as e:
+                logger.error("VIM exception %s %s", type(e).__name__, str(e))
+                failed_message = str(e)
+        if failed:
+            for net in net_list[datacenter_key]:
+                net_dict[net] = {'status': "VIM_ERROR", 'error_msg': failed_message}
+
+    # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
+    # 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')
+            net['vim_info']  = net_dict[net_id].get('vim_info')
+            # 5.1. Update in openmano DB the nets whose status changed
+            try:
+                updated = mydb.update_rows('instance_nets', UPDATE=net_dict[net_id], WHERE={'uuid':net["uuid"]})
+                nets_notupdated.remove(net["uuid"])
+                if updated>0:
+                    nets_updated.append(net["uuid"])
+            except db_base_Exception as e:
+                logger.error("nfvo.refresh_instance error database update: %s", str(e))
+
+    # Returns appropriate output
+    #print "nfvo.refresh_instance finishes"
+    logger.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
+                str(vms_updated), str(nets_updated), str(vms_notupdated), str(nets_notupdated))
+    instance_id = instanceDict['uuid']
+    if len(vms_notupdated)+len(nets_notupdated)>0:
+        error_msg = "VMs not updated: " + str(vms_notupdated) + "; nets not updated: " + str(nets_notupdated)
+        return len(vms_notupdated)+len(nets_notupdated), 'Scenario instance ' + instance_id + ' refreshed but some elements could not be updated in the database: ' + error_msg
+
+    return 0, 'Scenario instance ' + instance_id + ' refreshed.'
+
+
+def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
+    #print "Checking that the instance_id exists and getting the instance dictionary"
+    instanceDict = mydb.get_instance_scenario(instance_id, nfvo_tenant)
+    #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
+
+    #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
+    vims = get_vim(mydb, nfvo_tenant, instanceDict['datacenter_id'])
+    if len(vims) == 0:
+        raise NfvoException("datacenter '{}' not found".format(str(instanceDict['datacenter_id'])), HTTP_Not_Found)
+    myvim = vims.values()[0]
+
+
+    input_vnfs = action_dict.pop("vnfs", [])
+    input_vms = action_dict.pop("vms", [])
+    action_over_all = True if len(input_vnfs)==0 and len (input_vms)==0 else False
+    vm_result = {}
+    vm_error = 0
+    vm_ok = 0
+    for sce_vnf in instanceDict['vnfs']:
+        for vm in sce_vnf['vms']:
+            if not action_over_all:
+                if sce_vnf['uuid'] not in input_vnfs and sce_vnf['vnf_name'] not in input_vnfs and \
+                    vm['uuid'] not in input_vms and vm['name'] not in input_vms:
+                    continue
+            try:
+                data = myvim.action_vminstance(vm['vim_vm_id'], action_dict)
+                if "console" in action_dict:
+                    if not global_config["http_console_proxy"]:
+                        vm_result[ vm['uuid'] ] = {"vim_result": 200,
+                                                   "description": "{protocol}//{ip}:{port}/{suffix}".format(
+                                                                                protocol=data["protocol"],
+                                                                                ip = data["server"],
+                                                                                port = data["port"],
+                                                                                suffix = data["suffix"]),
+                                                   "name":vm['name']
+                                                }
+                        vm_ok +=1
+                    elif data["server"]=="127.0.0.1" or data["server"]=="localhost":
+                        vm_result[ vm['uuid'] ] = {"vim_result": -HTTP_Unauthorized,
+                                                   "description": "this console is only reachable by local interface",
+                                                   "name":vm['name']
+                                                }
+                        vm_error+=1
+                    else:
+                    #print "console data", data
+                        try:
+                            console_thread = create_or_use_console_proxy_thread(data["server"], data["port"])
+                            vm_result[ vm['uuid'] ] = {"vim_result": 200,
+                                                       "description": "{protocol}//{ip}:{port}/{suffix}".format(
+                                                                                    protocol=data["protocol"],
+                                                                                    ip = global_config["http_console_host"],
+                                                                                    port = console_thread.port,
+                                                                                    suffix = data["suffix"]),
+                                                       "name":vm['name']
+                                                    }
+                            vm_ok +=1
+                        except NfvoException as e:
+                            vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
+                            vm_error+=1
+
+                else:
+                    vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']}
+                    vm_ok +=1
+            except vimconn.vimconnException as e:
+                vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
+                vm_error+=1
+
+    if vm_ok==0: #all goes wrong
+        return vm_result
+    else:
+        return vm_result
+
+
+def create_or_use_console_proxy_thread(console_server, console_port):
+    #look for a non-used port
+    console_thread_key = console_server + ":" + str(console_port)
+    if console_thread_key in global_config["console_thread"]:
+        #global_config["console_thread"][console_thread_key].start_timeout()
+        return global_config["console_thread"][console_thread_key]
+
+    for port in  global_config["console_port_iterator"]():
+        #print "create_or_use_console_proxy_thread() port:", port
+        if port in global_config["console_ports"]:
+            continue
+        try:
+            clithread = cli.ConsoleProxyThread(global_config['http_host'], port, console_server, console_port)
+            clithread.start()
+            global_config["console_thread"][console_thread_key] = clithread
+            global_config["console_ports"][port] = console_thread_key
+            return clithread
+        except cli.ConsoleProxyExceptionPortUsed as e:
+            #port used, try with onoher
+            continue
+        except cli.ConsoleProxyException as e:
+            raise NfvoException(str(e), HTTP_Bad_Request)
+    raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict)
+
+
+def check_tenant(mydb, tenant_id):
+    '''check that tenant exists at database'''
+    tenant = mydb.get_rows(FROM='nfvo_tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id})
+    if not tenant:
+        raise NfvoException("tenant '{}' not found".format(tenant_id), HTTP_Not_Found)
+    return
+
+
+def new_tenant(mydb, tenant_dict):
+    tenant_id = mydb.new_row("nfvo_tenants", tenant_dict, add_uuid=True)
+    return tenant_id
+
+
+def delete_tenant(mydb, tenant):
+    #get nfvo_tenant info
+
+    tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', tenant, 'tenant')
+    mydb.delete_row_by_id("nfvo_tenants", tenant_dict['uuid'])
+    return tenant_dict['uuid'] + " " + tenant_dict["name"]
+
+
+def new_datacenter(mydb, datacenter_descriptor):
+    if "config" in datacenter_descriptor:
+        datacenter_descriptor["config"]=yaml.safe_dump(datacenter_descriptor["config"],default_flow_style=True,width=256)
+    #Check that datacenter-type is correct
+    datacenter_type = datacenter_descriptor.get("type", "openvim");
+    module_info = None
+    try:
+        module = "vimconn_" + datacenter_type
+        module_info = imp.find_module(module)
+    except (IOError, ImportError):
+        if module_info and module_info[0]:
+            file.close(module_info[0])
+        raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type, module), HTTP_Bad_Request)
+
+    datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True)
+    return datacenter_id
+
+
+def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor):
+    #obtain data, check that only one exist
+    datacenter = mydb.get_table_by_uuid_name('datacenters', datacenter_id_name)
+    #edit data
+    datacenter_id = datacenter['uuid']
+    where={'uuid': datacenter['uuid']}
+    if "config" in datacenter_descriptor:
+        if datacenter_descriptor['config']!=None:
+            try:
+                new_config_dict = datacenter_descriptor["config"]
+                #delete null fields
+                to_delete=[]
+                for k in new_config_dict:
+                    if new_config_dict[k]==None:
+                        to_delete.append(k)
+
+                config_dict = yaml.load(datacenter["config"])
+                config_dict.update(new_config_dict)
+                #delete null fields
+                for k in to_delete:
+                    del config_dict[k]
+            except Exception as e:
+                raise NfvoException("Bad format at datacenter:config " + str(e), HTTP_Bad_Request)
+        datacenter_descriptor["config"]= yaml.safe_dump(config_dict,default_flow_style=True,width=256) if len(config_dict)>0 else None
+    mydb.update_rows('datacenters', datacenter_descriptor, where)
+    return datacenter_id
+
+
+def delete_datacenter(mydb, datacenter):
+    #get nfvo_tenant info
+    datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter, '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, config=None):
+    #get datacenter info
+    datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter)
+    datacenter_name = myvim["name"]
+
+    create_vim_tenant = True if not vim_tenant_id and not vim_tenant_name else False
+
+    # get nfvo_tenant info
+    tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant)
+    if vim_tenant_name==None:
+        vim_tenant_name=tenant_dict['name']
+
+    #check that this association does not exist before
+    tenants_datacenter_dict={"nfvo_tenant_id":tenant_dict['uuid'], "datacenter_id":datacenter_id }
+    tenants_datacenters = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
+    if len(tenants_datacenters)>0:
+        raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id, tenant_dict['uuid']), HTTP_Conflict)
+
+    vim_tenant_id_exist_atdb=False
+    if not create_vim_tenant:
+        where_={"datacenter_id": datacenter_id}
+        if vim_tenant_id!=None:
+            where_["vim_tenant_id"] = vim_tenant_id
+        if vim_tenant_name!=None:
+            where_["vim_tenant_name"] = vim_tenant_name
+        #check if vim_tenant_id is already at database
+        datacenter_tenants_dict = mydb.get_rows(FROM='datacenter_tenants', WHERE=where_)
+        if len(datacenter_tenants_dict)>=1:
+            datacenter_tenants_dict = datacenter_tenants_dict[0]
+            vim_tenant_id_exist_atdb=True
+            #TODO check if a field has changed and edit entry at datacenter_tenants at DB
+        else: #result=0
+            datacenter_tenants_dict = {}
+            #insert at table datacenter_tenants
+    else: #if vim_tenant_id==None:
+        #create tenant at VIM if not provided
+        try:
+            vim_tenant_id = myvim.new_tenant(vim_tenant_name, "created by openmano for datacenter "+datacenter_name)
+        except vimconn.vimconnException as e:
+            raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id, str(e)), HTTP_Internal_Server_Error)
+        datacenter_tenants_dict = {}
+        datacenter_tenants_dict["created"]="true"
+
+    #fill datacenter_tenants table
+    if not vim_tenant_id_exist_atdb:
+        datacenter_tenants_dict["vim_tenant_id"] = vim_tenant_id
+        datacenter_tenants_dict["vim_tenant_name"] = vim_tenant_name
+        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_
+
+    #fill tenants_datacenters table
+    tenants_datacenter_dict["datacenter_tenant_id"]=datacenter_tenants_dict["uuid"]
+    mydb.new_row('tenants_datacenters', tenants_datacenter_dict)
+    # create thread
+    datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_dict['uuid'], datacenter_id)  # reload data
+    thread_name = get_non_used_vim_name(datacenter_name, datacenter_id, tenant_dict['name'], tenant_dict['uuid'])
+    new_thread = vim_thread.vim_thread(myvim, task_lock, thread_name, datacenter_name, db=db, db_lock=db_lock)
+    new_thread.start()
+    thread_id = datacenter_id + "." + tenant_dict['uuid']
+    vim_threads["running"][thread_id] = new_thread
+    return datacenter_id
+
+
+def deassociate_datacenter_to_tenant(mydb, tenant_id, datacenter, vim_tenant_id=None):
+    #get datacenter info
+    datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter)
+
+    #get nfvo_tenant info
+    if not tenant_id or tenant_id=="any":
+        tenant_uuid = None
+    else:
+        tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id)
+        tenant_uuid = tenant_dict['uuid']
+
+    #check that this association exist before
+    tenants_datacenter_dict={"datacenter_id":datacenter_id }
+    if tenant_uuid:
+        tenants_datacenter_dict["nfvo_tenant_id"] = tenant_uuid
+    tenant_datacenter_list = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
+    if len(tenant_datacenter_list)==0 and tenant_uuid:
+        raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id, tenant_dict['uuid']), HTTP_Not_Found)
+
+    #delete this association
+    mydb.delete_row(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
+
+    #get vim_tenant info and deletes
+    warning=''
+    for tenant_datacenter_item in tenant_datacenter_list:
+        vim_tenant_dict = mydb.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item['datacenter_tenant_id'])
+        #try to delete vim:tenant
+        try:
+            mydb.delete_row_by_id('datacenter_tenants', tenant_datacenter_item['datacenter_tenant_id'])
+            if vim_tenant_dict['created']=='true':
+                #delete tenant at VIM if created by NFVO
+                try:
+                    myvim.delete_tenant(vim_tenant_dict['vim_tenant_id'])
+                except vimconn.vimconnException as e:
+                    warning = "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict['vim_tenant_id'], str(e))
+                    logger.warn(warning)
+        except db_base_Exception as e:
+            logger.error("Cannot delete datacenter_tenants " + str(e))
+            pass  # the error will be caused because dependencies, vim_tenant can not be deleted
+        thread_id = datacenter_id + "." + tenant_datacenter_item["nfvo_tenant_id"]
+        thread = vim_threads["running"][thread_id]
+        thread.insert_task(new_task("exit", None, store=False))
+        vim_threads["deleting"][thread_id] = thread
+    return "datacenter {} detached. {}".format(datacenter_id, warning)
+
+
+def datacenter_action(mydb, tenant_id, datacenter, action_dict):
+    #DEPRECATED
+    #get datacenter info
+    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
+
+    if 'net-update' in action_dict:
+        try:
+            nets = myvim.get_network_list(filter_dict={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
+            #print content
+        except vimconn.vimconnException as e:
+            #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
+            raise NfvoException(str(e), HTTP_Internal_Server_Error)
+        #update nets Change from VIM format to NFVO format
+        net_list=[]
+        for net in nets:
+            net_nfvo={'datacenter_id': datacenter_id}
+            net_nfvo['name']       = net['name']
+            #net_nfvo['description']= net['name']
+            net_nfvo['vim_net_id'] = net['id']
+            net_nfvo['type']       = net['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man')  to ('bridge','data','ptp')
+            net_nfvo['shared']     = net['shared']
+            net_nfvo['multipoint'] = False if net['type']=='ptp' else True
+            net_list.append(net_nfvo)
+        inserted, deleted = mydb.update_datacenter_nets(datacenter_id, net_list)
+        logger.info("Inserted %d nets, deleted %d old nets", inserted, deleted)
+        return inserted
+    elif 'net-edit' in action_dict:
+        net = action_dict['net-edit'].pop('net')
+        what = 'vim_net_id' if utils.check_valid_uuid(net) else 'name'
+        result = mydb.update_rows('datacenter_nets', action_dict['net-edit'],
+                                WHERE={'datacenter_id':datacenter_id, what: net})
+        return result
+    elif 'net-delete' in action_dict:
+        net = action_dict['net-deelte'].get('net')
+        what = 'vim_net_id' if utils.check_valid_uuid(net) else 'name'
+        result = mydb.delete_row(FROM='datacenter_nets',
+                                WHERE={'datacenter_id':datacenter_id, what: net})
+        return result
+
+    else:
+        raise NfvoException("Unknown action " + str(action_dict), HTTP_Bad_Request)
+
+
+def datacenter_edit_netmap(mydb, tenant_id, datacenter, netmap, action_dict):
+    #get datacenter info
+    datacenter_id, _  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
+
+    what = 'uuid' if utils.check_valid_uuid(netmap) else 'name'
+    result = mydb.update_rows('datacenter_nets', action_dict['netmap'],
+                            WHERE={'datacenter_id':datacenter_id, what: netmap})
+    return result
+
+
+def datacenter_new_netmap(mydb, tenant_id, datacenter, action_dict=None):
+    #get datacenter info
+    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
+    filter_dict={}
+    if action_dict:
+        action_dict = action_dict["netmap"]
+        if 'vim_id' in action_dict:
+            filter_dict["id"] = action_dict['vim_id']
+        if 'vim_name' in action_dict:
+            filter_dict["name"] = action_dict['vim_name']
+    else:
+        filter_dict["shared"] = True
+
+    try:
+        vim_nets = myvim.get_network_list(filter_dict=filter_dict)
+    except vimconn.vimconnException as e:
+        #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
+        raise NfvoException(str(e), HTTP_Internal_Server_Error)
+    if len(vim_nets)>1 and action_dict:
+        raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict)
+    elif len(vim_nets)==0: # and action_dict:
+        raise NfvoException("Not found a network at VIM with " + str(filter_dict), HTTP_Not_Found)
+    net_list=[]
+    for net in vim_nets:
+        net_nfvo={'datacenter_id': datacenter_id}
+        if action_dict and "name" in action_dict:
+            net_nfvo['name']       = action_dict['name']
+        else:
+            net_nfvo['name']       = net['name']
+        #net_nfvo['description']= net['name']
+        net_nfvo['vim_net_id'] = net['id']
+        net_nfvo['type']       = net['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man')  to ('bridge','data','ptp')
+        net_nfvo['shared']     = net['shared']
+        net_nfvo['multipoint'] = False if net['type']=='ptp' else True
+        try:
+            net_id = mydb.new_row("datacenter_nets", net_nfvo, add_uuid=True)
+            net_nfvo["status"] = "OK"
+            net_nfvo["uuid"] = net_id
+        except db_base_Exception as e:
+            if action_dict:
+                raise
+            else:
+                net_nfvo["status"] = "FAIL: " + str(e)
+        net_list.append(net_nfvo)
+    return net_list
+
+
+def vim_action_get(mydb, tenant_id, datacenter, item, name):
+    #get datacenter info
+    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
+    filter_dict={}
+    if name:
+        if utils.check_valid_uuid(name):
+            filter_dict["id"] = name
+        else:
+            filter_dict["name"] = name
+    try:
+        if item=="networks":
+            #filter_dict['tenant_id'] = myvim['tenant_id']
+            content = myvim.get_network_list(filter_dict=filter_dict)
+        elif item=="tenants":
+            content = myvim.get_tenant_list(filter_dict=filter_dict)
+        elif item == "images":
+            content = myvim.get_image_list(filter_dict=filter_dict)
+        else:
+            raise NfvoException(item + "?", HTTP_Method_Not_Allowed)
+        logger.debug("vim_action response %s", content) #update nets Change from VIM format to NFVO format
+        if name and len(content)==1:
+            return {item[:-1]: content[0]}
+        elif name and len(content)==0:
+            raise NfvoException("No {} found with ".format(item[:-1]) + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), filter_dict.iteritems())),
+                 datacenter)
+        else:
+            return {item: content}
+    except vimconn.vimconnException as e:
+        print "vim_action Not possible to get_%s_list from VIM: %s " % (item, str(e))
+        raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code)
+
+
+def vim_action_delete(mydb, tenant_id, datacenter, item, name):
+    #get datacenter info
+    if tenant_id == "any":
+        tenant_id=None
+
+    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
+    #get uuid name
+    content = vim_action_get(mydb, tenant_id, datacenter, item, name)
+    logger.debug("vim_action_delete vim response: " + str(content))
+    items = content.values()[0]
+    if type(items)==list and len(items)==0:
+        raise NfvoException("Not found " + item, HTTP_Not_Found)
+    elif type(items)==list and len(items)>1:
+        raise NfvoException("Found more than one {} with this name. Use uuid.".format(item), HTTP_Not_Found)
+    else: # it is a dict
+        item_id = items["id"]
+        item_name = str(items.get("name"))
+
+    try:
+        if item=="networks":
+            content = myvim.delete_network(item_id)
+        elif item=="tenants":
+            content = myvim.delete_tenant(item_id)
+        elif item == "images":
+            content = myvim.delete_image(item_id)
+        else:
+            raise NfvoException(item + "?", HTTP_Method_Not_Allowed)
+    except vimconn.vimconnException as e:
+        #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
+        raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item, name, str(e)), e.http_code)
+
+    return "{} {} {} deleted".format(item[:-1], item_id,item_name)
+
+
+def vim_action_create(mydb, tenant_id, datacenter, item, descriptor):
+    #get datacenter info
+    logger.debug("vim_action_create descriptor %s", str(descriptor))
+    if tenant_id == "any":
+        tenant_id=None
+    datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
+    try:
+        if item=="networks":
+            net = descriptor["network"]
+            net_name = net.pop("name")
+            net_type = net.pop("type", "bridge")
+            net_public = net.pop("shared", False)
+            net_ipprofile = net.pop("ip_profile", None)
+            net_vlan = net.pop("vlan", None)
+            content = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, vlan=net_vlan) #, **net)
+        elif item=="tenants":
+            tenant = descriptor["tenant"]
+            content = myvim.new_tenant(tenant["name"], tenant.get("description"))
+        else:
+            raise NfvoException(item + "?", HTTP_Method_Not_Allowed)
+    except vimconn.vimconnException as e:
+        raise NfvoException("Not possible to create {} at VIM: {}".format(item, str(e)), e.http_code)
+
+    return vim_action_get(mydb, tenant_id, datacenter, item, content)
diff --git a/osm_ro/nfvo_db.py b/osm_ro/nfvo_db.py
new file mode 100644 (file)
index 0000000..b5ec9a0
--- /dev/null
@@ -0,0 +1,1052 @@
+# -*- 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
+##
+
+'''
+NFVO DB engine. It implements all the methods to interact with the Openmano Database
+'''
+__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
+__date__ ="$28-aug-2014 10:05:01$"
+
+import db_base
+import MySQLdb as mdb
+import json
+import yaml
+import time
+#import sys, os
+
+tables_with_createdat_field=["datacenters","instance_nets","instance_scenarios","instance_vms","instance_vnfs",
+                           "interfaces","nets","nfvo_tenants","scenarios","sce_interfaces","sce_nets",
+                           "sce_vnfs","tenants_datacenters","datacenter_tenants","vms","vnfs", "datacenter_nets"]
+
+class nfvo_db(db_base.db_base):
+    def __init__(self, host=None, user=None, passwd=None, database=None, log_name='openmano.db', log_level=None):
+        db_base.db_base.__init__(self, host, user, passwd, database, log_name, log_level)
+        db_base.db_base.tables_with_created_field=tables_with_createdat_field
+        return
+
+    def new_vnf_as_a_whole(self,nfvo_tenant,vnf_name,vnf_descriptor,VNFCDict):
+        self.logger.debug("Adding new vnf to the NFVO database")
+        tries = 2
+        while tries:
+            created_time = time.time()
+            try:
+                with self.con:
+            
+                    myVNFDict = {}
+                    myVNFDict["name"] = vnf_name
+                    myVNFDict["descriptor"] = vnf_descriptor['vnf'].get('descriptor')
+                    myVNFDict["public"] = vnf_descriptor['vnf'].get('public', "false")
+                    myVNFDict["description"] = vnf_descriptor['vnf']['description']
+                    myVNFDict["class"] = vnf_descriptor['vnf'].get('class',"MISC")
+                    myVNFDict["tenant_id"] = vnf_descriptor['vnf'].get("tenant_id")
+                    
+                    vnf_id = self._new_row_internal('vnfs', myVNFDict, add_uuid=True, root_uuid=None, created_time=created_time)
+                    #print "Adding new vms to the NFVO database"
+                    #For each vm, we must create the appropriate vm in the NFVO database.
+                    vmDict = {}
+                    for _,vm in VNFCDict.iteritems():
+                        #This code could make the name of the vms grow and grow.
+                        #If we agree to follow this convention, we should check with a regex that the vnfc name is not including yet the vnf name  
+                        #vm['name'] = "%s-%s" % (vnf_name,vm['name'])
+                        #print "VM name: %s. Description: %s" % (vm['name'], vm['description'])
+                        vm["vnf_id"] = vnf_id
+                        created_time += 0.00001
+                        vm_id = self._new_row_internal('vms', vm, add_uuid=True, root_uuid=vnf_id, created_time=created_time) 
+                        #print "Internal vm id in NFVO DB: %s" % vm_id
+                        vmDict[vm['name']] = vm_id
+                
+                    #Collect the bridge interfaces of each VM/VNFC under the 'bridge-ifaces' field
+                    bridgeInterfacesDict = {}
+                    for vm in vnf_descriptor['vnf']['VNFC']:
+                        if 'bridge-ifaces' in  vm:
+                            bridgeInterfacesDict[vm['name']] = {}
+                            for bridgeiface in vm['bridge-ifaces']:
+                                created_time += 0.00001
+                                if 'port-security' in bridgeiface:
+                                    bridgeiface['port_security'] = bridgeiface.pop('port-security')
+                                if 'floating-ip' in bridgeiface:
+                                    bridgeiface['floating_ip'] = bridgeiface.pop('floating-ip')
+                                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)
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['bw'] = bridgeiface.get('bandwidth', None)
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['model'] = bridgeiface.get('model', None)
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['port_security'] = \
+                                    int(bridgeiface.get('port_security', True))
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['floating_ip'] = \
+                                    int(bridgeiface.get('floating_ip', False))
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['created_time'] = created_time
+
+                    # Collect the data interfaces of each VM/VNFC under the 'numas' field
+                    dataifacesDict = {}
+                    for vm in vnf_descriptor['vnf']['VNFC']:
+                        dataifacesDict[vm['name']] = {}
+                        for numa in vm.get('numas', []):
+                            for dataiface in numa.get('interfaces', []):
+                                created_time += 0.00001
+                                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']
+                                dataifacesDict[vm['name']][dataiface['name']]['model'] = "PF" if dataiface[
+                                                                                                     'dedicated'] == "yes" else (
+                                "VF" if dataiface['dedicated'] == "no" else "VFnotShared")
+                                dataifacesDict[vm['name']][dataiface['name']]['created_time'] = created_time
+
+                    #For each internal connection, we add it to the interfaceDict and we  create the appropriate net in the NFVO database.
+                    #print "Adding new nets (VNF internal nets) to the NFVO database (if any)"
+                    internalconnList = []
+                    if 'internal-connections' in vnf_descriptor['vnf']:
+                        for net in vnf_descriptor['vnf']['internal-connections']:
+                            #print "Net name: %s. Description: %s" % (net['name'], net['description'])
+                            
+                            myNetDict = {}
+                            myNetDict["name"] = net['name']
+                            myNetDict["description"] = net['description']
+                            myNetDict["type"] = net['type']
+                            myNetDict["vnf_id"] = vnf_id
+                            
+                            created_time += 0.00001
+                            net_id = self._new_row_internal('nets', myNetDict, add_uuid=True, root_uuid=vnf_id, created_time=created_time)
+                                
+                            for element in net['elements']:
+                                ifaceItem = {}
+                                #ifaceItem["internal_name"] = "%s-%s-%s" % (net['name'],element['VNFC'], element['local_iface_name'])  
+                                ifaceItem["internal_name"] = element['local_iface_name']
+                                #ifaceItem["vm_id"] = vmDict["%s-%s" % (vnf_name,element['VNFC'])]
+                                ifaceItem["vm_id"] = vmDict[element['VNFC']]
+                                ifaceItem["net_id"] = net_id
+                                ifaceItem["type"] = net['type']
+                                if ifaceItem ["type"] == "data":
+                                    dataiface = dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]
+                                    ifaceItem["vpci"] =  dataiface['vpci']
+                                    ifaceItem["bw"] =    dataiface['bw']
+                                    ifaceItem["model"] = dataiface['model']
+                                    created_time_iface = dataiface['created_time']
+                                else:
+                                    bridgeiface =  bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]
+                                    ifaceItem["vpci"]          = bridgeiface['vpci']
+                                    ifaceItem["mac"]           = bridgeiface['mac']
+                                    ifaceItem["bw"]            = bridgeiface['bw']
+                                    ifaceItem["model"]         = bridgeiface['model']
+                                    ifaceItem["port_security"] = bridgeiface['port_security']
+                                    ifaceItem["floating_ip"]   = bridgeiface['floating_ip']
+                                    created_time_iface = bridgeiface['created_time']
+                                internalconnList.append(ifaceItem)
+                            #print "Internal net id in NFVO DB: %s" % net_id
+                    
+                    #print "Adding internal interfaces to the NFVO database (if any)"
+                    for iface in internalconnList:
+                        #print "Iface name: %s" % iface['internal_name']
+                        iface_id = self._new_row_internal('interfaces', iface, add_uuid=True, root_uuid=vnf_id, created_time = created_time_iface)
+                        #print "Iface id in NFVO DB: %s" % iface_id
+                    
+                    #print "Adding external interfaces to the NFVO database"
+                    for iface in vnf_descriptor['vnf']['external-connections']:
+                        myIfaceDict = {}
+                        #myIfaceDict["internal_name"] = "%s-%s-%s" % (vnf_name,iface['VNFC'], iface['local_iface_name'])  
+                        myIfaceDict["internal_name"] = iface['local_iface_name']
+                        #myIfaceDict["vm_id"] = vmDict["%s-%s" % (vnf_name,iface['VNFC'])]
+                        myIfaceDict["vm_id"] = vmDict[iface['VNFC']]
+                        myIfaceDict["external_name"] = iface['name']
+                        myIfaceDict["type"] = iface['type']
+                        if iface["type"] == "data":
+                            dataiface = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]
+                            myIfaceDict["vpci"]         = dataiface['vpci']
+                            myIfaceDict["bw"]           = dataiface['bw']
+                            myIfaceDict["model"]        = dataiface['model']
+                            created_time_iface = dataiface['created_time']
+                        else:
+                            bridgeiface = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]
+                            myIfaceDict["vpci"]         = bridgeiface['vpci']
+                            myIfaceDict["bw"]           = bridgeiface['bw']
+                            myIfaceDict["model"]        = bridgeiface['model']
+                            myIfaceDict["mac"]          = bridgeiface['mac']
+                            myIfaceDict["port_security"]= bridgeiface['port_security']
+                            myIfaceDict["floating_ip"]  = bridgeiface['floating_ip']
+                            created_time_iface = bridgeiface['created_time']
+                        #print "Iface name: %s" % iface['name']
+                        iface_id = self._new_row_internal('interfaces', myIfaceDict, add_uuid=True, root_uuid=vnf_id, created_time = created_time_iface)
+                        #print "Iface id in NFVO DB: %s" % iface_id
+                    
+                    return vnf_id
+                
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+        
+    def new_vnf_as_a_whole2(self,nfvo_tenant,vnf_name,vnf_descriptor,VNFCDict):
+        self.logger.debug("Adding new vnf to the NFVO database")
+        tries = 2
+        while tries:
+            created_time = time.time()
+            try:
+                with self.con:
+                     
+                    myVNFDict = {}
+                    myVNFDict["name"] = vnf_name
+                    myVNFDict["descriptor"] = vnf_descriptor['vnf'].get('descriptor')
+                    myVNFDict["public"] = vnf_descriptor['vnf'].get('public', "false")
+                    myVNFDict["description"] = vnf_descriptor['vnf']['description']
+                    myVNFDict["class"] = vnf_descriptor['vnf'].get('class',"MISC")
+                    myVNFDict["tenant_id"] = vnf_descriptor['vnf'].get("tenant_id")
+                    
+                    vnf_id = self._new_row_internal('vnfs', myVNFDict, add_uuid=True, root_uuid=None, created_time=created_time)
+                    #print "Adding new vms to the NFVO database"
+                    #For each vm, we must create the appropriate vm in the NFVO database.
+                    vmDict = {}
+                    for _,vm in VNFCDict.iteritems():
+                        #This code could make the name of the vms grow and grow.
+                        #If we agree to follow this convention, we should check with a regex that the vnfc name is not including yet the vnf name  
+                        #vm['name'] = "%s-%s" % (vnf_name,vm['name'])
+                        #print "VM name: %s. Description: %s" % (vm['name'], vm['description'])
+                        vm["vnf_id"] = vnf_id
+                        created_time += 0.00001
+                        vm_id = self._new_row_internal('vms', vm, add_uuid=True, root_uuid=vnf_id, created_time=created_time) 
+                        #print "Internal vm id in NFVO DB: %s" % vm_id
+                        vmDict[vm['name']] = vm_id
+                     
+                    #Collect the bridge interfaces of each VM/VNFC under the 'bridge-ifaces' field
+                    bridgeInterfacesDict = {}
+                    for vm in vnf_descriptor['vnf']['VNFC']:
+                        if 'bridge-ifaces' in  vm:
+                            bridgeInterfacesDict[vm['name']] = {}
+                            for bridgeiface in vm['bridge-ifaces']:
+                                created_time += 0.00001
+                                db_base._convert_bandwidth(bridgeiface, logger=self.logger)
+                                if 'port-security' in bridgeiface:
+                                    bridgeiface['port_security'] = bridgeiface.pop('port-security')
+                                if 'floating-ip' in bridgeiface:
+                                    bridgeiface['floating_ip'] = bridgeiface.pop('floating-ip')
+                                ifaceDict = {}
+                                ifaceDict['vpci'] = bridgeiface.get('vpci',None)
+                                ifaceDict['mac'] = bridgeiface.get('mac_address',None)
+                                ifaceDict['bw'] = bridgeiface.get('bandwidth', None)
+                                ifaceDict['model'] = bridgeiface.get('model', None)
+                                ifaceDict['port_security'] = int(bridgeiface.get('port_security', True))
+                                ifaceDict['floating_ip'] = int(bridgeiface.get('floating_ip', False))
+                                ifaceDict['created_time'] = created_time
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']] = ifaceDict
+
+                    # Collect the data interfaces of each VM/VNFC under the 'numas' field
+                    dataifacesDict = {}
+                    for vm in vnf_descriptor['vnf']['VNFC']:
+                        dataifacesDict[vm['name']] = {}
+                        for numa in vm.get('numas', []):
+                            for dataiface in numa.get('interfaces', []):
+                                created_time += 0.00001
+                                db_base._convert_bandwidth(dataiface, logger=self.logger)
+                                ifaceDict = {}
+                                ifaceDict['vpci'] = dataiface['vpci']
+                                ifaceDict['bw'] = dataiface['bandwidth']
+                                ifaceDict['model'] = "PF" if dataiface['dedicated'] == "yes" else \
+                                    ("VF" if dataiface['dedicated'] == "no" else "VFnotShared")
+                                ifaceDict['created_time'] = created_time
+                                dataifacesDict[vm['name']][dataiface['name']] = ifaceDict
+
+                    #For each internal connection, we add it to the interfaceDict and we  create the appropriate net in the NFVO database.
+                    #print "Adding new nets (VNF internal nets) to the NFVO database (if any)"
+                    if 'internal-connections' in vnf_descriptor['vnf']:
+                        for net in vnf_descriptor['vnf']['internal-connections']:
+                            #print "Net name: %s. Description: %s" % (net['name'], net['description'])
+                            
+                            myNetDict = {}
+                            myNetDict["name"] = net['name']
+                            myNetDict["description"] = net['description']
+                            if (net["implementation"] == "overlay"):
+                                net["type"] = "bridge"
+                                #It should give an error if the type is e-line. For the moment, we consider it as a bridge 
+                            elif (net["implementation"] == "underlay"):
+                                if (net["type"] == "e-line"):
+                                    net["type"] = "ptp"
+                                elif (net["type"] == "e-lan"):
+                                    net["type"] = "data"
+                            net.pop("implementation")
+                            myNetDict["type"] = net['type']
+                            myNetDict["vnf_id"] = vnf_id
+                            
+                            created_time += 0.00001
+                            net_id = self._new_row_internal('nets', myNetDict, add_uuid=True, root_uuid=vnf_id, created_time=created_time)
+                            
+                            if "ip-profile" in net:
+                                ip_profile = net["ip-profile"]
+                                myIPProfileDict = {}
+                                myIPProfileDict["net_id"] = net_id
+                                myIPProfileDict["ip_version"] = ip_profile.get('ip-version',"IPv4")
+                                myIPProfileDict["subnet_address"] = ip_profile.get('subnet-address',None)
+                                myIPProfileDict["gateway_address"] = ip_profile.get('gateway-address',None)
+                                myIPProfileDict["dns_address"] = ip_profile.get('dns-address',None)
+                                if ("dhcp" in ip_profile):
+                                    myIPProfileDict["dhcp_enabled"] = ip_profile["dhcp"].get('enabled',"true")
+                                    myIPProfileDict["dhcp_start_address"] = ip_profile["dhcp"].get('start-address',None)
+                                    myIPProfileDict["dhcp_count"] = ip_profile["dhcp"].get('count',None)
+                                
+                                created_time += 0.00001
+                                ip_profile_id = self._new_row_internal('ip_profiles', myIPProfileDict)
+                                
+                            for element in net['elements']:
+                                ifaceItem = {}
+                                #ifaceItem["internal_name"] = "%s-%s-%s" % (net['name'],element['VNFC'], element['local_iface_name'])  
+                                ifaceItem["internal_name"] = element['local_iface_name']
+                                #ifaceItem["vm_id"] = vmDict["%s-%s" % (vnf_name,element['VNFC'])]
+                                ifaceItem["vm_id"] = vmDict[element['VNFC']]
+                                ifaceItem["net_id"] = net_id
+                                ifaceItem["type"] = net['type']
+                                ifaceItem["ip_address"] = element.get('ip_address',None)
+                                if ifaceItem ["type"] == "data":
+                                    ifaceDict = dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]
+                                    ifaceItem["vpci"] =  ifaceDict['vpci']
+                                    ifaceItem["bw"] =    ifaceDict['bw']
+                                    ifaceItem["model"] = ifaceDict['model']
+                                else:
+                                    ifaceDict = bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]
+                                    ifaceItem["vpci"] =  ifaceDict['vpci']
+                                    ifaceItem["mac"] =  ifaceDict['mac']
+                                    ifaceItem["bw"] =    ifaceDict['bw']
+                                    ifaceItem["model"] = ifaceDict['model']
+                                    ifaceItem["port_security"] = ifaceDict['port_security']
+                                    ifaceItem["floating_ip"] = ifaceDict['floating_ip']
+                                created_time_iface = ifaceDict["created_time"]
+                                #print "Iface name: %s" % iface['internal_name']
+                                iface_id = self._new_row_internal('interfaces', ifaceItem, add_uuid=True, root_uuid=vnf_id, created_time=created_time_iface)
+                                #print "Iface id in NFVO DB: %s" % iface_id
+                    
+                    #print "Adding external interfaces to the NFVO database"
+                    for iface in vnf_descriptor['vnf']['external-connections']:
+                        myIfaceDict = {}
+                        #myIfaceDict["internal_name"] = "%s-%s-%s" % (vnf_name,iface['VNFC'], iface['local_iface_name'])  
+                        myIfaceDict["internal_name"] = iface['local_iface_name']
+                        #myIfaceDict["vm_id"] = vmDict["%s-%s" % (vnf_name,iface['VNFC'])]
+                        myIfaceDict["vm_id"] = vmDict[iface['VNFC']]
+                        myIfaceDict["external_name"] = iface['name']
+                        myIfaceDict["type"] = iface['type']
+                        if iface["type"] == "data":
+                            myIfaceDict["vpci"]  = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['vpci']
+                            myIfaceDict["bw"]    = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['bw']
+                            myIfaceDict["model"] = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['model']
+                            created_time_iface = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['created_time']
+                        else:
+                            myIfaceDict["vpci"]  = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['vpci']
+                            myIfaceDict["bw"]    = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['bw']
+                            myIfaceDict["model"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['model']
+                            myIfaceDict["mac"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['mac']
+                            myIfaceDict["port_security"] = \
+                                bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['port_security']
+                            myIfaceDict["floating_ip"] = \
+                                bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['floating_ip']
+                            created_time_iface = bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['created_time']
+                        #print "Iface name: %s" % iface['name']
+                        iface_id = self._new_row_internal('interfaces', myIfaceDict, add_uuid=True, root_uuid=vnf_id, created_time=created_time_iface)
+                        #print "Iface id in NFVO DB: %s" % iface_id
+                    
+                    return vnf_id
+                
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+#             except KeyError as e2:
+#                 exc_type, exc_obj, exc_tb = sys.exc_info()
+#                 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
+#                 self.logger.debug("Exception type: %s; Filename: %s; Line number: %s", exc_type, fname, exc_tb.tb_lineno)
+#                 raise KeyError
+            tries -= 1
+
+    def new_scenario(self, scenario_dict):
+        tries = 2
+        while tries:
+            created_time = time.time()
+            try:
+                with self.con:
+                    self.cur = self.con.cursor()
+                    tenant_id = scenario_dict.get('tenant_id')
+                    #scenario
+                    INSERT_={'tenant_id': tenant_id,
+                             'name': scenario_dict['name'],
+                             'description': scenario_dict['description'],
+                             'public': scenario_dict.get('public', "false")}
+                    
+                    scenario_uuid =  self._new_row_internal('scenarios', INSERT_, add_uuid=True, root_uuid=None, created_time=created_time)
+                    #sce_nets
+                    for net in scenario_dict['nets'].values():
+                        net_dict={'scenario_id': scenario_uuid}
+                        net_dict["name"] = net["name"]
+                        net_dict["type"] = net["type"]
+                        net_dict["description"] = net.get("description")
+                        net_dict["external"] = net.get("external", False)
+                        if "graph" in net:
+                            #net["graph"]=yaml.safe_dump(net["graph"],default_flow_style=True,width=256)
+                            #TODO, must be json because of the GUI, change to yaml
+                            net_dict["graph"]=json.dumps(net["graph"])
+                        created_time += 0.00001
+                        net_uuid =  self._new_row_internal('sce_nets', net_dict, add_uuid=True, root_uuid=scenario_uuid, created_time=created_time)
+                        net['uuid']=net_uuid
+
+                        if net.get("ip-profile"):
+                            ip_profile = net["ip-profile"]
+                            myIPProfileDict = {
+                                "sce_net_id": net_uuid,
+                                "ip_version": ip_profile.get('ip-version', "IPv4"),
+                                "subnet_address": ip_profile.get('subnet-address'),
+                                "gateway_address": ip_profile.get('gateway-address'),
+                                "dns_address": ip_profile.get('dns-address')}
+                            if "dhcp" in ip_profile:
+                                myIPProfileDict["dhcp_enabled"] = ip_profile["dhcp"].get('enabled', "true")
+                                myIPProfileDict["dhcp_start_address"] = ip_profile["dhcp"].get('start-address')
+                                myIPProfileDict["dhcp_count"] = ip_profile["dhcp"].get('count')
+                            self._new_row_internal('ip_profiles', myIPProfileDict)
+
+                    # sce_vnfs
+                    for k, vnf in scenario_dict['vnfs'].items():
+                        INSERT_ = {'scenario_id': scenario_uuid,
+                                   'name': k,
+                                   'vnf_id': vnf['uuid'],
+                                   # 'description': scenario_dict['name']
+                                   'description': vnf['description']}
+                        if "graph" in vnf:
+                            #I NSERT_["graph"]=yaml.safe_dump(vnf["graph"],default_flow_style=True,width=256)
+                            # TODO, must be json because of the GUI, change to yaml
+                            INSERT_["graph"] = json.dumps(vnf["graph"])
+                        created_time += 0.00001
+                        scn_vnf_uuid = self._new_row_internal('sce_vnfs', INSERT_, add_uuid=True,
+                                                              root_uuid=scenario_uuid, created_time=created_time)
+                        vnf['scn_vnf_uuid']=scn_vnf_uuid
+                        # sce_interfaces
+                        for iface in vnf['ifaces'].values():
+                            # print 'iface', iface
+                            if 'net_key' not in iface:
+                                continue
+                            iface['net_id'] = scenario_dict['nets'][ iface['net_key'] ]['uuid']
+                            INSERT_={'sce_vnf_id': scn_vnf_uuid,
+                                     'sce_net_id': iface['net_id'],
+                                     'interface_id':  iface['uuid'],
+                                     'ip_address': iface.get('ip_address')}
+                            created_time += 0.00001
+                            iface_uuid = self._new_row_internal('sce_interfaces', INSERT_, add_uuid=True,
+                                                                 root_uuid=scenario_uuid, created_time=created_time)
+                            
+                    return scenario_uuid
+                    
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+    def edit_scenario(self, scenario_dict):
+        tries = 2
+        while tries:
+            modified_time = time.time()
+            item_changed=0
+            try:
+                with self.con:
+                    self.cur = self.con.cursor()
+                    #check that scenario exist
+                    tenant_id = scenario_dict.get('tenant_id')
+                    scenario_uuid = scenario_dict['uuid']
+                    
+                    where_text = "uuid='{}'".format(scenario_uuid)
+                    if not tenant_id and tenant_id != "any":
+                        where_text += " AND (tenant_id='{}' OR public='True')".format(tenant_id)
+                    cmd = "SELECT * FROM scenarios WHERE "+ where_text
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    self.cur.fetchall()
+                    if self.cur.rowcount==0:
+                        raise db_base.db_base_Exception("No scenario found with this criteria " + where_text, db_base.HTTP_Bad_Request)
+                    elif self.cur.rowcount>1:
+                        raise db_base.db_base_Exception("More than one scenario found with this criteria " + where_text, db_base.HTTP_Bad_Request)
+
+                    #scenario
+                    nodes = {}
+                    topology = scenario_dict.pop("topology", None)
+                    if topology != None and "nodes" in topology:
+                        nodes = topology.get("nodes",{})
+                    UPDATE_ = {}
+                    if "name" in scenario_dict:        UPDATE_["name"] = scenario_dict["name"]
+                    if "description" in scenario_dict: UPDATE_["description"] = scenario_dict["description"]
+                    if len(UPDATE_)>0:
+                        WHERE_={'tenant_id': tenant_id, 'uuid': scenario_uuid}
+                        item_changed += self._update_rows('scenarios', UPDATE_, WHERE_, modified_time=modified_time)
+                    #sce_nets
+                    for node_id, node in nodes.items():
+                        if "graph" in node:
+                            #node["graph"] = yaml.safe_dump(node["graph"],default_flow_style=True,width=256)
+                            #TODO, must be json because of the GUI, change to yaml
+                            node["graph"] = json.dumps(node["graph"])
+                        WHERE_={'scenario_id': scenario_uuid, 'uuid': node_id}
+                        #Try to change at sce_nets(version 0 API backward compatibility and sce_vnfs)
+                        item_changed += self._update_rows('sce_nets', node, WHERE_)
+                        item_changed += self._update_rows('sce_vnfs', node, WHERE_, modified_time=modified_time)
+                    return item_changed
+                    
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+#     def get_instance_scenario(self, instance_scenario_id, tenant_id=None):
+#         '''Obtain the scenario instance information, filtering by one or serveral of the tenant, uuid or name
+#         instance_scenario_id is the uuid or the name if it is not a valid uuid format
+#         Only one scenario isntance must mutch the filtering or an error is returned
+#         ''' 
+#         print "1******************************************************************"
+#         try:
+#             with self.con:
+#                 self.cur = self.con.cursor(mdb.cursors.DictCursor)
+#                 #scenario table
+#                 where_list=[]
+#                 if tenant_id is not None: where_list.append( "tenant_id='" + tenant_id +"'" )
+#                 if db_base._check_valid_uuid(instance_scenario_id):
+#                     where_list.append( "uuid='" + instance_scenario_id +"'" )
+#                 else:
+#                     where_list.append( "name='" + instance_scenario_id +"'" )
+#                 where_text = " AND ".join(where_list)
+#                 self.cur.execute("SELECT * FROM instance_scenarios WHERE "+ where_text)
+#                 rows = self.cur.fetchall()
+#                 if self.cur.rowcount==0:
+#                     return -HTTP_Bad_Request, "No scenario instance found with this criteria " + where_text
+#                 elif self.cur.rowcount>1:
+#                     return -HTTP_Bad_Request, "More than one scenario instance found with this criteria " + where_text
+#                 instance_scenario_dict = rows[0]
+#                 
+#                 #instance_vnfs
+#                 self.cur.execute("SELECT uuid,vnf_id FROM instance_vnfs WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
+#                 instance_scenario_dict['instance_vnfs'] = self.cur.fetchall()
+#                 for vnf in instance_scenario_dict['instance_vnfs']:
+#                     #instance_vms
+#                     self.cur.execute("SELECT uuid, vim_vm_id "+
+#                                 "FROM instance_vms  "+
+#                                 "WHERE instance_vnf_id='" + vnf['uuid'] +"'"  
+#                                 )
+#                     vnf['instance_vms'] = self.cur.fetchall()
+#                 #instance_nets
+#                 self.cur.execute("SELECT uuid, vim_net_id FROM instance_nets WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
+#                 instance_scenario_dict['instance_nets'] = self.cur.fetchall()
+#                 
+#                 #instance_interfaces
+#                 self.cur.execute("SELECT uuid, vim_interface_id, instance_vm_id, instance_net_id FROM instance_interfaces WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
+#                 instance_scenario_dict['instance_interfaces'] = self.cur.fetchall()
+#                 
+#                 db_base._convert_datetime2str(instance_scenario_dict)
+#                 db_base._convert_str2boolean(instance_scenario_dict, ('public','shared','external') )
+#                 print "2******************************************************************"
+#                 return 1, instance_scenario_dict
+#         except (mdb.Error, AttributeError) as e:
+#             print "nfvo_db.get_instance_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
+#             return self._format_error(e)
+
+    def get_scenario(self, scenario_id, tenant_id=None, datacenter_id=None):
+        '''Obtain the scenario information, filtering by one or serveral of the tenant, uuid or name
+        scenario_id is the uuid or the name if it is not a valid uuid format
+        if datacenter_id is provided, it supply aditional vim_id fields with the matching vim uuid 
+        Only one scenario must mutch the filtering or an error is returned
+        ''' 
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
+                    where_text = "uuid='{}'".format(scenario_id)
+                    if not tenant_id and tenant_id != "any":
+                        where_text += " AND (tenant_id='{}' OR public='True')".format(tenant_id)
+                    cmd = "SELECT * FROM scenarios WHERE " + where_text
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    rows = self.cur.fetchall()
+                    if self.cur.rowcount==0:
+                        raise db_base.db_base_Exception("No scenario found with this criteria " + where_text, db_base.HTTP_Bad_Request)
+                    elif self.cur.rowcount>1:
+                        raise db_base.db_base_Exception("More than one scenario found with this criteria " + where_text, db_base.HTTP_Bad_Request)
+                    scenario_dict = rows[0]
+                    if scenario_dict["cloud_config"]:
+                        scenario_dict["cloud-config"] = yaml.load(scenario_dict["cloud_config"])
+                    del scenario_dict["cloud_config"]
+                    #sce_vnfs
+                    cmd = "SELECT uuid,name,vnf_id,description FROM sce_vnfs WHERE scenario_id='{}' ORDER BY created_at".format(scenario_dict['uuid'])
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    scenario_dict['vnfs'] = self.cur.fetchall()
+                    for vnf in scenario_dict['vnfs']:
+                        #sce_interfaces
+                        cmd = "SELECT scei.uuid,scei.sce_net_id,scei.interface_id,i.external_name,scei.ip_address FROM sce_interfaces as scei join interfaces as i on scei.interface_id=i.uuid WHERE scei.sce_vnf_id='{}' ORDER BY scei.created_at".format(vnf['uuid'])
+                        self.logger.debug(cmd)
+                        self.cur.execute(cmd)
+                        vnf['interfaces'] = self.cur.fetchall()
+                        #vms
+                        cmd = "SELECT vms.uuid as uuid, flavor_id, image_id, vms.name as name, vms.description as description, vms.boot_data as boot_data " \
+                                " FROM vnfs join vms on vnfs.uuid=vms.vnf_id " \
+                                " WHERE vnfs.uuid='" + vnf['vnf_id'] +"'"  \
+                                " ORDER BY vms.created_at"
+                        self.logger.debug(cmd)
+                        self.cur.execute(cmd)
+                        vnf['vms'] = self.cur.fetchall()
+                        for vm in vnf['vms']:
+                            if vm["boot_data"]:
+                                vm["boot_data"] = yaml.safe_load(vm["boot_data"])
+                            else:
+                                del vm["boot_data"]
+                            if datacenter_id!=None:
+                                cmd = "SELECT vim_id FROM datacenters_images WHERE image_id='{}' AND datacenter_id='{}'".format(vm['image_id'],datacenter_id)
+                                self.logger.debug(cmd)
+                                self.cur.execute(cmd) 
+                                if self.cur.rowcount==1:
+                                    vim_image_dict = self.cur.fetchone()
+                                    vm['vim_image_id']=vim_image_dict['vim_id']
+                                cmd = "SELECT vim_id FROM datacenters_flavors WHERE flavor_id='{}' AND datacenter_id='{}'".format(vm['flavor_id'],datacenter_id)
+                                self.logger.debug(cmd)
+                                self.cur.execute(cmd) 
+                                if self.cur.rowcount==1:
+                                    vim_flavor_dict = self.cur.fetchone()
+                                    vm['vim_flavor_id']=vim_flavor_dict['vim_id']
+                                
+                            #interfaces
+                            cmd = "SELECT uuid,internal_name,external_name,net_id,type,vpci,mac,bw,model,ip_address," \
+                                  "floating_ip, port_security" \
+                                    " FROM interfaces" \
+                                    " WHERE vm_id='{}'" \
+                                    " ORDER BY created_at".format(vm['uuid'])
+                            self.logger.debug(cmd)
+                            self.cur.execute(cmd)
+                            vm['interfaces'] = self.cur.fetchall()
+                            for index in range(0,len(vm['interfaces'])):
+                                vm['interfaces'][index]['port-security'] = vm['interfaces'][index].pop("port_security")
+                                vm['interfaces'][index]['floating-ip'] = vm['interfaces'][index].pop("floating_ip")
+                        #nets    every net of a vms
+                        cmd = "SELECT uuid,name,type,description FROM nets WHERE vnf_id='{}'".format(vnf['vnf_id'])  
+                        self.logger.debug(cmd)
+                        self.cur.execute(cmd)
+                        vnf['nets'] = self.cur.fetchall()
+                        for vnf_net in vnf['nets']:
+                            SELECT_ = "ip_version,subnet_address,gateway_address,dns_address,dhcp_enabled,dhcp_start_address,dhcp_count"
+                            cmd = "SELECT {} FROM ip_profiles WHERE net_id='{}'".format(SELECT_,vnf_net['uuid'])  
+                            self.logger.debug(cmd)
+                            self.cur.execute(cmd)
+                            ipprofiles = self.cur.fetchall()
+                            if self.cur.rowcount==1:
+                                vnf_net["ip_profile"] = ipprofiles[0]
+                            elif self.cur.rowcount>1:
+                                raise db_base.db_base_Exception("More than one ip-profile found with this criteria: net_id='{}'".format(vnf_net['uuid']), db_base.HTTP_Bad_Request)
+                            
+                    #sce_nets
+                    cmd = "SELECT uuid,name,type,external,description" \
+                          " FROM sce_nets  WHERE scenario_id='{}'" \
+                          " ORDER BY created_at ".format(scenario_dict['uuid'])
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    scenario_dict['nets'] = self.cur.fetchall()
+                    #datacenter_nets
+                    for net in scenario_dict['nets']:
+                        if str(net['external']) == 'false':
+                            SELECT_ = "ip_version,subnet_address,gateway_address,dns_address,dhcp_enabled,dhcp_start_address,dhcp_count"
+                            cmd = "SELECT {} FROM ip_profiles WHERE sce_net_id='{}'".format(SELECT_,net['uuid'])  
+                            self.logger.debug(cmd)
+                            self.cur.execute(cmd)
+                            ipprofiles = self.cur.fetchall()
+                            if self.cur.rowcount==1:
+                                net["ip_profile"] = ipprofiles[0]
+                            elif self.cur.rowcount>1:
+                                raise db_base.db_base_Exception("More than one ip-profile found with this criteria: sce_net_id='{}'".format(net['uuid']), db_base.HTTP_Bad_Request)
+                            continue
+                        WHERE_=" WHERE name='{}'".format(net['name'])
+                        if datacenter_id!=None:
+                            WHERE_ += " AND datacenter_id='{}'".format(datacenter_id)
+                        cmd = "SELECT vim_net_id FROM datacenter_nets" + WHERE_
+                        self.logger.debug(cmd)
+                        self.cur.execute(cmd) 
+                        d_net = self.cur.fetchone()
+                        if d_net==None or datacenter_id==None:
+                            #print "nfvo_db.get_scenario() WARNING external net %s not found"  % net['name']
+                            net['vim_id']=None
+                        else:
+                            net['vim_id']=d_net['vim_net_id']
+                    
+                    db_base._convert_datetime2str(scenario_dict)
+                    db_base._convert_str2boolean(scenario_dict, ('public','shared','external','port-security','floating-ip') )
+                    return scenario_dict
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+    def delete_scenario(self, scenario_id, tenant_id=None):
+        '''Deletes a scenario, filtering by one or several of the tenant, uuid or name
+        scenario_id is the uuid or the name if it is not a valid uuid format
+        Only one scenario must mutch the filtering or an error is returned
+        ''' 
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
+    
+                    #scenario table
+                    where_text = "uuid='{}'".format(scenario_id)
+                    if not tenant_id and tenant_id != "any":
+                        where_text += " AND (tenant_id='{}' OR public='True')".format(tenant_id)
+                    cmd = "SELECT * FROM scenarios WHERE "+ where_text
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    rows = self.cur.fetchall()
+                    if self.cur.rowcount==0:
+                        raise db_base.db_base_Exception("No scenario found where " + where_text, db_base.HTTP_Bad_Request)
+                    elif self.cur.rowcount>1:
+                        raise db_base.db_base_Exception("More than one scenario found where " + where_text, db_base.HTTP_Bad_Request)
+                    scenario_uuid = rows[0]["uuid"]
+                    scenario_name = rows[0]["name"]
+                    
+                    #sce_vnfs
+                    cmd = "DELETE FROM scenarios WHERE uuid='{}'".format(scenario_uuid)
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+    
+                    return scenario_uuid + " " + scenario_name
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries, "delete", "instances running")
+            tries -= 1
+
+    def new_instance_scenario_as_a_whole(self,tenant_id,instance_scenario_name,instance_scenario_description,scenarioDict):
+        tries = 2
+        while tries:
+            created_time = time.time()
+            try:
+                with self.con:
+                    self.cur = self.con.cursor()
+                    #instance_scenarios
+                    datacenter_id = scenarioDict['datacenter_id']
+                    INSERT_={'tenant_id': tenant_id,
+                        'datacenter_tenant_id': scenarioDict["datacenter2tenant"][datacenter_id],
+                        'name': instance_scenario_name,
+                        'description': instance_scenario_description,
+                        'scenario_id' : scenarioDict['uuid'],
+                        'datacenter_id': datacenter_id
+                    }
+                    if scenarioDict.get("cloud-config"):
+                        INSERT_["cloud_config"] = yaml.safe_dump(scenarioDict["cloud-config"], default_flow_style=True, width=256)
+
+                    instance_uuid = self._new_row_internal('instance_scenarios', INSERT_, add_uuid=True, root_uuid=None, created_time=created_time)
+                    
+                    net_scene2instance={}
+                    #instance_nets   #nets interVNF
+                    for net in scenarioDict['nets']:
+                        net_scene2instance[ net['uuid'] ] ={}
+                        datacenter_site_id = net.get('datacenter_id', datacenter_id)
+                        if not "vim_id_sites" in net:
+                            net["vim_id_sites"] ={datacenter_site_id: net['vim_id']}
+                            net["vim_id_sites"]["datacenter_site_id"] = {datacenter_site_id: net['vim_id']}
+                        sce_net_id = net.get("uuid")
+                        
+                        for datacenter_site_id,vim_id in net["vim_id_sites"].iteritems():
+                            INSERT_={'vim_net_id': vim_id, 'created': net.get('created', False), 'instance_scenario_id':instance_uuid } #,  'type': net['type']
+                            INSERT_['datacenter_id'] = datacenter_site_id 
+                            INSERT_['datacenter_tenant_id'] = scenarioDict["datacenter2tenant"][datacenter_site_id]
+                            if sce_net_id:
+                                INSERT_['sce_net_id'] = sce_net_id
+                            created_time += 0.00001
+                            instance_net_uuid =  self._new_row_internal('instance_nets', INSERT_, True, instance_uuid, created_time)
+                            net_scene2instance[ sce_net_id ][datacenter_site_id] = instance_net_uuid
+                            net['uuid'] = instance_net_uuid  #overwrite scnario uuid by instance uuid
+                        
+                        if 'ip_profile' in net:
+                            net['ip_profile']['net_id'] = None
+                            net['ip_profile']['sce_net_id'] = None
+                            net['ip_profile']['instance_net_id'] = instance_net_uuid
+                            created_time += 0.00001
+                            ip_profile_id = self._new_row_internal('ip_profiles', net['ip_profile'])
+                    
+                    #instance_vnfs
+                    for vnf in scenarioDict['vnfs']:
+                        datacenter_site_id = vnf.get('datacenter_id', datacenter_id)
+                        INSERT_={'instance_scenario_id': instance_uuid,  'vnf_id': vnf['vnf_id']  }
+                        INSERT_['datacenter_id'] = datacenter_site_id 
+                        INSERT_['datacenter_tenant_id'] = scenarioDict["datacenter2tenant"][datacenter_site_id]
+                        if vnf.get("uuid"):
+                            INSERT_['sce_vnf_id'] = vnf['uuid']
+                        created_time += 0.00001
+                        instance_vnf_uuid =  self._new_row_internal('instance_vnfs', INSERT_, True, instance_uuid, created_time)
+                        vnf['uuid'] = instance_vnf_uuid  #overwrite scnario uuid by instance uuid
+                        
+                        #instance_nets   #nets intraVNF
+                        for net in vnf['nets']:
+                            net_scene2instance[ net['uuid'] ] = {}
+                            INSERT_={'vim_net_id': net['vim_id'], 'created': net.get('created', False), 'instance_scenario_id':instance_uuid  } #,  'type': net['type']
+                            INSERT_['datacenter_id'] = net.get('datacenter_id', datacenter_site_id) 
+                            INSERT_['datacenter_tenant_id'] = scenarioDict["datacenter2tenant"][datacenter_id]
+                            if net.get("uuid"):
+                                INSERT_['net_id'] = net['uuid']
+                            created_time += 0.00001
+                            instance_net_uuid =  self._new_row_internal('instance_nets', INSERT_, True, instance_uuid, created_time)
+                            net_scene2instance[ net['uuid'] ][datacenter_site_id] = instance_net_uuid
+                            net['uuid'] = instance_net_uuid  #overwrite scnario uuid by instance uuid
+                            
+                            if 'ip_profile' in net:
+                                net['ip_profile']['net_id'] = None
+                                net['ip_profile']['sce_net_id'] = None
+                                net['ip_profile']['instance_net_id'] = instance_net_uuid
+                                created_time += 0.00001
+                                ip_profile_id = self._new_row_internal('ip_profiles', net['ip_profile'])
+
+                        #instance_vms
+                        for vm in vnf['vms']:
+                            INSERT_={'instance_vnf_id': instance_vnf_uuid,  'vm_id': vm['uuid'], 'vim_vm_id': vm['vim_id']  }
+                            created_time += 0.00001
+                            instance_vm_uuid =  self._new_row_internal('instance_vms', INSERT_, True, instance_uuid, created_time)
+                            vm['uuid'] = instance_vm_uuid  #overwrite scnario uuid by instance uuid
+                            
+                            #instance_interfaces
+                            for interface in vm['interfaces']:
+                                net_id = interface.get('net_id', None)
+                                if net_id is None:
+                                    #check if is connected to a inter VNFs net
+                                    for iface in vnf['interfaces']:
+                                        if iface['interface_id'] == interface['uuid']:
+                                            if 'ip_address' in iface:
+                                                interface['ip_address'] = iface['ip_address']
+                                            net_id = iface.get('sce_net_id', None)
+                                            break
+                                if net_id is None:
+                                    continue
+                                interface_type='external' if interface['external_name'] is not None else 'internal'
+                                INSERT_={'instance_vm_id': instance_vm_uuid,  'instance_net_id': net_scene2instance[net_id][datacenter_site_id],
+                                    'interface_id': interface['uuid'], 'vim_interface_id': interface.get('vim_id'), 'type':  interface_type,
+                                    'ip_address': interface.get('ip_address'), 'floating_ip': int(interface.get('floating-ip',False)),
+                                    'port_security': int(interface.get('port-security',True))}
+                                #created_time += 0.00001
+                                interface_uuid =  self._new_row_internal('instance_interfaces', INSERT_, True, instance_uuid) #, created_time)
+                                interface['uuid'] = interface_uuid  #overwrite scnario uuid by instance uuid
+                return instance_uuid
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+    def get_instance_scenario(self, instance_id, tenant_id=None, verbose=False):
+        '''Obtain the instance information, filtering by one or several of the tenant, uuid or name
+        instance_id is the uuid or the name if it is not a valid uuid format
+        Only one instance must mutch the filtering or an error is returned
+        ''' 
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
+                    #instance table
+                    where_list=[]
+                    if tenant_id is not None: where_list.append( "inst.tenant_id='" + tenant_id +"'" )
+                    if db_base._check_valid_uuid(instance_id):
+                        where_list.append( "inst.uuid='" + instance_id +"'" )
+                    else:
+                        where_list.append( "inst.name='" + instance_id +"'" )
+                    where_text = " AND ".join(where_list)
+                    cmd = "SELECT inst.uuid as uuid,inst.name as name,inst.scenario_id as scenario_id, datacenter_id" +\
+                                " ,datacenter_tenant_id, s.name as scenario_name,inst.tenant_id as tenant_id" + \
+                                " ,inst.description as description,inst.created_at as created_at" +\
+                                " ,inst.cloud_config as 'cloud_config'" +\
+                            " FROM instance_scenarios as inst join scenarios as s on inst.scenario_id=s.uuid"+\
+                            " WHERE " + where_text
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    rows = self.cur.fetchall()
+                    
+                    if self.cur.rowcount==0:
+                        raise db_base.db_base_Exception("No instance found where " + where_text, db_base.HTTP_Not_Found)
+                    elif self.cur.rowcount>1:
+                        raise db_base.db_base_Exception("More than one instance found where " + where_text, db_base.HTTP_Bad_Request)
+                    instance_dict = rows[0]
+                    if instance_dict["cloud_config"]:
+                        instance_dict["cloud-config"] = yaml.load(instance_dict["cloud_config"])
+                    del instance_dict["cloud_config"]
+                    
+                    #instance_vnfs
+                    cmd = "SELECT iv.uuid as uuid,sv.vnf_id as vnf_id,sv.name as vnf_name, sce_vnf_id, datacenter_id, datacenter_tenant_id"\
+                            " FROM instance_vnfs as iv join sce_vnfs as sv on iv.sce_vnf_id=sv.uuid" \
+                            " WHERE iv.instance_scenario_id='{}'" \
+                            " ORDER BY iv.created_at ".format(instance_dict['uuid'])
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    instance_dict['vnfs'] = self.cur.fetchall()
+                    for vnf in instance_dict['vnfs']:
+                        vnf_manage_iface_list=[]
+                        #instance vms
+                        cmd = "SELECT iv.uuid as uuid, vim_vm_id, status, error_msg, vim_info, iv.created_at as created_at, name "\
+                                " FROM instance_vms as iv join vms on iv.vm_id=vms.uuid "\
+                                " WHERE instance_vnf_id='{}' ORDER BY iv.created_at".format(vnf['uuid'])
+                        self.logger.debug(cmd)
+                        self.cur.execute(cmd)
+                        vnf['vms'] = self.cur.fetchall()
+                        for vm in vnf['vms']:
+                            vm_manage_iface_list=[]
+                            #instance_interfaces
+                            cmd = "SELECT vim_interface_id, instance_net_id, internal_name,external_name, mac_address,"\
+                                  " ii.ip_address as ip_address, vim_info, i.type as type"\
+                                  " FROM instance_interfaces as ii join interfaces as i on ii.interface_id=i.uuid"\
+                                  " WHERE instance_vm_id='{}' ORDER BY created_at".format(vm['uuid'])
+                            self.logger.debug(cmd)
+                            self.cur.execute(cmd )
+                            vm['interfaces'] = self.cur.fetchall()
+                            for iface in vm['interfaces']:
+                                if iface["type"] == "mgmt" and iface["ip_address"]:
+                                    vnf_manage_iface_list.append(iface["ip_address"])
+                                    vm_manage_iface_list.append(iface["ip_address"])
+                                if not verbose:
+                                    del iface["type"]
+                            if vm_manage_iface_list: vm["ip_address"] = ",".join(vm_manage_iface_list)
+                        if vnf_manage_iface_list: vnf["ip_address"] = ",".join(vnf_manage_iface_list)
+                        
+                    #instance_nets
+                    #select_text = "instance_nets.uuid as uuid,sce_nets.name as net_name,instance_nets.vim_net_id as net_id,instance_nets.status as status,instance_nets.external as external" 
+                    #from_text = "instance_nets join instance_scenarios on instance_nets.instance_scenario_id=instance_scenarios.uuid " + \
+                    #            "join sce_nets on instance_scenarios.scenario_id=sce_nets.scenario_id"
+                    #where_text = "instance_nets.instance_scenario_id='"+ instance_dict['uuid'] + "'"
+                    cmd = "SELECT uuid,vim_net_id,status,error_msg,vim_info,created, sce_net_id, net_id as vnf_net_id, datacenter_id, datacenter_tenant_id"\
+                            " FROM instance_nets" \
+                            " WHERE instance_scenario_id='{}' ORDER BY created_at".format(instance_dict['uuid'])
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    instance_dict['nets'] = self.cur.fetchall()
+                    
+                    db_base._convert_datetime2str(instance_dict)
+                    db_base._convert_str2boolean(instance_dict, ('public','shared','created') )
+                    return instance_dict
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+        
+    def delete_instance_scenario(self, instance_id, tenant_id=None):
+        '''Deletes a instance_Scenario, filtering by one or serveral of the tenant, uuid or name
+        instance_id is the uuid or the name if it is not a valid uuid format
+        Only one instance_scenario must mutch the filtering or an error is returned
+        ''' 
+        tries = 2
+        while tries:
+            try:
+                with self.con:
+                    self.cur = self.con.cursor(mdb.cursors.DictCursor)
+    
+                    #instance table
+                    where_list=[]
+                    if tenant_id is not None: where_list.append( "tenant_id='" + tenant_id +"'" )
+                    if db_base._check_valid_uuid(instance_id):
+                        where_list.append( "uuid='" + instance_id +"'" )
+                    else:
+                        where_list.append( "name='" + instance_id +"'" )
+                    where_text = " AND ".join(where_list)
+                    cmd = "SELECT * FROM instance_scenarios WHERE "+ where_text
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    rows = self.cur.fetchall()
+                    
+                    if self.cur.rowcount==0:
+                        raise db_base.db_base_Exception("No instance found where " + where_text, db_base.HTTP_Bad_Request)
+                    elif self.cur.rowcount>1:
+                        raise db_base.db_base_Exception("More than one instance found where " + where_text, db_base.HTTP_Bad_Request)
+                    instance_uuid = rows[0]["uuid"]
+                    instance_name = rows[0]["name"]
+                    
+                    #sce_vnfs
+                    cmd = "DELETE FROM instance_scenarios WHERE uuid='{}'".format(instance_uuid)
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+    
+                    return instance_uuid + " " + instance_name
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries, "delete", "No dependences can avoid deleting!!!!")
+            tries -= 1
+    
+    def new_instance_scenario(self, instance_scenario_dict, tenant_id):
+        #return self.new_row('vnfs', vnf_dict, None, tenant_id, True, True)
+        return self._new_row_internal('instance_scenarios', instance_scenario_dict, tenant_id, add_uuid=True, root_uuid=None, log=True)
+
+    def update_instance_scenario(self, instance_scenario_dict):
+        #TODO:
+        return
+
+    def new_instance_vnf(self, instance_vnf_dict, tenant_id, instance_scenario_id = None):
+        #return self.new_row('vms', vm_dict, tenant_id, True, True)
+        return self._new_row_internal('instance_vnfs', instance_vnf_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
+
+    def update_instance_vnf(self, instance_vnf_dict):
+        #TODO:
+        return
+    
+    def delete_instance_vnf(self, instance_vnf_id):
+        #TODO:
+        return
+
+    def new_instance_vm(self, instance_vm_dict, tenant_id, instance_scenario_id = None):
+        #return self.new_row('vms', vm_dict, tenant_id, True, True)
+        return self._new_row_internal('instance_vms', instance_vm_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
+
+    def update_instance_vm(self, instance_vm_dict):
+        #TODO:
+        return
+    
+    def delete_instance_vm(self, instance_vm_id):
+        #TODO:
+        return
+
+    def new_instance_net(self, instance_net_dict, tenant_id, instance_scenario_id = None):
+        return self._new_row_internal('instance_nets', instance_net_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
+    
+    def update_instance_net(self, instance_net_dict):
+        #TODO:
+        return
+
+    def delete_instance_net(self, instance_net_id):
+        #TODO:
+        return
+    
+    def new_instance_interface(self, instance_interface_dict, tenant_id, instance_scenario_id = None):
+        return self._new_row_internal('instance_interfaces', instance_interface_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
+
+    def update_instance_interface(self, instance_interface_dict):
+        #TODO:
+        return
+
+    def delete_instance_interface(self, instance_interface_dict):
+        #TODO:
+        return
+
+    def update_datacenter_nets(self, datacenter_id, new_net_list=[]):
+        ''' Removes the old and adds the new net list at datacenter list for one datacenter.
+        Attribute 
+            datacenter_id: uuid of the datacenter to act upon
+            table: table where to insert
+            new_net_list: the new values to be inserted. If empty it only deletes the existing nets
+        Return: (Inserted items, Deleted items) if OK, (-Error, text) if error
+        '''
+        tries = 2
+        while tries:
+            created_time = time.time()
+            try:
+                with self.con:
+                    self.cur = self.con.cursor()
+                    cmd="DELETE FROM datacenter_nets WHERE datacenter_id='{}'".format(datacenter_id)
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    deleted = self.cur.rowcount
+                    inserted = 0
+                    for new_net in new_net_list:
+                        created_time += 0.00001
+                        self._new_row_internal('datacenter_nets', new_net, add_uuid=True, created_time=created_time)
+                        inserted += 1
+                    return inserted, deleted
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+            tries -= 1
+
+        
diff --git a/osm_ro/openmano_schemas.py b/osm_ro/openmano_schemas.py
new file mode 100644 (file)
index 0000000..1ea64f6
--- /dev/null
@@ -0,0 +1,1097 @@
+# -*- 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
+##
+
+'''
+JSON schemas used by openmano httpserver.py module to parse the different files and messages sent through the API 
+'''
+__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
+__date__ ="$09-oct-2014 09:09:48$"
+
+#Basis schemas
+patern_name="^[ -~]+$"
+passwd_schema={"type" : "string", "minLength":1, "maxLength":60}
+nameshort_schema={"type" : "string", "minLength":1, "maxLength":60, "pattern" : "^[^,;()'\"]+$"}
+name_schema={"type" : "string", "minLength":1, "maxLength":255, "pattern" : "^[^,;()'\"]+$"}
+xml_text_schema={"type" : "string", "minLength":1, "maxLength":1000, "pattern" : "^[^']+$"}
+description_schema={"type" : ["string","null"], "maxLength":255, "pattern" : "^[^'\"]+$"}
+id_schema_fake = {"type" : "string", "minLength":2, "maxLength":36 }  #"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"
+id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
+pci_schema={"type":"string", "pattern":"^[0-9a-fA-F]{4}(:[0-9a-fA-F]{2}){2}\.[0-9a-fA-F]$"}
+http_schema={"type":"string", "pattern":"^https?://[^'\"=]+$"}
+bandwidth_schema={"type":"string", "pattern" : "^[0-9]+ *([MG]bps)?$"}
+memory_schema={"type":"string", "pattern" : "^[0-9]+ *([MG]i?[Bb])?$"}
+integer0_schema={"type":"integer","minimum":0}
+integer1_schema={"type":"integer","minimum":1}
+path_schema={"type":"string", "pattern":"^(\.){0,2}(/[^/\"':{}\(\)]+)+$"}
+vlan_schema={"type":"integer","minimum":1,"maximum":4095}
+vlan1000_schema={"type":"integer","minimum":1000,"maximum":4095}
+mac_schema={"type":"string", "pattern":"^[0-9a-fA-F][02468aceACE](:[0-9a-fA-F]{2}){5}$"}  #must be unicast LSB bit of MSB byte ==0 
+#mac_schema={"type":"string", "pattern":"^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$"}
+ip_schema={"type":"string","pattern":"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"}
+ip_prefix_schema={"type":"string","pattern":"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/(30|[12]?[0-9])$"}
+port_schema={"type":"integer","minimum":1,"maximum":65534}
+object_schema={"type":"object"}
+schema_version_2={"type":"integer","minimum":2,"maximum":2}
+#schema_version_string={"type":"string","enum": ["0.1", "2", "0.2", "3", "0.3"]}
+log_level_schema={"type":"string", "enum":["DEBUG", "INFO", "WARNING","ERROR","CRITICAL"]}
+checksum_schema={"type":"string", "pattern":"^[0-9a-fA-F]{32}$"}
+size_schema={"type":"integer","minimum":1,"maximum":100}
+
+metadata_schema={
+    "type":"object",
+    "properties":{
+        "architecture": {"type":"string"},
+        "use_incremental": {"type":"string","enum":["yes","no"]},
+        "vpci": pci_schema,
+        "os_distro": {"type":"string"},
+        "os_type": {"type":"string"},
+        "os_version": {"type":"string"},
+        "bus": {"type":"string"},
+        "topology": {"type":"string", "enum": ["oneSocket"]}
+    }
+}
+
+#Schema for the configuration file
+config_schema = {
+    "title":"configuration response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "http_port": port_schema,
+        "http_admin_port": port_schema,
+        "http_host": nameshort_schema,
+        "auto_push_VNF_to_VIMs": {"type":"boolean"},
+        "vnf_repository": path_schema,
+        "db_host": nameshort_schema,
+        "db_user": nameshort_schema,
+        "db_passwd": {"type":"string"},
+        "db_name": nameshort_schema,
+        # Next fields will disappear once the MANO API includes appropriate primitives
+        "vim_url": http_schema,
+        "vim_url_admin": http_schema,
+        "vim_name": nameshort_schema,
+        "vim_tenant_name": nameshort_schema,
+        "mano_tenant_name": nameshort_schema,
+        "mano_tenant_id": id_schema, 
+        "http_console_proxy": {"type":"boolean"},
+        "http_console_host": nameshort_schema,
+        "http_console_ports": {
+            "type": "array", 
+            "items": {"OneOf" : [
+                port_schema, 
+                {"type":"object", "properties":{"from": port_schema, "to": port_schema}, "required": ["from","to"]} 
+            ]}
+        },
+        "log_level": log_level_schema,
+        "log_socket_level": log_level_schema,
+        "log_level_db": log_level_schema,
+        "log_level_vim": log_level_schema,
+        "log_level_nfvo": log_level_schema,
+        "log_level_http": log_level_schema,
+        "log_level_console": log_level_schema,
+        "log_file_db": path_schema,
+        "log_file_vim": path_schema,
+        "log_file_nfvo": path_schema,
+        "log_file_http": path_schema,
+        "log_file_console": path_schema,
+        "log_socket_host": nameshort_schema,
+        "log_socket_port": port_schema,
+        "log_file": path_schema,
+    },
+    "required": ['db_host', 'db_user', 'db_passwd', 'db_name'],
+    "additionalProperties": False
+}
+
+tenant_schema = {
+    "title":"tenant information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "tenant":{
+            "type":"object",
+            "properties":{
+                "name": nameshort_schema,
+                "description": description_schema,
+            },
+            "required": ["name"],
+            "additionalProperties": True
+        }
+    },
+    "required": ["tenant"],
+    "additionalProperties": False
+}
+
+tenant_edit_schema = {
+    "title":"tenant edit information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "tenant":{
+            "type":"object",
+            "properties":{
+                "name": name_schema,
+                "description": description_schema,
+            },
+            "additionalProperties": False
+        }
+    },
+    "required": ["tenant"],
+    "additionalProperties": False
+}
+
+datacenter_schema_properties={
+    "name": name_schema,
+    "description": description_schema,
+    "type": nameshort_schema, #currently "openvim" or "openstack", can be enlarged with plugins
+    "vim_url": description_schema,
+    "vim_url_admin": description_schema,
+    "config": { "type":"object" }
+}
+
+datacenter_schema = {
+    "title":"datacenter information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "datacenter":{
+            "type":"object",
+            "properties":datacenter_schema_properties,
+            "required": ["name", "vim_url"],
+            "additionalProperties": True
+        }
+    },
+    "required": ["datacenter"],
+    "additionalProperties": False
+}
+
+
+datacenter_edit_schema = {
+    "title":"datacenter edit nformation schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "datacenter":{
+            "type":"object",
+            "properties":datacenter_schema_properties,
+            "additionalProperties": False
+        }
+    },
+    "required": ["datacenter"],
+    "additionalProperties": False
+}
+
+
+netmap_new_schema = {
+    "title":"netmap new information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "netmap":{   #delete from datacenter
+            "type":"object",
+            "properties":{
+                "name": name_schema,  #name or uuid of net to change
+                "vim_id": id_schema,
+                "vim_name": name_schema
+            },
+            "minProperties": 1,
+            "additionalProperties": False
+        },
+    },
+    "required": ["netmap"],
+    "additionalProperties": False
+}
+
+netmap_edit_schema = {
+    "title":"netmap edit information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "netmap":{   #delete from datacenter
+            "type":"object",
+            "properties":{
+                "name": name_schema,  #name or uuid of net to change
+            },
+            "minProperties": 1,
+            "additionalProperties": False
+        },
+    },
+    "required": ["netmap"],
+    "additionalProperties": False
+}
+
+datacenter_action_schema = {
+    "title":"datacenter action information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "net-update":{"type":"null",},
+        "net-edit":{
+            "type":"object",
+            "properties":{
+                "net": name_schema,  #name or uuid of net to change
+                "name": name_schema,
+                "description": description_schema,
+                "shared": {"type": "boolean"}
+            },
+            "minProperties": 1,
+            "additionalProperties": False
+        },
+        "net-delete":{
+            "type":"object",
+            "properties":{
+                "net": name_schema,  #name or uuid of net to change
+            },
+            "required": ["net"],
+            "additionalProperties": False
+        },
+    },
+    "minProperties": 1,
+    "maxProperties": 1,
+    "additionalProperties": False
+}
+
+
+datacenter_associate_schema={
+    "title":"datacenter associate information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "datacenter":{
+            "type":"object",
+            "properties":{
+                "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
+        }
+    },
+    "required": ["datacenter"],
+    "additionalProperties": False
+}
+
+dhcp_schema = {
+    "title":"DHCP schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "enabled": {"type": "boolean"},
+        "start-address": ip_schema,
+        "count": integer1_schema
+    },
+    "required": ["enabled", "start-address", "count"],
+}
+
+ip_profile_schema = {
+    "title":"IP profile schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "ip-version": {"type":"string", "enum":["IPv4","IPv6"]},
+        "subnet-address": ip_prefix_schema,
+        "gateway-address": ip_schema,
+        "dns-address": ip_schema,
+        "dhcp": dhcp_schema
+    },
+}
+
+key_pair_schema = {
+    "title": "Key-pair schema for cloud-init configuration schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "name": name_schema,
+        "key": {"type":"string"}
+    },
+    "required": ["key"],
+    "additionalProperties": False
+}
+
+cloud_config_user_schema = {
+    "title": "User schema for cloud-init configuration schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "name": nameshort_schema,
+        "user-info": {"type":"string"},
+        #"key-pairs": {"type" : "array", "items": key_pair_schema}
+        "key-pairs": {"type" : "array", "items": {"type":"string"}}
+    },
+    "required": ["name"],
+    "additionalProperties": False
+}
+
+cloud_config_schema = {
+    "title": "Cloud-init configuration schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        #"key-pairs": {"type" : "array", "items": key_pair_schema},
+        "key-pairs": {"type" : "array", "items": {"type":"string"}},
+        "users": {"type" : "array", "items": cloud_config_user_schema}
+    },
+    "additionalProperties": False
+}
+
+internal_connection_element_schema = {
+    "type":"object",
+    "properties":{
+        "VNFC": name_schema,
+        "local_iface_name": name_schema
+    }
+}
+
+internal_connection_element_schema_v02 = {
+    "type":"object",
+    "properties":{
+        "VNFC": name_schema,
+        "local_iface_name": name_schema,
+        "ip_address": ip_schema
+    }
+}
+
+internal_connection_schema = {
+    "type":"object",
+    "properties":{
+        "name": name_schema,
+        "description":description_schema,
+        "type":{"type":"string", "enum":["bridge","data","ptp"]},
+        "elements": {"type" : "array", "items": internal_connection_element_schema, "minItems":2}
+    },
+    "required": ["name", "type", "elements"],
+    "additionalProperties": False
+}
+
+internal_connection_schema_v02 = {
+    "type":"object",
+    "properties":{
+        "name": name_schema,
+        "description":description_schema,
+        "type": {"type": "string", "enum":["e-line", "e-lan"]},
+        "implementation": {"type": "string", "enum":["overlay", "underlay"]},
+        "ip-profile": ip_profile_schema,
+        "elements": {"type" : "array", "items": internal_connection_element_schema_v02, "minItems":2}
+    },
+    "required": ["name", "type", "implementation", "elements"],
+    "additionalProperties": False
+}
+
+external_connection_schema = {
+    "type":"object",
+    "properties":{
+        "name": name_schema,
+        "type":{"type":"string", "enum":["mgmt","bridge","data"]},
+        "VNFC": name_schema,
+        "local_iface_name": name_schema ,
+        "description":description_schema
+    },
+    "required": ["name", "type", "VNFC", "local_iface_name"],
+    "additionalProperties": False
+}
+
+#Not yet used
+external_connection_schema_v02 = {
+    "type":"object",
+    "properties":{
+        "name": name_schema,
+        "mgmt": {"type":"boolean"},
+        "type": {"type": "string", "enum":["e-line", "e-lan"]}, 
+        "implementation": {"type": "string", "enum":["overlay", "underlay"]},
+        "VNFC": name_schema,
+        "local_iface_name": name_schema ,
+        "description":description_schema
+    },
+    "required": ["name", "type", "VNFC", "local_iface_name"],
+    "additionalProperties": False
+}
+
+interfaces_schema={
+    "type":"array",
+    "items":{
+        "type":"object",
+        "properties":{
+            "name":name_schema,
+            "dedicated":{"type":"string","enum":["yes","no","yes:sriov"]},
+            "bandwidth":bandwidth_schema,
+            "vpci":pci_schema,
+            "mac_address": mac_schema
+        },
+        "additionalProperties": False,
+        "required": ["name","dedicated", "bandwidth"]
+    }
+}
+
+bridge_interfaces_schema={
+    "type":"array",
+    "items":{
+        "type":"object",
+        "properties":{
+            "name": name_schema,
+            "bandwidth":bandwidth_schema,
+            "vpci":pci_schema,
+            "mac_address": mac_schema,
+            "model": {"type":"string", "enum":["virtio","e1000","ne2k_pci","pcnet","rtl8139"]},
+            "port-security": {"type" : "boolean"},
+            "floating-ip": {"type" : "boolean"}
+        },
+        "additionalProperties": False,
+        "required": ["name"]
+    }
+}
+
+devices_schema={
+    "type":"array",
+    "items":{
+        "type":"object",
+        "properties":{
+            "type":{"type":"string", "enum":["disk","cdrom","xml"] },
+            "image": path_schema,
+            "image name": name_schema,
+            "image checksum": checksum_schema,
+            "image metadata": metadata_schema,
+            "size": size_schema,
+            "vpci":pci_schema,
+            "xml":xml_text_schema,
+        },
+        "additionalProperties": False,
+        "required": ["type"]
+    }
+}
+
+
+numa_schema = {
+    "type": "object",
+    "properties": {
+        "memory":integer1_schema,
+        "cores":integer1_schema,
+        "paired-threads":integer1_schema,
+        "threads":integer1_schema,
+        "cores-id":{"type":"array","items":integer0_schema},
+        "paired-threads-id":{"type":"array","items":{"type":"array","minItems":2,"maxItems":2,"items":integer0_schema}},
+        "threads-id":{"type":"array","items":integer0_schema},
+        "interfaces":interfaces_schema
+    },
+    "additionalProperties": False,
+    #"required": ["memory"]
+}
+
+config_files_schema = {
+    "title": "Config files for cloud init schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type": "object",
+    "properties": {
+        "dest": path_schema,
+        "encoding": {"type": "string", "enum": ["b64", "base64", "gz", "gz+b64", "gz+base64", "gzip+b64", "gzip+base64"]},  #by default text
+        "content": {"type": "string"},
+        "permissions": {"type": "string"}, # tiypically octal notation '0644'
+        "owner": {"type": "string"},  # format:   owner:group
+
+    },
+    "additionalProperties": False,
+    "required": ["dest", "content"],
+}
+
+boot_data_vdu_schema  = {
+    "title": "Boot data (Cloud-init) configuration schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type": "object",
+    "properties":{
+        "key-pairs": {"type" : "array", "items": {"type":"string"}},
+        "users": {"type" : "array", "items": cloud_config_user_schema},
+        "user-data": {"type" : "string"},  # scrip to run
+        "config-files": {"type": "array", "items": config_files_schema},
+        # NOTE: “user-data” are mutually exclusive with users and config-files because user/files are injected using user-data
+        "boot-data-drive": {"type": "boolean"},
+    },
+    "additionalProperties": False,
+}
+
+vnfc_schema = {
+    "type":"object",
+    "properties":{
+        "name": name_schema,
+        "description": description_schema,
+        "VNFC image": {"oneOf": [path_schema, http_schema]},
+        "image name": name_schema,
+        "image checksum": checksum_schema,
+        "image metadata": metadata_schema, 
+        #"cloud-config": cloud_config_schema, #common for all vnfs in the scenario
+        "processor": {
+            "type":"object",
+            "properties":{
+                "model":description_schema,
+                "features":{"type":"array","items":nameshort_schema}
+            },
+            "required": ["model"],
+            "additionalProperties": False
+        },
+        "hypervisor": {
+            "type":"object",
+            "properties":{
+                "type":nameshort_schema,
+                "version":description_schema
+            },
+        },
+        "ram":integer0_schema,
+        "vcpus":integer0_schema,
+        "disk": integer1_schema,
+        "numas": {
+            "type": "array",
+            "items": numa_schema
+        },
+        "bridge-ifaces": bridge_interfaces_schema,
+        "devices": devices_schema,
+        "boot-data" : boot_data_vdu_schema
+        
+    },
+    "required": ["name"],
+    "oneOf": [
+        {"required": ["VNFC image"]},
+        {"required": ["image name"]}
+    ],
+    "additionalProperties": False
+}
+
+vnfd_schema_v01 = {
+    "title":"vnfd information schema v0.1",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "vnf":{
+            "type":"object",
+            "properties":{
+                "name": name_schema,
+                "description": description_schema,
+                "class": nameshort_schema,
+                "public": {"type" : "boolean"},
+                "physical": {"type" : "boolean"},
+                "tenant_id": id_schema, #only valid for admin
+                "external-connections": {"type" : "array", "items": external_connection_schema, "minItems":1},
+                "internal-connections": {"type" : "array", "items": internal_connection_schema, "minItems":1},
+                "VNFC":{"type" : "array", "items": vnfc_schema, "minItems":1}
+            },
+            "required": ["name","external-connections"],
+            "additionalProperties": True
+        }
+    },
+    "required": ["vnf"],
+    "additionalProperties": False
+}
+
+#VNFD schema for OSM R1 
+vnfd_schema_v02 = {
+    "title":"vnfd information schema v0.2",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "schema_version": {"type": "string", "enum": ["0.2"]},
+        "vnf":{
+            "type":"object",
+            "properties":{
+                "name": name_schema,
+                "description": description_schema,
+                "class": nameshort_schema,
+                "public": {"type" : "boolean"},
+                "physical": {"type" : "boolean"},
+                "tenant_id": id_schema, #only valid for admin
+                "external-connections": {"type" : "array", "items": external_connection_schema, "minItems":1},
+                "internal-connections": {"type" : "array", "items": internal_connection_schema_v02, "minItems":1},
+                # "cloud-config": cloud_config_schema, #common for all vnfcs
+                "VNFC":{"type" : "array", "items": vnfc_schema, "minItems":1}
+            },
+            "required": ["name"],
+            "additionalProperties": True
+        }
+    },
+    "required": ["vnf", "schema_version"],
+    "additionalProperties": False
+}
+
+#vnfd_schema = vnfd_schema_v01
+#{
+#    "title":"vnfd information schema v0.2",
+#    "$schema": "http://json-schema.org/draft-04/schema#",
+#    "oneOf": [vnfd_schema_v01, vnfd_schema_v02]
+#}
+
+graph_schema = {
+    "title":"graphical scenario descriptor information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "x":      integer0_schema,
+        "y":      integer0_schema,
+        "ifaces": {
+            "type":"object",
+            "properties":{
+                "left": {"type":"array"},
+                "right": {"type":"array"},
+                "bottom": {"type":"array"},
+            }
+        }
+    },
+    "required": ["x","y"]
+}
+
+nsd_schema_v01 = {
+    "title":"network scenario descriptor information schema v0.1",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "name":name_schema,
+        "description": description_schema,
+        "tenant_id": id_schema, #only valid for admin
+        "public": {"type": "boolean"},
+        "topology":{
+            "type":"object",
+            "properties":{
+                "nodes": {
+                    "type":"object",
+                    "patternProperties":{
+                        ".": {
+                            "type": "object",
+                            "properties":{
+                                "type":{"type":"string", "enum":["VNF", "other_network", "network", "external_network"]},
+                                "vnf_id": id_schema,
+                                "graph": graph_schema,
+                            },
+                            "patternProperties":{
+                                "^(VNF )?model$": {"type": "string"}
+                            },
+                            "required": ["type"]
+                        }
+                    }
+                },
+                "connections": {
+                    "type":"object",
+                    "patternProperties":{
+                        ".": {
+                            "type": "object",
+                            "properties":{
+                                "nodes":{"oneOf":[{"type":"object", "minProperties":2}, {"type":"array", "minLength":1}]},
+                                "type": {"type": "string", "enum":["link", "external_network", "dataplane_net", "bridge_net"]},
+                                "graph": graph_schema
+                            },
+                            "required": ["nodes"]
+                        },
+                    }
+                }
+            },
+            "required": ["nodes"],
+            "additionalProperties": False
+        }
+    },
+    "required": ["name","topology"],
+    "additionalProperties": False
+}
+
+nsd_schema_v02 = {
+    "title":"network scenario descriptor information schema v0.2",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "schema_version": schema_version_2,
+        "scenario":{
+            "type":"object",
+            "properties":{
+                "name": name_schema,
+                "description": description_schema,
+                "tenant_id": id_schema, #only valid for admin
+                "public": {"type": "boolean"},
+                "vnfs": {
+                    "type":"object",
+                    "patternProperties":{
+                        ".": {
+                            "type": "object",
+                            "properties":{
+                                "vnf_id": id_schema,
+                                "graph": graph_schema,
+                                "vnf_name": name_schema,
+                            },
+                        }
+                    },
+                    "minProperties": 1
+                },
+                "networks": {
+                    "type":"object",
+                    "patternProperties":{
+                        ".": {
+                            "type": "object",
+                            "properties":{
+                                "interfaces":{"type":"array", "minLength":1},
+                                "type": {"type": "string", "enum":["dataplane", "bridge"]},
+                                "external" : {"type": "boolean"},
+                                "graph": graph_schema
+                            },
+                            "required": ["interfaces"]
+                        },
+                    }
+                },
+            
+            },
+            "required": ["vnfs", "name"],
+            "additionalProperties": False
+        }
+    },
+    "required": ["scenario","schema_version"],
+    "additionalProperties": False
+}
+
+#NSD schema for OSM R1
+nsd_schema_v03 = {
+    "title":"network scenario descriptor information schema v0.3",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "schema_version": {"type": "string", "enum": ["0.3"]},
+        "scenario":{
+            "type":"object",
+            "properties":{
+                "name": name_schema,
+                "description": description_schema,
+                "tenant_id": id_schema, #only valid for admin
+                "public": {"type": "boolean"},
+                "cloud-config": cloud_config_schema, #common for all vnfs in the scenario
+                #"datacenter": name_schema,
+                "vnfs": {
+                    "type":"object",
+                    "patternProperties":{
+                        ".": {
+                            "type": "object",
+                            "properties":{
+                                "vnf_id": id_schema,
+                                "graph": graph_schema,
+                                "vnf_name": name_schema,
+                                #"cloud-config": cloud_config_schema, #particular for a vnf
+                                #"datacenter": name_schema,
+                                "internal-connections": {
+                                    "type": "object",
+                                    "patternProperties": {
+                                        ".": {
+                                            "type": "object",
+                                            "properties": {
+                                                "ip-profile": ip_profile_schema,
+                                                "elements": {
+                                                    "type" : "array",
+                                                    "items":{
+                                                        "type":"object",
+                                                        "properties":{
+                                                            "VNFC": name_schema,
+                                                            "local_iface_name": name_schema,
+                                                            "ip_address": ip_schema
+                                                        },
+                                                        "required": ["VNFC", "local_iface_name"],
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            },
+                        }
+                    },
+                    "minProperties": 1
+                },
+                "networks": {
+                    "type":"object",
+                    "patternProperties":{
+                        ".": {
+                            "type": "object",
+                            "properties":{
+                                "interfaces":{
+                                    "type":"array",
+                                    "minLength":1,
+                                    "items":{
+                                        "type":"object",
+                                        "properties":{
+                                            "vnf": name_schema,
+                                            "vnf_interface": name_schema,
+                                            "ip_address": ip_schema
+                                        },
+                                        "required": ["vnf", "vnf_interface"],
+                                    }
+                                },
+                                "type": {"type": "string", "enum":["e-line", "e-lan"]},
+                                "implementation": {"type": "string", "enum":["overlay", "underlay"]},
+                                "external" : {"type": "boolean"},
+                                "graph": graph_schema,
+                                "ip-profile": ip_profile_schema
+                            },
+                            "required": ["interfaces"]
+                        },
+                    }
+                },
+            
+            },
+            "required": ["vnfs", "networks","name"],
+            "additionalProperties": False
+        }
+    },
+    "required": ["scenario","schema_version"],
+    "additionalProperties": False
+}
+
+#scenario_new_schema = {
+#    "title":"new scenario information schema",
+#    "$schema": "http://json-schema.org/draft-04/schema#",
+#    #"oneOf": [nsd_schema_v01, nsd_schema_v02]
+#    "oneOf": [nsd_schema_v01]
+#}
+
+scenario_edit_schema = {
+    "title":"edit scenario information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "name":name_schema,
+        "description": description_schema,
+        "topology":{
+            "type":"object",
+            "properties":{
+                "nodes": {
+                    "type":"object",
+                    "patternProperties":{
+                        "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$": {
+                            "type":"object",
+                            "properties":{
+                                "graph":{
+                                    "type": "object",
+                                    "properties":{
+                                        "x": integer0_schema,
+                                        "y": integer0_schema,
+                                        "ifaces":{ "type": "object"}
+                                    }
+                                },
+                                "description": description_schema,
+                                "name": name_schema
+                            }
+                        }
+                    }
+                }
+            },
+            "required": ["nodes"],
+            "additionalProperties": False
+        }
+    },
+    "additionalProperties": False
+}
+
+scenario_action_schema = {
+    "title":"scenario action information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "start":{
+            "type": "object",
+            "properties": {
+                "instance_name":name_schema,
+                "description":description_schema,
+                "datacenter": {"type": "string"}
+            },
+            "required": ["instance_name"]
+        },
+        "deploy":{
+            "type": "object",
+            "properties": {
+                "instance_name":name_schema,
+                "description":description_schema,
+                "datacenter": {"type": "string"}
+            },
+            "required": ["instance_name"]
+        },
+        "reserve":{
+            "type": "object",
+            "properties": {
+                "instance_name":name_schema,
+                "description":description_schema,
+                "datacenter": {"type": "string"}
+            },
+            "required": ["instance_name"]
+        },
+        "verify":{
+            "type": "object",
+            "properties": {
+                "instance_name":name_schema,
+                "description":description_schema,
+                "datacenter": {"type": "string"}
+            },
+            "required": ["instance_name"]
+        }
+    },
+    "minProperties": 1,
+    "maxProperties": 1,
+    "additionalProperties": False
+}
+
+instance_scenario_create_schema_v01 = {
+    "title":"instance scenario create information schema v0.1",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "schema_version": {"type": "string", "enum": ["0.1"]},
+        "instance":{
+            "type":"object",
+            "properties":{
+                "name":name_schema,
+                "description":description_schema,
+                "datacenter": name_schema,
+                "scenario" : name_schema, #can be an UUID or name
+                "action":{"enum": ["deploy","reserve","verify" ]},
+                "connect_mgmt_interfaces": {"oneOf": [{"type":"boolean"}, {"type":"object"}]},# can be true or a dict with datacenter: net_name
+                "cloud-config": cloud_config_schema, #common to all vnfs in the instance scenario
+                "vnfs":{             #mapping from scenario to datacenter
+                    "type": "object",
+                    "patternProperties":{
+                        ".": {
+                            "type": "object",
+                            "properties":{
+                                "name": name_schema, #override vnf name
+                                "datacenter": name_schema,
+                                #"metadata": {"type": "object"},
+                                #"user_data": {"type": "string"}
+                                #"cloud-config": cloud_config_schema, #particular for a vnf
+                                "external-connections": {
+                                    "type": "object",
+                                    "patternProperties": {
+                                        ".": {
+                                            "type": "object",
+                                            "properties": {
+                                                "vim-network-name": name_schema,
+                                                "ip_address": ip_schema
+                                            } 
+                                        }
+                                    }
+                                },
+                                "internal-connections": {
+                                    "type": "object",
+                                    "patternProperties": {
+                                        ".": {
+                                            "type": "object",
+                                            "properties": {
+                                                "ip-profile": ip_profile_schema,
+                                                "elements": {
+                                                    "type" : "array",
+                                                    "items":{
+                                                        "type":"object",
+                                                        "properties":{
+                                                            "VNFC": name_schema,
+                                                            "local_iface_name": name_schema,
+                                                            "ip_address": ip_schema
+                                                        },
+                                                        "required": ["VNFC", "local_iface_name"],
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                },
+                "networks":{             #mapping from scenario to datacenter
+                    "type": "object",
+                    "patternProperties":{
+                        ".": {
+                            "type": "object",
+                            "properties":{
+                                "interfaces":{
+                                    "type":"array",
+                                    "minLength":1,
+                                    "items":{
+                                        "type":"object",
+                                        "properties":{
+                                            "ip_address": ip_schema,
+                                            "datacenter": name_schema,
+                                            "vim-network-name": name_schema
+                                        },
+                                        "patternProperties":{
+                                            ".": {"type": "string"}
+                                        }
+                                    }
+                                },
+                                "ip-profile": ip_profile_schema,
+                                #if the network connects VNFs deployed at different sites, you must specify one entry per site that this network connect to 
+                                "sites": {
+                                    "type":"array",
+                                    "minLength":1,
+                                    "items":{
+                                        "type":"object",
+                                        "properties":{
+                                            # By default for an scenario 'external' network openmano looks for an existing VIM network to map this external scenario network,
+                                            # for other networks openamno creates at VIM
+                                            # Use netmap-create to force to create an external scenario network  
+                                            "netmap-create": {"oneOf":[name_schema,{"type": "null"}]}, #datacenter network to use. Null if must be created as an internal net
+                                            #netmap-use:   Indicates an existing VIM network that must be used for this scenario network. 
+                                            #Can use both the VIM network name (if it is not ambiguous) or the VIM net UUID
+                                            #If both 'netmap-create' and 'netmap-use'are supplied, netmap-use precedes, but if fails openmano follows the netmap-create
+                                            #In oder words, it is the same as 'try to map to the VIM network (netmap-use) if exist, and if not create the network (netmap-create)
+                                            "netmap-use": name_schema, # 
+                                            "vim-network-name": name_schema, #override network name
+                                            #"ip-profile": ip_profile_schema,
+                                            "datacenter": name_schema,                                        
+                                        }
+                                    }
+                                },
+                                
+
+
+                            }
+                        }
+                    },
+                },
+            },
+            "additionalProperties": False,
+            "required": ["name"]
+        },
+    },
+    "required": ["instance"],
+    "additionalProperties": False
+}
+
+instance_scenario_action_schema = {
+    "title":"instance scenario action information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "start":{"type": "null"},
+        "pause":{"type": "null"},
+        "resume":{"type": "null"},
+        "shutoff":{"type": "null"},
+        "shutdown":{"type": "null"},
+        "forceOff":{"type": "null"},
+        "rebuild":{"type": "null"},
+        "reboot":{
+            "type": ["object","null"],
+        },
+        "console": {"type": ["string", "null"], "enum": ["novnc", "xvpvnc", "rdp-html5", "spice-html5", None]},
+        "vnfs":{"type": "array", "items":{"type":"string"}},
+        "vms":{"type": "array", "items":{"type":"string"}}
+    },
+    "minProperties": 1,
+    #"maxProperties": 1,
+    "additionalProperties": False
+}
diff --git a/osm_ro/openmanoclient.py b/osm_ro/openmanoclient.py
new file mode 100644 (file)
index 0000000..c11f747
--- /dev/null
@@ -0,0 +1,916 @@
+#!/usr/bin/env python3
+# -*- 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
+##
+
+'''
+openmano python client used to interact with openmano-server  
+'''
+__author__="Alfonso Tierno"
+__date__ ="$09-Mar-2016 09:09:48$"
+__version__="0.0.1-r467"
+version_date="Mar 2016"
+
+import requests
+import json
+import yaml
+import logging
+import sys
+if  sys.version_info.major == 3:
+    from urllib.parse import quote
+elif sys.version_info.major == 2:
+    from urllib import quote
+
+class OpenmanoException(Exception):
+    '''Common Exception for all openmano client exceptions'''
+
+class OpenmanoBadParamsException(OpenmanoException):
+    '''Bad or missing input parameters'''
+
+class OpenmanoResponseException(OpenmanoException):
+    '''Unexpected response from openmano server'''
+
+class OpenmanoNotFoundException(OpenmanoException):
+    '''Not found at server'''
+
+# class vnf():
+#     def __init__(self, message):
+#         print "Error: %s" %message
+#         print
+#         self.print_usage()
+#         #self.print_help()
+#         print
+#         print "Type 'openmano -h' for help"
+
+class openmanoclient():
+    headers_req = {'Accept': 'application/yaml', 'content-type': 'application/yaml'}
+    
+    def __init__(self, **kwargs):
+        self.username = kwargs.get("username")
+        self.password = kwargs.get("password")
+        self.endpoint_url = kwargs.get("endpoint_url")
+        self.tenant_id = kwargs.get("tenant_id")
+        self.tenant_name = kwargs.get("tenant_name")
+        self.tenant = None
+        self.datacenter_id = kwargs.get("datacenter_id")
+        self.datacenter_name = kwargs.get("datacenter_name")
+        self.datacenter = None
+        self.logger = logging.getLogger(kwargs.get('logger','manoclient'))
+        if kwargs.get("debug"):
+            self.logger.setLevel(logging.DEBUG)
+        
+    def __getitem__(self, index):
+        if index=='tenant_name':
+            return self.tenant_name
+        elif index=='tenant_id':
+            return self.tenant_id
+        elif index=='datacenter_name':
+            return self.datacenter_name
+        elif index=='datacenter_id':
+            return self.datacenter_id
+        elif index=='username':
+            return self.username
+        elif index=='password':
+            return self.password
+        elif index=='endpoint_url':
+            return self.endpoint_url
+        else:
+            raise KeyError("Invalid key '%s'" %str(index))
+        
+    def __setitem__(self,index, value):
+        if index=='tenant_name':
+            self.tenant_name = value
+        elif index=='tenant_id':
+            self.tenant_id = value
+        elif index=='datacenter_name':
+            self.datacenter_name = value
+        elif index=='datacenter_id':
+            self.datacenter_id = value
+        elif index=='username':
+            self.username = value
+        elif index=='password':
+            self.password = value
+        elif index=='endpoint_url':
+            self.endpoint_url = value
+        else:
+            raise KeyError("Invalid key '%s'" %str(index)) 
+        self.tenant = None # force to reload tenant with different credentials
+        self.datacenter = None # force to reload datacenter with different credentials
+    
+    def _parse(self, descriptor, descriptor_format, response=False):
+        #try yaml
+        if descriptor_format and descriptor_format != "json" and descriptor_format != "yaml":
+            raise  OpenmanoBadParamsException("'descriptor_format' must be a 'json' or 'yaml' text")
+        if descriptor_format != "json":
+            try:
+                return yaml.load(descriptor)
+            except yaml.YAMLError as exc:
+                error_pos = ""
+                if hasattr(exc, 'problem_mark'):
+                    mark = exc.problem_mark
+                    error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1)
+                error_text = "yaml format error" + error_pos
+        elif descriptor_format != "yaml":
+            try:
+                return json.loads(descriptor) 
+            except Exception as e:
+                if response:
+                    error_text = "json format error" + str(e)
+
+        if response:
+            raise OpenmanoResponseException(error_text)
+        raise  OpenmanoBadParamsException(error_text)
+    
+    def _parse_yaml(self, descriptor, response=False):
+        try:
+            return yaml.load(descriptor)
+        except yaml.YAMLError as exc:
+            error_pos = ""
+            if hasattr(exc, 'problem_mark'):
+                mark = exc.problem_mark
+                error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1)
+            error_text = "yaml format error" + error_pos
+            if response:
+                raise OpenmanoResponseException(error_text)
+            raise  OpenmanoBadParamsException(error_text)
+
+    
+    def _get_item_uuid(self, item, item_id=None, item_name=None, all_tenants=False):
+        if all_tenants == None:
+            tenant_text = ""
+        elif all_tenants == False:
+            tenant_text = "/" + self.tenant
+        else:
+            tenant_text = "/any"
+        URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
+        self.logger.debug("GET %s", URLrequest )
+        mano_response = requests.get(URLrequest, headers=self.headers_req)
+        self.logger.debug("openmano response: %s", mano_response.text )
+        content = self._parse_yaml(mano_response.text, response=True)
+        #print content
+        found = 0
+        if not item_id and not item_name:
+            raise OpenmanoResponseException("Missing either {0}_name or {0}_id".format(item[:-1]))
+        for i in content[item]:
+            if item_id and i["uuid"] == item_id:
+                return item_id
+            elif item_name and i["name"] == item_name:
+                uuid = i["uuid"]
+                found += 1
+            
+        if found == 0:
+            if item_id:
+                raise OpenmanoNotFoundException("No {} found with id '{}'".format(item[:-1], item_id))
+            else:
+                #print(item, item_name)
+                raise OpenmanoNotFoundException("No {} found with name '{}'".format(item[:-1], item_name) )
+        elif found > 1:
+            raise OpenmanoNotFoundException("{} {} found with name '{}'. uuid must be used".format(found, item, item_name))
+        return uuid
+
+    def _get_item(self, item, uuid=None, name=None, all_tenants=False):
+        if all_tenants:
+            tenant_text = "/any"
+        elif all_tenants==None:
+            tenant_text = ""
+        else:
+            tenant_text = "/"+self._get_tenant()
+        if not uuid:
+            #check that exist
+            uuid = self._get_item_uuid(item, uuid, name, all_tenants)
+        
+        URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
+        self.logger.debug("GET %s", URLrequest )
+        mano_response = requests.get(URLrequest, headers=self.headers_req)
+        self.logger.debug("openmano response: %s", mano_response.text )
+    
+        content = self._parse_yaml(mano_response.text, response=True)
+        if mano_response.status_code==200:
+            return content
+        else:
+            raise OpenmanoResponseException(str(content))        
+
+    def _get_tenant(self):
+        if not self.tenant:
+            self.tenant = self._get_item_uuid("tenants", self.tenant_id, self.tenant_name, None)
+        return self.tenant
+    
+    def _get_datacenter(self):
+        if not self.tenant:
+            self._get_tenant()
+        if not self.datacenter:
+            self.datacenter = self._get_item_uuid("datacenters", self.datacenter_id, self.datacenter_name, False)
+        return self.datacenter
+
+    def _create_item(self, item, descriptor, all_tenants=False):
+        if all_tenants:
+            tenant_text = "/any"
+        elif all_tenants==None:
+            tenant_text = ""
+        else:
+            tenant_text = "/"+self._get_tenant()
+        payload_req = yaml.safe_dump(descriptor)
+            
+        #print payload_req
+            
+        URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
+        self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
+        mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
+        self.logger.debug("openmano response: %s", mano_response.text )
+    
+        content = self._parse_yaml(mano_response.text, response=True)
+        if mano_response.status_code==200:
+            return content
+        else:
+            raise OpenmanoResponseException(str(content))        
+
+    def _del_item(self, item, uuid=None, name=None, all_tenants=False):
+        if all_tenants:
+            tenant_text = "/any"
+        elif all_tenants==None:
+            tenant_text = ""
+        else:
+            tenant_text = "/"+self._get_tenant()
+        if not uuid:
+            #check that exist
+            uuid = self._get_item_uuid(item, uuid, name, all_tenants)
+        
+        URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
+        self.logger.debug("DELETE %s", URLrequest )
+        mano_response = requests.delete(URLrequest, headers = self.headers_req)
+        self.logger.debug("openmano response: %s", mano_response.text )
+    
+        content = self._parse_yaml(mano_response.text, response=True)
+        if mano_response.status_code==200:
+            return content
+        else:
+            raise OpenmanoResponseException(str(content))        
+    
+    def _list_item(self, item, all_tenants=False, filter_dict=None):
+        if all_tenants:
+            tenant_text = "/any"
+        elif all_tenants==None:
+            tenant_text = ""
+        else:
+            tenant_text = "/"+self._get_tenant()
+        
+        URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
+        separator="?"
+        if filter_dict:
+            for k in filter_dict:
+                URLrequest += separator + quote(str(k)) + "=" + quote(str(filter_dict[k])) 
+                separator = "&"
+        self.logger.debug("openmano GET %s", URLrequest)
+        mano_response = requests.get(URLrequest, headers=self.headers_req)
+        self.logger.debug("openmano response: %s", mano_response.text )
+    
+        content = self._parse_yaml(mano_response.text, response=True)
+        if mano_response.status_code==200:
+            return content
+        else:
+            raise OpenmanoResponseException(str(content))        
+
+    def _edit_item(self, item, descriptor, uuid=None, name=None, all_tenants=False):
+        if all_tenants:
+            tenant_text = "/any"
+        elif all_tenants==None:
+            tenant_text = ""
+        else:
+            tenant_text = "/"+self._get_tenant()
+
+        if not uuid:
+            #check that exist
+            uuid = self._get_item_uuid("tenants", uuid, name, all_tenants)
+        
+        payload_req = yaml.safe_dump(descriptor)
+            
+        #print payload_req
+            
+        URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
+        self.logger.debug("openmano PUT %s %s", URLrequest, payload_req)
+        mano_response = requests.put(URLrequest, headers = self.headers_req, data=payload_req)
+        self.logger.debug("openmano response: %s", mano_response.text )
+    
+        content = self._parse_yaml(mano_response.text, response=True)
+        if mano_response.status_code==200:
+            return content
+        else:
+            raise OpenmanoResponseException(str(content))        
+
+    #TENANTS
+    def list_tenants(self, **kwargs):
+        '''Obtain a list of tenants
+        Params: can be filtered by 'uuid','name','description'
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'tenants':[{tenant1_info},{tenant2_info},...]}}
+        '''
+        return self._list_item("tenants", all_tenants=None, filter_dict=kwargs)
+
+    def get_tenant(self, uuid=None, name=None):
+        '''Obtain the information of a tenant
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several
+                Obtain a dictionary with format {'tenant':{tenant_info}}
+        '''
+        return self._get_item("tenants", uuid, name, all_tenants=None)
+
+    def delete_tenant(self, uuid=None, name=None):
+        '''Delete a tenant
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several
+                Obtain a dictionary with format {'result': text indicating deleted}
+        '''
+        return self._del_item("tenants", uuid, name, all_tenants=None)
+
+    def create_tenant(self, descriptor=None, descriptor_format=None, name=None, description=None):
+        '''Creates a tenant
+        Params: must supply a descriptor or/and just a name
+            descriptor: with format {'tenant':{new_tenant_info}}
+                newtenant_info must contain 'name', and optionally 'description'
+                must be a dictionary or a json/yaml text.
+            name: the tenant name. Overwrite descriptor name if any
+            description: tenant descriptor.. Overwrite descriptor description if any
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'tenant':{new_tenant_info}}
+        '''
+        if isinstance(descriptor, str):
+            descriptor = self._parse(descriptor, descriptor_format)
+        elif descriptor:
+            pass
+        elif name:
+            descriptor={"tenant": {"name": name}}
+        else:
+            raise OpenmanoBadParamsException("Missing descriptor")
+
+        if 'tenant' not in descriptor or len(descriptor)!=1:
+            raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
+        if name:
+            descriptor['tenant']['name'] = name
+        if description:
+            descriptor['tenant']['description'] = description
+
+        return self._create_item("tenants", descriptor, all_tenants=None)
+
+    def edit_tenant(self, uuid=None, name=None, descriptor=None, descriptor_format=None, new_name=None, new_description=None):
+        '''Edit the parameters of a tenant
+        Params: must supply a descriptor or/and a new_name or new_description
+            uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+            descriptor: with format {'tenant':{params to change info}}
+                must be a dictionary or a json/yaml text.
+            name: the tenant name. Overwrite descriptor name if any
+            description: tenant descriptor.. Overwrite descriptor description if any
+        Return: Raises an exception on error, not found or found several
+                Obtain a dictionary with format {'tenant':{newtenant_info}}
+        '''
+
+        if isinstance(descriptor, str):
+            descriptor = self.parse(descriptor, descriptor_format)
+        elif descriptor:
+            pass
+        elif new_name or new_description:
+            descriptor={"tenant": {}}
+        else:
+            raise OpenmanoBadParamsException("Missing descriptor")
+
+        if 'tenant' not in descriptor or len(descriptor)!=1:
+            raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
+        if new_name:
+            descriptor['tenant']['name'] = new_name
+        if new_description:
+            descriptor['tenant']['description'] = new_description
+
+        return self._edit_item("tenants", descriptor, uuid, name, all_tenants=None)
+
+    #DATACENTERS
+
+    def list_datacenters(self, all_tenants=False, **kwargs):
+        '''Obtain a list of datacenters, that are the VIM information at openmano
+        Params: can be filtered by 'uuid','name','vim_url','type'
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'datacenters':[{datacenter1_info},{datacenter2_info},...]}}
+        '''
+        return self._list_item("datacenters", all_tenants, filter_dict=kwargs)
+
+    def get_datacenter(self, uuid=None, name=None, all_tenants=False):
+        '''Obtain the information of a datacenter
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several
+                Obtain a dictionary with format {'datacenter':{datacenter_info}}
+        '''
+        return self._get_item("datacenters", uuid, name, all_tenants)
+
+    def delete_datacenter(self, uuid=None, name=None):
+        '''Delete a datacenter
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several, not free
+                Obtain a dictionary with format {'result': text indicating deleted}
+        '''
+        if not uuid:
+            # check that exist
+            uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=True)
+        return self._del_item("datacenters", uuid, name, all_tenants=None)
+
+    def create_datacenter(self, descriptor=None, descriptor_format=None, name=None, vim_url=None, **kwargs):
+#, type="openvim", public=False, description=None):
+        '''Creates a datacenter
+        Params: must supply a descriptor or/and just a name and vim_url
+            descriptor: with format {'datacenter':{new_datacenter_info}}
+                newdatacenter_info must contain 'name', 'vim_url', and optionally 'description'
+                must be a dictionary or a json/yaml text.
+            name: the datacenter name. Overwrite descriptor name if any
+            vim_url: the datacenter URL. Overwrite descriptor vim_url if any
+            vim_url_admin: the datacenter URL for administrative issues. Overwrite descriptor vim_url if any
+            vim_type: the datacenter type, can be openstack or openvim. Overwrite descriptor type if any
+            public: boolean, by default not public
+            description: datacenter description. Overwrite descriptor description if any
+            config: dictionary with extra configuration for the concrete datacenter
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
+        '''
+        if isinstance(descriptor, str):
+            descriptor = self.parse(descriptor, descriptor_format)
+        elif descriptor:
+            pass
+        elif name and vim_url:
+            descriptor={"datacenter": {"name": name, "vim_url": vim_url}}
+        else:
+            raise OpenmanoBadParamsException("Missing descriptor, or name and vim_url")
+        
+        if 'datacenter' not in descriptor or len(descriptor)!=1:
+            raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
+        if name:
+            descriptor['datacenter']['name'] = name
+        if vim_url:
+            descriptor['datacenter']['vim_url'] = vim_url
+        for param in kwargs:
+            descriptor['datacenter'][param] = kwargs[param]
+
+        return self._create_item("datacenters", descriptor, all_tenants=None)
+
+    def edit_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
+        '''Edit the parameters of a datacenter
+        Params: must supply a descriptor or/and a parameter to change
+            uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+            descriptor: with format {'datacenter':{params to change info}}
+                must be a dictionary or a json/yaml text.
+            parameters to change can be supplyied by the descriptor or as parameters:
+                new_name: the datacenter name
+                vim_url: the datacenter URL
+                vim_url_admin: the datacenter URL for administrative issues
+                vim_type: the datacenter type, can be openstack or openvim.
+                public: boolean, available to other tenants
+                description: datacenter description
+        Return: Raises an exception on error, not found or found several
+                Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
+        '''
+
+        if isinstance(descriptor, str):
+            descriptor = self.parse(descriptor, descriptor_format)
+        elif descriptor:
+            pass
+        elif kwargs:
+            descriptor={"datacenter": {}}
+        else:
+            raise OpenmanoBadParamsException("Missing descriptor")
+
+        if 'datacenter' not in descriptor or len(descriptor)!=1:
+            raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
+        for param in kwargs:
+            if param=='new_name':
+                descriptor['datacenter']['name'] = kwargs[param]
+            else:
+                descriptor['datacenter'][param] = kwargs[param]
+        return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None)
+    
+    def attach_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None,  vim_user=None, vim_password=None, vim_tenant_name=None, vim_tenant_id=None):
+        #check that exist
+        uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=True)
+        tenant_text = "/"+self._get_tenant()
+
+        if isinstance(descriptor, str):
+            descriptor = self.parse(descriptor, descriptor_format)
+        elif descriptor:
+            pass
+        elif vim_user or vim_password or vim_tenant_name or vim_tenant_id:
+            descriptor={"datacenter": {}}
+        else:
+            raise OpenmanoBadParamsException("Missing descriptor or params")
+        
+        if vim_user or vim_password or vim_tenant_name or vim_tenant_id:
+            #print args.name
+            try:
+                if vim_user:
+                    descriptor['datacenter']['vim_user'] = vim_user
+                if vim_password:
+                    descriptor['datacenter']['vim_password'] = vim_password
+                if vim_tenant_name:
+                    descriptor['datacenter']['vim_tenant_name'] = vim_tenant_name
+                if vim_tenant_id:
+                    descriptor['datacenter']['vim_tenant'] = vim_tenant_id
+            except (KeyError, TypeError) as e:
+                if str(e)=='datacenter':           error_pos= "missing field 'datacenter'"
+                else:                       error_pos="wrong format"
+                raise OpenmanoBadParamsException("Wrong datacenter descriptor: " + error_pos)
+
+        payload_req = yaml.safe_dump(descriptor)
+        #print payload_req
+        URLrequest = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid)
+        self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
+        mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
+        self.logger.debug("openmano response: %s", mano_response.text )
+    
+        content = self._parse_yaml(mano_response.text, response=True)
+        if mano_response.status_code==200:
+            return content
+        else:
+            raise OpenmanoResponseException(str(content))        
+
+    def detach_datacenter(self, uuid=None, name=None):
+        if not uuid:
+            #check that exist
+            uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=False)
+        tenant_text = "/"+self._get_tenant()
+        URLrequest = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid)
+        self.logger.debug("openmano DELETE %s", URLrequest)
+        mano_response = requests.delete(URLrequest, headers = self.headers_req)
+        self.logger.debug("openmano response: %s", mano_response.text )
+    
+        content = self._parse_yaml(mano_response.text, response=True)
+        if mano_response.status_code==200:
+            return content
+        else:
+            raise OpenmanoResponseException(str(content))        
+
+    #VNFS
+    def list_vnfs(self, all_tenants=False, **kwargs):
+        '''Obtain a list of vnfs
+        Params: can be filtered by 'uuid','name','description','public', "tenant_id"
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'vnfs':[{vnf1_info},{vnf2_info},...]}}
+        '''
+        return self._list_item("vnfs", all_tenants, kwargs)
+
+    def get_vnf(self, uuid=None, name=None, all_tenants=False):
+        '''Obtain the information of a vnf
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several
+                Obtain a dictionary with format {'vnf':{vnf_info}}
+        '''
+        return self._get_item("vnfs", uuid, name, all_tenants)
+
+    def delete_vnf(self, uuid=None, name=None, all_tenants=False):
+        '''Delete a vnf
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several, not free
+                Obtain a dictionary with format {'result': text indicating deleted}
+        '''
+        return self._del_item("vnfs", uuid, name, all_tenants)
+
+    def create_vnf(self, descriptor=None, descriptor_format=None, **kwargs):
+        '''Creates a vnf
+        Params: must supply a descriptor
+            descriptor: with format {'vnf':{new_vnf_info}}
+                must be a dictionary or a json/yaml text.
+                must be a dictionary or a json/yaml text.
+            Other parameters can be:
+                name: the vnf name. Overwrite descriptor name if any
+                image_path: Can be a string or a string list. Overwrite the image_path at descriptor
+                description: vnf descriptor.. Overwrite descriptor description if any
+                public: boolean, available to other tenants
+                class: user text for vnf classification
+                tenant_id: Propietary tenant
+                ...
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'vnf':{new_vnf_info}}
+        '''
+        if isinstance(descriptor, str):
+            descriptor = self.parse(descriptor, descriptor_format)
+        elif descriptor:
+            pass
+        else:
+            raise OpenmanoBadParamsException("Missing descriptor")
+        
+        if 'vnf' not in descriptor or len(descriptor)>2:
+            raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field, and an optional version")
+        for param in kwargs:
+            if param == 'image_path':
+                #print args.name
+                try:
+                    if isinstance(kwargs[param], str):
+                        descriptor['vnf']['VNFC'][0]['VNFC image']=kwargs[param]
+                    elif isinstance(kwargs[param], tuple) or isinstance(kwargs[param], list):
+                        index=0
+                        for image_path_ in kwargs[param]:
+                            #print "image-path", image_path_
+                            descriptor['vnf']['VNFC'][index]['VNFC image']=image_path_
+                            index=index+1
+                    else:
+                        raise OpenmanoBadParamsException("Wrong image_path type. Expected text or a text list")
+                except (KeyError, TypeError) as e:
+                    if str(e)=='vnf':           error_pos= "missing field 'vnf'"
+                    elif str(e)=='VNFC':        error_pos= "missing field  'vnf':'VNFC'"
+                    elif str(e)==str(index):    error_pos= "field  'vnf':'VNFC' must be an array"
+                    elif str(e)=='VNFC image':  error_pos= "missing field 'vnf':'VNFC'['VNFC image']"
+                    else:                       error_pos="wrong format"
+                    raise OpenmanoBadParamsException("Wrong VNF descriptor: " + error_pos)
+            else:
+                descriptor['vnf'][param] = kwargs[param]
+        return self._create_item("vnfs", descriptor)
+
+#     def edit_vnf(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
+#         '''Edit the parameters of a vnf
+#         Params: must supply a descriptor or/and a parameters to change
+#             uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+#             descriptor: with format {'vnf':{params to change info}}
+#             parameters to change can be supplyied by the descriptor or as parameters:
+#                 new_name: the vnf name
+#                 vim_url: the vnf URL
+#                 vim_url_admin: the vnf URL for administrative issues
+#                 vim_type: the vnf type, can be openstack or openvim.
+#                 public: boolean, available to other tenants
+#                 description: vnf description
+#         Return: Raises an exception on error, not found or found several
+#                 Obtain a dictionary with format {'vnf':{new_vnf_info}}
+#         '''
+# 
+#        if isinstance(descriptor, str):
+#            descriptor = self.parse(descriptor, descriptor_format)
+#        elif descriptor:
+#            pass
+#         elif kwargs:
+#             descriptor={"vnf": {}}
+#         else:
+#             raise OpenmanoBadParamsException("Missing descriptor")
+# 
+#         if 'vnf' not in descriptor or len(descriptor)>2:
+#             raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field")
+#         for param in kwargs:
+#             if param=='new_name':
+#                 descriptor['vnf']['name'] = kwargs[param]
+#             else:
+#                 descriptor['vnf'][param] = kwargs[param]
+#         return self._edit_item("vnfs", descriptor, uuid, name, all_tenants=None)
+
+    #SCENARIOS
+    def list_scenarios(self, all_tenants=False, **kwargs):
+        '''Obtain a list of scenarios
+        Params: can be filtered by 'uuid','name','description','public', "tenant_id"
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'scenarios':[{scenario1_info},{scenario2_info},...]}}
+        '''
+        return self._list_item("scenarios", all_tenants, kwargs)
+
+    def get_scenario(self, uuid=None, name=None, all_tenants=False):
+        '''Obtain the information of a scenario
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several
+                Obtain a dictionary with format {'scenario':{scenario_info}}
+        '''
+        return self._get_item("scenarios", uuid, name, all_tenants)
+
+    def delete_scenario(self, uuid=None, name=None, all_tenants=False):
+        '''Delete a scenario
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several, not free
+                Obtain a dictionary with format {'result': text indicating deleted}
+        '''
+        return self._del_item("scenarios", uuid, name, all_tenants)
+
+    def create_scenario(self, descriptor=None, descriptor_format=None, **kwargs):
+        '''Creates a scenario
+        Params: must supply a descriptor
+            descriptor: with format {'scenario':{new_scenario_info}}
+                must be a dictionary or a json/yaml text.
+            Other parameters can be:
+                name: the scenario name. Overwrite descriptor name if any
+                description: scenario descriptor.. Overwrite descriptor description if any
+                public: boolean, available to other tenants
+                tenant_id. Propietary tenant
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'scenario':{new_scenario_info}}
+        '''
+        if isinstance(descriptor, str):
+            descriptor = self.parse(descriptor, descriptor_format)
+        elif descriptor:
+            pass
+        else:
+            raise OpenmanoBadParamsException("Missing descriptor")
+        
+        if 'scenario' not in descriptor or len(descriptor)>2:
+            raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field, and an optional version")
+        for param in kwargs:
+            descriptor['scenario'][param] = kwargs[param]
+        return self._create_item("scenarios", descriptor)
+
+    def edit_scenario(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
+        '''Edit the parameters of a scenario
+        Params: must supply a descriptor or/and a parameters to change
+            uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+            descriptor: with format {'scenario':{params to change info}}
+                must be a dictionary or a json/yaml text.
+            parameters to change can be supplyied by the descriptor or as parameters:
+                new_name: the scenario name
+                public: boolean, available to other tenants
+                description: scenario description
+                tenant_id. Propietary tenant
+        Return: Raises an exception on error, not found or found several
+                Obtain a dictionary with format {'scenario':{new_scenario_info}}
+        '''
+        if isinstance(descriptor, str):
+            descriptor = self.parse(descriptor, descriptor_format)
+        elif descriptor:
+            pass
+        elif kwargs:
+            descriptor={"scenario": {}}
+        else:
+            raise OpenmanoBadParamsException("Missing descriptor")
+        if 'scenario' not in descriptor or len(descriptor)>2:
+            raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field")
+        for param in kwargs:
+            if param=='new_name':
+                descriptor['scenario']['name'] = kwargs[param]
+            else:
+                descriptor['scenario'][param] = kwargs[param]
+        return self._edit_item("scenarios", descriptor, uuid, name, all_tenants=None)
+
+
+    #INSTANCE-SCENARIOS
+    def list_instances(self, all_tenants=False, **kwargs):
+        '''Obtain a list of instances
+        Params: can be filtered by 'uuid','name','description','scenario_id', "tenant_id"
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'instances':[{instance1_info},{instance2_info},...]}}
+        '''
+        return self._list_item("instances", all_tenants, kwargs)
+
+    def get_instance(self, uuid=None, name=None, all_tenants=False):
+        '''Obtain the information of a instance
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several
+                Obtain a dictionary with format {'instance':{instance_info}}
+        '''
+        return self._get_item("instances", uuid, name, all_tenants)
+
+    def delete_instance(self, uuid=None, name=None, all_tenants=False):
+        '''Delete a instance
+        Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
+        Return: Raises an exception on error, not found, found several, not free
+                Obtain a dictionary with format {'result': text indicating deleted}
+        '''
+        return self._del_item("instances", uuid, name, all_tenants)
+
+    def create_instance(self, descriptor=None, descriptor_format=None, name=None, **kwargs):
+        '''Creates a instance
+        Params: must supply a descriptor or/and a name and scenario
+            descriptor: with format {'instance':{new_instance_info}}
+                must be a dictionary or a json/yaml text.
+            name: the instance name. Overwrite descriptor name if any
+            Other parameters can be:
+                description: instance descriptor.. Overwrite descriptor description if any
+                datacenter_name, datacenter_id: datacenter  where to be deployed
+                scenario_name, scenario_id: Scenario this instance is based on
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'instance':{new_instance_info}}
+        '''
+        if isinstance(descriptor, str):
+            descriptor = self.parse(descriptor, descriptor_format)
+        elif descriptor:
+            pass
+        elif name and ("scenario_name" in kwargs or "scenario_id" in kwargs):
+            descriptor = {"instance":{"name": name}}
+        else:
+            raise OpenmanoBadParamsException("Missing descriptor")
+        
+        if 'instance' not in descriptor or len(descriptor)>2:
+            raise OpenmanoBadParamsException("Descriptor must contain only one 'instance' field, and an optional version")
+        if name:
+            descriptor['instance']["name"] = name
+        if "scenario_name" in kwargs or "scenario_id" in kwargs:
+            descriptor['instance']["scenario"] = self._get_item_uuid("scenarios", kwargs.get("scenario_id"), kwargs.get("scenario_name"))
+        if "datacenter_name" in kwargs or "datacenter_id" in kwargs:
+            descriptor['instance']["datacenter"] = self._get_item_uuid("datacenters", kwargs.get("datacenter_id"), kwargs.get("datacenter_name"))
+        if "description" in kwargs:
+            descriptor['instance']["description"] = kwargs.get("description")
+        #for param in kwargs:
+        #    descriptor['instance'][param] = kwargs[param]
+        if "datacenter" not in descriptor['instance']:
+            descriptor['instance']["datacenter"] = self._get_datacenter()
+        return self._create_item("instances", descriptor)
+
+    #VIM ACTIONS
+    def vim_action(self, action, item, uuid=None, all_tenants=False, **kwargs):
+        '''Perform an action over a vim
+        Params: 
+            action: can be 'list', 'get'/'show', 'delete' or 'create'
+            item: can be 'tenants' or 'networks'
+            uuid: uuid of the tenant/net to show or to delete. Ignore otherwise
+            other parameters:
+                datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter 
+                descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str 
+                    must be a dictionary or a json/yaml text.
+                name: for created tenant/net Overwrite descriptor name if any
+                description: tenant descriptor. Overwrite descriptor description if any
+                
+        Return: Raises an exception on error
+                Obtain a dictionary with format {'tenant':{new_tenant_info}}
+        '''
+        if item not in ("tenants", "networks", "images"):
+            raise OpenmanoBadParamsException("Unknown value for item '{}', must be 'tenants', 'nets' or "
+                                             "images".format(str(item)))
+
+        image_actions = ['list','get','show','delete']
+        if item == "images" and action not in image_actions:
+            raise OpenmanoBadParamsException("Only available actions for item '{}' are {}\n"
+                                             "Requested action was '{}'".format(item, ', '.join(image_actions), action))
+        if all_tenants:
+            tenant_text = "/any"
+        else:
+            tenant_text = "/"+self._get_tenant()
+        
+        if "datacenter_id" in kwargs or "datacenter_name" in kwargs:
+            datacenter = self._get_item_uuid("datacenters", kwargs.get("datacenter_id"), kwargs.get("datacenter_name"), all_tenants=all_tenants)
+        else:
+            datacenter = self._get_datacenter()
+
+        if action=="list":
+            URLrequest = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
+            self.logger.debug("GET %s", URLrequest )
+            mano_response = requests.get(URLrequest, headers=self.headers_req)
+            self.logger.debug("openmano response: %s", mano_response.text )
+            content = self._parse_yaml(mano_response.text, response=True)            
+            if mano_response.status_code==200:
+                return content
+            else:
+                raise OpenmanoResponseException(str(content))        
+        elif action=="get" or action=="show":
+            URLrequest = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
+            self.logger.debug("GET %s", URLrequest )
+            mano_response = requests.get(URLrequest, headers=self.headers_req)
+            self.logger.debug("openmano response: %s", mano_response.text )
+            content = self._parse_yaml(mano_response.text, response=True)            
+            if mano_response.status_code==200:
+                return content
+            else:
+                raise OpenmanoResponseException(str(content))        
+        elif action=="delete":
+            URLrequest = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
+            self.logger.debug("DELETE %s", URLrequest )
+            mano_response = requests.delete(URLrequest, headers=self.headers_req)
+            self.logger.debug("openmano response: %s", mano_response.text )
+            content = self._parse_yaml(mano_response.text, response=True)            
+            if mano_response.status_code==200:
+                return content
+            else:
+                raise OpenmanoResponseException(str(content))        
+        elif action=="create":
+            if "descriptor" in kwargs:
+                if isinstance(kwargs["descriptor"], str):
+                    descriptor = self._parse(kwargs["descriptor"], kwargs.get("descriptor_format") )
+                else:
+                    descriptor = kwargs["descriptor"]
+            elif "name" in kwargs:
+                descriptor={item[:-1]: {"name": kwargs["name"]}}
+            else:
+                raise OpenmanoResponseException("Missing descriptor")
+        
+            if item[:-1] not in descriptor or len(descriptor)!=1:
+                raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
+            if "name" in kwargs:
+                descriptor[ item[:-1] ]['name'] = kwargs["name"]
+            if "description" in kwargs:
+                descriptor[ item[:-1] ]['description'] = kwargs["description"]
+            payload_req = yaml.safe_dump(descriptor)
+            #print payload_req
+            URLrequest = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
+            self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
+            mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
+            self.logger.debug("openmano response: %s", mano_response.text )
+            content = self._parse_yaml(mano_response.text, response=True)
+            if mano_response.status_code==200:
+                return content
+            else:
+                raise OpenmanoResponseException(str(content))
+        else:
+            raise OpenmanoBadParamsException("Unknown value for action '{}".format(str(action))) 
+
diff --git a/osm_ro/utils.py b/osm_ro/utils.py
new file mode 100644 (file)
index 0000000..00f6f2d
--- /dev/null
@@ -0,0 +1,181 @@
+# -*- 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
+##
+
+'''
+utils is a module that implements functions that are used by all openmano modules,
+dealing with aspects such as reading/writing files, formatting inputs/outputs for quick translation
+from dictionaries to appropriate database dictionaries, etc.
+'''
+__author__="Alfonso Tierno, Gerardo Garcia"
+__date__ ="$08-sep-2014 12:21:22$"
+
+import datetime
+from jsonschema import validate as js_v, exceptions as js_e
+#from bs4 import BeautifulSoup
+
+def read_file(file_to_read):
+    """Reads a file specified by 'file_to_read' and returns (True,<its content as a string>) in case of success or (False, <error message>) in case of failure"""
+    try:
+        f = open(file_to_read, 'r')
+        read_data = f.read()
+        f.close()
+    except Exception as e:
+        return (False, str(e))
+      
+    return (True, read_data)
+
+def write_file(file_to_write, text):
+    """Write a file specified by 'file_to_write' and returns (True,NOne) in case of success or (False, <error message>) in case of failure"""
+    try:
+        f = open(file_to_write, 'w')
+        f.write(text)
+        f.close()
+    except Exception as e:
+        return (False, str(e))
+      
+    return (True, None)
+
+def format_in(http_response, schema):
+    try:
+        client_data = http_response.json()
+        js_v(client_data, schema)
+        #print "Input data: ", str(client_data)
+        return True, client_data
+    except js_e.ValidationError as exc:
+        print "validate_in error, jsonschema exception ", exc.message, "at", exc.path
+        return False, ("validate_in error, jsonschema exception ", exc.message, "at", exc.path)
+
+def remove_extra_items(data, schema):
+    deleted=[]
+    if type(data) is tuple or type(data) is list:
+        for d in data:
+            a= remove_extra_items(d, schema['items'])
+            if a is not None: deleted.append(a)
+    elif type(data) is dict:
+        #TODO deal with patternProperties
+        if 'properties' not in schema:
+            return None
+        for k in data.keys():
+            if k not in schema['properties'].keys():
+                del data[k]
+                deleted.append(k)
+            else:
+                a = remove_extra_items(data[k], schema['properties'][k])
+                if a is not None:  deleted.append({k:a})
+    if len(deleted) == 0: return None
+    elif len(deleted) == 1: return deleted[0]
+    else: return deleted
+
+#def format_html2text(http_content):
+#    soup=BeautifulSoup(http_content)
+#    text = soup.p.get_text() + " " + soup.pre.get_text()
+#    return text
+
+
+def convert_bandwidth(data, reverse=False):
+    '''Check the field bandwidth recursivelly and when found, it removes units and convert to number 
+    It assumes that bandwidth is well formed
+    Attributes:
+        'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
+        'reverse': by default convert form str to int (Mbps), if True it convert from number to units
+    Return:
+        None
+    '''
+    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)
+        if "bandwidth" in data:
+            try:
+                value=str(data["bandwidth"])
+                if not reverse:
+                    pos = value.find("bps")
+                    if pos>0:
+                        if value[pos-1]=="G": data["bandwidth"] =  int(data["bandwidth"][:pos-1]) * 1000
+                        elif value[pos-1]=="k": data["bandwidth"]= int(data["bandwidth"][:pos-1]) / 1000
+                        else: data["bandwidth"]= int(data["bandwidth"][:pos-1])
+                else:
+                    value = int(data["bandwidth"])
+                    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"]
+                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)
+
+
+
+def convert_datetime2str(var):
+    '''Converts a datetime variable to a string with the format '%Y-%m-%dT%H:%i:%s'
+    It enters recursively in the dict var finding this kind of variables
+    '''
+    if type(var) is dict:
+        for k,v in var.items():
+            if type(v) is datetime.datetime:
+                var[k]= v.strftime('%Y-%m-%dT%H:%M:%S')
+            elif type(v) is dict or type(v) is list or type(v) is tuple: 
+                convert_datetime2str(v)
+        if len(var) == 0: return True
+    elif type(var) is list or type(var) is tuple:
+        for v in var:
+            convert_datetime2str(v)
+
+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 
+    Done recursively
+    Attributes:
+        'data': dictionary variable to be checked. None or empty is considered valid
+        'items': tuple of keys to convert
+    Return:
+        None
+    '''
+    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_str2boolean(data[k], items)
+            if k in items:
+                if type(data[k]) is str:
+                    if   data[k]=="false" or data[k]=="False": data[k]=False
+                    elif data[k]=="true"  or data[k]=="True":  data[k]=True
+    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_str2boolean(k, items)
+
+def check_valid_uuid(uuid):
+    id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
+    id_schema2 = {"type" : "string", "pattern": "^[a-fA-F0-9]{32}$"}
+    try:
+        js_v(uuid, id_schema)
+        return True
+    except js_e.ValidationError:
+        try:
+            js_v(uuid, id_schema2)
+            return True
+        except js_e.ValidationError:
+            return False
+    return False
+    
diff --git a/osm_ro/vim_thread.py b/osm_ro/vim_thread.py
new file mode 100644 (file)
index 0000000..42279a2
--- /dev/null
@@ -0,0 +1,226 @@
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openvim
+# 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
+##
+
+'''
+This is thread that interact with the host and the libvirt to manage VM
+One thread will be launched per host 
+'''
+__author__ = "Alfonso Tierno"
+__date__ = "$10-feb-2017 12:07:15$"
+
+import threading
+import time
+import Queue
+import logging
+import vimconn
+from db_base import db_base_Exception
+
+
+# from logging import Logger
+# import auxiliary_functions as af
+
+
+def is_task_id(id):
+    return True if id[:5] == "TASK." else False
+
+
+class vim_thread(threading.Thread):
+
+    def __init__(self, vimconn, task_lock, name=None, datacenter_name=None, datacenter_tenant_id=None, db=None, db_lock=None):
+        """Init a thread.
+        Arguments:
+            'id' number of thead
+            'name' name of thread
+            'host','user':  host ip or name to manage and user
+            'db', 'db_lock': database class and lock to use it in exclusion
+        """
+        self.tasksResult = {}
+        """ It will contain a dictionary with
+            task_id:
+                status: enqueued,done,error,deleted,processing
+                result: VIM result,
+        """
+        threading.Thread.__init__(self)
+        self.vim = vimconn
+        self.datacenter_name = datacenter_name
+        self.datacenter_tenant_id = datacenter_tenant_id
+        if not name:
+            self.name = vimconn["id"] + "." + vimconn["config"]["datacenter_tenant_id"]
+        else:
+            self.name = name
+
+        self.logger = logging.getLogger('openmano.vim.'+self.name)
+        self.db = db
+        self.db_lock = db_lock
+
+        self.task_lock = task_lock
+        self.task_queue = Queue.Queue(2000)
+
+    def insert_task(self, task):
+        try:
+            self.task_queue.put(task, False)
+            return task["id"]
+        except Queue.Full:
+            raise vimconn.vimconnException(self.name + ": timeout inserting a task")
+
+    def del_task(self, task):
+        with self.task_lock:
+            if task["status"] == "enqueued":
+                task["status"] == "deleted"
+                return True
+            else:   # task["status"] == "processing"
+                self.task_lock.release()
+                return False
+
+    def run(self):
+        self.logger.debug("Starting")
+        while True:
+            #TODO reload service
+            while True:
+                if not self.task_queue.empty():
+                    task = self.task_queue.get()
+                    self.task_lock.acquire()
+                    if task["status"] == "deleted":
+                        self.task_lock.release()
+                        continue
+                    task["status"] == "processing"
+                    self.task_lock.release()
+                else:
+                    now=time.time()
+                    time.sleep(1)
+                    continue
+                self.logger.debug("processing task id={} name={} params={}".format(task["id"], task["name"],
+                                                                                   str(task["params"])))
+                if task["name"] == 'exit' or task["name"] == 'reload':
+                    result, content = self.terminate(task)
+                elif task["name"] == 'new-vm':
+                    result, content = self.new_vm(task)
+                elif task["name"] == 'del-vm':
+                    result, content = self.del_vm(task)
+                elif task["name"] == 'new-net':
+                    result, content = self.new_net(task)
+                elif task["name"] == 'del-net':
+                    result, content = self.del_net(task)
+                else:
+                    error_text = "unknown task {}".format(task["name"])
+                    self.logger.error(error_text)
+                    result = False
+                    content = error_text
+
+                with self.task_lock:
+                    task["status"] = "done" if result else "error"
+                    task["result"] = content
+                self.task_queue.task_done()
+
+                if task["name"] == 'exit':
+                    return 0
+                elif task["name"] == 'reload':
+                    break
+
+        self.logger.debug("Finishing")
+
+    def terminate(self, task):
+        return True, None
+
+    def new_net(self, task):
+        try:
+            task_id = task["id"]
+            params = task["params"]
+            net_id = self.vim.new_network(*params)
+            with self.db_lock:
+                self.db.update_rows("instance_nets", UPDATE={"vim_net_id": net_id}, WHERE={"vim_net_id": task_id})
+            return True, net_id
+        except db_base_Exception as e:
+            self.logger.error("Error updating database %s", str(e))
+            return True, net_id
+        except vimconn.vimconnException as e:
+            return False, str(e)
+
+    def new_vm(self, task):
+        try:
+            params = task["params"]
+            task_id = task["id"]
+            depends = task.get("depends")
+            net_list = params[5]
+            for net in net_list:
+                if is_task_id(net["net_id"]):  # change task_id into network_id
+                    try:
+                        task_net = depends[net["net_id"]]
+                        with self.task_lock:
+                            if task_net["status"] == "error":
+                                return False, "Cannot create VM because depends on a network that cannot be created: " + \
+                                       str(task_net["result"])
+                            elif task_net["status"] == "enqueued" or task_net["status"] == "processing":
+                                return False, "Cannot create VM because depends on a network still not created"
+                            network_id = task_net["result"]
+                        net["net_id"] = network_id
+                    except Exception as e:
+                        return False, "Error trying to map from task_id={} to task result: {}".format(net["net_id"],
+                                                                                                      str(e))
+            vm_id = self.vim.new_vminstance(*params)
+            with self.db_lock:
+                self.db.update_rows("instance_vms", UPDATE={"vim_vm_id": vm_id}, WHERE={"vim_vm_id": task_id})
+            return True, vm_id
+        except db_base_Exception as e:
+            self.logger.error("Error updtaing database %s", str(e))
+            return True, vm_id
+        except vimconn.vimconnException as e:
+            return False, str(e)
+
+    def del_vm(self, task):
+        vm_id = task["params"]
+        if is_task_id(vm_id):
+            try:
+                task_create = task["depends"][vm_id]
+                with self.task_lock:
+                    if task_create["status"] == "error":
+                        return True, "VM was not created. It has error: " + str(task_create["result"])
+                    elif task_create["status"] == "enqueued" or task_create["status"] == "processing":
+                        return False, "Cannot delete VM because still creating"
+                    vm_id = task_create["result"]
+            except Exception as e:
+                return False, "Error trying to get task_id='{}':".format(vm_id, str(e))
+        try:
+            return True, self.vim.delete_vminstance(vm_id)
+        except vimconn.vimconnException as e:
+            return False, str(e)
+
+    def del_net(self, task):
+        net_id = task["params"]
+        if is_task_id(net_id):
+            try:
+                task_create = task["depends"][net_id]
+                with self.task_lock:
+                    if task_create["status"] == "error":
+                        return True, "net was not created. It has error: " + str(task_create["result"])
+                    elif task_create["status"] == "enqueued" or task_create["status"] == "processing":
+                        return False, "Cannot delete net because still creating"
+                    net_id = task_create["result"]
+            except Exception as e:
+                return False, "Error trying to get task_id='{}':".format(net_id, str(e))
+        try:
+            return True, self.vim.delete_network(net_id)
+        except vimconn.vimconnException as e:
+            return False, str(e)
+
+
diff --git a/osm_ro/vimconn.py b/osm_ro/vimconn.py
new file mode 100644 (file)
index 0000000..a9bd9be
--- /dev/null
@@ -0,0 +1,506 @@
+# -*- 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
+##
+
+"""
+vimconn implement an Abstract class for the vim connector plugins
+ with the definition of the method to be implemented.
+"""
+__author__="Alfonso Tierno"
+__date__ ="$16-oct-2015 11:09:29$"
+
+import logging
+
+#Error variables 
+HTTP_Bad_Request = 400
+HTTP_Unauthorized = 401 
+HTTP_Not_Found = 404 
+HTTP_Method_Not_Allowed = 405 
+HTTP_Request_Timeout = 408
+HTTP_Conflict = 409
+HTTP_Not_Implemented = 501
+HTTP_Service_Unavailable = 503 
+HTTP_Internal_Server_Error = 500 
+
+class vimconnException(Exception):
+    """Common and base class Exception for all vimconnector exceptions"""
+    def __init__(self, message, http_code=HTTP_Bad_Request):
+        Exception.__init__(self, message)
+        self.http_code = http_code
+
+class vimconnConnectionException(vimconnException):
+    """Connectivity error with the VIM"""
+    def __init__(self, message, http_code=HTTP_Service_Unavailable):
+        vimconnException.__init__(self, message, http_code)
+    
+class vimconnUnexpectedResponse(vimconnException):
+    """Get an wrong response from VIM"""
+    def __init__(self, message, http_code=HTTP_Service_Unavailable):
+        vimconnException.__init__(self, message, http_code)
+
+class vimconnAuthException(vimconnException):
+    """Invalid credentials or authorization to perform this action over the VIM"""
+    def __init__(self, message, http_code=HTTP_Unauthorized):
+        vimconnException.__init__(self, message, http_code)
+
+class vimconnNotFoundException(vimconnException):
+    """The item is not found at VIM"""
+    def __init__(self, message, http_code=HTTP_Not_Found):
+        vimconnException.__init__(self, message, http_code)
+
+class vimconnConflictException(vimconnException):
+    """There is a conflict, e.g. more item found than one"""
+    def __init__(self, message, http_code=HTTP_Conflict):
+        vimconnException.__init__(self, message, http_code)
+
+class vimconnNotSupportedException(vimconnException):
+    """The request is not supported by connector"""
+    def __init__(self, message, http_code=HTTP_Service_Unavailable):
+        vimconnException.__init__(self, message, http_code)
+
+class vimconnNotImplemented(vimconnException):
+    """The method is not implemented by the connected"""
+    def __init__(self, message, http_code=HTTP_Not_Implemented):
+        vimconnException.__init__(self, message, http_code)
+
+class vimconnector():
+    """Abstract base class for all the VIM connector plugins
+    These plugins must implement a vimconnector class derived from this 
+    and all these privated methods
+    """ 
+    def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None,
+                 config={}, persitent_info={}):
+        """Constructor of VIM
+        Params:
+            'uuid': id asigned to this VIM
+            'name': name assigned to this VIM, can be used for logging
+            'tenant_id', 'tenant_name': (only one of them is mandatory) VIM tenant to be used
+            'url_admin': (optional), url used for administrative tasks
+            'user', 'passwd': credentials of the VIM user
+            'log_level': provider if it should 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 creation and particular VIM config at teh attachment
+            'persistent_info': dict where the class can store information that will be available among class
+                    destroy/creation cycles. This info is unique per VIM/credential. At first call it will contain an
+                    empty dict. Useful to store login/tokens information for speed up communication
+
+        Returns: Raise an exception is some needed parameter is missing, but it must not do any connectivity
+            check against the VIM
+        """
+        self.id        = uuid
+        self.name      = name
+        self.url       = url
+        self.url_admin = url_admin
+        self.tenant_id = tenant_id
+        self.tenant_name = tenant_name
+        self.user      = user
+        self.passwd    = passwd
+        self.config    = config
+        self.logger = logging.getLogger('openmano.vim')
+        if log_level:
+            self.logger.setLevel( getattr(logging, log_level) )
+        if not self.url_admin:  #try to use normal url 
+            self.url_admin = self.url
+    
+    def __getitem__(self,index):
+        if index=='tenant_id':
+            return self.tenant_id
+        if index=='tenant_name':
+            return self.tenant_name
+        elif index=='id':
+            return self.id
+        elif index=='name':
+            return self.name
+        elif index=='user':
+            return self.user
+        elif index=='passwd':
+            return self.passwd
+        elif index=='url':
+            return self.url
+        elif index=='url_admin':
+            return self.url_admin
+        elif index=="config":
+            return self.config
+        else:
+            raise KeyError("Invalid key '%s'" %str(index))
+        
+    def __setitem__(self,index, value):
+        if index=='tenant_id':
+            self.tenant_id = value
+        if index=='tenant_name':
+            self.tenant_name = value
+        elif index=='id':
+            self.id = value
+        elif index=='name':
+            self.name = value
+        elif index=='user':
+            self.user = value
+        elif index=='passwd':
+            self.passwd = value
+        elif index=='url':
+            self.url = value
+        elif index=='url_admin':
+            self.url_admin = value
+        else:
+            raise KeyError("Invalid key '%s'" %str(index))
+        
+    def check_vim_connectivity(self):
+        """Checks VIM can be reached and user credentials are ok.
+        Returns None if success or raised vimconnConnectionException, vimconnAuthException, ...
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def new_tenant(self,tenant_name,tenant_description):
+        """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
+        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 dictionary that can contain the following keys:
+            name: filter by tenant name
+            id: filter by tenant uuid/id
+            <other VIM specific>
+        Returns the tenant list of dictionaries, and empty list if no tenant match all the filers:
+            [{'name':'<name>, 'id':'<id>, ...}, ...]
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None):
+        """Adds a tenant network to VIM
+        Params:
+            'net_name': name of the network
+            'net_type': one of:
+                'bridge': overlay isolated network
+                'data':   underlay E-LAN network for Passthrough and SRIOV interfaces
+                'ptp':    underlay E-LINE network for Passthrough and SRIOV interfaces.
+            'ip_profile': is a dict containing the IP parameters of the network (Currently only IPv4 is implemented)
+                'ip-version': can be one of ["IPv4","IPv6"]
+                'subnet-address': ip_prefix_schema, that is X.X.X.X/Y
+                'gateway-address': (Optional) ip_schema, that is X.X.X.X
+                'dns-address': (Optional) ip_schema,
+                'dhcp': (Optional) dict containing
+                    'enabled': {"type": "boolean"},
+                    'start-address': ip_schema, first IP to grant
+                    'count': number of IPs to grant.
+            'shared': if this network can be seen/use by other tenants/organization
+            'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network
+        Returns the network identifier on success or raises and exception on failure
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def get_network_list(self, filter_dict={}):
+        """Obtain tenant networks of VIM
+        Params:
+            'filter_dict' (optional) contains entries to return only networks that matches ALL entries:
+                name: string  => returns only networks with this name
+                id:   string  => returns networks with this VIM id, this imply returns one network at most
+                shared: boolean >= returns only networks that are (or are not) shared
+                tenant_id: sting => returns only networks that belong to this tenant/project
+                ,#(not used yet) admin_state_up: boolean => returns only networks that are (or are not) in admin state active
+                #(not used yet) status: 'ACTIVE','ERROR',... => filter networks that are on this status
+        Returns the network list of dictionaries. each dictionary contains:
+            'id': (mandatory) VIM network id
+            'name': (mandatory) VIM network name
+            'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
+            'error_msg': (optional) text that explains the ERROR status
+            other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
+        List can be empty if no network map the filter_dict. Raise an exception only upon VIM connectivity,
+            authorization, or some other unspecific error
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def get_network(self, net_id):
+        """Obtain network details from the 'net_id' VIM network
+        Return a dict that contains:
+            'id': (mandatory) VIM network id, that is, net_id
+            'name': (mandatory) VIM network name
+            'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
+            'error_msg': (optional) text that explains the ERROR status
+            other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
+        Raises an exception upon error or when network is not found
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def delete_network(self, net_id):
+        """Deletes a tenant network from VIM
+        Returns the network identifier or raises an exception upon error or when network is not found
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def refresh_nets_status(self, net_list):
+        """Get the status of the networks
+        Params:
+            'net_list': a list with the VIM network id to be get the status
+        Returns a dictionary with:
+            'net_id':         #VIM id of this network
+                status:     #Mandatory. Text with one of:
+                    #  DELETED (not found at vim)
+                    #  VIM_ERROR (Cannot connect to VIM, authentication problems, VIM response error, ...)
+                    #  OTHER (Vim reported other status not understood)
+                    #  ERROR (VIM indicates an ERROR status)
+                    #  ACTIVE, INACTIVE, DOWN (admin down),
+                    #  BUILD (on building process)
+                error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR
+                vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+            'net_id2': ...
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def get_flavor(self, flavor_id):
+        """Obtain flavor details from the VIM
+        Returns the flavor dict details {'id':<>, 'name':<>, other vim specific }
+        Raises an exception upon error or if not found
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def get_flavor_id_from_data(self, flavor_dict):
+        """Obtain flavor id that match the flavor description
+        Params:
+            'flavor_dict': dictionary that contains:
+                'disk': main hard disk in GB
+                'ram': meomry in MB
+                'vcpus': number of virtual cpus
+                #TODO: complete parameters for EPA
+        Returns the flavor_id or raises a vimconnNotFoundException
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def new_flavor(self, flavor_data):
+        """Adds a tenant flavor to VIM
+            flavor_data contains a dictionary with information, keys:
+                name: flavor name
+                ram: memory (cloud type) in MBytes
+                vpcus: cpus (cloud type)
+                extended: EPA parameters
+                  - numas: #items requested in same NUMA
+                        memory: number of 1G huge pages memory
+                        paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
+                        interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
+                          - name: interface name
+                            dedicated: yes|no|yes:sriov;  for PT, SRIOV or only one SRIOV for the physical NIC
+                            bandwidth: X Gbps; requested guarantee bandwidth
+                            vpci: requested virtual PCI address   
+                disk: disk size
+                is_public:
+                 #TODO to concrete
+        Returns the flavor identifier"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def delete_flavor(self, flavor_id):
+        """Deletes a tenant flavor from VIM identify by its id
+        Returns the used id or raise an exception"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def new_image(self, image_dict):
+        """ Adds a tenant image to VIM
+        Returns the image id or raises an exception if failed
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def delete_image(self, image_id):
+        """Deletes a tenant image from VIM
+        Returns the image_id if image is deleted or raises an exception on error"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def get_image_id_from_path(self, path):
+        """Get the image id from image path in the VIM database.
+           Returns the image_id or raises a vimconnNotFoundException
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+        
+    def get_image_list(self, filter_dict={}):
+        """Obtain tenant images from VIM
+        Filter_dict can be:
+            name: image name
+            id: image uuid
+            checksum: image checksum
+            location: image path
+        Returns the image list of dictionaries:
+            [{<the fields at Filter_dict plus some VIM specific>}, ...]
+            List can be empty
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None,
+                       disk_list=None):
+        """Adds a VM instance to VIM
+        Params:
+            'start': (boolean) indicates if VM must start or created in pause mode.
+            'image_id','flavor_id': image and flavor VIM id to use for the VM
+            'net_list': list of interfaces, each one is a dictionary with:
+                'name': (optional) name for the interface.
+                'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual
+                'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM capabilities
+                'model': (optional and only have sense for type==virtual) interface model: virtio, e2000, ...
+                'mac_address': (optional) mac address to assign to this interface
+                #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not provided,
+                    the VLAN tag to be used. In case net_id is provided, the internal network vlan is used for tagging VF
+                'type': (mandatory) can be one of:
+                    'virtual', in this case always connected to a network of type 'net_type=bridge'
+                     'PF' (passthrough): depending on VIM capabilities it can be connected to a data/ptp network ot it
+                           can created unconnected
+                     'VF' (SRIOV with VLAN tag): same as PF for network connectivity.
+                     'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs
+                            are allocated on the same physical NIC
+                'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS
+                'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing
+                                or True, it must apply the default VIM behaviour
+                After execution the method will add the key:
+                'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this
+                        interface. 'net_list' is modified
+            'cloud_config': (optional) dictionary with:
+                'key-pairs': (optional) list of strings with the public key to be inserted to the default user
+                'users': (optional) list of users to be inserted, each item is a dict with:
+                    'name': (mandatory) user name,
+                    'key-pairs': (optional) list of strings with the public key to be inserted to the user
+                'user-data': (optional) string is a text script to be passed directly to cloud-init
+                'config-files': (optional). List of files to be transferred. Each item is a dict with:
+                    'dest': (mandatory) string with the destination absolute path
+                    'encoding': (optional, by default text). Can be one of:
+                        'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
+                    'content' (mandatory): string with the content of the file
+                    'permissions': (optional) string with file permissions, typically octal notation '0644'
+                    'owner': (optional) file owner, string with the format 'owner:group'
+                'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
+            'disk_list': (optional) list with additional disks to the VM. Each item is a dict with:
+                'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
+                'size': (mandatory) string with the size of the disk in GB
+        Returns the instance identifier or raises an exception on error
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+        
+    def get_vminstance(self,vm_id):
+        """Returns the VM instance information from VIM"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+        
+    def delete_vminstance(self, vm_id):
+        """Removes a VM instance from VIM
+        Returns the instance identifier"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def refresh_vms_status(self, vm_list):
+        """Get the status of the virtual machines and their interfaces/ports
+           Params: the list of VM identifiers
+           Returns a dictionary with:
+                vm_id:          #VIM id of this Virtual Machine
+                    status:     #Mandatory. Text with one of:
+                                #  DELETED (not found at vim)
+                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
+                                #  OTHER (Vim reported other status not understood)
+                                #  ERROR (VIM indicates an ERROR status)
+                                #  ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running), 
+                                #  BUILD (on building process), ERROR
+                                #  ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
+                                #
+                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
+                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+                    interfaces: list with interface info. Each item a dictionary with:
+                        vim_info:         #Text with plain information obtained from vim (yaml.safe_dump)
+                        mac_address:      #Text format XX:XX:XX:XX:XX:XX
+                        vim_net_id:       #network id where this interface is connected, if provided at creation
+                        vim_interface_id: #interface/port VIM id
+                        ip_address:       #null, or text with IPv4, IPv6 address
+                        physical_compute: #identification of compute node where PF,VF interface is allocated
+                        physical_pci:     #PCI address of the NIC that hosts the PF,VF
+                        physical_vlan:    #physical VLAN used for VF
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+    
+    def action_vminstance(self, vm_id, action_dict):
+        """Send and action over a VM instance from VIM
+        Returns the vm_id if the action was successfully sent to the VIM"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+    
+    def get_vminstance_console(self, vm_id, console_type="vnc"):
+        """
+        Get a console for the virtual machine
+        Params:
+            vm_id: uuid of the VM
+            console_type, can be:
+                "novnc" (by default), "xvpvnc" for VNC types, 
+                "rdp-html5" for RDP types, "spice-html5" for SPICE types
+        Returns dict with the console parameters:
+                protocol: ssh, ftp, http, https, ...
+                server:   usually ip address 
+                port:     the http, ssh, ... port 
+                suffix:   extra text, e.g. the http path and query string   
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+        
+#NOT USED METHODS in current version        
+
+    def host_vim2gui(self, host, server_dict):
+        """Transform host dictionary from VIM format to GUI format,
+        and append to the server_dict
+        """
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def get_hosts_info(self):
+        """Get the information of deployed hosts
+        Returns the hosts content"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def get_hosts(self, vim_tenant):
+        """Get the hosts and deployed instances
+        Returns the hosts content"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def get_processor_rankings(self):
+        """Get the processor rankings in the VIM database"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+    
+    def new_host(self, host_data):
+        """Adds a new host to VIM"""
+        """Returns status code of the VIM response"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+    
+    def new_external_port(self, port_data):
+        """Adds a external port to VIM"""
+        """Returns the port identifier"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+        
+    def new_external_network(self,net_name,net_type):
+        """Adds a external network to VIM (shared)"""
+        """Returns the network identifier"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def connect_port_network(self, port_id, network_id, admin=False):
+        """Connects a external port to a network"""
+        """Returns status code of the VIM response"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+
+    def new_vminstancefromJSON(self, vm_data):
+        """Adds a VM instance to VIM"""
+        """Returns the instance identifier"""
+        raise vimconnNotImplemented( "Should have implemented this" )
+
diff --git a/osm_ro/vimconn_openstack.py b/osm_ro/vimconn_openstack.py
new file mode 100644 (file)
index 0000000..b501d9d
--- /dev/null
@@ -0,0 +1,1336 @@
+# -*- 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
+##
+
+'''
+osconnector implements all the methods to interact with openstack using the python-client.
+'''
+__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research"
+__date__ ="$22-jun-2014 11:19:29$"
+
+import vimconn
+import json
+import yaml
+import logging
+import netaddr
+import time
+import yaml
+import random
+
+from novaclient import client as nClient_v2, exceptions as nvExceptions
+from novaclient import api_versions
+import keystoneclient.v2_0.client as ksClient_v2
+from novaclient.v2.client import Client as nClient
+import keystoneclient.v3.client as ksClient
+import keystoneclient.exceptions as ksExceptions
+import glanceclient.v2.client as glClient
+import glanceclient.client as gl1Client
+import glanceclient.exc as gl1Exceptions
+import cinderclient.v2.client as cClient_v2
+from httplib import HTTPException
+from neutronclient.neutron import client as neClient_v2
+from neutronclient.v2_0 import client as neClient
+from neutronclient.common import exceptions as neExceptions
+from requests.exceptions import ConnectionError
+
+'''contain the openstack virtual machine status to openmano status'''
+vmStatus2manoFormat={'ACTIVE':'ACTIVE',
+                     'PAUSED':'PAUSED',
+                     'SUSPENDED': 'SUSPENDED',
+                     'SHUTOFF':'INACTIVE',
+                     'BUILD':'BUILD',
+                     'ERROR':'ERROR','DELETED':'DELETED'
+                     }
+netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE','BUILD':'BUILD','ERROR':'ERROR','DELETED':'DELETED'
+                     }
+
+#global var to have a timeout creating and deleting volumes
+volume_timeout = 60
+server_timeout = 60
+
+class vimconnector(vimconn.vimconnector):
+    def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None,
+                 log_level=None, config={}, persistent_info={}):
+        '''using common constructor parameters. In this case
+        'url' is the keystone authorization url,
+        'url_admin' is not use
+        '''
+        self.osc_api_version = 'v2.0'
+        if config.get('APIversion') == 'v3.3':
+            self.osc_api_version = 'v3.3'
+        vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level, config)
+
+        self.persistent_info = persistent_info
+        self.k_creds={}
+        self.n_creds={}
+        if self.config.get("insecure"):
+            self.k_creds["insecure"] = True
+            self.n_creds["insecure"] = True
+        if not url:
+            raise TypeError, 'url param can not be NoneType'
+        self.k_creds['auth_url'] = url
+        self.n_creds['auth_url'] = url
+        if tenant_name:
+            self.k_creds['tenant_name'] = tenant_name
+            self.n_creds['project_id']  = tenant_name
+        if tenant_id:
+            self.k_creds['tenant_id'] = tenant_id
+            self.n_creds['tenant_id']  = tenant_id
+        if user:
+            self.k_creds['username'] = user
+            self.n_creds['username'] = user
+        if passwd:
+            self.k_creds['password'] = passwd
+            self.n_creds['api_key']  = passwd
+        if self.osc_api_version == 'v3.3':
+            self.k_creds['project_name'] = tenant_name
+            self.k_creds['project_id'] = tenant_id
+        if config.get('region_name'):
+            self.k_creds['region_name'] = config.get('region_name')
+            self.n_creds['region_name'] = config.get('region_name')
+
+        self.reload_client       = True
+        self.logger = logging.getLogger('openmano.vim.openstack')
+        if log_level:
+            self.logger.setLevel( getattr(logging, log_level) )
+    
+    def __setitem__(self,index, value):
+        '''Set individuals parameters 
+        Throw TypeError, KeyError
+        '''
+        if index=='tenant_id':
+            self.reload_client=True
+            self.tenant_id = value
+            if self.osc_api_version == 'v3.3':
+                if value:
+                    self.k_creds['project_id'] = value
+                    self.n_creds['project_id']  = value
+                else:
+                    del self.k_creds['project_id']
+                    del self.n_creds['project_id']
+            else:
+                if value:
+                    self.k_creds['tenant_id'] = value
+                    self.n_creds['tenant_id']  = value
+                else:
+                    del self.k_creds['tenant_id']
+                    del self.n_creds['tenant_id']
+        elif index=='tenant_name':
+            self.reload_client=True
+            self.tenant_name = value
+            if self.osc_api_version == 'v3.3':
+                if value:
+                    self.k_creds['project_name'] = value
+                    self.n_creds['project_name']  = value
+                else:
+                    del self.k_creds['project_name']
+                    del self.n_creds['project_name']
+            else:
+                if value:
+                    self.k_creds['tenant_name'] = value
+                    self.n_creds['project_id']  = value
+                else:
+                    del self.k_creds['tenant_name']
+                    del self.n_creds['project_id']
+        elif index=='user':
+            self.reload_client=True
+            self.user = value
+            if value:
+                self.k_creds['username'] = value
+                self.n_creds['username'] = value
+            else:
+                del self.k_creds['username']
+                del self.n_creds['username']
+        elif index=='passwd':
+            self.reload_client=True
+            self.passwd = value
+            if value:
+                self.k_creds['password'] = value
+                self.n_creds['api_key']  = value
+            else:
+                del self.k_creds['password']
+                del self.n_creds['api_key']
+        elif index=='url':
+            self.reload_client=True
+            self.url = value
+            if value:
+                self.k_creds['auth_url'] = value
+                self.n_creds['auth_url'] = value
+            else:
+                raise TypeError, 'url param can not be NoneType'
+        else:
+            vimconn.vimconnector.__setitem__(self,index, value)
+     
+    def _reload_connection(self):
+        '''Called before any operation, it check if credentials has changed
+        Throw keystoneclient.apiclient.exceptions.AuthorizationFailure
+        '''
+        #TODO control the timing and possible token timeout, but it seams that python client does this task for us :-) 
+        if self.reload_client:
+            #test valid params
+            if len(self.n_creds) <4:
+                raise ksExceptions.ClientException("Not enough parameters to connect to openstack")
+            if self.osc_api_version == 'v3.3':
+                self.nova = nClient(api_version=api_versions.APIVersion(version_str='2.0'), **self.n_creds)
+                #TODO To be updated for v3
+                #self.cinder = cClient.Client(**self.n_creds)
+                self.keystone = ksClient.Client(**self.k_creds)
+                self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+                self.neutron = neClient.Client(api_version=api_versions.APIVersion(version_str='2.0'), endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
+            else:
+                self.nova = nClient_v2.Client(version='2', **self.n_creds)
+                self.cinder = cClient_v2.Client(**self.n_creds)
+                self.keystone = ksClient_v2.Client(**self.k_creds)
+                self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+                self.neutron = neClient_v2.Client('2.0', endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
+            self.glance_endpoint = self.keystone.service_catalog.url_for(service_type='image', endpoint_type='publicURL')
+            self.glance = glClient.Client(self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds)  #TODO check k_creds vs n_creds
+            self.reload_client = False
+
+    def __net_os2mano(self, net_list_dict):
+        '''Transform the net openstack format to mano format
+        net_list_dict can be a list of dict or a single dict'''
+        if type(net_list_dict) is dict:
+            net_list_=(net_list_dict,)
+        elif type(net_list_dict) is list:
+            net_list_=net_list_dict
+        else:
+            raise TypeError("param net_list_dict must be a list or a dictionary")
+        for net in net_list_:
+            if net.get('provider:network_type') == "vlan":
+                net['type']='data'
+            else:
+                net['type']='bridge'
+                
+                
+            
+    def _format_exception(self, exception):
+        '''Transform a keystone, nova, neutron  exception into a vimconn exception'''
+        if isinstance(exception, (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError,
+                                  ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed
+                                  )):
+            raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))            
+        elif isinstance(exception, (nvExceptions.ClientException, ksExceptions.ClientException, 
+                                    neExceptions.NeutronException, nvExceptions.BadRequest)):
+            raise vimconn.vimconnUnexpectedResponse(type(exception).__name__ + ": " + str(exception))
+        elif isinstance(exception, (neExceptions.NetworkNotFoundClient, nvExceptions.NotFound)):
+            raise vimconn.vimconnNotFoundException(type(exception).__name__ + ": " + str(exception))
+        elif isinstance(exception, nvExceptions.Conflict):
+            raise vimconn.vimconnConflictException(type(exception).__name__ + ": " + str(exception))
+        else: # ()
+            raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))
+
+    def get_tenant_list(self, filter_dict={}):
+        '''Obtain tenants of VIM
+        filter_dict can contain the following keys:
+            name: filter by tenant name
+            id: filter by tenant uuid/id
+            <other VIM specific>
+        Returns the tenant list of dictionaries: [{'name':'<name>, 'id':'<id>, ...}, ...]
+        '''
+        self.logger.debug("Getting tenants from VIM filter: '%s'", str(filter_dict))
+        try:
+            self._reload_connection()
+            if self.osc_api_version == 'v3.3':
+                project_class_list=self.keystone.projects.findall(**filter_dict)
+            else:
+                project_class_list=self.keystone.tenants.findall(**filter_dict)
+            project_list=[]
+            for project in project_class_list:
+                project_list.append(project.to_dict())
+            return project_list
+        except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError)  as e:
+            self._format_exception(e)
+
+    def new_tenant(self, tenant_name, tenant_description):
+        '''Adds a new tenant to openstack VIM. Returns the tenant identifier'''
+        self.logger.debug("Adding a new tenant name: %s", tenant_name)
+        try:
+            self._reload_connection()
+            if self.osc_api_version == 'v3.3':
+                project=self.keystone.projects.create(tenant_name, tenant_description)
+            else:
+                project=self.keystone.tenants.create(tenant_name, tenant_description)
+            return project.id
+        except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError)  as e:
+            self._format_exception(e)
+
+    def delete_tenant(self, tenant_id):
+        '''Delete a tenant from openstack VIM. Returns the old tenant identifier'''
+        self.logger.debug("Deleting tenant %s from VIM", tenant_id)
+        try:
+            self._reload_connection()
+            if self.osc_api_version == 'v3.3':
+                self.keystone.projects.delete(tenant_id)
+            else:
+                self.keystone.tenants.delete(tenant_id)
+            return tenant_id
+        except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError)  as e:
+            self._format_exception(e)
+
+    def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None):
+        '''Adds a tenant network to VIM. Returns the network identifier'''
+        self.logger.debug("Adding a new network to VIM name '%s', type '%s'", net_name, net_type)
+        #self.logger.debug(">>>>>>>>>>>>>>>>>> IP profile %s", str(ip_profile))
+        try:
+            new_net = None
+            self._reload_connection()
+            network_dict = {'name': net_name, 'admin_state_up': True}
+            if net_type=="data" or net_type=="ptp":
+                if self.config.get('dataplane_physical_net') == None:
+                    raise vimconn.vimconnConflictException("You must provide a 'dataplane_physical_net' at config value before creating sriov network")
+                network_dict["provider:physical_network"] = self.config['dataplane_physical_net'] #"physnet_sriov" #TODO physical
+                network_dict["provider:network_type"]     = "vlan"
+                if vlan!=None:
+                    network_dict["provider:network_type"] = vlan
+            network_dict["shared"]=shared
+            new_net=self.neutron.create_network({'network':network_dict})
+            #print new_net
+            #create subnetwork, even if there is no profile
+            if not ip_profile:
+                ip_profile = {}
+            if 'subnet_address' not in ip_profile:
+                #Fake subnet is required
+                subnet_rand = random.randint(0, 255)
+                ip_profile['subnet_address'] = "192.168.{}.0/24".format(subnet_rand)
+            if 'ip_version' not in ip_profile: 
+                ip_profile['ip_version'] = "IPv4"
+            subnet={"name":net_name+"-subnet",
+                    "network_id": new_net["network"]["id"],
+                    "ip_version": 4 if ip_profile['ip_version']=="IPv4" else 6,
+                    "cidr": ip_profile['subnet_address']
+                    }
+            if 'gateway_address' in ip_profile:
+                subnet['gateway_ip'] = ip_profile['gateway_address']
+            if ip_profile.get('dns_address'):
+                #TODO: manage dns_address as a list of addresses separated by commas 
+                subnet['dns_nameservers'] = []
+                subnet['dns_nameservers'].append(ip_profile['dns_address'])
+            if 'dhcp_enabled' in ip_profile:
+                subnet['enable_dhcp'] = False if ip_profile['dhcp_enabled']=="false" else True
+            if 'dhcp_start_address' in ip_profile:
+                subnet['allocation_pools']=[]
+                subnet['allocation_pools'].append(dict())
+                subnet['allocation_pools'][0]['start'] = ip_profile['dhcp_start_address']
+            if 'dhcp_count' in ip_profile:
+                #parts = ip_profile['dhcp_start_address'].split('.')
+                #ip_int = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3])
+                ip_int = int(netaddr.IPAddress(ip_profile['dhcp_start_address']))
+                ip_int += ip_profile['dhcp_count'] - 1
+                ip_str = str(netaddr.IPAddress(ip_int))
+                subnet['allocation_pools'][0]['end'] = ip_str
+            #self.logger.debug(">>>>>>>>>>>>>>>>>> Subnet: %s", str(subnet))
+            self.neutron.create_subnet({"subnet": subnet} )
+            return new_net["network"]["id"]
+        except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
+            if new_net:
+                self.neutron.delete_network(new_net['network']['id'])
+            self._format_exception(e)
+
+    def get_network_list(self, filter_dict={}):
+        '''Obtain tenant networks of VIM
+        Filter_dict can be:
+            name: network name
+            id: network uuid
+            shared: boolean
+            tenant_id: tenant
+            admin_state_up: boolean
+            status: 'ACTIVE'
+        Returns the network list of dictionaries
+        '''
+        self.logger.debug("Getting network from VIM filter: '%s'", str(filter_dict))
+        try:
+            self._reload_connection()
+            if self.osc_api_version == 'v3.3' and "tenant_id" in filter_dict:
+                filter_dict['project_id'] = filter_dict.pop('tenant_id')
+            net_dict=self.neutron.list_networks(**filter_dict)
+            net_list=net_dict["networks"]
+            self.__net_os2mano(net_list)
+            return net_list
+        except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
+            self._format_exception(e)
+
+    def get_network(self, net_id):
+        '''Obtain details of network from VIM
+        Returns the network information from a network id'''
+        self.logger.debug(" Getting tenant network %s from VIM", net_id)
+        filter_dict={"id": net_id}
+        net_list = self.get_network_list(filter_dict)
+        if len(net_list)==0:
+            raise vimconn.vimconnNotFoundException("Network '{}' not found".format(net_id))
+        elif len(net_list)>1:
+            raise vimconn.vimconnConflictException("Found more than one network with this criteria")
+        net = net_list[0]
+        subnets=[]
+        for subnet_id in net.get("subnets", () ):
+            try:
+                subnet = self.neutron.show_subnet(subnet_id)
+            except Exception as e:
+                self.logger.error("osconnector.get_network(): Error getting subnet %s %s" % (net_id, str(e)))
+                subnet = {"id": subnet_id, "fault": str(e)}
+            subnets.append(subnet)
+        net["subnets"] = subnets
+        return net
+
+    def delete_network(self, net_id):
+        '''Deletes a tenant network from VIM. Returns the old network identifier'''
+        self.logger.debug("Deleting network '%s' from VIM", net_id)
+        try:
+            self._reload_connection()
+            #delete VM ports attached to this networks before the network
+            ports = self.neutron.list_ports(network_id=net_id)
+            for p in ports['ports']:
+                try:
+                    self.neutron.delete_port(p["id"])
+                except Exception as e:
+                    self.logger.error("Error deleting port %s: %s", p["id"], str(e))
+            self.neutron.delete_network(net_id)
+            return net_id
+        except (neExceptions.ConnectionFailed, neExceptions.NetworkNotFoundClient, neExceptions.NeutronException,
+                ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
+            self._format_exception(e)
+
+    def refresh_nets_status(self, net_list):
+        '''Get the status of the networks
+           Params: the list of network identifiers
+           Returns a dictionary with:
+                net_id:         #VIM id of this network
+                    status:     #Mandatory. Text with one of:
+                                #  DELETED (not found at vim)
+                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
+                                #  OTHER (Vim reported other status not understood)
+                                #  ERROR (VIM indicates an ERROR status)
+                                #  ACTIVE, INACTIVE, DOWN (admin down), 
+                                #  BUILD (on building process)
+                                #
+                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
+                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+
+        '''        
+        net_dict={}
+        for net_id in net_list:
+            net = {}
+            try:
+                net_vim = self.get_network(net_id)
+                if net_vim['status'] in netStatus2manoFormat:
+                    net["status"] = netStatus2manoFormat[ net_vim['status'] ]
+                else:
+                    net["status"] = "OTHER"
+                    net["error_msg"] = "VIM status reported " + net_vim['status']
+                    
+                if net['status'] == "ACTIVE" and not net_vim['admin_state_up']:
+                    net['status'] = 'DOWN'
+                try:
+                    net['vim_info'] = yaml.safe_dump(net_vim, default_flow_style=True, width=256)
+                except yaml.representer.RepresenterError:
+                    net['vim_info'] = str(net_vim)
+                if net_vim.get('fault'):  #TODO
+                    net['error_msg'] = str(net_vim['fault'])
+            except vimconn.vimconnNotFoundException as e:
+                self.logger.error("Exception getting net status: %s", str(e))
+                net['status'] = "DELETED"
+                net['error_msg'] = str(e)
+            except vimconn.vimconnException as e:
+                self.logger.error("Exception getting net status: %s", str(e))
+                net['status'] = "VIM_ERROR"
+                net['error_msg'] = str(e)
+            net_dict[net_id] = net
+        return net_dict
+
+    def get_flavor(self, flavor_id):
+        '''Obtain flavor details from the  VIM. Returns the flavor dict details'''
+        self.logger.debug("Getting flavor '%s'", flavor_id)
+        try:
+            self._reload_connection()
+            flavor = self.nova.flavors.find(id=flavor_id)
+            #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
+            return flavor.to_dict()
+        except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
+            self._format_exception(e)
+
+    def get_flavor_id_from_data(self, flavor_dict):
+        """Obtain flavor id that match the flavor description
+           Returns the flavor_id or raises a vimconnNotFoundException
+        """
+        try:
+            self._reload_connection()
+            numa=None
+            numas = flavor_dict.get("extended",{}).get("numas")
+            if numas:
+                #TODO
+                raise vimconn.vimconnNotFoundException("Flavor with EPA still not implemted")
+                # if len(numas) > 1:
+                #     raise vimconn.vimconnNotFoundException("Cannot find any flavor with more than one numa")
+                # numa=numas[0]
+                # numas = extended.get("numas")
+            for flavor in self.nova.flavors.list():
+                epa = flavor.get_keys()
+                if epa:
+                    continue
+                    #TODO 
+                if flavor.ram != flavor_dict["ram"]:
+                    continue
+                if flavor.vcpus != flavor_dict["vcpus"]:
+                    continue
+                if flavor.disk != flavor_dict["disk"]:
+                    continue
+                return flavor.id
+            raise vimconn.vimconnNotFoundException("Cannot find any flavor matching '{}'".format(str(flavor_dict)))
+        except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
+            self._format_exception(e)
+
+
+    def new_flavor(self, flavor_data, change_name_if_used=True):
+        '''Adds a tenant flavor to openstack VIM
+        if change_name_if_used is True, it will change name in case of conflict, because it is not supported name repetition
+        Returns the flavor identifier
+        '''
+        self.logger.debug("Adding flavor '%s'", str(flavor_data))
+        retry=0
+        max_retries=3
+        name_suffix = 0
+        name=flavor_data['name']
+        while retry<max_retries:
+            retry+=1
+            try:
+                self._reload_connection()
+                if change_name_if_used:
+                    #get used names
+                    fl_names=[]
+                    fl=self.nova.flavors.list()
+                    for f in fl:
+                        fl_names.append(f.name)
+                    while name in fl_names:
+                        name_suffix += 1
+                        name = flavor_data['name']+"-" + str(name_suffix)
+                        
+                ram = flavor_data.get('ram',64)
+                vcpus = flavor_data.get('vcpus',1)
+                numa_properties=None
+
+                extended = flavor_data.get("extended")
+                if extended:
+                    numas=extended.get("numas")
+                    if numas:
+                        numa_nodes = len(numas)
+                        if numa_nodes > 1:
+                            return -1, "Can not add flavor with more than one numa"
+                        numa_properties = {"hw:numa_nodes":str(numa_nodes)}
+                        numa_properties["hw:mem_page_size"] = "large"
+                        numa_properties["hw:cpu_policy"] = "dedicated"
+                        numa_properties["hw:numa_mempolicy"] = "strict"
+                        for numa in numas:
+                            #overwrite ram and vcpus
+                            ram = numa['memory']*1024
+                            if 'paired-threads' in numa:
+                                vcpus = numa['paired-threads']*2
+                                numa_properties["hw:cpu_threads_policy"] = "prefer"
+                            elif 'cores' in numa:
+                                vcpus = numa['cores']
+                                #numa_properties["hw:cpu_threads_policy"] = "prefer"
+                            elif 'threads' in numa:
+                                vcpus = numa['threads']
+                                numa_properties["hw:cpu_policy"] = "isolated"
+                            for interface in numa.get("interfaces",() ):
+                                if interface["dedicated"]=="yes":
+                                    raise vimconn.vimconnException("Passthrough interfaces are not supported for the openstack connector", http_code=vimconn.HTTP_Service_Unavailable)
+                                #TODO, add the key 'pci_passthrough:alias"="<label at config>:<number ifaces>"' when a way to connect it is available
+                                
+                #create flavor                 
+                new_flavor=self.nova.flavors.create(name, 
+                                ram, 
+                                vcpus, 
+                                flavor_data.get('disk',1),
+                                is_public=flavor_data.get('is_public', True)
+                            ) 
+                #add metadata
+                if numa_properties:
+                    new_flavor.set_keys(numa_properties)
+                return new_flavor.id
+            except nvExceptions.Conflict as e:
+                if change_name_if_used and retry < max_retries:
+                    continue
+                self._format_exception(e)
+            #except nvExceptions.BadRequest as e:
+            except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
+                self._format_exception(e)
+
+    def delete_flavor(self,flavor_id):
+        '''Deletes a tenant flavor from openstack VIM. Returns the old flavor_id
+        '''
+        try:
+            self._reload_connection()
+            self.nova.flavors.delete(flavor_id)
+            return flavor_id
+        #except nvExceptions.BadRequest as e:
+        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
+            self._format_exception(e)
+
+    def new_image(self,image_dict):
+        '''
+        Adds a tenant image to VIM. imge_dict is a dictionary with:
+            name: name
+            disk_format: qcow2, vhd, vmdk, raw (by default), ...
+            location: path or URI
+            public: "yes" or "no"
+            metadata: metadata of the image
+        Returns the image_id
+        '''
+        #using version 1 of glance client
+        glancev1 = gl1Client.Client('1',self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds)  #TODO check k_creds vs n_creds
+        retry=0
+        max_retries=3
+        while retry<max_retries:
+            retry+=1
+            try:
+                self._reload_connection()
+                #determine format  http://docs.openstack.org/developer/glance/formats.html
+                if "disk_format" in image_dict:
+                    disk_format=image_dict["disk_format"]
+                else: #autodiscover based on extension
+                    if image_dict['location'][-6:]==".qcow2":
+                        disk_format="qcow2"
+                    elif image_dict['location'][-4:]==".vhd":
+                        disk_format="vhd"
+                    elif image_dict['location'][-5:]==".vmdk":
+                        disk_format="vmdk"
+                    elif image_dict['location'][-4:]==".vdi":
+                        disk_format="vdi"
+                    elif image_dict['location'][-4:]==".iso":
+                        disk_format="iso"
+                    elif image_dict['location'][-4:]==".aki":
+                        disk_format="aki"
+                    elif image_dict['location'][-4:]==".ari":
+                        disk_format="ari"
+                    elif image_dict['location'][-4:]==".ami":
+                        disk_format="ami"
+                    else:
+                        disk_format="raw"
+                self.logger.debug("new_image: '%s' loading from '%s'", image_dict['name'], image_dict['location'])
+                if image_dict['location'][0:4]=="http":
+                    new_image = glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
+                            container_format="bare", location=image_dict['location'], disk_format=disk_format)
+                else: #local path
+                    with open(image_dict['location']) as fimage:
+                        new_image = glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
+                            container_format="bare", data=fimage, disk_format=disk_format)
+                #insert metadata. We cannot use 'new_image.properties.setdefault' 
+                #because nova and glance are "INDEPENDENT" and we are using nova for reading metadata
+                new_image_nova=self.nova.images.find(id=new_image.id)
+                new_image_nova.metadata.setdefault('location',image_dict['location'])
+                metadata_to_load = image_dict.get('metadata')
+                if metadata_to_load:
+                    for k,v in yaml.load(metadata_to_load).iteritems():
+                        new_image_nova.metadata.setdefault(k,v)
+                return new_image.id
+            except (nvExceptions.Conflict, ksExceptions.ClientException, nvExceptions.ClientException) as e:
+                self._format_exception(e)
+            except (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError, ConnectionError) as e:
+                if retry==max_retries:
+                    continue
+                self._format_exception(e)
+            except IOError as e:  #can not open the file
+                raise vimconn.vimconnConnectionException(type(e).__name__ + ": " + str(e)+ " for " + image_dict['location'],
+                                                         http_code=vimconn.HTTP_Bad_Request)
+     
+    def delete_image(self, image_id):
+        '''Deletes a tenant image from openstack VIM. Returns the old id
+        '''
+        try:
+            self._reload_connection()
+            self.nova.images.delete(image_id)
+            return image_id
+        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e: #TODO remove
+            self._format_exception(e)
+
+    def get_image_id_from_path(self, path):
+        '''Get the image id from image path in the VIM database. Returns the image_id''' 
+        try:
+            self._reload_connection()
+            images = self.nova.images.list()
+            for image in images:
+                if image.metadata.get("location")==path:
+                    return image.id
+            raise vimconn.vimconnNotFoundException("image with location '{}' not found".format( path))
+        except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
+            self._format_exception(e)
+        
+    def get_image_list(self, filter_dict={}):
+        '''Obtain tenant images from VIM
+        Filter_dict can be:
+            id: image id
+            name: image name
+            checksum: image checksum
+        Returns the image list of dictionaries:
+            [{<the fields at Filter_dict plus some VIM specific>}, ...]
+            List can be empty
+        '''
+        self.logger.debug("Getting image list from VIM filter: '%s'", str(filter_dict))
+        try:
+            self._reload_connection()
+            filter_dict_os=filter_dict.copy()
+            #First we filter by the available filter fields: name, id. The others are removed.
+            filter_dict_os.pop('checksum',None)
+            image_list=self.nova.images.findall(**filter_dict_os)
+            if len(image_list)==0:
+                return []
+            #Then we filter by the rest of filter fields: checksum
+            filtered_list = []
+            for image in image_list:
+                image_class=self.glance.images.get(image.id)
+                if 'checksum' not in filter_dict or image_class['checksum']==filter_dict.get('checksum'):
+                    filtered_list.append(image_class.copy())
+            return filtered_list
+        except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
+            self._format_exception(e)
+
+    def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None,disk_list=None):
+        '''Adds a VM instance to VIM
+        Params:
+            start: indicates if VM must start or boot in pause mode. Ignored
+            image_id,flavor_id: iamge and flavor uuid
+            net_list: list of interfaces, each one is a dictionary with:
+                name:
+                net_id: network uuid to connect
+                vpci: virtual vcpi to assign, ignored because openstack lack #TODO
+                model: interface model, ignored #TODO
+                mac_address: used for  SR-IOV ifaces #TODO for other types
+                use: 'data', 'bridge',  'mgmt'
+                type: 'virtual', 'PF', 'VF', 'VFnotShared'
+                vim_id: filled/added by this function
+                floating_ip: True/False (or it can be None)
+                #TODO ip, security groups
+        Returns the instance identifier
+        '''
+        self.logger.debug("new_vminstance input: image='%s' flavor='%s' nics='%s'",image_id, flavor_id,str(net_list))
+        try:
+            metadata={}
+            net_list_vim=[]
+            external_network=[] #list of external networks to be connected to instance, later on used to create floating_ip
+            self._reload_connection()
+            metadata_vpci={} #For a specific neutron plugin 
+            for net in net_list:
+                if not net.get("net_id"): #skip non connected iface
+                    continue
+                if net["type"]=="virtual" or net["type"]=="VF":
+                    port_dict={
+                        "network_id": net["net_id"],
+                        "name": net.get("name"),
+                        "admin_state_up": True
+                    }    
+                    if net["type"]=="virtual":
+                        if "vpci" in net:
+                            metadata_vpci[ net["net_id"] ] = [[ net["vpci"], "" ]]
+                    else: # for VF
+                        if "vpci" in net:
+                            if "VF" not in metadata_vpci:
+                                metadata_vpci["VF"]=[]
+                            metadata_vpci["VF"].append([ net["vpci"], "" ])
+                        port_dict["binding:vnic_type"]="direct"
+                    if not port_dict["name"]:
+                        port_dict["name"]=name
+                    if net.get("mac_address"):
+                        port_dict["mac_address"]=net["mac_address"]
+                    if net.get("port_security") == False:
+                        port_dict["port_security_enabled"]=net["port_security"]
+                    new_port = self.neutron.create_port({"port": port_dict })
+                    net["mac_adress"] = new_port["port"]["mac_address"]
+                    net["vim_id"] = new_port["port"]["id"]
+                    net["ip"] = new_port["port"].get("fixed_ips", [{}])[0].get("ip_address")
+                    net_list_vim.append({"port-id": new_port["port"]["id"]})
+                else:   # for PF
+                    self.logger.warn("new_vminstance: Warning, can not connect a passthrough interface ")
+                    #TODO insert this when openstack consider passthrough ports as openstack neutron ports
+                if net.get('floating_ip', False):
+                    net['exit_on_floating_ip_error'] = True
+                    external_network.append(net)
+                elif net['use'] == 'mgmt' and self.config.get('use_floating_ip'):
+                    net['exit_on_floating_ip_error'] = False
+                    external_network.append(net)
+
+            if metadata_vpci:
+                metadata = {"pci_assignement": json.dumps(metadata_vpci)}
+                if len(metadata["pci_assignement"]) >255:
+                    #limit the metadata size
+                    #metadata["pci_assignement"] = metadata["pci_assignement"][0:255]
+                    self.logger.warn("Metadata deleted since it exceeds the expected length (255) ")
+                    metadata = {}
+            
+            self.logger.debug("name '%s' image_id '%s'flavor_id '%s' net_list_vim '%s' description '%s' metadata %s",
+                              name, image_id, flavor_id, str(net_list_vim), description, str(metadata))
+            
+            security_groups   = self.config.get('security_groups')
+            if type(security_groups) is str:
+                security_groups = ( security_groups, )
+            #cloud config
+            userdata=None
+            config_drive = None
+            if isinstance(cloud_config, dict):
+                if cloud_config.get("user-data"):
+                    userdata=cloud_config["user-data"]
+                if cloud_config.get("boot-data-drive") != None:
+                    config_drive = cloud_config["boot-data-drive"]
+                if cloud_config.get("config-files") or cloud_config.get("users") or cloud_config.get("key-pairs"):
+                    if userdata:
+                        raise vimconn.vimconnConflictException("Cloud-config cannot contain both 'userdata' and 'config-files'/'users'/'key-pairs'")
+                    userdata_dict={}
+                    #default user
+                    if cloud_config.get("key-pairs"):
+                        userdata_dict["ssh-authorized-keys"] = cloud_config["key-pairs"]
+                        userdata_dict["users"] = [{"default": None, "ssh-authorized-keys": cloud_config["key-pairs"] }]
+                    if cloud_config.get("users"):
+                        if "users" not in userdata_dict:
+                            userdata_dict["users"] = [ "default" ]
+                        for user in cloud_config["users"]:
+                            user_info = {
+                                "name" : user["name"],
+                                "sudo": "ALL = (ALL)NOPASSWD:ALL"
+                            }
+                            if "user-info" in user:
+                                user_info["gecos"] = user["user-info"]
+                            if user.get("key-pairs"):
+                                user_info["ssh-authorized-keys"] = user["key-pairs"]
+                            userdata_dict["users"].append(user_info)
+
+                    if cloud_config.get("config-files"):
+                        userdata_dict["write_files"] = []
+                        for file in cloud_config["config-files"]:
+                            file_info = {
+                                "path" : file["dest"],
+                                "content": file["content"]
+                            }
+                            if file.get("encoding"):
+                                file_info["encoding"] = file["encoding"]
+                            if file.get("permissions"):
+                                file_info["permissions"] = file["permissions"]
+                            if file.get("owner"):
+                                file_info["owner"] = file["owner"]
+                            userdata_dict["write_files"].append(file_info)
+                    userdata = "#cloud-config\n"
+                    userdata += yaml.safe_dump(userdata_dict, indent=4, default_flow_style=False)
+                self.logger.debug("userdata: %s", userdata)
+            elif isinstance(cloud_config, str):
+                userdata = cloud_config
+
+            #Create additional volumes in case these are present in disk_list
+            block_device_mapping = None
+            base_disk_index = ord('b')
+            if disk_list != None:
+                block_device_mapping = dict()
+                for disk in disk_list:
+                    if 'image_id' in disk:
+                        volume = self.cinder.volumes.create(size = disk['size'],name = name + '_vd' +
+                                    chr(base_disk_index), imageRef = disk['image_id'])
+                    else:
+                        volume = self.cinder.volumes.create(size=disk['size'], name=name + '_vd' +
+                                    chr(base_disk_index))
+                    block_device_mapping['_vd' +  chr(base_disk_index)] = volume.id
+                    base_disk_index += 1
+
+                #wait until volumes are with status available
+                keep_waiting = True
+                elapsed_time = 0
+                while keep_waiting and elapsed_time < volume_timeout:
+                    keep_waiting = False
+                    for volume_id in block_device_mapping.itervalues():
+                        if self.cinder.volumes.get(volume_id).status != 'available':
+                            keep_waiting = True
+                    if keep_waiting:
+                        time.sleep(1)
+                        elapsed_time += 1
+
+                #if we exceeded the timeout rollback
+                if elapsed_time >= volume_timeout:
+                    #delete the volumes we just created
+                    for volume_id in block_device_mapping.itervalues():
+                        self.cinder.volumes.delete(volume_id)
+
+                    #delete ports we just created
+                    for net_item  in net_list_vim:
+                        if 'port-id' in net_item:
+                            self.neutron.delete_port(net_item['port-id'])
+
+                    raise vimconn.vimconnException('Timeout creating volumes for instance ' + name,
+                                                   http_code=vimconn.HTTP_Request_Timeout)
+
+            server = self.nova.servers.create(name, image_id, flavor_id, nics=net_list_vim, meta=metadata,
+                                              security_groups=security_groups,
+                                              availability_zone=self.config.get('availability_zone'),
+                                              key_name=self.config.get('keypair'),
+                                              userdata=userdata,
+                                              config_drive = config_drive,
+                                              block_device_mapping = block_device_mapping
+                                              )  # , description=description)
+            #print "DONE :-)", server
+            pool_id = None
+            floating_ips = self.neutron.list_floatingips().get("floatingips", ())
+            for floating_network in external_network:
+                try:
+                    # wait until vm is active
+                    elapsed_time = 0
+                    while elapsed_time < server_timeout:
+                        status = self.nova.servers.get(server.id).status
+                        if status == 'ACTIVE':
+                            break
+                        time.sleep(1)
+                        elapsed_time += 1
+
+                    #if we exceeded the timeout rollback
+                    if elapsed_time >= server_timeout:
+                        raise vimconn.vimconnException('Timeout creating instance ' + name,
+                                                       http_code=vimconn.HTTP_Request_Timeout)
+
+                    assigned = False
+                    while(assigned == False):
+                        if floating_ips:
+                            ip = floating_ips.pop(0)
+                            if not ip.get("port_id", False) and ip.get('tenant_id') == server.tenant_id:
+                                free_floating_ip = ip.get("floating_ip_address")
+                                try:
+                                    fix_ip = floating_network.get('ip')
+                                    server.add_floating_ip(free_floating_ip, fix_ip)
+                                    assigned = True
+                                except Exception as e:
+                                    raise vimconn.vimconnException(type(e).__name__ + ": Cannot create floating_ip "+  str(e), http_code=vimconn.HTTP_Conflict)
+                        else:
+                            #Find the external network
+                            external_nets = list()
+                            for net in self.neutron.list_networks()['networks']:
+                                if net['router:external']:
+                                        external_nets.append(net)
+
+                            if len(external_nets) == 0:
+                                raise vimconn.vimconnException("Cannot create floating_ip automatically since no external "
+                                                               "network is present",
+                                                                http_code=vimconn.HTTP_Conflict)
+                            if len(external_nets) > 1:
+                                raise vimconn.vimconnException("Cannot create floating_ip automatically since multiple "
+                                                               "external networks are present",
+                                                               http_code=vimconn.HTTP_Conflict)
+
+                            pool_id = external_nets[0].get('id')
+                            param = {'floatingip': {'floating_network_id': pool_id, 'tenant_id': server.tenant_id}}
+                            try:
+                                #self.logger.debug("Creating floating IP")
+                                new_floating_ip = self.neutron.create_floatingip(param)
+                                free_floating_ip = new_floating_ip['floatingip']['floating_ip_address']
+                                fix_ip = floating_network.get('ip')
+                                server.add_floating_ip(free_floating_ip, fix_ip)
+                                assigned=True
+                            except Exception as e:
+                                raise vimconn.vimconnException(type(e).__name__ + ": Cannot assign floating_ip "+  str(e), http_code=vimconn.HTTP_Conflict)
+                except Exception as e:
+                    if not floating_network['exit_on_floating_ip_error']:
+                        self.logger.warn("Cannot create floating_ip. %s", str(e))
+                        continue
+                    self.delete_vminstance(server.id)
+                    raise
+
+            return server.id
+#        except nvExceptions.NotFound as e:
+#            error_value=-vimconn.HTTP_Not_Found
+#            error_text= "vm instance %s not found" % vm_id
+        except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
+            # delete the volumes we just created
+            if block_device_mapping != None:
+                for volume_id in block_device_mapping.itervalues():
+                    self.cinder.volumes.delete(volume_id)
+
+            # delete ports we just created
+            for net_item in net_list_vim:
+                if 'port-id' in net_item:
+                    self.neutron.delete_port(net_item['port-id'])
+            self._format_exception(e)
+        except TypeError as e:
+            raise vimconn.vimconnException(type(e).__name__ + ": "+  str(e), http_code=vimconn.HTTP_Bad_Request)
+
+    def get_vminstance(self,vm_id):
+        '''Returns the VM instance information from VIM'''
+        #self.logger.debug("Getting VM from VIM")
+        try:
+            self._reload_connection()
+            server = self.nova.servers.find(id=vm_id)
+            #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
+            return server.to_dict()
+        except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e:
+            self._format_exception(e)
+
+    def get_vminstance_console(self,vm_id, console_type="vnc"):
+        '''
+        Get a console for the virtual machine
+        Params:
+            vm_id: uuid of the VM
+            console_type, can be:
+                "novnc" (by default), "xvpvnc" for VNC types, 
+                "rdp-html5" for RDP types, "spice-html5" for SPICE types
+        Returns dict with the console parameters:
+                protocol: ssh, ftp, http, https, ...
+                server:   usually ip address 
+                port:     the http, ssh, ... port 
+                suffix:   extra text, e.g. the http path and query string   
+        '''
+        self.logger.debug("Getting VM CONSOLE from VIM")
+        try:
+            self._reload_connection()
+            server = self.nova.servers.find(id=vm_id)
+            if console_type == None or console_type == "novnc":
+                console_dict = server.get_vnc_console("novnc")
+            elif console_type == "xvpvnc":
+                console_dict = server.get_vnc_console(console_type)
+            elif console_type == "rdp-html5":
+                console_dict = server.get_rdp_console(console_type)
+            elif console_type == "spice-html5":
+                console_dict = server.get_spice_console(console_type)
+            else:
+                raise vimconn.vimconnException("console type '{}' not allowed".format(console_type), http_code=vimconn.HTTP_Bad_Request)
+            
+            console_dict1 = console_dict.get("console")
+            if console_dict1:
+                console_url = console_dict1.get("url")
+                if console_url:
+                    #parse console_url
+                    protocol_index = console_url.find("//")
+                    suffix_index = console_url[protocol_index+2:].find("/") + protocol_index+2
+                    port_index = console_url[protocol_index+2:suffix_index].find(":") + protocol_index+2
+                    if protocol_index < 0 or port_index<0 or suffix_index<0:
+                        return -vimconn.HTTP_Internal_Server_Error, "Unexpected response from VIM"
+                    console_dict={"protocol": console_url[0:protocol_index],
+                                  "server":   console_url[protocol_index+2:port_index], 
+                                  "port":     console_url[port_index:suffix_index], 
+                                  "suffix":   console_url[suffix_index+1:] 
+                                  }
+                    protocol_index += 2
+                    return console_dict
+            raise vimconn.vimconnUnexpectedResponse("Unexpected response from VIM")
+            
+        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.BadRequest, ConnectionError) as e:
+            self._format_exception(e)
+
+    def delete_vminstance(self, vm_id):
+        '''Removes a VM instance from VIM. Returns the old identifier
+        '''
+        #print "osconnector: Getting VM from VIM"
+        try:
+            self._reload_connection()
+            #delete VM ports attached to this networks before the virtual machine
+            ports = self.neutron.list_ports(device_id=vm_id)
+            for p in ports['ports']:
+                try:
+                    self.neutron.delete_port(p["id"])
+                except Exception as e:
+                    self.logger.error("Error deleting port: " + type(e).__name__ + ": "+  str(e))
+
+            #commented because detaching the volumes makes the servers.delete not work properly ?!?
+            #dettach volumes attached
+            server = self.nova.servers.get(vm_id)
+            volumes_attached_dict = server._info['os-extended-volumes:volumes_attached']
+            #for volume in volumes_attached_dict:
+            #    self.cinder.volumes.detach(volume['id'])
+
+            self.nova.servers.delete(vm_id)
+
+            #delete volumes.
+            #Although having detached them should have them  in active status
+            #we ensure in this loop
+            keep_waiting = True
+            elapsed_time = 0
+            while keep_waiting and elapsed_time < volume_timeout:
+                keep_waiting = False
+                for volume in volumes_attached_dict:
+                    if self.cinder.volumes.get(volume['id']).status != 'available':
+                        keep_waiting = True
+                    else:
+                        self.cinder.volumes.delete(volume['id'])
+                if keep_waiting:
+                    time.sleep(1)
+                    elapsed_time += 1
+
+            return vm_id
+        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
+            self._format_exception(e)
+        #TODO insert exception vimconn.HTTP_Unauthorized
+        #if reaching here is because an exception
+
+    def refresh_vms_status(self, vm_list):
+        '''Get the status of the virtual machines and their interfaces/ports
+           Params: the list of VM identifiers
+           Returns a dictionary with:
+                vm_id:          #VIM id of this Virtual Machine
+                    status:     #Mandatory. Text with one of:
+                                #  DELETED (not found at vim)
+                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
+                                #  OTHER (Vim reported other status not understood)
+                                #  ERROR (VIM indicates an ERROR status)
+                                #  ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running), 
+                                #  CREATING (on building process), ERROR
+                                #  ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
+                                #
+                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
+                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+                    interfaces:
+                     -  vim_info:         #Text with plain information obtained from vim (yaml.safe_dump)
+                        mac_address:      #Text format XX:XX:XX:XX:XX:XX
+                        vim_net_id:       #network id where this interface is connected
+                        vim_interface_id: #interface/port VIM id
+                        ip_address:       #null, or text with IPv4, IPv6 address
+        '''
+        vm_dict={}
+        self.logger.debug("refresh_vms status: Getting tenant VM instance information from VIM")
+        for vm_id in vm_list:
+            vm={}
+            try:
+                vm_vim = self.get_vminstance(vm_id)
+                if vm_vim['status'] in vmStatus2manoFormat:
+                    vm['status']    =  vmStatus2manoFormat[ vm_vim['status'] ]
+                else:
+                    vm['status']    = "OTHER"
+                    vm['error_msg'] = "VIM status reported " + vm_vim['status']
+                try:
+                    vm['vim_info']  = yaml.safe_dump(vm_vim, default_flow_style=True, width=256)
+                except yaml.representer.RepresenterError:
+                    vm['vim_info'] = str(vm_vim)
+                vm["interfaces"] = []
+                if vm_vim.get('fault'):
+                    vm['error_msg'] = str(vm_vim['fault'])
+                #get interfaces
+                try:
+                    self._reload_connection()
+                    port_dict=self.neutron.list_ports(device_id=vm_id)
+                    for port in port_dict["ports"]:
+                        interface={}
+                        try:
+                            interface['vim_info'] = yaml.safe_dump(port, default_flow_style=True, width=256)
+                        except yaml.representer.RepresenterError:
+                            interface['vim_info'] = str(port)
+                        interface["mac_address"] = port.get("mac_address")
+                        interface["vim_net_id"] = port["network_id"]
+                        interface["vim_interface_id"] = port["id"]
+                        ips=[]
+                        #look for floating ip address
+                        floating_ip_dict = self.neutron.list_floatingips(port_id=port["id"])
+                        if floating_ip_dict.get("floatingips"):
+                            ips.append(floating_ip_dict["floatingips"][0].get("floating_ip_address") )
+
+                        for subnet in port["fixed_ips"]:
+                            ips.append(subnet["ip_address"])
+                        interface["ip_address"] = ";".join(ips)
+                        vm["interfaces"].append(interface)
+                except Exception as e:
+                    self.logger.error("Error getting vm interface information " + type(e).__name__ + ": "+  str(e))
+            except vimconn.vimconnNotFoundException as e:
+                self.logger.error("Exception getting vm status: %s", str(e))
+                vm['status'] = "DELETED"
+                vm['error_msg'] = str(e)
+            except vimconn.vimconnException as e:
+                self.logger.error("Exception getting vm status: %s", str(e))
+                vm['status'] = "VIM_ERROR"
+                vm['error_msg'] = str(e)
+            vm_dict[vm_id] = vm
+        return vm_dict
+    
+    def action_vminstance(self, vm_id, action_dict):
+        '''Send and action over a VM instance from VIM
+        Returns the vm_id if the action was successfully sent to the VIM'''
+        self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
+        try:
+            self._reload_connection()
+            server = self.nova.servers.find(id=vm_id)
+            if "start" in action_dict:
+                if action_dict["start"]=="rebuild":  
+                    server.rebuild()
+                else:
+                    if server.status=="PAUSED":
+                        server.unpause()
+                    elif server.status=="SUSPENDED":
+                        server.resume()
+                    elif server.status=="SHUTOFF":
+                        server.start()
+            elif "pause" in action_dict:
+                server.pause()
+            elif "resume" in action_dict:
+                server.resume()
+            elif "shutoff" in action_dict or "shutdown" in action_dict:
+                server.stop()
+            elif "forceOff" in action_dict:
+                server.stop() #TODO
+            elif "terminate" in action_dict:
+                server.delete()
+            elif "createImage" in action_dict:
+                server.create_image()
+                #"path":path_schema,
+                #"description":description_schema,
+                #"name":name_schema,
+                #"metadata":metadata_schema,
+                #"imageRef": id_schema,
+                #"disk": {"oneOf":[{"type": "null"}, {"type":"string"}] },
+            elif "rebuild" in action_dict:
+                server.rebuild(server.image['id'])
+            elif "reboot" in action_dict:
+                server.reboot() #reboot_type='SOFT'
+            elif "console" in action_dict:
+                console_type = action_dict["console"]
+                if console_type == None or console_type == "novnc":
+                    console_dict = server.get_vnc_console("novnc")
+                elif console_type == "xvpvnc":
+                    console_dict = server.get_vnc_console(console_type)
+                elif console_type == "rdp-html5":
+                    console_dict = server.get_rdp_console(console_type)
+                elif console_type == "spice-html5":
+                    console_dict = server.get_spice_console(console_type)
+                else:
+                    raise vimconn.vimconnException("console type '{}' not allowed".format(console_type), 
+                                                   http_code=vimconn.HTTP_Bad_Request)
+                try:
+                    console_url = console_dict["console"]["url"]
+                    #parse console_url
+                    protocol_index = console_url.find("//")
+                    suffix_index = console_url[protocol_index+2:].find("/") + protocol_index+2
+                    port_index = console_url[protocol_index+2:suffix_index].find(":") + protocol_index+2
+                    if protocol_index < 0 or port_index<0 or suffix_index<0:
+                        raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict))
+                    console_dict2={"protocol": console_url[0:protocol_index],
+                                  "server":   console_url[protocol_index+2 : port_index], 
+                                  "port":     int(console_url[port_index+1 : suffix_index]), 
+                                  "suffix":   console_url[suffix_index+1:] 
+                                  }
+                    return console_dict2               
+                except Exception as e:
+                    raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict))
+            
+            return vm_id
+        except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e:
+            self._format_exception(e)
+        #TODO insert exception vimconn.HTTP_Unauthorized
+
+#NOT USED FUNCTIONS
+    
+    def new_external_port(self, port_data):
+        #TODO openstack if needed
+        '''Adds a external port to VIM'''
+        '''Returns the port identifier'''
+        return -vimconn.HTTP_Internal_Server_Error, "osconnector.new_external_port() not implemented" 
+        
+    def connect_port_network(self, port_id, network_id, admin=False):
+        #TODO openstack if needed
+        '''Connects a external port to a network'''
+        '''Returns status code of the VIM response'''
+        return -vimconn.HTTP_Internal_Server_Error, "osconnector.connect_port_network() not implemented" 
+    
+    def new_user(self, user_name, user_passwd, tenant_id=None):
+        '''Adds a new user to openstack VIM'''
+        '''Returns the user identifier'''
+        self.logger.debug("osconnector: Adding a new user to VIM")
+        try:
+            self._reload_connection()
+            user=self.keystone.users.create(user_name, user_passwd, tenant_id=tenant_id)
+            #self.keystone.tenants.add_user(self.k_creds["username"], #role)
+            return user.id
+        except ksExceptions.ConnectionError as e:
+            error_value=-vimconn.HTTP_Bad_Request
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        except ksExceptions.ClientException as e: #TODO remove
+            error_value=-vimconn.HTTP_Bad_Request
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        #TODO insert exception vimconn.HTTP_Unauthorized
+        #if reaching here is because an exception
+        if self.debug:
+            self.logger.debug("new_user " + error_text)
+        return error_value, error_text        
+
+    def delete_user(self, user_id):
+        '''Delete a user from openstack VIM'''
+        '''Returns the user identifier'''
+        if self.debug:
+            print "osconnector: Deleting  a  user from VIM"
+        try:
+            self._reload_connection()
+            self.keystone.users.delete(user_id)
+            return 1, user_id
+        except ksExceptions.ConnectionError as e:
+            error_value=-vimconn.HTTP_Bad_Request
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        except ksExceptions.NotFound as e:
+            error_value=-vimconn.HTTP_Not_Found
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        except ksExceptions.ClientException as e: #TODO remove
+            error_value=-vimconn.HTTP_Bad_Request
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        #TODO insert exception vimconn.HTTP_Unauthorized
+        #if reaching here is because an exception
+        if self.debug:
+            print "delete_tenant " + error_text
+        return error_value, error_text
+    def get_hosts_info(self):
+        '''Get the information of deployed hosts
+        Returns the hosts content'''
+        if self.debug:
+            print "osconnector: Getting Host info from VIM"
+        try:
+            h_list=[]
+            self._reload_connection()
+            hypervisors = self.nova.hypervisors.list()
+            for hype in hypervisors:
+                h_list.append( hype.to_dict() )
+            return 1, {"hosts":h_list}
+        except nvExceptions.NotFound as e:
+            error_value=-vimconn.HTTP_Not_Found
+            error_text= (str(e) if len(e.args)==0 else str(e.args[0]))
+        except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
+            error_value=-vimconn.HTTP_Bad_Request
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        #TODO insert exception vimconn.HTTP_Unauthorized
+        #if reaching here is because an exception
+        if self.debug:
+            print "get_hosts_info " + error_text
+        return error_value, error_text        
+
+    def get_hosts(self, vim_tenant):
+        '''Get the hosts and deployed instances
+        Returns the hosts content'''
+        r, hype_dict = self.get_hosts_info()
+        if r<0:
+            return r, hype_dict
+        hypervisors = hype_dict["hosts"]
+        try:
+            servers = self.nova.servers.list()
+            for hype in hypervisors:
+                for server in servers:
+                    if server.to_dict()['OS-EXT-SRV-ATTR:hypervisor_hostname']==hype['hypervisor_hostname']:
+                        if 'vm' in hype:
+                            hype['vm'].append(server.id)
+                        else:
+                            hype['vm'] = [server.id]
+            return 1, hype_dict
+        except nvExceptions.NotFound as e:
+            error_value=-vimconn.HTTP_Not_Found
+            error_text= (str(e) if len(e.args)==0 else str(e.args[0]))
+        except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
+            error_value=-vimconn.HTTP_Bad_Request
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        #TODO insert exception vimconn.HTTP_Unauthorized
+        #if reaching here is because an exception
+        if self.debug:
+            print "get_hosts " + error_text
+        return error_value, error_text        
+  
+
diff --git a/osm_ro/vimconn_openvim.py b/osm_ro/vimconn_openvim.py
new file mode 100644 (file)
index 0000000..e86b54d
--- /dev/null
@@ -0,0 +1,1314 @@
+# -*- 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
+##
+
+'''
+vimconnector implements all the methods to interact with openvim using the openvim API.
+'''
+__author__="Alfonso Tierno, Gerardo Garcia"
+__date__ ="$26-aug-2014 11:09:29$"
+
+import vimconn
+import requests
+import json
+import yaml
+import logging
+from openmano_schemas import id_schema, name_schema, nameshort_schema, description_schema, \
+                            vlan1000_schema, integer0_schema
+from jsonschema import validate as js_v, exceptions as js_e
+from urllib import quote
+
+'''contain the openvim virtual machine status to openmano status'''
+vmStatus2manoFormat={'ACTIVE':'ACTIVE',
+                     'PAUSED':'PAUSED',
+                     'SUSPENDED': 'SUSPENDED',
+                     'INACTIVE':'INACTIVE',
+                     'CREATING':'BUILD',
+                     'ERROR':'ERROR','DELETED':'DELETED'
+                     }
+netStatus2manoFormat={'ACTIVE':'ACTIVE','INACTIVE':'INACTIVE','BUILD':'BUILD','ERROR':'ERROR','DELETED':'DELETED', 'DOWN':'DOWN'
+                     }
+
+
+host_schema = {
+    "type":"object",
+    "properties":{
+        "id": id_schema,
+        "name": name_schema,
+    },
+    "required": ["id"]
+}
+image_schema = {
+    "type":"object",
+    "properties":{
+        "id": id_schema,
+        "name": name_schema,
+    },
+    "required": ["id","name"]
+}
+server_schema = {
+    "type":"object",
+    "properties":{
+        "id":id_schema,
+        "name": name_schema,
+    },
+    "required": ["id","name"]
+}
+new_host_response_schema = {
+    "title":"host response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "host": host_schema
+    },
+    "required": ["host"],
+    "additionalProperties": False
+}
+
+get_images_response_schema = {
+    "title":"openvim images response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "images":{
+            "type":"array",
+            "items": image_schema,
+        }
+    },
+    "required": ["images"],
+    "additionalProperties": False
+}
+
+get_hosts_response_schema = {
+    "title":"openvim hosts response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "hosts":{
+            "type":"array",
+            "items": host_schema,
+        }
+    },
+    "required": ["hosts"],
+    "additionalProperties": False
+}
+
+get_host_detail_response_schema = new_host_response_schema # TODO: Content is not parsed yet
+
+get_server_response_schema = {
+    "title":"openvim server response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "servers":{
+            "type":"array",
+            "items": server_schema,
+        }
+    },
+    "required": ["servers"],
+    "additionalProperties": False
+}
+
+new_tenant_response_schema = {
+    "title":"tenant response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "tenant":{
+            "type":"object",
+            "properties":{
+                "id": id_schema,
+                "name": nameshort_schema,
+                "description":description_schema,
+                "enabled":{"type" : "boolean"}
+            },
+            "required": ["id"]
+        }
+    },
+    "required": ["tenant"],
+    "additionalProperties": False
+}
+
+new_network_response_schema = {
+    "title":"network response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "network":{
+            "type":"object",
+            "properties":{
+                "id":id_schema,
+                "name":name_schema,
+                "type":{"type":"string", "enum":["bridge_man","bridge_data","data", "ptp"]},
+                "shared":{"type":"boolean"},
+                "tenant_id":id_schema,
+                "admin_state_up":{"type":"boolean"},
+                "vlan":vlan1000_schema
+            },
+            "required": ["id"]
+        }
+    },
+    "required": ["network"],
+    "additionalProperties": False
+}
+
+
+# get_network_response_schema = {
+#     "title":"get network response information schema",
+#     "$schema": "http://json-schema.org/draft-04/schema#",
+#     "type":"object",
+#     "properties":{
+#         "network":{
+#             "type":"object",
+#             "properties":{
+#                 "id":id_schema,
+#                 "name":name_schema,
+#                 "type":{"type":"string", "enum":["bridge_man","bridge_data","data", "ptp"]},
+#                 "shared":{"type":"boolean"},
+#                 "tenant_id":id_schema,
+#                 "admin_state_up":{"type":"boolean"},
+#                 "vlan":vlan1000_schema
+#             },
+#             "required": ["id"]
+#         }
+#     },
+#     "required": ["network"],
+#     "additionalProperties": False
+# }
+
+
+new_port_response_schema = {
+    "title":"port response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "port":{
+            "type":"object",
+            "properties":{
+                "id":id_schema,
+            },
+            "required": ["id"]
+        }
+    },
+    "required": ["port"],
+    "additionalProperties": False
+}
+
+get_flavor_response_schema = {
+    "title":"openvim flavors response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "flavor":{
+            "type":"object",
+            "properties":{
+                "id":   id_schema,
+                "name": name_schema,
+                "extended": {"type":"object"},
+            },
+            "required": ["id", "name"],
+        }
+    },
+    "required": ["flavor"],
+    "additionalProperties": False
+}
+
+new_flavor_response_schema = {
+    "title":"flavor response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "flavor":{
+            "type":"object",
+            "properties":{
+                "id":id_schema,
+            },
+            "required": ["id"]
+        }
+    },
+    "required": ["flavor"],
+    "additionalProperties": False
+}
+
+get_image_response_schema = {
+    "title":"openvim images response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "image":{
+            "type":"object",
+            "properties":{
+                "id":   id_schema,
+                "name": name_schema,
+            },
+            "required": ["id", "name"],
+        }
+    },
+    "required": ["flavor"],
+    "additionalProperties": False
+}
+new_image_response_schema = {
+    "title":"image response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "image":{
+            "type":"object",
+            "properties":{
+                "id":id_schema,
+            },
+            "required": ["id"]
+        }
+    },
+    "required": ["image"],
+    "additionalProperties": False
+}
+
+new_vminstance_response_schema = {
+    "title":"server response information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "server":{
+            "type":"object",
+            "properties":{
+                "id":id_schema,
+            },
+            "required": ["id"]
+        }
+    },
+    "required": ["server"],
+    "additionalProperties": False
+}
+
+get_processor_rankings_response_schema = {
+    "title":"processor rankings information schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type":"object",
+    "properties":{
+        "rankings":{
+            "type":"array",
+            "items":{
+                "type":"object",
+                "properties":{
+                    "model": description_schema,
+                    "value": integer0_schema
+                },
+                "additionalProperties": False,
+                "required": ["model","value"]
+            }
+        },
+        "additionalProperties": False,
+        "required": ["rankings"]
+    }
+}
+
+class vimconnector(vimconn.vimconnector):
+    def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None,
+                 log_level="DEBUG", config={}, persistent_info={}):
+        vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level, config)
+        self.tenant = None
+        self.headers_req = {'content-type': 'application/json'}
+        self.logger = logging.getLogger('openmano.vim.openvim')
+        self.persistent_info = persistent_info
+        if tenant_id:
+            self.tenant = tenant_id
+
+    def __setitem__(self,index, value):
+        '''Set individuals parameters 
+        Throw TypeError, KeyError
+        '''
+        if index=='tenant_id':
+            self.tenant = value
+        elif index=='tenant_name':
+            self.tenant = None
+        vimconn.vimconnector.__setitem__(self,index, value)    
+
+    def _get_my_tenant(self):
+        '''Obtain uuid of my tenant from name
+        '''
+        if self.tenant:
+            return self.tenant
+
+        url = self.url+'/tenants?name='+ quote(self.tenant_name)
+        self.logger.info("Getting VIM tenant_id GET %s", url)
+        vim_response = requests.get(url, headers = self.headers_req)
+        self._check_http_request_response(vim_response)
+        try:
+            tenant_list = vim_response.json()["tenants"]
+            if len(tenant_list) == 0:
+                raise vimconn.vimconnNotFoundException("No tenant found for name '%s'" % str(self.tenant_name))
+            elif len(tenant_list) > 1:
+                raise vimconn.vimconnConflictException ("More that one tenant found for name '%s'" % str(self.tenant_name))
+            self.tenant = tenant_list[0]["id"]
+            return self.tenant
+        except Exception as e:
+            raise vimconn.vimconnUnexpectedResponse("Get VIM tenant {} '{}'".format(type(e).__name__, str(e)))
+
+    def _format_jsonerror(self,http_response):
+        #DEPRECATED, to delete in the future
+        try:
+            data = http_response.json()
+            return data["error"]["description"]
+        except:
+            return http_response.text
+
+    def _format_in(self, http_response, schema):
+        #DEPRECATED, to delete in the future
+        try:
+            client_data = http_response.json()
+            js_v(client_data, schema)
+            #print "Input data: ", str(client_data)
+            return True, client_data
+        except js_e.ValidationError as exc:
+            print "validate_in error, jsonschema exception ", exc.message, "at", exc.path
+            return False, ("validate_in error, jsonschema exception ", exc.message, "at", exc.path)
+    
+    def _remove_extra_items(self, data, schema):
+        deleted=[]
+        if type(data) is tuple or type(data) is list:
+            for d in data:
+                a= self._remove_extra_items(d, schema['items'])
+                if a is not None: deleted.append(a)
+        elif type(data) is dict:
+            for k in data.keys():
+                if 'properties' not in schema or k not in schema['properties'].keys():
+                    del data[k]
+                    deleted.append(k)
+                else:
+                    a = self._remove_extra_items(data[k], schema['properties'][k])
+                    if a is not None:  deleted.append({k:a})
+        if len(deleted) == 0: return None
+        elif len(deleted) == 1: return deleted[0]
+        else: return deleted
+        
+    def _format_request_exception(self, request_exception):
+        '''Transform a request exception into a vimconn exception'''
+        if isinstance(request_exception, js_e.ValidationError):
+            raise vimconn.vimconnUnexpectedResponse("jsonschema exception '{}' at '{}'".format(request_exception.message, request_exception.path))            
+        elif isinstance(request_exception, requests.exceptions.HTTPError):
+            raise vimconn.vimconnUnexpectedResponse(type(request_exception).__name__ + ": " + str(request_exception))
+        else:
+            raise vimconn.vimconnConnectionException(type(request_exception).__name__ + ": " + str(request_exception))
+
+    def _check_http_request_response(self, request_response):
+        '''Raise a vimconn exception if the response is not Ok'''
+        if request_response.status_code >= 200 and  request_response.status_code < 300:
+            return
+        if request_response.status_code == vimconn.HTTP_Unauthorized:
+            raise vimconn.vimconnAuthException(request_response.text)
+        elif request_response.status_code == vimconn.HTTP_Not_Found:
+            raise vimconn.vimconnNotFoundException(request_response.text)
+        elif request_response.status_code == vimconn.HTTP_Conflict:
+            raise vimconn.vimconnConflictException(request_response.text)
+        else: 
+            raise vimconn.vimconnUnexpectedResponse("VIM HTTP_response {}, {}".format(request_response.status_code, str(request_response.text)))
+
+    def new_tenant(self,tenant_name,tenant_description):
+        '''Adds a new tenant to VIM with this name and description, returns the tenant identifier'''
+        #print "VIMConnector: Adding a new tenant to VIM"
+        payload_dict = {"tenant": {"name":tenant_name,"description": tenant_description, "enabled": True}}
+        payload_req = json.dumps(payload_dict)
+        try:
+            url = self.url_admin+'/tenants'
+            self.logger.info("Adding a new tenant %s", url)
+            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, new_tenant_response_schema)
+            #r = self._remove_extra_items(response, new_tenant_response_schema)
+            #if r is not None: 
+            #    self.logger.warn("Warning: remove extra items %s", str(r))
+            tenant_id = response['tenant']['id']
+            return tenant_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def delete_tenant(self,tenant_id):
+        '''Delete a tenant from VIM. Returns the old tenant identifier'''
+        try:
+            url = self.url_admin+'/tenants/'+tenant_id
+            self.logger.info("Delete a tenant DELETE %s", url)
+            vim_response = requests.delete(url, headers = self.headers_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            return tenant_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def get_tenant_list(self, filter_dict={}):
+        '''Obtain tenants of VIM
+        filter_dict can contain the following keys:
+            name: filter by tenant name
+            id: filter by tenant uuid/id
+            <other VIM specific>
+        Returns the tenant list of dictionaries: [{'name':'<name>, 'id':'<id>, ...}, ...]
+        '''
+        filterquery=[]
+        filterquery_text=''
+        for k,v in filter_dict.iteritems():
+            filterquery.append(str(k)+'='+str(v))
+        if len(filterquery)>0:
+            filterquery_text='?'+ '&'.join(filterquery)
+        try:
+            url = self.url+'/tenants'+filterquery_text
+            self.logger.info("get_tenant_list GET %s", url)
+            vim_response = requests.get(url, headers = self.headers_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            return vim_response.json()["tenants"]
+        except requests.exceptions.RequestException as e:
+            self._format_request_exception(e)
+
+    def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None): #, **vim_specific):
+        '''Adds a tenant network to VIM'''
+        '''Returns the network identifier'''
+        try:
+            self._get_my_tenant()
+            if net_type=="bridge":
+                net_type="bridge_data"
+            payload_req = {"name": net_name, "type": net_type, "tenant_id": self.tenant, "shared": shared}
+            if vlan:
+                payload_req["provider:vlan"] = vlan
+            # payload_req.update(vim_specific)
+            url = self.url+'/networks'
+            self.logger.info("Adding a new network POST: %s  DATA: %s", url, str(payload_req))
+            vim_response = requests.post(url, headers = self.headers_req, data=json.dumps({"network": payload_req}) )
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, new_network_response_schema)
+            #r = self._remove_extra_items(response, new_network_response_schema)
+            #if r is not None: 
+            #    self.logger.warn("Warning: remove extra items %s", str(r))
+            network_id = response['network']['id']
+            return network_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+        
+    def get_network_list(self, filter_dict={}):
+        '''Obtain tenant networks of VIM
+        Filter_dict can be:
+            name: network name
+            id: network uuid
+            public: boolean
+            tenant_id: tenant
+            admin_state_up: boolean
+            status: 'ACTIVE'
+        Returns the network list of dictionaries
+        '''
+        try:
+            if 'tenant_id' not in filter_dict:
+                filter_dict["tenant_id"] = self._get_my_tenant()
+            elif not filter_dict["tenant_id"]:
+                del filter_dict["tenant_id"]
+            filterquery=[]
+            filterquery_text=''
+            for k,v in filter_dict.iteritems():
+                filterquery.append(str(k)+'='+str(v))
+            if len(filterquery)>0:
+                filterquery_text='?'+ '&'.join(filterquery)
+            url = self.url+'/networks'+filterquery_text
+            self.logger.info("Getting network list GET %s", url)
+            vim_response = requests.get(url, headers = self.headers_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            return response['networks']
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def get_network(self, net_id):
+        '''Obtain network details of network id'''
+        try:
+            url = self.url+'/networks/'+net_id
+            self.logger.info("Getting network GET %s", url)
+            vim_response = requests.get(url, headers = self.headers_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            return response['network']
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+            
+    def delete_network(self, net_id):
+        '''Deletes a tenant network from VIM'''
+        '''Returns the network identifier'''
+        try:
+            self._get_my_tenant()
+            url = self.url+'/networks/'+net_id
+            self.logger.info("Deleting VIM network DELETE %s", url)
+            vim_response = requests.delete(url, headers=self.headers_req)
+            self._check_http_request_response(vim_response)
+            #self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            return net_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def get_flavor(self, flavor_id):
+        '''Obtain flavor details from the  VIM'''
+        try:
+            self._get_my_tenant()
+            url = self.url+'/'+self.tenant+'/flavors/'+flavor_id
+            self.logger.info("Getting flavor GET %s", url)
+            vim_response = requests.get(url, headers = self.headers_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, get_flavor_response_schema)
+            r = self._remove_extra_items(response, get_flavor_response_schema)
+            if r is not None: 
+                self.logger.warn("Warning: remove extra items %s", str(r))
+            return response['flavor']
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+        
+    def new_flavor(self, flavor_data):
+        '''Adds a tenant flavor to VIM'''
+        '''Returns the flavor identifier'''
+        try:
+            new_flavor_dict = flavor_data.copy()
+            new_flavor_dict["name"] = flavor_data["name"][:64]
+            self._get_my_tenant()
+            payload_req = json.dumps({'flavor': new_flavor_dict})
+            url = self.url+'/'+self.tenant+'/flavors'
+            self.logger.info("Adding a new VIM flavor POST %s", url)
+            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, new_flavor_response_schema)
+            r = self._remove_extra_items(response, new_flavor_response_schema)
+            if r is not None: 
+                self.logger.warn("Warning: remove extra items %s", str(r))
+            flavor_id = response['flavor']['id']
+            return flavor_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def delete_flavor(self,flavor_id):
+        '''Deletes a tenant flavor from VIM'''
+        '''Returns the old flavor_id'''
+        try:
+            self._get_my_tenant()
+            url = self.url+'/'+self.tenant+'/flavors/'+flavor_id
+            self.logger.info("Deleting VIM flavor DELETE %s", url)
+            vim_response = requests.delete(url, headers=self.headers_req)
+            self._check_http_request_response(vim_response)
+            #self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            return flavor_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def get_image(self, image_id):
+        '''Obtain image details from the  VIM'''
+        try:
+            self._get_my_tenant()
+            url = self.url+'/'+self.tenant+'/images/'+image_id
+            self.logger.info("Getting image GET %s", url)
+            vim_response = requests.get(url, headers = self.headers_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, get_image_response_schema)
+            r = self._remove_extra_items(response, get_image_response_schema)
+            if r is not None: 
+                self.logger.warn("Warning: remove extra items %s", str(r))
+            return response['image']
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def new_image(self,image_dict):
+        ''' Adds a tenant image to VIM, returns image_id'''
+        try:
+            self._get_my_tenant()
+            new_image_dict={'name': image_dict['name'][:64]}
+            if image_dict.get('description'):
+                new_image_dict['description'] = image_dict['description']
+            if image_dict.get('metadata'):
+                new_image_dict['metadata'] = yaml.load(image_dict['metadata'])
+            if image_dict.get('location'):
+                new_image_dict['path'] = image_dict['location']
+            payload_req = json.dumps({"image":new_image_dict})
+            url=self.url + '/' + self.tenant + '/images'
+            self.logger.info("Adding a new VIM image POST %s", url)
+            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, new_image_response_schema)
+            r = self._remove_extra_items(response, new_image_response_schema)
+            if r is not None: 
+                self.logger.warn("Warning: remove extra items %s", str(r))
+            image_id = response['image']['id']
+            return image_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+            
+    def delete_image(self, image_id):
+        '''Deletes a tenant image from VIM'''
+        '''Returns the deleted image_id'''
+        try:
+            self._get_my_tenant()
+            url = self.url + '/'+ self.tenant +'/images/'+image_id
+            self.logger.info("Deleting VIM image DELETE %s", url)
+            vim_response = requests.delete(url, headers=self.headers_req)
+            self._check_http_request_response(vim_response)
+            #self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            return image_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    
+    def get_image_id_from_path(self, path):
+        '''Get the image id from image path in the VIM database. Returns the image_id'''
+        try:
+            self._get_my_tenant()
+            url=self.url + '/' + self.tenant + '/images?path='+quote(path)
+            self.logger.info("Getting images GET %s", url)
+            vim_response = requests.get(url)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, get_images_response_schema)
+            #r = self._remove_extra_items(response, get_images_response_schema)
+            #if r is not None: 
+            #    self.logger.warn("Warning: remove extra items %s", str(r))
+            if len(response['images'])==0:
+                raise vimconn.vimconnNotFoundException("Image not found at VIM with path '%s'", path)
+            elif len(response['images'])>1:
+                raise vimconn.vimconnConflictException("More than one image found at VIM with path '%s'", path)
+            return response['images'][0]['id']
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def get_image_list(self, filter_dict={}):
+        '''Obtain tenant images from VIM
+        Filter_dict can be:
+            name: image name
+            id: image uuid
+            checksum: image checksum
+            location: image path
+        Returns the image list of dictionaries:
+            [{<the fields at Filter_dict plus some VIM specific>}, ...]
+            List can be empty
+        '''
+        try:
+            self._get_my_tenant()
+            filterquery=[]
+            filterquery_text=''
+            for k,v in filter_dict.iteritems():
+                filterquery.append(str(k)+'='+str(v))
+            if len(filterquery)>0:
+                filterquery_text='?'+ '&'.join(filterquery)
+            url = self.url+'/'+self.tenant+'/images'+filterquery_text
+            self.logger.info("Getting image list GET %s", url)
+            vim_response = requests.get(url, headers = self.headers_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            return response['images']
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def new_vminstancefromJSON(self, vm_data):
+        '''Adds a VM instance to VIM'''
+        '''Returns the instance identifier'''
+        try:
+            self._get_my_tenant()
+        except Exception as e:
+            return -vimconn.HTTP_Not_Found, str(e)
+        print "VIMConnector: Adding a new VM instance from JSON to VIM"
+        payload_req = vm_data
+        try:
+            vim_response = requests.post(self.url+'/'+self.tenant+'/servers', headers = self.headers_req, data=payload_req)
+        except requests.exceptions.RequestException as e:
+            print "new_vminstancefromJSON Exception: ", e.args
+            return -vimconn.HTTP_Not_Found, str(e.args[0])
+        print vim_response
+        #print vim_response.status_code
+        if vim_response.status_code == 200:
+            #print vim_response.json()
+            #print json.dumps(vim_response.json(), indent=4)
+            res,http_content = self._format_in(vim_response, new_image_response_schema)
+            #print http_content
+            if res:
+                r = self._remove_extra_items(http_content, new_image_response_schema)
+                if r is not None: print "Warning: remove extra items ", r
+                #print http_content
+                vminstance_id = http_content['server']['id']
+                print "Tenant image id: ",vminstance_id
+                return vim_response.status_code,vminstance_id
+            else: return -vimconn.HTTP_Bad_Request,http_content
+        else:
+            #print vim_response.text
+            jsonerror = self._format_jsonerror(vim_response)
+            text = 'Error in VIM "%s": not possible to add new vm instance. HTTP Response: %d. Error: %s' % (self.url, vim_response.status_code, jsonerror)
+            #print text
+            return -vim_response.status_code,text
+
+    def new_vminstance(self,name,description,start,image_id,flavor_id,net_list, cloud_config=None, disk_list=None):
+        '''Adds a VM instance to VIM
+        Params:
+            start: indicates if VM must start or boot in pause mode. Ignored
+            image_id,flavor_id: image and flavor uuid
+            net_list: list of interfaces, each one is a dictionary with:
+                name:
+                net_id: network uuid to connect
+                vpci: virtual vcpi to assign
+                model: interface model, virtio, e2000, ...
+                mac_address: 
+                use: 'data', 'bridge',  'mgmt'
+                type: 'virtual', 'PF', 'VF', 'VFnotShared'
+                vim_id: filled/added by this function
+                #TODO ip, security groups
+        Returns the instance identifier
+        '''
+        self.logger.debug("new_vminstance input: image='%s' flavor='%s' nics='%s'", image_id, flavor_id, str(net_list))
+        try:
+            self._get_my_tenant()
+#            net_list = []
+#            for k,v in net_dict.items():
+#                print k,v
+#                net_list.append('{"name":"' + k + '", "uuid":"' + v + '"}')
+#            net_list_string = ', '.join(net_list) 
+            virtio_net_list=[]
+            for net in net_list:
+                if not net.get("net_id"):
+                    continue
+                net_dict={'uuid': net["net_id"]}
+                if net.get("type"):        net_dict["type"] = net["type"]
+                if net.get("name"):        net_dict["name"] = net["name"]
+                if net.get("vpci"):        net_dict["vpci"] = net["vpci"]
+                if net.get("model"):       net_dict["model"] = net["model"]
+                if net.get("mac_address"): net_dict["mac_address"] = net["mac_address"]
+                virtio_net_list.append(net_dict)
+            payload_dict={  "name":        name[:64],
+                            "description": description,
+                            "imageRef":    image_id,
+                            "flavorRef":   flavor_id,
+                            "networks": virtio_net_list
+                        }
+            if start != None:
+                payload_dict["start"] = start
+            payload_req = json.dumps({"server": payload_dict})
+            url = self.url+'/'+self.tenant+'/servers'
+            self.logger.info("Adding a new vm POST %s DATA %s", url, payload_req)
+            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, new_vminstance_response_schema)
+            #r = self._remove_extra_items(response, new_vminstance_response_schema)
+            #if r is not None: 
+            #    self.logger.warn("Warning: remove extra items %s", str(r))
+            vminstance_id = response['server']['id']
+
+            #connect data plane interfaces to network
+            for net in net_list:
+                if net["type"]=="virtual":
+                    if not net.get("net_id"):
+                        continue
+                    for iface in response['server']['networks']:
+                        if "name" in net:
+                            if net["name"]==iface["name"]:
+                                net["vim_id"] = iface['iface_id']
+                                break
+                        elif "net_id" in net:
+                            if net["net_id"]==iface["net_id"]:
+                                net["vim_id"] = iface['iface_id']
+                                break
+                else: #dataplane
+                    for numa in response['server'].get('extended',{}).get('numas',() ):
+                        for iface in numa.get('interfaces',() ):
+                            if net['name'] == iface['name']:
+                                net['vim_id'] = iface['iface_id']
+                                #Code bellow is not needed, current openvim connect dataplane interfaces 
+                                #if net.get("net_id"):
+                                ##connect dataplane interface
+                                #    result, port_id = self.connect_port_network(iface['iface_id'], net["net_id"])
+                                #    if result < 0:
+                                #        error_text = "Error attaching port %s to network %s: %s." % (iface['iface_id'], net["net_id"], port_id)
+                                #        print "new_vminstance: " + error_text
+                                #        self.delete_vminstance(vminstance_id)
+                                #        return result, error_text
+                                break
+        
+            return vminstance_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+        
+    def get_vminstance(self, vm_id):
+        '''Returns the VM instance information from VIM'''
+        try:
+            self._get_my_tenant()
+            url = self.url+'/'+self.tenant+'/servers/'+vm_id
+            self.logger.info("Getting vm GET %s", url)
+            vim_response = requests.get(url, headers = self.headers_req)
+            vim_response = requests.get(url, headers = self.headers_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, new_vminstance_response_schema)
+            #r = self._remove_extra_items(response, new_vminstance_response_schema)
+            #if r is not None: 
+            #    self.logger.warn("Warning: remove extra items %s", str(r))
+            return response['server']
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+        
+    def delete_vminstance(self, vm_id):
+        '''Removes a VM instance from VIM, returns the deleted vm_id'''
+        try:
+            self._get_my_tenant()
+            url = self.url+'/'+self.tenant+'/servers/'+vm_id
+            self.logger.info("Deleting VIM vm DELETE %s", url)
+            vim_response = requests.delete(url, headers=self.headers_req)
+            self._check_http_request_response(vim_response)
+            #self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            return vm_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+    def refresh_vms_status(self, vm_list):
+        '''Refreshes the status of the virtual machines'''
+        try:
+            self._get_my_tenant()
+        except requests.exceptions.RequestException as e:
+            self._format_request_exception(e)
+        vm_dict={}
+        for vm_id in vm_list:
+            vm={}
+            #print "VIMConnector refresh_tenant_vms and nets: Getting tenant VM instance information from VIM"
+            try:
+                url = self.url+'/'+self.tenant+'/servers/'+ vm_id
+                self.logger.info("Getting vm GET %s", url)
+                vim_response = requests.get(url, headers = self.headers_req)
+                self._check_http_request_response(vim_response)
+                response = vim_response.json()
+                js_v(response, new_vminstance_response_schema)
+                if response['server']['status'] in vmStatus2manoFormat:
+                    vm['status'] = vmStatus2manoFormat[ response['server']['status']  ]
+                else:
+                    vm['status'] = "OTHER"
+                    vm['error_msg'] = "VIM status reported " + response['server']['status']
+                if response['server'].get('last_error'):
+                    vm['error_msg'] = response['server']['last_error']
+                vm["vim_info"] = yaml.safe_dump(response['server'])
+                #get interfaces info
+                try:
+                    management_ip = False
+                    url2 = self.url+'/ports?device_id='+ quote(vm_id)
+                    self.logger.info("Getting PORTS GET %s", url2)
+                    vim_response2 = requests.get(url2, headers = self.headers_req)
+                    self._check_http_request_response(vim_response2)
+                    client_data = vim_response2.json()
+                    if isinstance(client_data.get("ports"), list):
+                        vm["interfaces"]=[]
+                    for port in client_data.get("ports"):
+                        interface={}
+                        interface['vim_info']  = yaml.safe_dump(port)
+                        interface["mac_address"] = port.get("mac_address")
+                        interface["vim_net_id"] = port.get("network_id")
+                        interface["vim_interface_id"] = port["id"]
+                        interface["ip_address"] = port.get("ip_address")
+                        if interface["ip_address"]:
+                            management_ip = True
+                        if interface["ip_address"] == "0.0.0.0":
+                            interface["ip_address"] = None
+                        vm["interfaces"].append(interface)
+                        
+                except Exception as e:
+                    self.logger.error("refresh_vms_and_nets. Port get %s: %s", type(e).__name__, str(e))
+
+                if vm['status'] == "ACTIVE" and not management_ip:
+                    vm['status'] = "ACTIVE:NoMgmtIP"
+                    
+            except vimconn.vimconnNotFoundException as e:
+                self.logger.error("Exception getting vm status: %s", str(e))
+                vm['status'] = "DELETED"
+                vm['error_msg'] = str(e)
+            except (requests.exceptions.RequestException, js_e.ValidationError, vimconn.vimconnException) as e:
+                self.logger.error("Exception getting vm status: %s", str(e))
+                vm['status'] = "VIM_ERROR"
+                vm['error_msg'] = str(e)
+            vm_dict[vm_id] = vm
+        return vm_dict
+
+    def refresh_nets_status(self, net_list):
+        '''Get the status of the networks
+           Params: the list of network identifiers
+           Returns a dictionary with:
+                net_id:         #VIM id of this network
+                    status:     #Mandatory. Text with one of:
+                                #  DELETED (not found at vim)
+                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
+                                #  OTHER (Vim reported other status not understood)
+                                #  ERROR (VIM indicates an ERROR status)
+                                #  ACTIVE, INACTIVE, DOWN (admin down), 
+                                #  BUILD (on building process)
+                                #
+                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
+                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+
+        '''
+        try:
+            self._get_my_tenant()
+        except requests.exceptions.RequestException as e:
+            self._format_request_exception(e)
+        
+        net_dict={}
+        for net_id in net_list:
+            net = {}
+            #print "VIMConnector refresh_tenant_vms_and_nets: Getting tenant network from VIM (tenant: " + str(self.tenant) + "): "
+            try:
+                net_vim = self.get_network(net_id)
+                if net_vim['status'] in netStatus2manoFormat:
+                    net["status"] = netStatus2manoFormat[ net_vim['status'] ]
+                else:
+                    net["status"] = "OTHER"
+                    net["error_msg"] = "VIM status reported " + net_vim['status']
+                    
+                if net["status"] == "ACTIVE" and not net_vim['admin_state_up']:
+                    net["status"] = "DOWN"
+                if net_vim.get('last_error'):
+                    net['error_msg'] = net_vim['last_error']
+                net["vim_info"] = yaml.safe_dump(net_vim)
+            except vimconn.vimconnNotFoundException as e:
+                self.logger.error("Exception getting net status: %s", str(e))
+                net['status'] = "DELETED"
+                net['error_msg'] = str(e)
+            except (requests.exceptions.RequestException, js_e.ValidationError, vimconn.vimconnException) as e:
+                self.logger.error("Exception getting net status: %s", str(e))
+                net['status'] = "VIM_ERROR"
+                net['error_msg'] = str(e)
+            net_dict[net_id] = net
+        return net_dict
+    
+    def action_vminstance(self, vm_id, action_dict):
+        '''Send and action over a VM instance from VIM'''
+        '''Returns the status'''
+        try:
+            self._get_my_tenant()
+            if "console" in action_dict:
+                raise vimconn.vimconnException("getting console is not available at openvim", http_code=vimconn.HTTP_Service_Unavailable)
+            url = self.url+'/'+self.tenant+'/servers/'+vm_id+"/action"
+            self.logger.info("Action over VM instance POST %s", url)
+            vim_response = requests.post(url, headers = self.headers_req, data=json.dumps(action_dict) )
+            self._check_http_request_response(vim_response)
+            return vm_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+
+#NOT USED METHODS in current version        
+  
+    def host_vim2gui(self, host, server_dict):
+        '''Transform host dictionary from VIM format to GUI format,
+        and append to the server_dict
+        '''
+        if type(server_dict) is not dict: 
+            print 'vimconnector.host_vim2gui() ERROR, param server_dict must be a dictionary'
+            return
+        RAD={}
+        occupation={}
+        for numa in host['host']['numas']:
+            RAD_item={}
+            occupation_item={}
+            #memory
+            RAD_item['memory']={'size': str(numa['memory'])+'GB', 'eligible': str(numa['hugepages'])+'GB'}
+            occupation_item['memory']= str(numa['hugepages_consumed'])+'GB'
+            #cpus
+            RAD_item['cpus']={}
+            RAD_item['cpus']['cores'] = []
+            RAD_item['cpus']['eligible_cores'] = []
+            occupation_item['cores']=[]
+            for _ in range(0, len(numa['cores']) / 2):
+                RAD_item['cpus']['cores'].append( [] )
+            for core in numa['cores']:
+                RAD_item['cpus']['cores'][core['core_id']].append(core['thread_id'])
+                if not 'status' in core: RAD_item['cpus']['eligible_cores'].append(core['thread_id'])
+                if 'instance_id' in core: occupation_item['cores'].append(core['thread_id'])
+            #ports
+            RAD_item['ports']={}
+            occupation_item['ports']={}
+            for iface in numa['interfaces']:
+                RAD_item['ports'][ iface['pci'] ] = 'speed:'+str(iface['Mbps'])+'M'
+                occupation_item['ports'][ iface['pci'] ] = { 'occupied': str(100*iface['Mbps_consumed'] / iface['Mbps']) + "%" }
+                
+            RAD[ numa['numa_socket'] ] = RAD_item
+            occupation[ numa['numa_socket'] ] = occupation_item
+        server_dict[ host['host']['name'] ] = {'RAD':RAD, 'occupation':occupation}
+
+    def get_hosts_info(self):
+        '''Get the information of deployed hosts
+        Returns the hosts content'''
+    #obtain hosts list
+        url=self.url+'/hosts'
+        try:
+            vim_response = requests.get(url)
+        except requests.exceptions.RequestException as e:
+            print "get_hosts_info Exception: ", e.args
+            return -vimconn.HTTP_Not_Found, str(e.args[0])
+        print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
+        #print vim_response.status_code
+        #print json.dumps(vim_response.json(), indent=4)
+        if vim_response.status_code != 200:
+            #TODO: get error
+            print 'vimconnector.get_hosts_info error getting host list %d %s' %(vim_response.status_code, vim_response.json())
+            return -vim_response.status_code, "Error getting host list"
+        
+        res,hosts = self._format_in(vim_response, get_hosts_response_schema)
+            
+        if res==False:
+            print "vimconnector.get_hosts_info error parsing GET HOSTS vim response", hosts
+            return vimconn.HTTP_Internal_Server_Error, hosts
+    #obtain hosts details
+        hosts_dict={}
+        for host in hosts['hosts']:
+            url=self.url+'/hosts/'+host['id']
+            try:
+                vim_response = requests.get(url)
+            except requests.exceptions.RequestException as e:
+                print "get_hosts_info Exception: ", e.args
+                return -vimconn.HTTP_Not_Found, str(e.args[0])
+            print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
+            if vim_response.status_code != 200:
+                print 'vimconnector.get_hosts_info error getting detailed host %d %s' %(vim_response.status_code, vim_response.json())
+                continue
+            res,host_detail = self._format_in(vim_response, get_host_detail_response_schema)
+            if res==False:
+                print "vimconnector.get_hosts_info error parsing GET HOSTS/%s vim response" % host['id'], host_detail
+                continue
+            #print 'host id '+host['id'], json.dumps(host_detail, indent=4)
+            self.host_vim2gui(host_detail, hosts_dict)
+        return 200, hosts_dict
+
+    def get_hosts(self, vim_tenant):
+        '''Get the hosts and deployed instances
+        Returns the hosts content'''
+    #obtain hosts list
+        url=self.url+'/hosts'
+        try:
+            vim_response = requests.get(url)
+        except requests.exceptions.RequestException as e:
+            print "get_hosts Exception: ", e.args
+            return -vimconn.HTTP_Not_Found, str(e.args[0])
+        print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
+        #print vim_response.status_code
+        #print json.dumps(vim_response.json(), indent=4)
+        if vim_response.status_code != 200:
+            #TODO: get error
+            print 'vimconnector.get_hosts error getting host list %d %s' %(vim_response.status_code, vim_response.json())
+            return -vim_response.status_code, "Error getting host list"
+        
+        res,hosts = self._format_in(vim_response, get_hosts_response_schema)
+            
+        if res==False:
+            print "vimconnector.get_host error parsing GET HOSTS vim response", hosts
+            return vimconn.HTTP_Internal_Server_Error, hosts
+    #obtain instances from hosts
+        for host in hosts['hosts']:
+            url=self.url+'/' + vim_tenant + '/servers?hostId='+host['id']
+            try:
+                vim_response = requests.get(url)
+            except requests.exceptions.RequestException as e:
+                print "get_hosts Exception: ", e.args
+                return -vimconn.HTTP_Not_Found, str(e.args[0])
+            print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
+            if vim_response.status_code != 200:
+                print 'vimconnector.get_hosts error getting instances at host %d %s' %(vim_response.status_code, vim_response.json())
+                continue
+            res,servers = self._format_in(vim_response, get_server_response_schema)
+            if res==False:
+                print "vimconnector.get_host error parsing GET SERVERS/%s vim response" % host['id'], servers
+                continue
+            #print 'host id '+host['id'], json.dumps(host_detail, indent=4)
+            host['instances'] = servers['servers']
+        return 200, hosts['hosts']
+
+    def get_processor_rankings(self):
+        '''Get the processor rankings in the VIM database'''
+        url=self.url+'/processor_ranking'
+        try:
+            vim_response = requests.get(url)
+        except requests.exceptions.RequestException as e:
+            print "get_processor_rankings Exception: ", e.args
+            return -vimconn.HTTP_Not_Found, str(e.args[0])
+        print "vim get", url, "response:", vim_response.status_code, vim_response.json()
+        #print vim_response.status_code
+        #print json.dumps(vim_response.json(), indent=4)
+        if vim_response.status_code != 200:
+            #TODO: get error
+            print 'vimconnector.get_processor_rankings error getting processor rankings %d %s' %(vim_response.status_code, vim_response.json())
+            return -vim_response.status_code, "Error getting processor rankings"
+        
+        res,rankings = self._format_in(vim_response, get_processor_rankings_response_schema)
+        return res, rankings['rankings']
+    
+    def new_host(self, host_data):
+        '''Adds a new host to VIM'''
+        '''Returns status code of the VIM response'''
+        payload_req = host_data
+        try:
+            url = self.url_admin+'/hosts'
+            self.logger.info("Adding a new host POST %s", url)
+            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
+            self._check_http_request_response(vim_response)
+            self.logger.debug(vim_response.text)
+            #print json.dumps(vim_response.json(), indent=4)
+            response = vim_response.json()
+            js_v(response, new_host_response_schema)
+            r = self._remove_extra_items(response, new_host_response_schema)
+            if r is not None: 
+                self.logger.warn("Warning: remove extra items %s", str(r))
+            host_id = response['host']['id']
+            return host_id
+        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
+            self._format_request_exception(e)
+    
+    def new_external_port(self, port_data):
+        '''Adds a external port to VIM'''
+        '''Returns the port identifier'''
+        #TODO change to logging exception code policies
+        print "VIMConnector: Adding a new external port"
+        payload_req = port_data
+        try:
+            vim_response = requests.post(self.url_admin+'/ports', headers = self.headers_req, data=payload_req)
+        except requests.exceptions.RequestException as e:
+            self.logger.error("new_external_port Exception: ", str(e))
+            return -vimconn.HTTP_Not_Found, str(e.args[0])
+        print vim_response
+        #print vim_response.status_code
+        if vim_response.status_code == 200:
+        #print vim_response.json()
+        #print json.dumps(vim_response.json(), indent=4)
+            res, http_content = self._format_in(vim_response, new_port_response_schema)
+        #print http_content
+            if res:
+                r = self._remove_extra_items(http_content, new_port_response_schema)
+                if r is not None: print "Warning: remove extra items ", r
+                #print http_content
+                port_id = http_content['port']['id']
+                print "Port id: ",port_id
+                return vim_response.status_code,port_id
+            else: return -vimconn.HTTP_Bad_Request,http_content
+        else:
+            #print vim_response.text
+            jsonerror = self._format_jsonerror(vim_response)
+            text = 'Error in VIM "%s": not possible to add new external port. HTTP Response: %d. Error: %s' % (self.url_admin, vim_response.status_code, jsonerror)
+            #print text
+            return -vim_response.status_code,text
+        
+    def new_external_network(self,net_name,net_type):
+        '''Adds a external network to VIM (shared)'''
+        '''Returns the network identifier'''
+        #TODO change to logging exception code policies
+        print "VIMConnector: Adding external shared network to VIM (type " + net_type + "): "+ net_name
+        
+        payload_req = '{"network":{"name": "' + net_name + '","shared":true,"type": "' + net_type + '"}}'
+        try:
+            vim_response = requests.post(self.url+'/networks', headers = self.headers_req, data=payload_req)
+        except requests.exceptions.RequestException as e:
+            self.logger.error( "new_external_network Exception: ", e.args)
+            return -vimconn.HTTP_Not_Found, str(e.args[0])
+        print vim_response
+        #print vim_response.status_code
+        if vim_response.status_code == 200:
+            #print vim_response.json()
+            #print json.dumps(vim_response.json(), indent=4)
+            res,http_content = self._format_in(vim_response, new_network_response_schema)
+            #print http_content
+            if res:
+                r = self._remove_extra_items(http_content, new_network_response_schema)
+                if r is not None: print "Warning: remove extra items ", r
+                #print http_content
+                network_id = http_content['network']['id']
+                print "Network id: ",network_id
+                return vim_response.status_code,network_id
+            else: return -vimconn.HTTP_Bad_Request,http_content
+        else:
+            #print vim_response.text
+            jsonerror = self._format_jsonerror(vim_response)
+            text = 'Error in VIM "%s": not possible to add new external network. HTTP Response: %d. Error: %s' % (self.url, vim_response.status_code, jsonerror)
+            #print text
+            return -vim_response.status_code,text
+        
+    def connect_port_network(self, port_id, network_id, admin=False):
+        '''Connects a external port to a network'''
+        '''Returns status code of the VIM response'''
+        #TODO change to logging exception code policies
+        print "VIMConnector: Connecting external port to network"
+        
+        payload_req = '{"port":{"network_id":"' + network_id + '"}}'
+        if admin:
+            if self.url_admin==None:
+                return -vimconn.HTTP_Unauthorized, "datacenter cannot contain  admin URL"
+            url= self.url_admin
+        else:
+            url= self.url
+        try:
+            vim_response = requests.put(url +'/ports/'+port_id, headers = self.headers_req, data=payload_req)
+        except requests.exceptions.RequestException as e:
+            print "connect_port_network Exception: ", e.args
+            return -vimconn.HTTP_Not_Found, str(e.args[0])
+        print vim_response
+        #print vim_response.status_code
+        if vim_response.status_code == 200:
+            #print vim_response.json()
+            #print json.dumps(vim_response.json(), indent=4)
+            res,http_content = self._format_in(vim_response, new_port_response_schema)
+            #print http_content
+            if res:
+                r = self._remove_extra_items(http_content, new_port_response_schema)
+                if r is not None: print "Warning: remove extra items ", r
+                #print http_content
+                port_id = http_content['port']['id']
+                print "Port id: ",port_id
+                return vim_response.status_code,port_id
+            else: return -vimconn.HTTP_Bad_Request,http_content
+        else:
+            print vim_response.text
+            jsonerror = self._format_jsonerror(vim_response)
+            text = 'Error in VIM "%s": not possible to connect external port to network. HTTP Response: %d. Error: %s' % (self.url_admin, vim_response.status_code, jsonerror)
+            print text
+            return -vim_response.status_code,text
+        
+
diff --git a/osm_ro/vimconn_vmware.py b/osm_ro/vimconn_vmware.py
new file mode 100644 (file)
index 0000000..a224255
--- /dev/null
@@ -0,0 +1,3471 @@
+# -*- 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
+##
+
+"""
+vimconn_vmware implementation an Abstract class in order to interact with VMware  vCloud Director.
+mbayramov@vmware.com
+"""
+from progressbar import Percentage, Bar, ETA, FileTransferSpeed, ProgressBar
+
+import vimconn
+import os
+import traceback
+import itertools
+import requests
+import ssl
+import atexit
+
+from pyVmomi import vim, vmodl
+from pyVim.connect import SmartConnect, Disconnect
+
+from xml.etree import ElementTree as XmlElementTree
+from lxml import etree as lxmlElementTree
+
+import yaml
+from pyvcloud import Http
+from pyvcloud.vcloudair import VCA
+from pyvcloud.schema.vcd.v1_5.schemas.vcloud import sessionType, organizationType, \
+    vAppType, organizationListType, vdcType, catalogType, queryRecordViewType, \
+    networkType, vcloudType, taskType, diskType, vmsType, vdcTemplateListType, mediaType
+from xml.sax.saxutils import escape
+
+from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TaskType
+from pyvcloud.schema.vcd.v1_5.schemas.vcloud.taskType import TaskType as GenericTask
+from pyvcloud.schema.vcd.v1_5.schemas.vcloud.vAppType import TaskType as VappTask
+from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TasksInProgressType
+
+import logging
+import json
+import time
+import uuid
+import httplib
+import hashlib
+import socket
+import struct
+import netaddr
+
+# global variable for vcd connector type
+STANDALONE = 'standalone'
+
+# key for flavor dicts
+FLAVOR_RAM_KEY = 'ram'
+FLAVOR_VCPUS_KEY = 'vcpus'
+FLAVOR_DISK_KEY = 'disk'
+DEFAULT_IP_PROFILE = {'gateway_address':"192.168.1.1",
+                      'dhcp_count':50,
+                      'subnet_address':"192.168.1.0/24",
+                      'dhcp_enabled':True,
+                      'dhcp_start_address':"192.168.1.3",
+                      'ip_version':"IPv4",
+                      'dns_address':"192.168.1.2"
+                      }
+# global variable for wait time
+INTERVAL_TIME = 5
+MAX_WAIT_TIME = 1800
+
+VCAVERSION = '5.9'
+
+__author__ = "Mustafa Bayramov, Arpita Kate, Sachin Bhangare"
+__date__ = "$12-Jan-2017 11:09:29$"
+__version__ = '0.1'
+
+#     -1: "Could not be created",
+#     0: "Unresolved",
+#     1: "Resolved",
+#     2: "Deployed",
+#     3: "Suspended",
+#     4: "Powered on",
+#     5: "Waiting for user input",
+#     6: "Unknown state",
+#     7: "Unrecognized state",
+#     8: "Powered off",
+#     9: "Inconsistent state",
+#     10: "Children do not all have the same status",
+#     11: "Upload initiated, OVF descriptor pending",
+#     12: "Upload initiated, copying contents",
+#     13: "Upload initiated , disk contents pending",
+#     14: "Upload has been quarantined",
+#     15: "Upload quarantine period has expired"
+
+# mapping vCD status to MANO
+vcdStatusCode2manoFormat = {4: 'ACTIVE',
+                            7: 'PAUSED',
+                            3: 'SUSPENDED',
+                            8: 'INACTIVE',
+                            12: 'BUILD',
+                            -1: 'ERROR',
+                            14: 'DELETED'}
+
+#
+netStatus2manoFormat = {'ACTIVE': 'ACTIVE', 'PAUSED': 'PAUSED', 'INACTIVE': 'INACTIVE', 'BUILD': 'BUILD',
+                        'ERROR': 'ERROR', 'DELETED': 'DELETED'
+                        }
+
+class vimconnector(vimconn.vimconnector):
+    # dict used to store flavor in memory
+    flavorlist = {}
+
+    def __init__(self, uuid=None, name=None, tenant_id=None, tenant_name=None,
+                 url=None, url_admin=None, user=None, passwd=None, log_level=None, config={}, persistent_info={}):
+        """
+        Constructor create vmware connector to vCloud director.
+
+        By default construct doesn't validate connection state. So client can create object with None arguments.
+        If client specified username , password and host and VDC name.  Connector initialize other missing attributes.
+
+        a) It initialize organization UUID
+        b) Initialize tenant_id/vdc ID.   (This information derived from tenant name)
+
+        Args:
+            uuid - is organization uuid.
+            name - is organization name that must be presented in vCloud director.
+            tenant_id - is VDC uuid it must be presented in vCloud director
+            tenant_name - is VDC name.
+            url - is hostname or ip address of vCloud director
+            url_admin - same as above.
+            user - is user that administrator for organization. Caller must make sure that
+                    username has right privileges.
+
+            password - is password for a user.
+
+            VMware connector also requires PVDC administrative privileges and separate account.
+            This variables must be passed via config argument dict contains keys
+
+            dict['admin_username']
+            dict['admin_password']
+            config - Provide NSX and vCenter information
+
+            Returns:
+                Nothing.
+        """
+
+        vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url,
+                                      url_admin, user, passwd, log_level, config)
+
+        self.logger = logging.getLogger('openmano.vim.vmware')
+        self.logger.setLevel(10)
+        self.persistent_info = persistent_info
+
+        self.name = name
+        self.id = uuid
+        self.url = url
+        self.url_admin = url_admin
+        self.tenant_id = tenant_id
+        self.tenant_name = tenant_name
+        self.user = user
+        self.passwd = passwd
+        self.config = config
+        self.admin_password = None
+        self.admin_user = None
+        self.org_name = ""
+        self.nsx_manager = None
+        self.nsx_user = None
+        self.nsx_password = None
+        self.vcenter_ip = None
+        self.vcenter_port = None
+        self.vcenter_user = None
+        self.vcenter_password = None
+
+        if tenant_name is not None:
+            orgnameandtenant = tenant_name.split(":")
+            if len(orgnameandtenant) == 2:
+                self.tenant_name = orgnameandtenant[1]
+                self.org_name = orgnameandtenant[0]
+            else:
+                self.tenant_name = tenant_name
+        if "orgname" in config:
+            self.org_name = config['orgname']
+
+        if log_level:
+            self.logger.setLevel(getattr(logging, log_level))
+
+        try:
+            self.admin_user = config['admin_username']
+            self.admin_password = config['admin_password']
+        except KeyError:
+            raise vimconn.vimconnException(message="Error admin username or admin password is empty.")
+
+        try:
+            self.nsx_manager = config['nsx_manager']
+            self.nsx_user = config['nsx_user']
+            self.nsx_password = config['nsx_password']
+        except KeyError:
+            raise vimconn.vimconnException(message="Error: nsx manager or nsx user or nsx password is empty in Config")
+
+        self.vcenter_ip = config.get("vcenter_ip", None)
+        self.vcenter_port = config.get("vcenter_port", None)
+        self.vcenter_user = config.get("vcenter_user", None)
+        self.vcenter_password = config.get("vcenter_password", None)
+
+        self.org_uuid = None
+        self.vca = None
+
+        if not url:
+            raise vimconn.vimconnException('url param can not be NoneType')
+
+        if not self.url_admin:  # try to use normal url
+            self.url_admin = self.url
+
+        logging.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self.id, self.org_name,
+                                                                              self.tenant_id, self.tenant_name))
+        logging.debug("vcd url {} vcd username: {} vcd password: {}".format(self.url, self.user, self.passwd))
+        logging.debug("vcd admin username {} vcd admin passowrd {}".format(self.admin_user, self.admin_password))
+
+        # initialize organization
+        if self.user is not None and self.passwd is not None and self.url:
+            self.init_organization()
+
+    def __getitem__(self, index):
+        if index == 'name':
+            return self.name
+        if index == 'tenant_id':
+            return self.tenant_id
+        if index == 'tenant_name':
+            return self.tenant_name
+        elif index == 'id':
+            return self.id
+        elif index == 'org_name':
+            return self.org_name
+        elif index == 'org_uuid':
+            return self.org_uuid
+        elif index == 'user':
+            return self.user
+        elif index == 'passwd':
+            return self.passwd
+        elif index == 'url':
+            return self.url
+        elif index == 'url_admin':
+            return self.url_admin
+        elif index == "config":
+            return self.config
+        else:
+            raise KeyError("Invalid key '%s'" % str(index))
+
+    def __setitem__(self, index, value):
+        if index == 'name':
+            self.name = value
+        if index == 'tenant_id':
+            self.tenant_id = value
+        if index == 'tenant_name':
+            self.tenant_name = value
+        elif index == 'id':
+            self.id = value
+        elif index == 'org_name':
+            self.org_name = value
+        elif index == 'org_uuid':
+            self.org_uuid = value
+        elif index == 'user':
+            self.user = value
+        elif index == 'passwd':
+            self.passwd = value
+        elif index == 'url':
+            self.url = value
+        elif index == 'url_admin':
+            self.url_admin = value
+        else:
+            raise KeyError("Invalid key '%s'" % str(index))
+
+    def connect_as_admin(self):
+        """ Method connect as pvdc admin user to vCloud director.
+            There are certain action that can be done only by provider vdc admin user.
+            Organization creation / provider network creation etc.
+
+            Returns:
+                The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
+        """
+
+        self.logger.debug("Logging in to a vca {} as admin.".format(self.org_name))
+
+        vca_admin = VCA(host=self.url,
+                        username=self.admin_user,
+                        service_type=STANDALONE,
+                        version=VCAVERSION,
+                        verify=False,
+                        log=False)
+        result = vca_admin.login(password=self.admin_password, org='System')
+        if not result:
+            raise vimconn.vimconnConnectionException(
+                "Can't connect to a vCloud director as: {}".format(self.admin_user))
+        result = vca_admin.login(token=vca_admin.token, org='System', org_url=vca_admin.vcloud_session.org_url)
+        if result is True:
+            self.logger.info(
+                "Successfully logged to a vcloud direct org: {} as user: {}".format('System', self.admin_user))
+
+        return vca_admin
+
+    def connect(self):
+        """ Method connect as normal user to vCloud director.
+
+            Returns:
+                The return vca object that letter can be used to connect to vCloud director as admin for VDC
+        """
+
+        try:
+            self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.org_name,
+                                                                                      self.user,
+                                                                                      self.org_name))
+            vca = VCA(host=self.url,
+                      username=self.user,
+                      service_type=STANDALONE,
+                      version=VCAVERSION,
+                      verify=False,
+                      log=False)
+
+            result = vca.login(password=self.passwd, org=self.org_name)
+            if not result:
+                raise vimconn.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self.user))
+            result = vca.login(token=vca.token, org=self.org_name, org_url=vca.vcloud_session.org_url)
+            if result is True:
+                self.logger.info(
+                    "Successfully logged to a vcloud direct org: {} as user: {}".format(self.org_name, self.user))
+
+        except:
+            raise vimconn.vimconnConnectionException("Can't connect to a vCloud director org: "
+                                                     "{} as user: {}".format(self.org_name, self.user))
+
+        return vca
+
+    def init_organization(self):
+        """ Method initialize organization UUID and VDC parameters.
+
+            At bare minimum client must provide organization name that present in vCloud director and VDC.
+
+            The VDC - UUID ( tenant_id) will be initialized at the run time if client didn't call constructor.
+            The Org - UUID will be initialized at the run time if data center present in vCloud director.
+
+            Returns:
+                The return vca object that letter can be used to connect to vcloud direct as admin
+        """
+        try:
+            if self.org_uuid is None:
+                org_dict = self.get_org_list()
+                for org in org_dict:
+                    # we set org UUID at the init phase but we can do it only when we have valid credential.
+                    if org_dict[org] == self.org_name:
+                        self.org_uuid = org
+                        self.logger.debug("Setting organization UUID {}".format(self.org_uuid))
+                        break
+                else:
+                    raise vimconn.vimconnException("Vcloud director organization {} not found".format(self.org_name))
+
+                # if well good we require for org details
+                org_details_dict = self.get_org(org_uuid=self.org_uuid)
+
+                # we have two case if we want to initialize VDC ID or VDC name at run time
+                # tenant_name provided but no tenant id
+                if self.tenant_id is None and self.tenant_name is not None and 'vdcs' in org_details_dict:
+                    vdcs_dict = org_details_dict['vdcs']
+                    for vdc in vdcs_dict:
+                        if vdcs_dict[vdc] == self.tenant_name:
+                            self.tenant_id = vdc
+                            self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
+                                                                                                    self.org_name))
+                            break
+                    else:
+                        raise vimconn.vimconnException("Tenant name indicated but not present in vcloud director.")
+                    # case two we have tenant_id but we don't have tenant name so we find and set it.
+                    if self.tenant_id is not None and self.tenant_name is None and 'vdcs' in org_details_dict:
+                        vdcs_dict = org_details_dict['vdcs']
+                        for vdc in vdcs_dict:
+                            if vdc == self.tenant_id:
+                                self.tenant_name = vdcs_dict[vdc]
+                                self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
+                                                                                                        self.org_name))
+                                break
+                        else:
+                            raise vimconn.vimconnException("Tenant id indicated but not present in vcloud director")
+            self.logger.debug("Setting organization uuid {}".format(self.org_uuid))
+        except:
+            self.logger.debug("Failed initialize organization UUID for org {}".format(self.org_name))
+            self.logger.debug(traceback.format_exc())
+            self.org_uuid = None
+
+    def new_tenant(self, tenant_name=None, tenant_description=None):
+        """ Method adds a new tenant to VIM with this name.
+            This action requires access to create VDC action in vCloud director.
+
+            Args:
+                tenant_name is tenant_name to be created.
+                tenant_description not used for this call
+
+            Return:
+                returns the tenant identifier in UUID format.
+                If action is failed method will throw vimconn.vimconnException method
+            """
+        vdc_task = self.create_vdc(vdc_name=tenant_name)
+        if vdc_task is not None:
+            vdc_uuid, value = vdc_task.popitem()
+            self.logger.info("Crated new vdc {} and uuid: {}".format(tenant_name, vdc_uuid))
+            return vdc_uuid
+        else:
+            raise vimconn.vimconnException("Failed create tenant {}".format(tenant_name))
+
+    def delete_tenant(self, tenant_id=None):
+        """Delete a tenant from VIM"""
+        'Returns the tenant identifier'
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def get_tenant_list(self, filter_dict={}):
+        """Obtain tenants of VIM
+        filter_dict can contain the following keys:
+            name: filter by tenant name
+            id: filter by tenant uuid/id
+            <other VIM specific>
+        Returns the tenant list of dictionaries:
+            [{'name':'<name>, 'id':'<id>, ...}, ...]
+
+        """
+        org_dict = self.get_org(self.org_uuid)
+        vdcs_dict = org_dict['vdcs']
+
+        vdclist = []
+        try:
+            for k in vdcs_dict:
+                entry = {'name': vdcs_dict[k], 'id': k}
+                # if caller didn't specify dictionary we return all tenants.
+                if filter_dict is not None and filter_dict:
+                    filtered_entry = entry.copy()
+                    filtered_dict = set(entry.keys()) - set(filter_dict)
+                    for unwanted_key in filtered_dict: del entry[unwanted_key]
+                    if filter_dict == entry:
+                        vdclist.append(filtered_entry)
+                else:
+                    vdclist.append(entry)
+        except:
+            self.logger.debug("Error in get_tenant_list()")
+            self.logger.debug(traceback.format_exc())
+            raise vimconn.vimconnException("Incorrect state. {}")
+
+        return vdclist
+
+    def new_network(self, net_name, net_type, ip_profile=None, shared=False):
+        """Adds a tenant network to VIM
+            net_name is the name
+            net_type can be 'bridge','data'.'ptp'.
+            ip_profile is a dict containing the IP parameters of the network
+            shared is a boolean
+        Returns the network identifier"""
+
+        self.logger.debug("new_network tenant {} net_type {} ip_profile {} shared {}"
+                          .format(net_name, net_type, ip_profile, shared))
+
+        isshared = 'false'
+        if shared:
+            isshared = 'true'
+
+        network_uuid = self.create_network(network_name=net_name, net_type=net_type,
+                                           ip_profile=ip_profile, isshared=isshared)
+        if network_uuid is not None:
+            return network_uuid
+        else:
+            raise vimconn.vimconnUnexpectedResponse("Failed create a new network {}".format(net_name))
+
+    def get_vcd_network_list(self):
+        """ Method available organization for a logged in tenant
+
+            Returns:
+                The return vca object that letter can be used to connect to vcloud direct as admin
+        """
+
+        self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        if not self.tenant_name:
+            raise vimconn.vimconnConnectionException("Tenant name is empty.")
+
+        vdc = vca.get_vdc(self.tenant_name)
+        if vdc is None:
+            raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}".format(self.tenant_name))
+
+        vdc_uuid = vdc.get_id().split(":")[3]
+        networks = vca.get_networks(vdc.get_name())
+        network_list = []
+        try:
+            for network in networks:
+                filter_dict = {}
+                netid = network.get_id().split(":")
+                if len(netid) != 4:
+                    continue
+
+                filter_dict["name"] = network.get_name()
+                filter_dict["id"] = netid[3]
+                filter_dict["shared"] = network.get_IsShared()
+                filter_dict["tenant_id"] = vdc_uuid
+                if network.get_status() == 1:
+                    filter_dict["admin_state_up"] = True
+                else:
+                    filter_dict["admin_state_up"] = False
+                filter_dict["status"] = "ACTIVE"
+                filter_dict["type"] = "bridge"
+                network_list.append(filter_dict)
+                self.logger.debug("get_vcd_network_list adding entry {}".format(filter_dict))
+        except:
+            self.logger.debug("Error in get_vcd_network_list")
+            self.logger.debug(traceback.format_exc())
+            pass
+
+        self.logger.debug("get_vcd_network_list returning {}".format(network_list))
+        return network_list
+
+    def get_network_list(self, filter_dict={}):
+        """Obtain tenant networks of VIM
+        Filter_dict can be:
+            name: network name  OR/AND
+            id: network uuid    OR/AND
+            shared: boolean     OR/AND
+            tenant_id: tenant   OR/AND
+            admin_state_up: boolean
+            status: 'ACTIVE'
+
+        [{key : value , key : value}]
+
+        Returns the network list of dictionaries:
+            [{<the fields at Filter_dict plus some VIM specific>}, ...]
+            List can be empty
+        """
+
+        self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        if not self.tenant_name:
+            raise vimconn.vimconnConnectionException("Tenant name is empty.")
+
+        vdc = vca.get_vdc(self.tenant_name)
+        if vdc is None:
+            raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}.".format(self.tenant_name))
+
+        vdcid = vdc.get_id().split(":")[3]
+        networks = vca.get_networks(vdc.get_name())
+        network_list = []
+
+        try:
+            for network in networks:
+                filter_entry = {}
+                net_uuid = network.get_id().split(":")
+                if len(net_uuid) != 4:
+                    continue
+                else:
+                    net_uuid = net_uuid[3]
+                # create dict entry
+                self.logger.debug("Adding  {} to a list vcd id {} network {}".format(net_uuid,
+                                                                                     vdcid,
+                                                                                     network.get_name()))
+                filter_entry["name"] = network.get_name()
+                filter_entry["id"] = net_uuid
+                filter_entry["shared"] = network.get_IsShared()
+                filter_entry["tenant_id"] = vdcid
+                if network.get_status() == 1:
+                    filter_entry["admin_state_up"] = True
+                else:
+                    filter_entry["admin_state_up"] = False
+                filter_entry["status"] = "ACTIVE"
+                filter_entry["type"] = "bridge"
+                filtered_entry = filter_entry.copy()
+
+                if filter_dict is not None and filter_dict:
+                    # we remove all the key : value we don't care and match only
+                    # respected field
+                    filtered_dict = set(filter_entry.keys()) - set(filter_dict)
+                    for unwanted_key in filtered_dict: del filter_entry[unwanted_key]
+                    if filter_dict == filter_entry:
+                        network_list.append(filtered_entry)
+                else:
+                    network_list.append(filtered_entry)
+        except:
+            self.logger.debug("Error in get_vcd_network_list")
+            self.logger.debug(traceback.format_exc())
+
+        self.logger.debug("Returning {}".format(network_list))
+        return network_list
+
+    def get_network(self, net_id):
+        """Method obtains network details of net_id VIM network
+           Return a dict with  the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+        vdc = vca.get_vdc(self.tenant_name)
+        vdc_id = vdc.get_id().split(":")[3]
+
+        networks = vca.get_networks(vdc.get_name())
+        filter_dict = {}
+
+        try:
+            for network in networks:
+                vdc_network_id = network.get_id().split(":")
+                if len(vdc_network_id) == 4 and vdc_network_id[3] == net_id:
+                    filter_dict["name"] = network.get_name()
+                    filter_dict["id"] = vdc_network_id[3]
+                    filter_dict["shared"] = network.get_IsShared()
+                    filter_dict["tenant_id"] = vdc_id
+                    if network.get_status() == 1:
+                        filter_dict["admin_state_up"] = True
+                    else:
+                        filter_dict["admin_state_up"] = False
+                    filter_dict["status"] = "ACTIVE"
+                    filter_dict["type"] = "bridge"
+                    self.logger.debug("Returning {}".format(filter_dict))
+                    return filter_dict
+        except:
+            self.logger.debug("Error in get_network")
+            self.logger.debug(traceback.format_exc())
+
+        return filter_dict
+
+    def delete_network(self, net_id):
+        """
+            Method Deletes a tenant network from VIM, provide the network id.
+
+            Returns the network identifier or raise an exception
+        """
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() for tenant {} is failed.".format(self.tenant_name))
+
+        vcd_network = self.get_vcd_network(network_uuid=net_id)
+        if vcd_network is not None and vcd_network:
+            if self.delete_network_action(network_uuid=net_id):
+                return net_id
+        else:
+            raise vimconn.vimconnNotFoundException("Network {} not found".format(net_id))
+
+    def refresh_nets_status(self, net_list):
+        """Get the status of the networks
+           Params: the list of network identifiers
+           Returns a dictionary with:
+                net_id:         #VIM id of this network
+                    status:     #Mandatory. Text with one of:
+                                #  DELETED (not found at vim)
+                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
+                                #  OTHER (Vim reported other status not understood)
+                                #  ERROR (VIM indicates an ERROR status)
+                                #  ACTIVE, INACTIVE, DOWN (admin down),
+                                #  BUILD (on building process)
+                                #
+                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR
+                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+
+        """
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+        dict_entry = {}
+        try:
+            for net in net_list:
+                errormsg = ''
+                vcd_network = self.get_vcd_network(network_uuid=net)
+                if vcd_network is not None and vcd_network:
+                    if vcd_network['status'] == '1':
+                        status = 'ACTIVE'
+                    else:
+                        status = 'DOWN'
+                else:
+                    status = 'DELETED'
+                    errormsg = 'Network not found.'
+
+                dict_entry[net] = {'status': status, 'error_msg': errormsg,
+                                   'vim_info': yaml.safe_dump(vcd_network)}
+        except:
+            self.logger.debug("Error in refresh_nets_status")
+            self.logger.debug(traceback.format_exc())
+
+        return dict_entry
+
+    def get_flavor(self, flavor_id):
+        """Obtain flavor details from the  VIM
+            Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
+        """
+        if flavor_id not in vimconnector.flavorlist:
+            raise vimconn.vimconnNotFoundException("Flavor not found.")
+        return vimconnector.flavorlist[flavor_id]
+
+    def new_flavor(self, flavor_data):
+        """Adds a tenant flavor to VIM
+            flavor_data contains a dictionary with information, keys:
+                name: flavor name
+                ram: memory (cloud type) in MBytes
+                vpcus: cpus (cloud type)
+                extended: EPA parameters
+                  - numas: #items requested in same NUMA
+                        memory: number of 1G huge pages memory
+                        paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
+                        interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
+                          - name: interface name
+                            dedicated: yes|no|yes:sriov;  for PT, SRIOV or only one SRIOV for the physical NIC
+                            bandwidth: X Gbps; requested guarantee bandwidth
+                            vpci: requested virtual PCI address
+                disk: disk size
+                is_public:
+                 #TODO to concrete
+        Returns the flavor identifier"""
+
+        # generate a new uuid put to internal dict and return it.
+        self.logger.debug("Creating new flavor - flavor_data: {}".format(flavor_data))
+        new_flavor=flavor_data
+        ram = flavor_data.get(FLAVOR_RAM_KEY, 1024)
+        cpu = flavor_data.get(FLAVOR_VCPUS_KEY, 1)
+        disk = flavor_data.get(FLAVOR_DISK_KEY, 1)
+
+        extended_flv = flavor_data.get("extended")
+        if extended_flv:
+            numas=extended_flv.get("numas")
+            if numas:
+                for numa in numas:
+                    #overwrite ram and vcpus
+                    ram = numa['memory']*1024
+                    if 'paired-threads' in numa:
+                        cpu = numa['paired-threads']*2
+                    elif 'cores' in numa:
+                        cpu = numa['cores']
+                    elif 'threads' in numa:
+                        cpu = numa['threads']
+
+        new_flavor[FLAVOR_RAM_KEY] = ram
+        new_flavor[FLAVOR_VCPUS_KEY] = cpu
+        new_flavor[FLAVOR_DISK_KEY] = disk
+        # generate a new uuid put to internal dict and return it.
+        flavor_id = uuid.uuid4()
+        vimconnector.flavorlist[str(flavor_id)] = new_flavor
+        self.logger.debug("Created flavor - {} : {}".format(flavor_id, new_flavor))
+
+        return str(flavor_id)
+
+    def delete_flavor(self, flavor_id):
+        """Deletes a tenant flavor from VIM identify by its id
+
+           Returns the used id or raise an exception
+        """
+        if flavor_id not in vimconnector.flavorlist:
+            raise vimconn.vimconnNotFoundException("Flavor not found.")
+
+        vimconnector.flavorlist.pop(flavor_id, None)
+        return flavor_id
+
+    def new_image(self, image_dict):
+        """
+        Adds a tenant image to VIM
+        Returns:
+            200, image-id        if the image is created
+            <0, message          if there is an error
+        """
+
+        return self.get_image_id_from_path(image_dict['location'])
+
+    def delete_image(self, image_id):
+        """
+
+        :param image_id:
+        :return:
+        """
+
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def catalog_exists(self, catalog_name, catalogs):
+        """
+
+        :param catalog_name:
+        :param catalogs:
+        :return:
+        """
+        for catalog in catalogs:
+            if catalog.name == catalog_name:
+                return True
+        return False
+
+    def create_vimcatalog(self, vca=None, catalog_name=None):
+        """ Create new catalog entry in vCloud director.
+
+            Args
+                vca:  vCloud director.
+                catalog_name catalog that client wish to create.   Note no validation done for a name.
+                Client must make sure that provide valid string representation.
+
+             Return (bool) True if catalog created.
+
+        """
+        try:
+            task = vca.create_catalog(catalog_name, catalog_name)
+            result = vca.block_until_completed(task)
+            if not result:
+                return False
+            catalogs = vca.get_catalogs()
+        except:
+            return False
+        return self.catalog_exists(catalog_name, catalogs)
+
+    # noinspection PyIncorrectDocstring
+    def upload_ovf(self, vca=None, catalog_name=None, image_name=None, media_file_name=None,
+                   description='', progress=False, chunk_bytes=128 * 1024):
+        """
+        Uploads a OVF file to a vCloud catalog
+
+        :param chunk_bytes:
+        :param progress:
+        :param description:
+        :param image_name:
+        :param vca:
+        :param catalog_name: (str): The name of the catalog to upload the media.
+        :param media_file_name: (str): The name of the local media file to upload.
+        :return: (bool) True if the media file was successfully uploaded, false otherwise.
+        """
+        os.path.isfile(media_file_name)
+        statinfo = os.stat(media_file_name)
+
+        #  find a catalog entry where we upload OVF.
+        #  create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
+        #  status change.
+        #  if VCD can parse OVF we upload VMDK file
+        for catalog in vca.get_catalogs():
+            if catalog_name != catalog.name:
+                continue
+            link = filter(lambda link: link.get_type() == "application/vnd.vmware.vcloud.media+xml" and
+                                       link.get_rel() == 'add', catalog.get_Link())
+            assert len(link) == 1
+            data = """
+            <UploadVAppTemplateParams name="%s" xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"><Description>%s vApp Template</Description></UploadVAppTemplateParams>
+            """ % (escape(catalog_name), escape(description))
+            headers = vca.vcloud_session.get_vcloud_headers()
+            headers['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
+            response = Http.post(link[0].get_href(), headers=headers, data=data, verify=vca.verify, logger=self.logger)
+            if response.status_code == requests.codes.created:
+                catalogItem = XmlElementTree.fromstring(response.content)
+                entity = [child for child in catalogItem if
+                          child.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
+                href = entity.get('href')
+                template = href
+                response = Http.get(href, headers=vca.vcloud_session.get_vcloud_headers(),
+                                    verify=vca.verify, logger=self.logger)
+
+                if response.status_code == requests.codes.ok:
+                    media = mediaType.parseString(response.content, True)
+                    link = filter(lambda link: link.get_rel() == 'upload:default',
+                                  media.get_Files().get_File()[0].get_Link())[0]
+                    headers = vca.vcloud_session.get_vcloud_headers()
+                    headers['Content-Type'] = 'Content-Type text/xml'
+                    response = Http.put(link.get_href(),
+                                        data=open(media_file_name, 'rb'),
+                                        headers=headers,
+                                        verify=vca.verify, logger=self.logger)
+                    if response.status_code != requests.codes.ok:
+                        self.logger.debug(
+                            "Failed create vApp template for catalog name {} and image {}".format(catalog_name,
+                                                                                                  media_file_name))
+                        return False
+
+                # TODO fix this with aync block
+                time.sleep(5)
+
+                self.logger.debug("vApp template for catalog name {} and image {}".format(catalog_name, media_file_name))
+
+                # uploading VMDK file
+                # check status of OVF upload and upload remaining files.
+                response = Http.get(template,
+                                    headers=vca.vcloud_session.get_vcloud_headers(),
+                                    verify=vca.verify,
+                                    logger=self.logger)
+
+                if response.status_code == requests.codes.ok:
+                    media = mediaType.parseString(response.content, True)
+                    number_of_files = len(media.get_Files().get_File())
+                    for index in xrange(0, number_of_files):
+                        links_list = filter(lambda link: link.get_rel() == 'upload:default',
+                                            media.get_Files().get_File()[index].get_Link())
+                        for link in links_list:
+                            # we skip ovf since it already uploaded.
+                            if 'ovf' in link.get_href():
+                                continue
+                            # The OVF file and VMDK must be in a same directory
+                            head, tail = os.path.split(media_file_name)
+                            file_vmdk = head + '/' + link.get_href().split("/")[-1]
+                            if not os.path.isfile(file_vmdk):
+                                return False
+                            statinfo = os.stat(file_vmdk)
+                            if statinfo.st_size == 0:
+                                return False
+                            hrefvmdk = link.get_href()
+
+                            if progress:
+                                print("Uploading file: {}".format(file_vmdk))
+                            if progress:
+                                widgets = ['Uploading file: ', Percentage(), ' ', Bar(), ' ', ETA(), ' ',
+                                           FileTransferSpeed()]
+                                progress_bar = ProgressBar(widgets=widgets, maxval=statinfo.st_size).start()
+
+                            bytes_transferred = 0
+                            f = open(file_vmdk, 'rb')
+                            while bytes_transferred < statinfo.st_size:
+                                my_bytes = f.read(chunk_bytes)
+                                if len(my_bytes) <= chunk_bytes:
+                                    headers = vca.vcloud_session.get_vcloud_headers()
+                                    headers['Content-Range'] = 'bytes %s-%s/%s' % (
+                                        bytes_transferred, len(my_bytes) - 1, statinfo.st_size)
+                                    headers['Content-Length'] = str(len(my_bytes))
+                                    response = Http.put(hrefvmdk,
+                                                        headers=headers,
+                                                        data=my_bytes,
+                                                        verify=vca.verify,
+                                                        logger=None)
+
+                                    if response.status_code == requests.codes.ok:
+                                        bytes_transferred += len(my_bytes)
+                                        if progress:
+                                            progress_bar.update(bytes_transferred)
+                                    else:
+                                        self.logger.debug(
+                                            'file upload failed with error: [%s] %s' % (response.status_code,
+                                                                                        response.content))
+
+                                        f.close()
+                                        return False
+                            f.close()
+                            if progress:
+                                progress_bar.finish()
+                            time.sleep(10)
+                    return True
+                else:
+                    self.logger.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
+                                      format(catalog_name, media_file_name))
+                    return False
+
+        self.logger.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name, media_file_name))
+        return False
+
+    def upload_vimimage(self, vca=None, catalog_name=None, media_name=None, medial_file_name=None, progress=False):
+        """Upload media file"""
+        # TODO add named parameters for readability
+
+        return self.upload_ovf(vca=vca, catalog_name=catalog_name, image_name=media_name.split(".")[0],
+                               media_file_name=medial_file_name, description='medial_file_name', progress=progress)
+
+    def validate_uuid4(self, uuid_string=None):
+        """  Method validate correct format of UUID.
+
+        Return: true if string represent valid uuid
+        """
+        try:
+            val = uuid.UUID(uuid_string, version=4)
+        except ValueError:
+            return False
+        return True
+
+    def get_catalogid(self, catalog_name=None, catalogs=None):
+        """  Method check catalog and return catalog ID in UUID format.
+
+        Args
+            catalog_name: catalog name as string
+            catalogs:  list of catalogs.
+
+        Return: catalogs uuid
+        """
+
+        for catalog in catalogs:
+            if catalog.name == catalog_name:
+                catalog_id = catalog.get_id().split(":")
+                return catalog_id[3]
+        return None
+
+    def get_catalogbyid(self, catalog_uuid=None, catalogs=None):
+        """  Method check catalog and return catalog name lookup done by catalog UUID.
+
+        Args
+            catalog_name: catalog name as string
+            catalogs:  list of catalogs.
+
+        Return: catalogs name or None
+        """
+
+        if not self.validate_uuid4(uuid_string=catalog_uuid):
+            return None
+
+        for catalog in catalogs:
+            catalog_id = catalog.get_id().split(":")[3]
+            if catalog_id == catalog_uuid:
+                return catalog.name
+        return None
+
+    def get_image_id_from_path(self, path=None, progress=False):
+        """  Method upload OVF image to vCloud director.
+
+        Each OVF image represented as single catalog entry in vcloud director.
+        The method check for existing catalog entry.  The check done by file name without file extension.
+
+        if given catalog name already present method will respond with existing catalog uuid otherwise
+        it will create new catalog entry and upload OVF file to newly created catalog.
+
+        If method can't create catalog entry or upload a file it will throw exception.
+
+        Method accept boolean flag progress that will output progress bar. It useful method
+        for standalone upload use case. In case to test large file upload.
+
+        Args
+            path: - valid path to OVF file.
+            progress - boolean progress bar show progress bar.
+
+        Return: if image uploaded correct method will provide image catalog UUID.
+        """
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        if not path:
+            raise vimconn.vimconnException("Image path can't be None.")
+
+        if not os.path.isfile(path):
+            raise vimconn.vimconnException("Can't read file. File not found.")
+
+        if not os.access(path, os.R_OK):
+            raise vimconn.vimconnException("Can't read file. Check file permission to read.")
+
+        self.logger.debug("get_image_id_from_path() client requesting {} ".format(path))
+
+        dirpath, filename = os.path.split(path)
+        flname, file_extension = os.path.splitext(path)
+        if file_extension != '.ovf':
+            self.logger.debug("Wrong file extension {} connector support only OVF container.".format(file_extension))
+            raise vimconn.vimconnException("Wrong container.  vCloud director supports only OVF.")
+
+        catalog_name = os.path.splitext(filename)[0]
+        catalog_md5_name = hashlib.md5(path).hexdigest()
+        self.logger.debug("File name {} Catalog Name {} file path {} "
+                          "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name))
+
+        catalogs = vca.get_catalogs()
+        if len(catalogs) == 0:
+            self.logger.info("Creating a new catalog entry {} in vcloud director".format(catalog_name))
+            result = self.create_vimcatalog(vca, catalog_md5_name)
+            if not result:
+                raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
+            result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
+                                          media_name=filename, medial_file_name=path, progress=progress)
+            if not result:
+                raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
+            return self.get_catalogid(catalog_name, vca.get_catalogs())
+        else:
+            for catalog in catalogs:
+                # search for existing catalog if we find same name we return ID
+                # TODO optimize this
+                if catalog.name == catalog_md5_name:
+                    self.logger.debug("Found existing catalog entry for {} "
+                                      "catalog id {}".format(catalog_name,
+                                                             self.get_catalogid(catalog_md5_name, catalogs)))
+                    return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
+
+        # if we didn't find existing catalog we create a new one and upload image.
+        self.logger.debug("Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name))
+        result = self.create_vimcatalog(vca, catalog_md5_name)
+        if not result:
+            raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
+
+        result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
+                                      media_name=filename, medial_file_name=path, progress=progress)
+        if not result:
+            raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_md5_name))
+
+        return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
+
+    def get_image_list(self, filter_dict={}):
+        '''Obtain tenant images from VIM
+        Filter_dict can be:
+            name: image name
+            id: image uuid
+            checksum: image checksum
+            location: image path
+        Returns the image list of dictionaries:
+            [{<the fields at Filter_dict plus some VIM specific>}, ...]
+            List can be empty
+        '''
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+        try:
+            image_list = []
+            catalogs = vca.get_catalogs()
+            if len(catalogs) == 0:
+                return image_list
+            else:
+                for catalog in catalogs:
+                    catalog_uuid = catalog.get_id().split(":")[3]
+                    name = catalog.name
+                    filtered_dict = {}
+                    if filter_dict.get("name") and filter_dict["name"] != name:
+                        continue
+                    if filter_dict.get("id") and filter_dict["id"] != catalog_uuid:
+                        continue
+                    filtered_dict ["name"] = name
+                    filtered_dict ["id"] = catalog_uuid
+                    image_list.append(filtered_dict)
+
+                self.logger.debug("List of already created catalog items: {}".format(image_list))
+                return image_list
+        except Exception as exp:
+            raise vimconn.vimconnException("Exception occured while retriving catalog items {}".format(exp))
+
+    def get_vappid(self, vdc=None, vapp_name=None):
+        """ Method takes vdc object and vApp name and returns vapp uuid or None
+
+        Args:
+            vdc: The VDC object.
+            vapp_name: is application vappp name identifier
+
+        Returns:
+                The return vApp name otherwise None
+        """
+        if vdc is None or vapp_name is None:
+            return None
+        # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
+        try:
+            refs = filter(lambda ref: ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
+                          vdc.ResourceEntities.ResourceEntity)
+            if len(refs) == 1:
+                return refs[0].href.split("vapp")[1][1:]
+        except Exception as e:
+            self.logger.exception(e)
+            return False
+        return None
+
+    def check_vapp(self, vdc=None, vapp_uuid=None):
+        """ Method Method returns True or False if vapp deployed in vCloud director
+
+            Args:
+                vca: Connector to VCA
+                vdc: The VDC object.
+                vappid: vappid is application identifier
+
+            Returns:
+                The return True if vApp deployed
+                :param vdc:
+                :param vapp_uuid:
+        """
+        try:
+            refs = filter(lambda ref:
+                          ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
+                          vdc.ResourceEntities.ResourceEntity)
+            for ref in refs:
+                vappid = ref.href.split("vapp")[1][1:]
+                # find vapp with respected vapp uuid
+                if vappid == vapp_uuid:
+                    return True
+        except Exception as e:
+            self.logger.exception(e)
+            return False
+        return False
+
+    def get_namebyvappid(self, vca=None, vdc=None, vapp_uuid=None):
+        """Method returns vApp name from vCD and lookup done by vapp_id.
+
+        Args:
+            vca: Connector to VCA
+            vdc: The VDC object.
+            vapp_uuid: vappid is application identifier
+
+        Returns:
+            The return vApp name otherwise None
+        """
+
+        try:
+            refs = filter(lambda ref: ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
+                          vdc.ResourceEntities.ResourceEntity)
+            for ref in refs:
+                # we care only about UUID the rest doesn't matter
+                vappid = ref.href.split("vapp")[1][1:]
+                if vappid == vapp_uuid:
+                    response = Http.get(ref.href, headers=vca.vcloud_session.get_vcloud_headers(), verify=vca.verify,
+                                        logger=self.logger)
+                    tree = XmlElementTree.fromstring(response.content)
+                    return tree.attrib['name']
+        except Exception as e:
+            self.logger.exception(e)
+            return None
+        return None
+
+    def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={},
+                       cloud_config=None, disk_list=None):
+        """Adds a VM instance to VIM
+        Params:
+            start: indicates if VM must start or boot in pause mode. Ignored
+            image_id,flavor_id: image and flavor uuid
+            net_list: list of interfaces, each one is a dictionary with:
+                name:
+                net_id: network uuid to connect
+                vpci: virtual vcpi to assign
+                model: interface model, virtio, e2000, ...
+                mac_address:
+                use: 'data', 'bridge',  'mgmt'
+                type: 'virtual', 'PF', 'VF', 'VFnotShared'
+                vim_id: filled/added by this function
+                cloud_config: can be a text script to be passed directly to cloud-init,
+                    or an object to inject users and ssh keys with format:
+                        key-pairs: [] list of keys to install to the default user
+                        users: [{ name, key-pairs: []}] list of users to add with their key-pair
+                #TODO ip, security groups
+        Returns >=0, the instance identifier
+                <0, error_text
+        """
+
+        self.logger.info("Creating new instance for entry {}".format(name))
+        self.logger.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".format(
+                                    description, start, image_id, flavor_id, net_list, cloud_config))
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        #new vm name = vmname + tenant_id + uuid
+        new_vm_name = [name, '-', str(uuid.uuid4())]
+        vmname_andid = ''.join(new_vm_name)
+
+        # if vm already deployed we return existing uuid
+        # vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), name)
+        # if vapp_uuid is not None:
+        #     return vapp_uuid
+
+        # we check for presence of VDC, Catalog entry and Flavor.
+        vdc = vca.get_vdc(self.tenant_name)
+        if vdc is None:
+            raise vimconn.vimconnNotFoundException(
+                "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(name))
+        catalogs = vca.get_catalogs()
+        if catalogs is None:
+            raise vimconn.vimconnNotFoundException(
+                "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(name))
+
+        catalog_hash_name = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
+        if catalog_hash_name:
+            self.logger.info("Found catalog entry {} for image id {}".format(catalog_hash_name, image_id))
+        else:
+            raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
+                                                   "(Failed retrieve catalog information {})".format(name, image_id))
+
+
+        # Set vCPU and Memory based on flavor.
+        #
+        vm_cpus = None
+        vm_memory = None
+        vm_disk = None
+        pci_devices_info = []
+        if flavor_id is not None:
+            if flavor_id not in vimconnector.flavorlist:
+                raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
+                                                       "Failed retrieve flavor information "
+                                                       "flavor id {}".format(name, flavor_id))
+            else:
+                try:
+                    flavor = vimconnector.flavorlist[flavor_id]
+                    vm_cpus = flavor[FLAVOR_VCPUS_KEY]
+                    vm_memory = flavor[FLAVOR_RAM_KEY]
+                    vm_disk = flavor[FLAVOR_DISK_KEY]
+                    extended = flavor.get("extended", None)
+                    if extended:
+                        numas=extended.get("numas", None)
+                        if numas:
+                            for numa in numas:
+                                for interface in numa.get("interfaces",() ):
+                                    if interface["dedicated"].strip()=="yes":
+                                        pci_devices_info.append(interface)
+                except Exception as exp:
+                    raise vimconn.vimconnException("Corrupted flavor. {}.Exception: {}".format(flavor_id, exp))
+
+        # image upload creates template name as catalog name space Template.
+        templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
+        power_on = 'false'
+        if start:
+            power_on = 'true'
+
+        # client must provide at least one entry in net_list if not we report error
+        #If net type is mgmt, then configure it as primary net & use its NIC index as primary NIC
+        #If no mgmt, then the 1st NN in netlist is considered as primary net. 
+        primary_net = None
+        primary_netname = None
+        network_mode = 'bridged'
+        if net_list is not None and len(net_list) > 0:
+            for net in net_list:
+                if 'use' in net and net['use'] == 'mgmt':
+                    primary_net = net
+            if primary_net is None:
+                primary_net = net_list[0]
+
+            try:
+                primary_net_id = primary_net['net_id']
+                network_dict = self.get_vcd_network(network_uuid=primary_net_id)
+                if 'name' in network_dict:
+                    primary_netname = network_dict['name']
+
+            except KeyError:
+                raise vimconn.vimconnException("Corrupted flavor. {}".format(primary_net))
+        else:
+            raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name))
+
+        # use: 'data', 'bridge', 'mgmt'
+        # create vApp.  Set vcpu and ram based on flavor id.
+        vapptask = vca.create_vapp(self.tenant_name, vmname_andid, templateName,
+                                   self.get_catalogbyid(image_id, catalogs),
+                                   network_name=None,  # None while creating vapp
+                                   network_mode=network_mode,
+                                   vm_name=vmname_andid,
+                                   vm_cpus=vm_cpus,  # can be None if flavor is None
+                                   vm_memory=vm_memory)  # can be None if flavor is None
+
+        if vapptask is None or vapptask is False:
+            raise vimconn.vimconnUnexpectedResponse("new_vminstance(): failed deploy vApp {}".format(vmname_andid))
+        if type(vapptask) is VappTask:
+            vca.block_until_completed(vapptask)
+
+        # we should have now vapp in undeployed state.
+        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
+        vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
+        if vapp is None:
+            raise vimconn.vimconnUnexpectedResponse(
+                "new_vminstance(): Failed failed retrieve vApp {} after we deployed".format(
+                                                                            vmname_andid))
+
+        #Add PCI passthrough configrations
+        PCI_devices_status = False
+        vm_obj = None
+        si = None
+        if len(pci_devices_info) > 0:
+            self.logger.info("Need to add PCI devices {} into VM {}".format(pci_devices_info,
+                                                                        vmname_andid ))
+            PCI_devices_status, vm_obj, vcenter_conect = self.add_pci_devices(vapp_uuid,
+                                                                            pci_devices_info,
+                                                                            vmname_andid)
+            if PCI_devices_status:
+                self.logger.info("Added PCI devives {} to VM {}".format(
+                                                            pci_devices_info,
+                                                            vmname_andid)
+                                 )
+            else:
+                self.logger.info("Fail to add PCI devives {} to VM {}".format(
+                                                            pci_devices_info,
+                                                            vmname_andid)
+                                 )
+        # add vm disk
+        if vm_disk:
+            #Assuming there is only one disk in ovf and fast provisioning in organization vDC is disabled
+            result = self.modify_vm_disk(vapp_uuid, vm_disk)
+            if result :
+                self.logger.debug("Modified Disk size of VM {} ".format(vmname_andid))
+
+        # add NICs & connect to networks in netlist
+        try:
+            self.logger.info("Request to connect VM to a network: {}".format(net_list))
+            nicIndex = 0
+            primary_nic_index = 0
+            for net in net_list:
+                # openmano uses network id in UUID format.
+                # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
+                # [{'use': 'bridge', 'net_id': '527d4bf7-566a-41e7-a9e7-ca3cdd9cef4f', 'type': 'virtual',
+                #   'vpci': '0000:00:11.0', 'name': 'eth0'}]
+
+                if 'net_id' not in net:
+                    continue
+
+                interface_net_id = net['net_id']
+                interface_net_name = self.get_network_name_by_id(network_uuid=interface_net_id)
+                interface_network_mode = net['use']
+
+                if interface_network_mode == 'mgmt':
+                    primary_nic_index = nicIndex
+
+                """- POOL (A static IP address is allocated automatically from a pool of addresses.)
+                                  - DHCP (The IP address is obtained from a DHCP service.)
+                                  - MANUAL (The IP address is assigned manually in the IpAddress element.)
+                                  - NONE (No IP addressing mode specified.)"""
+
+                if primary_netname is not None:
+                    nets = filter(lambda n: n.name == interface_net_name, vca.get_networks(self.tenant_name))
+                    if len(nets) == 1:
+                        self.logger.info("new_vminstance(): Found requested network: {}".format(nets[0].name))
+                        task = vapp.connect_to_network(nets[0].name, nets[0].href)
+                        if type(task) is GenericTask:
+                            vca.block_until_completed(task)
+                        # connect network to VM - with all DHCP by default
+                        self.logger.info("new_vminstance(): Connecting VM to a network {}".format(nets[0].name))
+                        task = vapp.connect_vms(nets[0].name,
+                                                connection_index=nicIndex,
+                                                connections_primary_index=primary_nic_index,
+                                                ip_allocation_mode='DHCP')
+                        if type(task) is GenericTask:
+                            vca.block_until_completed(task)
+                nicIndex += 1
+        except KeyError:
+            # it might be a case if specific mandatory entry in dict is empty
+            self.logger.debug("Key error {}".format(KeyError.message))
+            raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
+
+        # deploy and power on vm
+        self.logger.debug("new_vminstance(): Deploying vApp {} ".format(name))
+        deploytask = vapp.deploy(powerOn=False)
+        if type(deploytask) is GenericTask:
+            vca.block_until_completed(deploytask)
+
+        # If VM has PCI devices reserve memory for VM
+        if PCI_devices_status and vm_obj and vcenter_conect:
+            memReserve = vm_obj.config.hardware.memoryMB
+            spec = vim.vm.ConfigSpec()
+            spec.memoryAllocation = vim.ResourceAllocationInfo(reservation=memReserve)
+            task = vm_obj.ReconfigVM_Task(spec=spec)
+            if task:
+                result = self.wait_for_vcenter_task(task, vcenter_conect)
+                self.logger.info("Reserved memmoery {} MB for "\
+                                 "VM VM status: {}".format(str(memReserve),result))
+            else:
+                self.logger.info("Fail to reserved memmoery {} to VM {}".format(
+                                                            str(memReserve),str(vm_obj)))
+
+        self.logger.debug("new_vminstance(): power on vApp {} ".format(name))
+        poweron_task = vapp.poweron()
+        if type(poweron_task) is GenericTask:
+            vca.block_until_completed(poweron_task)
+
+        # check if vApp deployed and if that the case return vApp UUID otherwise -1
+        wait_time = 0
+        vapp_uuid = None
+        while wait_time <= MAX_WAIT_TIME:
+            vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
+            if vapp and vapp.me.deployed:
+                vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
+                break
+            else:
+                self.logger.debug("new_vminstance(): Wait for vApp {} to deploy".format(name))
+                time.sleep(INTERVAL_TIME)
+
+            wait_time +=INTERVAL_TIME
+
+        if vapp_uuid is not None:
+            return vapp_uuid
+        else:
+            raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
+
+    ##
+    ##
+    ##  based on current discussion
+    ##
+    ##
+    ##  server:
+    #   created: '2016-09-08T11:51:58'
+    #   description: simple-instance.linux1.1
+    #   flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
+    #   hostId: e836c036-74e7-11e6-b249-0800273e724c
+    #   image: dde30fe6-75a9-11e6-ad5f-0800273e724c
+    #   status: ACTIVE
+    #   error_msg:
+    #   interfaces: …
+    #
+    def get_vminstance(self, vim_vm_uuid=None):
+        """Returns the VM instance information from VIM"""
+
+        self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        vdc = vca.get_vdc(self.tenant_name)
+        if vdc is None:
+            raise vimconn.vimconnConnectionException(
+                "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
+
+        vm_info_dict = self.get_vapp_details_rest(vapp_uuid=vim_vm_uuid)
+        if not vm_info_dict:
+            self.logger.debug("get_vminstance(): Failed to get vApp name by UUID {}".format(vim_vm_uuid))
+            raise vimconn.vimconnNotFoundException("Failed to get vApp name by UUID {}".format(vim_vm_uuid))
+
+        status_key = vm_info_dict['status']
+        error = ''
+        try:
+            vm_dict = {'created': vm_info_dict['created'],
+                       'description': vm_info_dict['name'],
+                       'status': vcdStatusCode2manoFormat[int(status_key)],
+                       'hostId': vm_info_dict['vmuuid'],
+                       'error_msg': error,
+                       'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
+
+            if 'interfaces' in vm_info_dict:
+                vm_dict['interfaces'] = vm_info_dict['interfaces']
+            else:
+                vm_dict['interfaces'] = []
+        except KeyError:
+            vm_dict = {'created': '',
+                       'description': '',
+                       'status': vcdStatusCode2manoFormat[int(-1)],
+                       'hostId': vm_info_dict['vmuuid'],
+                       'error_msg': "Inconsistency state",
+                       'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
+
+        return vm_dict
+
+    def delete_vminstance(self, vm__vim_uuid):
+        """Method poweroff and remove VM instance from vcloud director network.
+
+        Args:
+            vm__vim_uuid: VM UUID
+
+        Returns:
+            Returns the instance identifier
+        """
+
+        self.logger.debug("Client requesting delete vm instance {} ".format(vm__vim_uuid))
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        vdc = vca.get_vdc(self.tenant_name)
+        if vdc is None:
+            self.logger.debug("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
+                self.tenant_name))
+            raise vimconn.vimconnException(
+                "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
+
+        try:
+            vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
+            if vapp_name is None:
+                self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
+                return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
+            else:
+                self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
+
+            # Delete vApp and wait for status change if task executed and vApp is None.
+            vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+
+            if vapp:
+                if vapp.me.deployed:
+                    self.logger.info("Powering off vApp {}".format(vapp_name))
+                    #Power off vApp
+                    powered_off = False
+                    wait_time = 0
+                    while wait_time <= MAX_WAIT_TIME:
+                        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+                        if not vapp:
+                            self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
+                            return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
+
+                        power_off_task = vapp.poweroff()
+                        if type(power_off_task) is GenericTask:
+                            result = vca.block_until_completed(power_off_task)
+                            if result:
+                                powered_off = True
+                                break
+                        else:
+                            self.logger.info("Wait for vApp {} to power off".format(vapp_name))
+                            time.sleep(INTERVAL_TIME)
+
+                        wait_time +=INTERVAL_TIME
+                    if not powered_off:
+                        self.logger.debug("delete_vminstance(): Failed to power off VM instance {} ".format(vm__vim_uuid))
+                    else:
+                        self.logger.info("delete_vminstance(): Powered off VM instance {} ".format(vm__vim_uuid))
+
+                    #Undeploy vApp
+                    self.logger.info("Undeploy vApp {}".format(vapp_name))
+                    wait_time = 0
+                    undeployed = False
+                    while wait_time <= MAX_WAIT_TIME:
+                        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+                        if not vapp:
+                            self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
+                            return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
+                        undeploy_task = vapp.undeploy(action='powerOff')
+
+                        if type(undeploy_task) is GenericTask:
+                            result = vca.block_until_completed(undeploy_task)
+                            if result:
+                                undeployed = True
+                                break
+                        else:
+                            self.logger.debug("Wait for vApp {} to undeploy".format(vapp_name))
+                            time.sleep(INTERVAL_TIME)
+
+                        wait_time +=INTERVAL_TIME
+
+                    if not undeployed:
+                        self.logger.debug("delete_vminstance(): Failed to undeploy vApp {} ".format(vm__vim_uuid)) 
+
+                # delete vapp
+                self.logger.info("Start deletion of vApp {} ".format(vapp_name))
+                vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+
+                if vapp is not None:
+                    wait_time = 0
+                    result = False
+
+                    while wait_time <= MAX_WAIT_TIME:
+                        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+                        if not vapp:
+                            self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
+                            return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
+
+                        delete_task = vapp.delete()
+
+                        if type(delete_task) is GenericTask:
+                            vca.block_until_completed(delete_task)
+                            result = vca.block_until_completed(delete_task)
+                            if result:
+                                break
+                        else:
+                            self.logger.debug("Wait for vApp {} to delete".format(vapp_name))
+                            time.sleep(INTERVAL_TIME)
+
+                        wait_time +=INTERVAL_TIME
+
+                    if not result:
+                        self.logger.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid))
+
+        except:
+            self.logger.debug(traceback.format_exc())
+            raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
+
+        if vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name) is None:
+            self.logger.info("Deleted vm instance {} sccessfully".format(vm__vim_uuid))
+            return vm__vim_uuid
+        else:
+            raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
+
+    def refresh_vms_status(self, vm_list):
+        """Get the status of the virtual machines and their interfaces/ports
+           Params: the list of VM identifiers
+           Returns a dictionary with:
+                vm_id:          #VIM id of this Virtual Machine
+                    status:     #Mandatory. Text with one of:
+                                #  DELETED (not found at vim)
+                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
+                                #  OTHER (Vim reported other status not understood)
+                                #  ERROR (VIM indicates an ERROR status)
+                                #  ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
+                                #  CREATING (on building process), ERROR
+                                #  ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
+                                #
+                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR
+                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+                    interfaces:
+                     -  vim_info:         #Text with plain information obtained from vim (yaml.safe_dump)
+                        mac_address:      #Text format XX:XX:XX:XX:XX:XX
+                        vim_net_id:       #network id where this interface is connected
+                        vim_interface_id: #interface/port VIM id
+                        ip_address:       #null, or text with IPv4, IPv6 address
+        """
+
+        self.logger.debug("Client requesting refresh vm status for {} ".format(vm_list))
+
+        mac_ip_addr={}
+        rheaders = {'Content-Type': 'application/xml'}
+        iso_edges = ['edge-2','edge-3','edge-6','edge-7','edge-8','edge-9','edge-10']
+
+        try:
+            for edge in iso_edges:
+                nsx_api_url = '/api/4.0/edges/'+ edge +'/dhcp/leaseInfo'
+                self.logger.debug("refresh_vms_status: NSX Manager url: {}".format(nsx_api_url))
+
+                resp = requests.get(self.nsx_manager + nsx_api_url,
+                                    auth = (self.nsx_user, self.nsx_password),
+                                    verify = False, headers = rheaders)
+
+                if resp.status_code == requests.codes.ok:
+                    dhcp_leases = XmlElementTree.fromstring(resp.text)
+                    for child in dhcp_leases:
+                        if child.tag == 'dhcpLeaseInfo':
+                            dhcpLeaseInfo = child
+                            for leaseInfo in dhcpLeaseInfo:
+                                for elem in leaseInfo:
+                                    if (elem.tag)=='macAddress':
+                                        mac_addr = elem.text
+                                    if (elem.tag)=='ipAddress':
+                                        ip_addr = elem.text
+                                if (mac_addr) is not None:
+                                    mac_ip_addr[mac_addr]= ip_addr
+                    self.logger.debug("NSX Manager DHCP Lease info: mac_ip_addr : {}".format(mac_ip_addr))
+                else:
+                    self.logger.debug("Error occurred while getting DHCP lease info from NSX Manager: {}".format(resp.content))
+        except KeyError:
+            self.logger.debug("Error in response from NSX Manager {}".format(KeyError.message))
+            self.logger.debug(traceback.format_exc())
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        vdc = vca.get_vdc(self.tenant_name)
+        if vdc is None:
+            raise vimconn.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
+
+        vms_dict = {}
+        for vmuuid in vm_list:
+            vmname = self.get_namebyvappid(vca, vdc, vmuuid)
+            if vmname is not None:
+
+                the_vapp = vca.get_vapp(vdc, vmname)
+                vm_info = the_vapp.get_vms_details()
+                vm_status = vm_info[0]['status']
+                vm_pci_details = self.get_vm_pci_details(vmuuid)
+                vm_info[0].update(vm_pci_details)
+
+                vm_dict = {'status': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
+                           'error_msg': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
+                           'vim_info': yaml.safe_dump(vm_info), 'interfaces': []}
+
+                # get networks
+                try:
+                    vm_app_networks = the_vapp.get_vms_network_info()
+                    for vapp_network in vm_app_networks:
+                        for vm_network in vapp_network:
+                            if vm_network['name'] == vmname:
+                                #Assign IP Address based on MAC Address in NSX DHCP lease info
+                                for mac_adres,ip_adres in mac_ip_addr.iteritems():
+                                    if mac_adres == vm_network['mac']:
+                                        vm_network['ip']=ip_adres
+                                interface = {"mac_address": vm_network['mac'],
+                                             "vim_net_id": self.get_network_id_by_name(vm_network['network_name']),
+                                             "vim_interface_id": self.get_network_id_by_name(vm_network['network_name']),
+                                             'ip_address': vm_network['ip']}
+                                # interface['vim_info'] = yaml.safe_dump(vm_network)
+                                vm_dict["interfaces"].append(interface)
+                    # add a vm to vm dict
+                    vms_dict.setdefault(vmuuid, vm_dict)
+                except KeyError:
+                    self.logger.debug("Error in respond {}".format(KeyError.message))
+                    self.logger.debug(traceback.format_exc())
+
+        return vms_dict
+
+    def action_vminstance(self, vm__vim_uuid=None, action_dict=None):
+        """Send and action over a VM instance from VIM
+        Returns the vm_id if the action was successfully sent to the VIM"""
+
+        self.logger.debug("Received action for vm {} and action dict {}".format(vm__vim_uuid, action_dict))
+        if vm__vim_uuid is None or action_dict is None:
+            raise vimconn.vimconnException("Invalid request. VM id or action is None.")
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        vdc = vca.get_vdc(self.tenant_name)
+        if vdc is None:
+            return -1, "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name)
+
+        vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
+        if vapp_name is None:
+            self.logger.debug("action_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
+            raise vimconn.vimconnException("Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
+        else:
+            self.logger.info("Action_vminstance vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
+
+        try:
+            the_vapp = vca.get_vapp(vdc, vapp_name)
+            # TODO fix all status
+            if "start" in action_dict:
+                vm_info = the_vapp.get_vms_details()
+                vm_status = vm_info[0]['status']
+                self.logger.info("Power on vApp: vm_status:{} {}".format(type(vm_status),vm_status))
+                if vm_status == "Suspended" or vm_status == "Powered off":
+                    power_on_task = the_vapp.poweron()
+                    if power_on_task is not None and type(power_on_task) is GenericTask:
+                        result = vca.block_until_completed(power_on_task)
+                        if result:
+                            self.logger.info("action_vminstance: Powered on vApp: {}".format(vapp_name))
+                        else:
+                            self.logger.info("action_vminstance: Failed to power on vApp: {}".format(vapp_name))
+                    else:
+                        self.logger.info("action_vminstance: Wait for vApp {} to power on".format(vapp_name))
+            elif "rebuild" in action_dict:
+                self.logger.info("action_vminstance: Rebuilding vApp: {}".format(vapp_name))
+                power_on_task = the_vapp.deploy(powerOn=True)
+                if type(power_on_task) is GenericTask:
+                    result = vca.block_until_completed(power_on_task)
+                    if result:
+                        self.logger.info("action_vminstance: Rebuilt vApp: {}".format(vapp_name))
+                    else:
+                        self.logger.info("action_vminstance: Failed to rebuild vApp: {}".format(vapp_name))
+                else:
+                    self.logger.info("action_vminstance: Wait for vApp rebuild {} to power on".format(vapp_name))
+            elif "pause" in action_dict:
+                pass
+                ## server.pause()
+            elif "resume" in action_dict:
+                pass
+                ## server.resume()
+            elif "shutoff" in action_dict or "shutdown" in action_dict:
+                power_off_task = the_vapp.undeploy(action='powerOff')
+                if type(power_off_task) is GenericTask:
+                    result = vca.block_until_completed(power_off_task)
+                    if result:
+                        self.logger.info("action_vminstance: Powered off vApp: {}".format(vapp_name))
+                    else:
+                        self.logger.info("action_vminstance: Failed to power off vApp: {}".format(vapp_name))
+                else:
+                    self.logger.info("action_vminstance: Wait for vApp {} to power off".format(vapp_name))
+            elif "forceOff" in action_dict:
+                the_vapp.reset()
+            elif "terminate" in action_dict:
+                the_vapp.delete()
+            # elif "createImage" in action_dict:
+            #     server.create_image()
+            else:
+                pass
+        except:
+            pass
+
+    def get_vminstance_console(self, vm_id, console_type="vnc"):
+        """
+        Get a console for the virtual machine
+        Params:
+            vm_id: uuid of the VM
+            console_type, can be:
+                "novnc" (by default), "xvpvnc" for VNC types,
+                "rdp-html5" for RDP types, "spice-html5" for SPICE types
+        Returns dict with the console parameters:
+                protocol: ssh, ftp, http, https, ...
+                server:   usually ip address
+                port:     the http, ssh, ... port
+                suffix:   extra text, e.g. the http path and query string
+        """
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    # NOT USED METHODS in current version
+
+    def host_vim2gui(self, host, server_dict):
+        """Transform host dictionary from VIM format to GUI format,
+        and append to the server_dict
+        """
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def get_hosts_info(self):
+        """Get the information of deployed hosts
+        Returns the hosts content"""
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def get_hosts(self, vim_tenant):
+        """Get the hosts and deployed instances
+        Returns the hosts content"""
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def get_processor_rankings(self):
+        """Get the processor rankings in the VIM database"""
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def new_host(self, host_data):
+        """Adds a new host to VIM"""
+        '''Returns status code of the VIM response'''
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def new_external_port(self, port_data):
+        """Adds a external port to VIM"""
+        '''Returns the port identifier'''
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def new_external_network(self, net_name, net_type):
+        """Adds a external network to VIM (shared)"""
+        '''Returns the network identifier'''
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def connect_port_network(self, port_id, network_id, admin=False):
+        """Connects a external port to a network"""
+        '''Returns status code of the VIM response'''
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def new_vminstancefromJSON(self, vm_data):
+        """Adds a VM instance to VIM"""
+        '''Returns the instance identifier'''
+        raise vimconn.vimconnNotImplemented("Should have implemented this")
+
+    def get_network_name_by_id(self, network_uuid=None):
+        """Method gets vcloud director network named based on supplied uuid.
+
+        Args:
+            network_uuid: network_id
+
+        Returns:
+            The return network name.
+        """
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        if not network_uuid:
+            return None
+
+        try:
+            org_dict = self.get_org(self.org_uuid)
+            if 'networks' in org_dict:
+                org_network_dict = org_dict['networks']
+                for net_uuid in org_network_dict:
+                    if net_uuid == network_uuid:
+                        return org_network_dict[net_uuid]
+        except:
+            self.logger.debug("Exception in get_network_name_by_id")
+            self.logger.debug(traceback.format_exc())
+
+        return None
+
+    def get_network_id_by_name(self, network_name=None):
+        """Method gets vcloud director network uuid based on supplied name.
+
+        Args:
+            network_name: network_name
+        Returns:
+            The return network uuid.
+            network_uuid: network_id
+        """
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        if not network_name:
+            self.logger.debug("get_network_id_by_name() : Network name is empty")
+            return None
+
+        try:
+            org_dict = self.get_org(self.org_uuid)
+            if org_dict and 'networks' in org_dict:
+                org_network_dict = org_dict['networks']
+                for net_uuid,net_name in org_network_dict.iteritems():
+                    if net_name == network_name:
+                        return net_uuid
+
+        except KeyError as exp:
+            self.logger.debug("get_network_id_by_name() : KeyError- {} ".format(exp))
+
+        return None
+
+    def list_org_action(self):
+        """
+        Method leverages vCloud director and query for available organization for particular user
+
+        Args:
+            vca - is active VCA connection.
+            vdc_name - is a vdc name that will be used to query vms action
+
+            Returns:
+                The return XML respond
+        """
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+        url_list = [vca.host, '/api/org']
+        vm_list_rest_call = ''.join(url_list)
+
+        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+            response = Http.get(url=vm_list_rest_call,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+            if response.status_code == requests.codes.ok:
+                return response.content
+
+        return None
+
+    def get_org_action(self, org_uuid=None):
+        """
+        Method leverages vCloud director and retrieve available object fdr organization.
+
+        Args:
+            vca - is active VCA connection.
+            vdc_name - is a vdc name that will be used to query vms action
+
+            Returns:
+                The return XML respond
+        """
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+        if org_uuid is None:
+            return None
+
+        url_list = [vca.host, '/api/org/', org_uuid]
+        vm_list_rest_call = ''.join(url_list)
+
+        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+            response = Http.get(url=vm_list_rest_call,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+            if response.status_code == requests.codes.ok:
+                return response.content
+
+        return None
+
+    def get_org(self, org_uuid=None):
+        """
+        Method retrieves available organization in vCloud Director
+
+        Args:
+            org_uuid - is a organization uuid.
+
+            Returns:
+                The return dictionary with following key
+                    "network" - for network list under the org
+                    "catalogs" - for network list under the org
+                    "vdcs" - for vdc list under org
+        """
+
+        org_dict = {}
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+        if org_uuid is None:
+            return org_dict
+
+        content = self.get_org_action(org_uuid=org_uuid)
+        try:
+            vdc_list = {}
+            network_list = {}
+            catalog_list = {}
+            vm_list_xmlroot = XmlElementTree.fromstring(content)
+            for child in vm_list_xmlroot:
+                if child.attrib['type'] == 'application/vnd.vmware.vcloud.vdc+xml':
+                    vdc_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
+                    org_dict['vdcs'] = vdc_list
+                if child.attrib['type'] == 'application/vnd.vmware.vcloud.orgNetwork+xml':
+                    network_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
+                    org_dict['networks'] = network_list
+                if child.attrib['type'] == 'application/vnd.vmware.vcloud.catalog+xml':
+                    catalog_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
+                    org_dict['catalogs'] = catalog_list
+        except:
+            pass
+
+        return org_dict
+
+    def get_org_list(self):
+        """
+        Method retrieves available organization in vCloud Director
+
+        Args:
+            vca - is active VCA connection.
+
+            Returns:
+                The return dictionary and key for each entry VDC UUID
+        """
+
+        org_dict = {}
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+        content = self.list_org_action()
+        try:
+            vm_list_xmlroot = XmlElementTree.fromstring(content)
+            for vm_xml in vm_list_xmlroot:
+                if vm_xml.tag.split("}")[1] == 'Org':
+                    org_uuid = vm_xml.attrib['href'].split('/')[-1:]
+                    org_dict[org_uuid[0]] = vm_xml.attrib['name']
+        except:
+            pass
+
+        return org_dict
+
+    def vms_view_action(self, vdc_name=None):
+        """ Method leverages vCloud director vms query call
+
+        Args:
+            vca - is active VCA connection.
+            vdc_name - is a vdc name that will be used to query vms action
+
+            Returns:
+                The return XML respond
+        """
+        vca = self.connect()
+        if vdc_name is None:
+            return None
+
+        url_list = [vca.host, '/api/vms/query']
+        vm_list_rest_call = ''.join(url_list)
+
+        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+            refs = filter(lambda ref: ref.name == vdc_name and ref.type_ == 'application/vnd.vmware.vcloud.vdc+xml',
+                          vca.vcloud_session.organization.Link)
+            if len(refs) == 1:
+                response = Http.get(url=vm_list_rest_call,
+                                    headers=vca.vcloud_session.get_vcloud_headers(),
+                                    verify=vca.verify,
+                                    logger=vca.logger)
+                if response.status_code == requests.codes.ok:
+                    return response.content
+
+        return None
+
+    def get_vapp_list(self, vdc_name=None):
+        """
+        Method retrieves vApp list deployed vCloud director and returns a dictionary
+        contains a list of all vapp deployed for queried VDC.
+        The key for a dictionary is vApp UUID
+
+
+        Args:
+            vca - is active VCA connection.
+            vdc_name - is a vdc name that will be used to query vms action
+
+            Returns:
+                The return dictionary and key for each entry vapp UUID
+        """
+
+        vapp_dict = {}
+        if vdc_name is None:
+            return vapp_dict
+
+        content = self.vms_view_action(vdc_name=vdc_name)
+        try:
+            vm_list_xmlroot = XmlElementTree.fromstring(content)
+            for vm_xml in vm_list_xmlroot:
+                if vm_xml.tag.split("}")[1] == 'VMRecord':
+                    if vm_xml.attrib['isVAppTemplate'] == 'true':
+                        rawuuid = vm_xml.attrib['container'].split('/')[-1:]
+                        if 'vappTemplate-' in rawuuid[0]:
+                            # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
+                            # vm and use raw UUID as key
+                            vapp_dict[rawuuid[0][13:]] = vm_xml.attrib
+        except:
+            pass
+
+        return vapp_dict
+
+    def get_vm_list(self, vdc_name=None):
+        """
+        Method retrieves VM's list deployed vCloud director. It returns a dictionary
+        contains a list of all VM's deployed for queried VDC.
+        The key for a dictionary is VM UUID
+
+
+        Args:
+            vca - is active VCA connection.
+            vdc_name - is a vdc name that will be used to query vms action
+
+            Returns:
+                The return dictionary and key for each entry vapp UUID
+        """
+        vm_dict = {}
+
+        if vdc_name is None:
+            return vm_dict
+
+        content = self.vms_view_action(vdc_name=vdc_name)
+        try:
+            vm_list_xmlroot = XmlElementTree.fromstring(content)
+            for vm_xml in vm_list_xmlroot:
+                if vm_xml.tag.split("}")[1] == 'VMRecord':
+                    if vm_xml.attrib['isVAppTemplate'] == 'false':
+                        rawuuid = vm_xml.attrib['href'].split('/')[-1:]
+                        if 'vm-' in rawuuid[0]:
+                            # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
+                            #  vm and use raw UUID as key
+                            vm_dict[rawuuid[0][3:]] = vm_xml.attrib
+        except:
+            pass
+
+        return vm_dict
+
+    def get_vapp(self, vdc_name=None, vapp_name=None, isuuid=False):
+        """
+        Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
+        contains a list of all VM's deployed for queried VDC.
+        The key for a dictionary is VM UUID
+
+
+        Args:
+            vca - is active VCA connection.
+            vdc_name - is a vdc name that will be used to query vms action
+
+            Returns:
+                The return dictionary and key for each entry vapp UUID
+        """
+        vm_dict = {}
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+        if vdc_name is None:
+            return vm_dict
+
+        content = self.vms_view_action(vdc_name=vdc_name)
+        try:
+            vm_list_xmlroot = XmlElementTree.fromstring(content)
+            for vm_xml in vm_list_xmlroot:
+                if vm_xml.tag.split("}")[1] == 'VMRecord' and vm_xml.attrib['isVAppTemplate'] == 'false':
+                    # lookup done by UUID
+                    if isuuid:
+                        if vapp_name in vm_xml.attrib['container']:
+                            rawuuid = vm_xml.attrib['href'].split('/')[-1:]
+                            if 'vm-' in rawuuid[0]:
+                                vm_dict[rawuuid[0][3:]] = vm_xml.attrib
+                                break
+                    # lookup done by Name
+                    else:
+                        if vapp_name in vm_xml.attrib['name']:
+                            rawuuid = vm_xml.attrib['href'].split('/')[-1:]
+                            if 'vm-' in rawuuid[0]:
+                                vm_dict[rawuuid[0][3:]] = vm_xml.attrib
+                                break
+        except:
+            pass
+
+        return vm_dict
+
+    def get_network_action(self, network_uuid=None):
+        """
+        Method leverages vCloud director and query network based on network uuid
+
+        Args:
+            vca - is active VCA connection.
+            network_uuid - is a network uuid
+
+            Returns:
+                The return XML respond
+        """
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+        if network_uuid is None:
+            return None
+
+        url_list = [vca.host, '/api/network/', network_uuid]
+        vm_list_rest_call = ''.join(url_list)
+
+        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+            response = Http.get(url=vm_list_rest_call,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+            if response.status_code == requests.codes.ok:
+                return response.content
+
+        return None
+
+    def get_vcd_network(self, network_uuid=None):
+        """
+        Method retrieves available network from vCloud Director
+
+        Args:
+            network_uuid - is VCD network UUID
+
+        Each element serialized as key : value pair
+
+        Following keys available for access.    network_configuration['Gateway'}
+        <Configuration>
+          <IpScopes>
+            <IpScope>
+                <IsInherited>true</IsInherited>
+                <Gateway>172.16.252.100</Gateway>
+                <Netmask>255.255.255.0</Netmask>
+                <Dns1>172.16.254.201</Dns1>
+                <Dns2>172.16.254.202</Dns2>
+                <DnsSuffix>vmwarelab.edu</DnsSuffix>
+                <IsEnabled>true</IsEnabled>
+                <IpRanges>
+                    <IpRange>
+                        <StartAddress>172.16.252.1</StartAddress>
+                        <EndAddress>172.16.252.99</EndAddress>
+                    </IpRange>
+                </IpRanges>
+            </IpScope>
+        </IpScopes>
+        <FenceMode>bridged</FenceMode>
+
+        Returns:
+                The return dictionary and key for each entry vapp UUID
+        """
+
+        network_configuration = {}
+        if network_uuid is None:
+            return network_uuid
+
+        content = self.get_network_action(network_uuid=network_uuid)
+        try:
+            vm_list_xmlroot = XmlElementTree.fromstring(content)
+
+            network_configuration['status'] = vm_list_xmlroot.get("status")
+            network_configuration['name'] = vm_list_xmlroot.get("name")
+            network_configuration['uuid'] = vm_list_xmlroot.get("id").split(":")[3]
+
+            for child in vm_list_xmlroot:
+                if child.tag.split("}")[1] == 'IsShared':
+                    network_configuration['isShared'] = child.text.strip()
+                if child.tag.split("}")[1] == 'Configuration':
+                    for configuration in child.iter():
+                        tagKey = configuration.tag.split("}")[1].strip()
+                        if tagKey != "":
+                            network_configuration[tagKey] = configuration.text.strip()
+            return network_configuration
+        except:
+            pass
+
+        return network_configuration
+
+    def delete_network_action(self, network_uuid=None):
+        """
+        Method delete given network from vCloud director
+
+        Args:
+            network_uuid - is a network uuid that client wish to delete
+
+            Returns:
+                The return None or XML respond or false
+        """
+
+        vca = self.connect_as_admin()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+        if network_uuid is None:
+            return False
+
+        url_list = [vca.host, '/api/admin/network/', network_uuid]
+        vm_list_rest_call = ''.join(url_list)
+
+        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+            response = Http.delete(url=vm_list_rest_call,
+                                   headers=vca.vcloud_session.get_vcloud_headers(),
+                                   verify=vca.verify,
+                                   logger=vca.logger)
+
+            if response.status_code == 202:
+                return True
+
+        return False
+
+    def create_network(self, network_name=None, net_type='bridge', parent_network_uuid=None,
+                       ip_profile=None, isshared='true'):
+        """
+        Method create network in vCloud director
+
+        Args:
+            network_name - is network name to be created.
+            net_type - can be 'bridge','data','ptp','mgmt'.
+            ip_profile is a dict containing the IP parameters of the network
+            isshared - is a boolean
+            parent_network_uuid - is parent provider vdc network that will be used for mapping.
+            It optional attribute. by default if no parent network indicate the first available will be used.
+
+            Returns:
+                The return network uuid or return None
+        """
+
+        new_network_name = [network_name, '-', str(uuid.uuid4())]
+        content = self.create_network_rest(network_name=''.join(new_network_name),
+                                           ip_profile=ip_profile,
+                                           net_type=net_type,
+                                           parent_network_uuid=parent_network_uuid,
+                                           isshared=isshared)
+        if content is None:
+            self.logger.debug("Failed create network {}.".format(network_name))
+            return None
+
+        try:
+            vm_list_xmlroot = XmlElementTree.fromstring(content)
+            vcd_uuid = vm_list_xmlroot.get('id').split(":")
+            if len(vcd_uuid) == 4:
+                self.logger.info("Create new network name: {} uuid: {}".format(network_name, vcd_uuid[3]))
+                return vcd_uuid[3]
+        except:
+            self.logger.debug("Failed create network {}".format(network_name))
+            return None
+
+    def create_network_rest(self, network_name=None, net_type='bridge', parent_network_uuid=None,
+                            ip_profile=None, isshared='true'):
+        """
+        Method create network in vCloud director
+
+        Args:
+            network_name - is network name to be created.
+            net_type - can be 'bridge','data','ptp','mgmt'.
+            ip_profile is a dict containing the IP parameters of the network
+            isshared - is a boolean
+            parent_network_uuid - is parent provider vdc network that will be used for mapping.
+            It optional attribute. by default if no parent network indicate the first available will be used.
+
+            Returns:
+                The return network uuid or return None
+        """
+
+        vca = self.connect_as_admin()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+        if network_name is None:
+            return None
+
+        url_list = [vca.host, '/api/admin/vdc/', self.tenant_id]
+        vm_list_rest_call = ''.join(url_list)
+        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+            response = Http.get(url=vm_list_rest_call,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+
+            provider_network = None
+            available_networks = None
+            add_vdc_rest_url = None
+
+            if response.status_code != requests.codes.ok:
+                self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
+                                                                                          response.status_code))
+                return None
+            else:
+                try:
+                    vm_list_xmlroot = XmlElementTree.fromstring(response.content)
+                    for child in vm_list_xmlroot:
+                        if child.tag.split("}")[1] == 'ProviderVdcReference':
+                            provider_network = child.attrib.get('href')
+                            # application/vnd.vmware.admin.providervdc+xml
+                        if child.tag.split("}")[1] == 'Link':
+                            if child.attrib.get('type') == 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' \
+                                    and child.attrib.get('rel') == 'add':
+                                add_vdc_rest_url = child.attrib.get('href')
+                except:
+                    self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
+                    self.logger.debug("Respond body {}".format(response.content))
+                    return None
+
+            # find  pvdc provided available network
+            response = Http.get(url=provider_network,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+            if response.status_code != requests.codes.ok:
+                self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
+                                                                                          response.status_code))
+                return None
+
+            # available_networks.split("/")[-1]
+
+            if parent_network_uuid is None:
+                try:
+                    vm_list_xmlroot = XmlElementTree.fromstring(response.content)
+                    for child in vm_list_xmlroot.iter():
+                        if child.tag.split("}")[1] == 'AvailableNetworks':
+                            for networks in child.iter():
+                                # application/vnd.vmware.admin.network+xml
+                                if networks.attrib.get('href') is not None:
+                                    available_networks = networks.attrib.get('href')
+                                    break
+                except:
+                    return None
+
+            #Configure IP profile of the network
+            ip_profile = ip_profile if ip_profile is not None else DEFAULT_IP_PROFILE
+
+            gateway_address=ip_profile['gateway_address']
+            dhcp_count=int(ip_profile['dhcp_count'])
+            subnet_address=self.convert_cidr_to_netmask(ip_profile['subnet_address'])
+
+            if ip_profile['dhcp_enabled']==True:
+                dhcp_enabled='true'
+            else:
+                dhcp_enabled='false'
+            dhcp_start_address=ip_profile['dhcp_start_address']
+
+            #derive dhcp_end_address from dhcp_start_address & dhcp_count
+            end_ip_int = int(netaddr.IPAddress(dhcp_start_address))
+            end_ip_int += dhcp_count - 1
+            dhcp_end_address = str(netaddr.IPAddress(end_ip_int))
+
+            ip_version=ip_profile['ip_version']
+            dns_address=ip_profile['dns_address']
+
+            # either use client provided UUID or search for a first available
+            #  if both are not defined we return none
+            if parent_network_uuid is not None:
+                url_list = [vca.host, '/api/admin/network/', parent_network_uuid]
+                add_vdc_rest_url = ''.join(url_list)
+
+            if net_type=='ptp':
+                fence_mode="isolated"
+                isshared='false'
+                is_inherited='false'
+                data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
+                                <Description>Openmano created</Description>
+                                        <Configuration>
+                                            <IpScopes>
+                                                <IpScope>
+                                                    <IsInherited>{1:s}</IsInherited>
+                                                    <Gateway>{2:s}</Gateway>
+                                                    <Netmask>{3:s}</Netmask>
+                                                    <Dns1>{4:s}</Dns1>
+                                                    <IsEnabled>{5:s}</IsEnabled>
+                                                    <IpRanges>
+                                                        <IpRange>
+                                                            <StartAddress>{6:s}</StartAddress>
+                                                            <EndAddress>{7:s}</EndAddress>
+                                                        </IpRange>
+                                                    </IpRanges>
+                                                </IpScope>
+                                            </IpScopes>
+                                            <FenceMode>{8:s}</FenceMode>
+                                        </Configuration>
+                                        <IsShared>{9:s}</IsShared>
+                            </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
+                                                        subnet_address, dns_address, dhcp_enabled,
+                                                        dhcp_start_address, dhcp_end_address, fence_mode, isshared)
+
+            else:
+                fence_mode="bridged"
+                is_inherited='false'
+                data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
+                                <Description>Openmano created</Description>
+                                        <Configuration>
+                                            <IpScopes>
+                                                <IpScope>
+                                                    <IsInherited>{1:s}</IsInherited>
+                                                    <Gateway>{2:s}</Gateway>
+                                                    <Netmask>{3:s}</Netmask>
+                                                    <Dns1>{4:s}</Dns1>
+                                                    <IsEnabled>{5:s}</IsEnabled>
+                                                    <IpRanges>
+                                                        <IpRange>
+                                                            <StartAddress>{6:s}</StartAddress>
+                                                            <EndAddress>{7:s}</EndAddress>
+                                                        </IpRange>
+                                                    </IpRanges>
+                                                </IpScope>
+                                            </IpScopes>
+                                            <ParentNetwork href="{8:s}"/>
+                                            <FenceMode>{9:s}</FenceMode>
+                                        </Configuration>
+                                        <IsShared>{10:s}</IsShared>
+                            </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
+                                                        subnet_address, dns_address, dhcp_enabled,
+                                                        dhcp_start_address, dhcp_end_address, available_networks,
+                                                        fence_mode, isshared)
+
+            headers = vca.vcloud_session.get_vcloud_headers()
+            headers['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
+            try:
+                response = Http.post(url=add_vdc_rest_url,
+                                     headers=headers,
+                                     data=data,
+                                     verify=vca.verify,
+                                     logger=vca.logger)
+
+                if response.status_code != 201:
+                    self.logger.debug("Create Network POST REST API call failed. Return status code {}"
+                                      .format(response.status_code))
+                else:
+                    network = networkType.parseString(response.content, True)
+                    create_nw_task = network.get_Tasks().get_Task()[0]
+
+                    # if we all ok we respond with content after network creation completes
+                    # otherwise by default return None
+                    if create_nw_task is not None:
+                        self.logger.debug("Create Network REST : Waiting for Nw creation complete")
+                        status = vca.block_until_completed(create_nw_task)
+                        if status:
+                            return response.content
+                        else:
+                            self.logger.debug("create_network_rest task failed. Network Create response : {}"
+                                              .format(response.content))
+            except Exception as exp:
+                self.logger.debug("create_network_rest : Exception : {} ".format(exp))
+
+        return None
+
+    def convert_cidr_to_netmask(self, cidr_ip=None):
+        """
+        Method sets convert CIDR netmask address to normal IP format
+        Args:
+            cidr_ip : CIDR IP address
+            Returns:
+                netmask : Converted netmask
+        """
+        if cidr_ip is not None:
+            if '/' in cidr_ip:
+                network, net_bits = cidr_ip.split('/')
+                netmask = socket.inet_ntoa(struct.pack(">I", (0xffffffff << (32 - int(net_bits))) & 0xffffffff))
+            else:
+                netmask = cidr_ip
+            return netmask
+        return None
+
+    def get_provider_rest(self, vca=None):
+        """
+        Method gets provider vdc view from vcloud director
+
+        Args:
+            network_name - is network name to be created.
+            parent_network_uuid - is parent provider vdc network that will be used for mapping.
+            It optional attribute. by default if no parent network indicate the first available will be used.
+
+            Returns:
+                The return xml content of respond or None
+        """
+
+        url_list = [vca.host, '/api/admin']
+        response = Http.get(url=''.join(url_list),
+                            headers=vca.vcloud_session.get_vcloud_headers(),
+                            verify=vca.verify,
+                            logger=vca.logger)
+
+        if response.status_code == requests.codes.ok:
+            return response.content
+        return None
+
+    def create_vdc(self, vdc_name=None):
+
+        vdc_dict = {}
+
+        xml_content = self.create_vdc_from_tmpl_rest(vdc_name=vdc_name)
+        if xml_content is not None:
+            try:
+                task_resp_xmlroot = XmlElementTree.fromstring(xml_content)
+                for child in task_resp_xmlroot:
+                    if child.tag.split("}")[1] == 'Owner':
+                        vdc_id = child.attrib.get('href').split("/")[-1]
+                        vdc_dict[vdc_id] = task_resp_xmlroot.get('href')
+                        return vdc_dict
+            except:
+                self.logger.debug("Respond body {}".format(xml_content))
+
+        return None
+
+    def create_vdc_from_tmpl_rest(self, vdc_name=None):
+        """
+        Method create vdc in vCloud director based on VDC template.
+        it uses pre-defined template that must be named openmano
+
+        Args:
+            vdc_name -  name of a new vdc.
+
+            Returns:
+                The return xml content of respond or None
+        """
+
+        self.logger.info("Creating new vdc {}".format(vdc_name))
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+        if vdc_name is None:
+            return None
+
+        url_list = [vca.host, '/api/vdcTemplates']
+        vm_list_rest_call = ''.join(url_list)
+        response = Http.get(url=vm_list_rest_call,
+                            headers=vca.vcloud_session.get_vcloud_headers(),
+                            verify=vca.verify,
+                            logger=vca.logger)
+
+        # container url to a template
+        vdc_template_ref = None
+        try:
+            vm_list_xmlroot = XmlElementTree.fromstring(response.content)
+            for child in vm_list_xmlroot:
+                # application/vnd.vmware.admin.providervdc+xml
+                # we need find a template from witch we instantiate VDC
+                if child.tag.split("}")[1] == 'VdcTemplate':
+                    if child.attrib.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml' and child.attrib.get(
+                            'name') == 'openmano':
+                        vdc_template_ref = child.attrib.get('href')
+        except:
+            self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
+            self.logger.debug("Respond body {}".format(response.content))
+            return None
+
+        # if we didn't found required pre defined template we return None
+        if vdc_template_ref is None:
+            return None
+
+        try:
+            # instantiate vdc
+            url_list = [vca.host, '/api/org/', self.org_uuid, '/action/instantiate']
+            vm_list_rest_call = ''.join(url_list)
+            data = """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
+                                        <Source href="{1:s}"></Source>
+                                        <Description>opnemano</Description>
+                                        </InstantiateVdcTemplateParams>""".format(vdc_name, vdc_template_ref)
+            headers = vca.vcloud_session.get_vcloud_headers()
+            headers['Content-Type'] = 'application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml'
+            response = Http.post(url=vm_list_rest_call, headers=headers, data=data, verify=vca.verify,
+                                 logger=vca.logger)
+            # if we all ok we respond with content otherwise by default None
+            if response.status_code >= 200 and response.status_code < 300:
+                return response.content
+            return None
+        except:
+            self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
+            self.logger.debug("Respond body {}".format(response.content))
+
+        return None
+
+    def create_vdc_rest(self, vdc_name=None):
+        """
+        Method create network in vCloud director
+
+        Args:
+            network_name - is network name to be created.
+            parent_network_uuid - is parent provider vdc network that will be used for mapping.
+            It optional attribute. by default if no parent network indicate the first available will be used.
+
+            Returns:
+                The return network uuid or return None
+        """
+
+        self.logger.info("Creating new vdc {}".format(vdc_name))
+
+        vca = self.connect_as_admin()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+        if vdc_name is None:
+            return None
+
+        url_list = [vca.host, '/api/admin/org/', self.org_uuid]
+        vm_list_rest_call = ''.join(url_list)
+        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+            response = Http.get(url=vm_list_rest_call,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+
+            provider_vdc_ref = None
+            add_vdc_rest_url = None
+            available_networks = None
+
+            if response.status_code != requests.codes.ok:
+                self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
+                                                                                          response.status_code))
+                return None
+            else:
+                try:
+                    vm_list_xmlroot = XmlElementTree.fromstring(response.content)
+                    for child in vm_list_xmlroot:
+                        # application/vnd.vmware.admin.providervdc+xml
+                        if child.tag.split("}")[1] == 'Link':
+                            if child.attrib.get('type') == 'application/vnd.vmware.admin.createVdcParams+xml' \
+                                    and child.attrib.get('rel') == 'add':
+                                add_vdc_rest_url = child.attrib.get('href')
+                except:
+                    self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
+                    self.logger.debug("Respond body {}".format(response.content))
+                    return None
+
+                response = self.get_provider_rest(vca=vca)
+                try:
+                    vm_list_xmlroot = XmlElementTree.fromstring(response)
+                    for child in vm_list_xmlroot:
+                        if child.tag.split("}")[1] == 'ProviderVdcReferences':
+                            for sub_child in child:
+                                provider_vdc_ref = sub_child.attrib.get('href')
+                except:
+                    self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
+                    self.logger.debug("Respond body {}".format(response))
+                    return None
+
+                if add_vdc_rest_url is not None and provider_vdc_ref is not None:
+                    data = """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
+                            <AllocationModel>ReservationPool</AllocationModel>
+                            <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
+                            <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
+                            </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
+                            <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
+                            <ProviderVdcReference
+                            name="Main Provider"
+                            href="{2:s}" />
+                    <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(escape(vdc_name),
+                                                                                                  escape(vdc_name),
+                                                                                                  provider_vdc_ref)
+
+                    headers = vca.vcloud_session.get_vcloud_headers()
+                    headers['Content-Type'] = 'application/vnd.vmware.admin.createVdcParams+xml'
+                    response = Http.post(url=add_vdc_rest_url, headers=headers, data=data, verify=vca.verify,
+                                         logger=vca.logger)
+
+                    # if we all ok we respond with content otherwise by default None
+                    if response.status_code == 201:
+                        return response.content
+        return None
+
+    def get_vapp_details_rest(self, vapp_uuid=None, need_admin_access=False):
+        """
+        Method retrieve vapp detail from vCloud director
+
+        Args:
+            vapp_uuid - is vapp identifier.
+
+            Returns:
+                The return network uuid or return None
+        """
+
+        parsed_respond = {}
+        vca = None
+
+        if need_admin_access:
+            vca = self.connect_as_admin()
+        else:
+            vca = self.connect()
+
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+        if vapp_uuid is None:
+            return None
+
+        url_list = [vca.host, '/api/vApp/vapp-', vapp_uuid]
+        get_vapp_restcall = ''.join(url_list)
+
+        if vca.vcloud_session and vca.vcloud_session.organization:
+            response = Http.get(url=get_vapp_restcall,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+
+            if response.status_code != requests.codes.ok:
+                self.logger.debug("REST API call {} failed. Return status code {}".format(get_vapp_restcall,
+                                                                                          response.status_code))
+                return parsed_respond
+
+            try:
+                xmlroot_respond = XmlElementTree.fromstring(response.content)
+                parsed_respond['ovfDescriptorUploaded'] = xmlroot_respond.attrib['ovfDescriptorUploaded']
+
+                namespaces = {"vssd":"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" ,
+                              'ovf': 'http://schemas.dmtf.org/ovf/envelope/1',
+                              'vmw': 'http://www.vmware.com/schema/ovf',
+                              'vm': 'http://www.vmware.com/vcloud/v1.5',
+                              'rasd':"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
+                              "vmext":"http://www.vmware.com/vcloud/extension/v1.5",
+                              "xmlns":"http://www.vmware.com/vcloud/v1.5"
+                             }
+
+                created_section = xmlroot_respond.find('vm:DateCreated', namespaces)
+                if created_section is not None:
+                    parsed_respond['created'] = created_section.text
+
+                network_section = xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig', namespaces)
+                if network_section is not None and 'networkName' in network_section.attrib:
+                    parsed_respond['networkname'] = network_section.attrib['networkName']
+
+                ipscopes_section = \
+                    xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig/vm:Configuration/vm:IpScopes',
+                                         namespaces)
+                if ipscopes_section is not None:
+                    for ipscope in ipscopes_section:
+                        for scope in ipscope:
+                            tag_key = scope.tag.split("}")[1]
+                            if tag_key == 'IpRanges':
+                                ip_ranges = scope.getchildren()
+                                for ipblock in ip_ranges:
+                                    for block in ipblock:
+                                        parsed_respond[block.tag.split("}")[1]] = block.text
+                            else:
+                                parsed_respond[tag_key] = scope.text
+
+                # parse children section for other attrib
+                children_section = xmlroot_respond.find('vm:Children/', namespaces)
+                if children_section is not None:
+                    parsed_respond['name'] = children_section.attrib['name']
+                    parsed_respond['nestedHypervisorEnabled'] = children_section.attrib['nestedHypervisorEnabled'] \
+                     if  "nestedHypervisorEnabled" in children_section.attrib else None
+                    parsed_respond['deployed'] = children_section.attrib['deployed']
+                    parsed_respond['status'] = children_section.attrib['status']
+                    parsed_respond['vmuuid'] = children_section.attrib['id'].split(":")[-1]
+                    network_adapter = children_section.find('vm:NetworkConnectionSection', namespaces)
+                    nic_list = []
+                    for adapters in network_adapter:
+                        adapter_key = adapters.tag.split("}")[1]
+                        if adapter_key == 'PrimaryNetworkConnectionIndex':
+                            parsed_respond['primarynetwork'] = adapters.text
+                        if adapter_key == 'NetworkConnection':
+                            vnic = {}
+                            if 'network' in adapters.attrib:
+                                vnic['network'] = adapters.attrib['network']
+                            for adapter in adapters:
+                                setting_key = adapter.tag.split("}")[1]
+                                vnic[setting_key] = adapter.text
+                            nic_list.append(vnic)
+
+                    for link in children_section:
+                        if link.tag.split("}")[1] == 'Link' and 'rel' in link.attrib:
+                            if link.attrib['rel'] == 'screen:acquireTicket':
+                                parsed_respond['acquireTicket'] = link.attrib
+                            if link.attrib['rel'] == 'screen:acquireMksTicket':
+                                parsed_respond['acquireMksTicket'] = link.attrib
+
+                    parsed_respond['interfaces'] = nic_list
+                    vCloud_extension_section = children_section.find('xmlns:VCloudExtension', namespaces)
+                    if vCloud_extension_section is not None:
+                        vm_vcenter_info = {}
+                        vim_info = vCloud_extension_section.find('vmext:VmVimInfo', namespaces)
+                        vmext = vim_info.find('vmext:VmVimObjectRef', namespaces)
+                        if vmext is not None:
+                            vm_vcenter_info["vm_moref_id"] = vmext.find('vmext:MoRef', namespaces).text
+                        parsed_respond["vm_vcenter_info"]= vm_vcenter_info
+
+                    virtual_hardware_section = children_section.find('ovf:VirtualHardwareSection', namespaces)
+                    vm_virtual_hardware_info = {}
+                    if virtual_hardware_section is not None:
+                        for item in virtual_hardware_section.iterfind('ovf:Item',namespaces):
+                            if item.find("rasd:Description",namespaces).text == "Hard disk":
+                                disk_size = item.find("rasd:HostResource" ,namespaces
+                                                ).attrib["{"+namespaces['vm']+"}capacity"]
+
+                                vm_virtual_hardware_info["disk_size"]= disk_size
+                                break
+
+                        for link in virtual_hardware_section:
+                            if link.tag.split("}")[1] == 'Link' and 'rel' in link.attrib:
+                                if link.attrib['rel'] == 'edit' and link.attrib['href'].endswith("/disks"):
+                                    vm_virtual_hardware_info["disk_edit_href"] = link.attrib['href']
+                                    break
+
+                    parsed_respond["vm_virtual_hardware"]= vm_virtual_hardware_info
+            except Exception as exp :
+                self.logger.info("Error occurred calling rest api for getting vApp details {}".format(exp))
+        return parsed_respond
+
+    def acuire_console(self, vm_uuid=None):
+
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+        if vm_uuid is None:
+            return None
+
+        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+            vm_dict = self.get_vapp_details_rest(self, vapp_uuid=vm_uuid)
+            console_dict = vm_dict['acquireTicket']
+            console_rest_call = console_dict['href']
+
+            response = Http.post(url=console_rest_call,
+                                 headers=vca.vcloud_session.get_vcloud_headers(),
+                                 verify=vca.verify,
+                                 logger=vca.logger)
+
+            if response.status_code == requests.codes.ok:
+                return response.content
+
+        return None
+
+    def modify_vm_disk(self, vapp_uuid, flavor_disk):
+        """
+        Method retrieve vm disk details
+
+        Args:
+            vapp_uuid - is vapp identifier.
+            flavor_disk - disk size as specified in VNFD (flavor)
+
+            Returns:
+                The return network uuid or return None
+        """
+        status = None
+        try:
+            #Flavor disk is in GB convert it into MB
+            flavor_disk = int(flavor_disk) * 1024
+            vm_details = self.get_vapp_details_rest(vapp_uuid)
+            if vm_details:
+                vm_name = vm_details["name"]
+                self.logger.info("VM: {} flavor_disk :{}".format(vm_name , flavor_disk))
+
+            if vm_details and "vm_virtual_hardware" in vm_details:
+                vm_disk = int(vm_details["vm_virtual_hardware"]["disk_size"])
+                disk_edit_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
+
+                self.logger.info("VM: {} VM_disk :{}".format(vm_name , vm_disk))
+
+                if flavor_disk > vm_disk:
+                    status = self.modify_vm_disk_rest(disk_edit_href ,flavor_disk)
+                    self.logger.info("Modify disk of VM {} from {} to {} MB".format(vm_name,
+                                                         vm_disk,  flavor_disk ))
+                else:
+                    status = True
+                    self.logger.info("No need to modify disk of VM {}".format(vm_name))
+
+            return status
+        except Exception as exp:
+            self.logger.info("Error occurred while modifing disk size {}".format(exp))
+
+
+    def modify_vm_disk_rest(self, disk_href , disk_size):
+        """
+        Method retrieve modify vm disk size
+
+        Args:
+            disk_href - vCD API URL to GET and PUT disk data
+            disk_size - disk size as specified in VNFD (flavor)
+
+            Returns:
+                The return network uuid or return None
+        """
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+        if disk_href is None or disk_size is None:
+            return None
+
+        if vca.vcloud_session and vca.vcloud_session.organization:
+            response = Http.get(url=disk_href,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+
+        if response.status_code != requests.codes.ok:
+            self.logger.debug("GET REST API call {} failed. Return status code {}".format(disk_href,
+                                                                            response.status_code))
+            return None
+        try:
+            lxmlroot_respond = lxmlElementTree.fromstring(response.content)
+            namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
+            namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
+
+            for item in lxmlroot_respond.iterfind('xmlns:Item',namespaces):
+                if item.find("rasd:Description",namespaces).text == "Hard disk":
+                    disk_item = item.find("rasd:HostResource" ,namespaces )
+                    if disk_item is not None:
+                        disk_item.attrib["{"+namespaces['xmlns']+"}capacity"] = str(disk_size)
+                        break
+
+            data = lxmlElementTree.tostring(lxmlroot_respond, encoding='utf8', method='xml',
+                                             xml_declaration=True)
+
+            #Send PUT request to modify disk size
+            headers = vca.vcloud_session.get_vcloud_headers()
+            headers['Content-Type'] = 'application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1'
+
+            response = Http.put(url=disk_href,
+                                data=data,
+                                headers=headers,
+                                verify=vca.verify, logger=self.logger)
+
+            if response.status_code != 202:
+                self.logger.debug("PUT REST API call {} failed. Return status code {}".format(disk_href,
+                                                                            response.status_code))
+            else:
+                modify_disk_task = taskType.parseString(response.content, True)
+                if type(modify_disk_task) is GenericTask:
+                    status = vca.block_until_completed(modify_disk_task)
+                    return status
+
+            return None
+
+        except Exception as exp :
+                self.logger.info("Error occurred calling rest api for modifing disk size {}".format(exp))
+                return None
+
+    def add_pci_devices(self, vapp_uuid , pci_devices , vmname_andid):
+        """
+            Method to attach pci devices to VM
+
+             Args:
+                vapp_uuid - uuid of vApp/VM
+                pci_devices - pci devices infromation as specified in VNFD (flavor)
+
+            Returns:
+                The status of add pci device task , vm object and
+                vcenter_conect object
+        """
+        vm_obj = None
+        vcenter_conect = None
+        self.logger.info("Add pci devices {} into vApp {}".format(pci_devices , vapp_uuid))
+        try:
+            vm_vcenter_info = self.get_vm_vcenter_info(vapp_uuid)
+        except Exception as exp:
+            self.logger.error("Error occurred while getting vCenter infromationn"\
+                             " for VM : {}".format(exp))
+            raise vimconn.vimconnException(message=exp)
+
+        if vm_vcenter_info["vm_moref_id"]:
+            context = None
+            if hasattr(ssl, '_create_unverified_context'):
+                context = ssl._create_unverified_context()
+            try:
+                no_of_pci_devices = len(pci_devices)
+                if no_of_pci_devices > 0:
+                    vcenter_conect = SmartConnect(
+                                            host=vm_vcenter_info["vm_vcenter_ip"],
+                                            user=vm_vcenter_info["vm_vcenter_user"],
+                                            pwd=vm_vcenter_info["vm_vcenter_password"],
+                                            port=int(vm_vcenter_info["vm_vcenter_port"]),
+                                            sslContext=context)
+                    atexit.register(Disconnect, vcenter_conect)
+                    content = vcenter_conect.RetrieveContent()
+
+                    #Get VM and its host
+                    host_obj, vm_obj = self.get_vm_obj(content ,vm_vcenter_info["vm_moref_id"])
+                    self.logger.info("VM {} is currently on host {}".format(vm_obj, host_obj))
+                    if host_obj and vm_obj:
+                        #get PCI devies from host on which vapp is currently installed
+                        avilable_pci_devices = self.get_pci_devices(host_obj, no_of_pci_devices)
+
+                        if avilable_pci_devices is None:
+                            #find other hosts with active pci devices
+                            new_host_obj , avilable_pci_devices = self.get_host_and_PCIdevices(
+                                                                content,
+                                                                no_of_pci_devices
+                                                                )
+
+                            if new_host_obj is not None and avilable_pci_devices is not None and len(avilable_pci_devices)> 0:
+                                #Migrate vm to the host where PCI devices are availble
+                                self.logger.info("Relocate VM {} on new host {}".format(vm_obj, new_host_obj))
+                                task = self.relocate_vm(new_host_obj, vm_obj)
+                                if task is not None:
+                                    result = self.wait_for_vcenter_task(task, vcenter_conect)
+                                    self.logger.info("Migrate VM status: {}".format(result))
+                                    host_obj = new_host_obj
+                                else:
+                                    self.logger.info("Fail to migrate VM : {}".format(result))
+                                    raise vimconn.vimconnNotFoundException(
+                                    "Fail to migrate VM : {} to host {}".format(
+                                                    vmname_andid,
+                                                    new_host_obj)
+                                        )
+
+                        if host_obj is not None and avilable_pci_devices is not None and len(avilable_pci_devices)> 0:
+                            #Add PCI devices one by one
+                            for pci_device in avilable_pci_devices:
+                                task = self.add_pci_to_vm(host_obj, vm_obj, pci_device)
+                                if task:
+                                    status= self.wait_for_vcenter_task(task, vcenter_conect)
+                                    if status:
+                                        self.logger.info("Added PCI device {} to VM {}".format(pci_device,str(vm_obj)))
+                                else:
+                                    self.logger.error("Fail to add PCI device {} to VM {}".format(pci_device,str(vm_obj)))
+                            return True, vm_obj, vcenter_conect
+                        else:
+                            self.logger.error("Currently there is no host with"\
+                                              " {} number of avaialble PCI devices required for VM {}".format(
+                                                                            no_of_pci_devices,
+                                                                            vmname_andid)
+                                              )
+                            raise vimconn.vimconnNotFoundException(
+                                    "Currently there is no host with {} "\
+                                    "number of avaialble PCI devices required for VM {}".format(
+                                                                            no_of_pci_devices,
+                                                                            vmname_andid))
+                else:
+                    self.logger.debug("No infromation about PCI devices {} ",pci_devices)
+
+            except vmodl.MethodFault as error:
+                self.logger.error("Error occurred while adding PCI devices {} ",error)
+        return None, vm_obj, vcenter_conect
+
+    def get_vm_obj(self, content, mob_id):
+        """
+            Method to get the vsphere VM object associated with a given morf ID
+             Args:
+                vapp_uuid - uuid of vApp/VM
+                content - vCenter content object
+                mob_id - mob_id of VM
+
+            Returns:
+                    VM and host object
+        """
+        vm_obj = None
+        host_obj = None
+        try :
+            container = content.viewManager.CreateContainerView(content.rootFolder,
+                                                        [vim.VirtualMachine], True
+                                                        )
+            for vm in container.view:
+                mobID = vm._GetMoId()
+                if mobID == mob_id:
+                    vm_obj = vm
+                    host_obj = vm_obj.runtime.host
+                    break
+        except Exception as exp:
+            self.logger.error("Error occurred while finding VM object : {}".format(exp))
+        return host_obj, vm_obj
+
+    def get_pci_devices(self, host, need_devices):
+        """
+            Method to get the details of pci devices on given host
+             Args:
+                host - vSphere host object
+                need_devices - number of pci devices needed on host
+
+             Returns:
+                array of pci devices
+        """
+        all_devices = []
+        all_device_ids = []
+        used_devices_ids = []
+
+        try:
+            if host:
+                pciPassthruInfo = host.config.pciPassthruInfo
+                pciDevies = host.hardware.pciDevice
+
+            for pci_status in pciPassthruInfo:
+                if pci_status.passthruActive:
+                    for device in pciDevies:
+                        if device.id == pci_status.id:
+                            all_device_ids.append(device.id)
+                            all_devices.append(device)
+
+            #check if devices are in use
+            avalible_devices = all_devices
+            for vm in host.vm:
+                if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
+                    vm_devices = vm.config.hardware.device
+                    for device in vm_devices:
+                        if type(device) is vim.vm.device.VirtualPCIPassthrough:
+                            if device.backing.id in all_device_ids:
+                                for use_device in avalible_devices:
+                                    if use_device.id == device.backing.id:
+                                        avalible_devices.remove(use_device)
+                                used_devices_ids.append(device.backing.id)
+                                self.logger.debug("Device {} from devices {}"\
+                                        "is in use".format(device.backing.id,
+                                                           device)
+                                            )
+            if len(avalible_devices) < need_devices:
+                self.logger.debug("Host {} don't have {} number of active devices".format(host,
+                                                                            need_devices))
+                self.logger.debug("found only {} devives {}".format(len(avalible_devices),
+                                                                    avalible_devices))
+                return None
+            else:
+                required_devices = avalible_devices[:need_devices]
+                self.logger.info("Found {} PCI devivces on host {} but required only {}".format(
+                                                            len(avalible_devices),
+                                                            host,
+                                                            need_devices))
+                self.logger.info("Retruning {} devices as {}".format(need_devices,
+                                                                required_devices ))
+                return required_devices
+
+        except Exception as exp:
+            self.logger.error("Error {} occurred while finding pci devices on host: {}".format(exp, host))
+
+        return None
+
+    def get_host_and_PCIdevices(self, content, need_devices):
+        """
+         Method to get the details of pci devices infromation on all hosts
+
+            Args:
+                content - vSphere host object
+                need_devices - number of pci devices needed on host
+
+            Returns:
+                 array of pci devices and host object
+        """
+        host_obj = None
+        pci_device_objs = None
+        try:
+            if content:
+                container = content.viewManager.CreateContainerView(content.rootFolder,
+                                                            [vim.HostSystem], True)
+                for host in container.view:
+                    devices = self.get_pci_devices(host, need_devices)
+                    if devices:
+                        host_obj = host
+                        pci_device_objs = devices
+                        break
+        except Exception as exp:
+            self.logger.error("Error {} occurred while finding pci devices on host: {}".format(exp, host_obj))
+
+        return host_obj,pci_device_objs
+
+    def relocate_vm(self, dest_host, vm) :
+        """
+         Method to get the relocate VM to new host
+
+            Args:
+                dest_host - vSphere host object
+                vm - vSphere VM object
+
+            Returns:
+                task object
+        """
+        task = None
+        try:
+            relocate_spec = vim.vm.RelocateSpec(host=dest_host)
+            task = vm.Relocate(relocate_spec)
+            self.logger.info("Migrating {} to destination host {}".format(vm, dest_host))
+        except Exception as exp:
+            self.logger.error("Error occurred while relocate VM {} to new host {}: {}".format(
+                                                                            dest_host, vm, exp))
+        return task
+
+    def wait_for_vcenter_task(self, task, actionName='job', hideResult=False):
+        """
+        Waits and provides updates on a vSphere task
+        """
+        while task.info.state == vim.TaskInfo.State.running:
+            time.sleep(2)
+
+        if task.info.state == vim.TaskInfo.State.success:
+            if task.info.result is not None and not hideResult:
+                self.logger.info('{} completed successfully, result: {}'.format(
+                                                            actionName,
+                                                            task.info.result))
+            else:
+                self.logger.info('Task {} completed successfully.'.format(actionName))
+        else:
+            self.logger.error('{} did not complete successfully: {} '.format(
+                                                            actionName,
+                                                            task.info.error)
+                              )
+
+        return task.info.result
+
+    def add_pci_to_vm(self,host_object, vm_object, host_pci_dev):
+        """
+         Method to add pci device in given VM
+
+            Args:
+                host_object - vSphere host object
+                vm_object - vSphere VM object
+                host_pci_dev -  host_pci_dev must be one of the devices from the
+                                host_object.hardware.pciDevice list
+                                which is configured as a PCI passthrough device
+
+            Returns:
+                task object
+        """
+        task = None
+        if vm_object and host_object and host_pci_dev:
+            try :
+                #Add PCI device to VM
+                pci_passthroughs = vm_object.environmentBrowser.QueryConfigTarget(host=None).pciPassthrough
+                systemid_by_pciid = {item.pciDevice.id: item.systemId for item in pci_passthroughs}
+
+                if host_pci_dev.id not in systemid_by_pciid:
+                    self.logger.error("Device {} is not a passthrough device ".format(host_pci_dev))
+                    return None
+
+                deviceId = hex(host_pci_dev.deviceId % 2**16).lstrip('0x')
+                backing = vim.VirtualPCIPassthroughDeviceBackingInfo(deviceId=deviceId,
+                                            id=host_pci_dev.id,
+                                            systemId=systemid_by_pciid[host_pci_dev.id],
+                                            vendorId=host_pci_dev.vendorId,
+                                            deviceName=host_pci_dev.deviceName)
+
+                hba_object = vim.VirtualPCIPassthrough(key=-100, backing=backing)
+
+                new_device_config = vim.VirtualDeviceConfigSpec(device=hba_object)
+                new_device_config.operation = "add"
+                vmConfigSpec = vim.vm.ConfigSpec()
+                vmConfigSpec.deviceChange = [new_device_config]
+
+                task = vm_object.ReconfigVM_Task(spec=vmConfigSpec)
+                self.logger.info("Adding PCI device {} into VM {} from host {} ".format(
+                                                            host_pci_dev, vm_object, host_object)
+                                )
+            except Exception as exp:
+                self.logger.error("Error occurred while adding pci devive {} to VM {}: {}".format(
+                                                                            host_pci_dev,
+                                                                            vm_object,
+                                                                             exp))
+        return task
+
+    def get_vm_vcenter_info(self , vapp_uuid):
+        """
+        Method to get details of vCenter and vm
+
+            Args:
+                vapp_uuid - uuid of vApp or VM
+
+            Returns:
+                Moref Id of VM and deails of vCenter
+        """
+        vm_vcenter_info = {}
+
+        if self.vcenter_ip is not None:
+            vm_vcenter_info["vm_vcenter_ip"] = self.vcenter_ip
+        else:
+            raise vimconn.vimconnException(message="vCenter IP is not provided."\
+                                           " Please provide vCenter IP while attaching datacenter to tenant in --config")
+        if self.vcenter_port is not None:
+            vm_vcenter_info["vm_vcenter_port"] = self.vcenter_port
+        else:
+            raise vimconn.vimconnException(message="vCenter port is not provided."\
+                                           " Please provide vCenter port while attaching datacenter to tenant in --config")
+        if self.vcenter_user is not None:
+            vm_vcenter_info["vm_vcenter_user"] = self.vcenter_user
+        else:
+            raise vimconn.vimconnException(message="vCenter user is not provided."\
+                                           " Please provide vCenter user while attaching datacenter to tenant in --config")
+
+        if self.vcenter_password is not None:
+            vm_vcenter_info["vm_vcenter_password"] = self.vcenter_password
+        else:
+            raise vimconn.vimconnException(message="vCenter user password is not provided."\
+                                           " Please provide vCenter user password while attaching datacenter to tenant in --config")
+        try:
+            vm_details = self.get_vapp_details_rest(vapp_uuid, need_admin_access=True)
+            if vm_details and "vm_vcenter_info" in vm_details:
+                vm_vcenter_info["vm_moref_id"] = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
+
+            return vm_vcenter_info
+
+        except Exception as exp:
+            self.logger.error("Error occurred while getting vCenter infromationn"\
+                             " for VM : {}".format(exp))
+
+
+    def get_vm_pci_details(self, vmuuid):
+        """
+            Method to get VM PCI device details from vCenter
+
+            Args:
+                vm_obj - vSphere VM object
+
+            Returns:
+                dict of PCI devives attached to VM
+
+        """
+        vm_pci_devices_info = {}
+        try:
+            vm_vcenter_info = self.get_vm_vcenter_info(vmuuid)
+            if vm_vcenter_info["vm_moref_id"]:
+                context = None
+                if hasattr(ssl, '_create_unverified_context'):
+                    context = ssl._create_unverified_context()
+                vcenter_conect = SmartConnect(host=vm_vcenter_info["vm_vcenter_ip"],
+                                        user=vm_vcenter_info["vm_vcenter_user"],
+                                        pwd=vm_vcenter_info["vm_vcenter_password"],
+                                        port=int(vm_vcenter_info["vm_vcenter_port"]),
+                                        sslContext=context
+                                    )
+                atexit.register(Disconnect, vcenter_conect)
+                content = vcenter_conect.RetrieveContent()
+
+                #Get VM and its host
+                if content:
+                    host_obj, vm_obj = self.get_vm_obj(content ,vm_vcenter_info["vm_moref_id"])
+                    if host_obj and vm_obj:
+                        vm_pci_devices_info["host_name"]= host_obj.name
+                        vm_pci_devices_info["host_ip"]= host_obj.config.network.vnic[0].spec.ip.ipAddress
+                        for device in vm_obj.config.hardware.device:
+                            if type(device) == vim.vm.device.VirtualPCIPassthrough:
+                                device_details={'devide_id':device.backing.id,
+                                                'pciSlotNumber':device.slotInfo.pciSlotNumber,
+                                            }
+                                vm_pci_devices_info[device.deviceInfo.label] = device_details
+                else:
+                    self.logger.error("Can not connect to vCenter while getting "\
+                                          "PCI devices infromationn")
+                return vm_pci_devices_info
+        except Exception as exp:
+            self.logger.error("Error occurred while getting VM infromationn"\
+                             " for VM : {}".format(exp))
+            raise vimconn.vimconnException(message=exp)
+
diff --git a/osm_ro/vmwarecli.py b/osm_ro/vmwarecli.py
new file mode 100755 (executable)
index 0000000..4583a65
--- /dev/null
@@ -0,0 +1,819 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##
+# This file is standalone vmware vcloud director util
+# 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: mbayramov@vmware.com
+##
+
+"""
+
+Standalone application that leverage openmano vmware connector work with vCloud director rest api.
+
+ - Provides capability to create and delete VDC for specific organization.
+ - Create, delete and manage network for specific VDC
+ - List deployed VM's , VAPPs, VDSs, Organization
+ - View detail information about VM / Vapp , Organization etc
+ - Operate with images upload / boot / power on etc
+
+ Usage example.
+
+ List organization created in vCloud director
+  vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list org
+
+ List VDC for particular organization
+  vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list vdc
+
+ Upload image
+  python vmwarerecli.py image upload /Users/spyroot/Developer/Openmano/Ro/vnfs/cirros/cirros.ovf
+
+ Boot Image
+    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF image boot cirros cirros
+
+ View vApp
+    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF view vapp 90bd2b4e-f782-46cf-b5e2-c3817dcf6633 -u
+
+ List VMS
+    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vms
+
+ List VDC in OSM format
+  python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vdc -o
+
+Mustaafa Bayramov
+mbayramov@vmware.com
+"""
+import os
+import argparse
+import traceback
+import uuid
+
+from xml.etree import ElementTree as ET
+
+import sys
+from pyvcloud import Http
+
+import logging
+import vimconn
+import time
+import uuid
+import urllib3
+import requests
+
+from vimconn_vmware import vimconnector
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
+from prettytable import PrettyTable
+
+requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+
+__author__ = "Mustafa Bayramov"
+__date__ = "$16-Sep-2016 11:09:29$"
+
+
+# TODO move to main vim
+def delete_network_action(vca=None, network_uuid=None):
+    """
+    Method leverages vCloud director and query network based on network uuid
+
+    Args:
+        vca - is active VCA connection.
+        network_uuid - is a network uuid
+
+        Returns:
+            The return XML respond
+    """
+
+    if vca is None or network_uuid is None:
+        return None
+
+    url_list = [vca.host, '/api/admin/network/', network_uuid]
+    vm_list_rest_call = ''.join(url_list)
+
+    if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+        response = Http.get(url=vm_list_rest_call,
+                            headers=vca.vcloud_session.get_vcloud_headers(),
+                            verify=vca.verify,
+                            logger=vca.logger)
+        if response.status_code == requests.codes.ok:
+            print response.content
+            return response.content
+
+    return None
+
+
+def print_vapp(vapp_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        vapp_dict: container vapp object.
+
+        Returns:
+            The return nothing
+    """
+
+    # following key available to print
+    # {'status': 'POWERED_OFF', 'storageProfileName': '*', 'hardwareVersion': '7', 'vmToolsVersion': '0',
+    #  'memoryMB': '384',
+    #  'href': 'https://172.16.254.206/api/vAppTemplate/vm-129e22e8-08dc-4cb6-8358-25f635e65d3b',
+    #  'isBusy': 'false', 'isDeployed': 'false', 'isInMaintenanceMode': 'false', 'isVAppTemplate': 'true',
+    #  'networkName': 'nat', 'isDeleted': 'false', 'catalogName': 'Cirros',
+    #  'containerName': 'Cirros Template', #  'container':
+    #  'https://172.16.254.206/api/vAppTemplate/vappTemplate-b966453d-c361-4505-9e38-ccef45815e5d',
+    #  'name': 'Cirros', 'pvdcHighestSupportedHardwareVersion': '11', 'isPublished': 'false',
+    #  'numberOfCpus': '1', 'vdc': 'https://172.16.254.206/api/vdc/a5056f85-418c-4bfd-8041-adb0f48be9d9',
+    #  'guestOs': 'Other (32-bit)', 'isVdcEnabled': 'true'}
+
+    if vapp_dict is None:
+        return
+
+    vm_table = PrettyTable(['vm   uuid',
+                            'vapp name',
+                            'vapp uuid',
+                            'network name',
+                            'storage name',
+                            'vcpu', 'memory', 'hw ver','deployed','status'])
+    for k in vapp_dict:
+        entry = []
+        entry.append(k)
+        entry.append(vapp_dict[k]['containerName'])
+        # vm-b1f5cd4c-2239-4c89-8fdc-a41ff18e0d61
+        entry.append(vapp_dict[k]['container'].split('/')[-1:][0][5:])
+        entry.append(vapp_dict[k]['networkName'])
+        entry.append(vapp_dict[k]['storageProfileName'])
+        entry.append(vapp_dict[k]['numberOfCpus'])
+        entry.append(vapp_dict[k]['memoryMB'])
+        entry.append(vapp_dict[k]['pvdcHighestSupportedHardwareVersion'])
+        entry.append(vapp_dict[k]['isDeployed'])
+        entry.append(vapp_dict[k]['status'])
+
+        vm_table.add_row(entry)
+
+    print vm_table
+
+
+def print_org(org_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        org_dict:  dictionary of organization where key is org uuid.
+
+        Returns:
+            The return nothing
+    """
+
+    if org_dict is None:
+        return
+
+    org_table = PrettyTable(['org uuid', 'name'])
+    for k in org_dict:
+        entry = [k, org_dict[k]]
+        org_table.add_row(entry)
+
+    print org_table
+
+
+def print_vm_list(vm_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        vm_dict:  dictionary of organization where key is org uuid.
+
+        Returns:
+            The return nothing
+    """
+    if vm_dict is None:
+        return
+
+    vm_table = PrettyTable(
+        ['vm uuid', 'vm name', 'vapp uuid', 'vdc uuid', 'network name', 'is deployed', 'vcpu', 'memory', 'status'])
+
+    try:
+        for k in vm_dict:
+            entry = []
+            entry.append(k)
+            entry.append(vm_dict[k]['name'])
+            entry.append(vm_dict[k]['container'].split('/')[-1:][0][5:])
+            entry.append(vm_dict[k]['vdc'].split('/')[-1:][0])
+            entry.append(vm_dict[k]['networkName'])
+            entry.append(vm_dict[k]['isDeployed'])
+            entry.append(vm_dict[k]['numberOfCpus'])
+            entry.append(vm_dict[k]['memoryMB'])
+            entry.append(vm_dict[k]['status'])
+            vm_table.add_row(entry)
+        print vm_table
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        pass
+
+
+def print_vdc_list(org_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        org_dict:  dictionary of organization where key is org uuid.
+
+        Returns:
+            The return nothing
+    """
+    if org_dict is None:
+        return
+    try:
+        vdcs_dict = {}
+        if org_dict.has_key('vdcs'):
+            vdcs_dict = org_dict['vdcs']
+        vdc_table = PrettyTable(['vdc uuid', 'vdc name'])
+        for k in vdcs_dict:
+            entry = [k, vdcs_dict[k]]
+            vdc_table.add_row(entry)
+
+        print vdc_table
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def print_network_list(org_dict=None):
+    """ Method print network list.
+
+    Args:
+        org_dict:   dictionary of organization that contain key networks with a list of all
+                    network for for specific VDC
+
+        Returns:
+            The return nothing
+    """
+    if org_dict is None:
+        return
+    try:
+        network_dict = {}
+        if org_dict.has_key('networks'):
+            network_dict = org_dict['networks']
+        network_table = PrettyTable(['network uuid', 'network name'])
+        for k in network_dict:
+            entry = [k, network_dict[k]]
+            network_table.add_row(entry)
+
+        print network_table
+
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def print_org_details(org_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        org_dict:  dictionary of organization where key is org uuid.
+
+        Returns:
+            The return nothing
+    """
+    if org_dict is None:
+        return
+    try:
+        catalogs_dict = {}
+
+        print_vdc_list(org_dict=org_dict)
+        print_network_list(org_dict=org_dict)
+
+        if org_dict.has_key('catalogs'):
+            catalogs_dict = org_dict['catalogs']
+
+        catalog_table = PrettyTable(['catalog uuid', 'catalog name'])
+        for k in catalogs_dict:
+            entry = [k, catalogs_dict[k]]
+            catalog_table.add_row(entry)
+
+        print catalog_table
+
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def delete_actions(vim=None, action=None, namespace=None):
+    if action == 'network' or namespace.action == 'network':
+        logger.debug("Requesting delete for network {}".format(namespace.network_name))
+        network_uuid = namespace.network_name
+        # if request name based we need find UUID
+        # TODO optimize it or move to external function
+        if not namespace.uuid:
+            org_dict = vim.get_org_list()
+            for org in org_dict:
+                org_net = vim.get_org(org)['networks']
+                for network in org_net:
+                    if org_net[network] == namespace.network_name:
+                        network_uuid = network
+
+        vim.delete_network_action(network_uuid=network_uuid)
+
+
+def list_actions(vim=None, action=None, namespace=None):
+    """ Method provide list object from VDC action
+
+       Args:
+           vim - is vcloud director vim connector.
+           action - is action for list ( vdc / org etc)
+           namespace -  must contain VDC / Org information.
+
+           Returns:
+               The return nothing
+       """
+
+    org_id = None
+    myorgs = vim.get_org_list()
+    for org in myorgs:
+        if myorgs[org] == namespace.vcdorg:
+            org_id = org
+        break
+    else:
+        print(" Invalid organization.")
+        return
+
+    if action == 'vms' or namespace.action == 'vms':
+        vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
+        print_vm_list(vm_dict=vm_dict)
+    elif action == 'vapps' or namespace.action == 'vapps':
+        vapp_dict = vim.get_vapp_list(vdc_name=namespace.vcdvdc)
+        print_vapp(vapp_dict=vapp_dict)
+    elif action == 'networks' or namespace.action == 'networks':
+        if namespace.osm:
+            osm_print(vim.get_network_list(filter_dict={}))
+        else:
+            print_network_list(vim.get_org(org_uuid=org_id))
+    elif action == 'vdc' or namespace.action == 'vdc':
+        if namespace.osm:
+            osm_print(vim.get_tenant_list(filter_dict=None))
+        else:
+            print_vdc_list(vim.get_org(org_uuid=org_id))
+    elif action == 'org' or namespace.action == 'org':
+        print_org(org_dict=vim.get_org_list())
+    else:
+        return None
+
+
+def print_network_details(network_dict=None):
+    try:
+        network_table = PrettyTable(network_dict.keys())
+        entry = [network_dict.values()]
+        network_table.add_row(entry[0])
+        print network_table
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def osm_print(generic_dict=None):
+
+    try:
+        for element in generic_dict:
+            table = PrettyTable(element.keys())
+            entry = [element.values()]
+            table.add_row(entry[0])
+        print table
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def view_actions(vim=None, action=None, namespace=None):
+    org_id = None
+    orgs = vim.get_org_list()
+    for org in orgs:
+        if orgs[org] == namespace.vcdorg:
+            org_id = org
+        break
+    else:
+        print(" Invalid organization.")
+        return
+
+    myorg = vim.get_org(org_uuid=org_id)
+
+    # view org
+    if action == 'org' or namespace.action == 'org':
+        org_id = None
+        orgs = vim.get_org_list()
+        if namespace.uuid:
+            if namespace.org_name in orgs:
+                org_id = namespace.org_name
+        else:
+            # we need find UUID based on name provided
+            for org in orgs:
+                if orgs[org] == namespace.org_name:
+                    org_id = org
+                    break
+
+        logger.debug("Requesting view for orgs {}".format(org_id))
+        print_org_details(vim.get_org(org_uuid=org_id))
+
+    # view vapp action
+    if action == 'vapp' or namespace.action == 'vapp':
+        if namespace.vapp_name is not None and namespace.uuid:
+            logger.debug("Requesting vapp {} for vdc {}".format(namespace.vapp_name, namespace.vcdvdc))
+            vapp_dict = {}
+            vapp_uuid = namespace.vapp_name
+            # if request based on just name we need get UUID
+            if not namespace.uuid:
+                vapp_uuid = vim.get_vappid(vdc=namespace.vcdvdc, vapp_name=namespace.vapp_name)
+                if vapp_uuid is None:
+                    print("Can't find vapp by given name {}".format(namespace.vapp_name))
+                    return
+
+            print " namespace {}".format(namespace)
+            if vapp_dict is not None and namespace.osm:
+                vm_info_dict = vim.get_vminstance(vim_vm_uuid=vapp_uuid)
+                print vm_info_dict
+            if vapp_dict is not None and namespace.osm != True:
+                vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vapp_uuid, isuuid=True)
+                print_vapp(vapp_dict=vapp_dict)
+
+    # view network
+    if action == 'network' or namespace.action == 'network':
+        logger.debug("Requesting view for network {}".format(namespace.network_name))
+        network_uuid = namespace.network_name
+        # if request name based we need find UUID
+        # TODO optimize it or move to external function
+        if not namespace.uuid:
+            if not myorg.has_key('networks'):
+                print("Network {} is undefined in vcloud director for org {} vdc {}".format(namespace.network_name,
+                                                                                            vim.name,
+                                                                                            vim.tenant_name))
+                return
+
+            my_org_net = myorg['networks']
+            for network in my_org_net:
+                if my_org_net[network] == namespace.network_name:
+                    network_uuid = network
+                    break
+
+        print print_network_details(network_dict=vim.get_vcd_network(network_uuid=network_uuid))
+
+
+def create_actions(vim=None, action=None, namespace=None):
+    """Method gets provider vdc view from vcloud director
+
+        Args:
+            vim - is Cloud director vim connector
+            action - action for create ( network / vdc etc)
+
+        Returns:
+            The return xml content of respond or None
+    """
+    if action == 'network' or namespace.action == 'network':
+        logger.debug("Creating a network in vcloud director".format(namespace.network_name))
+        network_uuid = vim.create_network(namespace.network_name)
+        if network_uuid is not None:
+            print ("Crated new network {} and uuid: {}".format(namespace.network_name, network_uuid))
+        else:
+            print ("Failed create a new network {}".format(namespace.network_name))
+    elif action == 'vdc' or namespace.action == 'vdc':
+        logger.debug("Creating a new vdc in vcloud director.".format(namespace.vdc_name))
+        vdc_uuid = vim.create_vdc(namespace.vdc_name)
+        if vdc_uuid is not None:
+            print ("Crated new vdc {} and uuid: {}".format(namespace.vdc_name, vdc_uuid))
+        else:
+            print ("Failed create a new vdc {}".format(namespace.vdc_name))
+    else:
+        return None
+
+
+def validate_uuid4(uuid_string):
+    """Function validate that string contain valid uuid4
+
+        Args:
+            uuid_string - valid UUID string
+
+        Returns:
+            The return true if string contain valid UUID format
+    """
+    try:
+        val = uuid.UUID(uuid_string, version=4)
+    except ValueError:
+        return False
+    return True
+
+
+def upload_image(vim=None, image_file=None):
+    """Function upload image to vcloud director
+
+        Args:
+            image_file - valid UUID string
+
+        Returns:
+            The return true if image uploaded correctly
+    """
+    try:
+        catalog_uuid = vim.get_image_id_from_path(path=image_file, progress=True)
+        if catalog_uuid is not None and validate_uuid4(catalog_uuid):
+            print("Image uploaded and uuid {}".format(catalog_uuid))
+            return True
+    except vimconn.vimconnException as upload_exception:
+        print("Failed uploaded {} image".format(image_file))
+        print("Error Reason: {}".format(upload_exception.message))
+    return False
+
+
+def boot_image(vim=None, image_name=None, vm_name=None):
+    """ Function boot image that resided in vcloud director.
+        The image name can be UUID of name.
+
+        Args:
+            vim - vim connector
+            image_name - image identified by UUID or text string.
+            vm_name - vmname
+
+
+         Returns:
+             The return true if image uploaded correctly
+     """
+
+    vim_catalog = None
+    try:
+        catalogs = vim.vca.get_catalogs()
+        if not validate_uuid4(image_name):
+            vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
+            if vim_catalog is None:
+                return None
+        else:
+            vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
+            if vim_catalog is None:
+                return None
+
+        print (" Booting {} image id {} ".format(vm_name, vim_catalog))
+        vm_uuid = vim.new_vminstance(name=vm_name, image_id=vim_catalog)
+        if vm_uuid is not None and validate_uuid4(vm_uuid):
+            print("Image booted and vm uuid {}".format(vm_uuid))
+            vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vm_uuid, isuuid=True)
+            if vapp_dict is not None:
+                print_vapp(vapp_dict=vapp_dict)
+        return True
+    except vimconn.vimconnNotFoundException as notFound:
+        print("Failed boot {} image".format(image_name))
+        print(notFound.message)
+    except vimconn.vimconnException as vimconError:
+        print("Failed boot {} image".format(image_name))
+        print(vimconError.message)
+    except:
+        print("Failed boot {} image".format(image_name))
+
+
+        return False
+
+
+def image_action(vim=None, action=None, namespace=None):
+    """ Function present set of action to manipulate with image.
+          - upload image
+          - boot image.
+          - delete image ( not yet done )
+
+        Args:
+             vim - vcloud director connector
+             action - string (upload/boot etc)
+             namespace - contain other attributes image name etc
+
+         Returns:
+             The return nothing
+     """
+
+    if action == 'upload' or namespace.action == 'upload':
+        upload_image(vim=vim, image_file=namespace.image)
+    elif action == 'boot' or namespace.action == 'boot':
+        boot_image(vim=vim, image_name=namespace.image, vm_name=namespace.vmname)
+    else:
+        return None
+
+
+def vmwarecli(command=None, action=None, namespace=None):
+    logger.debug("Namespace {}".format(namespace))
+    urllib3.disable_warnings()
+
+    vcduser = None
+    vcdpasword = None
+    vcdhost = None
+    vcdorg = None
+
+    if hasattr(__builtins__, 'raw_input'):
+        input = raw_input
+
+    if namespace.vcdvdc is None:
+        while True:
+            vcduser = input("Enter vcd username: ")
+            if vcduser is not None and len(vcduser) > 0:
+                break
+    else:
+        vcduser = namespace.vcduser
+
+    if namespace.vcdpassword is None:
+        while True:
+            vcdpasword = input("Please enter vcd password: ")
+            if vcdpasword is not None and len(vcdpasword) > 0:
+                break
+    else:
+        vcdpasword = namespace.vcdpassword
+
+    if namespace.vcdhost is None:
+        while True:
+            vcdhost = input("Please enter vcd host name or ip: ")
+            if vcdhost is not None and len(vcdhost) > 0:
+                break
+    else:
+        vcdhost = namespace.vcdhost
+
+    if namespace.vcdorg is None:
+        while True:
+            vcdorg = input("Please enter vcd organization name: ")
+            if vcdorg is not None and len(vcdorg) > 0:
+                break
+    else:
+        vcdorg = namespace.vcdorg
+
+    try:
+        vim = vimconnector(uuid=None,
+                           name=vcdorg,
+                           tenant_id=None,
+                           tenant_name=namespace.vcdvdc,
+                           url=vcdhost,
+                           url_admin=vcdhost,
+                           user=vcduser,
+                           passwd=vcdpasword,
+                           log_level="DEBUG",
+                           config={'admin_username': namespace.vcdamdin, 'admin_password': namespace.vcdadminpassword})
+        vim.vca = vim.connect()
+
+    except vimconn.vimconnConnectionException:
+        print("Failed connect to vcloud director. Please check credential and hostname.")
+        return
+
+    # list
+    if command == 'list' or namespace.command == 'list':
+        logger.debug("Client requested list action")
+        # route request to list actions
+        list_actions(vim=vim, action=action, namespace=namespace)
+
+    # view action
+    if command == 'view' or namespace.command == 'view':
+        logger.debug("Client requested view action")
+        view_actions(vim=vim, action=action, namespace=namespace)
+
+    # delete action
+    if command == 'delete' or namespace.command == 'delete':
+        logger.debug("Client requested delete action")
+        delete_actions(vim=vim, action=action, namespace=namespace)
+
+    # create action
+    if command == 'create' or namespace.command == 'create':
+        logger.debug("Client requested create action")
+        create_actions(vim=vim, action=action, namespace=namespace)
+
+    # image action
+    if command == 'image' or namespace.command == 'image':
+        logger.debug("Client requested create action")
+        image_action(vim=vim, action=action, namespace=namespace)
+
+
+if __name__ == '__main__':
+    defaults = {'vcdvdc': 'default',
+                'vcduser': 'admin',
+                'vcdpassword': 'admin',
+                'vcdhost': 'https://localhost',
+                'vcdorg': 'default',
+                'debug': 'INFO'}
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-u', '--vcduser', help='vcloud director username', type=str)
+    parser.add_argument('-p', '--vcdpassword', help='vcloud director password', type=str)
+    parser.add_argument('-U', '--vcdamdin', help='vcloud director password', type=str)
+    parser.add_argument('-P', '--vcdadminpassword', help='vcloud director password', type=str)
+    parser.add_argument('-c', '--vcdhost', help='vcloud director host', type=str)
+    parser.add_argument('-o', '--vcdorg', help='vcloud director org', type=str)
+    parser.add_argument('-v', '--vcdvdc', help='vcloud director vdc', type=str)
+    parser.add_argument('-d', '--debug', help='debug level', type=int)
+
+    parser_subparsers = parser.add_subparsers(help='commands', dest='command')
+    sub = parser_subparsers.add_parser('list', help='List objects (VMs, vApps, networks)')
+    sub_subparsers = sub.add_subparsers(dest='action')
+
+    list_vms = sub_subparsers.add_parser('vms', help='list - all vm deployed in vCloud director')
+    list_vapps = sub_subparsers.add_parser('vapps', help='list - all vapps deployed in vCloud director')
+    list_network = sub_subparsers.add_parser('networks', help='list - all networks deployed')
+    list_network.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
+
+    #list vdc
+    list_vdc = sub_subparsers.add_parser('vdc', help='list - list all vdc for organization accessible to you')
+    list_vdc.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
+
+    list_org = sub_subparsers.add_parser('org', help='list - list of organizations accessible to you.')
+
+    create_sub = parser_subparsers.add_parser('create')
+    create_sub_subparsers = create_sub.add_subparsers(dest='action')
+    create_vms = create_sub_subparsers.add_parser('vms')
+    create_vapp = create_sub_subparsers.add_parser('vapp')
+    create_vapp.add_argument('uuid')
+
+    # add network
+    create_network = create_sub_subparsers.add_parser('network')
+    create_network.add_argument('network_name', action='store', help='create a network for a vdc')
+
+    # add VDC
+    create_vdc = create_sub_subparsers.add_parser('vdc')
+    create_vdc.add_argument('vdc_name', action='store', help='create a new VDC for org')
+
+    delete_sub = parser_subparsers.add_parser('delete')
+    del_sub_subparsers = delete_sub.add_subparsers(dest='action')
+    del_vms = del_sub_subparsers.add_parser('vms')
+    del_vapp = del_sub_subparsers.add_parser('vapp')
+    del_vapp.add_argument('uuid', help='view vapp based on UUID')
+
+    # delete network
+    del_network = del_sub_subparsers.add_parser('network')
+    del_network.add_argument('network_name', action='store',
+                             help='- delete network for vcloud director by provided name')
+    del_network.add_argument('-u', '--uuid', default=False, action='store_true',
+                             help='delete network for vcloud director by provided uuid')
+
+    # delete vdc
+    del_vdc = del_sub_subparsers.add_parser('vdc')
+
+    view_sub = parser_subparsers.add_parser('view')
+    view_sub_subparsers = view_sub.add_subparsers(dest='action')
+
+    view_vms_parser = view_sub_subparsers.add_parser('vms')
+    view_vms_parser.add_argument('uuid', default=False, action='store_true',
+                                 help='- View VM for specific uuid in vcloud director')
+    view_vms_parser.add_argument('name', default=False, action='store_true',
+                                 help='- View VM for specific vapp name in vcloud director')
+
+    # view vapp
+    view_vapp_parser = view_sub_subparsers.add_parser('vapp')
+    view_vapp_parser.add_argument('vapp_name', action='store',
+                                  help='- view vapp for specific vapp name in vcloud director')
+    view_vapp_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view vapp based on uuid')
+    view_vapp_parser.add_argument('-o', '--osm', default=False, action='store_true',  help='provide view in OSM format')
+
+    # view network
+    view_network = view_sub_subparsers.add_parser('network')
+    view_network.add_argument('network_name', action='store',
+                              help='- view network for specific network name in vcloud director')
+    view_network.add_argument('-u', '--uuid', default=False, action='store_true', help='view network based on uuid')
+
+    # view VDC command and actions
+    view_vdc = view_sub_subparsers.add_parser('vdc')
+    view_vdc.add_argument('vdc_name', action='store',
+                          help='- View VDC based and action based on provided vdc uuid')
+    view_vdc.add_argument('-u', '--uuid', default=False, action='store_true', help='view vdc based on uuid')
+
+    # view organization command and actions
+    view_org = view_sub_subparsers.add_parser('org')
+    view_org.add_argument('org_name', action='store',
+                          help='- View VDC based and action based on provided vdc uuid')
+    view_org.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
+
+    # upload image action
+    image_sub = parser_subparsers.add_parser('image')
+    image_subparsers = image_sub.add_subparsers(dest='action')
+    upload_parser = image_subparsers.add_parser('upload')
+    upload_parser.add_argument('image', default=False, action='store', help='- valid path to OVF image ')
+    upload_parser.add_argument('catalog', default=False, action='store_true', help='- catalog name')
+
+    # boot vm action
+    boot_parser = image_subparsers.add_parser('boot')
+    boot_parser.add_argument('image', default=False, action='store', help='- Image name')
+    boot_parser.add_argument('vmname', default=False, action='store', help='- VM name')
+    boot_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
+
+    namespace = parser.parse_args()
+    # put command_line args to mapping
+    command_line_args = {k: v for k, v in vars(namespace).items() if v}
+
+    d = defaults.copy()
+    d.update(os.environ)
+    d.update(command_line_args)
+
+    logger = logging.getLogger('mano.vim.vmware')
+    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+    ch = logging.StreamHandler()
+    ch.setLevel(str.upper(d['debug']))
+    ch.setFormatter(formatter)
+    logger.addHandler(ch)
+    logger.setLevel(getattr(logging, str.upper(d['debug'])))
+    logger.info(
+        "Connecting {} username: {} org: {} vdc: {} ".format(d['vcdhost'], d['vcduser'], d['vcdorg'], d['vcdvdc']))
+
+    logger.debug("command: \"{}\" actio: \"{}\"".format(d['command'], d['action']))
+
+    # main entry point.
+    vmwarecli(namespace=namespace)
diff --git a/osm_ro/vmwarerecli.py b/osm_ro/vmwarerecli.py
new file mode 100755 (executable)
index 0000000..acd4240
--- /dev/null
@@ -0,0 +1,818 @@
+# -*- coding: utf-8 -*-
+##
+# This file is standalone vmware vcloud director util
+# 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: mbayramov@vmware.com
+##
+
+"""
+
+Standalone application that leverage openmano vmware connector work with vCloud director rest api.
+
+ - Provides capability to create and delete VDC for specific organization.
+ - Create, delete and manage network for specific VDC
+ - List deployed VM's , VAPPs, VDSs, Organization
+ - View detail information about VM / Vapp , Organization etc
+ - Operate with images upload / boot / power on etc
+
+ Usage example.
+
+ List organization created in vCloud director
+  vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list org
+
+ List VDC for particular organization
+  vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list vdc
+
+ Upload image
+  python vmwarerecli.py image upload /Users/spyroot/Developer/Openmano/Ro/vnfs/cirros/cirros.ovf
+
+ Boot Image
+    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF image boot cirros cirros
+
+ View vApp
+    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF view vapp 90bd2b4e-f782-46cf-b5e2-c3817dcf6633 -u
+
+ List VMS
+    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vms
+
+ List VDC in OSM format
+  python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vdc -o
+
+Mustaafa Bayramov
+mbayramov@vmware.com
+"""
+import os
+import argparse
+import traceback
+import uuid
+
+from xml.etree import ElementTree as ET
+
+import sys
+from pyvcloud import Http
+
+import logging
+import vimconn
+import time
+import uuid
+import urllib3
+import requests
+
+from vimconn_vmware import vimconnector
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
+from prettytable import PrettyTable
+
+requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+
+__author__ = "Mustafa Bayramov"
+__date__ = "$16-Sep-2016 11:09:29$"
+
+
+# TODO move to main vim
+def delete_network_action(vca=None, network_uuid=None):
+    """
+    Method leverages vCloud director and query network based on network uuid
+
+    Args:
+        vca - is active VCA connection.
+        network_uuid - is a network uuid
+
+        Returns:
+            The return XML respond
+    """
+
+    if vca is None or network_uuid is None:
+        return None
+
+    url_list = [vca.host, '/api/admin/network/', network_uuid]
+    vm_list_rest_call = ''.join(url_list)
+
+    if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+        response = Http.get(url=vm_list_rest_call,
+                            headers=vca.vcloud_session.get_vcloud_headers(),
+                            verify=vca.verify,
+                            logger=vca.logger)
+        if response.status_code == requests.codes.ok:
+            print response.content
+            return response.content
+
+    return None
+
+
+def print_vapp(vapp_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        vapp_dict: container vapp object.
+
+        Returns:
+            The return nothing
+    """
+
+    # following key available to print
+    # {'status': 'POWERED_OFF', 'storageProfileName': '*', 'hardwareVersion': '7', 'vmToolsVersion': '0',
+    #  'memoryMB': '384',
+    #  'href': 'https://172.16.254.206/api/vAppTemplate/vm-129e22e8-08dc-4cb6-8358-25f635e65d3b',
+    #  'isBusy': 'false', 'isDeployed': 'false', 'isInMaintenanceMode': 'false', 'isVAppTemplate': 'true',
+    #  'networkName': 'nat', 'isDeleted': 'false', 'catalogName': 'Cirros',
+    #  'containerName': 'Cirros Template', #  'container':
+    #  'https://172.16.254.206/api/vAppTemplate/vappTemplate-b966453d-c361-4505-9e38-ccef45815e5d',
+    #  'name': 'Cirros', 'pvdcHighestSupportedHardwareVersion': '11', 'isPublished': 'false',
+    #  'numberOfCpus': '1', 'vdc': 'https://172.16.254.206/api/vdc/a5056f85-418c-4bfd-8041-adb0f48be9d9',
+    #  'guestOs': 'Other (32-bit)', 'isVdcEnabled': 'true'}
+
+    if vapp_dict is None:
+        return
+
+    vm_table = PrettyTable(['vm   uuid',
+                            'vapp name',
+                            'vapp uuid',
+                            'network name',
+                            'storage name',
+                            'vcpu', 'memory', 'hw ver','deployed','status'])
+    for k in vapp_dict:
+        entry = []
+        entry.append(k)
+        entry.append(vapp_dict[k]['containerName'])
+        # vm-b1f5cd4c-2239-4c89-8fdc-a41ff18e0d61
+        entry.append(vapp_dict[k]['container'].split('/')[-1:][0][5:])
+        entry.append(vapp_dict[k]['networkName'])
+        entry.append(vapp_dict[k]['storageProfileName'])
+        entry.append(vapp_dict[k]['numberOfCpus'])
+        entry.append(vapp_dict[k]['memoryMB'])
+        entry.append(vapp_dict[k]['pvdcHighestSupportedHardwareVersion'])
+        entry.append(vapp_dict[k]['isDeployed'])
+        entry.append(vapp_dict[k]['status'])
+
+        vm_table.add_row(entry)
+
+    print vm_table
+
+
+def print_org(org_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        org_dict:  dictionary of organization where key is org uuid.
+
+        Returns:
+            The return nothing
+    """
+
+    if org_dict is None:
+        return
+
+    org_table = PrettyTable(['org uuid', 'name'])
+    for k in org_dict:
+        entry = [k, org_dict[k]]
+        org_table.add_row(entry)
+
+    print org_table
+
+
+def print_vm_list(vm_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        vm_dict:  dictionary of organization where key is org uuid.
+
+        Returns:
+            The return nothing
+    """
+    if vm_dict is None:
+        return
+
+    vm_table = PrettyTable(
+        ['vm uuid', 'vm name', 'vapp uuid', 'vdc uuid', 'network name', 'is deployed', 'vcpu', 'memory', 'status'])
+
+    try:
+        for k in vm_dict:
+            entry = []
+            entry.append(k)
+            entry.append(vm_dict[k]['name'])
+            entry.append(vm_dict[k]['container'].split('/')[-1:][0][5:])
+            entry.append(vm_dict[k]['vdc'].split('/')[-1:][0])
+            entry.append(vm_dict[k]['networkName'])
+            entry.append(vm_dict[k]['isDeployed'])
+            entry.append(vm_dict[k]['numberOfCpus'])
+            entry.append(vm_dict[k]['memoryMB'])
+            entry.append(vm_dict[k]['status'])
+            vm_table.add_row(entry)
+        print vm_table
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        pass
+
+
+def print_vdc_list(org_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        org_dict:  dictionary of organization where key is org uuid.
+
+        Returns:
+            The return nothing
+    """
+    if org_dict is None:
+        return
+    try:
+        vdcs_dict = {}
+        if org_dict.has_key('vdcs'):
+            vdcs_dict = org_dict['vdcs']
+        vdc_table = PrettyTable(['vdc uuid', 'vdc name'])
+        for k in vdcs_dict:
+            entry = [k, vdcs_dict[k]]
+            vdc_table.add_row(entry)
+
+        print vdc_table
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def print_network_list(org_dict=None):
+    """ Method print network list.
+
+    Args:
+        org_dict:   dictionary of organization that contain key networks with a list of all
+                    network for for specific VDC
+
+        Returns:
+            The return nothing
+    """
+    if org_dict is None:
+        return
+    try:
+        network_dict = {}
+        if org_dict.has_key('networks'):
+            network_dict = org_dict['networks']
+        network_table = PrettyTable(['network uuid', 'network name'])
+        for k in network_dict:
+            entry = [k, network_dict[k]]
+            network_table.add_row(entry)
+
+        print network_table
+
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def print_org_details(org_dict=None):
+    """ Method takes vapp_dict and print in tabular format
+
+    Args:
+        org_dict:  dictionary of organization where key is org uuid.
+
+        Returns:
+            The return nothing
+    """
+    if org_dict is None:
+        return
+    try:
+        catalogs_dict = {}
+
+        print_vdc_list(org_dict=org_dict)
+        print_network_list(org_dict=org_dict)
+
+        if org_dict.has_key('catalogs'):
+            catalogs_dict = org_dict['catalogs']
+
+        catalog_table = PrettyTable(['catalog uuid', 'catalog name'])
+        for k in catalogs_dict:
+            entry = [k, catalogs_dict[k]]
+            catalog_table.add_row(entry)
+
+        print catalog_table
+
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def delete_actions(vim=None, action=None, namespace=None):
+    if action == 'network' or namespace.action == 'network':
+        logger.debug("Requesting delete for network {}".format(namespace.network_name))
+        network_uuid = namespace.network_name
+        # if request name based we need find UUID
+        # TODO optimize it or move to external function
+        if not namespace.uuid:
+            org_dict = vim.get_org_list()
+            for org in org_dict:
+                org_net = vim.get_org(org)['networks']
+                for network in org_net:
+                    if org_net[network] == namespace.network_name:
+                        network_uuid = network
+
+        vim.delete_network_action(network_uuid=network_uuid)
+
+
+def list_actions(vim=None, action=None, namespace=None):
+    """ Method provide list object from VDC action
+
+       Args:
+           vim - is vcloud director vim connector.
+           action - is action for list ( vdc / org etc)
+           namespace -  must contain VDC / Org information.
+
+           Returns:
+               The return nothing
+       """
+
+    org_id = None
+    myorgs = vim.get_org_list()
+    for org in myorgs:
+        if myorgs[org] == namespace.vcdorg:
+            org_id = org
+        break
+    else:
+        print(" Invalid organization.")
+        return
+
+    if action == 'vms' or namespace.action == 'vms':
+        vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
+        print_vm_list(vm_dict=vm_dict)
+    elif action == 'vapps' or namespace.action == 'vapps':
+        vapp_dict = vim.get_vapp_list(vdc_name=namespace.vcdvdc)
+        print_vapp(vapp_dict=vapp_dict)
+    elif action == 'networks' or namespace.action == 'networks':
+        if namespace.osm:
+            osm_print(vim.get_network_list(filter_dict={}))
+        else:
+            print_network_list(vim.get_org(org_uuid=org_id))
+    elif action == 'vdc' or namespace.action == 'vdc':
+        if namespace.osm:
+            osm_print(vim.get_tenant_list(filter_dict=None))
+        else:
+            print_vdc_list(vim.get_org(org_uuid=org_id))
+    elif action == 'org' or namespace.action == 'org':
+        print_org(org_dict=vim.get_org_list())
+    else:
+        return None
+
+
+def print_network_details(network_dict=None):
+    try:
+        network_table = PrettyTable(network_dict.keys())
+        entry = [network_dict.values()]
+        network_table.add_row(entry[0])
+        print network_table
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def osm_print(generic_dict=None):
+
+    try:
+        for element in generic_dict:
+            table = PrettyTable(element.keys())
+            entry = [element.values()]
+            table.add_row(entry[0])
+        print table
+    except KeyError:
+        logger.error("wrong key {}".format(KeyError.message))
+        logger.logger.debug(traceback.format_exc())
+
+
+def view_actions(vim=None, action=None, namespace=None):
+    org_id = None
+    orgs = vim.get_org_list()
+    for org in orgs:
+        if orgs[org] == namespace.vcdorg:
+            org_id = org
+        break
+    else:
+        print(" Invalid organization.")
+        return
+
+    myorg = vim.get_org(org_uuid=org_id)
+
+    # view org
+    if action == 'org' or namespace.action == 'org':
+        org_id = None
+        orgs = vim.get_org_list()
+        if namespace.uuid:
+            if namespace.org_name in orgs:
+                org_id = namespace.org_name
+        else:
+            # we need find UUID based on name provided
+            for org in orgs:
+                if orgs[org] == namespace.org_name:
+                    org_id = org
+                    break
+
+        logger.debug("Requesting view for orgs {}".format(org_id))
+        print_org_details(vim.get_org(org_uuid=org_id))
+
+    # view vapp action
+    if action == 'vapp' or namespace.action == 'vapp':
+        if namespace.vapp_name is not None and namespace.uuid:
+            logger.debug("Requesting vapp {} for vdc {}".format(namespace.vapp_name, namespace.vcdvdc))
+            vapp_dict = {}
+            vapp_uuid = namespace.vapp_name
+            # if request based on just name we need get UUID
+            if not namespace.uuid:
+                vapp_uuid = vim.get_vappid(vdc=namespace.vcdvdc, vapp_name=namespace.vapp_name)
+                if vapp_uuid is None:
+                    print("Can't find vapp by given name {}".format(namespace.vapp_name))
+                    return
+
+            print " namespace {}".format(namespace)
+            if vapp_dict is not None and namespace.osm:
+                vm_info_dict = vim.get_vminstance(vim_vm_uuid=vapp_uuid)
+                print vm_info_dict
+            if vapp_dict is not None and namespace.osm != True:
+                vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vapp_uuid, isuuid=True)
+                print_vapp(vapp_dict=vapp_dict)
+
+    # view network
+    if action == 'network' or namespace.action == 'network':
+        logger.debug("Requesting view for network {}".format(namespace.network_name))
+        network_uuid = namespace.network_name
+        # if request name based we need find UUID
+        # TODO optimize it or move to external function
+        if not namespace.uuid:
+            if not myorg.has_key('networks'):
+                print("Network {} is undefined in vcloud director for org {} vdc {}".format(namespace.network_name,
+                                                                                            vim.name,
+                                                                                            vim.tenant_name))
+                return
+
+            my_org_net = myorg['networks']
+            for network in my_org_net:
+                if my_org_net[network] == namespace.network_name:
+                    network_uuid = network
+                    break
+
+        print print_network_details(network_dict=vim.get_vcd_network(network_uuid=network_uuid))
+
+
+def create_actions(vim=None, action=None, namespace=None):
+    """Method gets provider vdc view from vcloud director
+
+        Args:
+            vim - is Cloud director vim connector
+            action - action for create ( network / vdc etc)
+
+        Returns:
+            The return xml content of respond or None
+    """
+    if action == 'network' or namespace.action == 'network':
+        logger.debug("Creating a network in vcloud director".format(namespace.network_name))
+        network_uuid = vim.create_network(namespace.network_name)
+        if network_uuid is not None:
+            print ("Crated new network {} and uuid: {}".format(namespace.network_name, network_uuid))
+        else:
+            print ("Failed create a new network {}".format(namespace.network_name))
+    elif action == 'vdc' or namespace.action == 'vdc':
+        logger.debug("Creating a new vdc in vcloud director.".format(namespace.vdc_name))
+        vdc_uuid = vim.create_vdc(namespace.vdc_name)
+        if vdc_uuid is not None:
+            print ("Crated new vdc {} and uuid: {}".format(namespace.vdc_name, vdc_uuid))
+        else:
+            print ("Failed create a new vdc {}".format(namespace.vdc_name))
+    else:
+        return None
+
+
+def validate_uuid4(uuid_string):
+    """Function validate that string contain valid uuid4
+
+        Args:
+            uuid_string - valid UUID string
+
+        Returns:
+            The return true if string contain valid UUID format
+    """
+    try:
+        val = uuid.UUID(uuid_string, version=4)
+    except ValueError:
+        return False
+    return True
+
+
+def upload_image(vim=None, image_file=None):
+    """Function upload image to vcloud director
+
+        Args:
+            image_file - valid UUID string
+
+        Returns:
+            The return true if image uploaded correctly
+    """
+    try:
+        catalog_uuid = vim.get_image_id_from_path(path=image_file, progress=True)
+        if catalog_uuid is not None and validate_uuid4(catalog_uuid):
+            print("Image uploaded and uuid {}".format(catalog_uuid))
+            return True
+    except vimconn.vimconnException as upload_exception:
+        print("Failed uploaded {} image".format(image_file))
+        print("Error Reason: {}".format(upload_exception.message))
+    return False
+
+
+def boot_image(vim=None, image_name=None, vm_name=None):
+    """ Function boot image that resided in vcloud director.
+        The image name can be UUID of name.
+
+        Args:
+            vim - vim connector
+            image_name - image identified by UUID or text string.
+            vm_name - vmname
+
+
+         Returns:
+             The return true if image uploaded correctly
+     """
+
+    vim_catalog = None
+    try:
+        catalogs = vim.vca.get_catalogs()
+        if not validate_uuid4(image_name):
+            vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
+            if vim_catalog is None:
+                return None
+        else:
+            vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
+            if vim_catalog is None:
+                return None
+
+        print (" Booting {} image id {} ".format(vm_name, vim_catalog))
+        vm_uuid = vim.new_vminstance(name=vm_name, image_id=vim_catalog)
+        if vm_uuid is not None and validate_uuid4(vm_uuid):
+            print("Image booted and vm uuid {}".format(vm_uuid))
+            vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vm_uuid, isuuid=True)
+            if vapp_dict is not None:
+                print_vapp(vapp_dict=vapp_dict)
+        return True
+    except vimconn.vimconnNotFoundException as notFound:
+        print("Failed boot {} image".format(image_name))
+        print(notFound.message)
+    except vimconn.vimconnException as vimconError:
+        print("Failed boot {} image".format(image_name))
+        print(vimconError.message)
+    except:
+        print("Failed boot {} image".format(image_name))
+
+
+        return False
+
+
+def image_action(vim=None, action=None, namespace=None):
+    """ Function present set of action to manipulate with image.
+          - upload image
+          - boot image.
+          - delete image ( not yet done )
+
+        Args:
+             vim - vcloud director connector
+             action - string (upload/boot etc)
+             namespace - contain other attributes image name etc
+
+         Returns:
+             The return nothing
+     """
+
+    if action == 'upload' or namespace.action == 'upload':
+        upload_image(vim=vim, image_file=namespace.image)
+    elif action == 'boot' or namespace.action == 'boot':
+        boot_image(vim=vim, image_name=namespace.image, vm_name=namespace.vmname)
+    else:
+        return None
+
+
+def vmwarecli(command=None, action=None, namespace=None):
+    logger.debug("Namespace {}".format(namespace))
+    urllib3.disable_warnings()
+
+    vcduser = None
+    vcdpasword = None
+    vcdhost = None
+    vcdorg = None
+
+    if hasattr(__builtins__, 'raw_input'):
+        input = raw_input
+
+    if namespace.vcdvdc is None:
+        while True:
+            vcduser = input("Enter vcd username: ")
+            if vcduser is not None and len(vcduser) > 0:
+                break
+    else:
+        vcduser = namespace.vcduser
+
+    if namespace.vcdpassword is None:
+        while True:
+            vcdpasword = input("Please enter vcd password: ")
+            if vcdpasword is not None and len(vcdpasword) > 0:
+                break
+    else:
+        vcdpasword = namespace.vcdpassword
+
+    if namespace.vcdhost is None:
+        while True:
+            vcdhost = input("Please enter vcd host name or ip: ")
+            if vcdhost is not None and len(vcdhost) > 0:
+                break
+    else:
+        vcdhost = namespace.vcdhost
+
+    if namespace.vcdorg is None:
+        while True:
+            vcdorg = input("Please enter vcd organization name: ")
+            if vcdorg is not None and len(vcdorg) > 0:
+                break
+    else:
+        vcdorg = namespace.vcdorg
+
+    try:
+        vim = vimconnector(uuid=None,
+                           name=vcdorg,
+                           tenant_id=None,
+                           tenant_name=namespace.vcdvdc,
+                           url=vcdhost,
+                           url_admin=vcdhost,
+                           user=vcduser,
+                           passwd=vcdpasword,
+                           log_level="DEBUG",
+                           config={'admin_username': namespace.vcdamdin, 'admin_password': namespace.vcdadminpassword})
+        vim.vca = vim.connect()
+
+    except vimconn.vimconnConnectionException:
+        print("Failed connect to vcloud director. Please check credential and hostname.")
+        return
+
+    # list
+    if command == 'list' or namespace.command == 'list':
+        logger.debug("Client requested list action")
+        # route request to list actions
+        list_actions(vim=vim, action=action, namespace=namespace)
+
+    # view action
+    if command == 'view' or namespace.command == 'view':
+        logger.debug("Client requested view action")
+        view_actions(vim=vim, action=action, namespace=namespace)
+
+    # delete action
+    if command == 'delete' or namespace.command == 'delete':
+        logger.debug("Client requested delete action")
+        delete_actions(vim=vim, action=action, namespace=namespace)
+
+    # create action
+    if command == 'create' or namespace.command == 'create':
+        logger.debug("Client requested create action")
+        create_actions(vim=vim, action=action, namespace=namespace)
+
+    # image action
+    if command == 'image' or namespace.command == 'image':
+        logger.debug("Client requested create action")
+        image_action(vim=vim, action=action, namespace=namespace)
+
+
+if __name__ == '__main__':
+    defaults = {'vcdvdc': 'default',
+                'vcduser': 'admin',
+                'vcdpassword': 'admin',
+                'vcdhost': 'https://localhost',
+                'vcdorg': 'default',
+                'debug': 'INFO'}
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-u', '--vcduser', help='vcloud director username', type=str)
+    parser.add_argument('-p', '--vcdpassword', help='vcloud director password', type=str)
+    parser.add_argument('-U', '--vcdamdin', help='vcloud director password', type=str)
+    parser.add_argument('-P', '--vcdadminpassword', help='vcloud director password', type=str)
+    parser.add_argument('-c', '--vcdhost', help='vcloud director host', type=str)
+    parser.add_argument('-o', '--vcdorg', help='vcloud director org', type=str)
+    parser.add_argument('-v', '--vcdvdc', help='vcloud director vdc', type=str)
+    parser.add_argument('-d', '--debug', help='debug level', type=int)
+
+    parser_subparsers = parser.add_subparsers(help='commands', dest='command')
+    sub = parser_subparsers.add_parser('list', help='List objects (VMs, vApps, networks)')
+    sub_subparsers = sub.add_subparsers(dest='action')
+
+    list_vms = sub_subparsers.add_parser('vms', help='list - all vm deployed in vCloud director')
+    list_vapps = sub_subparsers.add_parser('vapps', help='list - all vapps deployed in vCloud director')
+    list_network = sub_subparsers.add_parser('networks', help='list - all networks deployed')
+    list_network.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
+
+    #list vdc
+    list_vdc = sub_subparsers.add_parser('vdc', help='list - list all vdc for organization accessible to you')
+    list_vdc.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
+
+    list_org = sub_subparsers.add_parser('org', help='list - list of organizations accessible to you.')
+
+    create_sub = parser_subparsers.add_parser('create')
+    create_sub_subparsers = create_sub.add_subparsers(dest='action')
+    create_vms = create_sub_subparsers.add_parser('vms')
+    create_vapp = create_sub_subparsers.add_parser('vapp')
+    create_vapp.add_argument('uuid')
+
+    # add network
+    create_network = create_sub_subparsers.add_parser('network')
+    create_network.add_argument('network_name', action='store', help='create a network for a vdc')
+
+    # add VDC
+    create_vdc = create_sub_subparsers.add_parser('vdc')
+    create_vdc.add_argument('vdc_name', action='store', help='create a new VDC for org')
+
+    delete_sub = parser_subparsers.add_parser('delete')
+    del_sub_subparsers = delete_sub.add_subparsers(dest='action')
+    del_vms = del_sub_subparsers.add_parser('vms')
+    del_vapp = del_sub_subparsers.add_parser('vapp')
+    del_vapp.add_argument('uuid', help='view vapp based on UUID')
+
+    # delete network
+    del_network = del_sub_subparsers.add_parser('network')
+    del_network.add_argument('network_name', action='store',
+                             help='- delete network for vcloud director by provided name')
+    del_network.add_argument('-u', '--uuid', default=False, action='store_true',
+                             help='delete network for vcloud director by provided uuid')
+
+    # delete vdc
+    del_vdc = del_sub_subparsers.add_parser('vdc')
+
+    view_sub = parser_subparsers.add_parser('view')
+    view_sub_subparsers = view_sub.add_subparsers(dest='action')
+
+    view_vms_parser = view_sub_subparsers.add_parser('vms')
+    view_vms_parser.add_argument('uuid', default=False, action='store_true',
+                                 help='- View VM for specific uuid in vcloud director')
+    view_vms_parser.add_argument('name', default=False, action='store_true',
+                                 help='- View VM for specific vapp name in vcloud director')
+
+    # view vapp
+    view_vapp_parser = view_sub_subparsers.add_parser('vapp')
+    view_vapp_parser.add_argument('vapp_name', action='store',
+                                  help='- view vapp for specific vapp name in vcloud director')
+    view_vapp_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view vapp based on uuid')
+    view_vapp_parser.add_argument('-o', '--osm', default=False, action='store_true',  help='provide view in OSM format')
+
+    # view network
+    view_network = view_sub_subparsers.add_parser('network')
+    view_network.add_argument('network_name', action='store',
+                              help='- view network for specific network name in vcloud director')
+    view_network.add_argument('-u', '--uuid', default=False, action='store_true', help='view network based on uuid')
+
+    # view VDC command and actions
+    view_vdc = view_sub_subparsers.add_parser('vdc')
+    view_vdc.add_argument('vdc_name', action='store',
+                          help='- View VDC based and action based on provided vdc uuid')
+    view_vdc.add_argument('-u', '--uuid', default=False, action='store_true', help='view vdc based on uuid')
+
+    # view organization command and actions
+    view_org = view_sub_subparsers.add_parser('org')
+    view_org.add_argument('org_name', action='store',
+                          help='- View VDC based and action based on provided vdc uuid')
+    view_org.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
+
+    # upload image action
+    image_sub = parser_subparsers.add_parser('image')
+    image_subparsers = image_sub.add_subparsers(dest='action')
+    upload_parser = image_subparsers.add_parser('upload')
+    upload_parser.add_argument('image', default=False, action='store', help='- valid path to OVF image ')
+    upload_parser.add_argument('catalog', default=False, action='store_true', help='- catalog name')
+
+    # boot vm action
+    boot_parser = image_subparsers.add_parser('boot')
+    boot_parser.add_argument('image', default=False, action='store', help='- Image name')
+    boot_parser.add_argument('vmname', default=False, action='store', help='- VM name')
+    boot_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
+
+    namespace = parser.parse_args()
+    # put command_line args to mapping
+    command_line_args = {k: v for k, v in vars(namespace).items() if v}
+
+    d = defaults.copy()
+    d.update(os.environ)
+    d.update(command_line_args)
+
+    logger = logging.getLogger('mano.vim.vmware')
+    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+    ch = logging.StreamHandler()
+    ch.setLevel(str.upper(d['debug']))
+    ch.setFormatter(formatter)
+    logger.addHandler(ch)
+    logger.setLevel(getattr(logging, str.upper(d['debug'])))
+    logger.info(
+        "Connecting {} username: {} org: {} vdc: {} ".format(d['vcdhost'], d['vcduser'], d['vcdorg'], d['vcdvdc']))
+
+    logger.debug("command: \"{}\" actio: \"{}\"".format(d['command'], d['action']))
+
+    # main entry point.
+    vmwarecli(namespace=namespace)
index 0f6b6f6..38c055c 100644 (file)
@@ -1,21 +1,21 @@
 --index-url https://pypi.python.org/simple/
 
-PyYAML==3.10
-bottle==0.12.7
-PyMySQL==0.7.2
-jsonschema==2.5.1
-paramiko==1.16.0
-argcomplete==0.8.1
-requests==2.13.0
-logutils==0.3.3
-python-cinderclient==1.6.0
-python-glanceclient==2.0.0
-python-keystoneclient==2.3.1
-python-neutronclient==4.1.1
-python-novaclient==3.3.1
-pyvcloud==16
-pyvmomi==6.5
-progressbar==2.3
-prettytable==0.7.2
-boto==2.38.0
+PyYAML
+bottle
+MySQL-python
+jsonschema
+paramiko
+argcomplete
+requests
+logutils
+python-novaclient
+python-keystoneclient
+python-glanceclient
+python-neutronclient
+python-cinderclient
+pyvcloud
+pyvmomi
+progressbar
+prettytable
+boto
 
index 1a48d4a..0224d20 100755 (executable)
@@ -116,7 +116,7 @@ do
             running=y
         done
         #if installed as a service and it is not provided a screen name call service
-        [[ -f /etc/systemd/system/openmano.service ]] && [[ -z $option_screen_name ]] && running=y #&& service openmano status
+        [[ -f /etc/systemd/system/osm-ro.service ]] && [[ -z $option_screen_name ]] && running=y #&& service osm-ro status
         if [ -z "$running" ]
         then
             echo -n "    $om_name not running" && [[ -n "$option_screen_name" ]] && echo " on screen '$option_screen_name'" || echo
@@ -124,7 +124,7 @@ do
     fi
 
     #if installed as a service and it is not provided a screen name call service
-    [[ -f /etc/systemd/system/openmano.service ]] && [[ -z $option_screen_name ]] && service openmano $om_action && ( [[ $om_action == status ]] || sleep 5 ) && exit $?
+    [[ -f /etc/systemd/system/osm-ro.service ]] && [[ -z $option_screen_name ]] && service osm-ro $om_action && ( [[ $om_action == status ]] || sleep 5 ) && exit $?
 
 
     #stop
index 2d2d07a..68781be 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -1,68 +1,69 @@
 #!/usr/bin/env python
 
 from setuptools import setup
+from setuptools.command.install import install
+from os import system
 #import glob
 
-requirements = [
+_name = 'osm_ro'
+_version = '1.0.0'
+_description = 'OSM Resource Orchestrator'
+_author = 'ETSI OSM'
+_author_email = 'alfonso.tiernosepulveda@telefonica.com'
+_maintainer = 'garciadeblas'
+_maintainer_email = 'gerardo.garciadeblas@telefonica.com'
+_license = 'Apache 2.0'
+_url = 'https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary'
+_requirements = [
     "PyYAML",
     "bottle",
-    "mysqldb",
+    "MySQL-python",
     "jsonschema",
     "paramiko",
     "argcomplete",
     "requests",
     "logutils",
-    "pip",
-    "novaclient",
-    "keystoneclient",
-    "glanceclient",
-    "neutronclient",
-    "cinderclient",
-    "boto",
+    "python-novaclient",
+    "python-keystoneclient",
+    "python-glanceclient",
+    "python-neutronclient",
+    "python-cinderclient",
     "pyvcloud",
     "progressbar",
     "prettytable",
     "pyvmomi",
+    "boto",
 ]
 
-setup(name='osm-ro',
-      version='1.0',
-      description='OSM Resource Orchestrator',
-      long_description=open('README.rst').read(),
-      author='ETSI OSM',
-      author_email='alfonso.tiernosepulveda@telefonica.com',
-      maintainer='garciadeblas',
-      maintainer_email='gerardo.garciadeblas@telefonica.com',
-      url='https://osm.etsi.org/gitweb/?p=osm/RO.git;a=summary',
-      license='Apache 2.0',
-      #packages=['ro-server', 'ro-client'],
-      #py_modules=glob.glob('*.py')
-      py_modules=['console_proxy_thread',
-                  'db_base',
-                  'httpserver',
-                  'nfvo_db',
-                  'nfvo',
-                  'openmanoclient',
-                  'openmanoconfig',
-                  'openmanod',
-                  'openmano_schemas',
-                  'utils',
-                  'vimconn_openstack',
-                  'vimconn_openvim',
-                  'vimconn',
-                  'vimconn_vmware',
-                  'vmwarecli',
-                  'vmwarerecli',
-                 ],
-     install_requires=requirements,
-     #package_data={'': ['vnfs', 'scenarios', 'instance-scenarios', 'database_utils/mano_db_structure.sql']}
-     data_files=[('/etc/osm/', ['openmanod.cfg']),
-                 ('/etc/systemd/system/', ['openmano.service']),
-                 ('vnfs', ['vnfs']),
-                 ('scenarios', ['scenarios']),
-                 ('instance-scenarios', ['instance-scenarios']),
-                 ('database_utils', ['database-utils']),
-                ],
-     scripts=['openmanod.py', 'openmano', 'scripts/service-openmano', 'scripts/openmano-report',]
-     )
+class ROInstaller(install):
+    def run(self):
+        cmd = 'echo "Running install script"'
+        system(cmd)
+        install.run(self)
+
+setup(name=_name,
+      version = _version,
+      description = _description,
+      long_description = open('README.rst').read(),
+      author = _author,
+      author_email = _author_email,
+      maintainer = _maintainer,
+      maintainer_email = _maintainer_email,
+      url = _url,
+      license = _license,
+      packages = [_name],
+      #packages = ['osm_ro', 'osm_roclient'],
+      package_dir = {_name: _name},
+      package_data = {_name: ['vnfs/*.yaml', 'vnfs/examples/*.yaml',
+                         'scenarios/*.yaml', 'scenarios/examples/*.yaml',
+                         'instance-scenarios/examples/*.yaml', 'database_utils/*',
+                         'scripts/install-openmano*.sh']},
+      data_files = [('/etc/osm/', ['openmanod.cfg']),
+                   ('/etc/systemd/system/', ['osm-ro.service']),
+                   ],
+      scripts=['openmanod.py', 'openmano', 'osm_ro/scripts/service-openmano.sh', 'osm_ro/scripts/openmano-report.sh',],
+      install_requires=_requirements,
+      include_package_data=True,
+      cmdclass = {'install': ROInstaller},
+      )
 
diff --git a/utils.py b/utils.py
deleted file mode 100644 (file)
index 00f6f2d..0000000
--- a/utils.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# -*- 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
-##
-
-'''
-utils is a module that implements functions that are used by all openmano modules,
-dealing with aspects such as reading/writing files, formatting inputs/outputs for quick translation
-from dictionaries to appropriate database dictionaries, etc.
-'''
-__author__="Alfonso Tierno, Gerardo Garcia"
-__date__ ="$08-sep-2014 12:21:22$"
-
-import datetime
-from jsonschema import validate as js_v, exceptions as js_e
-#from bs4 import BeautifulSoup
-
-def read_file(file_to_read):
-    """Reads a file specified by 'file_to_read' and returns (True,<its content as a string>) in case of success or (False, <error message>) in case of failure"""
-    try:
-        f = open(file_to_read, 'r')
-        read_data = f.read()
-        f.close()
-    except Exception as e:
-        return (False, str(e))
-      
-    return (True, read_data)
-
-def write_file(file_to_write, text):
-    """Write a file specified by 'file_to_write' and returns (True,NOne) in case of success or (False, <error message>) in case of failure"""
-    try:
-        f = open(file_to_write, 'w')
-        f.write(text)
-        f.close()
-    except Exception as e:
-        return (False, str(e))
-      
-    return (True, None)
-
-def format_in(http_response, schema):
-    try:
-        client_data = http_response.json()
-        js_v(client_data, schema)
-        #print "Input data: ", str(client_data)
-        return True, client_data
-    except js_e.ValidationError as exc:
-        print "validate_in error, jsonschema exception ", exc.message, "at", exc.path
-        return False, ("validate_in error, jsonschema exception ", exc.message, "at", exc.path)
-
-def remove_extra_items(data, schema):
-    deleted=[]
-    if type(data) is tuple or type(data) is list:
-        for d in data:
-            a= remove_extra_items(d, schema['items'])
-            if a is not None: deleted.append(a)
-    elif type(data) is dict:
-        #TODO deal with patternProperties
-        if 'properties' not in schema:
-            return None
-        for k in data.keys():
-            if k not in schema['properties'].keys():
-                del data[k]
-                deleted.append(k)
-            else:
-                a = remove_extra_items(data[k], schema['properties'][k])
-                if a is not None:  deleted.append({k:a})
-    if len(deleted) == 0: return None
-    elif len(deleted) == 1: return deleted[0]
-    else: return deleted
-
-#def format_html2text(http_content):
-#    soup=BeautifulSoup(http_content)
-#    text = soup.p.get_text() + " " + soup.pre.get_text()
-#    return text
-
-
-def convert_bandwidth(data, reverse=False):
-    '''Check the field bandwidth recursivelly and when found, it removes units and convert to number 
-    It assumes that bandwidth is well formed
-    Attributes:
-        'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
-        'reverse': by default convert form str to int (Mbps), if True it convert from number to units
-    Return:
-        None
-    '''
-    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)
-        if "bandwidth" in data:
-            try:
-                value=str(data["bandwidth"])
-                if not reverse:
-                    pos = value.find("bps")
-                    if pos>0:
-                        if value[pos-1]=="G": data["bandwidth"] =  int(data["bandwidth"][:pos-1]) * 1000
-                        elif value[pos-1]=="k": data["bandwidth"]= int(data["bandwidth"][:pos-1]) / 1000
-                        else: data["bandwidth"]= int(data["bandwidth"][:pos-1])
-                else:
-                    value = int(data["bandwidth"])
-                    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"]
-                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)
-
-
-
-def convert_datetime2str(var):
-    '''Converts a datetime variable to a string with the format '%Y-%m-%dT%H:%i:%s'
-    It enters recursively in the dict var finding this kind of variables
-    '''
-    if type(var) is dict:
-        for k,v in var.items():
-            if type(v) is datetime.datetime:
-                var[k]= v.strftime('%Y-%m-%dT%H:%M:%S')
-            elif type(v) is dict or type(v) is list or type(v) is tuple: 
-                convert_datetime2str(v)
-        if len(var) == 0: return True
-    elif type(var) is list or type(var) is tuple:
-        for v in var:
-            convert_datetime2str(v)
-
-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 
-    Done recursively
-    Attributes:
-        'data': dictionary variable to be checked. None or empty is considered valid
-        'items': tuple of keys to convert
-    Return:
-        None
-    '''
-    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_str2boolean(data[k], items)
-            if k in items:
-                if type(data[k]) is str:
-                    if   data[k]=="false" or data[k]=="False": data[k]=False
-                    elif data[k]=="true"  or data[k]=="True":  data[k]=True
-    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_str2boolean(k, items)
-
-def check_valid_uuid(uuid):
-    id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
-    id_schema2 = {"type" : "string", "pattern": "^[a-fA-F0-9]{32}$"}
-    try:
-        js_v(uuid, id_schema)
-        return True
-    except js_e.ValidationError:
-        try:
-            js_v(uuid, id_schema2)
-            return True
-        except js_e.ValidationError:
-            return False
-    return False
-    
diff --git a/vim_thread.py b/vim_thread.py
deleted file mode 100644 (file)
index 42279a2..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-# -*- coding: utf-8 -*-
-
-##
-# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
-# This file is part of openvim
-# 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
-##
-
-'''
-This is thread that interact with the host and the libvirt to manage VM
-One thread will be launched per host 
-'''
-__author__ = "Alfonso Tierno"
-__date__ = "$10-feb-2017 12:07:15$"
-
-import threading
-import time
-import Queue
-import logging
-import vimconn
-from db_base import db_base_Exception
-
-
-# from logging import Logger
-# import auxiliary_functions as af
-
-
-def is_task_id(id):
-    return True if id[:5] == "TASK." else False
-
-
-class vim_thread(threading.Thread):
-
-    def __init__(self, vimconn, task_lock, name=None, datacenter_name=None, datacenter_tenant_id=None, db=None, db_lock=None):
-        """Init a thread.
-        Arguments:
-            'id' number of thead
-            'name' name of thread
-            'host','user':  host ip or name to manage and user
-            'db', 'db_lock': database class and lock to use it in exclusion
-        """
-        self.tasksResult = {}
-        """ It will contain a dictionary with
-            task_id:
-                status: enqueued,done,error,deleted,processing
-                result: VIM result,
-        """
-        threading.Thread.__init__(self)
-        self.vim = vimconn
-        self.datacenter_name = datacenter_name
-        self.datacenter_tenant_id = datacenter_tenant_id
-        if not name:
-            self.name = vimconn["id"] + "." + vimconn["config"]["datacenter_tenant_id"]
-        else:
-            self.name = name
-
-        self.logger = logging.getLogger('openmano.vim.'+self.name)
-        self.db = db
-        self.db_lock = db_lock
-
-        self.task_lock = task_lock
-        self.task_queue = Queue.Queue(2000)
-
-    def insert_task(self, task):
-        try:
-            self.task_queue.put(task, False)
-            return task["id"]
-        except Queue.Full:
-            raise vimconn.vimconnException(self.name + ": timeout inserting a task")
-
-    def del_task(self, task):
-        with self.task_lock:
-            if task["status"] == "enqueued":
-                task["status"] == "deleted"
-                return True
-            else:   # task["status"] == "processing"
-                self.task_lock.release()
-                return False
-
-    def run(self):
-        self.logger.debug("Starting")
-        while True:
-            #TODO reload service
-            while True:
-                if not self.task_queue.empty():
-                    task = self.task_queue.get()
-                    self.task_lock.acquire()
-                    if task["status"] == "deleted":
-                        self.task_lock.release()
-                        continue
-                    task["status"] == "processing"
-                    self.task_lock.release()
-                else:
-                    now=time.time()
-                    time.sleep(1)
-                    continue
-                self.logger.debug("processing task id={} name={} params={}".format(task["id"], task["name"],
-                                                                                   str(task["params"])))
-                if task["name"] == 'exit' or task["name"] == 'reload':
-                    result, content = self.terminate(task)
-                elif task["name"] == 'new-vm':
-                    result, content = self.new_vm(task)
-                elif task["name"] == 'del-vm':
-                    result, content = self.del_vm(task)
-                elif task["name"] == 'new-net':
-                    result, content = self.new_net(task)
-                elif task["name"] == 'del-net':
-                    result, content = self.del_net(task)
-                else:
-                    error_text = "unknown task {}".format(task["name"])
-                    self.logger.error(error_text)
-                    result = False
-                    content = error_text
-
-                with self.task_lock:
-                    task["status"] = "done" if result else "error"
-                    task["result"] = content
-                self.task_queue.task_done()
-
-                if task["name"] == 'exit':
-                    return 0
-                elif task["name"] == 'reload':
-                    break
-
-        self.logger.debug("Finishing")
-
-    def terminate(self, task):
-        return True, None
-
-    def new_net(self, task):
-        try:
-            task_id = task["id"]
-            params = task["params"]
-            net_id = self.vim.new_network(*params)
-            with self.db_lock:
-                self.db.update_rows("instance_nets", UPDATE={"vim_net_id": net_id}, WHERE={"vim_net_id": task_id})
-            return True, net_id
-        except db_base_Exception as e:
-            self.logger.error("Error updating database %s", str(e))
-            return True, net_id
-        except vimconn.vimconnException as e:
-            return False, str(e)
-
-    def new_vm(self, task):
-        try:
-            params = task["params"]
-            task_id = task["id"]
-            depends = task.get("depends")
-            net_list = params[5]
-            for net in net_list:
-                if is_task_id(net["net_id"]):  # change task_id into network_id
-                    try:
-                        task_net = depends[net["net_id"]]
-                        with self.task_lock:
-                            if task_net["status"] == "error":
-                                return False, "Cannot create VM because depends on a network that cannot be created: " + \
-                                       str(task_net["result"])
-                            elif task_net["status"] == "enqueued" or task_net["status"] == "processing":
-                                return False, "Cannot create VM because depends on a network still not created"
-                            network_id = task_net["result"]
-                        net["net_id"] = network_id
-                    except Exception as e:
-                        return False, "Error trying to map from task_id={} to task result: {}".format(net["net_id"],
-                                                                                                      str(e))
-            vm_id = self.vim.new_vminstance(*params)
-            with self.db_lock:
-                self.db.update_rows("instance_vms", UPDATE={"vim_vm_id": vm_id}, WHERE={"vim_vm_id": task_id})
-            return True, vm_id
-        except db_base_Exception as e:
-            self.logger.error("Error updtaing database %s", str(e))
-            return True, vm_id
-        except vimconn.vimconnException as e:
-            return False, str(e)
-
-    def del_vm(self, task):
-        vm_id = task["params"]
-        if is_task_id(vm_id):
-            try:
-                task_create = task["depends"][vm_id]
-                with self.task_lock:
-                    if task_create["status"] == "error":
-                        return True, "VM was not created. It has error: " + str(task_create["result"])
-                    elif task_create["status"] == "enqueued" or task_create["status"] == "processing":
-                        return False, "Cannot delete VM because still creating"
-                    vm_id = task_create["result"]
-            except Exception as e:
-                return False, "Error trying to get task_id='{}':".format(vm_id, str(e))
-        try:
-            return True, self.vim.delete_vminstance(vm_id)
-        except vimconn.vimconnException as e:
-            return False, str(e)
-
-    def del_net(self, task):
-        net_id = task["params"]
-        if is_task_id(net_id):
-            try:
-                task_create = task["depends"][net_id]
-                with self.task_lock:
-                    if task_create["status"] == "error":
-                        return True, "net was not created. It has error: " + str(task_create["result"])
-                    elif task_create["status"] == "enqueued" or task_create["status"] == "processing":
-                        return False, "Cannot delete net because still creating"
-                    net_id = task_create["result"]
-            except Exception as e:
-                return False, "Error trying to get task_id='{}':".format(net_id, str(e))
-        try:
-            return True, self.vim.delete_network(net_id)
-        except vimconn.vimconnException as e:
-            return False, str(e)
-
-
diff --git a/vimconn.py b/vimconn.py
deleted file mode 100644 (file)
index a9bd9be..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-# -*- 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
-##
-
-"""
-vimconn implement an Abstract class for the vim connector plugins
- with the definition of the method to be implemented.
-"""
-__author__="Alfonso Tierno"
-__date__ ="$16-oct-2015 11:09:29$"
-
-import logging
-
-#Error variables 
-HTTP_Bad_Request = 400
-HTTP_Unauthorized = 401 
-HTTP_Not_Found = 404 
-HTTP_Method_Not_Allowed = 405 
-HTTP_Request_Timeout = 408
-HTTP_Conflict = 409
-HTTP_Not_Implemented = 501
-HTTP_Service_Unavailable = 503 
-HTTP_Internal_Server_Error = 500 
-
-class vimconnException(Exception):
-    """Common and base class Exception for all vimconnector exceptions"""
-    def __init__(self, message, http_code=HTTP_Bad_Request):
-        Exception.__init__(self, message)
-        self.http_code = http_code
-
-class vimconnConnectionException(vimconnException):
-    """Connectivity error with the VIM"""
-    def __init__(self, message, http_code=HTTP_Service_Unavailable):
-        vimconnException.__init__(self, message, http_code)
-    
-class vimconnUnexpectedResponse(vimconnException):
-    """Get an wrong response from VIM"""
-    def __init__(self, message, http_code=HTTP_Service_Unavailable):
-        vimconnException.__init__(self, message, http_code)
-
-class vimconnAuthException(vimconnException):
-    """Invalid credentials or authorization to perform this action over the VIM"""
-    def __init__(self, message, http_code=HTTP_Unauthorized):
-        vimconnException.__init__(self, message, http_code)
-
-class vimconnNotFoundException(vimconnException):
-    """The item is not found at VIM"""
-    def __init__(self, message, http_code=HTTP_Not_Found):
-        vimconnException.__init__(self, message, http_code)
-
-class vimconnConflictException(vimconnException):
-    """There is a conflict, e.g. more item found than one"""
-    def __init__(self, message, http_code=HTTP_Conflict):
-        vimconnException.__init__(self, message, http_code)
-
-class vimconnNotSupportedException(vimconnException):
-    """The request is not supported by connector"""
-    def __init__(self, message, http_code=HTTP_Service_Unavailable):
-        vimconnException.__init__(self, message, http_code)
-
-class vimconnNotImplemented(vimconnException):
-    """The method is not implemented by the connected"""
-    def __init__(self, message, http_code=HTTP_Not_Implemented):
-        vimconnException.__init__(self, message, http_code)
-
-class vimconnector():
-    """Abstract base class for all the VIM connector plugins
-    These plugins must implement a vimconnector class derived from this 
-    and all these privated methods
-    """ 
-    def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None,
-                 config={}, persitent_info={}):
-        """Constructor of VIM
-        Params:
-            'uuid': id asigned to this VIM
-            'name': name assigned to this VIM, can be used for logging
-            'tenant_id', 'tenant_name': (only one of them is mandatory) VIM tenant to be used
-            'url_admin': (optional), url used for administrative tasks
-            'user', 'passwd': credentials of the VIM user
-            'log_level': provider if it should 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 creation and particular VIM config at teh attachment
-            'persistent_info': dict where the class can store information that will be available among class
-                    destroy/creation cycles. This info is unique per VIM/credential. At first call it will contain an
-                    empty dict. Useful to store login/tokens information for speed up communication
-
-        Returns: Raise an exception is some needed parameter is missing, but it must not do any connectivity
-            check against the VIM
-        """
-        self.id        = uuid
-        self.name      = name
-        self.url       = url
-        self.url_admin = url_admin
-        self.tenant_id = tenant_id
-        self.tenant_name = tenant_name
-        self.user      = user
-        self.passwd    = passwd
-        self.config    = config
-        self.logger = logging.getLogger('openmano.vim')
-        if log_level:
-            self.logger.setLevel( getattr(logging, log_level) )
-        if not self.url_admin:  #try to use normal url 
-            self.url_admin = self.url
-    
-    def __getitem__(self,index):
-        if index=='tenant_id':
-            return self.tenant_id
-        if index=='tenant_name':
-            return self.tenant_name
-        elif index=='id':
-            return self.id
-        elif index=='name':
-            return self.name
-        elif index=='user':
-            return self.user
-        elif index=='passwd':
-            return self.passwd
-        elif index=='url':
-            return self.url
-        elif index=='url_admin':
-            return self.url_admin
-        elif index=="config":
-            return self.config
-        else:
-            raise KeyError("Invalid key '%s'" %str(index))
-        
-    def __setitem__(self,index, value):
-        if index=='tenant_id':
-            self.tenant_id = value
-        if index=='tenant_name':
-            self.tenant_name = value
-        elif index=='id':
-            self.id = value
-        elif index=='name':
-            self.name = value
-        elif index=='user':
-            self.user = value
-        elif index=='passwd':
-            self.passwd = value
-        elif index=='url':
-            self.url = value
-        elif index=='url_admin':
-            self.url_admin = value
-        else:
-            raise KeyError("Invalid key '%s'" %str(index))
-        
-    def check_vim_connectivity(self):
-        """Checks VIM can be reached and user credentials are ok.
-        Returns None if success or raised vimconnConnectionException, vimconnAuthException, ...
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def new_tenant(self,tenant_name,tenant_description):
-        """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
-        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 dictionary that can contain the following keys:
-            name: filter by tenant name
-            id: filter by tenant uuid/id
-            <other VIM specific>
-        Returns the tenant list of dictionaries, and empty list if no tenant match all the filers:
-            [{'name':'<name>, 'id':'<id>, ...}, ...]
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None):
-        """Adds a tenant network to VIM
-        Params:
-            'net_name': name of the network
-            'net_type': one of:
-                'bridge': overlay isolated network
-                'data':   underlay E-LAN network for Passthrough and SRIOV interfaces
-                'ptp':    underlay E-LINE network for Passthrough and SRIOV interfaces.
-            'ip_profile': is a dict containing the IP parameters of the network (Currently only IPv4 is implemented)
-                'ip-version': can be one of ["IPv4","IPv6"]
-                'subnet-address': ip_prefix_schema, that is X.X.X.X/Y
-                'gateway-address': (Optional) ip_schema, that is X.X.X.X
-                'dns-address': (Optional) ip_schema,
-                'dhcp': (Optional) dict containing
-                    'enabled': {"type": "boolean"},
-                    'start-address': ip_schema, first IP to grant
-                    'count': number of IPs to grant.
-            'shared': if this network can be seen/use by other tenants/organization
-            'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network
-        Returns the network identifier on success or raises and exception on failure
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def get_network_list(self, filter_dict={}):
-        """Obtain tenant networks of VIM
-        Params:
-            'filter_dict' (optional) contains entries to return only networks that matches ALL entries:
-                name: string  => returns only networks with this name
-                id:   string  => returns networks with this VIM id, this imply returns one network at most
-                shared: boolean >= returns only networks that are (or are not) shared
-                tenant_id: sting => returns only networks that belong to this tenant/project
-                ,#(not used yet) admin_state_up: boolean => returns only networks that are (or are not) in admin state active
-                #(not used yet) status: 'ACTIVE','ERROR',... => filter networks that are on this status
-        Returns the network list of dictionaries. each dictionary contains:
-            'id': (mandatory) VIM network id
-            'name': (mandatory) VIM network name
-            'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
-            'error_msg': (optional) text that explains the ERROR status
-            other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
-        List can be empty if no network map the filter_dict. Raise an exception only upon VIM connectivity,
-            authorization, or some other unspecific error
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def get_network(self, net_id):
-        """Obtain network details from the 'net_id' VIM network
-        Return a dict that contains:
-            'id': (mandatory) VIM network id, that is, net_id
-            'name': (mandatory) VIM network name
-            'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
-            'error_msg': (optional) text that explains the ERROR status
-            other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
-        Raises an exception upon error or when network is not found
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def delete_network(self, net_id):
-        """Deletes a tenant network from VIM
-        Returns the network identifier or raises an exception upon error or when network is not found
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def refresh_nets_status(self, net_list):
-        """Get the status of the networks
-        Params:
-            'net_list': a list with the VIM network id to be get the status
-        Returns a dictionary with:
-            'net_id':         #VIM id of this network
-                status:     #Mandatory. Text with one of:
-                    #  DELETED (not found at vim)
-                    #  VIM_ERROR (Cannot connect to VIM, authentication problems, VIM response error, ...)
-                    #  OTHER (Vim reported other status not understood)
-                    #  ERROR (VIM indicates an ERROR status)
-                    #  ACTIVE, INACTIVE, DOWN (admin down),
-                    #  BUILD (on building process)
-                error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR
-                vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
-            'net_id2': ...
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def get_flavor(self, flavor_id):
-        """Obtain flavor details from the VIM
-        Returns the flavor dict details {'id':<>, 'name':<>, other vim specific }
-        Raises an exception upon error or if not found
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def get_flavor_id_from_data(self, flavor_dict):
-        """Obtain flavor id that match the flavor description
-        Params:
-            'flavor_dict': dictionary that contains:
-                'disk': main hard disk in GB
-                'ram': meomry in MB
-                'vcpus': number of virtual cpus
-                #TODO: complete parameters for EPA
-        Returns the flavor_id or raises a vimconnNotFoundException
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def new_flavor(self, flavor_data):
-        """Adds a tenant flavor to VIM
-            flavor_data contains a dictionary with information, keys:
-                name: flavor name
-                ram: memory (cloud type) in MBytes
-                vpcus: cpus (cloud type)
-                extended: EPA parameters
-                  - numas: #items requested in same NUMA
-                        memory: number of 1G huge pages memory
-                        paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
-                        interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
-                          - name: interface name
-                            dedicated: yes|no|yes:sriov;  for PT, SRIOV or only one SRIOV for the physical NIC
-                            bandwidth: X Gbps; requested guarantee bandwidth
-                            vpci: requested virtual PCI address   
-                disk: disk size
-                is_public:
-                 #TODO to concrete
-        Returns the flavor identifier"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def delete_flavor(self, flavor_id):
-        """Deletes a tenant flavor from VIM identify by its id
-        Returns the used id or raise an exception"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def new_image(self, image_dict):
-        """ Adds a tenant image to VIM
-        Returns the image id or raises an exception if failed
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def delete_image(self, image_id):
-        """Deletes a tenant image from VIM
-        Returns the image_id if image is deleted or raises an exception on error"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def get_image_id_from_path(self, path):
-        """Get the image id from image path in the VIM database.
-           Returns the image_id or raises a vimconnNotFoundException
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-        
-    def get_image_list(self, filter_dict={}):
-        """Obtain tenant images from VIM
-        Filter_dict can be:
-            name: image name
-            id: image uuid
-            checksum: image checksum
-            location: image path
-        Returns the image list of dictionaries:
-            [{<the fields at Filter_dict plus some VIM specific>}, ...]
-            List can be empty
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None,
-                       disk_list=None):
-        """Adds a VM instance to VIM
-        Params:
-            'start': (boolean) indicates if VM must start or created in pause mode.
-            'image_id','flavor_id': image and flavor VIM id to use for the VM
-            'net_list': list of interfaces, each one is a dictionary with:
-                'name': (optional) name for the interface.
-                'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual
-                'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM capabilities
-                'model': (optional and only have sense for type==virtual) interface model: virtio, e2000, ...
-                'mac_address': (optional) mac address to assign to this interface
-                #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not provided,
-                    the VLAN tag to be used. In case net_id is provided, the internal network vlan is used for tagging VF
-                'type': (mandatory) can be one of:
-                    'virtual', in this case always connected to a network of type 'net_type=bridge'
-                     'PF' (passthrough): depending on VIM capabilities it can be connected to a data/ptp network ot it
-                           can created unconnected
-                     'VF' (SRIOV with VLAN tag): same as PF for network connectivity.
-                     'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs
-                            are allocated on the same physical NIC
-                'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS
-                'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing
-                                or True, it must apply the default VIM behaviour
-                After execution the method will add the key:
-                'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this
-                        interface. 'net_list' is modified
-            'cloud_config': (optional) dictionary with:
-                'key-pairs': (optional) list of strings with the public key to be inserted to the default user
-                'users': (optional) list of users to be inserted, each item is a dict with:
-                    'name': (mandatory) user name,
-                    'key-pairs': (optional) list of strings with the public key to be inserted to the user
-                'user-data': (optional) string is a text script to be passed directly to cloud-init
-                'config-files': (optional). List of files to be transferred. Each item is a dict with:
-                    'dest': (mandatory) string with the destination absolute path
-                    'encoding': (optional, by default text). Can be one of:
-                        'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
-                    'content' (mandatory): string with the content of the file
-                    'permissions': (optional) string with file permissions, typically octal notation '0644'
-                    'owner': (optional) file owner, string with the format 'owner:group'
-                'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
-            'disk_list': (optional) list with additional disks to the VM. Each item is a dict with:
-                'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
-                'size': (mandatory) string with the size of the disk in GB
-        Returns the instance identifier or raises an exception on error
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-        
-    def get_vminstance(self,vm_id):
-        """Returns the VM instance information from VIM"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-        
-    def delete_vminstance(self, vm_id):
-        """Removes a VM instance from VIM
-        Returns the instance identifier"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def refresh_vms_status(self, vm_list):
-        """Get the status of the virtual machines and their interfaces/ports
-           Params: the list of VM identifiers
-           Returns a dictionary with:
-                vm_id:          #VIM id of this Virtual Machine
-                    status:     #Mandatory. Text with one of:
-                                #  DELETED (not found at vim)
-                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
-                                #  OTHER (Vim reported other status not understood)
-                                #  ERROR (VIM indicates an ERROR status)
-                                #  ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running), 
-                                #  BUILD (on building process), ERROR
-                                #  ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
-                                #
-                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
-                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
-                    interfaces: list with interface info. Each item a dictionary with:
-                        vim_info:         #Text with plain information obtained from vim (yaml.safe_dump)
-                        mac_address:      #Text format XX:XX:XX:XX:XX:XX
-                        vim_net_id:       #network id where this interface is connected, if provided at creation
-                        vim_interface_id: #interface/port VIM id
-                        ip_address:       #null, or text with IPv4, IPv6 address
-                        physical_compute: #identification of compute node where PF,VF interface is allocated
-                        physical_pci:     #PCI address of the NIC that hosts the PF,VF
-                        physical_vlan:    #physical VLAN used for VF
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-    
-    def action_vminstance(self, vm_id, action_dict):
-        """Send and action over a VM instance from VIM
-        Returns the vm_id if the action was successfully sent to the VIM"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-    
-    def get_vminstance_console(self, vm_id, console_type="vnc"):
-        """
-        Get a console for the virtual machine
-        Params:
-            vm_id: uuid of the VM
-            console_type, can be:
-                "novnc" (by default), "xvpvnc" for VNC types, 
-                "rdp-html5" for RDP types, "spice-html5" for SPICE types
-        Returns dict with the console parameters:
-                protocol: ssh, ftp, http, https, ...
-                server:   usually ip address 
-                port:     the http, ssh, ... port 
-                suffix:   extra text, e.g. the http path and query string   
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-        
-#NOT USED METHODS in current version        
-
-    def host_vim2gui(self, host, server_dict):
-        """Transform host dictionary from VIM format to GUI format,
-        and append to the server_dict
-        """
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def get_hosts_info(self):
-        """Get the information of deployed hosts
-        Returns the hosts content"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def get_hosts(self, vim_tenant):
-        """Get the hosts and deployed instances
-        Returns the hosts content"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def get_processor_rankings(self):
-        """Get the processor rankings in the VIM database"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-    
-    def new_host(self, host_data):
-        """Adds a new host to VIM"""
-        """Returns status code of the VIM response"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-    
-    def new_external_port(self, port_data):
-        """Adds a external port to VIM"""
-        """Returns the port identifier"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-        
-    def new_external_network(self,net_name,net_type):
-        """Adds a external network to VIM (shared)"""
-        """Returns the network identifier"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def connect_port_network(self, port_id, network_id, admin=False):
-        """Connects a external port to a network"""
-        """Returns status code of the VIM response"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-
-    def new_vminstancefromJSON(self, vm_data):
-        """Adds a VM instance to VIM"""
-        """Returns the instance identifier"""
-        raise vimconnNotImplemented( "Should have implemented this" )
-
diff --git a/vimconn_openstack.py b/vimconn_openstack.py
deleted file mode 100644 (file)
index b501d9d..0000000
+++ /dev/null
@@ -1,1336 +0,0 @@
-# -*- 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
-##
-
-'''
-osconnector implements all the methods to interact with openstack using the python-client.
-'''
-__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research"
-__date__ ="$22-jun-2014 11:19:29$"
-
-import vimconn
-import json
-import yaml
-import logging
-import netaddr
-import time
-import yaml
-import random
-
-from novaclient import client as nClient_v2, exceptions as nvExceptions
-from novaclient import api_versions
-import keystoneclient.v2_0.client as ksClient_v2
-from novaclient.v2.client import Client as nClient
-import keystoneclient.v3.client as ksClient
-import keystoneclient.exceptions as ksExceptions
-import glanceclient.v2.client as glClient
-import glanceclient.client as gl1Client
-import glanceclient.exc as gl1Exceptions
-import cinderclient.v2.client as cClient_v2
-from httplib import HTTPException
-from neutronclient.neutron import client as neClient_v2
-from neutronclient.v2_0 import client as neClient
-from neutronclient.common import exceptions as neExceptions
-from requests.exceptions import ConnectionError
-
-'''contain the openstack virtual machine status to openmano status'''
-vmStatus2manoFormat={'ACTIVE':'ACTIVE',
-                     'PAUSED':'PAUSED',
-                     'SUSPENDED': 'SUSPENDED',
-                     'SHUTOFF':'INACTIVE',
-                     'BUILD':'BUILD',
-                     'ERROR':'ERROR','DELETED':'DELETED'
-                     }
-netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE','BUILD':'BUILD','ERROR':'ERROR','DELETED':'DELETED'
-                     }
-
-#global var to have a timeout creating and deleting volumes
-volume_timeout = 60
-server_timeout = 60
-
-class vimconnector(vimconn.vimconnector):
-    def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None,
-                 log_level=None, config={}, persistent_info={}):
-        '''using common constructor parameters. In this case
-        'url' is the keystone authorization url,
-        'url_admin' is not use
-        '''
-        self.osc_api_version = 'v2.0'
-        if config.get('APIversion') == 'v3.3':
-            self.osc_api_version = 'v3.3'
-        vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level, config)
-
-        self.persistent_info = persistent_info
-        self.k_creds={}
-        self.n_creds={}
-        if self.config.get("insecure"):
-            self.k_creds["insecure"] = True
-            self.n_creds["insecure"] = True
-        if not url:
-            raise TypeError, 'url param can not be NoneType'
-        self.k_creds['auth_url'] = url
-        self.n_creds['auth_url'] = url
-        if tenant_name:
-            self.k_creds['tenant_name'] = tenant_name
-            self.n_creds['project_id']  = tenant_name
-        if tenant_id:
-            self.k_creds['tenant_id'] = tenant_id
-            self.n_creds['tenant_id']  = tenant_id
-        if user:
-            self.k_creds['username'] = user
-            self.n_creds['username'] = user
-        if passwd:
-            self.k_creds['password'] = passwd
-            self.n_creds['api_key']  = passwd
-        if self.osc_api_version == 'v3.3':
-            self.k_creds['project_name'] = tenant_name
-            self.k_creds['project_id'] = tenant_id
-        if config.get('region_name'):
-            self.k_creds['region_name'] = config.get('region_name')
-            self.n_creds['region_name'] = config.get('region_name')
-
-        self.reload_client       = True
-        self.logger = logging.getLogger('openmano.vim.openstack')
-        if log_level:
-            self.logger.setLevel( getattr(logging, log_level) )
-    
-    def __setitem__(self,index, value):
-        '''Set individuals parameters 
-        Throw TypeError, KeyError
-        '''
-        if index=='tenant_id':
-            self.reload_client=True
-            self.tenant_id = value
-            if self.osc_api_version == 'v3.3':
-                if value:
-                    self.k_creds['project_id'] = value
-                    self.n_creds['project_id']  = value
-                else:
-                    del self.k_creds['project_id']
-                    del self.n_creds['project_id']
-            else:
-                if value:
-                    self.k_creds['tenant_id'] = value
-                    self.n_creds['tenant_id']  = value
-                else:
-                    del self.k_creds['tenant_id']
-                    del self.n_creds['tenant_id']
-        elif index=='tenant_name':
-            self.reload_client=True
-            self.tenant_name = value
-            if self.osc_api_version == 'v3.3':
-                if value:
-                    self.k_creds['project_name'] = value
-                    self.n_creds['project_name']  = value
-                else:
-                    del self.k_creds['project_name']
-                    del self.n_creds['project_name']
-            else:
-                if value:
-                    self.k_creds['tenant_name'] = value
-                    self.n_creds['project_id']  = value
-                else:
-                    del self.k_creds['tenant_name']
-                    del self.n_creds['project_id']
-        elif index=='user':
-            self.reload_client=True
-            self.user = value
-            if value:
-                self.k_creds['username'] = value
-                self.n_creds['username'] = value
-            else:
-                del self.k_creds['username']
-                del self.n_creds['username']
-        elif index=='passwd':
-            self.reload_client=True
-            self.passwd = value
-            if value:
-                self.k_creds['password'] = value
-                self.n_creds['api_key']  = value
-            else:
-                del self.k_creds['password']
-                del self.n_creds['api_key']
-        elif index=='url':
-            self.reload_client=True
-            self.url = value
-            if value:
-                self.k_creds['auth_url'] = value
-                self.n_creds['auth_url'] = value
-            else:
-                raise TypeError, 'url param can not be NoneType'
-        else:
-            vimconn.vimconnector.__setitem__(self,index, value)
-     
-    def _reload_connection(self):
-        '''Called before any operation, it check if credentials has changed
-        Throw keystoneclient.apiclient.exceptions.AuthorizationFailure
-        '''
-        #TODO control the timing and possible token timeout, but it seams that python client does this task for us :-) 
-        if self.reload_client:
-            #test valid params
-            if len(self.n_creds) <4:
-                raise ksExceptions.ClientException("Not enough parameters to connect to openstack")
-            if self.osc_api_version == 'v3.3':
-                self.nova = nClient(api_version=api_versions.APIVersion(version_str='2.0'), **self.n_creds)
-                #TODO To be updated for v3
-                #self.cinder = cClient.Client(**self.n_creds)
-                self.keystone = ksClient.Client(**self.k_creds)
-                self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
-                self.neutron = neClient.Client(api_version=api_versions.APIVersion(version_str='2.0'), endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
-            else:
-                self.nova = nClient_v2.Client(version='2', **self.n_creds)
-                self.cinder = cClient_v2.Client(**self.n_creds)
-                self.keystone = ksClient_v2.Client(**self.k_creds)
-                self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
-                self.neutron = neClient_v2.Client('2.0', endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
-            self.glance_endpoint = self.keystone.service_catalog.url_for(service_type='image', endpoint_type='publicURL')
-            self.glance = glClient.Client(self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds)  #TODO check k_creds vs n_creds
-            self.reload_client = False
-
-    def __net_os2mano(self, net_list_dict):
-        '''Transform the net openstack format to mano format
-        net_list_dict can be a list of dict or a single dict'''
-        if type(net_list_dict) is dict:
-            net_list_=(net_list_dict,)
-        elif type(net_list_dict) is list:
-            net_list_=net_list_dict
-        else:
-            raise TypeError("param net_list_dict must be a list or a dictionary")
-        for net in net_list_:
-            if net.get('provider:network_type') == "vlan":
-                net['type']='data'
-            else:
-                net['type']='bridge'
-                
-                
-            
-    def _format_exception(self, exception):
-        '''Transform a keystone, nova, neutron  exception into a vimconn exception'''
-        if isinstance(exception, (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError,
-                                  ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed
-                                  )):
-            raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))            
-        elif isinstance(exception, (nvExceptions.ClientException, ksExceptions.ClientException, 
-                                    neExceptions.NeutronException, nvExceptions.BadRequest)):
-            raise vimconn.vimconnUnexpectedResponse(type(exception).__name__ + ": " + str(exception))
-        elif isinstance(exception, (neExceptions.NetworkNotFoundClient, nvExceptions.NotFound)):
-            raise vimconn.vimconnNotFoundException(type(exception).__name__ + ": " + str(exception))
-        elif isinstance(exception, nvExceptions.Conflict):
-            raise vimconn.vimconnConflictException(type(exception).__name__ + ": " + str(exception))
-        else: # ()
-            raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))
-
-    def get_tenant_list(self, filter_dict={}):
-        '''Obtain tenants of VIM
-        filter_dict can contain the following keys:
-            name: filter by tenant name
-            id: filter by tenant uuid/id
-            <other VIM specific>
-        Returns the tenant list of dictionaries: [{'name':'<name>, 'id':'<id>, ...}, ...]
-        '''
-        self.logger.debug("Getting tenants from VIM filter: '%s'", str(filter_dict))
-        try:
-            self._reload_connection()
-            if self.osc_api_version == 'v3.3':
-                project_class_list=self.keystone.projects.findall(**filter_dict)
-            else:
-                project_class_list=self.keystone.tenants.findall(**filter_dict)
-            project_list=[]
-            for project in project_class_list:
-                project_list.append(project.to_dict())
-            return project_list
-        except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError)  as e:
-            self._format_exception(e)
-
-    def new_tenant(self, tenant_name, tenant_description):
-        '''Adds a new tenant to openstack VIM. Returns the tenant identifier'''
-        self.logger.debug("Adding a new tenant name: %s", tenant_name)
-        try:
-            self._reload_connection()
-            if self.osc_api_version == 'v3.3':
-                project=self.keystone.projects.create(tenant_name, tenant_description)
-            else:
-                project=self.keystone.tenants.create(tenant_name, tenant_description)
-            return project.id
-        except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError)  as e:
-            self._format_exception(e)
-
-    def delete_tenant(self, tenant_id):
-        '''Delete a tenant from openstack VIM. Returns the old tenant identifier'''
-        self.logger.debug("Deleting tenant %s from VIM", tenant_id)
-        try:
-            self._reload_connection()
-            if self.osc_api_version == 'v3.3':
-                self.keystone.projects.delete(tenant_id)
-            else:
-                self.keystone.tenants.delete(tenant_id)
-            return tenant_id
-        except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError)  as e:
-            self._format_exception(e)
-
-    def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None):
-        '''Adds a tenant network to VIM. Returns the network identifier'''
-        self.logger.debug("Adding a new network to VIM name '%s', type '%s'", net_name, net_type)
-        #self.logger.debug(">>>>>>>>>>>>>>>>>> IP profile %s", str(ip_profile))
-        try:
-            new_net = None
-            self._reload_connection()
-            network_dict = {'name': net_name, 'admin_state_up': True}
-            if net_type=="data" or net_type=="ptp":
-                if self.config.get('dataplane_physical_net') == None:
-                    raise vimconn.vimconnConflictException("You must provide a 'dataplane_physical_net' at config value before creating sriov network")
-                network_dict["provider:physical_network"] = self.config['dataplane_physical_net'] #"physnet_sriov" #TODO physical
-                network_dict["provider:network_type"]     = "vlan"
-                if vlan!=None:
-                    network_dict["provider:network_type"] = vlan
-            network_dict["shared"]=shared
-            new_net=self.neutron.create_network({'network':network_dict})
-            #print new_net
-            #create subnetwork, even if there is no profile
-            if not ip_profile:
-                ip_profile = {}
-            if 'subnet_address' not in ip_profile:
-                #Fake subnet is required
-                subnet_rand = random.randint(0, 255)
-                ip_profile['subnet_address'] = "192.168.{}.0/24".format(subnet_rand)
-            if 'ip_version' not in ip_profile: 
-                ip_profile['ip_version'] = "IPv4"
-            subnet={"name":net_name+"-subnet",
-                    "network_id": new_net["network"]["id"],
-                    "ip_version": 4 if ip_profile['ip_version']=="IPv4" else 6,
-                    "cidr": ip_profile['subnet_address']
-                    }
-            if 'gateway_address' in ip_profile:
-                subnet['gateway_ip'] = ip_profile['gateway_address']
-            if ip_profile.get('dns_address'):
-                #TODO: manage dns_address as a list of addresses separated by commas 
-                subnet['dns_nameservers'] = []
-                subnet['dns_nameservers'].append(ip_profile['dns_address'])
-            if 'dhcp_enabled' in ip_profile:
-                subnet['enable_dhcp'] = False if ip_profile['dhcp_enabled']=="false" else True
-            if 'dhcp_start_address' in ip_profile:
-                subnet['allocation_pools']=[]
-                subnet['allocation_pools'].append(dict())
-                subnet['allocation_pools'][0]['start'] = ip_profile['dhcp_start_address']
-            if 'dhcp_count' in ip_profile:
-                #parts = ip_profile['dhcp_start_address'].split('.')
-                #ip_int = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3])
-                ip_int = int(netaddr.IPAddress(ip_profile['dhcp_start_address']))
-                ip_int += ip_profile['dhcp_count'] - 1
-                ip_str = str(netaddr.IPAddress(ip_int))
-                subnet['allocation_pools'][0]['end'] = ip_str
-            #self.logger.debug(">>>>>>>>>>>>>>>>>> Subnet: %s", str(subnet))
-            self.neutron.create_subnet({"subnet": subnet} )
-            return new_net["network"]["id"]
-        except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
-            if new_net:
-                self.neutron.delete_network(new_net['network']['id'])
-            self._format_exception(e)
-
-    def get_network_list(self, filter_dict={}):
-        '''Obtain tenant networks of VIM
-        Filter_dict can be:
-            name: network name
-            id: network uuid
-            shared: boolean
-            tenant_id: tenant
-            admin_state_up: boolean
-            status: 'ACTIVE'
-        Returns the network list of dictionaries
-        '''
-        self.logger.debug("Getting network from VIM filter: '%s'", str(filter_dict))
-        try:
-            self._reload_connection()
-            if self.osc_api_version == 'v3.3' and "tenant_id" in filter_dict:
-                filter_dict['project_id'] = filter_dict.pop('tenant_id')
-            net_dict=self.neutron.list_networks(**filter_dict)
-            net_list=net_dict["networks"]
-            self.__net_os2mano(net_list)
-            return net_list
-        except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
-            self._format_exception(e)
-
-    def get_network(self, net_id):
-        '''Obtain details of network from VIM
-        Returns the network information from a network id'''
-        self.logger.debug(" Getting tenant network %s from VIM", net_id)
-        filter_dict={"id": net_id}
-        net_list = self.get_network_list(filter_dict)
-        if len(net_list)==0:
-            raise vimconn.vimconnNotFoundException("Network '{}' not found".format(net_id))
-        elif len(net_list)>1:
-            raise vimconn.vimconnConflictException("Found more than one network with this criteria")
-        net = net_list[0]
-        subnets=[]
-        for subnet_id in net.get("subnets", () ):
-            try:
-                subnet = self.neutron.show_subnet(subnet_id)
-            except Exception as e:
-                self.logger.error("osconnector.get_network(): Error getting subnet %s %s" % (net_id, str(e)))
-                subnet = {"id": subnet_id, "fault": str(e)}
-            subnets.append(subnet)
-        net["subnets"] = subnets
-        return net
-
-    def delete_network(self, net_id):
-        '''Deletes a tenant network from VIM. Returns the old network identifier'''
-        self.logger.debug("Deleting network '%s' from VIM", net_id)
-        try:
-            self._reload_connection()
-            #delete VM ports attached to this networks before the network
-            ports = self.neutron.list_ports(network_id=net_id)
-            for p in ports['ports']:
-                try:
-                    self.neutron.delete_port(p["id"])
-                except Exception as e:
-                    self.logger.error("Error deleting port %s: %s", p["id"], str(e))
-            self.neutron.delete_network(net_id)
-            return net_id
-        except (neExceptions.ConnectionFailed, neExceptions.NetworkNotFoundClient, neExceptions.NeutronException,
-                ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
-            self._format_exception(e)
-
-    def refresh_nets_status(self, net_list):
-        '''Get the status of the networks
-           Params: the list of network identifiers
-           Returns a dictionary with:
-                net_id:         #VIM id of this network
-                    status:     #Mandatory. Text with one of:
-                                #  DELETED (not found at vim)
-                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
-                                #  OTHER (Vim reported other status not understood)
-                                #  ERROR (VIM indicates an ERROR status)
-                                #  ACTIVE, INACTIVE, DOWN (admin down), 
-                                #  BUILD (on building process)
-                                #
-                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
-                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
-
-        '''        
-        net_dict={}
-        for net_id in net_list:
-            net = {}
-            try:
-                net_vim = self.get_network(net_id)
-                if net_vim['status'] in netStatus2manoFormat:
-                    net["status"] = netStatus2manoFormat[ net_vim['status'] ]
-                else:
-                    net["status"] = "OTHER"
-                    net["error_msg"] = "VIM status reported " + net_vim['status']
-                    
-                if net['status'] == "ACTIVE" and not net_vim['admin_state_up']:
-                    net['status'] = 'DOWN'
-                try:
-                    net['vim_info'] = yaml.safe_dump(net_vim, default_flow_style=True, width=256)
-                except yaml.representer.RepresenterError:
-                    net['vim_info'] = str(net_vim)
-                if net_vim.get('fault'):  #TODO
-                    net['error_msg'] = str(net_vim['fault'])
-            except vimconn.vimconnNotFoundException as e:
-                self.logger.error("Exception getting net status: %s", str(e))
-                net['status'] = "DELETED"
-                net['error_msg'] = str(e)
-            except vimconn.vimconnException as e:
-                self.logger.error("Exception getting net status: %s", str(e))
-                net['status'] = "VIM_ERROR"
-                net['error_msg'] = str(e)
-            net_dict[net_id] = net
-        return net_dict
-
-    def get_flavor(self, flavor_id):
-        '''Obtain flavor details from the  VIM. Returns the flavor dict details'''
-        self.logger.debug("Getting flavor '%s'", flavor_id)
-        try:
-            self._reload_connection()
-            flavor = self.nova.flavors.find(id=flavor_id)
-            #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
-            return flavor.to_dict()
-        except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
-            self._format_exception(e)
-
-    def get_flavor_id_from_data(self, flavor_dict):
-        """Obtain flavor id that match the flavor description
-           Returns the flavor_id or raises a vimconnNotFoundException
-        """
-        try:
-            self._reload_connection()
-            numa=None
-            numas = flavor_dict.get("extended",{}).get("numas")
-            if numas:
-                #TODO
-                raise vimconn.vimconnNotFoundException("Flavor with EPA still not implemted")
-                # if len(numas) > 1:
-                #     raise vimconn.vimconnNotFoundException("Cannot find any flavor with more than one numa")
-                # numa=numas[0]
-                # numas = extended.get("numas")
-            for flavor in self.nova.flavors.list():
-                epa = flavor.get_keys()
-                if epa:
-                    continue
-                    #TODO 
-                if flavor.ram != flavor_dict["ram"]:
-                    continue
-                if flavor.vcpus != flavor_dict["vcpus"]:
-                    continue
-                if flavor.disk != flavor_dict["disk"]:
-                    continue
-                return flavor.id
-            raise vimconn.vimconnNotFoundException("Cannot find any flavor matching '{}'".format(str(flavor_dict)))
-        except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
-            self._format_exception(e)
-
-
-    def new_flavor(self, flavor_data, change_name_if_used=True):
-        '''Adds a tenant flavor to openstack VIM
-        if change_name_if_used is True, it will change name in case of conflict, because it is not supported name repetition
-        Returns the flavor identifier
-        '''
-        self.logger.debug("Adding flavor '%s'", str(flavor_data))
-        retry=0
-        max_retries=3
-        name_suffix = 0
-        name=flavor_data['name']
-        while retry<max_retries:
-            retry+=1
-            try:
-                self._reload_connection()
-                if change_name_if_used:
-                    #get used names
-                    fl_names=[]
-                    fl=self.nova.flavors.list()
-                    for f in fl:
-                        fl_names.append(f.name)
-                    while name in fl_names:
-                        name_suffix += 1
-                        name = flavor_data['name']+"-" + str(name_suffix)
-                        
-                ram = flavor_data.get('ram',64)
-                vcpus = flavor_data.get('vcpus',1)
-                numa_properties=None
-
-                extended = flavor_data.get("extended")
-                if extended:
-                    numas=extended.get("numas")
-                    if numas:
-                        numa_nodes = len(numas)
-                        if numa_nodes > 1:
-                            return -1, "Can not add flavor with more than one numa"
-                        numa_properties = {"hw:numa_nodes":str(numa_nodes)}
-                        numa_properties["hw:mem_page_size"] = "large"
-                        numa_properties["hw:cpu_policy"] = "dedicated"
-                        numa_properties["hw:numa_mempolicy"] = "strict"
-                        for numa in numas:
-                            #overwrite ram and vcpus
-                            ram = numa['memory']*1024
-                            if 'paired-threads' in numa:
-                                vcpus = numa['paired-threads']*2
-                                numa_properties["hw:cpu_threads_policy"] = "prefer"
-                            elif 'cores' in numa:
-                                vcpus = numa['cores']
-                                #numa_properties["hw:cpu_threads_policy"] = "prefer"
-                            elif 'threads' in numa:
-                                vcpus = numa['threads']
-                                numa_properties["hw:cpu_policy"] = "isolated"
-                            for interface in numa.get("interfaces",() ):
-                                if interface["dedicated"]=="yes":
-                                    raise vimconn.vimconnException("Passthrough interfaces are not supported for the openstack connector", http_code=vimconn.HTTP_Service_Unavailable)
-                                #TODO, add the key 'pci_passthrough:alias"="<label at config>:<number ifaces>"' when a way to connect it is available
-                                
-                #create flavor                 
-                new_flavor=self.nova.flavors.create(name, 
-                                ram, 
-                                vcpus, 
-                                flavor_data.get('disk',1),
-                                is_public=flavor_data.get('is_public', True)
-                            ) 
-                #add metadata
-                if numa_properties:
-                    new_flavor.set_keys(numa_properties)
-                return new_flavor.id
-            except nvExceptions.Conflict as e:
-                if change_name_if_used and retry < max_retries:
-                    continue
-                self._format_exception(e)
-            #except nvExceptions.BadRequest as e:
-            except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
-                self._format_exception(e)
-
-    def delete_flavor(self,flavor_id):
-        '''Deletes a tenant flavor from openstack VIM. Returns the old flavor_id
-        '''
-        try:
-            self._reload_connection()
-            self.nova.flavors.delete(flavor_id)
-            return flavor_id
-        #except nvExceptions.BadRequest as e:
-        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
-            self._format_exception(e)
-
-    def new_image(self,image_dict):
-        '''
-        Adds a tenant image to VIM. imge_dict is a dictionary with:
-            name: name
-            disk_format: qcow2, vhd, vmdk, raw (by default), ...
-            location: path or URI
-            public: "yes" or "no"
-            metadata: metadata of the image
-        Returns the image_id
-        '''
-        #using version 1 of glance client
-        glancev1 = gl1Client.Client('1',self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds)  #TODO check k_creds vs n_creds
-        retry=0
-        max_retries=3
-        while retry<max_retries:
-            retry+=1
-            try:
-                self._reload_connection()
-                #determine format  http://docs.openstack.org/developer/glance/formats.html
-                if "disk_format" in image_dict:
-                    disk_format=image_dict["disk_format"]
-                else: #autodiscover based on extension
-                    if image_dict['location'][-6:]==".qcow2":
-                        disk_format="qcow2"
-                    elif image_dict['location'][-4:]==".vhd":
-                        disk_format="vhd"
-                    elif image_dict['location'][-5:]==".vmdk":
-                        disk_format="vmdk"
-                    elif image_dict['location'][-4:]==".vdi":
-                        disk_format="vdi"
-                    elif image_dict['location'][-4:]==".iso":
-                        disk_format="iso"
-                    elif image_dict['location'][-4:]==".aki":
-                        disk_format="aki"
-                    elif image_dict['location'][-4:]==".ari":
-                        disk_format="ari"
-                    elif image_dict['location'][-4:]==".ami":
-                        disk_format="ami"
-                    else:
-                        disk_format="raw"
-                self.logger.debug("new_image: '%s' loading from '%s'", image_dict['name'], image_dict['location'])
-                if image_dict['location'][0:4]=="http":
-                    new_image = glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
-                            container_format="bare", location=image_dict['location'], disk_format=disk_format)
-                else: #local path
-                    with open(image_dict['location']) as fimage:
-                        new_image = glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
-                            container_format="bare", data=fimage, disk_format=disk_format)
-                #insert metadata. We cannot use 'new_image.properties.setdefault' 
-                #because nova and glance are "INDEPENDENT" and we are using nova for reading metadata
-                new_image_nova=self.nova.images.find(id=new_image.id)
-                new_image_nova.metadata.setdefault('location',image_dict['location'])
-                metadata_to_load = image_dict.get('metadata')
-                if metadata_to_load:
-                    for k,v in yaml.load(metadata_to_load).iteritems():
-                        new_image_nova.metadata.setdefault(k,v)
-                return new_image.id
-            except (nvExceptions.Conflict, ksExceptions.ClientException, nvExceptions.ClientException) as e:
-                self._format_exception(e)
-            except (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError, ConnectionError) as e:
-                if retry==max_retries:
-                    continue
-                self._format_exception(e)
-            except IOError as e:  #can not open the file
-                raise vimconn.vimconnConnectionException(type(e).__name__ + ": " + str(e)+ " for " + image_dict['location'],
-                                                         http_code=vimconn.HTTP_Bad_Request)
-     
-    def delete_image(self, image_id):
-        '''Deletes a tenant image from openstack VIM. Returns the old id
-        '''
-        try:
-            self._reload_connection()
-            self.nova.images.delete(image_id)
-            return image_id
-        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e: #TODO remove
-            self._format_exception(e)
-
-    def get_image_id_from_path(self, path):
-        '''Get the image id from image path in the VIM database. Returns the image_id''' 
-        try:
-            self._reload_connection()
-            images = self.nova.images.list()
-            for image in images:
-                if image.metadata.get("location")==path:
-                    return image.id
-            raise vimconn.vimconnNotFoundException("image with location '{}' not found".format( path))
-        except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
-            self._format_exception(e)
-        
-    def get_image_list(self, filter_dict={}):
-        '''Obtain tenant images from VIM
-        Filter_dict can be:
-            id: image id
-            name: image name
-            checksum: image checksum
-        Returns the image list of dictionaries:
-            [{<the fields at Filter_dict plus some VIM specific>}, ...]
-            List can be empty
-        '''
-        self.logger.debug("Getting image list from VIM filter: '%s'", str(filter_dict))
-        try:
-            self._reload_connection()
-            filter_dict_os=filter_dict.copy()
-            #First we filter by the available filter fields: name, id. The others are removed.
-            filter_dict_os.pop('checksum',None)
-            image_list=self.nova.images.findall(**filter_dict_os)
-            if len(image_list)==0:
-                return []
-            #Then we filter by the rest of filter fields: checksum
-            filtered_list = []
-            for image in image_list:
-                image_class=self.glance.images.get(image.id)
-                if 'checksum' not in filter_dict or image_class['checksum']==filter_dict.get('checksum'):
-                    filtered_list.append(image_class.copy())
-            return filtered_list
-        except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
-            self._format_exception(e)
-
-    def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None,disk_list=None):
-        '''Adds a VM instance to VIM
-        Params:
-            start: indicates if VM must start or boot in pause mode. Ignored
-            image_id,flavor_id: iamge and flavor uuid
-            net_list: list of interfaces, each one is a dictionary with:
-                name:
-                net_id: network uuid to connect
-                vpci: virtual vcpi to assign, ignored because openstack lack #TODO
-                model: interface model, ignored #TODO
-                mac_address: used for  SR-IOV ifaces #TODO for other types
-                use: 'data', 'bridge',  'mgmt'
-                type: 'virtual', 'PF', 'VF', 'VFnotShared'
-                vim_id: filled/added by this function
-                floating_ip: True/False (or it can be None)
-                #TODO ip, security groups
-        Returns the instance identifier
-        '''
-        self.logger.debug("new_vminstance input: image='%s' flavor='%s' nics='%s'",image_id, flavor_id,str(net_list))
-        try:
-            metadata={}
-            net_list_vim=[]
-            external_network=[] #list of external networks to be connected to instance, later on used to create floating_ip
-            self._reload_connection()
-            metadata_vpci={} #For a specific neutron plugin 
-            for net in net_list:
-                if not net.get("net_id"): #skip non connected iface
-                    continue
-                if net["type"]=="virtual" or net["type"]=="VF":
-                    port_dict={
-                        "network_id": net["net_id"],
-                        "name": net.get("name"),
-                        "admin_state_up": True
-                    }    
-                    if net["type"]=="virtual":
-                        if "vpci" in net:
-                            metadata_vpci[ net["net_id"] ] = [[ net["vpci"], "" ]]
-                    else: # for VF
-                        if "vpci" in net:
-                            if "VF" not in metadata_vpci:
-                                metadata_vpci["VF"]=[]
-                            metadata_vpci["VF"].append([ net["vpci"], "" ])
-                        port_dict["binding:vnic_type"]="direct"
-                    if not port_dict["name"]:
-                        port_dict["name"]=name
-                    if net.get("mac_address"):
-                        port_dict["mac_address"]=net["mac_address"]
-                    if net.get("port_security") == False:
-                        port_dict["port_security_enabled"]=net["port_security"]
-                    new_port = self.neutron.create_port({"port": port_dict })
-                    net["mac_adress"] = new_port["port"]["mac_address"]
-                    net["vim_id"] = new_port["port"]["id"]
-                    net["ip"] = new_port["port"].get("fixed_ips", [{}])[0].get("ip_address")
-                    net_list_vim.append({"port-id": new_port["port"]["id"]})
-                else:   # for PF
-                    self.logger.warn("new_vminstance: Warning, can not connect a passthrough interface ")
-                    #TODO insert this when openstack consider passthrough ports as openstack neutron ports
-                if net.get('floating_ip', False):
-                    net['exit_on_floating_ip_error'] = True
-                    external_network.append(net)
-                elif net['use'] == 'mgmt' and self.config.get('use_floating_ip'):
-                    net['exit_on_floating_ip_error'] = False
-                    external_network.append(net)
-
-            if metadata_vpci:
-                metadata = {"pci_assignement": json.dumps(metadata_vpci)}
-                if len(metadata["pci_assignement"]) >255:
-                    #limit the metadata size
-                    #metadata["pci_assignement"] = metadata["pci_assignement"][0:255]
-                    self.logger.warn("Metadata deleted since it exceeds the expected length (255) ")
-                    metadata = {}
-            
-            self.logger.debug("name '%s' image_id '%s'flavor_id '%s' net_list_vim '%s' description '%s' metadata %s",
-                              name, image_id, flavor_id, str(net_list_vim), description, str(metadata))
-            
-            security_groups   = self.config.get('security_groups')
-            if type(security_groups) is str:
-                security_groups = ( security_groups, )
-            #cloud config
-            userdata=None
-            config_drive = None
-            if isinstance(cloud_config, dict):
-                if cloud_config.get("user-data"):
-                    userdata=cloud_config["user-data"]
-                if cloud_config.get("boot-data-drive") != None:
-                    config_drive = cloud_config["boot-data-drive"]
-                if cloud_config.get("config-files") or cloud_config.get("users") or cloud_config.get("key-pairs"):
-                    if userdata:
-                        raise vimconn.vimconnConflictException("Cloud-config cannot contain both 'userdata' and 'config-files'/'users'/'key-pairs'")
-                    userdata_dict={}
-                    #default user
-                    if cloud_config.get("key-pairs"):
-                        userdata_dict["ssh-authorized-keys"] = cloud_config["key-pairs"]
-                        userdata_dict["users"] = [{"default": None, "ssh-authorized-keys": cloud_config["key-pairs"] }]
-                    if cloud_config.get("users"):
-                        if "users" not in userdata_dict:
-                            userdata_dict["users"] = [ "default" ]
-                        for user in cloud_config["users"]:
-                            user_info = {
-                                "name" : user["name"],
-                                "sudo": "ALL = (ALL)NOPASSWD:ALL"
-                            }
-                            if "user-info" in user:
-                                user_info["gecos"] = user["user-info"]
-                            if user.get("key-pairs"):
-                                user_info["ssh-authorized-keys"] = user["key-pairs"]
-                            userdata_dict["users"].append(user_info)
-
-                    if cloud_config.get("config-files"):
-                        userdata_dict["write_files"] = []
-                        for file in cloud_config["config-files"]:
-                            file_info = {
-                                "path" : file["dest"],
-                                "content": file["content"]
-                            }
-                            if file.get("encoding"):
-                                file_info["encoding"] = file["encoding"]
-                            if file.get("permissions"):
-                                file_info["permissions"] = file["permissions"]
-                            if file.get("owner"):
-                                file_info["owner"] = file["owner"]
-                            userdata_dict["write_files"].append(file_info)
-                    userdata = "#cloud-config\n"
-                    userdata += yaml.safe_dump(userdata_dict, indent=4, default_flow_style=False)
-                self.logger.debug("userdata: %s", userdata)
-            elif isinstance(cloud_config, str):
-                userdata = cloud_config
-
-            #Create additional volumes in case these are present in disk_list
-            block_device_mapping = None
-            base_disk_index = ord('b')
-            if disk_list != None:
-                block_device_mapping = dict()
-                for disk in disk_list:
-                    if 'image_id' in disk:
-                        volume = self.cinder.volumes.create(size = disk['size'],name = name + '_vd' +
-                                    chr(base_disk_index), imageRef = disk['image_id'])
-                    else:
-                        volume = self.cinder.volumes.create(size=disk['size'], name=name + '_vd' +
-                                    chr(base_disk_index))
-                    block_device_mapping['_vd' +  chr(base_disk_index)] = volume.id
-                    base_disk_index += 1
-
-                #wait until volumes are with status available
-                keep_waiting = True
-                elapsed_time = 0
-                while keep_waiting and elapsed_time < volume_timeout:
-                    keep_waiting = False
-                    for volume_id in block_device_mapping.itervalues():
-                        if self.cinder.volumes.get(volume_id).status != 'available':
-                            keep_waiting = True
-                    if keep_waiting:
-                        time.sleep(1)
-                        elapsed_time += 1
-
-                #if we exceeded the timeout rollback
-                if elapsed_time >= volume_timeout:
-                    #delete the volumes we just created
-                    for volume_id in block_device_mapping.itervalues():
-                        self.cinder.volumes.delete(volume_id)
-
-                    #delete ports we just created
-                    for net_item  in net_list_vim:
-                        if 'port-id' in net_item:
-                            self.neutron.delete_port(net_item['port-id'])
-
-                    raise vimconn.vimconnException('Timeout creating volumes for instance ' + name,
-                                                   http_code=vimconn.HTTP_Request_Timeout)
-
-            server = self.nova.servers.create(name, image_id, flavor_id, nics=net_list_vim, meta=metadata,
-                                              security_groups=security_groups,
-                                              availability_zone=self.config.get('availability_zone'),
-                                              key_name=self.config.get('keypair'),
-                                              userdata=userdata,
-                                              config_drive = config_drive,
-                                              block_device_mapping = block_device_mapping
-                                              )  # , description=description)
-            #print "DONE :-)", server
-            pool_id = None
-            floating_ips = self.neutron.list_floatingips().get("floatingips", ())
-            for floating_network in external_network:
-                try:
-                    # wait until vm is active
-                    elapsed_time = 0
-                    while elapsed_time < server_timeout:
-                        status = self.nova.servers.get(server.id).status
-                        if status == 'ACTIVE':
-                            break
-                        time.sleep(1)
-                        elapsed_time += 1
-
-                    #if we exceeded the timeout rollback
-                    if elapsed_time >= server_timeout:
-                        raise vimconn.vimconnException('Timeout creating instance ' + name,
-                                                       http_code=vimconn.HTTP_Request_Timeout)
-
-                    assigned = False
-                    while(assigned == False):
-                        if floating_ips:
-                            ip = floating_ips.pop(0)
-                            if not ip.get("port_id", False) and ip.get('tenant_id') == server.tenant_id:
-                                free_floating_ip = ip.get("floating_ip_address")
-                                try:
-                                    fix_ip = floating_network.get('ip')
-                                    server.add_floating_ip(free_floating_ip, fix_ip)
-                                    assigned = True
-                                except Exception as e:
-                                    raise vimconn.vimconnException(type(e).__name__ + ": Cannot create floating_ip "+  str(e), http_code=vimconn.HTTP_Conflict)
-                        else:
-                            #Find the external network
-                            external_nets = list()
-                            for net in self.neutron.list_networks()['networks']:
-                                if net['router:external']:
-                                        external_nets.append(net)
-
-                            if len(external_nets) == 0:
-                                raise vimconn.vimconnException("Cannot create floating_ip automatically since no external "
-                                                               "network is present",
-                                                                http_code=vimconn.HTTP_Conflict)
-                            if len(external_nets) > 1:
-                                raise vimconn.vimconnException("Cannot create floating_ip automatically since multiple "
-                                                               "external networks are present",
-                                                               http_code=vimconn.HTTP_Conflict)
-
-                            pool_id = external_nets[0].get('id')
-                            param = {'floatingip': {'floating_network_id': pool_id, 'tenant_id': server.tenant_id}}
-                            try:
-                                #self.logger.debug("Creating floating IP")
-                                new_floating_ip = self.neutron.create_floatingip(param)
-                                free_floating_ip = new_floating_ip['floatingip']['floating_ip_address']
-                                fix_ip = floating_network.get('ip')
-                                server.add_floating_ip(free_floating_ip, fix_ip)
-                                assigned=True
-                            except Exception as e:
-                                raise vimconn.vimconnException(type(e).__name__ + ": Cannot assign floating_ip "+  str(e), http_code=vimconn.HTTP_Conflict)
-                except Exception as e:
-                    if not floating_network['exit_on_floating_ip_error']:
-                        self.logger.warn("Cannot create floating_ip. %s", str(e))
-                        continue
-                    self.delete_vminstance(server.id)
-                    raise
-
-            return server.id
-#        except nvExceptions.NotFound as e:
-#            error_value=-vimconn.HTTP_Not_Found
-#            error_text= "vm instance %s not found" % vm_id
-        except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
-            # delete the volumes we just created
-            if block_device_mapping != None:
-                for volume_id in block_device_mapping.itervalues():
-                    self.cinder.volumes.delete(volume_id)
-
-            # delete ports we just created
-            for net_item in net_list_vim:
-                if 'port-id' in net_item:
-                    self.neutron.delete_port(net_item['port-id'])
-            self._format_exception(e)
-        except TypeError as e:
-            raise vimconn.vimconnException(type(e).__name__ + ": "+  str(e), http_code=vimconn.HTTP_Bad_Request)
-
-    def get_vminstance(self,vm_id):
-        '''Returns the VM instance information from VIM'''
-        #self.logger.debug("Getting VM from VIM")
-        try:
-            self._reload_connection()
-            server = self.nova.servers.find(id=vm_id)
-            #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
-            return server.to_dict()
-        except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e:
-            self._format_exception(e)
-
-    def get_vminstance_console(self,vm_id, console_type="vnc"):
-        '''
-        Get a console for the virtual machine
-        Params:
-            vm_id: uuid of the VM
-            console_type, can be:
-                "novnc" (by default), "xvpvnc" for VNC types, 
-                "rdp-html5" for RDP types, "spice-html5" for SPICE types
-        Returns dict with the console parameters:
-                protocol: ssh, ftp, http, https, ...
-                server:   usually ip address 
-                port:     the http, ssh, ... port 
-                suffix:   extra text, e.g. the http path and query string   
-        '''
-        self.logger.debug("Getting VM CONSOLE from VIM")
-        try:
-            self._reload_connection()
-            server = self.nova.servers.find(id=vm_id)
-            if console_type == None or console_type == "novnc":
-                console_dict = server.get_vnc_console("novnc")
-            elif console_type == "xvpvnc":
-                console_dict = server.get_vnc_console(console_type)
-            elif console_type == "rdp-html5":
-                console_dict = server.get_rdp_console(console_type)
-            elif console_type == "spice-html5":
-                console_dict = server.get_spice_console(console_type)
-            else:
-                raise vimconn.vimconnException("console type '{}' not allowed".format(console_type), http_code=vimconn.HTTP_Bad_Request)
-            
-            console_dict1 = console_dict.get("console")
-            if console_dict1:
-                console_url = console_dict1.get("url")
-                if console_url:
-                    #parse console_url
-                    protocol_index = console_url.find("//")
-                    suffix_index = console_url[protocol_index+2:].find("/") + protocol_index+2
-                    port_index = console_url[protocol_index+2:suffix_index].find(":") + protocol_index+2
-                    if protocol_index < 0 or port_index<0 or suffix_index<0:
-                        return -vimconn.HTTP_Internal_Server_Error, "Unexpected response from VIM"
-                    console_dict={"protocol": console_url[0:protocol_index],
-                                  "server":   console_url[protocol_index+2:port_index], 
-                                  "port":     console_url[port_index:suffix_index], 
-                                  "suffix":   console_url[suffix_index+1:] 
-                                  }
-                    protocol_index += 2
-                    return console_dict
-            raise vimconn.vimconnUnexpectedResponse("Unexpected response from VIM")
-            
-        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.BadRequest, ConnectionError) as e:
-            self._format_exception(e)
-
-    def delete_vminstance(self, vm_id):
-        '''Removes a VM instance from VIM. Returns the old identifier
-        '''
-        #print "osconnector: Getting VM from VIM"
-        try:
-            self._reload_connection()
-            #delete VM ports attached to this networks before the virtual machine
-            ports = self.neutron.list_ports(device_id=vm_id)
-            for p in ports['ports']:
-                try:
-                    self.neutron.delete_port(p["id"])
-                except Exception as e:
-                    self.logger.error("Error deleting port: " + type(e).__name__ + ": "+  str(e))
-
-            #commented because detaching the volumes makes the servers.delete not work properly ?!?
-            #dettach volumes attached
-            server = self.nova.servers.get(vm_id)
-            volumes_attached_dict = server._info['os-extended-volumes:volumes_attached']
-            #for volume in volumes_attached_dict:
-            #    self.cinder.volumes.detach(volume['id'])
-
-            self.nova.servers.delete(vm_id)
-
-            #delete volumes.
-            #Although having detached them should have them  in active status
-            #we ensure in this loop
-            keep_waiting = True
-            elapsed_time = 0
-            while keep_waiting and elapsed_time < volume_timeout:
-                keep_waiting = False
-                for volume in volumes_attached_dict:
-                    if self.cinder.volumes.get(volume['id']).status != 'available':
-                        keep_waiting = True
-                    else:
-                        self.cinder.volumes.delete(volume['id'])
-                if keep_waiting:
-                    time.sleep(1)
-                    elapsed_time += 1
-
-            return vm_id
-        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
-            self._format_exception(e)
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-
-    def refresh_vms_status(self, vm_list):
-        '''Get the status of the virtual machines and their interfaces/ports
-           Params: the list of VM identifiers
-           Returns a dictionary with:
-                vm_id:          #VIM id of this Virtual Machine
-                    status:     #Mandatory. Text with one of:
-                                #  DELETED (not found at vim)
-                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
-                                #  OTHER (Vim reported other status not understood)
-                                #  ERROR (VIM indicates an ERROR status)
-                                #  ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running), 
-                                #  CREATING (on building process), ERROR
-                                #  ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
-                                #
-                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
-                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
-                    interfaces:
-                     -  vim_info:         #Text with plain information obtained from vim (yaml.safe_dump)
-                        mac_address:      #Text format XX:XX:XX:XX:XX:XX
-                        vim_net_id:       #network id where this interface is connected
-                        vim_interface_id: #interface/port VIM id
-                        ip_address:       #null, or text with IPv4, IPv6 address
-        '''
-        vm_dict={}
-        self.logger.debug("refresh_vms status: Getting tenant VM instance information from VIM")
-        for vm_id in vm_list:
-            vm={}
-            try:
-                vm_vim = self.get_vminstance(vm_id)
-                if vm_vim['status'] in vmStatus2manoFormat:
-                    vm['status']    =  vmStatus2manoFormat[ vm_vim['status'] ]
-                else:
-                    vm['status']    = "OTHER"
-                    vm['error_msg'] = "VIM status reported " + vm_vim['status']
-                try:
-                    vm['vim_info']  = yaml.safe_dump(vm_vim, default_flow_style=True, width=256)
-                except yaml.representer.RepresenterError:
-                    vm['vim_info'] = str(vm_vim)
-                vm["interfaces"] = []
-                if vm_vim.get('fault'):
-                    vm['error_msg'] = str(vm_vim['fault'])
-                #get interfaces
-                try:
-                    self._reload_connection()
-                    port_dict=self.neutron.list_ports(device_id=vm_id)
-                    for port in port_dict["ports"]:
-                        interface={}
-                        try:
-                            interface['vim_info'] = yaml.safe_dump(port, default_flow_style=True, width=256)
-                        except yaml.representer.RepresenterError:
-                            interface['vim_info'] = str(port)
-                        interface["mac_address"] = port.get("mac_address")
-                        interface["vim_net_id"] = port["network_id"]
-                        interface["vim_interface_id"] = port["id"]
-                        ips=[]
-                        #look for floating ip address
-                        floating_ip_dict = self.neutron.list_floatingips(port_id=port["id"])
-                        if floating_ip_dict.get("floatingips"):
-                            ips.append(floating_ip_dict["floatingips"][0].get("floating_ip_address") )
-
-                        for subnet in port["fixed_ips"]:
-                            ips.append(subnet["ip_address"])
-                        interface["ip_address"] = ";".join(ips)
-                        vm["interfaces"].append(interface)
-                except Exception as e:
-                    self.logger.error("Error getting vm interface information " + type(e).__name__ + ": "+  str(e))
-            except vimconn.vimconnNotFoundException as e:
-                self.logger.error("Exception getting vm status: %s", str(e))
-                vm['status'] = "DELETED"
-                vm['error_msg'] = str(e)
-            except vimconn.vimconnException as e:
-                self.logger.error("Exception getting vm status: %s", str(e))
-                vm['status'] = "VIM_ERROR"
-                vm['error_msg'] = str(e)
-            vm_dict[vm_id] = vm
-        return vm_dict
-    
-    def action_vminstance(self, vm_id, action_dict):
-        '''Send and action over a VM instance from VIM
-        Returns the vm_id if the action was successfully sent to the VIM'''
-        self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
-        try:
-            self._reload_connection()
-            server = self.nova.servers.find(id=vm_id)
-            if "start" in action_dict:
-                if action_dict["start"]=="rebuild":  
-                    server.rebuild()
-                else:
-                    if server.status=="PAUSED":
-                        server.unpause()
-                    elif server.status=="SUSPENDED":
-                        server.resume()
-                    elif server.status=="SHUTOFF":
-                        server.start()
-            elif "pause" in action_dict:
-                server.pause()
-            elif "resume" in action_dict:
-                server.resume()
-            elif "shutoff" in action_dict or "shutdown" in action_dict:
-                server.stop()
-            elif "forceOff" in action_dict:
-                server.stop() #TODO
-            elif "terminate" in action_dict:
-                server.delete()
-            elif "createImage" in action_dict:
-                server.create_image()
-                #"path":path_schema,
-                #"description":description_schema,
-                #"name":name_schema,
-                #"metadata":metadata_schema,
-                #"imageRef": id_schema,
-                #"disk": {"oneOf":[{"type": "null"}, {"type":"string"}] },
-            elif "rebuild" in action_dict:
-                server.rebuild(server.image['id'])
-            elif "reboot" in action_dict:
-                server.reboot() #reboot_type='SOFT'
-            elif "console" in action_dict:
-                console_type = action_dict["console"]
-                if console_type == None or console_type == "novnc":
-                    console_dict = server.get_vnc_console("novnc")
-                elif console_type == "xvpvnc":
-                    console_dict = server.get_vnc_console(console_type)
-                elif console_type == "rdp-html5":
-                    console_dict = server.get_rdp_console(console_type)
-                elif console_type == "spice-html5":
-                    console_dict = server.get_spice_console(console_type)
-                else:
-                    raise vimconn.vimconnException("console type '{}' not allowed".format(console_type), 
-                                                   http_code=vimconn.HTTP_Bad_Request)
-                try:
-                    console_url = console_dict["console"]["url"]
-                    #parse console_url
-                    protocol_index = console_url.find("//")
-                    suffix_index = console_url[protocol_index+2:].find("/") + protocol_index+2
-                    port_index = console_url[protocol_index+2:suffix_index].find(":") + protocol_index+2
-                    if protocol_index < 0 or port_index<0 or suffix_index<0:
-                        raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict))
-                    console_dict2={"protocol": console_url[0:protocol_index],
-                                  "server":   console_url[protocol_index+2 : port_index], 
-                                  "port":     int(console_url[port_index+1 : suffix_index]), 
-                                  "suffix":   console_url[suffix_index+1:] 
-                                  }
-                    return console_dict2               
-                except Exception as e:
-                    raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict))
-            
-            return vm_id
-        except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e:
-            self._format_exception(e)
-        #TODO insert exception vimconn.HTTP_Unauthorized
-
-#NOT USED FUNCTIONS
-    
-    def new_external_port(self, port_data):
-        #TODO openstack if needed
-        '''Adds a external port to VIM'''
-        '''Returns the port identifier'''
-        return -vimconn.HTTP_Internal_Server_Error, "osconnector.new_external_port() not implemented" 
-        
-    def connect_port_network(self, port_id, network_id, admin=False):
-        #TODO openstack if needed
-        '''Connects a external port to a network'''
-        '''Returns status code of the VIM response'''
-        return -vimconn.HTTP_Internal_Server_Error, "osconnector.connect_port_network() not implemented" 
-    
-    def new_user(self, user_name, user_passwd, tenant_id=None):
-        '''Adds a new user to openstack VIM'''
-        '''Returns the user identifier'''
-        self.logger.debug("osconnector: Adding a new user to VIM")
-        try:
-            self._reload_connection()
-            user=self.keystone.users.create(user_name, user_passwd, tenant_id=tenant_id)
-            #self.keystone.tenants.add_user(self.k_creds["username"], #role)
-            return user.id
-        except ksExceptions.ConnectionError as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except ksExceptions.ClientException as e: #TODO remove
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            self.logger.debug("new_user " + error_text)
-        return error_value, error_text        
-
-    def delete_user(self, user_id):
-        '''Delete a user from openstack VIM'''
-        '''Returns the user identifier'''
-        if self.debug:
-            print "osconnector: Deleting  a  user from VIM"
-        try:
-            self._reload_connection()
-            self.keystone.users.delete(user_id)
-            return 1, user_id
-        except ksExceptions.ConnectionError as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except ksExceptions.NotFound as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except ksExceptions.ClientException as e: #TODO remove
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "delete_tenant " + error_text
-        return error_value, error_text
-    def get_hosts_info(self):
-        '''Get the information of deployed hosts
-        Returns the hosts content'''
-        if self.debug:
-            print "osconnector: Getting Host info from VIM"
-        try:
-            h_list=[]
-            self._reload_connection()
-            hypervisors = self.nova.hypervisors.list()
-            for hype in hypervisors:
-                h_list.append( hype.to_dict() )
-            return 1, {"hosts":h_list}
-        except nvExceptions.NotFound as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= (str(e) if len(e.args)==0 else str(e.args[0]))
-        except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "get_hosts_info " + error_text
-        return error_value, error_text        
-
-    def get_hosts(self, vim_tenant):
-        '''Get the hosts and deployed instances
-        Returns the hosts content'''
-        r, hype_dict = self.get_hosts_info()
-        if r<0:
-            return r, hype_dict
-        hypervisors = hype_dict["hosts"]
-        try:
-            servers = self.nova.servers.list()
-            for hype in hypervisors:
-                for server in servers:
-                    if server.to_dict()['OS-EXT-SRV-ATTR:hypervisor_hostname']==hype['hypervisor_hostname']:
-                        if 'vm' in hype:
-                            hype['vm'].append(server.id)
-                        else:
-                            hype['vm'] = [server.id]
-            return 1, hype_dict
-        except nvExceptions.NotFound as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= (str(e) if len(e.args)==0 else str(e.args[0]))
-        except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "get_hosts " + error_text
-        return error_value, error_text        
-  
-
diff --git a/vimconn_openvim.py b/vimconn_openvim.py
deleted file mode 100644 (file)
index e86b54d..0000000
+++ /dev/null
@@ -1,1314 +0,0 @@
-# -*- 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
-##
-
-'''
-vimconnector implements all the methods to interact with openvim using the openvim API.
-'''
-__author__="Alfonso Tierno, Gerardo Garcia"
-__date__ ="$26-aug-2014 11:09:29$"
-
-import vimconn
-import requests
-import json
-import yaml
-import logging
-from openmano_schemas import id_schema, name_schema, nameshort_schema, description_schema, \
-                            vlan1000_schema, integer0_schema
-from jsonschema import validate as js_v, exceptions as js_e
-from urllib import quote
-
-'''contain the openvim virtual machine status to openmano status'''
-vmStatus2manoFormat={'ACTIVE':'ACTIVE',
-                     'PAUSED':'PAUSED',
-                     'SUSPENDED': 'SUSPENDED',
-                     'INACTIVE':'INACTIVE',
-                     'CREATING':'BUILD',
-                     'ERROR':'ERROR','DELETED':'DELETED'
-                     }
-netStatus2manoFormat={'ACTIVE':'ACTIVE','INACTIVE':'INACTIVE','BUILD':'BUILD','ERROR':'ERROR','DELETED':'DELETED', 'DOWN':'DOWN'
-                     }
-
-
-host_schema = {
-    "type":"object",
-    "properties":{
-        "id": id_schema,
-        "name": name_schema,
-    },
-    "required": ["id"]
-}
-image_schema = {
-    "type":"object",
-    "properties":{
-        "id": id_schema,
-        "name": name_schema,
-    },
-    "required": ["id","name"]
-}
-server_schema = {
-    "type":"object",
-    "properties":{
-        "id":id_schema,
-        "name": name_schema,
-    },
-    "required": ["id","name"]
-}
-new_host_response_schema = {
-    "title":"host response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "host": host_schema
-    },
-    "required": ["host"],
-    "additionalProperties": False
-}
-
-get_images_response_schema = {
-    "title":"openvim images response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "images":{
-            "type":"array",
-            "items": image_schema,
-        }
-    },
-    "required": ["images"],
-    "additionalProperties": False
-}
-
-get_hosts_response_schema = {
-    "title":"openvim hosts response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "hosts":{
-            "type":"array",
-            "items": host_schema,
-        }
-    },
-    "required": ["hosts"],
-    "additionalProperties": False
-}
-
-get_host_detail_response_schema = new_host_response_schema # TODO: Content is not parsed yet
-
-get_server_response_schema = {
-    "title":"openvim server response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "servers":{
-            "type":"array",
-            "items": server_schema,
-        }
-    },
-    "required": ["servers"],
-    "additionalProperties": False
-}
-
-new_tenant_response_schema = {
-    "title":"tenant response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "tenant":{
-            "type":"object",
-            "properties":{
-                "id": id_schema,
-                "name": nameshort_schema,
-                "description":description_schema,
-                "enabled":{"type" : "boolean"}
-            },
-            "required": ["id"]
-        }
-    },
-    "required": ["tenant"],
-    "additionalProperties": False
-}
-
-new_network_response_schema = {
-    "title":"network response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "network":{
-            "type":"object",
-            "properties":{
-                "id":id_schema,
-                "name":name_schema,
-                "type":{"type":"string", "enum":["bridge_man","bridge_data","data", "ptp"]},
-                "shared":{"type":"boolean"},
-                "tenant_id":id_schema,
-                "admin_state_up":{"type":"boolean"},
-                "vlan":vlan1000_schema
-            },
-            "required": ["id"]
-        }
-    },
-    "required": ["network"],
-    "additionalProperties": False
-}
-
-
-# get_network_response_schema = {
-#     "title":"get network response information schema",
-#     "$schema": "http://json-schema.org/draft-04/schema#",
-#     "type":"object",
-#     "properties":{
-#         "network":{
-#             "type":"object",
-#             "properties":{
-#                 "id":id_schema,
-#                 "name":name_schema,
-#                 "type":{"type":"string", "enum":["bridge_man","bridge_data","data", "ptp"]},
-#                 "shared":{"type":"boolean"},
-#                 "tenant_id":id_schema,
-#                 "admin_state_up":{"type":"boolean"},
-#                 "vlan":vlan1000_schema
-#             },
-#             "required": ["id"]
-#         }
-#     },
-#     "required": ["network"],
-#     "additionalProperties": False
-# }
-
-
-new_port_response_schema = {
-    "title":"port response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "port":{
-            "type":"object",
-            "properties":{
-                "id":id_schema,
-            },
-            "required": ["id"]
-        }
-    },
-    "required": ["port"],
-    "additionalProperties": False
-}
-
-get_flavor_response_schema = {
-    "title":"openvim flavors response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "flavor":{
-            "type":"object",
-            "properties":{
-                "id":   id_schema,
-                "name": name_schema,
-                "extended": {"type":"object"},
-            },
-            "required": ["id", "name"],
-        }
-    },
-    "required": ["flavor"],
-    "additionalProperties": False
-}
-
-new_flavor_response_schema = {
-    "title":"flavor response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "flavor":{
-            "type":"object",
-            "properties":{
-                "id":id_schema,
-            },
-            "required": ["id"]
-        }
-    },
-    "required": ["flavor"],
-    "additionalProperties": False
-}
-
-get_image_response_schema = {
-    "title":"openvim images response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "image":{
-            "type":"object",
-            "properties":{
-                "id":   id_schema,
-                "name": name_schema,
-            },
-            "required": ["id", "name"],
-        }
-    },
-    "required": ["flavor"],
-    "additionalProperties": False
-}
-new_image_response_schema = {
-    "title":"image response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "image":{
-            "type":"object",
-            "properties":{
-                "id":id_schema,
-            },
-            "required": ["id"]
-        }
-    },
-    "required": ["image"],
-    "additionalProperties": False
-}
-
-new_vminstance_response_schema = {
-    "title":"server response information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "server":{
-            "type":"object",
-            "properties":{
-                "id":id_schema,
-            },
-            "required": ["id"]
-        }
-    },
-    "required": ["server"],
-    "additionalProperties": False
-}
-
-get_processor_rankings_response_schema = {
-    "title":"processor rankings information schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type":"object",
-    "properties":{
-        "rankings":{
-            "type":"array",
-            "items":{
-                "type":"object",
-                "properties":{
-                    "model": description_schema,
-                    "value": integer0_schema
-                },
-                "additionalProperties": False,
-                "required": ["model","value"]
-            }
-        },
-        "additionalProperties": False,
-        "required": ["rankings"]
-    }
-}
-
-class vimconnector(vimconn.vimconnector):
-    def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None,
-                 log_level="DEBUG", config={}, persistent_info={}):
-        vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level, config)
-        self.tenant = None
-        self.headers_req = {'content-type': 'application/json'}
-        self.logger = logging.getLogger('openmano.vim.openvim')
-        self.persistent_info = persistent_info
-        if tenant_id:
-            self.tenant = tenant_id
-
-    def __setitem__(self,index, value):
-        '''Set individuals parameters 
-        Throw TypeError, KeyError
-        '''
-        if index=='tenant_id':
-            self.tenant = value
-        elif index=='tenant_name':
-            self.tenant = None
-        vimconn.vimconnector.__setitem__(self,index, value)    
-
-    def _get_my_tenant(self):
-        '''Obtain uuid of my tenant from name
-        '''
-        if self.tenant:
-            return self.tenant
-
-        url = self.url+'/tenants?name='+ quote(self.tenant_name)
-        self.logger.info("Getting VIM tenant_id GET %s", url)
-        vim_response = requests.get(url, headers = self.headers_req)
-        self._check_http_request_response(vim_response)
-        try:
-            tenant_list = vim_response.json()["tenants"]
-            if len(tenant_list) == 0:
-                raise vimconn.vimconnNotFoundException("No tenant found for name '%s'" % str(self.tenant_name))
-            elif len(tenant_list) > 1:
-                raise vimconn.vimconnConflictException ("More that one tenant found for name '%s'" % str(self.tenant_name))
-            self.tenant = tenant_list[0]["id"]
-            return self.tenant
-        except Exception as e:
-            raise vimconn.vimconnUnexpectedResponse("Get VIM tenant {} '{}'".format(type(e).__name__, str(e)))
-
-    def _format_jsonerror(self,http_response):
-        #DEPRECATED, to delete in the future
-        try:
-            data = http_response.json()
-            return data["error"]["description"]
-        except:
-            return http_response.text
-
-    def _format_in(self, http_response, schema):
-        #DEPRECATED, to delete in the future
-        try:
-            client_data = http_response.json()
-            js_v(client_data, schema)
-            #print "Input data: ", str(client_data)
-            return True, client_data
-        except js_e.ValidationError as exc:
-            print "validate_in error, jsonschema exception ", exc.message, "at", exc.path
-            return False, ("validate_in error, jsonschema exception ", exc.message, "at", exc.path)
-    
-    def _remove_extra_items(self, data, schema):
-        deleted=[]
-        if type(data) is tuple or type(data) is list:
-            for d in data:
-                a= self._remove_extra_items(d, schema['items'])
-                if a is not None: deleted.append(a)
-        elif type(data) is dict:
-            for k in data.keys():
-                if 'properties' not in schema or k not in schema['properties'].keys():
-                    del data[k]
-                    deleted.append(k)
-                else:
-                    a = self._remove_extra_items(data[k], schema['properties'][k])
-                    if a is not None:  deleted.append({k:a})
-        if len(deleted) == 0: return None
-        elif len(deleted) == 1: return deleted[0]
-        else: return deleted
-        
-    def _format_request_exception(self, request_exception):
-        '''Transform a request exception into a vimconn exception'''
-        if isinstance(request_exception, js_e.ValidationError):
-            raise vimconn.vimconnUnexpectedResponse("jsonschema exception '{}' at '{}'".format(request_exception.message, request_exception.path))            
-        elif isinstance(request_exception, requests.exceptions.HTTPError):
-            raise vimconn.vimconnUnexpectedResponse(type(request_exception).__name__ + ": " + str(request_exception))
-        else:
-            raise vimconn.vimconnConnectionException(type(request_exception).__name__ + ": " + str(request_exception))
-
-    def _check_http_request_response(self, request_response):
-        '''Raise a vimconn exception if the response is not Ok'''
-        if request_response.status_code >= 200 and  request_response.status_code < 300:
-            return
-        if request_response.status_code == vimconn.HTTP_Unauthorized:
-            raise vimconn.vimconnAuthException(request_response.text)
-        elif request_response.status_code == vimconn.HTTP_Not_Found:
-            raise vimconn.vimconnNotFoundException(request_response.text)
-        elif request_response.status_code == vimconn.HTTP_Conflict:
-            raise vimconn.vimconnConflictException(request_response.text)
-        else: 
-            raise vimconn.vimconnUnexpectedResponse("VIM HTTP_response {}, {}".format(request_response.status_code, str(request_response.text)))
-
-    def new_tenant(self,tenant_name,tenant_description):
-        '''Adds a new tenant to VIM with this name and description, returns the tenant identifier'''
-        #print "VIMConnector: Adding a new tenant to VIM"
-        payload_dict = {"tenant": {"name":tenant_name,"description": tenant_description, "enabled": True}}
-        payload_req = json.dumps(payload_dict)
-        try:
-            url = self.url_admin+'/tenants'
-            self.logger.info("Adding a new tenant %s", url)
-            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, new_tenant_response_schema)
-            #r = self._remove_extra_items(response, new_tenant_response_schema)
-            #if r is not None: 
-            #    self.logger.warn("Warning: remove extra items %s", str(r))
-            tenant_id = response['tenant']['id']
-            return tenant_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def delete_tenant(self,tenant_id):
-        '''Delete a tenant from VIM. Returns the old tenant identifier'''
-        try:
-            url = self.url_admin+'/tenants/'+tenant_id
-            self.logger.info("Delete a tenant DELETE %s", url)
-            vim_response = requests.delete(url, headers = self.headers_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            return tenant_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def get_tenant_list(self, filter_dict={}):
-        '''Obtain tenants of VIM
-        filter_dict can contain the following keys:
-            name: filter by tenant name
-            id: filter by tenant uuid/id
-            <other VIM specific>
-        Returns the tenant list of dictionaries: [{'name':'<name>, 'id':'<id>, ...}, ...]
-        '''
-        filterquery=[]
-        filterquery_text=''
-        for k,v in filter_dict.iteritems():
-            filterquery.append(str(k)+'='+str(v))
-        if len(filterquery)>0:
-            filterquery_text='?'+ '&'.join(filterquery)
-        try:
-            url = self.url+'/tenants'+filterquery_text
-            self.logger.info("get_tenant_list GET %s", url)
-            vim_response = requests.get(url, headers = self.headers_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            return vim_response.json()["tenants"]
-        except requests.exceptions.RequestException as e:
-            self._format_request_exception(e)
-
-    def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None): #, **vim_specific):
-        '''Adds a tenant network to VIM'''
-        '''Returns the network identifier'''
-        try:
-            self._get_my_tenant()
-            if net_type=="bridge":
-                net_type="bridge_data"
-            payload_req = {"name": net_name, "type": net_type, "tenant_id": self.tenant, "shared": shared}
-            if vlan:
-                payload_req["provider:vlan"] = vlan
-            # payload_req.update(vim_specific)
-            url = self.url+'/networks'
-            self.logger.info("Adding a new network POST: %s  DATA: %s", url, str(payload_req))
-            vim_response = requests.post(url, headers = self.headers_req, data=json.dumps({"network": payload_req}) )
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, new_network_response_schema)
-            #r = self._remove_extra_items(response, new_network_response_schema)
-            #if r is not None: 
-            #    self.logger.warn("Warning: remove extra items %s", str(r))
-            network_id = response['network']['id']
-            return network_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-        
-    def get_network_list(self, filter_dict={}):
-        '''Obtain tenant networks of VIM
-        Filter_dict can be:
-            name: network name
-            id: network uuid
-            public: boolean
-            tenant_id: tenant
-            admin_state_up: boolean
-            status: 'ACTIVE'
-        Returns the network list of dictionaries
-        '''
-        try:
-            if 'tenant_id' not in filter_dict:
-                filter_dict["tenant_id"] = self._get_my_tenant()
-            elif not filter_dict["tenant_id"]:
-                del filter_dict["tenant_id"]
-            filterquery=[]
-            filterquery_text=''
-            for k,v in filter_dict.iteritems():
-                filterquery.append(str(k)+'='+str(v))
-            if len(filterquery)>0:
-                filterquery_text='?'+ '&'.join(filterquery)
-            url = self.url+'/networks'+filterquery_text
-            self.logger.info("Getting network list GET %s", url)
-            vim_response = requests.get(url, headers = self.headers_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            return response['networks']
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def get_network(self, net_id):
-        '''Obtain network details of network id'''
-        try:
-            url = self.url+'/networks/'+net_id
-            self.logger.info("Getting network GET %s", url)
-            vim_response = requests.get(url, headers = self.headers_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            return response['network']
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-            
-    def delete_network(self, net_id):
-        '''Deletes a tenant network from VIM'''
-        '''Returns the network identifier'''
-        try:
-            self._get_my_tenant()
-            url = self.url+'/networks/'+net_id
-            self.logger.info("Deleting VIM network DELETE %s", url)
-            vim_response = requests.delete(url, headers=self.headers_req)
-            self._check_http_request_response(vim_response)
-            #self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            return net_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def get_flavor(self, flavor_id):
-        '''Obtain flavor details from the  VIM'''
-        try:
-            self._get_my_tenant()
-            url = self.url+'/'+self.tenant+'/flavors/'+flavor_id
-            self.logger.info("Getting flavor GET %s", url)
-            vim_response = requests.get(url, headers = self.headers_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, get_flavor_response_schema)
-            r = self._remove_extra_items(response, get_flavor_response_schema)
-            if r is not None: 
-                self.logger.warn("Warning: remove extra items %s", str(r))
-            return response['flavor']
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-        
-    def new_flavor(self, flavor_data):
-        '''Adds a tenant flavor to VIM'''
-        '''Returns the flavor identifier'''
-        try:
-            new_flavor_dict = flavor_data.copy()
-            new_flavor_dict["name"] = flavor_data["name"][:64]
-            self._get_my_tenant()
-            payload_req = json.dumps({'flavor': new_flavor_dict})
-            url = self.url+'/'+self.tenant+'/flavors'
-            self.logger.info("Adding a new VIM flavor POST %s", url)
-            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, new_flavor_response_schema)
-            r = self._remove_extra_items(response, new_flavor_response_schema)
-            if r is not None: 
-                self.logger.warn("Warning: remove extra items %s", str(r))
-            flavor_id = response['flavor']['id']
-            return flavor_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def delete_flavor(self,flavor_id):
-        '''Deletes a tenant flavor from VIM'''
-        '''Returns the old flavor_id'''
-        try:
-            self._get_my_tenant()
-            url = self.url+'/'+self.tenant+'/flavors/'+flavor_id
-            self.logger.info("Deleting VIM flavor DELETE %s", url)
-            vim_response = requests.delete(url, headers=self.headers_req)
-            self._check_http_request_response(vim_response)
-            #self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            return flavor_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def get_image(self, image_id):
-        '''Obtain image details from the  VIM'''
-        try:
-            self._get_my_tenant()
-            url = self.url+'/'+self.tenant+'/images/'+image_id
-            self.logger.info("Getting image GET %s", url)
-            vim_response = requests.get(url, headers = self.headers_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, get_image_response_schema)
-            r = self._remove_extra_items(response, get_image_response_schema)
-            if r is not None: 
-                self.logger.warn("Warning: remove extra items %s", str(r))
-            return response['image']
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def new_image(self,image_dict):
-        ''' Adds a tenant image to VIM, returns image_id'''
-        try:
-            self._get_my_tenant()
-            new_image_dict={'name': image_dict['name'][:64]}
-            if image_dict.get('description'):
-                new_image_dict['description'] = image_dict['description']
-            if image_dict.get('metadata'):
-                new_image_dict['metadata'] = yaml.load(image_dict['metadata'])
-            if image_dict.get('location'):
-                new_image_dict['path'] = image_dict['location']
-            payload_req = json.dumps({"image":new_image_dict})
-            url=self.url + '/' + self.tenant + '/images'
-            self.logger.info("Adding a new VIM image POST %s", url)
-            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, new_image_response_schema)
-            r = self._remove_extra_items(response, new_image_response_schema)
-            if r is not None: 
-                self.logger.warn("Warning: remove extra items %s", str(r))
-            image_id = response['image']['id']
-            return image_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-            
-    def delete_image(self, image_id):
-        '''Deletes a tenant image from VIM'''
-        '''Returns the deleted image_id'''
-        try:
-            self._get_my_tenant()
-            url = self.url + '/'+ self.tenant +'/images/'+image_id
-            self.logger.info("Deleting VIM image DELETE %s", url)
-            vim_response = requests.delete(url, headers=self.headers_req)
-            self._check_http_request_response(vim_response)
-            #self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            return image_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    
-    def get_image_id_from_path(self, path):
-        '''Get the image id from image path in the VIM database. Returns the image_id'''
-        try:
-            self._get_my_tenant()
-            url=self.url + '/' + self.tenant + '/images?path='+quote(path)
-            self.logger.info("Getting images GET %s", url)
-            vim_response = requests.get(url)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, get_images_response_schema)
-            #r = self._remove_extra_items(response, get_images_response_schema)
-            #if r is not None: 
-            #    self.logger.warn("Warning: remove extra items %s", str(r))
-            if len(response['images'])==0:
-                raise vimconn.vimconnNotFoundException("Image not found at VIM with path '%s'", path)
-            elif len(response['images'])>1:
-                raise vimconn.vimconnConflictException("More than one image found at VIM with path '%s'", path)
-            return response['images'][0]['id']
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def get_image_list(self, filter_dict={}):
-        '''Obtain tenant images from VIM
-        Filter_dict can be:
-            name: image name
-            id: image uuid
-            checksum: image checksum
-            location: image path
-        Returns the image list of dictionaries:
-            [{<the fields at Filter_dict plus some VIM specific>}, ...]
-            List can be empty
-        '''
-        try:
-            self._get_my_tenant()
-            filterquery=[]
-            filterquery_text=''
-            for k,v in filter_dict.iteritems():
-                filterquery.append(str(k)+'='+str(v))
-            if len(filterquery)>0:
-                filterquery_text='?'+ '&'.join(filterquery)
-            url = self.url+'/'+self.tenant+'/images'+filterquery_text
-            self.logger.info("Getting image list GET %s", url)
-            vim_response = requests.get(url, headers = self.headers_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            return response['images']
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def new_vminstancefromJSON(self, vm_data):
-        '''Adds a VM instance to VIM'''
-        '''Returns the instance identifier'''
-        try:
-            self._get_my_tenant()
-        except Exception as e:
-            return -vimconn.HTTP_Not_Found, str(e)
-        print "VIMConnector: Adding a new VM instance from JSON to VIM"
-        payload_req = vm_data
-        try:
-            vim_response = requests.post(self.url+'/'+self.tenant+'/servers', headers = self.headers_req, data=payload_req)
-        except requests.exceptions.RequestException as e:
-            print "new_vminstancefromJSON Exception: ", e.args
-            return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print vim_response
-        #print vim_response.status_code
-        if vim_response.status_code == 200:
-            #print vim_response.json()
-            #print json.dumps(vim_response.json(), indent=4)
-            res,http_content = self._format_in(vim_response, new_image_response_schema)
-            #print http_content
-            if res:
-                r = self._remove_extra_items(http_content, new_image_response_schema)
-                if r is not None: print "Warning: remove extra items ", r
-                #print http_content
-                vminstance_id = http_content['server']['id']
-                print "Tenant image id: ",vminstance_id
-                return vim_response.status_code,vminstance_id
-            else: return -vimconn.HTTP_Bad_Request,http_content
-        else:
-            #print vim_response.text
-            jsonerror = self._format_jsonerror(vim_response)
-            text = 'Error in VIM "%s": not possible to add new vm instance. HTTP Response: %d. Error: %s' % (self.url, vim_response.status_code, jsonerror)
-            #print text
-            return -vim_response.status_code,text
-
-    def new_vminstance(self,name,description,start,image_id,flavor_id,net_list, cloud_config=None, disk_list=None):
-        '''Adds a VM instance to VIM
-        Params:
-            start: indicates if VM must start or boot in pause mode. Ignored
-            image_id,flavor_id: image and flavor uuid
-            net_list: list of interfaces, each one is a dictionary with:
-                name:
-                net_id: network uuid to connect
-                vpci: virtual vcpi to assign
-                model: interface model, virtio, e2000, ...
-                mac_address: 
-                use: 'data', 'bridge',  'mgmt'
-                type: 'virtual', 'PF', 'VF', 'VFnotShared'
-                vim_id: filled/added by this function
-                #TODO ip, security groups
-        Returns the instance identifier
-        '''
-        self.logger.debug("new_vminstance input: image='%s' flavor='%s' nics='%s'", image_id, flavor_id, str(net_list))
-        try:
-            self._get_my_tenant()
-#            net_list = []
-#            for k,v in net_dict.items():
-#                print k,v
-#                net_list.append('{"name":"' + k + '", "uuid":"' + v + '"}')
-#            net_list_string = ', '.join(net_list) 
-            virtio_net_list=[]
-            for net in net_list:
-                if not net.get("net_id"):
-                    continue
-                net_dict={'uuid': net["net_id"]}
-                if net.get("type"):        net_dict["type"] = net["type"]
-                if net.get("name"):        net_dict["name"] = net["name"]
-                if net.get("vpci"):        net_dict["vpci"] = net["vpci"]
-                if net.get("model"):       net_dict["model"] = net["model"]
-                if net.get("mac_address"): net_dict["mac_address"] = net["mac_address"]
-                virtio_net_list.append(net_dict)
-            payload_dict={  "name":        name[:64],
-                            "description": description,
-                            "imageRef":    image_id,
-                            "flavorRef":   flavor_id,
-                            "networks": virtio_net_list
-                        }
-            if start != None:
-                payload_dict["start"] = start
-            payload_req = json.dumps({"server": payload_dict})
-            url = self.url+'/'+self.tenant+'/servers'
-            self.logger.info("Adding a new vm POST %s DATA %s", url, payload_req)
-            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, new_vminstance_response_schema)
-            #r = self._remove_extra_items(response, new_vminstance_response_schema)
-            #if r is not None: 
-            #    self.logger.warn("Warning: remove extra items %s", str(r))
-            vminstance_id = response['server']['id']
-
-            #connect data plane interfaces to network
-            for net in net_list:
-                if net["type"]=="virtual":
-                    if not net.get("net_id"):
-                        continue
-                    for iface in response['server']['networks']:
-                        if "name" in net:
-                            if net["name"]==iface["name"]:
-                                net["vim_id"] = iface['iface_id']
-                                break
-                        elif "net_id" in net:
-                            if net["net_id"]==iface["net_id"]:
-                                net["vim_id"] = iface['iface_id']
-                                break
-                else: #dataplane
-                    for numa in response['server'].get('extended',{}).get('numas',() ):
-                        for iface in numa.get('interfaces',() ):
-                            if net['name'] == iface['name']:
-                                net['vim_id'] = iface['iface_id']
-                                #Code bellow is not needed, current openvim connect dataplane interfaces 
-                                #if net.get("net_id"):
-                                ##connect dataplane interface
-                                #    result, port_id = self.connect_port_network(iface['iface_id'], net["net_id"])
-                                #    if result < 0:
-                                #        error_text = "Error attaching port %s to network %s: %s." % (iface['iface_id'], net["net_id"], port_id)
-                                #        print "new_vminstance: " + error_text
-                                #        self.delete_vminstance(vminstance_id)
-                                #        return result, error_text
-                                break
-        
-            return vminstance_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-        
-    def get_vminstance(self, vm_id):
-        '''Returns the VM instance information from VIM'''
-        try:
-            self._get_my_tenant()
-            url = self.url+'/'+self.tenant+'/servers/'+vm_id
-            self.logger.info("Getting vm GET %s", url)
-            vim_response = requests.get(url, headers = self.headers_req)
-            vim_response = requests.get(url, headers = self.headers_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, new_vminstance_response_schema)
-            #r = self._remove_extra_items(response, new_vminstance_response_schema)
-            #if r is not None: 
-            #    self.logger.warn("Warning: remove extra items %s", str(r))
-            return response['server']
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-        
-    def delete_vminstance(self, vm_id):
-        '''Removes a VM instance from VIM, returns the deleted vm_id'''
-        try:
-            self._get_my_tenant()
-            url = self.url+'/'+self.tenant+'/servers/'+vm_id
-            self.logger.info("Deleting VIM vm DELETE %s", url)
-            vim_response = requests.delete(url, headers=self.headers_req)
-            self._check_http_request_response(vim_response)
-            #self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            return vm_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-    def refresh_vms_status(self, vm_list):
-        '''Refreshes the status of the virtual machines'''
-        try:
-            self._get_my_tenant()
-        except requests.exceptions.RequestException as e:
-            self._format_request_exception(e)
-        vm_dict={}
-        for vm_id in vm_list:
-            vm={}
-            #print "VIMConnector refresh_tenant_vms and nets: Getting tenant VM instance information from VIM"
-            try:
-                url = self.url+'/'+self.tenant+'/servers/'+ vm_id
-                self.logger.info("Getting vm GET %s", url)
-                vim_response = requests.get(url, headers = self.headers_req)
-                self._check_http_request_response(vim_response)
-                response = vim_response.json()
-                js_v(response, new_vminstance_response_schema)
-                if response['server']['status'] in vmStatus2manoFormat:
-                    vm['status'] = vmStatus2manoFormat[ response['server']['status']  ]
-                else:
-                    vm['status'] = "OTHER"
-                    vm['error_msg'] = "VIM status reported " + response['server']['status']
-                if response['server'].get('last_error'):
-                    vm['error_msg'] = response['server']['last_error']
-                vm["vim_info"] = yaml.safe_dump(response['server'])
-                #get interfaces info
-                try:
-                    management_ip = False
-                    url2 = self.url+'/ports?device_id='+ quote(vm_id)
-                    self.logger.info("Getting PORTS GET %s", url2)
-                    vim_response2 = requests.get(url2, headers = self.headers_req)
-                    self._check_http_request_response(vim_response2)
-                    client_data = vim_response2.json()
-                    if isinstance(client_data.get("ports"), list):
-                        vm["interfaces"]=[]
-                    for port in client_data.get("ports"):
-                        interface={}
-                        interface['vim_info']  = yaml.safe_dump(port)
-                        interface["mac_address"] = port.get("mac_address")
-                        interface["vim_net_id"] = port.get("network_id")
-                        interface["vim_interface_id"] = port["id"]
-                        interface["ip_address"] = port.get("ip_address")
-                        if interface["ip_address"]:
-                            management_ip = True
-                        if interface["ip_address"] == "0.0.0.0":
-                            interface["ip_address"] = None
-                        vm["interfaces"].append(interface)
-                        
-                except Exception as e:
-                    self.logger.error("refresh_vms_and_nets. Port get %s: %s", type(e).__name__, str(e))
-
-                if vm['status'] == "ACTIVE" and not management_ip:
-                    vm['status'] = "ACTIVE:NoMgmtIP"
-                    
-            except vimconn.vimconnNotFoundException as e:
-                self.logger.error("Exception getting vm status: %s", str(e))
-                vm['status'] = "DELETED"
-                vm['error_msg'] = str(e)
-            except (requests.exceptions.RequestException, js_e.ValidationError, vimconn.vimconnException) as e:
-                self.logger.error("Exception getting vm status: %s", str(e))
-                vm['status'] = "VIM_ERROR"
-                vm['error_msg'] = str(e)
-            vm_dict[vm_id] = vm
-        return vm_dict
-
-    def refresh_nets_status(self, net_list):
-        '''Get the status of the networks
-           Params: the list of network identifiers
-           Returns a dictionary with:
-                net_id:         #VIM id of this network
-                    status:     #Mandatory. Text with one of:
-                                #  DELETED (not found at vim)
-                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
-                                #  OTHER (Vim reported other status not understood)
-                                #  ERROR (VIM indicates an ERROR status)
-                                #  ACTIVE, INACTIVE, DOWN (admin down), 
-                                #  BUILD (on building process)
-                                #
-                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
-                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
-
-        '''
-        try:
-            self._get_my_tenant()
-        except requests.exceptions.RequestException as e:
-            self._format_request_exception(e)
-        
-        net_dict={}
-        for net_id in net_list:
-            net = {}
-            #print "VIMConnector refresh_tenant_vms_and_nets: Getting tenant network from VIM (tenant: " + str(self.tenant) + "): "
-            try:
-                net_vim = self.get_network(net_id)
-                if net_vim['status'] in netStatus2manoFormat:
-                    net["status"] = netStatus2manoFormat[ net_vim['status'] ]
-                else:
-                    net["status"] = "OTHER"
-                    net["error_msg"] = "VIM status reported " + net_vim['status']
-                    
-                if net["status"] == "ACTIVE" and not net_vim['admin_state_up']:
-                    net["status"] = "DOWN"
-                if net_vim.get('last_error'):
-                    net['error_msg'] = net_vim['last_error']
-                net["vim_info"] = yaml.safe_dump(net_vim)
-            except vimconn.vimconnNotFoundException as e:
-                self.logger.error("Exception getting net status: %s", str(e))
-                net['status'] = "DELETED"
-                net['error_msg'] = str(e)
-            except (requests.exceptions.RequestException, js_e.ValidationError, vimconn.vimconnException) as e:
-                self.logger.error("Exception getting net status: %s", str(e))
-                net['status'] = "VIM_ERROR"
-                net['error_msg'] = str(e)
-            net_dict[net_id] = net
-        return net_dict
-    
-    def action_vminstance(self, vm_id, action_dict):
-        '''Send and action over a VM instance from VIM'''
-        '''Returns the status'''
-        try:
-            self._get_my_tenant()
-            if "console" in action_dict:
-                raise vimconn.vimconnException("getting console is not available at openvim", http_code=vimconn.HTTP_Service_Unavailable)
-            url = self.url+'/'+self.tenant+'/servers/'+vm_id+"/action"
-            self.logger.info("Action over VM instance POST %s", url)
-            vim_response = requests.post(url, headers = self.headers_req, data=json.dumps(action_dict) )
-            self._check_http_request_response(vim_response)
-            return vm_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-
-#NOT USED METHODS in current version        
-  
-    def host_vim2gui(self, host, server_dict):
-        '''Transform host dictionary from VIM format to GUI format,
-        and append to the server_dict
-        '''
-        if type(server_dict) is not dict: 
-            print 'vimconnector.host_vim2gui() ERROR, param server_dict must be a dictionary'
-            return
-        RAD={}
-        occupation={}
-        for numa in host['host']['numas']:
-            RAD_item={}
-            occupation_item={}
-            #memory
-            RAD_item['memory']={'size': str(numa['memory'])+'GB', 'eligible': str(numa['hugepages'])+'GB'}
-            occupation_item['memory']= str(numa['hugepages_consumed'])+'GB'
-            #cpus
-            RAD_item['cpus']={}
-            RAD_item['cpus']['cores'] = []
-            RAD_item['cpus']['eligible_cores'] = []
-            occupation_item['cores']=[]
-            for _ in range(0, len(numa['cores']) / 2):
-                RAD_item['cpus']['cores'].append( [] )
-            for core in numa['cores']:
-                RAD_item['cpus']['cores'][core['core_id']].append(core['thread_id'])
-                if not 'status' in core: RAD_item['cpus']['eligible_cores'].append(core['thread_id'])
-                if 'instance_id' in core: occupation_item['cores'].append(core['thread_id'])
-            #ports
-            RAD_item['ports']={}
-            occupation_item['ports']={}
-            for iface in numa['interfaces']:
-                RAD_item['ports'][ iface['pci'] ] = 'speed:'+str(iface['Mbps'])+'M'
-                occupation_item['ports'][ iface['pci'] ] = { 'occupied': str(100*iface['Mbps_consumed'] / iface['Mbps']) + "%" }
-                
-            RAD[ numa['numa_socket'] ] = RAD_item
-            occupation[ numa['numa_socket'] ] = occupation_item
-        server_dict[ host['host']['name'] ] = {'RAD':RAD, 'occupation':occupation}
-
-    def get_hosts_info(self):
-        '''Get the information of deployed hosts
-        Returns the hosts content'''
-    #obtain hosts list
-        url=self.url+'/hosts'
-        try:
-            vim_response = requests.get(url)
-        except requests.exceptions.RequestException as e:
-            print "get_hosts_info Exception: ", e.args
-            return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
-        #print vim_response.status_code
-        #print json.dumps(vim_response.json(), indent=4)
-        if vim_response.status_code != 200:
-            #TODO: get error
-            print 'vimconnector.get_hosts_info error getting host list %d %s' %(vim_response.status_code, vim_response.json())
-            return -vim_response.status_code, "Error getting host list"
-        
-        res,hosts = self._format_in(vim_response, get_hosts_response_schema)
-            
-        if res==False:
-            print "vimconnector.get_hosts_info error parsing GET HOSTS vim response", hosts
-            return vimconn.HTTP_Internal_Server_Error, hosts
-    #obtain hosts details
-        hosts_dict={}
-        for host in hosts['hosts']:
-            url=self.url+'/hosts/'+host['id']
-            try:
-                vim_response = requests.get(url)
-            except requests.exceptions.RequestException as e:
-                print "get_hosts_info Exception: ", e.args
-                return -vimconn.HTTP_Not_Found, str(e.args[0])
-            print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
-            if vim_response.status_code != 200:
-                print 'vimconnector.get_hosts_info error getting detailed host %d %s' %(vim_response.status_code, vim_response.json())
-                continue
-            res,host_detail = self._format_in(vim_response, get_host_detail_response_schema)
-            if res==False:
-                print "vimconnector.get_hosts_info error parsing GET HOSTS/%s vim response" % host['id'], host_detail
-                continue
-            #print 'host id '+host['id'], json.dumps(host_detail, indent=4)
-            self.host_vim2gui(host_detail, hosts_dict)
-        return 200, hosts_dict
-
-    def get_hosts(self, vim_tenant):
-        '''Get the hosts and deployed instances
-        Returns the hosts content'''
-    #obtain hosts list
-        url=self.url+'/hosts'
-        try:
-            vim_response = requests.get(url)
-        except requests.exceptions.RequestException as e:
-            print "get_hosts Exception: ", e.args
-            return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
-        #print vim_response.status_code
-        #print json.dumps(vim_response.json(), indent=4)
-        if vim_response.status_code != 200:
-            #TODO: get error
-            print 'vimconnector.get_hosts error getting host list %d %s' %(vim_response.status_code, vim_response.json())
-            return -vim_response.status_code, "Error getting host list"
-        
-        res,hosts = self._format_in(vim_response, get_hosts_response_schema)
-            
-        if res==False:
-            print "vimconnector.get_host error parsing GET HOSTS vim response", hosts
-            return vimconn.HTTP_Internal_Server_Error, hosts
-    #obtain instances from hosts
-        for host in hosts['hosts']:
-            url=self.url+'/' + vim_tenant + '/servers?hostId='+host['id']
-            try:
-                vim_response = requests.get(url)
-            except requests.exceptions.RequestException as e:
-                print "get_hosts Exception: ", e.args
-                return -vimconn.HTTP_Not_Found, str(e.args[0])
-            print "vim get", url, "response:",  vim_response.status_code, vim_response.json()
-            if vim_response.status_code != 200:
-                print 'vimconnector.get_hosts error getting instances at host %d %s' %(vim_response.status_code, vim_response.json())
-                continue
-            res,servers = self._format_in(vim_response, get_server_response_schema)
-            if res==False:
-                print "vimconnector.get_host error parsing GET SERVERS/%s vim response" % host['id'], servers
-                continue
-            #print 'host id '+host['id'], json.dumps(host_detail, indent=4)
-            host['instances'] = servers['servers']
-        return 200, hosts['hosts']
-
-    def get_processor_rankings(self):
-        '''Get the processor rankings in the VIM database'''
-        url=self.url+'/processor_ranking'
-        try:
-            vim_response = requests.get(url)
-        except requests.exceptions.RequestException as e:
-            print "get_processor_rankings Exception: ", e.args
-            return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print "vim get", url, "response:", vim_response.status_code, vim_response.json()
-        #print vim_response.status_code
-        #print json.dumps(vim_response.json(), indent=4)
-        if vim_response.status_code != 200:
-            #TODO: get error
-            print 'vimconnector.get_processor_rankings error getting processor rankings %d %s' %(vim_response.status_code, vim_response.json())
-            return -vim_response.status_code, "Error getting processor rankings"
-        
-        res,rankings = self._format_in(vim_response, get_processor_rankings_response_schema)
-        return res, rankings['rankings']
-    
-    def new_host(self, host_data):
-        '''Adds a new host to VIM'''
-        '''Returns status code of the VIM response'''
-        payload_req = host_data
-        try:
-            url = self.url_admin+'/hosts'
-            self.logger.info("Adding a new host POST %s", url)
-            vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
-            self._check_http_request_response(vim_response)
-            self.logger.debug(vim_response.text)
-            #print json.dumps(vim_response.json(), indent=4)
-            response = vim_response.json()
-            js_v(response, new_host_response_schema)
-            r = self._remove_extra_items(response, new_host_response_schema)
-            if r is not None: 
-                self.logger.warn("Warning: remove extra items %s", str(r))
-            host_id = response['host']['id']
-            return host_id
-        except (requests.exceptions.RequestException, js_e.ValidationError) as e:
-            self._format_request_exception(e)
-    
-    def new_external_port(self, port_data):
-        '''Adds a external port to VIM'''
-        '''Returns the port identifier'''
-        #TODO change to logging exception code policies
-        print "VIMConnector: Adding a new external port"
-        payload_req = port_data
-        try:
-            vim_response = requests.post(self.url_admin+'/ports', headers = self.headers_req, data=payload_req)
-        except requests.exceptions.RequestException as e:
-            self.logger.error("new_external_port Exception: ", str(e))
-            return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print vim_response
-        #print vim_response.status_code
-        if vim_response.status_code == 200:
-        #print vim_response.json()
-        #print json.dumps(vim_response.json(), indent=4)
-            res, http_content = self._format_in(vim_response, new_port_response_schema)
-        #print http_content
-            if res:
-                r = self._remove_extra_items(http_content, new_port_response_schema)
-                if r is not None: print "Warning: remove extra items ", r
-                #print http_content
-                port_id = http_content['port']['id']
-                print "Port id: ",port_id
-                return vim_response.status_code,port_id
-            else: return -vimconn.HTTP_Bad_Request,http_content
-        else:
-            #print vim_response.text
-            jsonerror = self._format_jsonerror(vim_response)
-            text = 'Error in VIM "%s": not possible to add new external port. HTTP Response: %d. Error: %s' % (self.url_admin, vim_response.status_code, jsonerror)
-            #print text
-            return -vim_response.status_code,text
-        
-    def new_external_network(self,net_name,net_type):
-        '''Adds a external network to VIM (shared)'''
-        '''Returns the network identifier'''
-        #TODO change to logging exception code policies
-        print "VIMConnector: Adding external shared network to VIM (type " + net_type + "): "+ net_name
-        
-        payload_req = '{"network":{"name": "' + net_name + '","shared":true,"type": "' + net_type + '"}}'
-        try:
-            vim_response = requests.post(self.url+'/networks', headers = self.headers_req, data=payload_req)
-        except requests.exceptions.RequestException as e:
-            self.logger.error( "new_external_network Exception: ", e.args)
-            return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print vim_response
-        #print vim_response.status_code
-        if vim_response.status_code == 200:
-            #print vim_response.json()
-            #print json.dumps(vim_response.json(), indent=4)
-            res,http_content = self._format_in(vim_response, new_network_response_schema)
-            #print http_content
-            if res:
-                r = self._remove_extra_items(http_content, new_network_response_schema)
-                if r is not None: print "Warning: remove extra items ", r
-                #print http_content
-                network_id = http_content['network']['id']
-                print "Network id: ",network_id
-                return vim_response.status_code,network_id
-            else: return -vimconn.HTTP_Bad_Request,http_content
-        else:
-            #print vim_response.text
-            jsonerror = self._format_jsonerror(vim_response)
-            text = 'Error in VIM "%s": not possible to add new external network. HTTP Response: %d. Error: %s' % (self.url, vim_response.status_code, jsonerror)
-            #print text
-            return -vim_response.status_code,text
-        
-    def connect_port_network(self, port_id, network_id, admin=False):
-        '''Connects a external port to a network'''
-        '''Returns status code of the VIM response'''
-        #TODO change to logging exception code policies
-        print "VIMConnector: Connecting external port to network"
-        
-        payload_req = '{"port":{"network_id":"' + network_id + '"}}'
-        if admin:
-            if self.url_admin==None:
-                return -vimconn.HTTP_Unauthorized, "datacenter cannot contain  admin URL"
-            url= self.url_admin
-        else:
-            url= self.url
-        try:
-            vim_response = requests.put(url +'/ports/'+port_id, headers = self.headers_req, data=payload_req)
-        except requests.exceptions.RequestException as e:
-            print "connect_port_network Exception: ", e.args
-            return -vimconn.HTTP_Not_Found, str(e.args[0])
-        print vim_response
-        #print vim_response.status_code
-        if vim_response.status_code == 200:
-            #print vim_response.json()
-            #print json.dumps(vim_response.json(), indent=4)
-            res,http_content = self._format_in(vim_response, new_port_response_schema)
-            #print http_content
-            if res:
-                r = self._remove_extra_items(http_content, new_port_response_schema)
-                if r is not None: print "Warning: remove extra items ", r
-                #print http_content
-                port_id = http_content['port']['id']
-                print "Port id: ",port_id
-                return vim_response.status_code,port_id
-            else: return -vimconn.HTTP_Bad_Request,http_content
-        else:
-            print vim_response.text
-            jsonerror = self._format_jsonerror(vim_response)
-            text = 'Error in VIM "%s": not possible to connect external port to network. HTTP Response: %d. Error: %s' % (self.url_admin, vim_response.status_code, jsonerror)
-            print text
-            return -vim_response.status_code,text
-        
-
diff --git a/vimconn_vmware.py b/vimconn_vmware.py
deleted file mode 100644 (file)
index a224255..0000000
+++ /dev/null
@@ -1,3471 +0,0 @@
-# -*- 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
-##
-
-"""
-vimconn_vmware implementation an Abstract class in order to interact with VMware  vCloud Director.
-mbayramov@vmware.com
-"""
-from progressbar import Percentage, Bar, ETA, FileTransferSpeed, ProgressBar
-
-import vimconn
-import os
-import traceback
-import itertools
-import requests
-import ssl
-import atexit
-
-from pyVmomi import vim, vmodl
-from pyVim.connect import SmartConnect, Disconnect
-
-from xml.etree import ElementTree as XmlElementTree
-from lxml import etree as lxmlElementTree
-
-import yaml
-from pyvcloud import Http
-from pyvcloud.vcloudair import VCA
-from pyvcloud.schema.vcd.v1_5.schemas.vcloud import sessionType, organizationType, \
-    vAppType, organizationListType, vdcType, catalogType, queryRecordViewType, \
-    networkType, vcloudType, taskType, diskType, vmsType, vdcTemplateListType, mediaType
-from xml.sax.saxutils import escape
-
-from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TaskType
-from pyvcloud.schema.vcd.v1_5.schemas.vcloud.taskType import TaskType as GenericTask
-from pyvcloud.schema.vcd.v1_5.schemas.vcloud.vAppType import TaskType as VappTask
-from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TasksInProgressType
-
-import logging
-import json
-import time
-import uuid
-import httplib
-import hashlib
-import socket
-import struct
-import netaddr
-
-# global variable for vcd connector type
-STANDALONE = 'standalone'
-
-# key for flavor dicts
-FLAVOR_RAM_KEY = 'ram'
-FLAVOR_VCPUS_KEY = 'vcpus'
-FLAVOR_DISK_KEY = 'disk'
-DEFAULT_IP_PROFILE = {'gateway_address':"192.168.1.1",
-                      'dhcp_count':50,
-                      'subnet_address':"192.168.1.0/24",
-                      'dhcp_enabled':True,
-                      'dhcp_start_address':"192.168.1.3",
-                      'ip_version':"IPv4",
-                      'dns_address':"192.168.1.2"
-                      }
-# global variable for wait time
-INTERVAL_TIME = 5
-MAX_WAIT_TIME = 1800
-
-VCAVERSION = '5.9'
-
-__author__ = "Mustafa Bayramov, Arpita Kate, Sachin Bhangare"
-__date__ = "$12-Jan-2017 11:09:29$"
-__version__ = '0.1'
-
-#     -1: "Could not be created",
-#     0: "Unresolved",
-#     1: "Resolved",
-#     2: "Deployed",
-#     3: "Suspended",
-#     4: "Powered on",
-#     5: "Waiting for user input",
-#     6: "Unknown state",
-#     7: "Unrecognized state",
-#     8: "Powered off",
-#     9: "Inconsistent state",
-#     10: "Children do not all have the same status",
-#     11: "Upload initiated, OVF descriptor pending",
-#     12: "Upload initiated, copying contents",
-#     13: "Upload initiated , disk contents pending",
-#     14: "Upload has been quarantined",
-#     15: "Upload quarantine period has expired"
-
-# mapping vCD status to MANO
-vcdStatusCode2manoFormat = {4: 'ACTIVE',
-                            7: 'PAUSED',
-                            3: 'SUSPENDED',
-                            8: 'INACTIVE',
-                            12: 'BUILD',
-                            -1: 'ERROR',
-                            14: 'DELETED'}
-
-#
-netStatus2manoFormat = {'ACTIVE': 'ACTIVE', 'PAUSED': 'PAUSED', 'INACTIVE': 'INACTIVE', 'BUILD': 'BUILD',
-                        'ERROR': 'ERROR', 'DELETED': 'DELETED'
-                        }
-
-class vimconnector(vimconn.vimconnector):
-    # dict used to store flavor in memory
-    flavorlist = {}
-
-    def __init__(self, uuid=None, name=None, tenant_id=None, tenant_name=None,
-                 url=None, url_admin=None, user=None, passwd=None, log_level=None, config={}, persistent_info={}):
-        """
-        Constructor create vmware connector to vCloud director.
-
-        By default construct doesn't validate connection state. So client can create object with None arguments.
-        If client specified username , password and host and VDC name.  Connector initialize other missing attributes.
-
-        a) It initialize organization UUID
-        b) Initialize tenant_id/vdc ID.   (This information derived from tenant name)
-
-        Args:
-            uuid - is organization uuid.
-            name - is organization name that must be presented in vCloud director.
-            tenant_id - is VDC uuid it must be presented in vCloud director
-            tenant_name - is VDC name.
-            url - is hostname or ip address of vCloud director
-            url_admin - same as above.
-            user - is user that administrator for organization. Caller must make sure that
-                    username has right privileges.
-
-            password - is password for a user.
-
-            VMware connector also requires PVDC administrative privileges and separate account.
-            This variables must be passed via config argument dict contains keys
-
-            dict['admin_username']
-            dict['admin_password']
-            config - Provide NSX and vCenter information
-
-            Returns:
-                Nothing.
-        """
-
-        vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url,
-                                      url_admin, user, passwd, log_level, config)
-
-        self.logger = logging.getLogger('openmano.vim.vmware')
-        self.logger.setLevel(10)
-        self.persistent_info = persistent_info
-
-        self.name = name
-        self.id = uuid
-        self.url = url
-        self.url_admin = url_admin
-        self.tenant_id = tenant_id
-        self.tenant_name = tenant_name
-        self.user = user
-        self.passwd = passwd
-        self.config = config
-        self.admin_password = None
-        self.admin_user = None
-        self.org_name = ""
-        self.nsx_manager = None
-        self.nsx_user = None
-        self.nsx_password = None
-        self.vcenter_ip = None
-        self.vcenter_port = None
-        self.vcenter_user = None
-        self.vcenter_password = None
-
-        if tenant_name is not None:
-            orgnameandtenant = tenant_name.split(":")
-            if len(orgnameandtenant) == 2:
-                self.tenant_name = orgnameandtenant[1]
-                self.org_name = orgnameandtenant[0]
-            else:
-                self.tenant_name = tenant_name
-        if "orgname" in config:
-            self.org_name = config['orgname']
-
-        if log_level:
-            self.logger.setLevel(getattr(logging, log_level))
-
-        try:
-            self.admin_user = config['admin_username']
-            self.admin_password = config['admin_password']
-        except KeyError:
-            raise vimconn.vimconnException(message="Error admin username or admin password is empty.")
-
-        try:
-            self.nsx_manager = config['nsx_manager']
-            self.nsx_user = config['nsx_user']
-            self.nsx_password = config['nsx_password']
-        except KeyError:
-            raise vimconn.vimconnException(message="Error: nsx manager or nsx user or nsx password is empty in Config")
-
-        self.vcenter_ip = config.get("vcenter_ip", None)
-        self.vcenter_port = config.get("vcenter_port", None)
-        self.vcenter_user = config.get("vcenter_user", None)
-        self.vcenter_password = config.get("vcenter_password", None)
-
-        self.org_uuid = None
-        self.vca = None
-
-        if not url:
-            raise vimconn.vimconnException('url param can not be NoneType')
-
-        if not self.url_admin:  # try to use normal url
-            self.url_admin = self.url
-
-        logging.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self.id, self.org_name,
-                                                                              self.tenant_id, self.tenant_name))
-        logging.debug("vcd url {} vcd username: {} vcd password: {}".format(self.url, self.user, self.passwd))
-        logging.debug("vcd admin username {} vcd admin passowrd {}".format(self.admin_user, self.admin_password))
-
-        # initialize organization
-        if self.user is not None and self.passwd is not None and self.url:
-            self.init_organization()
-
-    def __getitem__(self, index):
-        if index == 'name':
-            return self.name
-        if index == 'tenant_id':
-            return self.tenant_id
-        if index == 'tenant_name':
-            return self.tenant_name
-        elif index == 'id':
-            return self.id
-        elif index == 'org_name':
-            return self.org_name
-        elif index == 'org_uuid':
-            return self.org_uuid
-        elif index == 'user':
-            return self.user
-        elif index == 'passwd':
-            return self.passwd
-        elif index == 'url':
-            return self.url
-        elif index == 'url_admin':
-            return self.url_admin
-        elif index == "config":
-            return self.config
-        else:
-            raise KeyError("Invalid key '%s'" % str(index))
-
-    def __setitem__(self, index, value):
-        if index == 'name':
-            self.name = value
-        if index == 'tenant_id':
-            self.tenant_id = value
-        if index == 'tenant_name':
-            self.tenant_name = value
-        elif index == 'id':
-            self.id = value
-        elif index == 'org_name':
-            self.org_name = value
-        elif index == 'org_uuid':
-            self.org_uuid = value
-        elif index == 'user':
-            self.user = value
-        elif index == 'passwd':
-            self.passwd = value
-        elif index == 'url':
-            self.url = value
-        elif index == 'url_admin':
-            self.url_admin = value
-        else:
-            raise KeyError("Invalid key '%s'" % str(index))
-
-    def connect_as_admin(self):
-        """ Method connect as pvdc admin user to vCloud director.
-            There are certain action that can be done only by provider vdc admin user.
-            Organization creation / provider network creation etc.
-
-            Returns:
-                The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
-        """
-
-        self.logger.debug("Logging in to a vca {} as admin.".format(self.org_name))
-
-        vca_admin = VCA(host=self.url,
-                        username=self.admin_user,
-                        service_type=STANDALONE,
-                        version=VCAVERSION,
-                        verify=False,
-                        log=False)
-        result = vca_admin.login(password=self.admin_password, org='System')
-        if not result:
-            raise vimconn.vimconnConnectionException(
-                "Can't connect to a vCloud director as: {}".format(self.admin_user))
-        result = vca_admin.login(token=vca_admin.token, org='System', org_url=vca_admin.vcloud_session.org_url)
-        if result is True:
-            self.logger.info(
-                "Successfully logged to a vcloud direct org: {} as user: {}".format('System', self.admin_user))
-
-        return vca_admin
-
-    def connect(self):
-        """ Method connect as normal user to vCloud director.
-
-            Returns:
-                The return vca object that letter can be used to connect to vCloud director as admin for VDC
-        """
-
-        try:
-            self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.org_name,
-                                                                                      self.user,
-                                                                                      self.org_name))
-            vca = VCA(host=self.url,
-                      username=self.user,
-                      service_type=STANDALONE,
-                      version=VCAVERSION,
-                      verify=False,
-                      log=False)
-
-            result = vca.login(password=self.passwd, org=self.org_name)
-            if not result:
-                raise vimconn.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self.user))
-            result = vca.login(token=vca.token, org=self.org_name, org_url=vca.vcloud_session.org_url)
-            if result is True:
-                self.logger.info(
-                    "Successfully logged to a vcloud direct org: {} as user: {}".format(self.org_name, self.user))
-
-        except:
-            raise vimconn.vimconnConnectionException("Can't connect to a vCloud director org: "
-                                                     "{} as user: {}".format(self.org_name, self.user))
-
-        return vca
-
-    def init_organization(self):
-        """ Method initialize organization UUID and VDC parameters.
-
-            At bare minimum client must provide organization name that present in vCloud director and VDC.
-
-            The VDC - UUID ( tenant_id) will be initialized at the run time if client didn't call constructor.
-            The Org - UUID will be initialized at the run time if data center present in vCloud director.
-
-            Returns:
-                The return vca object that letter can be used to connect to vcloud direct as admin
-        """
-        try:
-            if self.org_uuid is None:
-                org_dict = self.get_org_list()
-                for org in org_dict:
-                    # we set org UUID at the init phase but we can do it only when we have valid credential.
-                    if org_dict[org] == self.org_name:
-                        self.org_uuid = org
-                        self.logger.debug("Setting organization UUID {}".format(self.org_uuid))
-                        break
-                else:
-                    raise vimconn.vimconnException("Vcloud director organization {} not found".format(self.org_name))
-
-                # if well good we require for org details
-                org_details_dict = self.get_org(org_uuid=self.org_uuid)
-
-                # we have two case if we want to initialize VDC ID or VDC name at run time
-                # tenant_name provided but no tenant id
-                if self.tenant_id is None and self.tenant_name is not None and 'vdcs' in org_details_dict:
-                    vdcs_dict = org_details_dict['vdcs']
-                    for vdc in vdcs_dict:
-                        if vdcs_dict[vdc] == self.tenant_name:
-                            self.tenant_id = vdc
-                            self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
-                                                                                                    self.org_name))
-                            break
-                    else:
-                        raise vimconn.vimconnException("Tenant name indicated but not present in vcloud director.")
-                    # case two we have tenant_id but we don't have tenant name so we find and set it.
-                    if self.tenant_id is not None and self.tenant_name is None and 'vdcs' in org_details_dict:
-                        vdcs_dict = org_details_dict['vdcs']
-                        for vdc in vdcs_dict:
-                            if vdc == self.tenant_id:
-                                self.tenant_name = vdcs_dict[vdc]
-                                self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
-                                                                                                        self.org_name))
-                                break
-                        else:
-                            raise vimconn.vimconnException("Tenant id indicated but not present in vcloud director")
-            self.logger.debug("Setting organization uuid {}".format(self.org_uuid))
-        except:
-            self.logger.debug("Failed initialize organization UUID for org {}".format(self.org_name))
-            self.logger.debug(traceback.format_exc())
-            self.org_uuid = None
-
-    def new_tenant(self, tenant_name=None, tenant_description=None):
-        """ Method adds a new tenant to VIM with this name.
-            This action requires access to create VDC action in vCloud director.
-
-            Args:
-                tenant_name is tenant_name to be created.
-                tenant_description not used for this call
-
-            Return:
-                returns the tenant identifier in UUID format.
-                If action is failed method will throw vimconn.vimconnException method
-            """
-        vdc_task = self.create_vdc(vdc_name=tenant_name)
-        if vdc_task is not None:
-            vdc_uuid, value = vdc_task.popitem()
-            self.logger.info("Crated new vdc {} and uuid: {}".format(tenant_name, vdc_uuid))
-            return vdc_uuid
-        else:
-            raise vimconn.vimconnException("Failed create tenant {}".format(tenant_name))
-
-    def delete_tenant(self, tenant_id=None):
-        """Delete a tenant from VIM"""
-        'Returns the tenant identifier'
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def get_tenant_list(self, filter_dict={}):
-        """Obtain tenants of VIM
-        filter_dict can contain the following keys:
-            name: filter by tenant name
-            id: filter by tenant uuid/id
-            <other VIM specific>
-        Returns the tenant list of dictionaries:
-            [{'name':'<name>, 'id':'<id>, ...}, ...]
-
-        """
-        org_dict = self.get_org(self.org_uuid)
-        vdcs_dict = org_dict['vdcs']
-
-        vdclist = []
-        try:
-            for k in vdcs_dict:
-                entry = {'name': vdcs_dict[k], 'id': k}
-                # if caller didn't specify dictionary we return all tenants.
-                if filter_dict is not None and filter_dict:
-                    filtered_entry = entry.copy()
-                    filtered_dict = set(entry.keys()) - set(filter_dict)
-                    for unwanted_key in filtered_dict: del entry[unwanted_key]
-                    if filter_dict == entry:
-                        vdclist.append(filtered_entry)
-                else:
-                    vdclist.append(entry)
-        except:
-            self.logger.debug("Error in get_tenant_list()")
-            self.logger.debug(traceback.format_exc())
-            raise vimconn.vimconnException("Incorrect state. {}")
-
-        return vdclist
-
-    def new_network(self, net_name, net_type, ip_profile=None, shared=False):
-        """Adds a tenant network to VIM
-            net_name is the name
-            net_type can be 'bridge','data'.'ptp'.
-            ip_profile is a dict containing the IP parameters of the network
-            shared is a boolean
-        Returns the network identifier"""
-
-        self.logger.debug("new_network tenant {} net_type {} ip_profile {} shared {}"
-                          .format(net_name, net_type, ip_profile, shared))
-
-        isshared = 'false'
-        if shared:
-            isshared = 'true'
-
-        network_uuid = self.create_network(network_name=net_name, net_type=net_type,
-                                           ip_profile=ip_profile, isshared=isshared)
-        if network_uuid is not None:
-            return network_uuid
-        else:
-            raise vimconn.vimconnUnexpectedResponse("Failed create a new network {}".format(net_name))
-
-    def get_vcd_network_list(self):
-        """ Method available organization for a logged in tenant
-
-            Returns:
-                The return vca object that letter can be used to connect to vcloud direct as admin
-        """
-
-        self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        if not self.tenant_name:
-            raise vimconn.vimconnConnectionException("Tenant name is empty.")
-
-        vdc = vca.get_vdc(self.tenant_name)
-        if vdc is None:
-            raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}".format(self.tenant_name))
-
-        vdc_uuid = vdc.get_id().split(":")[3]
-        networks = vca.get_networks(vdc.get_name())
-        network_list = []
-        try:
-            for network in networks:
-                filter_dict = {}
-                netid = network.get_id().split(":")
-                if len(netid) != 4:
-                    continue
-
-                filter_dict["name"] = network.get_name()
-                filter_dict["id"] = netid[3]
-                filter_dict["shared"] = network.get_IsShared()
-                filter_dict["tenant_id"] = vdc_uuid
-                if network.get_status() == 1:
-                    filter_dict["admin_state_up"] = True
-                else:
-                    filter_dict["admin_state_up"] = False
-                filter_dict["status"] = "ACTIVE"
-                filter_dict["type"] = "bridge"
-                network_list.append(filter_dict)
-                self.logger.debug("get_vcd_network_list adding entry {}".format(filter_dict))
-        except:
-            self.logger.debug("Error in get_vcd_network_list")
-            self.logger.debug(traceback.format_exc())
-            pass
-
-        self.logger.debug("get_vcd_network_list returning {}".format(network_list))
-        return network_list
-
-    def get_network_list(self, filter_dict={}):
-        """Obtain tenant networks of VIM
-        Filter_dict can be:
-            name: network name  OR/AND
-            id: network uuid    OR/AND
-            shared: boolean     OR/AND
-            tenant_id: tenant   OR/AND
-            admin_state_up: boolean
-            status: 'ACTIVE'
-
-        [{key : value , key : value}]
-
-        Returns the network list of dictionaries:
-            [{<the fields at Filter_dict plus some VIM specific>}, ...]
-            List can be empty
-        """
-
-        self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        if not self.tenant_name:
-            raise vimconn.vimconnConnectionException("Tenant name is empty.")
-
-        vdc = vca.get_vdc(self.tenant_name)
-        if vdc is None:
-            raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}.".format(self.tenant_name))
-
-        vdcid = vdc.get_id().split(":")[3]
-        networks = vca.get_networks(vdc.get_name())
-        network_list = []
-
-        try:
-            for network in networks:
-                filter_entry = {}
-                net_uuid = network.get_id().split(":")
-                if len(net_uuid) != 4:
-                    continue
-                else:
-                    net_uuid = net_uuid[3]
-                # create dict entry
-                self.logger.debug("Adding  {} to a list vcd id {} network {}".format(net_uuid,
-                                                                                     vdcid,
-                                                                                     network.get_name()))
-                filter_entry["name"] = network.get_name()
-                filter_entry["id"] = net_uuid
-                filter_entry["shared"] = network.get_IsShared()
-                filter_entry["tenant_id"] = vdcid
-                if network.get_status() == 1:
-                    filter_entry["admin_state_up"] = True
-                else:
-                    filter_entry["admin_state_up"] = False
-                filter_entry["status"] = "ACTIVE"
-                filter_entry["type"] = "bridge"
-                filtered_entry = filter_entry.copy()
-
-                if filter_dict is not None and filter_dict:
-                    # we remove all the key : value we don't care and match only
-                    # respected field
-                    filtered_dict = set(filter_entry.keys()) - set(filter_dict)
-                    for unwanted_key in filtered_dict: del filter_entry[unwanted_key]
-                    if filter_dict == filter_entry:
-                        network_list.append(filtered_entry)
-                else:
-                    network_list.append(filtered_entry)
-        except:
-            self.logger.debug("Error in get_vcd_network_list")
-            self.logger.debug(traceback.format_exc())
-
-        self.logger.debug("Returning {}".format(network_list))
-        return network_list
-
-    def get_network(self, net_id):
-        """Method obtains network details of net_id VIM network
-           Return a dict with  the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
-        vdc = vca.get_vdc(self.tenant_name)
-        vdc_id = vdc.get_id().split(":")[3]
-
-        networks = vca.get_networks(vdc.get_name())
-        filter_dict = {}
-
-        try:
-            for network in networks:
-                vdc_network_id = network.get_id().split(":")
-                if len(vdc_network_id) == 4 and vdc_network_id[3] == net_id:
-                    filter_dict["name"] = network.get_name()
-                    filter_dict["id"] = vdc_network_id[3]
-                    filter_dict["shared"] = network.get_IsShared()
-                    filter_dict["tenant_id"] = vdc_id
-                    if network.get_status() == 1:
-                        filter_dict["admin_state_up"] = True
-                    else:
-                        filter_dict["admin_state_up"] = False
-                    filter_dict["status"] = "ACTIVE"
-                    filter_dict["type"] = "bridge"
-                    self.logger.debug("Returning {}".format(filter_dict))
-                    return filter_dict
-        except:
-            self.logger.debug("Error in get_network")
-            self.logger.debug(traceback.format_exc())
-
-        return filter_dict
-
-    def delete_network(self, net_id):
-        """
-            Method Deletes a tenant network from VIM, provide the network id.
-
-            Returns the network identifier or raise an exception
-        """
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() for tenant {} is failed.".format(self.tenant_name))
-
-        vcd_network = self.get_vcd_network(network_uuid=net_id)
-        if vcd_network is not None and vcd_network:
-            if self.delete_network_action(network_uuid=net_id):
-                return net_id
-        else:
-            raise vimconn.vimconnNotFoundException("Network {} not found".format(net_id))
-
-    def refresh_nets_status(self, net_list):
-        """Get the status of the networks
-           Params: the list of network identifiers
-           Returns a dictionary with:
-                net_id:         #VIM id of this network
-                    status:     #Mandatory. Text with one of:
-                                #  DELETED (not found at vim)
-                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
-                                #  OTHER (Vim reported other status not understood)
-                                #  ERROR (VIM indicates an ERROR status)
-                                #  ACTIVE, INACTIVE, DOWN (admin down),
-                                #  BUILD (on building process)
-                                #
-                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR
-                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
-
-        """
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
-        dict_entry = {}
-        try:
-            for net in net_list:
-                errormsg = ''
-                vcd_network = self.get_vcd_network(network_uuid=net)
-                if vcd_network is not None and vcd_network:
-                    if vcd_network['status'] == '1':
-                        status = 'ACTIVE'
-                    else:
-                        status = 'DOWN'
-                else:
-                    status = 'DELETED'
-                    errormsg = 'Network not found.'
-
-                dict_entry[net] = {'status': status, 'error_msg': errormsg,
-                                   'vim_info': yaml.safe_dump(vcd_network)}
-        except:
-            self.logger.debug("Error in refresh_nets_status")
-            self.logger.debug(traceback.format_exc())
-
-        return dict_entry
-
-    def get_flavor(self, flavor_id):
-        """Obtain flavor details from the  VIM
-            Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
-        """
-        if flavor_id not in vimconnector.flavorlist:
-            raise vimconn.vimconnNotFoundException("Flavor not found.")
-        return vimconnector.flavorlist[flavor_id]
-
-    def new_flavor(self, flavor_data):
-        """Adds a tenant flavor to VIM
-            flavor_data contains a dictionary with information, keys:
-                name: flavor name
-                ram: memory (cloud type) in MBytes
-                vpcus: cpus (cloud type)
-                extended: EPA parameters
-                  - numas: #items requested in same NUMA
-                        memory: number of 1G huge pages memory
-                        paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
-                        interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
-                          - name: interface name
-                            dedicated: yes|no|yes:sriov;  for PT, SRIOV or only one SRIOV for the physical NIC
-                            bandwidth: X Gbps; requested guarantee bandwidth
-                            vpci: requested virtual PCI address
-                disk: disk size
-                is_public:
-                 #TODO to concrete
-        Returns the flavor identifier"""
-
-        # generate a new uuid put to internal dict and return it.
-        self.logger.debug("Creating new flavor - flavor_data: {}".format(flavor_data))
-        new_flavor=flavor_data
-        ram = flavor_data.get(FLAVOR_RAM_KEY, 1024)
-        cpu = flavor_data.get(FLAVOR_VCPUS_KEY, 1)
-        disk = flavor_data.get(FLAVOR_DISK_KEY, 1)
-
-        extended_flv = flavor_data.get("extended")
-        if extended_flv:
-            numas=extended_flv.get("numas")
-            if numas:
-                for numa in numas:
-                    #overwrite ram and vcpus
-                    ram = numa['memory']*1024
-                    if 'paired-threads' in numa:
-                        cpu = numa['paired-threads']*2
-                    elif 'cores' in numa:
-                        cpu = numa['cores']
-                    elif 'threads' in numa:
-                        cpu = numa['threads']
-
-        new_flavor[FLAVOR_RAM_KEY] = ram
-        new_flavor[FLAVOR_VCPUS_KEY] = cpu
-        new_flavor[FLAVOR_DISK_KEY] = disk
-        # generate a new uuid put to internal dict and return it.
-        flavor_id = uuid.uuid4()
-        vimconnector.flavorlist[str(flavor_id)] = new_flavor
-        self.logger.debug("Created flavor - {} : {}".format(flavor_id, new_flavor))
-
-        return str(flavor_id)
-
-    def delete_flavor(self, flavor_id):
-        """Deletes a tenant flavor from VIM identify by its id
-
-           Returns the used id or raise an exception
-        """
-        if flavor_id not in vimconnector.flavorlist:
-            raise vimconn.vimconnNotFoundException("Flavor not found.")
-
-        vimconnector.flavorlist.pop(flavor_id, None)
-        return flavor_id
-
-    def new_image(self, image_dict):
-        """
-        Adds a tenant image to VIM
-        Returns:
-            200, image-id        if the image is created
-            <0, message          if there is an error
-        """
-
-        return self.get_image_id_from_path(image_dict['location'])
-
-    def delete_image(self, image_id):
-        """
-
-        :param image_id:
-        :return:
-        """
-
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def catalog_exists(self, catalog_name, catalogs):
-        """
-
-        :param catalog_name:
-        :param catalogs:
-        :return:
-        """
-        for catalog in catalogs:
-            if catalog.name == catalog_name:
-                return True
-        return False
-
-    def create_vimcatalog(self, vca=None, catalog_name=None):
-        """ Create new catalog entry in vCloud director.
-
-            Args
-                vca:  vCloud director.
-                catalog_name catalog that client wish to create.   Note no validation done for a name.
-                Client must make sure that provide valid string representation.
-
-             Return (bool) True if catalog created.
-
-        """
-        try:
-            task = vca.create_catalog(catalog_name, catalog_name)
-            result = vca.block_until_completed(task)
-            if not result:
-                return False
-            catalogs = vca.get_catalogs()
-        except:
-            return False
-        return self.catalog_exists(catalog_name, catalogs)
-
-    # noinspection PyIncorrectDocstring
-    def upload_ovf(self, vca=None, catalog_name=None, image_name=None, media_file_name=None,
-                   description='', progress=False, chunk_bytes=128 * 1024):
-        """
-        Uploads a OVF file to a vCloud catalog
-
-        :param chunk_bytes:
-        :param progress:
-        :param description:
-        :param image_name:
-        :param vca:
-        :param catalog_name: (str): The name of the catalog to upload the media.
-        :param media_file_name: (str): The name of the local media file to upload.
-        :return: (bool) True if the media file was successfully uploaded, false otherwise.
-        """
-        os.path.isfile(media_file_name)
-        statinfo = os.stat(media_file_name)
-
-        #  find a catalog entry where we upload OVF.
-        #  create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
-        #  status change.
-        #  if VCD can parse OVF we upload VMDK file
-        for catalog in vca.get_catalogs():
-            if catalog_name != catalog.name:
-                continue
-            link = filter(lambda link: link.get_type() == "application/vnd.vmware.vcloud.media+xml" and
-                                       link.get_rel() == 'add', catalog.get_Link())
-            assert len(link) == 1
-            data = """
-            <UploadVAppTemplateParams name="%s" xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"><Description>%s vApp Template</Description></UploadVAppTemplateParams>
-            """ % (escape(catalog_name), escape(description))
-            headers = vca.vcloud_session.get_vcloud_headers()
-            headers['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
-            response = Http.post(link[0].get_href(), headers=headers, data=data, verify=vca.verify, logger=self.logger)
-            if response.status_code == requests.codes.created:
-                catalogItem = XmlElementTree.fromstring(response.content)
-                entity = [child for child in catalogItem if
-                          child.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
-                href = entity.get('href')
-                template = href
-                response = Http.get(href, headers=vca.vcloud_session.get_vcloud_headers(),
-                                    verify=vca.verify, logger=self.logger)
-
-                if response.status_code == requests.codes.ok:
-                    media = mediaType.parseString(response.content, True)
-                    link = filter(lambda link: link.get_rel() == 'upload:default',
-                                  media.get_Files().get_File()[0].get_Link())[0]
-                    headers = vca.vcloud_session.get_vcloud_headers()
-                    headers['Content-Type'] = 'Content-Type text/xml'
-                    response = Http.put(link.get_href(),
-                                        data=open(media_file_name, 'rb'),
-                                        headers=headers,
-                                        verify=vca.verify, logger=self.logger)
-                    if response.status_code != requests.codes.ok:
-                        self.logger.debug(
-                            "Failed create vApp template for catalog name {} and image {}".format(catalog_name,
-                                                                                                  media_file_name))
-                        return False
-
-                # TODO fix this with aync block
-                time.sleep(5)
-
-                self.logger.debug("vApp template for catalog name {} and image {}".format(catalog_name, media_file_name))
-
-                # uploading VMDK file
-                # check status of OVF upload and upload remaining files.
-                response = Http.get(template,
-                                    headers=vca.vcloud_session.get_vcloud_headers(),
-                                    verify=vca.verify,
-                                    logger=self.logger)
-
-                if response.status_code == requests.codes.ok:
-                    media = mediaType.parseString(response.content, True)
-                    number_of_files = len(media.get_Files().get_File())
-                    for index in xrange(0, number_of_files):
-                        links_list = filter(lambda link: link.get_rel() == 'upload:default',
-                                            media.get_Files().get_File()[index].get_Link())
-                        for link in links_list:
-                            # we skip ovf since it already uploaded.
-                            if 'ovf' in link.get_href():
-                                continue
-                            # The OVF file and VMDK must be in a same directory
-                            head, tail = os.path.split(media_file_name)
-                            file_vmdk = head + '/' + link.get_href().split("/")[-1]
-                            if not os.path.isfile(file_vmdk):
-                                return False
-                            statinfo = os.stat(file_vmdk)
-                            if statinfo.st_size == 0:
-                                return False
-                            hrefvmdk = link.get_href()
-
-                            if progress:
-                                print("Uploading file: {}".format(file_vmdk))
-                            if progress:
-                                widgets = ['Uploading file: ', Percentage(), ' ', Bar(), ' ', ETA(), ' ',
-                                           FileTransferSpeed()]
-                                progress_bar = ProgressBar(widgets=widgets, maxval=statinfo.st_size).start()
-
-                            bytes_transferred = 0
-                            f = open(file_vmdk, 'rb')
-                            while bytes_transferred < statinfo.st_size:
-                                my_bytes = f.read(chunk_bytes)
-                                if len(my_bytes) <= chunk_bytes:
-                                    headers = vca.vcloud_session.get_vcloud_headers()
-                                    headers['Content-Range'] = 'bytes %s-%s/%s' % (
-                                        bytes_transferred, len(my_bytes) - 1, statinfo.st_size)
-                                    headers['Content-Length'] = str(len(my_bytes))
-                                    response = Http.put(hrefvmdk,
-                                                        headers=headers,
-                                                        data=my_bytes,
-                                                        verify=vca.verify,
-                                                        logger=None)
-
-                                    if response.status_code == requests.codes.ok:
-                                        bytes_transferred += len(my_bytes)
-                                        if progress:
-                                            progress_bar.update(bytes_transferred)
-                                    else:
-                                        self.logger.debug(
-                                            'file upload failed with error: [%s] %s' % (response.status_code,
-                                                                                        response.content))
-
-                                        f.close()
-                                        return False
-                            f.close()
-                            if progress:
-                                progress_bar.finish()
-                            time.sleep(10)
-                    return True
-                else:
-                    self.logger.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
-                                      format(catalog_name, media_file_name))
-                    return False
-
-        self.logger.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name, media_file_name))
-        return False
-
-    def upload_vimimage(self, vca=None, catalog_name=None, media_name=None, medial_file_name=None, progress=False):
-        """Upload media file"""
-        # TODO add named parameters for readability
-
-        return self.upload_ovf(vca=vca, catalog_name=catalog_name, image_name=media_name.split(".")[0],
-                               media_file_name=medial_file_name, description='medial_file_name', progress=progress)
-
-    def validate_uuid4(self, uuid_string=None):
-        """  Method validate correct format of UUID.
-
-        Return: true if string represent valid uuid
-        """
-        try:
-            val = uuid.UUID(uuid_string, version=4)
-        except ValueError:
-            return False
-        return True
-
-    def get_catalogid(self, catalog_name=None, catalogs=None):
-        """  Method check catalog and return catalog ID in UUID format.
-
-        Args
-            catalog_name: catalog name as string
-            catalogs:  list of catalogs.
-
-        Return: catalogs uuid
-        """
-
-        for catalog in catalogs:
-            if catalog.name == catalog_name:
-                catalog_id = catalog.get_id().split(":")
-                return catalog_id[3]
-        return None
-
-    def get_catalogbyid(self, catalog_uuid=None, catalogs=None):
-        """  Method check catalog and return catalog name lookup done by catalog UUID.
-
-        Args
-            catalog_name: catalog name as string
-            catalogs:  list of catalogs.
-
-        Return: catalogs name or None
-        """
-
-        if not self.validate_uuid4(uuid_string=catalog_uuid):
-            return None
-
-        for catalog in catalogs:
-            catalog_id = catalog.get_id().split(":")[3]
-            if catalog_id == catalog_uuid:
-                return catalog.name
-        return None
-
-    def get_image_id_from_path(self, path=None, progress=False):
-        """  Method upload OVF image to vCloud director.
-
-        Each OVF image represented as single catalog entry in vcloud director.
-        The method check for existing catalog entry.  The check done by file name without file extension.
-
-        if given catalog name already present method will respond with existing catalog uuid otherwise
-        it will create new catalog entry and upload OVF file to newly created catalog.
-
-        If method can't create catalog entry or upload a file it will throw exception.
-
-        Method accept boolean flag progress that will output progress bar. It useful method
-        for standalone upload use case. In case to test large file upload.
-
-        Args
-            path: - valid path to OVF file.
-            progress - boolean progress bar show progress bar.
-
-        Return: if image uploaded correct method will provide image catalog UUID.
-        """
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        if not path:
-            raise vimconn.vimconnException("Image path can't be None.")
-
-        if not os.path.isfile(path):
-            raise vimconn.vimconnException("Can't read file. File not found.")
-
-        if not os.access(path, os.R_OK):
-            raise vimconn.vimconnException("Can't read file. Check file permission to read.")
-
-        self.logger.debug("get_image_id_from_path() client requesting {} ".format(path))
-
-        dirpath, filename = os.path.split(path)
-        flname, file_extension = os.path.splitext(path)
-        if file_extension != '.ovf':
-            self.logger.debug("Wrong file extension {} connector support only OVF container.".format(file_extension))
-            raise vimconn.vimconnException("Wrong container.  vCloud director supports only OVF.")
-
-        catalog_name = os.path.splitext(filename)[0]
-        catalog_md5_name = hashlib.md5(path).hexdigest()
-        self.logger.debug("File name {} Catalog Name {} file path {} "
-                          "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name))
-
-        catalogs = vca.get_catalogs()
-        if len(catalogs) == 0:
-            self.logger.info("Creating a new catalog entry {} in vcloud director".format(catalog_name))
-            result = self.create_vimcatalog(vca, catalog_md5_name)
-            if not result:
-                raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
-            result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
-                                          media_name=filename, medial_file_name=path, progress=progress)
-            if not result:
-                raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
-            return self.get_catalogid(catalog_name, vca.get_catalogs())
-        else:
-            for catalog in catalogs:
-                # search for existing catalog if we find same name we return ID
-                # TODO optimize this
-                if catalog.name == catalog_md5_name:
-                    self.logger.debug("Found existing catalog entry for {} "
-                                      "catalog id {}".format(catalog_name,
-                                                             self.get_catalogid(catalog_md5_name, catalogs)))
-                    return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
-
-        # if we didn't find existing catalog we create a new one and upload image.
-        self.logger.debug("Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name))
-        result = self.create_vimcatalog(vca, catalog_md5_name)
-        if not result:
-            raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
-
-        result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
-                                      media_name=filename, medial_file_name=path, progress=progress)
-        if not result:
-            raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_md5_name))
-
-        return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
-
-    def get_image_list(self, filter_dict={}):
-        '''Obtain tenant images from VIM
-        Filter_dict can be:
-            name: image name
-            id: image uuid
-            checksum: image checksum
-            location: image path
-        Returns the image list of dictionaries:
-            [{<the fields at Filter_dict plus some VIM specific>}, ...]
-            List can be empty
-        '''
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-        try:
-            image_list = []
-            catalogs = vca.get_catalogs()
-            if len(catalogs) == 0:
-                return image_list
-            else:
-                for catalog in catalogs:
-                    catalog_uuid = catalog.get_id().split(":")[3]
-                    name = catalog.name
-                    filtered_dict = {}
-                    if filter_dict.get("name") and filter_dict["name"] != name:
-                        continue
-                    if filter_dict.get("id") and filter_dict["id"] != catalog_uuid:
-                        continue
-                    filtered_dict ["name"] = name
-                    filtered_dict ["id"] = catalog_uuid
-                    image_list.append(filtered_dict)
-
-                self.logger.debug("List of already created catalog items: {}".format(image_list))
-                return image_list
-        except Exception as exp:
-            raise vimconn.vimconnException("Exception occured while retriving catalog items {}".format(exp))
-
-    def get_vappid(self, vdc=None, vapp_name=None):
-        """ Method takes vdc object and vApp name and returns vapp uuid or None
-
-        Args:
-            vdc: The VDC object.
-            vapp_name: is application vappp name identifier
-
-        Returns:
-                The return vApp name otherwise None
-        """
-        if vdc is None or vapp_name is None:
-            return None
-        # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
-        try:
-            refs = filter(lambda ref: ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
-                          vdc.ResourceEntities.ResourceEntity)
-            if len(refs) == 1:
-                return refs[0].href.split("vapp")[1][1:]
-        except Exception as e:
-            self.logger.exception(e)
-            return False
-        return None
-
-    def check_vapp(self, vdc=None, vapp_uuid=None):
-        """ Method Method returns True or False if vapp deployed in vCloud director
-
-            Args:
-                vca: Connector to VCA
-                vdc: The VDC object.
-                vappid: vappid is application identifier
-
-            Returns:
-                The return True if vApp deployed
-                :param vdc:
-                :param vapp_uuid:
-        """
-        try:
-            refs = filter(lambda ref:
-                          ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
-                          vdc.ResourceEntities.ResourceEntity)
-            for ref in refs:
-                vappid = ref.href.split("vapp")[1][1:]
-                # find vapp with respected vapp uuid
-                if vappid == vapp_uuid:
-                    return True
-        except Exception as e:
-            self.logger.exception(e)
-            return False
-        return False
-
-    def get_namebyvappid(self, vca=None, vdc=None, vapp_uuid=None):
-        """Method returns vApp name from vCD and lookup done by vapp_id.
-
-        Args:
-            vca: Connector to VCA
-            vdc: The VDC object.
-            vapp_uuid: vappid is application identifier
-
-        Returns:
-            The return vApp name otherwise None
-        """
-
-        try:
-            refs = filter(lambda ref: ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
-                          vdc.ResourceEntities.ResourceEntity)
-            for ref in refs:
-                # we care only about UUID the rest doesn't matter
-                vappid = ref.href.split("vapp")[1][1:]
-                if vappid == vapp_uuid:
-                    response = Http.get(ref.href, headers=vca.vcloud_session.get_vcloud_headers(), verify=vca.verify,
-                                        logger=self.logger)
-                    tree = XmlElementTree.fromstring(response.content)
-                    return tree.attrib['name']
-        except Exception as e:
-            self.logger.exception(e)
-            return None
-        return None
-
-    def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={},
-                       cloud_config=None, disk_list=None):
-        """Adds a VM instance to VIM
-        Params:
-            start: indicates if VM must start or boot in pause mode. Ignored
-            image_id,flavor_id: image and flavor uuid
-            net_list: list of interfaces, each one is a dictionary with:
-                name:
-                net_id: network uuid to connect
-                vpci: virtual vcpi to assign
-                model: interface model, virtio, e2000, ...
-                mac_address:
-                use: 'data', 'bridge',  'mgmt'
-                type: 'virtual', 'PF', 'VF', 'VFnotShared'
-                vim_id: filled/added by this function
-                cloud_config: can be a text script to be passed directly to cloud-init,
-                    or an object to inject users and ssh keys with format:
-                        key-pairs: [] list of keys to install to the default user
-                        users: [{ name, key-pairs: []}] list of users to add with their key-pair
-                #TODO ip, security groups
-        Returns >=0, the instance identifier
-                <0, error_text
-        """
-
-        self.logger.info("Creating new instance for entry {}".format(name))
-        self.logger.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".format(
-                                    description, start, image_id, flavor_id, net_list, cloud_config))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        #new vm name = vmname + tenant_id + uuid
-        new_vm_name = [name, '-', str(uuid.uuid4())]
-        vmname_andid = ''.join(new_vm_name)
-
-        # if vm already deployed we return existing uuid
-        # vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), name)
-        # if vapp_uuid is not None:
-        #     return vapp_uuid
-
-        # we check for presence of VDC, Catalog entry and Flavor.
-        vdc = vca.get_vdc(self.tenant_name)
-        if vdc is None:
-            raise vimconn.vimconnNotFoundException(
-                "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(name))
-        catalogs = vca.get_catalogs()
-        if catalogs is None:
-            raise vimconn.vimconnNotFoundException(
-                "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(name))
-
-        catalog_hash_name = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
-        if catalog_hash_name:
-            self.logger.info("Found catalog entry {} for image id {}".format(catalog_hash_name, image_id))
-        else:
-            raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
-                                                   "(Failed retrieve catalog information {})".format(name, image_id))
-
-
-        # Set vCPU and Memory based on flavor.
-        #
-        vm_cpus = None
-        vm_memory = None
-        vm_disk = None
-        pci_devices_info = []
-        if flavor_id is not None:
-            if flavor_id not in vimconnector.flavorlist:
-                raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
-                                                       "Failed retrieve flavor information "
-                                                       "flavor id {}".format(name, flavor_id))
-            else:
-                try:
-                    flavor = vimconnector.flavorlist[flavor_id]
-                    vm_cpus = flavor[FLAVOR_VCPUS_KEY]
-                    vm_memory = flavor[FLAVOR_RAM_KEY]
-                    vm_disk = flavor[FLAVOR_DISK_KEY]
-                    extended = flavor.get("extended", None)
-                    if extended:
-                        numas=extended.get("numas", None)
-                        if numas:
-                            for numa in numas:
-                                for interface in numa.get("interfaces",() ):
-                                    if interface["dedicated"].strip()=="yes":
-                                        pci_devices_info.append(interface)
-                except Exception as exp:
-                    raise vimconn.vimconnException("Corrupted flavor. {}.Exception: {}".format(flavor_id, exp))
-
-        # image upload creates template name as catalog name space Template.
-        templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
-        power_on = 'false'
-        if start:
-            power_on = 'true'
-
-        # client must provide at least one entry in net_list if not we report error
-        #If net type is mgmt, then configure it as primary net & use its NIC index as primary NIC
-        #If no mgmt, then the 1st NN in netlist is considered as primary net. 
-        primary_net = None
-        primary_netname = None
-        network_mode = 'bridged'
-        if net_list is not None and len(net_list) > 0:
-            for net in net_list:
-                if 'use' in net and net['use'] == 'mgmt':
-                    primary_net = net
-            if primary_net is None:
-                primary_net = net_list[0]
-
-            try:
-                primary_net_id = primary_net['net_id']
-                network_dict = self.get_vcd_network(network_uuid=primary_net_id)
-                if 'name' in network_dict:
-                    primary_netname = network_dict['name']
-
-            except KeyError:
-                raise vimconn.vimconnException("Corrupted flavor. {}".format(primary_net))
-        else:
-            raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name))
-
-        # use: 'data', 'bridge', 'mgmt'
-        # create vApp.  Set vcpu and ram based on flavor id.
-        vapptask = vca.create_vapp(self.tenant_name, vmname_andid, templateName,
-                                   self.get_catalogbyid(image_id, catalogs),
-                                   network_name=None,  # None while creating vapp
-                                   network_mode=network_mode,
-                                   vm_name=vmname_andid,
-                                   vm_cpus=vm_cpus,  # can be None if flavor is None
-                                   vm_memory=vm_memory)  # can be None if flavor is None
-
-        if vapptask is None or vapptask is False:
-            raise vimconn.vimconnUnexpectedResponse("new_vminstance(): failed deploy vApp {}".format(vmname_andid))
-        if type(vapptask) is VappTask:
-            vca.block_until_completed(vapptask)
-
-        # we should have now vapp in undeployed state.
-        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
-        vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
-        if vapp is None:
-            raise vimconn.vimconnUnexpectedResponse(
-                "new_vminstance(): Failed failed retrieve vApp {} after we deployed".format(
-                                                                            vmname_andid))
-
-        #Add PCI passthrough configrations
-        PCI_devices_status = False
-        vm_obj = None
-        si = None
-        if len(pci_devices_info) > 0:
-            self.logger.info("Need to add PCI devices {} into VM {}".format(pci_devices_info,
-                                                                        vmname_andid ))
-            PCI_devices_status, vm_obj, vcenter_conect = self.add_pci_devices(vapp_uuid,
-                                                                            pci_devices_info,
-                                                                            vmname_andid)
-            if PCI_devices_status:
-                self.logger.info("Added PCI devives {} to VM {}".format(
-                                                            pci_devices_info,
-                                                            vmname_andid)
-                                 )
-            else:
-                self.logger.info("Fail to add PCI devives {} to VM {}".format(
-                                                            pci_devices_info,
-                                                            vmname_andid)
-                                 )
-        # add vm disk
-        if vm_disk:
-            #Assuming there is only one disk in ovf and fast provisioning in organization vDC is disabled
-            result = self.modify_vm_disk(vapp_uuid, vm_disk)
-            if result :
-                self.logger.debug("Modified Disk size of VM {} ".format(vmname_andid))
-
-        # add NICs & connect to networks in netlist
-        try:
-            self.logger.info("Request to connect VM to a network: {}".format(net_list))
-            nicIndex = 0
-            primary_nic_index = 0
-            for net in net_list:
-                # openmano uses network id in UUID format.
-                # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
-                # [{'use': 'bridge', 'net_id': '527d4bf7-566a-41e7-a9e7-ca3cdd9cef4f', 'type': 'virtual',
-                #   'vpci': '0000:00:11.0', 'name': 'eth0'}]
-
-                if 'net_id' not in net:
-                    continue
-
-                interface_net_id = net['net_id']
-                interface_net_name = self.get_network_name_by_id(network_uuid=interface_net_id)
-                interface_network_mode = net['use']
-
-                if interface_network_mode == 'mgmt':
-                    primary_nic_index = nicIndex
-
-                """- POOL (A static IP address is allocated automatically from a pool of addresses.)
-                                  - DHCP (The IP address is obtained from a DHCP service.)
-                                  - MANUAL (The IP address is assigned manually in the IpAddress element.)
-                                  - NONE (No IP addressing mode specified.)"""
-
-                if primary_netname is not None:
-                    nets = filter(lambda n: n.name == interface_net_name, vca.get_networks(self.tenant_name))
-                    if len(nets) == 1:
-                        self.logger.info("new_vminstance(): Found requested network: {}".format(nets[0].name))
-                        task = vapp.connect_to_network(nets[0].name, nets[0].href)
-                        if type(task) is GenericTask:
-                            vca.block_until_completed(task)
-                        # connect network to VM - with all DHCP by default
-                        self.logger.info("new_vminstance(): Connecting VM to a network {}".format(nets[0].name))
-                        task = vapp.connect_vms(nets[0].name,
-                                                connection_index=nicIndex,
-                                                connections_primary_index=primary_nic_index,
-                                                ip_allocation_mode='DHCP')
-                        if type(task) is GenericTask:
-                            vca.block_until_completed(task)
-                nicIndex += 1
-        except KeyError:
-            # it might be a case if specific mandatory entry in dict is empty
-            self.logger.debug("Key error {}".format(KeyError.message))
-            raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
-
-        # deploy and power on vm
-        self.logger.debug("new_vminstance(): Deploying vApp {} ".format(name))
-        deploytask = vapp.deploy(powerOn=False)
-        if type(deploytask) is GenericTask:
-            vca.block_until_completed(deploytask)
-
-        # If VM has PCI devices reserve memory for VM
-        if PCI_devices_status and vm_obj and vcenter_conect:
-            memReserve = vm_obj.config.hardware.memoryMB
-            spec = vim.vm.ConfigSpec()
-            spec.memoryAllocation = vim.ResourceAllocationInfo(reservation=memReserve)
-            task = vm_obj.ReconfigVM_Task(spec=spec)
-            if task:
-                result = self.wait_for_vcenter_task(task, vcenter_conect)
-                self.logger.info("Reserved memmoery {} MB for "\
-                                 "VM VM status: {}".format(str(memReserve),result))
-            else:
-                self.logger.info("Fail to reserved memmoery {} to VM {}".format(
-                                                            str(memReserve),str(vm_obj)))
-
-        self.logger.debug("new_vminstance(): power on vApp {} ".format(name))
-        poweron_task = vapp.poweron()
-        if type(poweron_task) is GenericTask:
-            vca.block_until_completed(poweron_task)
-
-        # check if vApp deployed and if that the case return vApp UUID otherwise -1
-        wait_time = 0
-        vapp_uuid = None
-        while wait_time <= MAX_WAIT_TIME:
-            vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
-            if vapp and vapp.me.deployed:
-                vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
-                break
-            else:
-                self.logger.debug("new_vminstance(): Wait for vApp {} to deploy".format(name))
-                time.sleep(INTERVAL_TIME)
-
-            wait_time +=INTERVAL_TIME
-
-        if vapp_uuid is not None:
-            return vapp_uuid
-        else:
-            raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
-
-    ##
-    ##
-    ##  based on current discussion
-    ##
-    ##
-    ##  server:
-    #   created: '2016-09-08T11:51:58'
-    #   description: simple-instance.linux1.1
-    #   flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
-    #   hostId: e836c036-74e7-11e6-b249-0800273e724c
-    #   image: dde30fe6-75a9-11e6-ad5f-0800273e724c
-    #   status: ACTIVE
-    #   error_msg:
-    #   interfaces: …
-    #
-    def get_vminstance(self, vim_vm_uuid=None):
-        """Returns the VM instance information from VIM"""
-
-        self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        vdc = vca.get_vdc(self.tenant_name)
-        if vdc is None:
-            raise vimconn.vimconnConnectionException(
-                "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
-
-        vm_info_dict = self.get_vapp_details_rest(vapp_uuid=vim_vm_uuid)
-        if not vm_info_dict:
-            self.logger.debug("get_vminstance(): Failed to get vApp name by UUID {}".format(vim_vm_uuid))
-            raise vimconn.vimconnNotFoundException("Failed to get vApp name by UUID {}".format(vim_vm_uuid))
-
-        status_key = vm_info_dict['status']
-        error = ''
-        try:
-            vm_dict = {'created': vm_info_dict['created'],
-                       'description': vm_info_dict['name'],
-                       'status': vcdStatusCode2manoFormat[int(status_key)],
-                       'hostId': vm_info_dict['vmuuid'],
-                       'error_msg': error,
-                       'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
-
-            if 'interfaces' in vm_info_dict:
-                vm_dict['interfaces'] = vm_info_dict['interfaces']
-            else:
-                vm_dict['interfaces'] = []
-        except KeyError:
-            vm_dict = {'created': '',
-                       'description': '',
-                       'status': vcdStatusCode2manoFormat[int(-1)],
-                       'hostId': vm_info_dict['vmuuid'],
-                       'error_msg': "Inconsistency state",
-                       'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
-
-        return vm_dict
-
-    def delete_vminstance(self, vm__vim_uuid):
-        """Method poweroff and remove VM instance from vcloud director network.
-
-        Args:
-            vm__vim_uuid: VM UUID
-
-        Returns:
-            Returns the instance identifier
-        """
-
-        self.logger.debug("Client requesting delete vm instance {} ".format(vm__vim_uuid))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        vdc = vca.get_vdc(self.tenant_name)
-        if vdc is None:
-            self.logger.debug("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
-                self.tenant_name))
-            raise vimconn.vimconnException(
-                "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
-
-        try:
-            vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
-            if vapp_name is None:
-                self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
-                return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
-            else:
-                self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
-
-            # Delete vApp and wait for status change if task executed and vApp is None.
-            vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
-
-            if vapp:
-                if vapp.me.deployed:
-                    self.logger.info("Powering off vApp {}".format(vapp_name))
-                    #Power off vApp
-                    powered_off = False
-                    wait_time = 0
-                    while wait_time <= MAX_WAIT_TIME:
-                        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
-                        if not vapp:
-                            self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
-                            return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
-
-                        power_off_task = vapp.poweroff()
-                        if type(power_off_task) is GenericTask:
-                            result = vca.block_until_completed(power_off_task)
-                            if result:
-                                powered_off = True
-                                break
-                        else:
-                            self.logger.info("Wait for vApp {} to power off".format(vapp_name))
-                            time.sleep(INTERVAL_TIME)
-
-                        wait_time +=INTERVAL_TIME
-                    if not powered_off:
-                        self.logger.debug("delete_vminstance(): Failed to power off VM instance {} ".format(vm__vim_uuid))
-                    else:
-                        self.logger.info("delete_vminstance(): Powered off VM instance {} ".format(vm__vim_uuid))
-
-                    #Undeploy vApp
-                    self.logger.info("Undeploy vApp {}".format(vapp_name))
-                    wait_time = 0
-                    undeployed = False
-                    while wait_time <= MAX_WAIT_TIME:
-                        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
-                        if not vapp:
-                            self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
-                            return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
-                        undeploy_task = vapp.undeploy(action='powerOff')
-
-                        if type(undeploy_task) is GenericTask:
-                            result = vca.block_until_completed(undeploy_task)
-                            if result:
-                                undeployed = True
-                                break
-                        else:
-                            self.logger.debug("Wait for vApp {} to undeploy".format(vapp_name))
-                            time.sleep(INTERVAL_TIME)
-
-                        wait_time +=INTERVAL_TIME
-
-                    if not undeployed:
-                        self.logger.debug("delete_vminstance(): Failed to undeploy vApp {} ".format(vm__vim_uuid)) 
-
-                # delete vapp
-                self.logger.info("Start deletion of vApp {} ".format(vapp_name))
-                vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
-
-                if vapp is not None:
-                    wait_time = 0
-                    result = False
-
-                    while wait_time <= MAX_WAIT_TIME:
-                        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
-                        if not vapp:
-                            self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
-                            return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
-
-                        delete_task = vapp.delete()
-
-                        if type(delete_task) is GenericTask:
-                            vca.block_until_completed(delete_task)
-                            result = vca.block_until_completed(delete_task)
-                            if result:
-                                break
-                        else:
-                            self.logger.debug("Wait for vApp {} to delete".format(vapp_name))
-                            time.sleep(INTERVAL_TIME)
-
-                        wait_time +=INTERVAL_TIME
-
-                    if not result:
-                        self.logger.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid))
-
-        except:
-            self.logger.debug(traceback.format_exc())
-            raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
-
-        if vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name) is None:
-            self.logger.info("Deleted vm instance {} sccessfully".format(vm__vim_uuid))
-            return vm__vim_uuid
-        else:
-            raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
-
-    def refresh_vms_status(self, vm_list):
-        """Get the status of the virtual machines and their interfaces/ports
-           Params: the list of VM identifiers
-           Returns a dictionary with:
-                vm_id:          #VIM id of this Virtual Machine
-                    status:     #Mandatory. Text with one of:
-                                #  DELETED (not found at vim)
-                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
-                                #  OTHER (Vim reported other status not understood)
-                                #  ERROR (VIM indicates an ERROR status)
-                                #  ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
-                                #  CREATING (on building process), ERROR
-                                #  ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
-                                #
-                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR
-                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
-                    interfaces:
-                     -  vim_info:         #Text with plain information obtained from vim (yaml.safe_dump)
-                        mac_address:      #Text format XX:XX:XX:XX:XX:XX
-                        vim_net_id:       #network id where this interface is connected
-                        vim_interface_id: #interface/port VIM id
-                        ip_address:       #null, or text with IPv4, IPv6 address
-        """
-
-        self.logger.debug("Client requesting refresh vm status for {} ".format(vm_list))
-
-        mac_ip_addr={}
-        rheaders = {'Content-Type': 'application/xml'}
-        iso_edges = ['edge-2','edge-3','edge-6','edge-7','edge-8','edge-9','edge-10']
-
-        try:
-            for edge in iso_edges:
-                nsx_api_url = '/api/4.0/edges/'+ edge +'/dhcp/leaseInfo'
-                self.logger.debug("refresh_vms_status: NSX Manager url: {}".format(nsx_api_url))
-
-                resp = requests.get(self.nsx_manager + nsx_api_url,
-                                    auth = (self.nsx_user, self.nsx_password),
-                                    verify = False, headers = rheaders)
-
-                if resp.status_code == requests.codes.ok:
-                    dhcp_leases = XmlElementTree.fromstring(resp.text)
-                    for child in dhcp_leases:
-                        if child.tag == 'dhcpLeaseInfo':
-                            dhcpLeaseInfo = child
-                            for leaseInfo in dhcpLeaseInfo:
-                                for elem in leaseInfo:
-                                    if (elem.tag)=='macAddress':
-                                        mac_addr = elem.text
-                                    if (elem.tag)=='ipAddress':
-                                        ip_addr = elem.text
-                                if (mac_addr) is not None:
-                                    mac_ip_addr[mac_addr]= ip_addr
-                    self.logger.debug("NSX Manager DHCP Lease info: mac_ip_addr : {}".format(mac_ip_addr))
-                else:
-                    self.logger.debug("Error occurred while getting DHCP lease info from NSX Manager: {}".format(resp.content))
-        except KeyError:
-            self.logger.debug("Error in response from NSX Manager {}".format(KeyError.message))
-            self.logger.debug(traceback.format_exc())
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        vdc = vca.get_vdc(self.tenant_name)
-        if vdc is None:
-            raise vimconn.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
-
-        vms_dict = {}
-        for vmuuid in vm_list:
-            vmname = self.get_namebyvappid(vca, vdc, vmuuid)
-            if vmname is not None:
-
-                the_vapp = vca.get_vapp(vdc, vmname)
-                vm_info = the_vapp.get_vms_details()
-                vm_status = vm_info[0]['status']
-                vm_pci_details = self.get_vm_pci_details(vmuuid)
-                vm_info[0].update(vm_pci_details)
-
-                vm_dict = {'status': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
-                           'error_msg': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
-                           'vim_info': yaml.safe_dump(vm_info), 'interfaces': []}
-
-                # get networks
-                try:
-                    vm_app_networks = the_vapp.get_vms_network_info()
-                    for vapp_network in vm_app_networks:
-                        for vm_network in vapp_network:
-                            if vm_network['name'] == vmname:
-                                #Assign IP Address based on MAC Address in NSX DHCP lease info
-                                for mac_adres,ip_adres in mac_ip_addr.iteritems():
-                                    if mac_adres == vm_network['mac']:
-                                        vm_network['ip']=ip_adres
-                                interface = {"mac_address": vm_network['mac'],
-                                             "vim_net_id": self.get_network_id_by_name(vm_network['network_name']),
-                                             "vim_interface_id": self.get_network_id_by_name(vm_network['network_name']),
-                                             'ip_address': vm_network['ip']}
-                                # interface['vim_info'] = yaml.safe_dump(vm_network)
-                                vm_dict["interfaces"].append(interface)
-                    # add a vm to vm dict
-                    vms_dict.setdefault(vmuuid, vm_dict)
-                except KeyError:
-                    self.logger.debug("Error in respond {}".format(KeyError.message))
-                    self.logger.debug(traceback.format_exc())
-
-        return vms_dict
-
-    def action_vminstance(self, vm__vim_uuid=None, action_dict=None):
-        """Send and action over a VM instance from VIM
-        Returns the vm_id if the action was successfully sent to the VIM"""
-
-        self.logger.debug("Received action for vm {} and action dict {}".format(vm__vim_uuid, action_dict))
-        if vm__vim_uuid is None or action_dict is None:
-            raise vimconn.vimconnException("Invalid request. VM id or action is None.")
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        vdc = vca.get_vdc(self.tenant_name)
-        if vdc is None:
-            return -1, "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name)
-
-        vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
-        if vapp_name is None:
-            self.logger.debug("action_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
-            raise vimconn.vimconnException("Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
-        else:
-            self.logger.info("Action_vminstance vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
-
-        try:
-            the_vapp = vca.get_vapp(vdc, vapp_name)
-            # TODO fix all status
-            if "start" in action_dict:
-                vm_info = the_vapp.get_vms_details()
-                vm_status = vm_info[0]['status']
-                self.logger.info("Power on vApp: vm_status:{} {}".format(type(vm_status),vm_status))
-                if vm_status == "Suspended" or vm_status == "Powered off":
-                    power_on_task = the_vapp.poweron()
-                    if power_on_task is not None and type(power_on_task) is GenericTask:
-                        result = vca.block_until_completed(power_on_task)
-                        if result:
-                            self.logger.info("action_vminstance: Powered on vApp: {}".format(vapp_name))
-                        else:
-                            self.logger.info("action_vminstance: Failed to power on vApp: {}".format(vapp_name))
-                    else:
-                        self.logger.info("action_vminstance: Wait for vApp {} to power on".format(vapp_name))
-            elif "rebuild" in action_dict:
-                self.logger.info("action_vminstance: Rebuilding vApp: {}".format(vapp_name))
-                power_on_task = the_vapp.deploy(powerOn=True)
-                if type(power_on_task) is GenericTask:
-                    result = vca.block_until_completed(power_on_task)
-                    if result:
-                        self.logger.info("action_vminstance: Rebuilt vApp: {}".format(vapp_name))
-                    else:
-                        self.logger.info("action_vminstance: Failed to rebuild vApp: {}".format(vapp_name))
-                else:
-                    self.logger.info("action_vminstance: Wait for vApp rebuild {} to power on".format(vapp_name))
-            elif "pause" in action_dict:
-                pass
-                ## server.pause()
-            elif "resume" in action_dict:
-                pass
-                ## server.resume()
-            elif "shutoff" in action_dict or "shutdown" in action_dict:
-                power_off_task = the_vapp.undeploy(action='powerOff')
-                if type(power_off_task) is GenericTask:
-                    result = vca.block_until_completed(power_off_task)
-                    if result:
-                        self.logger.info("action_vminstance: Powered off vApp: {}".format(vapp_name))
-                    else:
-                        self.logger.info("action_vminstance: Failed to power off vApp: {}".format(vapp_name))
-                else:
-                    self.logger.info("action_vminstance: Wait for vApp {} to power off".format(vapp_name))
-            elif "forceOff" in action_dict:
-                the_vapp.reset()
-            elif "terminate" in action_dict:
-                the_vapp.delete()
-            # elif "createImage" in action_dict:
-            #     server.create_image()
-            else:
-                pass
-        except:
-            pass
-
-    def get_vminstance_console(self, vm_id, console_type="vnc"):
-        """
-        Get a console for the virtual machine
-        Params:
-            vm_id: uuid of the VM
-            console_type, can be:
-                "novnc" (by default), "xvpvnc" for VNC types,
-                "rdp-html5" for RDP types, "spice-html5" for SPICE types
-        Returns dict with the console parameters:
-                protocol: ssh, ftp, http, https, ...
-                server:   usually ip address
-                port:     the http, ssh, ... port
-                suffix:   extra text, e.g. the http path and query string
-        """
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    # NOT USED METHODS in current version
-
-    def host_vim2gui(self, host, server_dict):
-        """Transform host dictionary from VIM format to GUI format,
-        and append to the server_dict
-        """
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def get_hosts_info(self):
-        """Get the information of deployed hosts
-        Returns the hosts content"""
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def get_hosts(self, vim_tenant):
-        """Get the hosts and deployed instances
-        Returns the hosts content"""
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def get_processor_rankings(self):
-        """Get the processor rankings in the VIM database"""
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def new_host(self, host_data):
-        """Adds a new host to VIM"""
-        '''Returns status code of the VIM response'''
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def new_external_port(self, port_data):
-        """Adds a external port to VIM"""
-        '''Returns the port identifier'''
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def new_external_network(self, net_name, net_type):
-        """Adds a external network to VIM (shared)"""
-        '''Returns the network identifier'''
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def connect_port_network(self, port_id, network_id, admin=False):
-        """Connects a external port to a network"""
-        '''Returns status code of the VIM response'''
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def new_vminstancefromJSON(self, vm_data):
-        """Adds a VM instance to VIM"""
-        '''Returns the instance identifier'''
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
-
-    def get_network_name_by_id(self, network_uuid=None):
-        """Method gets vcloud director network named based on supplied uuid.
-
-        Args:
-            network_uuid: network_id
-
-        Returns:
-            The return network name.
-        """
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        if not network_uuid:
-            return None
-
-        try:
-            org_dict = self.get_org(self.org_uuid)
-            if 'networks' in org_dict:
-                org_network_dict = org_dict['networks']
-                for net_uuid in org_network_dict:
-                    if net_uuid == network_uuid:
-                        return org_network_dict[net_uuid]
-        except:
-            self.logger.debug("Exception in get_network_name_by_id")
-            self.logger.debug(traceback.format_exc())
-
-        return None
-
-    def get_network_id_by_name(self, network_name=None):
-        """Method gets vcloud director network uuid based on supplied name.
-
-        Args:
-            network_name: network_name
-        Returns:
-            The return network uuid.
-            network_uuid: network_id
-        """
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        if not network_name:
-            self.logger.debug("get_network_id_by_name() : Network name is empty")
-            return None
-
-        try:
-            org_dict = self.get_org(self.org_uuid)
-            if org_dict and 'networks' in org_dict:
-                org_network_dict = org_dict['networks']
-                for net_uuid,net_name in org_network_dict.iteritems():
-                    if net_name == network_name:
-                        return net_uuid
-
-        except KeyError as exp:
-            self.logger.debug("get_network_id_by_name() : KeyError- {} ".format(exp))
-
-        return None
-
-    def list_org_action(self):
-        """
-        Method leverages vCloud director and query for available organization for particular user
-
-        Args:
-            vca - is active VCA connection.
-            vdc_name - is a vdc name that will be used to query vms action
-
-            Returns:
-                The return XML respond
-        """
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
-        url_list = [vca.host, '/api/org']
-        vm_list_rest_call = ''.join(url_list)
-
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-            response = Http.get(url=vm_list_rest_call,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
-            if response.status_code == requests.codes.ok:
-                return response.content
-
-        return None
-
-    def get_org_action(self, org_uuid=None):
-        """
-        Method leverages vCloud director and retrieve available object fdr organization.
-
-        Args:
-            vca - is active VCA connection.
-            vdc_name - is a vdc name that will be used to query vms action
-
-            Returns:
-                The return XML respond
-        """
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
-        if org_uuid is None:
-            return None
-
-        url_list = [vca.host, '/api/org/', org_uuid]
-        vm_list_rest_call = ''.join(url_list)
-
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-            response = Http.get(url=vm_list_rest_call,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
-            if response.status_code == requests.codes.ok:
-                return response.content
-
-        return None
-
-    def get_org(self, org_uuid=None):
-        """
-        Method retrieves available organization in vCloud Director
-
-        Args:
-            org_uuid - is a organization uuid.
-
-            Returns:
-                The return dictionary with following key
-                    "network" - for network list under the org
-                    "catalogs" - for network list under the org
-                    "vdcs" - for vdc list under org
-        """
-
-        org_dict = {}
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
-        if org_uuid is None:
-            return org_dict
-
-        content = self.get_org_action(org_uuid=org_uuid)
-        try:
-            vdc_list = {}
-            network_list = {}
-            catalog_list = {}
-            vm_list_xmlroot = XmlElementTree.fromstring(content)
-            for child in vm_list_xmlroot:
-                if child.attrib['type'] == 'application/vnd.vmware.vcloud.vdc+xml':
-                    vdc_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
-                    org_dict['vdcs'] = vdc_list
-                if child.attrib['type'] == 'application/vnd.vmware.vcloud.orgNetwork+xml':
-                    network_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
-                    org_dict['networks'] = network_list
-                if child.attrib['type'] == 'application/vnd.vmware.vcloud.catalog+xml':
-                    catalog_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
-                    org_dict['catalogs'] = catalog_list
-        except:
-            pass
-
-        return org_dict
-
-    def get_org_list(self):
-        """
-        Method retrieves available organization in vCloud Director
-
-        Args:
-            vca - is active VCA connection.
-
-            Returns:
-                The return dictionary and key for each entry VDC UUID
-        """
-
-        org_dict = {}
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
-        content = self.list_org_action()
-        try:
-            vm_list_xmlroot = XmlElementTree.fromstring(content)
-            for vm_xml in vm_list_xmlroot:
-                if vm_xml.tag.split("}")[1] == 'Org':
-                    org_uuid = vm_xml.attrib['href'].split('/')[-1:]
-                    org_dict[org_uuid[0]] = vm_xml.attrib['name']
-        except:
-            pass
-
-        return org_dict
-
-    def vms_view_action(self, vdc_name=None):
-        """ Method leverages vCloud director vms query call
-
-        Args:
-            vca - is active VCA connection.
-            vdc_name - is a vdc name that will be used to query vms action
-
-            Returns:
-                The return XML respond
-        """
-        vca = self.connect()
-        if vdc_name is None:
-            return None
-
-        url_list = [vca.host, '/api/vms/query']
-        vm_list_rest_call = ''.join(url_list)
-
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-            refs = filter(lambda ref: ref.name == vdc_name and ref.type_ == 'application/vnd.vmware.vcloud.vdc+xml',
-                          vca.vcloud_session.organization.Link)
-            if len(refs) == 1:
-                response = Http.get(url=vm_list_rest_call,
-                                    headers=vca.vcloud_session.get_vcloud_headers(),
-                                    verify=vca.verify,
-                                    logger=vca.logger)
-                if response.status_code == requests.codes.ok:
-                    return response.content
-
-        return None
-
-    def get_vapp_list(self, vdc_name=None):
-        """
-        Method retrieves vApp list deployed vCloud director and returns a dictionary
-        contains a list of all vapp deployed for queried VDC.
-        The key for a dictionary is vApp UUID
-
-
-        Args:
-            vca - is active VCA connection.
-            vdc_name - is a vdc name that will be used to query vms action
-
-            Returns:
-                The return dictionary and key for each entry vapp UUID
-        """
-
-        vapp_dict = {}
-        if vdc_name is None:
-            return vapp_dict
-
-        content = self.vms_view_action(vdc_name=vdc_name)
-        try:
-            vm_list_xmlroot = XmlElementTree.fromstring(content)
-            for vm_xml in vm_list_xmlroot:
-                if vm_xml.tag.split("}")[1] == 'VMRecord':
-                    if vm_xml.attrib['isVAppTemplate'] == 'true':
-                        rawuuid = vm_xml.attrib['container'].split('/')[-1:]
-                        if 'vappTemplate-' in rawuuid[0]:
-                            # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
-                            # vm and use raw UUID as key
-                            vapp_dict[rawuuid[0][13:]] = vm_xml.attrib
-        except:
-            pass
-
-        return vapp_dict
-
-    def get_vm_list(self, vdc_name=None):
-        """
-        Method retrieves VM's list deployed vCloud director. It returns a dictionary
-        contains a list of all VM's deployed for queried VDC.
-        The key for a dictionary is VM UUID
-
-
-        Args:
-            vca - is active VCA connection.
-            vdc_name - is a vdc name that will be used to query vms action
-
-            Returns:
-                The return dictionary and key for each entry vapp UUID
-        """
-        vm_dict = {}
-
-        if vdc_name is None:
-            return vm_dict
-
-        content = self.vms_view_action(vdc_name=vdc_name)
-        try:
-            vm_list_xmlroot = XmlElementTree.fromstring(content)
-            for vm_xml in vm_list_xmlroot:
-                if vm_xml.tag.split("}")[1] == 'VMRecord':
-                    if vm_xml.attrib['isVAppTemplate'] == 'false':
-                        rawuuid = vm_xml.attrib['href'].split('/')[-1:]
-                        if 'vm-' in rawuuid[0]:
-                            # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
-                            #  vm and use raw UUID as key
-                            vm_dict[rawuuid[0][3:]] = vm_xml.attrib
-        except:
-            pass
-
-        return vm_dict
-
-    def get_vapp(self, vdc_name=None, vapp_name=None, isuuid=False):
-        """
-        Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
-        contains a list of all VM's deployed for queried VDC.
-        The key for a dictionary is VM UUID
-
-
-        Args:
-            vca - is active VCA connection.
-            vdc_name - is a vdc name that will be used to query vms action
-
-            Returns:
-                The return dictionary and key for each entry vapp UUID
-        """
-        vm_dict = {}
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
-        if vdc_name is None:
-            return vm_dict
-
-        content = self.vms_view_action(vdc_name=vdc_name)
-        try:
-            vm_list_xmlroot = XmlElementTree.fromstring(content)
-            for vm_xml in vm_list_xmlroot:
-                if vm_xml.tag.split("}")[1] == 'VMRecord' and vm_xml.attrib['isVAppTemplate'] == 'false':
-                    # lookup done by UUID
-                    if isuuid:
-                        if vapp_name in vm_xml.attrib['container']:
-                            rawuuid = vm_xml.attrib['href'].split('/')[-1:]
-                            if 'vm-' in rawuuid[0]:
-                                vm_dict[rawuuid[0][3:]] = vm_xml.attrib
-                                break
-                    # lookup done by Name
-                    else:
-                        if vapp_name in vm_xml.attrib['name']:
-                            rawuuid = vm_xml.attrib['href'].split('/')[-1:]
-                            if 'vm-' in rawuuid[0]:
-                                vm_dict[rawuuid[0][3:]] = vm_xml.attrib
-                                break
-        except:
-            pass
-
-        return vm_dict
-
-    def get_network_action(self, network_uuid=None):
-        """
-        Method leverages vCloud director and query network based on network uuid
-
-        Args:
-            vca - is active VCA connection.
-            network_uuid - is a network uuid
-
-            Returns:
-                The return XML respond
-        """
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
-        if network_uuid is None:
-            return None
-
-        url_list = [vca.host, '/api/network/', network_uuid]
-        vm_list_rest_call = ''.join(url_list)
-
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-            response = Http.get(url=vm_list_rest_call,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
-            if response.status_code == requests.codes.ok:
-                return response.content
-
-        return None
-
-    def get_vcd_network(self, network_uuid=None):
-        """
-        Method retrieves available network from vCloud Director
-
-        Args:
-            network_uuid - is VCD network UUID
-
-        Each element serialized as key : value pair
-
-        Following keys available for access.    network_configuration['Gateway'}
-        <Configuration>
-          <IpScopes>
-            <IpScope>
-                <IsInherited>true</IsInherited>
-                <Gateway>172.16.252.100</Gateway>
-                <Netmask>255.255.255.0</Netmask>
-                <Dns1>172.16.254.201</Dns1>
-                <Dns2>172.16.254.202</Dns2>
-                <DnsSuffix>vmwarelab.edu</DnsSuffix>
-                <IsEnabled>true</IsEnabled>
-                <IpRanges>
-                    <IpRange>
-                        <StartAddress>172.16.252.1</StartAddress>
-                        <EndAddress>172.16.252.99</EndAddress>
-                    </IpRange>
-                </IpRanges>
-            </IpScope>
-        </IpScopes>
-        <FenceMode>bridged</FenceMode>
-
-        Returns:
-                The return dictionary and key for each entry vapp UUID
-        """
-
-        network_configuration = {}
-        if network_uuid is None:
-            return network_uuid
-
-        content = self.get_network_action(network_uuid=network_uuid)
-        try:
-            vm_list_xmlroot = XmlElementTree.fromstring(content)
-
-            network_configuration['status'] = vm_list_xmlroot.get("status")
-            network_configuration['name'] = vm_list_xmlroot.get("name")
-            network_configuration['uuid'] = vm_list_xmlroot.get("id").split(":")[3]
-
-            for child in vm_list_xmlroot:
-                if child.tag.split("}")[1] == 'IsShared':
-                    network_configuration['isShared'] = child.text.strip()
-                if child.tag.split("}")[1] == 'Configuration':
-                    for configuration in child.iter():
-                        tagKey = configuration.tag.split("}")[1].strip()
-                        if tagKey != "":
-                            network_configuration[tagKey] = configuration.text.strip()
-            return network_configuration
-        except:
-            pass
-
-        return network_configuration
-
-    def delete_network_action(self, network_uuid=None):
-        """
-        Method delete given network from vCloud director
-
-        Args:
-            network_uuid - is a network uuid that client wish to delete
-
-            Returns:
-                The return None or XML respond or false
-        """
-
-        vca = self.connect_as_admin()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-        if network_uuid is None:
-            return False
-
-        url_list = [vca.host, '/api/admin/network/', network_uuid]
-        vm_list_rest_call = ''.join(url_list)
-
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-            response = Http.delete(url=vm_list_rest_call,
-                                   headers=vca.vcloud_session.get_vcloud_headers(),
-                                   verify=vca.verify,
-                                   logger=vca.logger)
-
-            if response.status_code == 202:
-                return True
-
-        return False
-
-    def create_network(self, network_name=None, net_type='bridge', parent_network_uuid=None,
-                       ip_profile=None, isshared='true'):
-        """
-        Method create network in vCloud director
-
-        Args:
-            network_name - is network name to be created.
-            net_type - can be 'bridge','data','ptp','mgmt'.
-            ip_profile is a dict containing the IP parameters of the network
-            isshared - is a boolean
-            parent_network_uuid - is parent provider vdc network that will be used for mapping.
-            It optional attribute. by default if no parent network indicate the first available will be used.
-
-            Returns:
-                The return network uuid or return None
-        """
-
-        new_network_name = [network_name, '-', str(uuid.uuid4())]
-        content = self.create_network_rest(network_name=''.join(new_network_name),
-                                           ip_profile=ip_profile,
-                                           net_type=net_type,
-                                           parent_network_uuid=parent_network_uuid,
-                                           isshared=isshared)
-        if content is None:
-            self.logger.debug("Failed create network {}.".format(network_name))
-            return None
-
-        try:
-            vm_list_xmlroot = XmlElementTree.fromstring(content)
-            vcd_uuid = vm_list_xmlroot.get('id').split(":")
-            if len(vcd_uuid) == 4:
-                self.logger.info("Create new network name: {} uuid: {}".format(network_name, vcd_uuid[3]))
-                return vcd_uuid[3]
-        except:
-            self.logger.debug("Failed create network {}".format(network_name))
-            return None
-
-    def create_network_rest(self, network_name=None, net_type='bridge', parent_network_uuid=None,
-                            ip_profile=None, isshared='true'):
-        """
-        Method create network in vCloud director
-
-        Args:
-            network_name - is network name to be created.
-            net_type - can be 'bridge','data','ptp','mgmt'.
-            ip_profile is a dict containing the IP parameters of the network
-            isshared - is a boolean
-            parent_network_uuid - is parent provider vdc network that will be used for mapping.
-            It optional attribute. by default if no parent network indicate the first available will be used.
-
-            Returns:
-                The return network uuid or return None
-        """
-
-        vca = self.connect_as_admin()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-        if network_name is None:
-            return None
-
-        url_list = [vca.host, '/api/admin/vdc/', self.tenant_id]
-        vm_list_rest_call = ''.join(url_list)
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-            response = Http.get(url=vm_list_rest_call,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
-
-            provider_network = None
-            available_networks = None
-            add_vdc_rest_url = None
-
-            if response.status_code != requests.codes.ok:
-                self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
-                                                                                          response.status_code))
-                return None
-            else:
-                try:
-                    vm_list_xmlroot = XmlElementTree.fromstring(response.content)
-                    for child in vm_list_xmlroot:
-                        if child.tag.split("}")[1] == 'ProviderVdcReference':
-                            provider_network = child.attrib.get('href')
-                            # application/vnd.vmware.admin.providervdc+xml
-                        if child.tag.split("}")[1] == 'Link':
-                            if child.attrib.get('type') == 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' \
-                                    and child.attrib.get('rel') == 'add':
-                                add_vdc_rest_url = child.attrib.get('href')
-                except:
-                    self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
-                    self.logger.debug("Respond body {}".format(response.content))
-                    return None
-
-            # find  pvdc provided available network
-            response = Http.get(url=provider_network,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
-            if response.status_code != requests.codes.ok:
-                self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
-                                                                                          response.status_code))
-                return None
-
-            # available_networks.split("/")[-1]
-
-            if parent_network_uuid is None:
-                try:
-                    vm_list_xmlroot = XmlElementTree.fromstring(response.content)
-                    for child in vm_list_xmlroot.iter():
-                        if child.tag.split("}")[1] == 'AvailableNetworks':
-                            for networks in child.iter():
-                                # application/vnd.vmware.admin.network+xml
-                                if networks.attrib.get('href') is not None:
-                                    available_networks = networks.attrib.get('href')
-                                    break
-                except:
-                    return None
-
-            #Configure IP profile of the network
-            ip_profile = ip_profile if ip_profile is not None else DEFAULT_IP_PROFILE
-
-            gateway_address=ip_profile['gateway_address']
-            dhcp_count=int(ip_profile['dhcp_count'])
-            subnet_address=self.convert_cidr_to_netmask(ip_profile['subnet_address'])
-
-            if ip_profile['dhcp_enabled']==True:
-                dhcp_enabled='true'
-            else:
-                dhcp_enabled='false'
-            dhcp_start_address=ip_profile['dhcp_start_address']
-
-            #derive dhcp_end_address from dhcp_start_address & dhcp_count
-            end_ip_int = int(netaddr.IPAddress(dhcp_start_address))
-            end_ip_int += dhcp_count - 1
-            dhcp_end_address = str(netaddr.IPAddress(end_ip_int))
-
-            ip_version=ip_profile['ip_version']
-            dns_address=ip_profile['dns_address']
-
-            # either use client provided UUID or search for a first available
-            #  if both are not defined we return none
-            if parent_network_uuid is not None:
-                url_list = [vca.host, '/api/admin/network/', parent_network_uuid]
-                add_vdc_rest_url = ''.join(url_list)
-
-            if net_type=='ptp':
-                fence_mode="isolated"
-                isshared='false'
-                is_inherited='false'
-                data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
-                                <Description>Openmano created</Description>
-                                        <Configuration>
-                                            <IpScopes>
-                                                <IpScope>
-                                                    <IsInherited>{1:s}</IsInherited>
-                                                    <Gateway>{2:s}</Gateway>
-                                                    <Netmask>{3:s}</Netmask>
-                                                    <Dns1>{4:s}</Dns1>
-                                                    <IsEnabled>{5:s}</IsEnabled>
-                                                    <IpRanges>
-                                                        <IpRange>
-                                                            <StartAddress>{6:s}</StartAddress>
-                                                            <EndAddress>{7:s}</EndAddress>
-                                                        </IpRange>
-                                                    </IpRanges>
-                                                </IpScope>
-                                            </IpScopes>
-                                            <FenceMode>{8:s}</FenceMode>
-                                        </Configuration>
-                                        <IsShared>{9:s}</IsShared>
-                            </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
-                                                        subnet_address, dns_address, dhcp_enabled,
-                                                        dhcp_start_address, dhcp_end_address, fence_mode, isshared)
-
-            else:
-                fence_mode="bridged"
-                is_inherited='false'
-                data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
-                                <Description>Openmano created</Description>
-                                        <Configuration>
-                                            <IpScopes>
-                                                <IpScope>
-                                                    <IsInherited>{1:s}</IsInherited>
-                                                    <Gateway>{2:s}</Gateway>
-                                                    <Netmask>{3:s}</Netmask>
-                                                    <Dns1>{4:s}</Dns1>
-                                                    <IsEnabled>{5:s}</IsEnabled>
-                                                    <IpRanges>
-                                                        <IpRange>
-                                                            <StartAddress>{6:s}</StartAddress>
-                                                            <EndAddress>{7:s}</EndAddress>
-                                                        </IpRange>
-                                                    </IpRanges>
-                                                </IpScope>
-                                            </IpScopes>
-                                            <ParentNetwork href="{8:s}"/>
-                                            <FenceMode>{9:s}</FenceMode>
-                                        </Configuration>
-                                        <IsShared>{10:s}</IsShared>
-                            </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
-                                                        subnet_address, dns_address, dhcp_enabled,
-                                                        dhcp_start_address, dhcp_end_address, available_networks,
-                                                        fence_mode, isshared)
-
-            headers = vca.vcloud_session.get_vcloud_headers()
-            headers['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
-            try:
-                response = Http.post(url=add_vdc_rest_url,
-                                     headers=headers,
-                                     data=data,
-                                     verify=vca.verify,
-                                     logger=vca.logger)
-
-                if response.status_code != 201:
-                    self.logger.debug("Create Network POST REST API call failed. Return status code {}"
-                                      .format(response.status_code))
-                else:
-                    network = networkType.parseString(response.content, True)
-                    create_nw_task = network.get_Tasks().get_Task()[0]
-
-                    # if we all ok we respond with content after network creation completes
-                    # otherwise by default return None
-                    if create_nw_task is not None:
-                        self.logger.debug("Create Network REST : Waiting for Nw creation complete")
-                        status = vca.block_until_completed(create_nw_task)
-                        if status:
-                            return response.content
-                        else:
-                            self.logger.debug("create_network_rest task failed. Network Create response : {}"
-                                              .format(response.content))
-            except Exception as exp:
-                self.logger.debug("create_network_rest : Exception : {} ".format(exp))
-
-        return None
-
-    def convert_cidr_to_netmask(self, cidr_ip=None):
-        """
-        Method sets convert CIDR netmask address to normal IP format
-        Args:
-            cidr_ip : CIDR IP address
-            Returns:
-                netmask : Converted netmask
-        """
-        if cidr_ip is not None:
-            if '/' in cidr_ip:
-                network, net_bits = cidr_ip.split('/')
-                netmask = socket.inet_ntoa(struct.pack(">I", (0xffffffff << (32 - int(net_bits))) & 0xffffffff))
-            else:
-                netmask = cidr_ip
-            return netmask
-        return None
-
-    def get_provider_rest(self, vca=None):
-        """
-        Method gets provider vdc view from vcloud director
-
-        Args:
-            network_name - is network name to be created.
-            parent_network_uuid - is parent provider vdc network that will be used for mapping.
-            It optional attribute. by default if no parent network indicate the first available will be used.
-
-            Returns:
-                The return xml content of respond or None
-        """
-
-        url_list = [vca.host, '/api/admin']
-        response = Http.get(url=''.join(url_list),
-                            headers=vca.vcloud_session.get_vcloud_headers(),
-                            verify=vca.verify,
-                            logger=vca.logger)
-
-        if response.status_code == requests.codes.ok:
-            return response.content
-        return None
-
-    def create_vdc(self, vdc_name=None):
-
-        vdc_dict = {}
-
-        xml_content = self.create_vdc_from_tmpl_rest(vdc_name=vdc_name)
-        if xml_content is not None:
-            try:
-                task_resp_xmlroot = XmlElementTree.fromstring(xml_content)
-                for child in task_resp_xmlroot:
-                    if child.tag.split("}")[1] == 'Owner':
-                        vdc_id = child.attrib.get('href').split("/")[-1]
-                        vdc_dict[vdc_id] = task_resp_xmlroot.get('href')
-                        return vdc_dict
-            except:
-                self.logger.debug("Respond body {}".format(xml_content))
-
-        return None
-
-    def create_vdc_from_tmpl_rest(self, vdc_name=None):
-        """
-        Method create vdc in vCloud director based on VDC template.
-        it uses pre-defined template that must be named openmano
-
-        Args:
-            vdc_name -  name of a new vdc.
-
-            Returns:
-                The return xml content of respond or None
-        """
-
-        self.logger.info("Creating new vdc {}".format(vdc_name))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-        if vdc_name is None:
-            return None
-
-        url_list = [vca.host, '/api/vdcTemplates']
-        vm_list_rest_call = ''.join(url_list)
-        response = Http.get(url=vm_list_rest_call,
-                            headers=vca.vcloud_session.get_vcloud_headers(),
-                            verify=vca.verify,
-                            logger=vca.logger)
-
-        # container url to a template
-        vdc_template_ref = None
-        try:
-            vm_list_xmlroot = XmlElementTree.fromstring(response.content)
-            for child in vm_list_xmlroot:
-                # application/vnd.vmware.admin.providervdc+xml
-                # we need find a template from witch we instantiate VDC
-                if child.tag.split("}")[1] == 'VdcTemplate':
-                    if child.attrib.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml' and child.attrib.get(
-                            'name') == 'openmano':
-                        vdc_template_ref = child.attrib.get('href')
-        except:
-            self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
-            self.logger.debug("Respond body {}".format(response.content))
-            return None
-
-        # if we didn't found required pre defined template we return None
-        if vdc_template_ref is None:
-            return None
-
-        try:
-            # instantiate vdc
-            url_list = [vca.host, '/api/org/', self.org_uuid, '/action/instantiate']
-            vm_list_rest_call = ''.join(url_list)
-            data = """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
-                                        <Source href="{1:s}"></Source>
-                                        <Description>opnemano</Description>
-                                        </InstantiateVdcTemplateParams>""".format(vdc_name, vdc_template_ref)
-            headers = vca.vcloud_session.get_vcloud_headers()
-            headers['Content-Type'] = 'application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml'
-            response = Http.post(url=vm_list_rest_call, headers=headers, data=data, verify=vca.verify,
-                                 logger=vca.logger)
-            # if we all ok we respond with content otherwise by default None
-            if response.status_code >= 200 and response.status_code < 300:
-                return response.content
-            return None
-        except:
-            self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
-            self.logger.debug("Respond body {}".format(response.content))
-
-        return None
-
-    def create_vdc_rest(self, vdc_name=None):
-        """
-        Method create network in vCloud director
-
-        Args:
-            network_name - is network name to be created.
-            parent_network_uuid - is parent provider vdc network that will be used for mapping.
-            It optional attribute. by default if no parent network indicate the first available will be used.
-
-            Returns:
-                The return network uuid or return None
-        """
-
-        self.logger.info("Creating new vdc {}".format(vdc_name))
-
-        vca = self.connect_as_admin()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-        if vdc_name is None:
-            return None
-
-        url_list = [vca.host, '/api/admin/org/', self.org_uuid]
-        vm_list_rest_call = ''.join(url_list)
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-            response = Http.get(url=vm_list_rest_call,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
-
-            provider_vdc_ref = None
-            add_vdc_rest_url = None
-            available_networks = None
-
-            if response.status_code != requests.codes.ok:
-                self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
-                                                                                          response.status_code))
-                return None
-            else:
-                try:
-                    vm_list_xmlroot = XmlElementTree.fromstring(response.content)
-                    for child in vm_list_xmlroot:
-                        # application/vnd.vmware.admin.providervdc+xml
-                        if child.tag.split("}")[1] == 'Link':
-                            if child.attrib.get('type') == 'application/vnd.vmware.admin.createVdcParams+xml' \
-                                    and child.attrib.get('rel') == 'add':
-                                add_vdc_rest_url = child.attrib.get('href')
-                except:
-                    self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
-                    self.logger.debug("Respond body {}".format(response.content))
-                    return None
-
-                response = self.get_provider_rest(vca=vca)
-                try:
-                    vm_list_xmlroot = XmlElementTree.fromstring(response)
-                    for child in vm_list_xmlroot:
-                        if child.tag.split("}")[1] == 'ProviderVdcReferences':
-                            for sub_child in child:
-                                provider_vdc_ref = sub_child.attrib.get('href')
-                except:
-                    self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
-                    self.logger.debug("Respond body {}".format(response))
-                    return None
-
-                if add_vdc_rest_url is not None and provider_vdc_ref is not None:
-                    data = """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
-                            <AllocationModel>ReservationPool</AllocationModel>
-                            <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
-                            <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
-                            </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
-                            <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
-                            <ProviderVdcReference
-                            name="Main Provider"
-                            href="{2:s}" />
-                    <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(escape(vdc_name),
-                                                                                                  escape(vdc_name),
-                                                                                                  provider_vdc_ref)
-
-                    headers = vca.vcloud_session.get_vcloud_headers()
-                    headers['Content-Type'] = 'application/vnd.vmware.admin.createVdcParams+xml'
-                    response = Http.post(url=add_vdc_rest_url, headers=headers, data=data, verify=vca.verify,
-                                         logger=vca.logger)
-
-                    # if we all ok we respond with content otherwise by default None
-                    if response.status_code == 201:
-                        return response.content
-        return None
-
-    def get_vapp_details_rest(self, vapp_uuid=None, need_admin_access=False):
-        """
-        Method retrieve vapp detail from vCloud director
-
-        Args:
-            vapp_uuid - is vapp identifier.
-
-            Returns:
-                The return network uuid or return None
-        """
-
-        parsed_respond = {}
-        vca = None
-
-        if need_admin_access:
-            vca = self.connect_as_admin()
-        else:
-            vca = self.connect()
-
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-        if vapp_uuid is None:
-            return None
-
-        url_list = [vca.host, '/api/vApp/vapp-', vapp_uuid]
-        get_vapp_restcall = ''.join(url_list)
-
-        if vca.vcloud_session and vca.vcloud_session.organization:
-            response = Http.get(url=get_vapp_restcall,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
-
-            if response.status_code != requests.codes.ok:
-                self.logger.debug("REST API call {} failed. Return status code {}".format(get_vapp_restcall,
-                                                                                          response.status_code))
-                return parsed_respond
-
-            try:
-                xmlroot_respond = XmlElementTree.fromstring(response.content)
-                parsed_respond['ovfDescriptorUploaded'] = xmlroot_respond.attrib['ovfDescriptorUploaded']
-
-                namespaces = {"vssd":"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" ,
-                              'ovf': 'http://schemas.dmtf.org/ovf/envelope/1',
-                              'vmw': 'http://www.vmware.com/schema/ovf',
-                              'vm': 'http://www.vmware.com/vcloud/v1.5',
-                              'rasd':"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
-                              "vmext":"http://www.vmware.com/vcloud/extension/v1.5",
-                              "xmlns":"http://www.vmware.com/vcloud/v1.5"
-                             }
-
-                created_section = xmlroot_respond.find('vm:DateCreated', namespaces)
-                if created_section is not None:
-                    parsed_respond['created'] = created_section.text
-
-                network_section = xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig', namespaces)
-                if network_section is not None and 'networkName' in network_section.attrib:
-                    parsed_respond['networkname'] = network_section.attrib['networkName']
-
-                ipscopes_section = \
-                    xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig/vm:Configuration/vm:IpScopes',
-                                         namespaces)
-                if ipscopes_section is not None:
-                    for ipscope in ipscopes_section:
-                        for scope in ipscope:
-                            tag_key = scope.tag.split("}")[1]
-                            if tag_key == 'IpRanges':
-                                ip_ranges = scope.getchildren()
-                                for ipblock in ip_ranges:
-                                    for block in ipblock:
-                                        parsed_respond[block.tag.split("}")[1]] = block.text
-                            else:
-                                parsed_respond[tag_key] = scope.text
-
-                # parse children section for other attrib
-                children_section = xmlroot_respond.find('vm:Children/', namespaces)
-                if children_section is not None:
-                    parsed_respond['name'] = children_section.attrib['name']
-                    parsed_respond['nestedHypervisorEnabled'] = children_section.attrib['nestedHypervisorEnabled'] \
-                     if  "nestedHypervisorEnabled" in children_section.attrib else None
-                    parsed_respond['deployed'] = children_section.attrib['deployed']
-                    parsed_respond['status'] = children_section.attrib['status']
-                    parsed_respond['vmuuid'] = children_section.attrib['id'].split(":")[-1]
-                    network_adapter = children_section.find('vm:NetworkConnectionSection', namespaces)
-                    nic_list = []
-                    for adapters in network_adapter:
-                        adapter_key = adapters.tag.split("}")[1]
-                        if adapter_key == 'PrimaryNetworkConnectionIndex':
-                            parsed_respond['primarynetwork'] = adapters.text
-                        if adapter_key == 'NetworkConnection':
-                            vnic = {}
-                            if 'network' in adapters.attrib:
-                                vnic['network'] = adapters.attrib['network']
-                            for adapter in adapters:
-                                setting_key = adapter.tag.split("}")[1]
-                                vnic[setting_key] = adapter.text
-                            nic_list.append(vnic)
-
-                    for link in children_section:
-                        if link.tag.split("}")[1] == 'Link' and 'rel' in link.attrib:
-                            if link.attrib['rel'] == 'screen:acquireTicket':
-                                parsed_respond['acquireTicket'] = link.attrib
-                            if link.attrib['rel'] == 'screen:acquireMksTicket':
-                                parsed_respond['acquireMksTicket'] = link.attrib
-
-                    parsed_respond['interfaces'] = nic_list
-                    vCloud_extension_section = children_section.find('xmlns:VCloudExtension', namespaces)
-                    if vCloud_extension_section is not None:
-                        vm_vcenter_info = {}
-                        vim_info = vCloud_extension_section.find('vmext:VmVimInfo', namespaces)
-                        vmext = vim_info.find('vmext:VmVimObjectRef', namespaces)
-                        if vmext is not None:
-                            vm_vcenter_info["vm_moref_id"] = vmext.find('vmext:MoRef', namespaces).text
-                        parsed_respond["vm_vcenter_info"]= vm_vcenter_info
-
-                    virtual_hardware_section = children_section.find('ovf:VirtualHardwareSection', namespaces)
-                    vm_virtual_hardware_info = {}
-                    if virtual_hardware_section is not None:
-                        for item in virtual_hardware_section.iterfind('ovf:Item',namespaces):
-                            if item.find("rasd:Description",namespaces).text == "Hard disk":
-                                disk_size = item.find("rasd:HostResource" ,namespaces
-                                                ).attrib["{"+namespaces['vm']+"}capacity"]
-
-                                vm_virtual_hardware_info["disk_size"]= disk_size
-                                break
-
-                        for link in virtual_hardware_section:
-                            if link.tag.split("}")[1] == 'Link' and 'rel' in link.attrib:
-                                if link.attrib['rel'] == 'edit' and link.attrib['href'].endswith("/disks"):
-                                    vm_virtual_hardware_info["disk_edit_href"] = link.attrib['href']
-                                    break
-
-                    parsed_respond["vm_virtual_hardware"]= vm_virtual_hardware_info
-            except Exception as exp :
-                self.logger.info("Error occurred calling rest api for getting vApp details {}".format(exp))
-        return parsed_respond
-
-    def acuire_console(self, vm_uuid=None):
-
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-        if vm_uuid is None:
-            return None
-
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-            vm_dict = self.get_vapp_details_rest(self, vapp_uuid=vm_uuid)
-            console_dict = vm_dict['acquireTicket']
-            console_rest_call = console_dict['href']
-
-            response = Http.post(url=console_rest_call,
-                                 headers=vca.vcloud_session.get_vcloud_headers(),
-                                 verify=vca.verify,
-                                 logger=vca.logger)
-
-            if response.status_code == requests.codes.ok:
-                return response.content
-
-        return None
-
-    def modify_vm_disk(self, vapp_uuid, flavor_disk):
-        """
-        Method retrieve vm disk details
-
-        Args:
-            vapp_uuid - is vapp identifier.
-            flavor_disk - disk size as specified in VNFD (flavor)
-
-            Returns:
-                The return network uuid or return None
-        """
-        status = None
-        try:
-            #Flavor disk is in GB convert it into MB
-            flavor_disk = int(flavor_disk) * 1024
-            vm_details = self.get_vapp_details_rest(vapp_uuid)
-            if vm_details:
-                vm_name = vm_details["name"]
-                self.logger.info("VM: {} flavor_disk :{}".format(vm_name , flavor_disk))
-
-            if vm_details and "vm_virtual_hardware" in vm_details:
-                vm_disk = int(vm_details["vm_virtual_hardware"]["disk_size"])
-                disk_edit_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
-
-                self.logger.info("VM: {} VM_disk :{}".format(vm_name , vm_disk))
-
-                if flavor_disk > vm_disk:
-                    status = self.modify_vm_disk_rest(disk_edit_href ,flavor_disk)
-                    self.logger.info("Modify disk of VM {} from {} to {} MB".format(vm_name,
-                                                         vm_disk,  flavor_disk ))
-                else:
-                    status = True
-                    self.logger.info("No need to modify disk of VM {}".format(vm_name))
-
-            return status
-        except Exception as exp:
-            self.logger.info("Error occurred while modifing disk size {}".format(exp))
-
-
-    def modify_vm_disk_rest(self, disk_href , disk_size):
-        """
-        Method retrieve modify vm disk size
-
-        Args:
-            disk_href - vCD API URL to GET and PUT disk data
-            disk_size - disk size as specified in VNFD (flavor)
-
-            Returns:
-                The return network uuid or return None
-        """
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-        if disk_href is None or disk_size is None:
-            return None
-
-        if vca.vcloud_session and vca.vcloud_session.organization:
-            response = Http.get(url=disk_href,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
-
-        if response.status_code != requests.codes.ok:
-            self.logger.debug("GET REST API call {} failed. Return status code {}".format(disk_href,
-                                                                            response.status_code))
-            return None
-        try:
-            lxmlroot_respond = lxmlElementTree.fromstring(response.content)
-            namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
-            namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
-
-            for item in lxmlroot_respond.iterfind('xmlns:Item',namespaces):
-                if item.find("rasd:Description",namespaces).text == "Hard disk":
-                    disk_item = item.find("rasd:HostResource" ,namespaces )
-                    if disk_item is not None:
-                        disk_item.attrib["{"+namespaces['xmlns']+"}capacity"] = str(disk_size)
-                        break
-
-            data = lxmlElementTree.tostring(lxmlroot_respond, encoding='utf8', method='xml',
-                                             xml_declaration=True)
-
-            #Send PUT request to modify disk size
-            headers = vca.vcloud_session.get_vcloud_headers()
-            headers['Content-Type'] = 'application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1'
-
-            response = Http.put(url=disk_href,
-                                data=data,
-                                headers=headers,
-                                verify=vca.verify, logger=self.logger)
-
-            if response.status_code != 202:
-                self.logger.debug("PUT REST API call {} failed. Return status code {}".format(disk_href,
-                                                                            response.status_code))
-            else:
-                modify_disk_task = taskType.parseString(response.content, True)
-                if type(modify_disk_task) is GenericTask:
-                    status = vca.block_until_completed(modify_disk_task)
-                    return status
-
-            return None
-
-        except Exception as exp :
-                self.logger.info("Error occurred calling rest api for modifing disk size {}".format(exp))
-                return None
-
-    def add_pci_devices(self, vapp_uuid , pci_devices , vmname_andid):
-        """
-            Method to attach pci devices to VM
-
-             Args:
-                vapp_uuid - uuid of vApp/VM
-                pci_devices - pci devices infromation as specified in VNFD (flavor)
-
-            Returns:
-                The status of add pci device task , vm object and
-                vcenter_conect object
-        """
-        vm_obj = None
-        vcenter_conect = None
-        self.logger.info("Add pci devices {} into vApp {}".format(pci_devices , vapp_uuid))
-        try:
-            vm_vcenter_info = self.get_vm_vcenter_info(vapp_uuid)
-        except Exception as exp:
-            self.logger.error("Error occurred while getting vCenter infromationn"\
-                             " for VM : {}".format(exp))
-            raise vimconn.vimconnException(message=exp)
-
-        if vm_vcenter_info["vm_moref_id"]:
-            context = None
-            if hasattr(ssl, '_create_unverified_context'):
-                context = ssl._create_unverified_context()
-            try:
-                no_of_pci_devices = len(pci_devices)
-                if no_of_pci_devices > 0:
-                    vcenter_conect = SmartConnect(
-                                            host=vm_vcenter_info["vm_vcenter_ip"],
-                                            user=vm_vcenter_info["vm_vcenter_user"],
-                                            pwd=vm_vcenter_info["vm_vcenter_password"],
-                                            port=int(vm_vcenter_info["vm_vcenter_port"]),
-                                            sslContext=context)
-                    atexit.register(Disconnect, vcenter_conect)
-                    content = vcenter_conect.RetrieveContent()
-
-                    #Get VM and its host
-                    host_obj, vm_obj = self.get_vm_obj(content ,vm_vcenter_info["vm_moref_id"])
-                    self.logger.info("VM {} is currently on host {}".format(vm_obj, host_obj))
-                    if host_obj and vm_obj:
-                        #get PCI devies from host on which vapp is currently installed
-                        avilable_pci_devices = self.get_pci_devices(host_obj, no_of_pci_devices)
-
-                        if avilable_pci_devices is None:
-                            #find other hosts with active pci devices
-                            new_host_obj , avilable_pci_devices = self.get_host_and_PCIdevices(
-                                                                content,
-                                                                no_of_pci_devices
-                                                                )
-
-                            if new_host_obj is not None and avilable_pci_devices is not None and len(avilable_pci_devices)> 0:
-                                #Migrate vm to the host where PCI devices are availble
-                                self.logger.info("Relocate VM {} on new host {}".format(vm_obj, new_host_obj))
-                                task = self.relocate_vm(new_host_obj, vm_obj)
-                                if task is not None:
-                                    result = self.wait_for_vcenter_task(task, vcenter_conect)
-                                    self.logger.info("Migrate VM status: {}".format(result))
-                                    host_obj = new_host_obj
-                                else:
-                                    self.logger.info("Fail to migrate VM : {}".format(result))
-                                    raise vimconn.vimconnNotFoundException(
-                                    "Fail to migrate VM : {} to host {}".format(
-                                                    vmname_andid,
-                                                    new_host_obj)
-                                        )
-
-                        if host_obj is not None and avilable_pci_devices is not None and len(avilable_pci_devices)> 0:
-                            #Add PCI devices one by one
-                            for pci_device in avilable_pci_devices:
-                                task = self.add_pci_to_vm(host_obj, vm_obj, pci_device)
-                                if task:
-                                    status= self.wait_for_vcenter_task(task, vcenter_conect)
-                                    if status:
-                                        self.logger.info("Added PCI device {} to VM {}".format(pci_device,str(vm_obj)))
-                                else:
-                                    self.logger.error("Fail to add PCI device {} to VM {}".format(pci_device,str(vm_obj)))
-                            return True, vm_obj, vcenter_conect
-                        else:
-                            self.logger.error("Currently there is no host with"\
-                                              " {} number of avaialble PCI devices required for VM {}".format(
-                                                                            no_of_pci_devices,
-                                                                            vmname_andid)
-                                              )
-                            raise vimconn.vimconnNotFoundException(
-                                    "Currently there is no host with {} "\
-                                    "number of avaialble PCI devices required for VM {}".format(
-                                                                            no_of_pci_devices,
-                                                                            vmname_andid))
-                else:
-                    self.logger.debug("No infromation about PCI devices {} ",pci_devices)
-
-            except vmodl.MethodFault as error:
-                self.logger.error("Error occurred while adding PCI devices {} ",error)
-        return None, vm_obj, vcenter_conect
-
-    def get_vm_obj(self, content, mob_id):
-        """
-            Method to get the vsphere VM object associated with a given morf ID
-             Args:
-                vapp_uuid - uuid of vApp/VM
-                content - vCenter content object
-                mob_id - mob_id of VM
-
-            Returns:
-                    VM and host object
-        """
-        vm_obj = None
-        host_obj = None
-        try :
-            container = content.viewManager.CreateContainerView(content.rootFolder,
-                                                        [vim.VirtualMachine], True
-                                                        )
-            for vm in container.view:
-                mobID = vm._GetMoId()
-                if mobID == mob_id:
-                    vm_obj = vm
-                    host_obj = vm_obj.runtime.host
-                    break
-        except Exception as exp:
-            self.logger.error("Error occurred while finding VM object : {}".format(exp))
-        return host_obj, vm_obj
-
-    def get_pci_devices(self, host, need_devices):
-        """
-            Method to get the details of pci devices on given host
-             Args:
-                host - vSphere host object
-                need_devices - number of pci devices needed on host
-
-             Returns:
-                array of pci devices
-        """
-        all_devices = []
-        all_device_ids = []
-        used_devices_ids = []
-
-        try:
-            if host:
-                pciPassthruInfo = host.config.pciPassthruInfo
-                pciDevies = host.hardware.pciDevice
-
-            for pci_status in pciPassthruInfo:
-                if pci_status.passthruActive:
-                    for device in pciDevies:
-                        if device.id == pci_status.id:
-                            all_device_ids.append(device.id)
-                            all_devices.append(device)
-
-            #check if devices are in use
-            avalible_devices = all_devices
-            for vm in host.vm:
-                if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
-                    vm_devices = vm.config.hardware.device
-                    for device in vm_devices:
-                        if type(device) is vim.vm.device.VirtualPCIPassthrough:
-                            if device.backing.id in all_device_ids:
-                                for use_device in avalible_devices:
-                                    if use_device.id == device.backing.id:
-                                        avalible_devices.remove(use_device)
-                                used_devices_ids.append(device.backing.id)
-                                self.logger.debug("Device {} from devices {}"\
-                                        "is in use".format(device.backing.id,
-                                                           device)
-                                            )
-            if len(avalible_devices) < need_devices:
-                self.logger.debug("Host {} don't have {} number of active devices".format(host,
-                                                                            need_devices))
-                self.logger.debug("found only {} devives {}".format(len(avalible_devices),
-                                                                    avalible_devices))
-                return None
-            else:
-                required_devices = avalible_devices[:need_devices]
-                self.logger.info("Found {} PCI devivces on host {} but required only {}".format(
-                                                            len(avalible_devices),
-                                                            host,
-                                                            need_devices))
-                self.logger.info("Retruning {} devices as {}".format(need_devices,
-                                                                required_devices ))
-                return required_devices
-
-        except Exception as exp:
-            self.logger.error("Error {} occurred while finding pci devices on host: {}".format(exp, host))
-
-        return None
-
-    def get_host_and_PCIdevices(self, content, need_devices):
-        """
-         Method to get the details of pci devices infromation on all hosts
-
-            Args:
-                content - vSphere host object
-                need_devices - number of pci devices needed on host
-
-            Returns:
-                 array of pci devices and host object
-        """
-        host_obj = None
-        pci_device_objs = None
-        try:
-            if content:
-                container = content.viewManager.CreateContainerView(content.rootFolder,
-                                                            [vim.HostSystem], True)
-                for host in container.view:
-                    devices = self.get_pci_devices(host, need_devices)
-                    if devices:
-                        host_obj = host
-                        pci_device_objs = devices
-                        break
-        except Exception as exp:
-            self.logger.error("Error {} occurred while finding pci devices on host: {}".format(exp, host_obj))
-
-        return host_obj,pci_device_objs
-
-    def relocate_vm(self, dest_host, vm) :
-        """
-         Method to get the relocate VM to new host
-
-            Args:
-                dest_host - vSphere host object
-                vm - vSphere VM object
-
-            Returns:
-                task object
-        """
-        task = None
-        try:
-            relocate_spec = vim.vm.RelocateSpec(host=dest_host)
-            task = vm.Relocate(relocate_spec)
-            self.logger.info("Migrating {} to destination host {}".format(vm, dest_host))
-        except Exception as exp:
-            self.logger.error("Error occurred while relocate VM {} to new host {}: {}".format(
-                                                                            dest_host, vm, exp))
-        return task
-
-    def wait_for_vcenter_task(self, task, actionName='job', hideResult=False):
-        """
-        Waits and provides updates on a vSphere task
-        """
-        while task.info.state == vim.TaskInfo.State.running:
-            time.sleep(2)
-
-        if task.info.state == vim.TaskInfo.State.success:
-            if task.info.result is not None and not hideResult:
-                self.logger.info('{} completed successfully, result: {}'.format(
-                                                            actionName,
-                                                            task.info.result))
-            else:
-                self.logger.info('Task {} completed successfully.'.format(actionName))
-        else:
-            self.logger.error('{} did not complete successfully: {} '.format(
-                                                            actionName,
-                                                            task.info.error)
-                              )
-
-        return task.info.result
-
-    def add_pci_to_vm(self,host_object, vm_object, host_pci_dev):
-        """
-         Method to add pci device in given VM
-
-            Args:
-                host_object - vSphere host object
-                vm_object - vSphere VM object
-                host_pci_dev -  host_pci_dev must be one of the devices from the
-                                host_object.hardware.pciDevice list
-                                which is configured as a PCI passthrough device
-
-            Returns:
-                task object
-        """
-        task = None
-        if vm_object and host_object and host_pci_dev:
-            try :
-                #Add PCI device to VM
-                pci_passthroughs = vm_object.environmentBrowser.QueryConfigTarget(host=None).pciPassthrough
-                systemid_by_pciid = {item.pciDevice.id: item.systemId for item in pci_passthroughs}
-
-                if host_pci_dev.id not in systemid_by_pciid:
-                    self.logger.error("Device {} is not a passthrough device ".format(host_pci_dev))
-                    return None
-
-                deviceId = hex(host_pci_dev.deviceId % 2**16).lstrip('0x')
-                backing = vim.VirtualPCIPassthroughDeviceBackingInfo(deviceId=deviceId,
-                                            id=host_pci_dev.id,
-                                            systemId=systemid_by_pciid[host_pci_dev.id],
-                                            vendorId=host_pci_dev.vendorId,
-                                            deviceName=host_pci_dev.deviceName)
-
-                hba_object = vim.VirtualPCIPassthrough(key=-100, backing=backing)
-
-                new_device_config = vim.VirtualDeviceConfigSpec(device=hba_object)
-                new_device_config.operation = "add"
-                vmConfigSpec = vim.vm.ConfigSpec()
-                vmConfigSpec.deviceChange = [new_device_config]
-
-                task = vm_object.ReconfigVM_Task(spec=vmConfigSpec)
-                self.logger.info("Adding PCI device {} into VM {} from host {} ".format(
-                                                            host_pci_dev, vm_object, host_object)
-                                )
-            except Exception as exp:
-                self.logger.error("Error occurred while adding pci devive {} to VM {}: {}".format(
-                                                                            host_pci_dev,
-                                                                            vm_object,
-                                                                             exp))
-        return task
-
-    def get_vm_vcenter_info(self , vapp_uuid):
-        """
-        Method to get details of vCenter and vm
-
-            Args:
-                vapp_uuid - uuid of vApp or VM
-
-            Returns:
-                Moref Id of VM and deails of vCenter
-        """
-        vm_vcenter_info = {}
-
-        if self.vcenter_ip is not None:
-            vm_vcenter_info["vm_vcenter_ip"] = self.vcenter_ip
-        else:
-            raise vimconn.vimconnException(message="vCenter IP is not provided."\
-                                           " Please provide vCenter IP while attaching datacenter to tenant in --config")
-        if self.vcenter_port is not None:
-            vm_vcenter_info["vm_vcenter_port"] = self.vcenter_port
-        else:
-            raise vimconn.vimconnException(message="vCenter port is not provided."\
-                                           " Please provide vCenter port while attaching datacenter to tenant in --config")
-        if self.vcenter_user is not None:
-            vm_vcenter_info["vm_vcenter_user"] = self.vcenter_user
-        else:
-            raise vimconn.vimconnException(message="vCenter user is not provided."\
-                                           " Please provide vCenter user while attaching datacenter to tenant in --config")
-
-        if self.vcenter_password is not None:
-            vm_vcenter_info["vm_vcenter_password"] = self.vcenter_password
-        else:
-            raise vimconn.vimconnException(message="vCenter user password is not provided."\
-                                           " Please provide vCenter user password while attaching datacenter to tenant in --config")
-        try:
-            vm_details = self.get_vapp_details_rest(vapp_uuid, need_admin_access=True)
-            if vm_details and "vm_vcenter_info" in vm_details:
-                vm_vcenter_info["vm_moref_id"] = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
-
-            return vm_vcenter_info
-
-        except Exception as exp:
-            self.logger.error("Error occurred while getting vCenter infromationn"\
-                             " for VM : {}".format(exp))
-
-
-    def get_vm_pci_details(self, vmuuid):
-        """
-            Method to get VM PCI device details from vCenter
-
-            Args:
-                vm_obj - vSphere VM object
-
-            Returns:
-                dict of PCI devives attached to VM
-
-        """
-        vm_pci_devices_info = {}
-        try:
-            vm_vcenter_info = self.get_vm_vcenter_info(vmuuid)
-            if vm_vcenter_info["vm_moref_id"]:
-                context = None
-                if hasattr(ssl, '_create_unverified_context'):
-                    context = ssl._create_unverified_context()
-                vcenter_conect = SmartConnect(host=vm_vcenter_info["vm_vcenter_ip"],
-                                        user=vm_vcenter_info["vm_vcenter_user"],
-                                        pwd=vm_vcenter_info["vm_vcenter_password"],
-                                        port=int(vm_vcenter_info["vm_vcenter_port"]),
-                                        sslContext=context
-                                    )
-                atexit.register(Disconnect, vcenter_conect)
-                content = vcenter_conect.RetrieveContent()
-
-                #Get VM and its host
-                if content:
-                    host_obj, vm_obj = self.get_vm_obj(content ,vm_vcenter_info["vm_moref_id"])
-                    if host_obj and vm_obj:
-                        vm_pci_devices_info["host_name"]= host_obj.name
-                        vm_pci_devices_info["host_ip"]= host_obj.config.network.vnic[0].spec.ip.ipAddress
-                        for device in vm_obj.config.hardware.device:
-                            if type(device) == vim.vm.device.VirtualPCIPassthrough:
-                                device_details={'devide_id':device.backing.id,
-                                                'pciSlotNumber':device.slotInfo.pciSlotNumber,
-                                            }
-                                vm_pci_devices_info[device.deviceInfo.label] = device_details
-                else:
-                    self.logger.error("Can not connect to vCenter while getting "\
-                                          "PCI devices infromationn")
-                return vm_pci_devices_info
-        except Exception as exp:
-            self.logger.error("Error occurred while getting VM infromationn"\
-                             " for VM : {}".format(exp))
-            raise vimconn.vimconnException(message=exp)
-
diff --git a/vmwarecli.py b/vmwarecli.py
deleted file mode 100755 (executable)
index 4583a65..0000000
+++ /dev/null
@@ -1,819 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-##
-# This file is standalone vmware vcloud director util
-# 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: mbayramov@vmware.com
-##
-
-"""
-
-Standalone application that leverage openmano vmware connector work with vCloud director rest api.
-
- - Provides capability to create and delete VDC for specific organization.
- - Create, delete and manage network for specific VDC
- - List deployed VM's , VAPPs, VDSs, Organization
- - View detail information about VM / Vapp , Organization etc
- - Operate with images upload / boot / power on etc
-
- Usage example.
-
- List organization created in vCloud director
-  vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list org
-
- List VDC for particular organization
-  vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list vdc
-
- Upload image
-  python vmwarerecli.py image upload /Users/spyroot/Developer/Openmano/Ro/vnfs/cirros/cirros.ovf
-
- Boot Image
-    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF image boot cirros cirros
-
- View vApp
-    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF view vapp 90bd2b4e-f782-46cf-b5e2-c3817dcf6633 -u
-
- List VMS
-    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vms
-
- List VDC in OSM format
-  python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vdc -o
-
-Mustaafa Bayramov
-mbayramov@vmware.com
-"""
-import os
-import argparse
-import traceback
-import uuid
-
-from xml.etree import ElementTree as ET
-
-import sys
-from pyvcloud import Http
-
-import logging
-import vimconn
-import time
-import uuid
-import urllib3
-import requests
-
-from vimconn_vmware import vimconnector
-from requests.packages.urllib3.exceptions import InsecureRequestWarning
-from prettytable import PrettyTable
-
-requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
-
-__author__ = "Mustafa Bayramov"
-__date__ = "$16-Sep-2016 11:09:29$"
-
-
-# TODO move to main vim
-def delete_network_action(vca=None, network_uuid=None):
-    """
-    Method leverages vCloud director and query network based on network uuid
-
-    Args:
-        vca - is active VCA connection.
-        network_uuid - is a network uuid
-
-        Returns:
-            The return XML respond
-    """
-
-    if vca is None or network_uuid is None:
-        return None
-
-    url_list = [vca.host, '/api/admin/network/', network_uuid]
-    vm_list_rest_call = ''.join(url_list)
-
-    if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-        response = Http.get(url=vm_list_rest_call,
-                            headers=vca.vcloud_session.get_vcloud_headers(),
-                            verify=vca.verify,
-                            logger=vca.logger)
-        if response.status_code == requests.codes.ok:
-            print response.content
-            return response.content
-
-    return None
-
-
-def print_vapp(vapp_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        vapp_dict: container vapp object.
-
-        Returns:
-            The return nothing
-    """
-
-    # following key available to print
-    # {'status': 'POWERED_OFF', 'storageProfileName': '*', 'hardwareVersion': '7', 'vmToolsVersion': '0',
-    #  'memoryMB': '384',
-    #  'href': 'https://172.16.254.206/api/vAppTemplate/vm-129e22e8-08dc-4cb6-8358-25f635e65d3b',
-    #  'isBusy': 'false', 'isDeployed': 'false', 'isInMaintenanceMode': 'false', 'isVAppTemplate': 'true',
-    #  'networkName': 'nat', 'isDeleted': 'false', 'catalogName': 'Cirros',
-    #  'containerName': 'Cirros Template', #  'container':
-    #  'https://172.16.254.206/api/vAppTemplate/vappTemplate-b966453d-c361-4505-9e38-ccef45815e5d',
-    #  'name': 'Cirros', 'pvdcHighestSupportedHardwareVersion': '11', 'isPublished': 'false',
-    #  'numberOfCpus': '1', 'vdc': 'https://172.16.254.206/api/vdc/a5056f85-418c-4bfd-8041-adb0f48be9d9',
-    #  'guestOs': 'Other (32-bit)', 'isVdcEnabled': 'true'}
-
-    if vapp_dict is None:
-        return
-
-    vm_table = PrettyTable(['vm   uuid',
-                            'vapp name',
-                            'vapp uuid',
-                            'network name',
-                            'storage name',
-                            'vcpu', 'memory', 'hw ver','deployed','status'])
-    for k in vapp_dict:
-        entry = []
-        entry.append(k)
-        entry.append(vapp_dict[k]['containerName'])
-        # vm-b1f5cd4c-2239-4c89-8fdc-a41ff18e0d61
-        entry.append(vapp_dict[k]['container'].split('/')[-1:][0][5:])
-        entry.append(vapp_dict[k]['networkName'])
-        entry.append(vapp_dict[k]['storageProfileName'])
-        entry.append(vapp_dict[k]['numberOfCpus'])
-        entry.append(vapp_dict[k]['memoryMB'])
-        entry.append(vapp_dict[k]['pvdcHighestSupportedHardwareVersion'])
-        entry.append(vapp_dict[k]['isDeployed'])
-        entry.append(vapp_dict[k]['status'])
-
-        vm_table.add_row(entry)
-
-    print vm_table
-
-
-def print_org(org_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        org_dict:  dictionary of organization where key is org uuid.
-
-        Returns:
-            The return nothing
-    """
-
-    if org_dict is None:
-        return
-
-    org_table = PrettyTable(['org uuid', 'name'])
-    for k in org_dict:
-        entry = [k, org_dict[k]]
-        org_table.add_row(entry)
-
-    print org_table
-
-
-def print_vm_list(vm_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        vm_dict:  dictionary of organization where key is org uuid.
-
-        Returns:
-            The return nothing
-    """
-    if vm_dict is None:
-        return
-
-    vm_table = PrettyTable(
-        ['vm uuid', 'vm name', 'vapp uuid', 'vdc uuid', 'network name', 'is deployed', 'vcpu', 'memory', 'status'])
-
-    try:
-        for k in vm_dict:
-            entry = []
-            entry.append(k)
-            entry.append(vm_dict[k]['name'])
-            entry.append(vm_dict[k]['container'].split('/')[-1:][0][5:])
-            entry.append(vm_dict[k]['vdc'].split('/')[-1:][0])
-            entry.append(vm_dict[k]['networkName'])
-            entry.append(vm_dict[k]['isDeployed'])
-            entry.append(vm_dict[k]['numberOfCpus'])
-            entry.append(vm_dict[k]['memoryMB'])
-            entry.append(vm_dict[k]['status'])
-            vm_table.add_row(entry)
-        print vm_table
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        pass
-
-
-def print_vdc_list(org_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        org_dict:  dictionary of organization where key is org uuid.
-
-        Returns:
-            The return nothing
-    """
-    if org_dict is None:
-        return
-    try:
-        vdcs_dict = {}
-        if org_dict.has_key('vdcs'):
-            vdcs_dict = org_dict['vdcs']
-        vdc_table = PrettyTable(['vdc uuid', 'vdc name'])
-        for k in vdcs_dict:
-            entry = [k, vdcs_dict[k]]
-            vdc_table.add_row(entry)
-
-        print vdc_table
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def print_network_list(org_dict=None):
-    """ Method print network list.
-
-    Args:
-        org_dict:   dictionary of organization that contain key networks with a list of all
-                    network for for specific VDC
-
-        Returns:
-            The return nothing
-    """
-    if org_dict is None:
-        return
-    try:
-        network_dict = {}
-        if org_dict.has_key('networks'):
-            network_dict = org_dict['networks']
-        network_table = PrettyTable(['network uuid', 'network name'])
-        for k in network_dict:
-            entry = [k, network_dict[k]]
-            network_table.add_row(entry)
-
-        print network_table
-
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def print_org_details(org_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        org_dict:  dictionary of organization where key is org uuid.
-
-        Returns:
-            The return nothing
-    """
-    if org_dict is None:
-        return
-    try:
-        catalogs_dict = {}
-
-        print_vdc_list(org_dict=org_dict)
-        print_network_list(org_dict=org_dict)
-
-        if org_dict.has_key('catalogs'):
-            catalogs_dict = org_dict['catalogs']
-
-        catalog_table = PrettyTable(['catalog uuid', 'catalog name'])
-        for k in catalogs_dict:
-            entry = [k, catalogs_dict[k]]
-            catalog_table.add_row(entry)
-
-        print catalog_table
-
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def delete_actions(vim=None, action=None, namespace=None):
-    if action == 'network' or namespace.action == 'network':
-        logger.debug("Requesting delete for network {}".format(namespace.network_name))
-        network_uuid = namespace.network_name
-        # if request name based we need find UUID
-        # TODO optimize it or move to external function
-        if not namespace.uuid:
-            org_dict = vim.get_org_list()
-            for org in org_dict:
-                org_net = vim.get_org(org)['networks']
-                for network in org_net:
-                    if org_net[network] == namespace.network_name:
-                        network_uuid = network
-
-        vim.delete_network_action(network_uuid=network_uuid)
-
-
-def list_actions(vim=None, action=None, namespace=None):
-    """ Method provide list object from VDC action
-
-       Args:
-           vim - is vcloud director vim connector.
-           action - is action for list ( vdc / org etc)
-           namespace -  must contain VDC / Org information.
-
-           Returns:
-               The return nothing
-       """
-
-    org_id = None
-    myorgs = vim.get_org_list()
-    for org in myorgs:
-        if myorgs[org] == namespace.vcdorg:
-            org_id = org
-        break
-    else:
-        print(" Invalid organization.")
-        return
-
-    if action == 'vms' or namespace.action == 'vms':
-        vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
-        print_vm_list(vm_dict=vm_dict)
-    elif action == 'vapps' or namespace.action == 'vapps':
-        vapp_dict = vim.get_vapp_list(vdc_name=namespace.vcdvdc)
-        print_vapp(vapp_dict=vapp_dict)
-    elif action == 'networks' or namespace.action == 'networks':
-        if namespace.osm:
-            osm_print(vim.get_network_list(filter_dict={}))
-        else:
-            print_network_list(vim.get_org(org_uuid=org_id))
-    elif action == 'vdc' or namespace.action == 'vdc':
-        if namespace.osm:
-            osm_print(vim.get_tenant_list(filter_dict=None))
-        else:
-            print_vdc_list(vim.get_org(org_uuid=org_id))
-    elif action == 'org' or namespace.action == 'org':
-        print_org(org_dict=vim.get_org_list())
-    else:
-        return None
-
-
-def print_network_details(network_dict=None):
-    try:
-        network_table = PrettyTable(network_dict.keys())
-        entry = [network_dict.values()]
-        network_table.add_row(entry[0])
-        print network_table
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def osm_print(generic_dict=None):
-
-    try:
-        for element in generic_dict:
-            table = PrettyTable(element.keys())
-            entry = [element.values()]
-            table.add_row(entry[0])
-        print table
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def view_actions(vim=None, action=None, namespace=None):
-    org_id = None
-    orgs = vim.get_org_list()
-    for org in orgs:
-        if orgs[org] == namespace.vcdorg:
-            org_id = org
-        break
-    else:
-        print(" Invalid organization.")
-        return
-
-    myorg = vim.get_org(org_uuid=org_id)
-
-    # view org
-    if action == 'org' or namespace.action == 'org':
-        org_id = None
-        orgs = vim.get_org_list()
-        if namespace.uuid:
-            if namespace.org_name in orgs:
-                org_id = namespace.org_name
-        else:
-            # we need find UUID based on name provided
-            for org in orgs:
-                if orgs[org] == namespace.org_name:
-                    org_id = org
-                    break
-
-        logger.debug("Requesting view for orgs {}".format(org_id))
-        print_org_details(vim.get_org(org_uuid=org_id))
-
-    # view vapp action
-    if action == 'vapp' or namespace.action == 'vapp':
-        if namespace.vapp_name is not None and namespace.uuid:
-            logger.debug("Requesting vapp {} for vdc {}".format(namespace.vapp_name, namespace.vcdvdc))
-            vapp_dict = {}
-            vapp_uuid = namespace.vapp_name
-            # if request based on just name we need get UUID
-            if not namespace.uuid:
-                vapp_uuid = vim.get_vappid(vdc=namespace.vcdvdc, vapp_name=namespace.vapp_name)
-                if vapp_uuid is None:
-                    print("Can't find vapp by given name {}".format(namespace.vapp_name))
-                    return
-
-            print " namespace {}".format(namespace)
-            if vapp_dict is not None and namespace.osm:
-                vm_info_dict = vim.get_vminstance(vim_vm_uuid=vapp_uuid)
-                print vm_info_dict
-            if vapp_dict is not None and namespace.osm != True:
-                vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vapp_uuid, isuuid=True)
-                print_vapp(vapp_dict=vapp_dict)
-
-    # view network
-    if action == 'network' or namespace.action == 'network':
-        logger.debug("Requesting view for network {}".format(namespace.network_name))
-        network_uuid = namespace.network_name
-        # if request name based we need find UUID
-        # TODO optimize it or move to external function
-        if not namespace.uuid:
-            if not myorg.has_key('networks'):
-                print("Network {} is undefined in vcloud director for org {} vdc {}".format(namespace.network_name,
-                                                                                            vim.name,
-                                                                                            vim.tenant_name))
-                return
-
-            my_org_net = myorg['networks']
-            for network in my_org_net:
-                if my_org_net[network] == namespace.network_name:
-                    network_uuid = network
-                    break
-
-        print print_network_details(network_dict=vim.get_vcd_network(network_uuid=network_uuid))
-
-
-def create_actions(vim=None, action=None, namespace=None):
-    """Method gets provider vdc view from vcloud director
-
-        Args:
-            vim - is Cloud director vim connector
-            action - action for create ( network / vdc etc)
-
-        Returns:
-            The return xml content of respond or None
-    """
-    if action == 'network' or namespace.action == 'network':
-        logger.debug("Creating a network in vcloud director".format(namespace.network_name))
-        network_uuid = vim.create_network(namespace.network_name)
-        if network_uuid is not None:
-            print ("Crated new network {} and uuid: {}".format(namespace.network_name, network_uuid))
-        else:
-            print ("Failed create a new network {}".format(namespace.network_name))
-    elif action == 'vdc' or namespace.action == 'vdc':
-        logger.debug("Creating a new vdc in vcloud director.".format(namespace.vdc_name))
-        vdc_uuid = vim.create_vdc(namespace.vdc_name)
-        if vdc_uuid is not None:
-            print ("Crated new vdc {} and uuid: {}".format(namespace.vdc_name, vdc_uuid))
-        else:
-            print ("Failed create a new vdc {}".format(namespace.vdc_name))
-    else:
-        return None
-
-
-def validate_uuid4(uuid_string):
-    """Function validate that string contain valid uuid4
-
-        Args:
-            uuid_string - valid UUID string
-
-        Returns:
-            The return true if string contain valid UUID format
-    """
-    try:
-        val = uuid.UUID(uuid_string, version=4)
-    except ValueError:
-        return False
-    return True
-
-
-def upload_image(vim=None, image_file=None):
-    """Function upload image to vcloud director
-
-        Args:
-            image_file - valid UUID string
-
-        Returns:
-            The return true if image uploaded correctly
-    """
-    try:
-        catalog_uuid = vim.get_image_id_from_path(path=image_file, progress=True)
-        if catalog_uuid is not None and validate_uuid4(catalog_uuid):
-            print("Image uploaded and uuid {}".format(catalog_uuid))
-            return True
-    except vimconn.vimconnException as upload_exception:
-        print("Failed uploaded {} image".format(image_file))
-        print("Error Reason: {}".format(upload_exception.message))
-    return False
-
-
-def boot_image(vim=None, image_name=None, vm_name=None):
-    """ Function boot image that resided in vcloud director.
-        The image name can be UUID of name.
-
-        Args:
-            vim - vim connector
-            image_name - image identified by UUID or text string.
-            vm_name - vmname
-
-
-         Returns:
-             The return true if image uploaded correctly
-     """
-
-    vim_catalog = None
-    try:
-        catalogs = vim.vca.get_catalogs()
-        if not validate_uuid4(image_name):
-            vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
-            if vim_catalog is None:
-                return None
-        else:
-            vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
-            if vim_catalog is None:
-                return None
-
-        print (" Booting {} image id {} ".format(vm_name, vim_catalog))
-        vm_uuid = vim.new_vminstance(name=vm_name, image_id=vim_catalog)
-        if vm_uuid is not None and validate_uuid4(vm_uuid):
-            print("Image booted and vm uuid {}".format(vm_uuid))
-            vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vm_uuid, isuuid=True)
-            if vapp_dict is not None:
-                print_vapp(vapp_dict=vapp_dict)
-        return True
-    except vimconn.vimconnNotFoundException as notFound:
-        print("Failed boot {} image".format(image_name))
-        print(notFound.message)
-    except vimconn.vimconnException as vimconError:
-        print("Failed boot {} image".format(image_name))
-        print(vimconError.message)
-    except:
-        print("Failed boot {} image".format(image_name))
-
-
-        return False
-
-
-def image_action(vim=None, action=None, namespace=None):
-    """ Function present set of action to manipulate with image.
-          - upload image
-          - boot image.
-          - delete image ( not yet done )
-
-        Args:
-             vim - vcloud director connector
-             action - string (upload/boot etc)
-             namespace - contain other attributes image name etc
-
-         Returns:
-             The return nothing
-     """
-
-    if action == 'upload' or namespace.action == 'upload':
-        upload_image(vim=vim, image_file=namespace.image)
-    elif action == 'boot' or namespace.action == 'boot':
-        boot_image(vim=vim, image_name=namespace.image, vm_name=namespace.vmname)
-    else:
-        return None
-
-
-def vmwarecli(command=None, action=None, namespace=None):
-    logger.debug("Namespace {}".format(namespace))
-    urllib3.disable_warnings()
-
-    vcduser = None
-    vcdpasword = None
-    vcdhost = None
-    vcdorg = None
-
-    if hasattr(__builtins__, 'raw_input'):
-        input = raw_input
-
-    if namespace.vcdvdc is None:
-        while True:
-            vcduser = input("Enter vcd username: ")
-            if vcduser is not None and len(vcduser) > 0:
-                break
-    else:
-        vcduser = namespace.vcduser
-
-    if namespace.vcdpassword is None:
-        while True:
-            vcdpasword = input("Please enter vcd password: ")
-            if vcdpasword is not None and len(vcdpasword) > 0:
-                break
-    else:
-        vcdpasword = namespace.vcdpassword
-
-    if namespace.vcdhost is None:
-        while True:
-            vcdhost = input("Please enter vcd host name or ip: ")
-            if vcdhost is not None and len(vcdhost) > 0:
-                break
-    else:
-        vcdhost = namespace.vcdhost
-
-    if namespace.vcdorg is None:
-        while True:
-            vcdorg = input("Please enter vcd organization name: ")
-            if vcdorg is not None and len(vcdorg) > 0:
-                break
-    else:
-        vcdorg = namespace.vcdorg
-
-    try:
-        vim = vimconnector(uuid=None,
-                           name=vcdorg,
-                           tenant_id=None,
-                           tenant_name=namespace.vcdvdc,
-                           url=vcdhost,
-                           url_admin=vcdhost,
-                           user=vcduser,
-                           passwd=vcdpasword,
-                           log_level="DEBUG",
-                           config={'admin_username': namespace.vcdamdin, 'admin_password': namespace.vcdadminpassword})
-        vim.vca = vim.connect()
-
-    except vimconn.vimconnConnectionException:
-        print("Failed connect to vcloud director. Please check credential and hostname.")
-        return
-
-    # list
-    if command == 'list' or namespace.command == 'list':
-        logger.debug("Client requested list action")
-        # route request to list actions
-        list_actions(vim=vim, action=action, namespace=namespace)
-
-    # view action
-    if command == 'view' or namespace.command == 'view':
-        logger.debug("Client requested view action")
-        view_actions(vim=vim, action=action, namespace=namespace)
-
-    # delete action
-    if command == 'delete' or namespace.command == 'delete':
-        logger.debug("Client requested delete action")
-        delete_actions(vim=vim, action=action, namespace=namespace)
-
-    # create action
-    if command == 'create' or namespace.command == 'create':
-        logger.debug("Client requested create action")
-        create_actions(vim=vim, action=action, namespace=namespace)
-
-    # image action
-    if command == 'image' or namespace.command == 'image':
-        logger.debug("Client requested create action")
-        image_action(vim=vim, action=action, namespace=namespace)
-
-
-if __name__ == '__main__':
-    defaults = {'vcdvdc': 'default',
-                'vcduser': 'admin',
-                'vcdpassword': 'admin',
-                'vcdhost': 'https://localhost',
-                'vcdorg': 'default',
-                'debug': 'INFO'}
-
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-u', '--vcduser', help='vcloud director username', type=str)
-    parser.add_argument('-p', '--vcdpassword', help='vcloud director password', type=str)
-    parser.add_argument('-U', '--vcdamdin', help='vcloud director password', type=str)
-    parser.add_argument('-P', '--vcdadminpassword', help='vcloud director password', type=str)
-    parser.add_argument('-c', '--vcdhost', help='vcloud director host', type=str)
-    parser.add_argument('-o', '--vcdorg', help='vcloud director org', type=str)
-    parser.add_argument('-v', '--vcdvdc', help='vcloud director vdc', type=str)
-    parser.add_argument('-d', '--debug', help='debug level', type=int)
-
-    parser_subparsers = parser.add_subparsers(help='commands', dest='command')
-    sub = parser_subparsers.add_parser('list', help='List objects (VMs, vApps, networks)')
-    sub_subparsers = sub.add_subparsers(dest='action')
-
-    list_vms = sub_subparsers.add_parser('vms', help='list - all vm deployed in vCloud director')
-    list_vapps = sub_subparsers.add_parser('vapps', help='list - all vapps deployed in vCloud director')
-    list_network = sub_subparsers.add_parser('networks', help='list - all networks deployed')
-    list_network.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
-
-    #list vdc
-    list_vdc = sub_subparsers.add_parser('vdc', help='list - list all vdc for organization accessible to you')
-    list_vdc.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
-
-    list_org = sub_subparsers.add_parser('org', help='list - list of organizations accessible to you.')
-
-    create_sub = parser_subparsers.add_parser('create')
-    create_sub_subparsers = create_sub.add_subparsers(dest='action')
-    create_vms = create_sub_subparsers.add_parser('vms')
-    create_vapp = create_sub_subparsers.add_parser('vapp')
-    create_vapp.add_argument('uuid')
-
-    # add network
-    create_network = create_sub_subparsers.add_parser('network')
-    create_network.add_argument('network_name', action='store', help='create a network for a vdc')
-
-    # add VDC
-    create_vdc = create_sub_subparsers.add_parser('vdc')
-    create_vdc.add_argument('vdc_name', action='store', help='create a new VDC for org')
-
-    delete_sub = parser_subparsers.add_parser('delete')
-    del_sub_subparsers = delete_sub.add_subparsers(dest='action')
-    del_vms = del_sub_subparsers.add_parser('vms')
-    del_vapp = del_sub_subparsers.add_parser('vapp')
-    del_vapp.add_argument('uuid', help='view vapp based on UUID')
-
-    # delete network
-    del_network = del_sub_subparsers.add_parser('network')
-    del_network.add_argument('network_name', action='store',
-                             help='- delete network for vcloud director by provided name')
-    del_network.add_argument('-u', '--uuid', default=False, action='store_true',
-                             help='delete network for vcloud director by provided uuid')
-
-    # delete vdc
-    del_vdc = del_sub_subparsers.add_parser('vdc')
-
-    view_sub = parser_subparsers.add_parser('view')
-    view_sub_subparsers = view_sub.add_subparsers(dest='action')
-
-    view_vms_parser = view_sub_subparsers.add_parser('vms')
-    view_vms_parser.add_argument('uuid', default=False, action='store_true',
-                                 help='- View VM for specific uuid in vcloud director')
-    view_vms_parser.add_argument('name', default=False, action='store_true',
-                                 help='- View VM for specific vapp name in vcloud director')
-
-    # view vapp
-    view_vapp_parser = view_sub_subparsers.add_parser('vapp')
-    view_vapp_parser.add_argument('vapp_name', action='store',
-                                  help='- view vapp for specific vapp name in vcloud director')
-    view_vapp_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view vapp based on uuid')
-    view_vapp_parser.add_argument('-o', '--osm', default=False, action='store_true',  help='provide view in OSM format')
-
-    # view network
-    view_network = view_sub_subparsers.add_parser('network')
-    view_network.add_argument('network_name', action='store',
-                              help='- view network for specific network name in vcloud director')
-    view_network.add_argument('-u', '--uuid', default=False, action='store_true', help='view network based on uuid')
-
-    # view VDC command and actions
-    view_vdc = view_sub_subparsers.add_parser('vdc')
-    view_vdc.add_argument('vdc_name', action='store',
-                          help='- View VDC based and action based on provided vdc uuid')
-    view_vdc.add_argument('-u', '--uuid', default=False, action='store_true', help='view vdc based on uuid')
-
-    # view organization command and actions
-    view_org = view_sub_subparsers.add_parser('org')
-    view_org.add_argument('org_name', action='store',
-                          help='- View VDC based and action based on provided vdc uuid')
-    view_org.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
-
-    # upload image action
-    image_sub = parser_subparsers.add_parser('image')
-    image_subparsers = image_sub.add_subparsers(dest='action')
-    upload_parser = image_subparsers.add_parser('upload')
-    upload_parser.add_argument('image', default=False, action='store', help='- valid path to OVF image ')
-    upload_parser.add_argument('catalog', default=False, action='store_true', help='- catalog name')
-
-    # boot vm action
-    boot_parser = image_subparsers.add_parser('boot')
-    boot_parser.add_argument('image', default=False, action='store', help='- Image name')
-    boot_parser.add_argument('vmname', default=False, action='store', help='- VM name')
-    boot_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
-
-    namespace = parser.parse_args()
-    # put command_line args to mapping
-    command_line_args = {k: v for k, v in vars(namespace).items() if v}
-
-    d = defaults.copy()
-    d.update(os.environ)
-    d.update(command_line_args)
-
-    logger = logging.getLogger('mano.vim.vmware')
-    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
-    ch = logging.StreamHandler()
-    ch.setLevel(str.upper(d['debug']))
-    ch.setFormatter(formatter)
-    logger.addHandler(ch)
-    logger.setLevel(getattr(logging, str.upper(d['debug'])))
-    logger.info(
-        "Connecting {} username: {} org: {} vdc: {} ".format(d['vcdhost'], d['vcduser'], d['vcdorg'], d['vcdvdc']))
-
-    logger.debug("command: \"{}\" actio: \"{}\"".format(d['command'], d['action']))
-
-    # main entry point.
-    vmwarecli(namespace=namespace)
diff --git a/vmwarerecli.py b/vmwarerecli.py
deleted file mode 100755 (executable)
index acd4240..0000000
+++ /dev/null
@@ -1,818 +0,0 @@
-# -*- coding: utf-8 -*-
-##
-# This file is standalone vmware vcloud director util
-# 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: mbayramov@vmware.com
-##
-
-"""
-
-Standalone application that leverage openmano vmware connector work with vCloud director rest api.
-
- - Provides capability to create and delete VDC for specific organization.
- - Create, delete and manage network for specific VDC
- - List deployed VM's , VAPPs, VDSs, Organization
- - View detail information about VM / Vapp , Organization etc
- - Operate with images upload / boot / power on etc
-
- Usage example.
-
- List organization created in vCloud director
-  vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list org
-
- List VDC for particular organization
-  vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list vdc
-
- Upload image
-  python vmwarerecli.py image upload /Users/spyroot/Developer/Openmano/Ro/vnfs/cirros/cirros.ovf
-
- Boot Image
-    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF image boot cirros cirros
-
- View vApp
-    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF view vapp 90bd2b4e-f782-46cf-b5e2-c3817dcf6633 -u
-
- List VMS
-    python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vms
-
- List VDC in OSM format
-  python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vdc -o
-
-Mustaafa Bayramov
-mbayramov@vmware.com
-"""
-import os
-import argparse
-import traceback
-import uuid
-
-from xml.etree import ElementTree as ET
-
-import sys
-from pyvcloud import Http
-
-import logging
-import vimconn
-import time
-import uuid
-import urllib3
-import requests
-
-from vimconn_vmware import vimconnector
-from requests.packages.urllib3.exceptions import InsecureRequestWarning
-from prettytable import PrettyTable
-
-requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
-
-__author__ = "Mustafa Bayramov"
-__date__ = "$16-Sep-2016 11:09:29$"
-
-
-# TODO move to main vim
-def delete_network_action(vca=None, network_uuid=None):
-    """
-    Method leverages vCloud director and query network based on network uuid
-
-    Args:
-        vca - is active VCA connection.
-        network_uuid - is a network uuid
-
-        Returns:
-            The return XML respond
-    """
-
-    if vca is None or network_uuid is None:
-        return None
-
-    url_list = [vca.host, '/api/admin/network/', network_uuid]
-    vm_list_rest_call = ''.join(url_list)
-
-    if not (not vca.vcloud_session or not vca.vcloud_session.organization):
-        response = Http.get(url=vm_list_rest_call,
-                            headers=vca.vcloud_session.get_vcloud_headers(),
-                            verify=vca.verify,
-                            logger=vca.logger)
-        if response.status_code == requests.codes.ok:
-            print response.content
-            return response.content
-
-    return None
-
-
-def print_vapp(vapp_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        vapp_dict: container vapp object.
-
-        Returns:
-            The return nothing
-    """
-
-    # following key available to print
-    # {'status': 'POWERED_OFF', 'storageProfileName': '*', 'hardwareVersion': '7', 'vmToolsVersion': '0',
-    #  'memoryMB': '384',
-    #  'href': 'https://172.16.254.206/api/vAppTemplate/vm-129e22e8-08dc-4cb6-8358-25f635e65d3b',
-    #  'isBusy': 'false', 'isDeployed': 'false', 'isInMaintenanceMode': 'false', 'isVAppTemplate': 'true',
-    #  'networkName': 'nat', 'isDeleted': 'false', 'catalogName': 'Cirros',
-    #  'containerName': 'Cirros Template', #  'container':
-    #  'https://172.16.254.206/api/vAppTemplate/vappTemplate-b966453d-c361-4505-9e38-ccef45815e5d',
-    #  'name': 'Cirros', 'pvdcHighestSupportedHardwareVersion': '11', 'isPublished': 'false',
-    #  'numberOfCpus': '1', 'vdc': 'https://172.16.254.206/api/vdc/a5056f85-418c-4bfd-8041-adb0f48be9d9',
-    #  'guestOs': 'Other (32-bit)', 'isVdcEnabled': 'true'}
-
-    if vapp_dict is None:
-        return
-
-    vm_table = PrettyTable(['vm   uuid',
-                            'vapp name',
-                            'vapp uuid',
-                            'network name',
-                            'storage name',
-                            'vcpu', 'memory', 'hw ver','deployed','status'])
-    for k in vapp_dict:
-        entry = []
-        entry.append(k)
-        entry.append(vapp_dict[k]['containerName'])
-        # vm-b1f5cd4c-2239-4c89-8fdc-a41ff18e0d61
-        entry.append(vapp_dict[k]['container'].split('/')[-1:][0][5:])
-        entry.append(vapp_dict[k]['networkName'])
-        entry.append(vapp_dict[k]['storageProfileName'])
-        entry.append(vapp_dict[k]['numberOfCpus'])
-        entry.append(vapp_dict[k]['memoryMB'])
-        entry.append(vapp_dict[k]['pvdcHighestSupportedHardwareVersion'])
-        entry.append(vapp_dict[k]['isDeployed'])
-        entry.append(vapp_dict[k]['status'])
-
-        vm_table.add_row(entry)
-
-    print vm_table
-
-
-def print_org(org_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        org_dict:  dictionary of organization where key is org uuid.
-
-        Returns:
-            The return nothing
-    """
-
-    if org_dict is None:
-        return
-
-    org_table = PrettyTable(['org uuid', 'name'])
-    for k in org_dict:
-        entry = [k, org_dict[k]]
-        org_table.add_row(entry)
-
-    print org_table
-
-
-def print_vm_list(vm_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        vm_dict:  dictionary of organization where key is org uuid.
-
-        Returns:
-            The return nothing
-    """
-    if vm_dict is None:
-        return
-
-    vm_table = PrettyTable(
-        ['vm uuid', 'vm name', 'vapp uuid', 'vdc uuid', 'network name', 'is deployed', 'vcpu', 'memory', 'status'])
-
-    try:
-        for k in vm_dict:
-            entry = []
-            entry.append(k)
-            entry.append(vm_dict[k]['name'])
-            entry.append(vm_dict[k]['container'].split('/')[-1:][0][5:])
-            entry.append(vm_dict[k]['vdc'].split('/')[-1:][0])
-            entry.append(vm_dict[k]['networkName'])
-            entry.append(vm_dict[k]['isDeployed'])
-            entry.append(vm_dict[k]['numberOfCpus'])
-            entry.append(vm_dict[k]['memoryMB'])
-            entry.append(vm_dict[k]['status'])
-            vm_table.add_row(entry)
-        print vm_table
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        pass
-
-
-def print_vdc_list(org_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        org_dict:  dictionary of organization where key is org uuid.
-
-        Returns:
-            The return nothing
-    """
-    if org_dict is None:
-        return
-    try:
-        vdcs_dict = {}
-        if org_dict.has_key('vdcs'):
-            vdcs_dict = org_dict['vdcs']
-        vdc_table = PrettyTable(['vdc uuid', 'vdc name'])
-        for k in vdcs_dict:
-            entry = [k, vdcs_dict[k]]
-            vdc_table.add_row(entry)
-
-        print vdc_table
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def print_network_list(org_dict=None):
-    """ Method print network list.
-
-    Args:
-        org_dict:   dictionary of organization that contain key networks with a list of all
-                    network for for specific VDC
-
-        Returns:
-            The return nothing
-    """
-    if org_dict is None:
-        return
-    try:
-        network_dict = {}
-        if org_dict.has_key('networks'):
-            network_dict = org_dict['networks']
-        network_table = PrettyTable(['network uuid', 'network name'])
-        for k in network_dict:
-            entry = [k, network_dict[k]]
-            network_table.add_row(entry)
-
-        print network_table
-
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def print_org_details(org_dict=None):
-    """ Method takes vapp_dict and print in tabular format
-
-    Args:
-        org_dict:  dictionary of organization where key is org uuid.
-
-        Returns:
-            The return nothing
-    """
-    if org_dict is None:
-        return
-    try:
-        catalogs_dict = {}
-
-        print_vdc_list(org_dict=org_dict)
-        print_network_list(org_dict=org_dict)
-
-        if org_dict.has_key('catalogs'):
-            catalogs_dict = org_dict['catalogs']
-
-        catalog_table = PrettyTable(['catalog uuid', 'catalog name'])
-        for k in catalogs_dict:
-            entry = [k, catalogs_dict[k]]
-            catalog_table.add_row(entry)
-
-        print catalog_table
-
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def delete_actions(vim=None, action=None, namespace=None):
-    if action == 'network' or namespace.action == 'network':
-        logger.debug("Requesting delete for network {}".format(namespace.network_name))
-        network_uuid = namespace.network_name
-        # if request name based we need find UUID
-        # TODO optimize it or move to external function
-        if not namespace.uuid:
-            org_dict = vim.get_org_list()
-            for org in org_dict:
-                org_net = vim.get_org(org)['networks']
-                for network in org_net:
-                    if org_net[network] == namespace.network_name:
-                        network_uuid = network
-
-        vim.delete_network_action(network_uuid=network_uuid)
-
-
-def list_actions(vim=None, action=None, namespace=None):
-    """ Method provide list object from VDC action
-
-       Args:
-           vim - is vcloud director vim connector.
-           action - is action for list ( vdc / org etc)
-           namespace -  must contain VDC / Org information.
-
-           Returns:
-               The return nothing
-       """
-
-    org_id = None
-    myorgs = vim.get_org_list()
-    for org in myorgs:
-        if myorgs[org] == namespace.vcdorg:
-            org_id = org
-        break
-    else:
-        print(" Invalid organization.")
-        return
-
-    if action == 'vms' or namespace.action == 'vms':
-        vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
-        print_vm_list(vm_dict=vm_dict)
-    elif action == 'vapps' or namespace.action == 'vapps':
-        vapp_dict = vim.get_vapp_list(vdc_name=namespace.vcdvdc)
-        print_vapp(vapp_dict=vapp_dict)
-    elif action == 'networks' or namespace.action == 'networks':
-        if namespace.osm:
-            osm_print(vim.get_network_list(filter_dict={}))
-        else:
-            print_network_list(vim.get_org(org_uuid=org_id))
-    elif action == 'vdc' or namespace.action == 'vdc':
-        if namespace.osm:
-            osm_print(vim.get_tenant_list(filter_dict=None))
-        else:
-            print_vdc_list(vim.get_org(org_uuid=org_id))
-    elif action == 'org' or namespace.action == 'org':
-        print_org(org_dict=vim.get_org_list())
-    else:
-        return None
-
-
-def print_network_details(network_dict=None):
-    try:
-        network_table = PrettyTable(network_dict.keys())
-        entry = [network_dict.values()]
-        network_table.add_row(entry[0])
-        print network_table
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def osm_print(generic_dict=None):
-
-    try:
-        for element in generic_dict:
-            table = PrettyTable(element.keys())
-            entry = [element.values()]
-            table.add_row(entry[0])
-        print table
-    except KeyError:
-        logger.error("wrong key {}".format(KeyError.message))
-        logger.logger.debug(traceback.format_exc())
-
-
-def view_actions(vim=None, action=None, namespace=None):
-    org_id = None
-    orgs = vim.get_org_list()
-    for org in orgs:
-        if orgs[org] == namespace.vcdorg:
-            org_id = org
-        break
-    else:
-        print(" Invalid organization.")
-        return
-
-    myorg = vim.get_org(org_uuid=org_id)
-
-    # view org
-    if action == 'org' or namespace.action == 'org':
-        org_id = None
-        orgs = vim.get_org_list()
-        if namespace.uuid:
-            if namespace.org_name in orgs:
-                org_id = namespace.org_name
-        else:
-            # we need find UUID based on name provided
-            for org in orgs:
-                if orgs[org] == namespace.org_name:
-                    org_id = org
-                    break
-
-        logger.debug("Requesting view for orgs {}".format(org_id))
-        print_org_details(vim.get_org(org_uuid=org_id))
-
-    # view vapp action
-    if action == 'vapp' or namespace.action == 'vapp':
-        if namespace.vapp_name is not None and namespace.uuid:
-            logger.debug("Requesting vapp {} for vdc {}".format(namespace.vapp_name, namespace.vcdvdc))
-            vapp_dict = {}
-            vapp_uuid = namespace.vapp_name
-            # if request based on just name we need get UUID
-            if not namespace.uuid:
-                vapp_uuid = vim.get_vappid(vdc=namespace.vcdvdc, vapp_name=namespace.vapp_name)
-                if vapp_uuid is None:
-                    print("Can't find vapp by given name {}".format(namespace.vapp_name))
-                    return
-
-            print " namespace {}".format(namespace)
-            if vapp_dict is not None and namespace.osm:
-                vm_info_dict = vim.get_vminstance(vim_vm_uuid=vapp_uuid)
-                print vm_info_dict
-            if vapp_dict is not None and namespace.osm != True:
-                vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vapp_uuid, isuuid=True)
-                print_vapp(vapp_dict=vapp_dict)
-
-    # view network
-    if action == 'network' or namespace.action == 'network':
-        logger.debug("Requesting view for network {}".format(namespace.network_name))
-        network_uuid = namespace.network_name
-        # if request name based we need find UUID
-        # TODO optimize it or move to external function
-        if not namespace.uuid:
-            if not myorg.has_key('networks'):
-                print("Network {} is undefined in vcloud director for org {} vdc {}".format(namespace.network_name,
-                                                                                            vim.name,
-                                                                                            vim.tenant_name))
-                return
-
-            my_org_net = myorg['networks']
-            for network in my_org_net:
-                if my_org_net[network] == namespace.network_name:
-                    network_uuid = network
-                    break
-
-        print print_network_details(network_dict=vim.get_vcd_network(network_uuid=network_uuid))
-
-
-def create_actions(vim=None, action=None, namespace=None):
-    """Method gets provider vdc view from vcloud director
-
-        Args:
-            vim - is Cloud director vim connector
-            action - action for create ( network / vdc etc)
-
-        Returns:
-            The return xml content of respond or None
-    """
-    if action == 'network' or namespace.action == 'network':
-        logger.debug("Creating a network in vcloud director".format(namespace.network_name))
-        network_uuid = vim.create_network(namespace.network_name)
-        if network_uuid is not None:
-            print ("Crated new network {} and uuid: {}".format(namespace.network_name, network_uuid))
-        else:
-            print ("Failed create a new network {}".format(namespace.network_name))
-    elif action == 'vdc' or namespace.action == 'vdc':
-        logger.debug("Creating a new vdc in vcloud director.".format(namespace.vdc_name))
-        vdc_uuid = vim.create_vdc(namespace.vdc_name)
-        if vdc_uuid is not None:
-            print ("Crated new vdc {} and uuid: {}".format(namespace.vdc_name, vdc_uuid))
-        else:
-            print ("Failed create a new vdc {}".format(namespace.vdc_name))
-    else:
-        return None
-
-
-def validate_uuid4(uuid_string):
-    """Function validate that string contain valid uuid4
-
-        Args:
-            uuid_string - valid UUID string
-
-        Returns:
-            The return true if string contain valid UUID format
-    """
-    try:
-        val = uuid.UUID(uuid_string, version=4)
-    except ValueError:
-        return False
-    return True
-
-
-def upload_image(vim=None, image_file=None):
-    """Function upload image to vcloud director
-
-        Args:
-            image_file - valid UUID string
-
-        Returns:
-            The return true if image uploaded correctly
-    """
-    try:
-        catalog_uuid = vim.get_image_id_from_path(path=image_file, progress=True)
-        if catalog_uuid is not None and validate_uuid4(catalog_uuid):
-            print("Image uploaded and uuid {}".format(catalog_uuid))
-            return True
-    except vimconn.vimconnException as upload_exception:
-        print("Failed uploaded {} image".format(image_file))
-        print("Error Reason: {}".format(upload_exception.message))
-    return False
-
-
-def boot_image(vim=None, image_name=None, vm_name=None):
-    """ Function boot image that resided in vcloud director.
-        The image name can be UUID of name.
-
-        Args:
-            vim - vim connector
-            image_name - image identified by UUID or text string.
-            vm_name - vmname
-
-
-         Returns:
-             The return true if image uploaded correctly
-     """
-
-    vim_catalog = None
-    try:
-        catalogs = vim.vca.get_catalogs()
-        if not validate_uuid4(image_name):
-            vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
-            if vim_catalog is None:
-                return None
-        else:
-            vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
-            if vim_catalog is None:
-                return None
-
-        print (" Booting {} image id {} ".format(vm_name, vim_catalog))
-        vm_uuid = vim.new_vminstance(name=vm_name, image_id=vim_catalog)
-        if vm_uuid is not None and validate_uuid4(vm_uuid):
-            print("Image booted and vm uuid {}".format(vm_uuid))
-            vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vm_uuid, isuuid=True)
-            if vapp_dict is not None:
-                print_vapp(vapp_dict=vapp_dict)
-        return True
-    except vimconn.vimconnNotFoundException as notFound:
-        print("Failed boot {} image".format(image_name))
-        print(notFound.message)
-    except vimconn.vimconnException as vimconError:
-        print("Failed boot {} image".format(image_name))
-        print(vimconError.message)
-    except:
-        print("Failed boot {} image".format(image_name))
-
-
-        return False
-
-
-def image_action(vim=None, action=None, namespace=None):
-    """ Function present set of action to manipulate with image.
-          - upload image
-          - boot image.
-          - delete image ( not yet done )
-
-        Args:
-             vim - vcloud director connector
-             action - string (upload/boot etc)
-             namespace - contain other attributes image name etc
-
-         Returns:
-             The return nothing
-     """
-
-    if action == 'upload' or namespace.action == 'upload':
-        upload_image(vim=vim, image_file=namespace.image)
-    elif action == 'boot' or namespace.action == 'boot':
-        boot_image(vim=vim, image_name=namespace.image, vm_name=namespace.vmname)
-    else:
-        return None
-
-
-def vmwarecli(command=None, action=None, namespace=None):
-    logger.debug("Namespace {}".format(namespace))
-    urllib3.disable_warnings()
-
-    vcduser = None
-    vcdpasword = None
-    vcdhost = None
-    vcdorg = None
-
-    if hasattr(__builtins__, 'raw_input'):
-        input = raw_input
-
-    if namespace.vcdvdc is None:
-        while True:
-            vcduser = input("Enter vcd username: ")
-            if vcduser is not None and len(vcduser) > 0:
-                break
-    else:
-        vcduser = namespace.vcduser
-
-    if namespace.vcdpassword is None:
-        while True:
-            vcdpasword = input("Please enter vcd password: ")
-            if vcdpasword is not None and len(vcdpasword) > 0:
-                break
-    else:
-        vcdpasword = namespace.vcdpassword
-
-    if namespace.vcdhost is None:
-        while True:
-            vcdhost = input("Please enter vcd host name or ip: ")
-            if vcdhost is not None and len(vcdhost) > 0:
-                break
-    else:
-        vcdhost = namespace.vcdhost
-
-    if namespace.vcdorg is None:
-        while True:
-            vcdorg = input("Please enter vcd organization name: ")
-            if vcdorg is not None and len(vcdorg) > 0:
-                break
-    else:
-        vcdorg = namespace.vcdorg
-
-    try:
-        vim = vimconnector(uuid=None,
-                           name=vcdorg,
-                           tenant_id=None,
-                           tenant_name=namespace.vcdvdc,
-                           url=vcdhost,
-                           url_admin=vcdhost,
-                           user=vcduser,
-                           passwd=vcdpasword,
-                           log_level="DEBUG",
-                           config={'admin_username': namespace.vcdamdin, 'admin_password': namespace.vcdadminpassword})
-        vim.vca = vim.connect()
-
-    except vimconn.vimconnConnectionException:
-        print("Failed connect to vcloud director. Please check credential and hostname.")
-        return
-
-    # list
-    if command == 'list' or namespace.command == 'list':
-        logger.debug("Client requested list action")
-        # route request to list actions
-        list_actions(vim=vim, action=action, namespace=namespace)
-
-    # view action
-    if command == 'view' or namespace.command == 'view':
-        logger.debug("Client requested view action")
-        view_actions(vim=vim, action=action, namespace=namespace)
-
-    # delete action
-    if command == 'delete' or namespace.command == 'delete':
-        logger.debug("Client requested delete action")
-        delete_actions(vim=vim, action=action, namespace=namespace)
-
-    # create action
-    if command == 'create' or namespace.command == 'create':
-        logger.debug("Client requested create action")
-        create_actions(vim=vim, action=action, namespace=namespace)
-
-    # image action
-    if command == 'image' or namespace.command == 'image':
-        logger.debug("Client requested create action")
-        image_action(vim=vim, action=action, namespace=namespace)
-
-
-if __name__ == '__main__':
-    defaults = {'vcdvdc': 'default',
-                'vcduser': 'admin',
-                'vcdpassword': 'admin',
-                'vcdhost': 'https://localhost',
-                'vcdorg': 'default',
-                'debug': 'INFO'}
-
-    parser = argparse.ArgumentParser()
-    parser.add_argument('-u', '--vcduser', help='vcloud director username', type=str)
-    parser.add_argument('-p', '--vcdpassword', help='vcloud director password', type=str)
-    parser.add_argument('-U', '--vcdamdin', help='vcloud director password', type=str)
-    parser.add_argument('-P', '--vcdadminpassword', help='vcloud director password', type=str)
-    parser.add_argument('-c', '--vcdhost', help='vcloud director host', type=str)
-    parser.add_argument('-o', '--vcdorg', help='vcloud director org', type=str)
-    parser.add_argument('-v', '--vcdvdc', help='vcloud director vdc', type=str)
-    parser.add_argument('-d', '--debug', help='debug level', type=int)
-
-    parser_subparsers = parser.add_subparsers(help='commands', dest='command')
-    sub = parser_subparsers.add_parser('list', help='List objects (VMs, vApps, networks)')
-    sub_subparsers = sub.add_subparsers(dest='action')
-
-    list_vms = sub_subparsers.add_parser('vms', help='list - all vm deployed in vCloud director')
-    list_vapps = sub_subparsers.add_parser('vapps', help='list - all vapps deployed in vCloud director')
-    list_network = sub_subparsers.add_parser('networks', help='list - all networks deployed')
-    list_network.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
-
-    #list vdc
-    list_vdc = sub_subparsers.add_parser('vdc', help='list - list all vdc for organization accessible to you')
-    list_vdc.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
-
-    list_org = sub_subparsers.add_parser('org', help='list - list of organizations accessible to you.')
-
-    create_sub = parser_subparsers.add_parser('create')
-    create_sub_subparsers = create_sub.add_subparsers(dest='action')
-    create_vms = create_sub_subparsers.add_parser('vms')
-    create_vapp = create_sub_subparsers.add_parser('vapp')
-    create_vapp.add_argument('uuid')
-
-    # add network
-    create_network = create_sub_subparsers.add_parser('network')
-    create_network.add_argument('network_name', action='store', help='create a network for a vdc')
-
-    # add VDC
-    create_vdc = create_sub_subparsers.add_parser('vdc')
-    create_vdc.add_argument('vdc_name', action='store', help='create a new VDC for org')
-
-    delete_sub = parser_subparsers.add_parser('delete')
-    del_sub_subparsers = delete_sub.add_subparsers(dest='action')
-    del_vms = del_sub_subparsers.add_parser('vms')
-    del_vapp = del_sub_subparsers.add_parser('vapp')
-    del_vapp.add_argument('uuid', help='view vapp based on UUID')
-
-    # delete network
-    del_network = del_sub_subparsers.add_parser('network')
-    del_network.add_argument('network_name', action='store',
-                             help='- delete network for vcloud director by provided name')
-    del_network.add_argument('-u', '--uuid', default=False, action='store_true',
-                             help='delete network for vcloud director by provided uuid')
-
-    # delete vdc
-    del_vdc = del_sub_subparsers.add_parser('vdc')
-
-    view_sub = parser_subparsers.add_parser('view')
-    view_sub_subparsers = view_sub.add_subparsers(dest='action')
-
-    view_vms_parser = view_sub_subparsers.add_parser('vms')
-    view_vms_parser.add_argument('uuid', default=False, action='store_true',
-                                 help='- View VM for specific uuid in vcloud director')
-    view_vms_parser.add_argument('name', default=False, action='store_true',
-                                 help='- View VM for specific vapp name in vcloud director')
-
-    # view vapp
-    view_vapp_parser = view_sub_subparsers.add_parser('vapp')
-    view_vapp_parser.add_argument('vapp_name', action='store',
-                                  help='- view vapp for specific vapp name in vcloud director')
-    view_vapp_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view vapp based on uuid')
-    view_vapp_parser.add_argument('-o', '--osm', default=False, action='store_true',  help='provide view in OSM format')
-
-    # view network
-    view_network = view_sub_subparsers.add_parser('network')
-    view_network.add_argument('network_name', action='store',
-                              help='- view network for specific network name in vcloud director')
-    view_network.add_argument('-u', '--uuid', default=False, action='store_true', help='view network based on uuid')
-
-    # view VDC command and actions
-    view_vdc = view_sub_subparsers.add_parser('vdc')
-    view_vdc.add_argument('vdc_name', action='store',
-                          help='- View VDC based and action based on provided vdc uuid')
-    view_vdc.add_argument('-u', '--uuid', default=False, action='store_true', help='view vdc based on uuid')
-
-    # view organization command and actions
-    view_org = view_sub_subparsers.add_parser('org')
-    view_org.add_argument('org_name', action='store',
-                          help='- View VDC based and action based on provided vdc uuid')
-    view_org.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
-
-    # upload image action
-    image_sub = parser_subparsers.add_parser('image')
-    image_subparsers = image_sub.add_subparsers(dest='action')
-    upload_parser = image_subparsers.add_parser('upload')
-    upload_parser.add_argument('image', default=False, action='store', help='- valid path to OVF image ')
-    upload_parser.add_argument('catalog', default=False, action='store_true', help='- catalog name')
-
-    # boot vm action
-    boot_parser = image_subparsers.add_parser('boot')
-    boot_parser.add_argument('image', default=False, action='store', help='- Image name')
-    boot_parser.add_argument('vmname', default=False, action='store', help='- VM name')
-    boot_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
-
-    namespace = parser.parse_args()
-    # put command_line args to mapping
-    command_line_args = {k: v for k, v in vars(namespace).items() if v}
-
-    d = defaults.copy()
-    d.update(os.environ)
-    d.update(command_line_args)
-
-    logger = logging.getLogger('mano.vim.vmware')
-    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
-    ch = logging.StreamHandler()
-    ch.setLevel(str.upper(d['debug']))
-    ch.setFormatter(formatter)
-    logger.addHandler(ch)
-    logger.setLevel(getattr(logging, str.upper(d['debug'])))
-    logger.info(
-        "Connecting {} username: {} org: {} vdc: {} ".format(d['vcdhost'], d['vcduser'], d['vcdorg'], d['vcdvdc']))
-
-    logger.debug("command: \"{}\" actio: \"{}\"".format(d['command'], d['action']))
-
-    # main entry point.
-    vmwarecli(namespace=namespace)