Merge branch 'v2.0' 63/1863/1
authortierno <alfonso.tiernosepulveda@telefonica.com>
Wed, 24 May 2017 09:23:28 +0000 (11:23 +0200)
committertierno <alfonso.tiernosepulveda@telefonica.com>
Wed, 24 May 2017 09:23:28 +0000 (11:23 +0200)
19 files changed:
database_utils/install-db-server.sh
openmano
openmanod
osm_ro/httpserver.py
osm_ro/nfvo.py
osm_ro/vmware_utils/OVF_converter/config/disk_controller.yaml [new file with mode: 0644]
osm_ro/vmware_utils/OVF_converter/config/os_type.yaml [new file with mode: 0644]
osm_ro/vmware_utils/OVF_converter/format_converter/__init__.py [new file with mode: 0644]
osm_ro/vmware_utils/OVF_converter/format_converter/command_progress.py [new file with mode: 0644]
osm_ro/vmware_utils/OVF_converter/format_converter/converter.py [new file with mode: 0644]
osm_ro/vmware_utils/OVF_converter/format_converter/ovf_converter_cli.py [new file with mode: 0644]
osm_ro/vmware_utils/OVF_converter/install.sh [new file with mode: 0755]
osm_ro/vmware_utils/OVF_converter/ovf_template/template.xml [new file with mode: 0644]
osm_ro/vmware_utils/OVF_converter/readme.txt [new file with mode: 0644]
scripts/install-openmano-service.sh
scripts/install-openmano.sh
test/RO_tests/simple_multi_vnfc/scenario_multi_vnfc.yaml
test/basictest.sh
test/test_RO.py

index 2f4df76..36b8003 100755 (executable)
@@ -156,8 +156,8 @@ echo '
 function db_exists(){  # (db_name, credential_file)
     # check credentials
     mysqlshow --defaults-extra-file="$2" >/dev/null  || exit 1
-    RESULT=`mysqlshow --defaults-extra-file="$2" | grep -v Wildcard | grep -o $1`
-    if [ "$RESULT" == "$1" ]; then
+    if mysqlshow --defaults-extra-file="$2" | grep -v Wildcard | grep -w -q $1
+    then
         # echo " DB $1 exists"
         return 0
     fi
index 45db340..7b33cb4 100755 (executable)
--- a/openmano
+++ b/openmano
@@ -1462,6 +1462,15 @@ def datacenter_edit(args):
         args.verbose += 1
     return _print_verbose(mano_response, args.verbose)
 
+def version(args):
+    headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
+    URLrequest = "http://%s:%s/openmano/version" % (mano_host, mano_port)
+
+    mano_response = requests.get(URLrequest, headers=headers_req)
+    logger.debug("openmano response: %s", mano_response.text)
+    print mano_response.text
+
+
 global mano_host
 global mano_port
 global mano_tenant
@@ -1474,8 +1483,10 @@ if __name__=="__main__":
     mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
     
     main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
-    main_parser.add_argument('--version', action='version', version='%(prog)s ' + __version__ )
-    
+    main_parser.add_argument('--version', action='version', help="get version of this client",
+                            version='%(prog)s client version ' + __version__ +
+                                    " (Note: use '%(prog)s version' to get server version)")
+
     subparsers = main_parser.add_subparsers(help='commands')
     
     parent_parser = argparse.ArgumentParser(add_help=False)
@@ -1486,6 +1497,9 @@ if __name__=="__main__":
     config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
     config_parser.set_defaults(func=config)
 
+    version_parser = subparsers.add_parser('version', parents=[parent_parser], help="get server version")
+    version_parser.set_defaults(func=version)
+
     vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
     vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
     vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
@@ -1590,13 +1604,11 @@ if __name__=="__main__":
     tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
     tenant_list_parser.set_defaults(func=tenant_list)
 
-    item_list=('tenant') #put tenant before so that help appear in order
-    for item in item_list:
-        element_edit_parser = subparsers.add_parser(item+'-edit', parents=[parent_parser], help="edits one "+item)
-        element_edit_parser.add_argument("name", help="name or uuid of the "+item)
-        element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
-        element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
-        element_edit_parser.set_defaults(func=element_edit, element=item + 's')
+    element_edit_parser = subparsers.add_parser('tenant-edit', parents=[parent_parser], help="edits one tenant")
+    element_edit_parser.add_argument("name", help="name or uuid of the tenant")
+    element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
+    element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
+    element_edit_parser.set_defaults(func=element_edit, element='tenants')
 
     datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
     datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
index f1ce0a7..0ad7a9e 100755 (executable)
--- a/openmanod
+++ b/openmanod
@@ -186,6 +186,8 @@ if __name__=="__main__":
             else:
                 assert False, "Unhandled option"
         global_config = load_configuration(config_file)
+        global_config["version"] = __version__
+        global_config["version_date"] = version_date
         #print global_config
         # Override parameters obtained by command line
         if port:
index 4841a98..d6dc0c7 100644 (file)
@@ -305,6 +305,9 @@ def enable_cors():
     '''Don't know yet if really needed. Keep it just in case'''
     bottle.response.headers['Access-Control-Allow-Origin'] = '*'
 
+@bottle.route(url_base + '/version', method='GET')
+def http_get_version():
+    return nfvo.get_version()
 #
 # VNFs
 #
index 7646994..5a29eed 100644 (file)
@@ -194,6 +194,10 @@ def stop_service():
         for thread in global_config["console_thread"]:
             thread.terminate = True
 
+def get_version():
+    return  ("openmanod version {} {}\n(c) Copyright Telefonica".format(global_config["version"],
+                                                                        global_config["version_date"] ))
+
 
 def get_flavorlist(mydb, vnf_id, nfvo_tenant=None):
     '''Obtain flavorList
diff --git a/osm_ro/vmware_utils/OVF_converter/config/disk_controller.yaml b/osm_ro/vmware_utils/OVF_converter/config/disk_controller.yaml
new file mode 100644 (file)
index 0000000..b090232
--- /dev/null
@@ -0,0 +1,30 @@
+##\r
+# Copyright 2016-2017 VMware Inc.\r
+# This file is part of ETSI OSM\r
+# All Rights Reserved.\r
+#\r
+# Licensed under the Apache License, Version 2.0 (the "License"); you may\r
+# not use this file except in compliance with the License. You may obtain\r
+# a copy of the License at\r
+#\r
+#         http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+# Unless required by applicable law or agreed to in writing, software\r
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\r
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r
+# License for the specific language governing permissions and limitations\r
+# under the License.\r
+#\r
+# For those usages not covered by the Apache License, Version 2.0 please\r
+# contact:  osslegalrouting@vmware.com\r
+##\r
\r
+---\r
+SATA Controller:\r
+  ResourceType: 20\r
+  ResourceSubTypes: ["vmware.sata.ahci"]\r
+IDE Controller:\r
+  ResourceType: 5\r
+SCSI Controller:\r
+  ResourceType: 6\r
+  ResourceSubTypes: ["VirtualSCSI", "lsilogic", "buslogic", "lsilogicsas"]
\ No newline at end of file
diff --git a/osm_ro/vmware_utils/OVF_converter/config/os_type.yaml b/osm_ro/vmware_utils/OVF_converter/config/os_type.yaml
new file mode 100644 (file)
index 0000000..385cd7b
--- /dev/null
@@ -0,0 +1,138 @@
+##\r
+# Copyright 2016-2017 VMware Inc.\r
+# This file is part of ETSI OSM\r
+# All Rights Reserved.\r
+#\r
+# Licensed under the Apache License, Version 2.0 (the "License"); you may\r
+# not use this file except in compliance with the License. You may obtain\r
+# a copy of the License at\r
+#\r
+#         http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+# Unless required by applicable law or agreed to in writing, software\r
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\r
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r
+# License for the specific language governing permissions and limitations\r
+# under the License.\r
+#\r
+# For those usages not covered by the Apache License, Version 2.0 please\r
+# contact:  osslegalrouting@vmware.com\r
+##\r
+\r
+---\r
+'0': Unknown\r
+'1': Other (32-bit)\r
+'2': MACOS\r
+'3': ATTUNIX\r
+'4': DGUX\r
+'5': DECNT\r
+'6': Tru64 UNIX\r
+'7': OpenVMS\r
+'8': HPUX\r
+'9': AIX\r
+'10': MVS\r
+'11': OS400\r
+'12': OS/2\r
+'13': JavaVM\r
+'14': MSDOS\r
+'15': WIN3x\r
+'16': WIN95\r
+'17': WIN98\r
+'18': WINNT\r
+'19': WINCE\r
+'20': NCR3000\r
+'21': NetWare\r
+'22': OSF\r
+'23': DC/OS\r
+'24': Reliant UNIX\r
+'25': SCO UnixWare\r
+'26': SCO OpenServer\r
+'27': Sequent\r
+'28': IRIX\r
+'29': Solaris\r
+'30': SunOS\r
+'31': U6000\r
+'32': ASERIES\r
+'33': HP NonStop OS\r
+'34': HP NonStop OSS\r
+'35': BS2000\r
+'36': LINUX\r
+'37': Lynx\r
+'38': XENIX\r
+'39': VM\r
+'40': Interactive UNIX\r
+'41': BSDUNIX\r
+'42': FreeBSD\r
+'43': NetBSD\r
+'44': GNU Hurd\r
+'45': OS9\r
+'46': MACH Kernel\r
+'47': Inferno\r
+'48': QNX\r
+'49': EPOC\r
+'50': IxWorks\r
+'51': VxWorks\r
+'52': MiNT\r
+'53': BeOS\r
+'54': HP MPE\r
+'55': NextStep\r
+'56': PalmPilot\r
+'57': Rhapsody\r
+'58': Windows 2000\r
+'59': Dedicated\r
+'60': OS/390\r
+'61': VSE\r
+'62': TPF\r
+'63': Windows (R) Me\r
+'64': Caldera Open UNIX\r
+'65': OpenBSD\r
+'66': Not Applicable\r
+'67': Windows XP\r
+'68': z/OS\r
+'69': Microsoft Windows Server 2003\r
+'70': Microsoft Windows Server 2003 64-Bit\r
+'71': Windows XP 64-Bit\r
+'72': Windows XP Embedded\r
+'73': Windows Vista\r
+'74': Windows Vista 64-Bit\r
+'75': Windows Embedded for Point of Service\r
+'76': Microsoft Windows Server 2008\r
+'77': Microsoft Windows Server 2008 64-Bit\r
+'78': FreeBSD 64-Bit\r
+'79': RedHat Enterprise Linux\r
+'80': RedHat Enterprise Linux 64-Bit\r
+'81': Solaris 64-Bit\r
+'82': SUSE\r
+'83': SUSE 64-Bit\r
+'84': SLES\r
+'85': SLES 64-Bit\r
+'86': Novell OES\r
+'87': Novell Linux Desktop\r
+'88': Sun Java Desktop System\r
+'89': Mandriva\r
+'90': Mandriva 64-Bit\r
+'91': TurboLinux\r
+'92': TurboLinux 64-Bit\r
+'93': Ubuntu\r
+'94': Ubuntu 64-Bit\r
+'95': Debian\r
+'96': Debian 64-Bit\r
+'97': Linux 2.4.x\r
+'98': Linux 2.4.x 64-Bit\r
+'99': Linux 2.6.x\r
+'100': Linux 2.6.x 64-Bit\r
+'101': Linux 64-Bit\r
+'102': Other 64-Bit\r
+'103': Microsoft Windows Server 2008 R2\r
+'104': VMware ESXi\r
+'105': Microsoft Windows 7\r
+'106': CentOS 32-bit\r
+'107': CentOS 64-bit\r
+'108': Oracle Linux 32-bit\r
+'109': Oracle Linux 64-bit\r
+'110': eComStation 32-bitx\r
+'111': Microsoft Windows Server 2011\r
+'113': Microsoft Windows Server 2012\r
+'114': Microsoft Windows 8\r
+'115': Microsoft Windows 8 64-bit\r
+'116': Microsoft Windows Server 2012 R2\r
diff --git a/osm_ro/vmware_utils/OVF_converter/format_converter/__init__.py b/osm_ro/vmware_utils/OVF_converter/format_converter/__init__.py
new file mode 100644 (file)
index 0000000..db9e016
--- /dev/null
@@ -0,0 +1,20 @@
+##
+# Copyright 2016-2017 VMware Inc.
+# This file is part of ETSI OSM
+# 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:  osslegalrouting@vmware.com
+##
diff --git a/osm_ro/vmware_utils/OVF_converter/format_converter/command_progress.py b/osm_ro/vmware_utils/OVF_converter/format_converter/command_progress.py
new file mode 100644 (file)
index 0000000..cbfb737
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2016-2017 VMware Inc.
+# This file is part of ETSI OSM
+# 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:  osslegalrouting@vmware.com
+##
+
+import threading
+import sys
+
+class RepeatingTimer(threading._Timer):
+    """ Class to run thread parally """
+    def run(self):
+        """ Method to run thread """
+        while True:
+            self.finished.wait(self.interval)
+            if self.finished.is_set():
+                return
+            else:
+                self.function(*self.args, **self.kwargs)
+
+
+class CommandProgressbar(object):
+    """ Class to show progressbar while waiting fro command output """
+
+    def __init__(self):
+        self.timer = None
+
+    def __show_progressbar(self):
+        """
+            Private method to show progressbar while waiting for command to complete
+            Args  : None
+            Return : None
+        """
+        print '\b.',
+        sys.stdout.flush()
+
+    def start_progressbar(self):
+        """
+            Method to start progressbar thread
+            Args  : None
+            Return : None
+        """
+        self.timer = RepeatingTimer(1.0, self.__show_progressbar)
+        self.timer.daemon = True # Allows program to exit if only the thread is alive
+        self.timer.start()
+
+    def stop_progressbar(self):
+        """
+            Method to stop progressbar thread
+            Args  : None
+            Return : None
+        """
+        self.timer.cancel()
diff --git a/osm_ro/vmware_utils/OVF_converter/format_converter/converter.py b/osm_ro/vmware_utils/OVF_converter/format_converter/converter.py
new file mode 100644 (file)
index 0000000..3c647a9
--- /dev/null
@@ -0,0 +1,569 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2016-2017 VMware Inc.
+# This file is part of ETSI OSM
+# 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:  osslegalrouting@vmware.com
+##
+
+import logging
+import os
+import subprocess
+import yaml
+from lxml import etree as ET
+from command_progress import CommandProgressbar
+
+#file paths
+MODULE_DIR = os.path.dirname(__file__)
+OVF_TEMPLATE_PATH = os.path.join(os.path.dirname(MODULE_DIR),
+                                "ovf_template/template.xml")
+OS_INFO_FILE_PATH = os.path.join(os.path.dirname(MODULE_DIR), 
+                                "config/os_type.yaml")
+DISK_CONTROLLER_INFO_FILE_PATH = os.path.join(os.path.dirname(MODULE_DIR),
+                                              "config/disk_controller.yaml")
+
+
+#Set logger
+LOG_FILE = os.path.join(os.path.dirname(MODULE_DIR),"logs/ovf_converter.log")
+logger = logging.getLogger(__name__)
+hdlr = logging.FileHandler(LOG_FILE)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+hdlr.setFormatter(formatter)
+logger.addHandler(hdlr)
+logger.setLevel(10)
+
+__version__ = "1.0"
+__description__ = "initial Release"
+
+def get_version(*args, **kwargs):
+    """ get version of this application"""
+    version = str(__version__ ) +" - "+ str( __description__ )
+    return version
+
+#converter class
+class OVFConverter(object):
+    """ Class to convert input image into OVF format """
+
+    def __init__(self, source_img_path, output_location=None, output_ovf_name=None,
+                    memory=None, cpu=None, disk=None, os_type=None,
+                    disk_controller=None,
+                    options={'subformat':'streamOptimized'}):
+        """
+            Constructor to initialize object of class OVFConverter
+            Args:
+            source_img_path - absolute path to source image which will get convert into ovf
+            output_location - location where created OVF will be kept. This location
+                              should have write access. If not given file will get
+                              created at source location  (optional)
+            output_ovf_name - name of output ovf.If not given source image name will 
+                              be used (optional)
+            memory -          required memory for VM in MB (optional)
+            cpu -             required number of virtual cpus for VM (optional)
+            disk -            required size of disk for VM in GB (optional)
+            os_type-          required operating system type as specified in user document
+                                (default os type other 32 bit) (optional)
+            disk_controller - required disk controller type
+                                (default controller SCSI with lsilogicsas)
+                                (SATA, IDE, Paravirtual, Buslogic, Lsilogic, Lsilogicsas) (optional)
+            options - subformat option for OVF  (optional)
+
+            Returns:
+                Nothing.
+        """
+        self.logger = logger
+        self.ovf_template_path = OVF_TEMPLATE_PATH
+
+        self.source_img_path = source_img_path
+        file_location, file_extension = os.path.splitext(self.source_img_path)
+        self.source_img_location = os.path.dirname(self.source_img_path)
+        self.source_format = file_extension[1:]
+        self.source_img_filename = os.path.basename(self.source_img_path).split('.')[0]
+
+        self.output_format = "ovf"
+        self.output_ovf_name = output_ovf_name.split('.')[0] if output_ovf_name else self.source_img_filename
+        self.output_location = output_location if output_location else self.source_img_location
+        self.output_ovf_name_ext = self.output_ovf_name + "." + self.output_format
+        self.output_path = os.path.join(self.output_location , self.output_ovf_name_ext )
+
+        self.output_diskimage_format = "vmdk"
+        self.output_diskimage_name = self.source_img_filename + "."+ self.output_diskimage_format
+        self.output_diskimage_path = os.path.join(self.output_location,  self.output_diskimage_name)
+
+
+        self.logger.info("Input parameters to Converter: \n ovf_template_path = {}, \n source_img_path = {}, \n"\
+                    "source_img_location ={} , \n source_format = {}, \n source_img_filename = {}".format(
+                                                        self.ovf_template_path,
+                                                        self.source_img_path, self.source_img_location,
+                                                        self.source_format, self.source_img_filename ))
+
+        self.logger.info("Output parameters to Converter: \n output_format = {}, \n output_ovf_name = {}, \n"\
+                    "output_location ={} , \n output_path = {}, \n output_diskimage_name = {} , \n"\
+                    " output_diskimage_path = {} ".format(self.output_format, self.output_ovf_name,
+                                                    self.output_location, self.output_path,
+                                                    self.output_diskimage_name,self.output_diskimage_path ))
+
+
+        self.disk_capacity = 1
+        self.disk_populated_size = 0
+
+        self.vm_name = self.output_ovf_name
+        self.memory = str(memory) if memory is not None else None
+        self.cpu = str(cpu) if cpu is not None else None
+        self.os_type=str(os_type).strip() if os_type else None
+
+        if self.os_type:
+            self.osID , self.osType = self.__get_osType()
+            if self.osID is None or self.osType is None:
+               error_msg = "ERROR: Invalid input can not find OS type {} ".format(self.os_type)
+               self.__raise_exception(error_msg)
+
+        self.disk_controller = str(disk_controller).strip() if disk_controller else None
+
+        if self.disk_controller:
+            self.disk_controller_info = self.__get_diskcontroller()
+
+            if not self.disk_controller_info:
+                error_msg = "ERROR: Invalid input can not find Disk Controller {} ".format(self.disk_controller)
+                self.__raise_exception(error_msg)
+
+        if disk is not None:
+            #convert disk size from GB to bytes
+            self.disk_size = int(disk) * 1024 * 1024 * 1024
+        else:
+            self.disk_size = None
+
+        self.logger.info("Other input parameters to Converter: \n vm_name = {}, \n memory = {}, \n"\
+                    "disk_size ={} \n os type = {} \n disk controller = {}".format(
+                                self.vm_name, self.memory, self.disk_size, self.os_type, self.disk_controller
+                                ))
+
+        #check access for read input location and write output location return none if no access
+        if not os.access(self.source_img_path, os.F_OK):
+            error_msg = "ERROR: Source image file {} not present".format(self.source_img_path)
+            self.__raise_exception(error_msg, exception_type="IO")
+
+        elif not os.access(self.source_img_path, os.R_OK):
+            error_msg = "ERROR: Cannot read source image file {}".format(self.source_img_path)
+            self.__raise_exception(error_msg, exception_type="IO")
+
+        if not os.access(self.output_location, os.W_OK):
+            error_msg = "ERROR: Not have write access to location {} to write output OVF ".format(self.source_img_path)
+            self.__raise_exception(error_msg, exception_type="IO")
+
+    def __get_image_info(self):
+        """ 
+            Private method to get information about source imager.
+            Args  : None
+            Return : True on success else False
+        """
+        try:
+            print("Getting source image information")
+            command = "qemu-img info \t " + self.source_img_path
+            output, error, returncode= self.__execute_command(command)
+
+            if error or returncode:
+                self.logger.error("ERROR: Error occurred while getting information about source image : {} \n "\
+                                  "return code : {} ".format(error, returncode))
+                return False
+
+            elif output:
+                self.logger.info("Get Image Info Output : {} \n ".format(output))
+                split_output = output.split("\n")
+                for line in split_output:
+                    line = line.strip()
+                    if "virtual size" in line:
+                        virtual_size_info = line.split(":")[1].split()
+                        if len(virtual_size_info) == 3 and virtual_size_info[2].strip(")") == "bytes":
+                            self.disk_capacity  = int(virtual_size_info[1].strip("("))
+                        else:
+                            self.disk_capacity  = self.__convert_size(virtual_size_info[0])
+
+                    elif "disk size" in line:
+                        size = line.split(":")[1].split()[0]
+                        self.disk_populated_size = self.__convert_size(size)
+                    elif "file format" in line:
+                        self.source_format = line.split(":")[1]
+
+                self.logger.info("Updated source image virtual disk capacity : {} ,"\
+                                 "Updated source image populated size: {}".format(self.disk_capacity,
+                                                                    self.disk_populated_size))
+                return True
+        except Exception as exp:
+            error_msg = "ERROR: Error occurred while getting information about source image : {}".format(exp)
+            self.logger.error(error_msg)
+            print(error_msg)
+            return False
+
+    def __convert_image(self):
+        """ 
+            Private method to convert source disk image into .vmdk disk image.
+            Args  : None
+            Return : True on success else False
+        """
+
+        print("Converting source disk image to .vmdk ")
+
+        progress = CommandProgressbar()
+        progress.start_progressbar()
+
+        command = "qemu-img convert -f "+ self.source_format +" -O " + self.output_diskimage_format + \
+                " -o subformat=streamOptimized " + self.source_img_path + "\t" + self.output_diskimage_path
+
+        output, error , returncode = self.__execute_command(command)
+
+        progress.stop_progressbar()
+
+        if error or returncode :
+            error_msg = "ERROR: Error occurred while converting source disk image into vmdk : {} \n "\
+                                  "return code : {} ".format(error, returncode)
+            self.logger.error(error_msg)
+            print(error_msg)
+            return False
+        else:
+            if os.path.isfile(self.output_diskimage_path):
+                self.logger.info("Successfully converted source image {} into {} \n "\
+                                  "return code : {} ".format(self.source_img_path,
+                                                        self.output_diskimage_path,
+                                                        returncode))
+                result = self.__make_image_bootable()
+                if result:
+                    self.logger.info("Made {} bootable".format(self.output_diskimage_path))
+                    return True
+                else:
+                    self.logger.error("Cannot make {} bootable".format(self.output_diskimage_path))
+                    print("ERROR: Fail to convert source image into .vmdk")
+                    return False
+            else:
+                self.logger.error("Converted vmdk disk file {} is not present \n ".format(
+                                                    self.output_diskimage_path))
+                print("Fail to convert source image into .vmdk")
+                return False
+
+    def __make_image_bootable(self):
+        """ 
+            Private method to make source disk image bootable.
+            Args  : None
+            Return : True on success else False
+        """
+        command = "printf '\x03' | dd conv=notrunc of="+ self.output_diskimage_path + "\t bs=1 seek=$((0x4))"
+        output, error, returncode = self.__execute_command(command)
+
+        if error and returncode :
+            error_msg = "ERROR:Error occurred while making source disk image bootable : {} \n "\
+                                  "return code : {} ".format(error, returncode)
+            self.logger.error(error_msg)
+            print(error_msg)
+            return False
+        else:
+            self.logger.info("Make Image Bootable Output : {} ".format(output))
+            return True
+
+
+    def __edit_ovf_template(self):
+        """ 
+            Private method to create new OVF file by editing OVF template
+            Args  : None
+            Return : True on success else False
+        """
+        try:
+            print("\nCreating OVF")
+            #Read OVF template file
+            OVF_tree = ET.parse(self.ovf_template_path)
+            root = OVF_tree.getroot()
+
+            #Collect namespaces
+            nsmap = {k:v for k,v in root.nsmap.iteritems() if k}
+            nsmap["xmlns"]= "http://schemas.dmtf.org/ovf/envelope/1"
+
+            #Edit OVF template
+            references = root.find('xmlns:References',nsmap)
+            if references is not None:
+                file_tag = references.find('xmlns:File', nsmap)
+                if file_tag is not None:
+                    file_tag.attrib['{'+nsmap['ovf']+'}href'] = self.output_diskimage_name
+
+            disksection = root.find('xmlns:DiskSection',nsmap)
+            if disksection is not None:
+                diak_tag = disksection.find('xmlns:Disk', nsmap)
+                if diak_tag is not None:
+                    if self.disk_size and self.disk_size > self.disk_capacity:
+                        self.disk_capacity = self.disk_size
+                    diak_tag.attrib['{'+nsmap['ovf']+'}capacity'] = str(self.disk_capacity)
+                    diak_tag.attrib['{'+nsmap['ovf']+'}populatedSize'] = str(self.disk_populated_size)
+
+            virtuasystem = root.find('xmlns:VirtualSystem',nsmap)
+            if virtuasystem is not None:
+                name_tag = virtuasystem.find('xmlns:Name', nsmap)
+                if name_tag is not None:
+                    name_tag.text = self.vm_name
+
+                if self.os_type is not None:
+                    operatingSystemSection = virtuasystem.find('xmlns:OperatingSystemSection', nsmap)
+                    if self.osID and self.osType:
+                        operatingSystemSection.attrib['{'+nsmap['ovf']+'}id'] = self.osID
+                        os_discription_tag = operatingSystemSection.find('xmlns:Description', nsmap)
+                        os_discription_tag.text = self.osType
+
+                virtualHardwareSection = virtuasystem.find('xmlns:VirtualHardwareSection', nsmap)
+                system = virtualHardwareSection.find('xmlns:System', nsmap)
+                virtualSystemIdentifier = system.find('vssd:VirtualSystemIdentifier', nsmap)
+                if virtualSystemIdentifier is not None:
+                    virtualSystemIdentifier.text = self.vm_name
+
+                if self.memory is not None or self.cpu is not None or self.disk_controller is not None:
+                    for item in virtualHardwareSection.iterfind('xmlns:Item',nsmap):
+                        description = item.find("rasd:Description",nsmap)
+
+                        if self.cpu is not None:
+                            if description is not None and description.text == "Number of Virtual CPUs":
+                                cpu_item = item.find("rasd:VirtualQuantity", nsmap)
+                                name_item = item.find("rasd:ElementName", nsmap)
+                                if cpu_item is not None:
+                                    cpu_item.text = self.cpu
+                                    name_item.text = self.cpu+" virtual CPU(s)"
+
+                        if self.memory is not None:
+                            if description is not None and description.text == "Memory Size":
+                                mem_item = item.find("rasd:VirtualQuantity", nsmap)
+                                name_item = item.find("rasd:ElementName", nsmap)
+                                if mem_item is not None:
+                                    mem_item.text = self.memory
+                                    name_item.text = self.memory + " MB of memory"
+
+                        if self.disk_controller is not None:
+                            if description is not None and description.text == "SCSI Controller":
+                                if self.disk_controller_info is not None:
+                                    name_item = item.find("rasd:ElementName", nsmap)
+                                    name_item.text = str(self.disk_controller_info["controllerName"])+"0"
+
+                                    resource_type = item.find("rasd:ResourceType", nsmap)
+                                    resource_type.text = self.disk_controller_info["resourceType"]
+
+                                    description.text = self.disk_controller_info["controllerName"]
+                                    resource_subtype = item.find("rasd:ResourceSubType", nsmap)
+                                    if self.disk_controller_info["controllerName"] == "IDE Controller":
+                                        #Remove resource subtype item
+                                        resource_subtype.getparent().remove(resource_subtype)
+                                    if "resourceSubType" in  self.disk_controller_info:
+                                        resource_subtype.text = self.disk_controller_info["resourceSubType"]
+
+                #Save output OVF
+            OVF_tree.write(self.output_path, xml_declaration=True,encoding='utf-8',
+               method="xml" )
+
+            if os.path.isfile(self.output_path):
+                logger.info("Successfully written output OVF at {}".format(self.output_path))
+                print("Output OVF is at :  {}".format(self.output_path))
+                return self.output_path
+            else:
+                error_msg = "ERROR: Error occurred while creating OVF file"
+                print(error_msg)
+                return False
+
+        except Exception as exp:
+            error_msg = "ERROR: Error occurred while editing OVF template : {}".format(exp)
+            self.logger.error(error_msg)
+            print(error_msg)
+            return False
+
+
+    def __convert_size(self,size):
+        """ 
+            Private method to convert disk size from GB,MB to bytes.
+            Args :
+                size  : disk size with prefix 'G' for GB and 'M' for MB
+            Return :  disk size in bytes
+        """
+        byte_size= 0
+        try:
+            if not size:
+                self.logger.error("No size {} to convert in bytes".format(size))
+            else:
+                size = str(size)
+                disk_size = float(size[:-1])
+                input_type = size[-1].strip()
+
+                self.logger.info("Disk size : {} , size type : {} ".format(disk_size,input_type))
+
+                if input_type == "G":
+                    byte_size = disk_size * 1024 * 1024 *1024
+                elif input_type == "M":
+                    byte_size = disk_size * 1024 * 1024
+
+                self.logger.info("Disk size in bytes: {} ".format(byte_size))
+
+            return int(byte_size)
+
+        except Exception as exp:
+            error_msg = "ERROR:Error occurred while converting disk size in bytes : {}".format(exp)
+            self.logger.error(error_msg)
+            print(error_msg)
+            return False
+
+    def __get_osType(self):
+        """ 
+            Private method to get OS ID and Type
+            Args :
+                None
+            Return :
+                osID : OS ID
+                osType: OS Type
+        """
+        osID = None
+        osType = None
+        os_info = self.__read_yaml_file(OS_INFO_FILE_PATH)
+        try:
+            if self.os_type and os_info:
+                for os_id , os_type in os_info.iteritems():
+                    if self.os_type.lower() == os_type.lower():
+                        osID = os_id
+                        osType = os_type
+                        break
+        except Exception as exp:
+            error_msg = "ERROR:Error occurred while getting OS details : {}".format(exp)
+            self.logger.error(error_msg)
+            print(error_msg)
+
+        return osID, osType
+
+
+    def __get_diskcontroller(self):
+        """ 
+            Private method to get details of Disk Controller
+            Args :
+                None
+            Return :
+                disk_controller : dict with details of Disk Controller
+        """
+        disk_controller = {}
+        scsi_subtype = None
+        if self.disk_controller.lower() in ["paravirtual", "lsilogic", "buslogic", "lsilogicsas"]:
+            scsi_subtype = self.disk_controller
+            self.disk_controller = "SCSI"
+
+        disk_controller_info = self.__read_yaml_file(DISK_CONTROLLER_INFO_FILE_PATH)
+        try:
+            if self.disk_controller and disk_controller_info:
+                for key , value in disk_controller_info.iteritems():
+                    if self.disk_controller.lower() in key.lower():
+                        disk_controller['controllerName'] = key
+                        disk_controller['resourceType'] = str(value["ResourceType"])
+                        resourceSubTypes = value["ResourceSubTypes"] if "ResourceSubTypes" in value else None
+                        if key == "SATA Controller":
+                            disk_controller["resourceSubType"] = resourceSubTypes[0]
+                        elif key == "SCSI Controller":
+                            if scsi_subtype:
+                                if scsi_subtype.lower() == "paravirtual":
+                                    scsi_subtype = "VirtualSCSI"
+                                for subtype in resourceSubTypes:
+                                    if scsi_subtype.lower() == subtype.lower():
+                                        disk_controller["resourceSubType"] = subtype
+                                        break
+                                else:
+                                    error_msg = "ERROR: Invalid inputs can not "\
+                                    "find SCSI subtype {}".format(scsi_subtype)
+                                    self.__raise_exception(error_msg)
+
+        except KeyError as exp:
+            error_msg = "ERROR:Error occurred while getting Disk Controller details : {}".format(exp)
+            self.logger.error(error_msg)
+            print(error_msg)
+
+        return disk_controller
+
+    def __read_yaml_file(self, file_path):
+        """ 
+            Private method to execute command
+            Args :
+                command  : command to execute
+            Return :
+                Dict of yaml data
+        """
+        with open(file_path) as data_file:    
+            data = yaml.load(data_file)
+        return data
+
+    def __raise_exception(self, error_msg , exception_type="Generic"):
+        """ 
+            Private method to execute command
+            Args :
+                command  : command to execute
+            Return :
+               None
+        """
+        if error_msg:
+            self.logger.debug(error_msg)
+            print(error_msg)
+            if exception_type == "Generic":
+                raise Exception(error_msg)
+            elif exception_type == "IO":
+                raise Exception(error_msg)
+
+    def __execute_command(self, command):
+        """ 
+            Private method to execute command
+            Args :
+                command  : command to execute
+            Return :
+                stdout : output of command
+                stderr: error occurred while executing command if any
+                returncode : return code of command execution
+        """
+        try:
+            self.logger.info("Execute command: {} ".format(command))
+
+            proc = subprocess.Popen(command , stdout = subprocess.PIPE, stdin = subprocess.PIPE,
+                                             stderr = subprocess.PIPE,shell=True)
+            stdout, stderr = proc.communicate()
+            returncode = proc.returncode
+
+        except Exception as exp:
+            self.logger.error("Error {} occurred while executing command {} ".format(exp,command))
+
+        return  stdout, stderr , returncode
+
+
+    def create_ovf(self):
+        """ 
+            Method to convert source image into OVF
+            Args : None
+            Return : True on success else False
+        """
+        #check output format
+        if self.source_format == self.output_format:
+            self.logger.info("Source format is OVF. No need to convert: {} ")
+            return self.source_img_path
+
+        #Get source img properties
+        img_info = self.__get_image_info()
+        if img_info:
+
+            #Create vmdk disk image
+            disk_img = self.__convert_image()
+            if disk_img:
+
+                #Edit OVF tempalte
+                ovf_path = self.__edit_ovf_template()
+                return ovf_path
+        else:
+            self.logger.error("Error in getting image information cannot convert image")
+            raise Exception("Error in getting image information cannot convert image")
+            return False
+
diff --git a/osm_ro/vmware_utils/OVF_converter/format_converter/ovf_converter_cli.py b/osm_ro/vmware_utils/OVF_converter/format_converter/ovf_converter_cli.py
new file mode 100644 (file)
index 0000000..209c05d
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2016-2017 VMware Inc.
+# This file is part of ETSI OSM
+# 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:  osslegalrouting@vmware.com
+##
+
+import argparse
+from converter import OVFConverter , get_version
+
+def execute_cli():
+
+    """
+        Method to parse CLI arguments and execute commands accordingly
+        Args : None
+        Return : None
+    """
+    parser = argparse.ArgumentParser(description='OVF converter to convert .qcow2 or raw image into OVF')
+
+    parser.add_argument("-v","--version", action="version", version=str(get_version()),
+                            help="shows version of OVF Converter tool")
+
+    parser.add_argument("path", action="store",
+                            help=" absolute path to source image which will get convert into ovf")
+
+    parser.add_argument("-o", "--output_location", action="store",
+                            help="location where created OVF will be kept. This location "\
+                                  "should have write access. If not given file will get "\
+                                  "created at source location  (optional)")
+
+    parser.add_argument("-n","--ovf_name", action="store",
+                            help="name of output ovf file. If not given source image name will "\
+                            " be used (optional)")
+
+    parser.add_argument("-m","--memory", action="store",
+                            help="required memory for VM in MB (default 1 GB)(optional)")
+
+    parser.add_argument("-c","--cpu", action="store",
+                            help="required number of virtual cpus for VM (default 1 cpu) (optional)")
+
+    parser.add_argument("-d","--disk", action="store",
+                            help="required size of disk for VM in GB "\
+                            "(default as in source disk img) (optional)")
+
+    parser.add_argument("-s","--osType", action="store",
+                            help="required operating system type as specified "\
+                            "in user document (default os type other 32 bit) (optional)")
+
+    parser.add_argument("-dc","--disk_Controller", action="store",
+                            help="required disk controller type "\
+                            " (default controller SCSI with lsilogicsas) "\
+                            "(SATA, IDE, Paravirtual, Buslogic, Lsilogic, Lsilogicsas) (optional)")
+
+    args = parser.parse_args()
+
+    if args.path:
+        con = OVFConverter(args.path,
+                           output_location=args.output_location,
+                           output_ovf_name=args.ovf_name,
+                           memory=args.memory,
+                           cpu=args.cpu,
+                           disk=args.disk,
+                           os_type=args.osType,
+                           disk_controller=args.disk_Controller,
+                           )
+
+        print("#### Start OVF conversion  ####")
+        con.create_ovf()
+        print("#### Completed OVF conversion  ####")
+
+
+if __name__ == "__main__":
+    execute_cli()
+
diff --git a/osm_ro/vmware_utils/OVF_converter/install.sh b/osm_ro/vmware_utils/OVF_converter/install.sh
new file mode 100755 (executable)
index 0000000..7b184c8
--- /dev/null
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+
+##
+# Copyright 2016-2017 VMware Inc.
+# This file is part of ETSI OSM
+# 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:  osslegalrouting@vmware.com
+##
+
+echo '
+ #################################################################
+ #####             Installing Require Packages             #####
+ #################################################################'
+
+# Paths to copy application files
+Install_dir="/usr/local/bin"
+App_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+App_CLI_path="${App_dir}/format_converter/ovf_converter_cli.py"
+Install_CLI_path="${Install_dir}/OVF_converter/format_converter/ovf_converter_cli.py"
+Logs_Folder="${Install_dir}/OVF_converter/logs"
+Log_Path="${Install_dir}/OVF_converter/logs/ovf_converter.log"
+
+#Function to install packages using apt-get
+function install_packages(){
+      [ -x /usr/bin/apt-get ] && apt-get install -y $*
+       
+       #check properly installed
+       for PACKAGE in $*
+       do
+           PACKAGE_INSTALLED="no"
+           [ -x /usr/bin/apt-get ] && dpkg -l $PACKAGE            &>> /dev/null && PACKAGE_INSTALLED="yes"
+           if [ "$PACKAGE_INSTALLED" = "no" ]
+           then
+               echo "failed to install package '$PACKAGE'. Revise network connectivity and try again" >&2
+               exit 1
+          fi
+       done
+   }
+  
+apt-get update  # To get the latest package lists
+install_packages "libxml2-dev libxslt-dev python-dev python-pip python-lxml python-yaml"
+install_packages "qemu-utils"
+
+#apt-get install <package name> -y
+
+#Move OVF Converter to usr/bin
+cp -R "${App_dir}"   "${Install_dir}"
+
+#Create logs folder and file
+mkdir "${Logs_Folder}"
+touch "${Log_Path}"
+
+#Change permission
+chmod -R 777 $Install_CLI_path
+chmod -R 777 $Log_Path
+
+touch "${Install_dir}/ovf_converter"
+echo  "#!/bin/sh" > "${Install_dir}/ovf_converter"
+echo  "python ${Install_CLI_path} \"\$@\"" >> "${Install_dir}/ovf_converter"
+chmod a+x "${Install_dir}/ovf_converter"
+
+echo ' 
+ #################################################################
+ #####             Done                                #####
+ #################################################################'
diff --git a/osm_ro/vmware_utils/OVF_converter/ovf_template/template.xml b/osm_ro/vmware_utils/OVF_converter/ovf_template/template.xml
new file mode 100644 (file)
index 0000000..5cbb328
--- /dev/null
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<Envelope xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <References>\r
+     <File ovf:href="disk_img_filename.vmdk" ovf:id="file1" />\r
+  </References>\r
+   <DiskSection>\r
+    <Info>Virtual disk information</Info>\r
+    <Disk ovf:capacity="1" ovf:capacityAllocationUnits="byte" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="0"/>\r
+  </DiskSection>\r
+  \r
+  <NetworkSection>\r
+       <Info>List of logical networks used in the package</Info> \r
+ </NetworkSection>\r
+       \r
+ <VirtualSystem ovf:id="vm">\r
+    <Info>A virtual machine</Info>\r
+    <Name>Virtual machine name</Name>\r
+    \r
+    <OperatingSystemSection ovf:id="1">\r
+      <Info>The kind of installed guest operating system</Info>\r
+      <Description>Other (32-bit)</Description>\r
+    </OperatingSystemSection>\r
+\r
+    <VirtualHardwareSection>\r
+      <Info>Virtual hardware requirements</Info>\r
+      <System>\r
+               <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\r
+               <vssd:InstanceID>0</vssd:InstanceID>\r
+               <vssd:VirtualSystemIdentifier>Test1</vssd:VirtualSystemIdentifier>\r
+               <vssd:VirtualSystemType>vmx-7</vssd:VirtualSystemType>\r
+         </System>\r
+           \r
+      <Item>\r
+        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\r
+        <rasd:Description>Number of Virtual CPUs</rasd:Description>\r
+        <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>\r
+        <rasd:InstanceID>1</rasd:InstanceID>\r
+        <rasd:ResourceType>3</rasd:ResourceType>\r
+        <rasd:VirtualQuantity>1</rasd:VirtualQuantity>\r
+      </Item>\r
+      <Item>\r
+        <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\r
+        <rasd:Description>Memory Size</rasd:Description>\r
+        <rasd:ElementName>1GB of memory</rasd:ElementName>\r
+        <rasd:InstanceID>2</rasd:InstanceID>\r
+        <rasd:ResourceType>4</rasd:ResourceType>\r
+        <rasd:VirtualQuantity>1024</rasd:VirtualQuantity>\r
+      </Item>\r
+      <Item>\r
+        <rasd:Address>0</rasd:Address>\r
+        <rasd:Description>SCSI Controller</rasd:Description>\r
+        <rasd:ElementName>scsiController0</rasd:ElementName>\r
+        <rasd:InstanceID>3</rasd:InstanceID>\r
+        <rasd:ResourceSubType>lsilogicsas</rasd:ResourceSubType>\r
+        <rasd:ResourceType>6</rasd:ResourceType>\r
+      </Item>\r
+      <Item>\r
+        <rasd:AddressOnParent>0</rasd:AddressOnParent>\r
+        <rasd:ElementName>disk0</rasd:ElementName>\r
+        <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>\r
+        <rasd:InstanceID>4</rasd:InstanceID>\r
+        <rasd:Parent>3</rasd:Parent>\r
+        <rasd:ResourceType>17</rasd:ResourceType>\r
+      </Item>\r
+      <Item ovf:required="false">\r
+        <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>\r
+        <rasd:ElementName>video</rasd:ElementName>\r
+        <rasd:InstanceID>5</rasd:InstanceID>\r
+        <rasd:ResourceType>24</rasd:ResourceType>\r
+      </Item>\r
+      <Item ovf:required="false">\r
+        <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>\r
+        <rasd:ElementName>vmci</rasd:ElementName>\r
+        <rasd:InstanceID>6</rasd:InstanceID>\r
+        <rasd:ResourceSubType>vmware.vmci</rasd:ResourceSubType>\r
+        <rasd:ResourceType>1</rasd:ResourceType>\r
+      </Item>\r
+      <vmw:Config ovf:required="false" vmw:key="cpuHotAddEnabled" vmw:value="true"/>\r
+      <vmw:Config ovf:required="false" vmw:key="powerOpInfo.powerOffType" vmw:value="soft"/>\r
+      <vmw:Config ovf:required="false" vmw:key="powerOpInfo.resetType" vmw:value="soft"/>\r
+      <vmw:Config ovf:required="false" vmw:key="powerOpInfo.suspendType" vmw:value="soft"/>\r
+      <vmw:Config ovf:required="false" vmw:key="tools.syncTimeWithHost" vmw:value="true"/>\r
+      <vmw:Config ovf:required="false" vmw:key="tools.toolsUpgradePolicy" vmw:value="upgradeAtPowerCycle"/>\r
+    </VirtualHardwareSection>\r
+               \r
+  </VirtualSystem>\r
+</Envelope>
\ No newline at end of file
diff --git a/osm_ro/vmware_utils/OVF_converter/readme.txt b/osm_ro/vmware_utils/OVF_converter/readme.txt
new file mode 100644 (file)
index 0000000..0e6117b
--- /dev/null
@@ -0,0 +1,181 @@
+##
+# Copyright 2016-2017 VMware Inc.
+# This file is part of ETSI OSM
+# 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:  osslegalrouting@vmware.com
+##
+
+This README file explains how to use OVF Converter Tool to generate OVF file from .qcow2, .img (raw) disk images.
+
+CONTENTS OF THIS FILE
+=====================
+This readme file contains the following sections:
+
+o Introduction
+o Tool Requirements
+o Installation
+o Usage
+o Trouble shooting
+o Release History
+
+
+Introduction
+==================
+OVF Converter Tool is a Command Line Interface (CLI) basically designed to generate OVF files from disk image such as .qcow2, and .img (raw format) which are other than .vmdk. 
+Given a path to .qcow2 image this tool can generate .vmdk and .ovf files.
+User can optionally specify name and location of ovf file. Also, one can use command line options to give disk size (GB), memory (MB), number of cpus, OS type, disk controller required for VM which will get deployed using generated OVF.
+Generated OVF file can be used to deploy VM in Vmware vSphere or vCloud Director.
+
+Note- Currently this tool supports only Ubuntu platform.
+
+
+Tool Requirements
+==================
+
+This tool requires the following software package:
+o      apt-get package manager
+o      qemu-utils
+o      python 2.7
+o      python-lxml
+o      libxml2-dev 
+o      libxslt-dev 
+o      python-dev 
+o      python-pip
+        
+Install.sh script in this folder will install all of these
+software packages.
+
+
+Installation
+==================
+User needs root privileges to install OVF Generator Tool.
+Follow below setups for installation of OVF Converter Tool.
+1. Make install.sh script in this folder executable by running below command
+   chmod a+x install.sh
+2. Run install.sh script as:
+   ./install.sh
+   
+   Sample output -
+               #################################################################
+               #####             Installing Require Packages             #####
+               #################################################################
+               Hit:1 http://us.archive.ubuntu.com/ubuntu xenial InRelease
+               Get:2 http://us.archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]
+               Get:3 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
+               Get:4 http://us.archive.ubuntu.com/ubuntu xenial-backports InRelease [102 kB]
+               Fetched 306 kB in 1s (286 kB/s)
+               Reading package lists... Done
+               Reading package lists... Done
+               Building dependency tree
+               Reading state information... Done
+               Note, selecting 'libxslt1-dev' instead of 'libxslt-dev'
+               libxslt1-dev is already the newest version (1.1.28-2.1).
+               python-dev is already the newest version (2.7.11-1).
+               python-lxml is already the newest version (3.5.0-1build1).
+               libxml2-dev is already the newest version (2.9.3+dfsg1-1ubuntu0.1).
+
+               t version (1:2.5+dfsg-5ubuntu10.6).
+               0 upgraded, 0 newly installed, 0 to remove and 72 not upgraded.
+
+               #################################################################
+               #####             Done                                #####
+               #################################################################
+               root@ubuntu:/home/vmware/OVF_converter#
+               root@ubuntu:/home/vmware/OVF_converter#
+     
+3. Now tool is installed at /usr/local/bin and available for all users
+4. User can access commands of OVF Generator Tool as:
+    ovf_converter path [output location] [ovf name][memory][cpu][disk][ostype][disk_controller]
+
+
+Usage
+===================
+o      Get version of tool as:
+
+       Command -      ovf_converter -v
+       Sample output -
+                               root@ubuntu:/home/vmware/OVF_converter# ovf_converter -v
+                               1.0 - Initial Realse
+                               root@ubuntu:/home/vmware/OVF_converter#
+
+o      See all command line options of tool as:
+       Command -       ovf_converter -h
+       Sample output -
+                               root@ubuntu:/home/vmware/OVF_converter#
+                               root@ubuntu:/home/vmware/OVF_converter# ovf_converter -h
+                               Usage: ovf_converter_cli.py [-h] [-v] [-o OUTPUT_LOCATION] [-n OVF_NAME]
+                            [-m MEMORY] [-c CPU] [-d DISK] [-s OSTYPE]
+                            [-dc DISK_CONTROLLER]
+                            path
+
+                               OVF converter to convert .qcow2 or raw image into OVF
+                               
+                               positional arguments:
+                                 path                  absolute path to source image which will get convert
+                                                       into ovf
+                               
+                               optional arguments:
+                                 -h, --help            show this help message and exit
+                                 -v, --version         shows version of OVF Converter tool
+                                 -o OUTPUT_LOCATION, --output_location OUTPUT_LOCATION
+                                                       location where created OVF will be kept. This location
+                                                       should have write access. If not given file will get
+                                                       created at source location (optional)
+                                 -n OVF_NAME, --ovf_name OVF_NAME
+                                                       name of output ovf file. If not given source image
+                                                       name will be used (optional)
+                                 -m MEMORY, --memory MEMORY
+                                                       required memory for VM in MB (default 1 GB)(optional)
+                                 -c CPU, --cpu CPU     required number of virtual cpus for VM (default 1 cpu)
+                                                       (optional)
+                                 -d DISK, --disk DISK  required size of disk for VM in GB (default as
+                                                       in source disk img) (optional)
+                                 -s OSTYPE, --osType OSTYPE
+                                                       required operating system type as specified in user
+                                                       document (default os type other 32 bit) (optional)
+                                 -dc DISK_CONTROLLER, --disk_Controller DISK_CONTROLLER
+                                                       required disk controller type (default controller SCSI
+                                                       with lsilogicsas) (SATA, IDE, Paravirtual, Buslogic,
+                                                       lsilogic, lsilogicsas) (optional)
+
+                                 
+o      Create OVF file from qcow2 or raw disk image as:
+       Command -     ovf_converter /home/vmware/centos_ovf/CentOS-7-x86_64-GenericCloud-1503.qcow2 -n centos_qcow2.ovf -m 2048 -c 4 -d 10 -s "Centos 32-bit" -dc "SATA"
+       Sample output -
+                               root@ubuntu:/home/vmware/OVF_converter# ovf_converter /home/vmware/centos_ovf/CentOS-7-x86_64-GenericCloud-1503.qcow2 -n centos_qcow2.ovf -m 2048 -c 4 -d 10
+                               #### Start OVF conversion ####
+                               Getting source image information
+                               Converting source disk image to .vmdk                                                                         
+                               .....................................................
+                               Creating OVF
+                               Output OVF is at:  /home/vmware/centos_ovf/centos_qcow2.ovf
+                               #### Completed OVF conversion ####
+
+
+Trouble shooting
+==================
+After installation of tool logs will get created at /usr/local/bin/OVF_converter/logs/ovf_converter.log file.
+User can use these logs for debugging or trouble shooting.
+
+
+Release History
+===============
+
+Version 1.0
+-------------
+
+Initial release  
index a909dd1..6476618 100755 (executable)
@@ -36,11 +36,15 @@ function usage(){
 }
 
 function uninstall(){
-    echo "systemctl disable openmano.service " &&  systemctl disable openmano.service 2>/dev/null || echo "  Already done"
-    echo "systemctl disable osm-ro.service " &&  systemctl disable osm-ro.service 2>/dev/null || echo "  Already done"
+    echo "systemctl disable openmano.service " &&  systemctl disable openmano.service 2>/dev/null ||
+        echo "  Already done"
+    echo "systemctl disable osm-ro.service " &&  systemctl disable osm-ro.service 2>/dev/null ||
+        echo "  Already done"
     echo "service openmano stop " && service openmano stop 2>/dev/null || echo "  Already done"
     echo "service osm-ro stop " && service osm-ro stop 2>/dev/null || echo "  Already done"
-    for file in /opt/openmano /etc/default/openmanod.cfg /etc/osm/openmanod.cfg /var/log/openmano /var/log/osm/openmano* /etc/systemd/system/openmano.service /etc/systemd/system/osm-ro.service /usr/bin/openmano /usr/sbin/service-openmano /usr/bin/openmano-report
+    for file in /opt/openmano /etc/default/openmanod.cfg /etc/osm/openmanod.cfg /var/log/openmano /var/log/osm/openmano* \
+        /etc/systemd/system/openmano.service /etc/systemd/system/osm-ro.service /usr/bin/openmano /usr/sbin/service-openmano \
+        /usr/bin/openmano-report
     do
         echo rm $file
         rm -rf $file || ! echo "Can not delete '$file'. Needed root privileges?" >&2 || exit 1
@@ -131,7 +135,8 @@ uninstall
 #copy files
 cp -r "$FILE" /opt/openmano         || ! echo $BAD_PATH_ERROR >&2 || exit 1
 mkdir -p /etc/osm  || echo "warning cannot create config folder '/etc/osm'"
-cp /opt/openmano/osm_ro/openmanod.cfg /etc/osm/openmanod.cfg  || echo "warning cannot create file '/etc/osm/openmanod.cfg'"
+cp /opt/openmano/osm_ro/openmanod.cfg /etc/osm/openmanod.cfg  ||
+    echo "warning cannot create file '/etc/osm/openmanod.cfg'"
 mkdir -p /var/log/osm  || echo "warning cannot create log folder '/var/log/osm'"
 #makes links
 ln -s -v /opt/openmano/openmano /usr/bin/openmano
@@ -154,7 +159,7 @@ Restart=always
 WantedBy=multi-user.target
 EOF
 
-[[ -n $DELETE ]] && rm -rf ${FILE}
+[[ -n $DELETE ]] && rm -rf "${FILE}"
 
 service osm-ro start
 systemctl enable osm-ro.service
index 5cf538c..0110d75 100755 (executable)
@@ -156,8 +156,8 @@ fi
 if [ "$_DISTRO" == "Ubuntu" ]
 then
     _RELEASE=$(lsb_release -rs)
-    if [[ ${_RELEASE%%.*} != 14 ]] && [[ ${_RELEASE%%.*} != 16 ]] 
-    then 
+    if [[ ${_RELEASE%%.*} != 14 ]] && [[ ${_RELEASE%%.*} != 16 ]]
+    then
         [[ -z $QUIET_MODE ]] &&
             ! ask_user "WARNING! Not tested Ubuntu version. Continue assuming a trusty (14.XX)' (y/N)? " n &&
             echo "Cancelled" && exit 1
@@ -197,14 +197,14 @@ INSTALL_AS_A_SERVICE=""
 # Next operations require knowing BASEFOLDER
 if [[ -z "$NOCLONE" ]]; then
     if [[ -n "$INSTALL_AS_A_SERVICE" ]] ; then
-        OPENMANO_BASEFOLDER=__openmano__${RANDOM}
+        BASEFOLDER=__openmano__${RANDOM}
     else
-        OPENMANO_BASEFOLDER="${PWD}/openmano"
+        BASEFOLDER="${PWD}/openmano"
     fi
-    [[ -n "$FORCE" ]] && rm -rf $OPENMANO_BASEFOLDER #make idempotent
+    [[ -n "$FORCE" ]] && rm -rf $BASEFOLDER #make idempotent
 else
-    HERE=$(realpath $(dirname $0))
-    OPENMANO_BASEFOLDER=$(dirname $HERE)
+    HERE=$(dirname $(readlink -f ${BASH_SOURCE[0]}))
+    BASEFOLDER=$(dirname $HERE)
 fi
 
 if [[ -z "$NO_PACKAGES" ]]
@@ -258,34 +258,34 @@ if [[ -z $NOCLONE ]]; then
         "#################################################################\n"\
         "#####        DOWNLOAD SOURCE                                #####\n"\
         "#################################################################"
-    if [[ -d "${OPENMANO_BASEFOLDER}" ]] ; then
+    if [[ -d "${BASEFOLDER}" ]] ; then
         if [[ -n "$FORCE" ]] ; then
-            echo "deleting '${OPENMANO_BASEFOLDER}' folder"
-            rm -rf "$OPENMANO_BASEFOLDER" #make idempotent
+            echo "deleting '${BASEFOLDER}' folder"
+            rm -rf "$BASEFOLDER" #make idempotent
         elif [[ -z "$QUIET_MODE" ]] ; then
-            ! ask_user "folder '${OPENMANO_BASEFOLDER}' exists, overwrite (y/N)? " n && echo "Cancelled!" && exit 1
-            rm -rf "$OPENMANO_BASEFOLDER"
+            ! ask_user "folder '${BASEFOLDER}' exists, overwrite (y/N)? " n && echo "Cancelled!" && exit 1
+            rm -rf "$BASEFOLDER"
         else
-            echo "'${OPENMANO_BASEFOLDER}' folder exists. Use "--force" to overwrite" >&2 && exit 1
+            echo "'${BASEFOLDER}' folder exists. Use "--force" to overwrite" >&2 && exit 1
         fi
     fi
-    su $SUDO_USER -c "git clone ${GIT_URL} ${OPENMANO_BASEFOLDER}"
-    su $SUDO_USER -c "cp ${OPENMANO_BASEFOLDER}/.gitignore-common ${OPENMANO_BASEFOLDER}/.gitignore"
-    [[ -z $DEVELOP ]] && su $SUDO_USER -c "git -C ${OPENMANO_BASEFOLDER} checkout v2.0"
+    su $SUDO_USER -c "git clone ${GIT_URL} ${BASEFOLDER}"
+    su $SUDO_USER -c "cp ${BASEFOLDER}/.gitignore-common ${BASEFOLDER}/.gitignore"
+    [[ -z $DEVELOP ]] && su $SUDO_USER -c "git -C ${BASEFOLDER} checkout v2.0"
 fi
 
 echo -e "\n"\
     "#################################################################\n"\
     "#####        INSTALLING OVIM LIBRARY                        #####\n"\
     "#################################################################"
-su $SUDO_USER -c "git -C ${OPENMANO_BASEFOLDER} clone ${GIT_OVIM_URL} openvim"
-[[ -z $DEVELOP ]] && su $SUDO_USER -c "git -C ${OPENMANO_BASEFOLDER}/openvim checkout v2.0"
+su $SUDO_USER -c "git -C ${BASEFOLDER} clone ${GIT_OVIM_URL} openvim"
+[[ -z $DEVELOP ]] && su $SUDO_USER -c "git -C ${BASEFOLDER}/openvim checkout v2.0"
 
 # Install debian dependencies before setup.py
 [ "$_DISTRO" == "Ubuntu" ] && install_packages "libmysqlclient-dev"
 [ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ] && install_packages "libmysqlclient-dev"  #TODO check if that's the name in CentOS and RedHat
-make -C ${OPENMANO_BASEFOLDER}/openvim lite
-rm -rf "${OPENMANO_BASEFOLDER}/openvim"
+make -C ${BASEFOLDER}/openvim lite
+rm -rf "${BASEFOLDER}/openvim"
 OSMLIBOVIM_PATH=`python -c 'import lib_osm_openvim; print lib_osm_openvim.__path__[0]'`
 
 if [ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ]
@@ -318,8 +318,8 @@ then
 fi
 
 echo -e "\n"\
-    "#################################################################n"\
-    "#####        CONFIGURE OPENMANO CLIENT                      #####n"\
+    "#################################################################\n"\
+    "#####        CONFIGURE OPENMANO CLIENT                      #####\n"\
     "#################################################################"
 #creates a link at ~/bin if not configured as a service
 if [[ -z "$INSTALL_AS_A_SERVICE" ]]
@@ -328,9 +328,9 @@ then
     su $SUDO_USER -c 'rm -f ${HOME}/bin/openmano'
     su $SUDO_USER -c 'rm -f ${HOME}/bin/openmano-report'
     su $SUDO_USER -c 'rm -f ${HOME}/bin/service-openmano'
-    su $SUDO_USER -c "ln -s '${OPENMANO_BASEFOLDER}/openmano' "'${HOME}/bin/openmano'
-    su $SUDO_USER -c "ln -s '${OPENMANO_BASEFOLDER}/scripts/openmano-report.sh'   "'${HOME}/bin/openmano-report'
-    su $SUDO_USER -c "ln -s '${OPENMANO_BASEFOLDER}/scripts/service-openmano'  "'${HOME}/bin/service-openmano'
+    su $SUDO_USER -c "ln -s '${BASEFOLDER}/openmano' "'${HOME}/bin/openmano'
+    su $SUDO_USER -c "ln -s '${BASEFOLDER}/scripts/openmano-report.sh'   "'${HOME}/bin/openmano-report'
+    su $SUDO_USER -c "ln -s '${BASEFOLDER}/scripts/service-openmano'  "'${HOME}/bin/service-openmano'
 
     #insert /home/<user>/bin in the PATH
     #skiped because normally this is done authomatically when ~/bin exists
@@ -339,13 +339,14 @@ then
     #    echo "    inserting /home/$SUDO_USER/bin in the PATH at .bashrc"
     #    su $SUDO_USER -c 'echo "PATH=\$PATH:\${HOME}/bin" >> ~/.bashrc'
     #fi
-    if [[ $SUDO_USER == root ]] 
+    
+    if [[ $SUDO_USER == root ]]
     then
         if ! echo $PATH | grep -q "${HOME}/bin"
         then
             echo "PATH=\$PATH:\${HOME}/bin" >> ${HOME}/.bashrc
         fi
-    fi 
+    fi
 fi
 
 #configure arg-autocomplete for this user
@@ -361,17 +362,17 @@ fi
 
 if [ -z "$NO_DB" ]; then
     echo -e "\n"\
-        "#################################################################"\n"\
-        "#####               INSTALL DATABASE SERVER                 #####"\n"\
+        "#################################################################\n"\
+        "#####               INSTALL DATABASE SERVER                 #####\n"\
         "#################################################################"
 
     if [ -n "$QUIET_MODE" ]; then
         DB_QUIET='-q'
     fi
-    ${OPENMANO_BASEFOLDER}/database_utils/install-db-server.sh -U $DBUSER ${DBPASSWD_PARAM/p/P} $DB_QUIET $DB_FORCE_UPDATE || exit 1
+    ${BASEFOLDER}/database_utils/install-db-server.sh -U $DBUSER ${DBPASSWD_PARAM/p/P} $DB_QUIET $DB_FORCE_UPDATE || exit 1
     echo -e "\n"\
-        "#################################################################"\n"\
-        "#####        CREATE AND INIT MANO_VIM DATABASE              #####"\n"\
+        "#################################################################\n"\
+        "#####        CREATE AND INIT MANO_VIM DATABASE              #####\n"\
         "#################################################################"
     # Install mano_vim_db after setup
     ${OSMLIBOVIM_PATH}/database_utils/install-db-server.sh -U $DBUSER ${DBPASSWD_PARAM/p/P} -u mano -p manopw -d mano_vim_db --no-install-packages $DB_QUIET $DB_FORCE_UPDATE || exit 1
@@ -380,12 +381,12 @@ fi   # [ -z "$NO_DB" ]
 if [[ -n "$INSTALL_AS_A_SERVICE"  ]]
 then
     echo -e "\n"\
-        "#################################################################"\n"\
-        "#####        CONFIGURE OPENMANO SERVICE                     #####"\n"\
+        "#################################################################\n"\
+        "#####        CONFIGURE OPENMANO SERVICE                     #####\n"\
         "#################################################################"
 
-    ${OPENMANO_BASEFOLDER}/scripts/install-openmano-service.sh -f ${OPENMANO_BASEFOLDER} `[[ -z "$NOCLONE" ]] && echo "-d"`
-    # rm -rf ${OPENMANO_BASEFOLDER}
+    ${BASEFOLDER}/scripts/install-openmano-service.sh -f ${BASEFOLDER} `[[ -z "$NOCLONE" ]] && echo "-d"`
+    # rm -rf ${BASEFOLDER}
     # alias service-openmano="service openmano"
     # echo 'alias service-openmano="service openmano"' >> ${HOME}/.bashrc
     echo
@@ -394,5 +395,5 @@ then
 else
     echo
     echo "Done!  you may need to logout and login again for loading client configuration"
-    echo " Run './${OPENMANO_BASEFOLDER}/scripts/service-openmano start' for starting openmano in a screen"
+    echo " Run './${BASEFOLDER}/scripts/service-openmano start' for starting openmano in a screen"
 fi
index 8de7993..c38b2e5 100644 (file)
@@ -31,4 +31,5 @@ scenario:
       external:  true
       interfaces: 
       - linux1:  control0       # Node and its interface
+      - linux1:  control1       # Node and its interface
 
index 2308377..e38b208 100755 (executable)
@@ -29,19 +29,21 @@ function usage(){
     echo -e "usage: ${BASH_SOURCE[0]} [OPTIONS] <action>\n  test openmano using openvim as a VIM"
     echo -e "           the OPENVIM_HOST, OPENVIM_PORT shell variables indicate openvim location"
     echo -e "           by default localhost:9080"
-    echo -e "  <action> is a list of the following items (by default 'reset create delete')"
-    echo -e "    reset     reset the openmano database content"
-    echo -e "    create    creates items"
-    echo -e "    delete    delete created items"
+    echo -e "  <action> is a list of the following items (by default 'reset add-openvim create delete del-openvim')"
+    echo -e "    reset       resets the openmano database content and creates osm tenant"
+    echo -e "    add-openvim adds and attaches a local openvim datacenter"
+    echo -e "    del-openvim detaches and deletes the local openvim datacenter"
+    echo -e "    create      creates VNFs, scenarios and instances"
+    echo -e "    delete      deletes the created instances, scenarios and VNFs"
     echo -e "  OPTIONS:"
     echo -e "    -f --force       does not prompt for confirmation"
     echo -e "    -h --help        shows this help"
     echo -e "    --screen         forces to run openmano (and openvim) service in a screen"
     echo -e "    --insert-bashrc  insert the created tenant,datacenter variables at"
     echo -e "                     ~/.bashrc to be available by openmano CLI"
-    echo -e "    --install-openvim   install openvim in test mode"
-    echo -e "    --init-openvim   if openvim runs locally, an init is called to clean openvim"
-    echo -e "                      database and add fake hosts"
+    echo -e "    --install-openvim   installs openvim in test mode"
+    echo -e "    --init-openvim --initopenvim    if openvim runs locally, initopenvim is called to clean openvim"\
+            "database, create osm tenant and add fake hosts"
 }
 
 function is_valid_uuid(){
@@ -54,11 +56,19 @@ DIRNAME=$(dirname $(readlink -f ${BASH_SOURCE[0]}))
 DIRmano=$(dirname $DIRNAME)
 DIRscript=${DIRmano}/scripts
 
+#detect paths of executables, preceding the relative paths
+openmano=openmano && [[ -x "${DIRmano}/openmano" ]] && openmano="${DIRmano}/openmano"
+service_openmano=service-openmano && [[ -x "$DIRscript/service-openmano" ]] &&
+    service_openmano="$DIRscript/service-openmano"
+initopenvim="initopenvim"
+openvim="openvim"
+
 [[ ${BASH_SOURCE[0]} != $0 ]] && _exit="return" || _exit="exit"
 
 
 #process options
-source ${DIRscript}/get-options.sh "force:f help:h insert-bashrc init-openvim install-openvim screen" $* || $_exit 1
+source ${DIRscript}/get-options.sh "force:f help:h insert-bashrc init-openvim:initopenvim install-openvim screen" \
+                $* || $_exit 1
 
 #help
 [ -n "$option_help" ] && usage && $_exit 0
@@ -73,7 +83,8 @@ action_list=""
 
 for argument in $params
 do
-    if [[ $argument == reset ]] || [[ $argument == create ]] || [[ $argument == delete ]] || [[ -z "$argument" ]]
+    if [[ $argument == reset ]] || [[ $argument == create ]] || [[ $argument == delete ]] ||
+       [[ $argument == add-openvim ]] || [[ $argument == del-openvim ]] || [[ -z "$argument" ]]
     then
         action_list="$action_list $argument"
         continue
@@ -88,24 +99,34 @@ export OPENMANO_PORT=9090
 
 
 #by default action should be reset and create
-[[ -z $action_list ]]  && action_list="reset create delete"
+[[ -z $action_list ]]  && action_list="reset add-openvim create delete del-openvim"
 
 if [[ -n "$option_install_openvim" ]] 
 then
+    echo
+    echo "action: install openvim"
+    echo "################################"
     mkdir -p ${DIRNAME}/local
     pushd ${DIRNAME}/local
     echo "installing openvim at  ${DIRNAME}/openvim ... "
     wget -O install-openvim.sh "https://osm.etsi.org/gitweb/?p=osm/openvim.git;a=blob_plain;f=scripts/install-openvim.sh"
     chmod +x install-openvim.sh
     sudo ./install-openvim.sh --no-install-packages --force --quiet --develop
-    export alias initopenvim="${PWD}/openvim/scripts/initopenvim.sh"
-    export alias openvim="${PWD}/openvim/scripts/openvim"
-    option_init_openvim=""
-    ${DIRNAME}/local/openvim/scripts/initopenvim.sh${force_param}${insert_bashrc_param}${screen_vim_param} || echo "WARNING openvim cannot be initialized. The rest of test can fail!"
-
+    openvim="${DIRNAME}/local/openvim/openvim"
+    #force inito-penvim
+    option_init_openvim="-"
+    initopenvim="${DIRNAME}/local/openvim/scripts/initopenvim"
     popd
 fi
-[[ -z "$option_init_openvim" ]] || initopenvim${force_param}${insert_bashrc_param}${screen_vim_param} || echo "WARNING openvim cannot be initialized. The rest of test can fail!"
+
+if [[ -n "$option_init_openvim" ]]
+then
+    echo
+    echo "action: init openvim"
+    echo "################################"
+    ${initopenvim} ${force_param}${insert_bashrc_param}${screen_vim_param} || \
+        echo "WARNING openvim cannot be initialized. The rest of test can fail!"
+fi
 
 #check openvim client variables are set
 #fail=""
@@ -116,6 +137,9 @@ fi
 
 for action in $action_list
 do
+    echo
+    echo "action: $action"
+    echo "################################"
 #if [[ $action == "install-openvim" ]]
     #echo "Installing and starting openvim"
     #mkdir -p temp
@@ -133,84 +157,88 @@ then
     [[ $force_ != y ]] && [[ $force_ != yes ]] && echo "aborted!" && $_exit
 
     echo "Stopping openmano"
-    $DIRscript/service-openmano mano stop${screen_mano_param}
+    $service_openmano mano stop${screen_mano_param}
     echo "Initializing openmano database"
-    $DIRmano/database_utils/init_mano_db.sh -u mano -p manopw --createdb
+    $DIRmano/database_utils/init_mano_db.sh -u mano -p manopw
     echo "Starting openmano"
-    $DIRscript/service-openmano mano start${screen_mano_param}
+    $service_openmano mano start${screen_mano_param}
     echo
+    printf "%-50s" "Creating openmano tenant 'osm': "
+    result=`$openmano tenant-create osm --description="created by basictest.sh"`
+    nfvotenant=`echo $result |gawk '{print $1}'`
+    #check a valid uuid is obtained
+    ! is_valid_uuid $nfvotenant && echo "FAIL" && echo "    $result" && $_exit 1
+    export OPENMANO_TENANT=osm
+    [[ -n "$option_insert_bashrc" ]] && echo -e "\nexport OPENMANO_TENANT=osm"  >> ~/.bashrc
+    echo $nfvotenant
 
 elif [[ $action == "delete" ]]
 then
-    result=`openmano tenant-list TEST-tenant`
+    result=`openmano tenant-list osm`
     nfvotenant=`echo $result |gawk '{print $1}'`
     #check a valid uuid is obtained
-    is_valid_uuid $nfvotenant || ! echo "Tenant TEST-tenant not found. Already delete?" >&2 || $_exit 1
+    is_valid_uuid $nfvotenant || ! echo "Tenant osm not found. Already delete?" >&2 || $_exit 1
     export OPENMANO_TENANT=$nfvotenant
-    ${DIRmano}/openmano instance-scenario-delete -f simple-instance     || echo "fail"
-    ${DIRmano}/openmano instance-scenario-delete -f complex-instance    || echo "fail"
-    ${DIRmano}/openmano instance-scenario-delete -f complex2-instance   || echo "fail"
-    ${DIRmano}/openmano instance-scenario-delete -f complex3-instance   || echo "fail"
-    ${DIRmano}/openmano instance-scenario-delete -f complex4-instance   || echo "fail"
-    ${DIRmano}/openmano instance-scenario-delete -f complex5-instance   || echo "fail"
-    ${DIRmano}/openmano scenario-delete -f simple           || echo "fail"
-    ${DIRmano}/openmano scenario-delete -f complex          || echo "fail"
-    ${DIRmano}/openmano scenario-delete -f complex2         || echo "fail"
-    ${DIRmano}/openmano scenario-delete -f complex3         || echo "fail"
-    ${DIRmano}/openmano scenario-delete -f complex4         || echo "fail"
-    ${DIRmano}/openmano scenario-delete -f complex5         || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f linux                 || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f linux_2VMs_v02        || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f dataplaneVNF_2VMs     || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f dataplaneVNF_2VMs_v02 || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f dataplaneVNF4 || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f dataplaneVNF2         || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f dataplaneVNF3         || echo "fail"
-    ${DIRmano}/openmano datacenter-detach TEST-dc           || echo "fail"
-    ${DIRmano}/openmano datacenter-delete -f TEST-dc        || echo "fail"
-    ${DIRmano}/openmano tenant-delete -f TEST-tenant        || echo "fail"
-    echo
+    $openmano instance-scenario-delete -f simple-instance     || echo "fail"
+    $openmano instance-scenario-delete -f complex-instance    || echo "fail"
+    $openmano instance-scenario-delete -f complex2-instance   || echo "fail"
+    $openmano instance-scenario-delete -f complex3-instance   || echo "fail"
+    $openmano instance-scenario-delete -f complex4-instance   || echo "fail"
+    $openmano instance-scenario-delete -f complex5-instance   || echo "fail"
+    $openmano scenario-delete -f simple           || echo "fail"
+    $openmano scenario-delete -f complex          || echo "fail"
+    $openmano scenario-delete -f complex2         || echo "fail"
+    $openmano scenario-delete -f complex3         || echo "fail"
+    $openmano scenario-delete -f complex4         || echo "fail"
+    $openmano scenario-delete -f complex5         || echo "fail"
+    $openmano vnf-delete -f linux                 || echo "fail"
+    $openmano vnf-delete -f linux_2VMs_v02        || echo "fail"
+    $openmano vnf-delete -f dataplaneVNF_2VMs     || echo "fail"
+    $openmano vnf-delete -f dataplaneVNF_2VMs_v02 || echo "fail"
+    $openmano vnf-delete -f dataplaneVNF4         || echo "fail"
+    $openmano vnf-delete -f dataplaneVNF2         || echo "fail"
+    $openmano vnf-delete -f dataplaneVNF3         || echo "fail"
+
+elif [[ $action == "del-openvim" ]]
+then
+    $openmano datacenter-detach local-openvim           || echo "fail"
+    $openmano datacenter-delete -f local-openvim        || echo "fail"
 
-elif [[ $action == "create" ]]
+elif [[ $action == "add-openvim" ]]
 then
-    printf "%-50s" "Creating openmano tenant 'TEST-tenant': "
-    result=`${DIRmano}/openmano tenant-create TEST-tenant --description="created by basictest.sh"`
-    nfvotenant=`echo $result |gawk '{print $1}'`
-    #check a valid uuid is obtained
-    ! is_valid_uuid $nfvotenant && echo "FAIL" && echo "    $result" && $_exit 1
-    export OPENMANO_TENANT=$nfvotenant
-    [[ -n "$option_insert_bashrc" ]] && echo -e "\nexport OPENMANO_TENANT=$nfvotenant"  >> ~/.bashrc
-    echo $nfvotenant
 
-    printf "%-50s" "Creating datacenter 'TEST-dc' in openmano:"
+    printf "%-50s" "Creating datacenter 'local-openvim' at openmano:"
     [[ -z $OPENVIM_HOST ]] && OPENVIM_HOST=localhost
     [[ -z $OPENVIM_PORT ]] && OPENVIM_PORT=9080
     URL_ADMIN_PARAM=""
     [[ -n $OPENVIM_ADMIN_PORT ]] && URL_ADMIN_PARAM=" --url_admin=http://${OPENVIM_HOST}:${OPENVIM_ADMIN_PORT}/openvim"
-    result=`${DIRmano}/openmano datacenter-create TEST-dc "http://${OPENVIM_HOST}:${OPENVIM_PORT}/openvim" --type=openvim${URL_ADMIN_PARAM} --config="{test: no use just for test}"`
+    result=`$openmano datacenter-create local-openvim "http://${OPENVIM_HOST}:${OPENVIM_PORT}/openvim" \
+            --type=openvim${URL_ADMIN_PARAM} --config="{test: no use just for test}"`
     datacenter=`echo $result |gawk '{print $1}'`
     #check a valid uuid is obtained
     ! is_valid_uuid $datacenter && echo "FAIL" && echo "    $result" && $_exit 1
     echo $datacenter
-    export OPENMANO_DATACENTER=$datacenter
-    [[ -n "$option_insert_bashrc" ]] && echo -e "\nexport OPENMANO_DATACENTER=$datacenter"  >> ~/.bashrc
+    export OPENMANO_DATACENTER=local-openvim
+    [[ -n "$option_insert_bashrc" ]] && echo -e "\nexport OPENMANO_DATACENTER=local-openvim"  >> ~/.bashrc
 
     printf "%-50s" "Attaching openmano tenant to the datacenter:"
-    result=`${DIRmano}/openmano datacenter-attach TEST-dc --config="{test: no use just for test}"`
+    result=`$openmano datacenter-attach local-openvim --vim-tenant-name=osm --config="{test: no use just for test}"`
     [[ $? != 0 ]] && echo  "FAIL" && echo "    $result" && $_exit 1
     echo OK
 
     printf "%-50s" "Updating external nets in openmano: "
-    result=`${DIRmano}/openmano datacenter-netmap-delete -f --all`
+    result=`$openmano datacenter-netmap-delete -f --all`
     [[ $? != 0 ]] && echo  "FAIL" && echo "    $result"  && $_exit 1
-    result=`${DIRmano}/openmano datacenter-netmap-import -f`
+    result=`$openmano datacenter-netmap-import -f`
     [[ $? != 0 ]] && echo  "FAIL" && echo "    $result"  && $_exit 1
     echo OK
 
+elif [[ $action == "create" ]]
+then
     for VNF in linux dataplaneVNF1 dataplaneVNF2 dataplaneVNF_2VMs dataplaneVNF_2VMs_v02 dataplaneVNF3 linux_2VMs_v02 dataplaneVNF4
     do    
         printf "%-50s" "Creating VNF '${VNF}': "
-        result=`$DIRmano/openmano vnf-create $DIRmano/vnfs/examples/${VNF}.yaml`
+        result=`$openmano vnf-create $DIRmano/vnfs/examples/${VNF}.yaml`
         vnf=`echo $result |gawk '{print $1}'`
         #check a valid uuid is obtained
         ! is_valid_uuid $vnf && echo FAIL && echo "    $result" &&  $_exit 1
@@ -219,7 +247,7 @@ then
     for NS in simple complex complex2 complex3 complex4 complex5
     do
         printf "%-50s" "Creating scenario '${NS}':"
-        result=`$DIRmano/openmano scenario-create $DIRmano/scenarios/examples/${NS}.yaml`
+        result=`$openmano scenario-create $DIRmano/scenarios/examples/${NS}.yaml`
         scenario=`echo $result |gawk '{print $1}'`
         ! is_valid_uuid $scenario && echo FAIL && echo "    $result" &&  $_exit 1
         echo $scenario
@@ -228,14 +256,14 @@ then
     for IS in simple complex complex2 complex3 complex5
     do
         printf "%-50s" "Creating instance-scenario '${IS}':"
-        result=`$DIRmano/openmano instance-scenario-create  --scenario ${IS} --name ${IS}-instance`
+        result=`$openmano instance-scenario-create  --scenario ${IS} --name ${IS}-instance`
         instance=`echo $result |gawk '{print $1}'`
         ! is_valid_uuid $instance && echo FAIL && echo "    $result" &&  $_exit 1
         echo $instance
     done
 
     printf "%-50s" "Creating instance-scenario 'complex4':"
-    result=`$DIRmano/openmano instance-scenario-create $DIRmano/instance-scenarios/examples/instance-creation-complex4.yaml`
+    result=`$openmano instance-scenario-create $DIRmano/instance-scenarios/examples/instance-creation-complex4.yaml`
     instance=`echo $result |gawk '{print $1}'`
     ! is_valid_uuid $instance && echo FAIL && echo "    $result" &&  $_exit 1
     echo $instance
index f5194ac..26a7c94 100755 (executable)
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 
 ##
-# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# Copyright 2017
 # This file is part of openmano
 # All Rights Reserved.
 #
 # 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
 ##
 
 '''
 Module for testing openmano functionality. It uses openmanoclient.py for invoking openmano
 '''
-__author__="Pablo Montes"
+__author__="Pablo Montes, Alfonso Tierno"
 __date__ ="$16-Feb-2017 17:08:16$"
-__version__="0.0.1"
-version_date="Feb 2017"
+__version__="0.0.3"
+version_date="May 2017"
 
 import logging
-import imp
 import os
-from optparse import OptionParser
+from argparse import ArgumentParser
+import argcomplete
 import unittest
 import string
 import inspect
@@ -44,15 +42,12 @@ import yaml
 import sys
 import time
 
-global test_number
-global test_directory
-global scenario_test_folder
-global test_image_name
-global management_network
-global manual
+global test_config   #  used for global variables with the test configuration
+test_config = {}
+
 
 def check_instance_scenario_active(uuid):
-    instance = client.get_instance(uuid=uuid)
+    instance = test_config["client"].get_instance(uuid=uuid)
 
     for net in instance['nets']:
         status = net['status']
@@ -67,22 +62,23 @@ def check_instance_scenario_active(uuid):
 
     return (True, None)
 
+
 '''
 IMPORTANT NOTE
 All unittest classes for code based tests must have prefix 'test_' in order to be taken into account for tests
 '''
-class test_tenant_operations(unittest.TestCase):
+class test_VIM_datacenter_tenant_operations(unittest.TestCase):
     test_index = 1
     tenant_name = None
     test_text = None
 
     @classmethod
     def setUpClass(cls):
-        logger.info("{}. {}".format(test_number, cls.__name__))
+        logger.info("{}. {}".format(test_config["test_number"], cls.__name__))
 
     @classmethod
     def tearDownClass(cls):
-        globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+        test_config["test_number"] += 1
 
     def tearDown(self):
         exec_info = sys.exc_info()
@@ -98,41 +94,43 @@ class test_tenant_operations(unittest.TestCase):
 
     def test_000_create_RO_tenant(self):
         self.__class__.tenant_name = _get_random_string(20)
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
-        tenant = client.create_tenant(name=self.__class__.tenant_name, description=self.__class__.tenant_name)
+        tenant = test_config["client"].create_tenant(name=self.__class__.tenant_name,
+                                                     description=self.__class__.tenant_name)
         logger.debug("{}".format(tenant))
         self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.tenant_name)
 
     def test_010_list_RO_tenant(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
-        tenant = client.get_tenant(name=self.__class__.tenant_name)
+        tenant = test_config["client"].get_tenant(name=self.__class__.tenant_name)
         logger.debug("{}".format(tenant))
         self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.tenant_name)
 
     def test_020_delete_RO_tenant(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
-        tenant = client.delete_tenant(name=self.__class__.tenant_name)
+        tenant = test_config["client"].delete_tenant(name=self.__class__.tenant_name)
         logger.debug("{}".format(tenant))
         assert('deleted' in tenant.get('result',""))
 
-class test_datacenter_operations(unittest.TestCase):
+
+class test_VIM_datacenter_operations(unittest.TestCase):
     test_index = 1
     datacenter_name = None
     test_text = None
 
     @classmethod
     def setUpClass(cls):
-        logger.info("{}. {}".format(test_number, cls.__name__))
+        logger.info("{}. {}".format(test_config["test_number"], cls.__name__))
 
     @classmethod
     def tearDownClass(cls):
-        globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+        test_config["test_number"] += 1
 
     def tearDown(self):
         exec_info = sys.exc_info()
@@ -147,59 +145,62 @@ class test_datacenter_operations(unittest.TestCase):
             logger.critical("{}".format(msg))
 
     def test_000_create_datacenter(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.datacenter_name = _get_random_string(20)
         self.__class__.test_index += 1
-        self.datacenter = client.create_datacenter(name=self.__class__.datacenter_name, vim_url="http://fakeurl/fake")
+        self.datacenter = test_config["client"].create_datacenter(name=self.__class__.datacenter_name,
+                                                                  vim_url="http://fakeurl/fake")
         logger.debug("{}".format(self.datacenter))
         self.assertEqual (self.datacenter.get('datacenter', {}).get('name',''), self.__class__.datacenter_name)
 
     def test_010_list_datacenter(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
 
         self.__class__.test_index += 1
-        self.datacenter = client.get_datacenter(all_tenants=True, name=self.__class__.datacenter_name)
+        self.datacenter = test_config["client"].get_datacenter(all_tenants=True, name=self.__class__.datacenter_name)
         logger.debug("{}".format(self.datacenter))
         self.assertEqual (self.datacenter.get('datacenter', {}).get('name', ''), self.__class__.datacenter_name)
 
     def test_020_attach_datacenter(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
 
         self.__class__.test_index += 1
-        self.datacenter = client.attach_datacenter(name=self.__class__.datacenter_name, vim_tenant_name='fake')
+        self.datacenter = test_config["client"].attach_datacenter(name=self.__class__.datacenter_name,
+                                                                  vim_tenant_name='fake')
         logger.debug("{}".format(self.datacenter))
         assert ('vim_tenants' in self.datacenter.get('datacenter', {}))
 
     def test_030_list_attached_datacenter(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
 
         self.__class__.test_index += 1
-        self.datacenter = client.get_datacenter(all_tenants=False, name=self.__class__.datacenter_name)
+        self.datacenter = test_config["client"].get_datacenter(all_tenants=False, name=self.__class__.datacenter_name)
         logger.debug("{}".format(self.datacenter))
         self.assertEqual (self.datacenter.get('datacenter', {}).get('name', ''), self.__class__.datacenter_name)
 
     def test_040_detach_datacenter(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
 
         self.__class__.test_index += 1
-        self.datacenter = client.detach_datacenter(name=self.__class__.datacenter_name)
+        self.datacenter = test_config["client"].detach_datacenter(name=self.__class__.datacenter_name)
         logger.debug("{}".format(self.datacenter))
         assert ('detached' in self.datacenter.get('result', ""))
 
     def test_050_delete_datacenter(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
 
         self.__class__.test_index += 1
-        self.datacenter = client.delete_datacenter(name=self.__class__.datacenter_name)
+        self.datacenter = test_config["client"].delete_datacenter(name=self.__class__.datacenter_name)
         logger.debug("{}".format(self.datacenter))
         assert('deleted' in self.datacenter.get('result',""))
 
+
 class test_VIM_network_operations(unittest.TestCase):
     test_index = 1
     vim_network_name = None
@@ -208,11 +209,11 @@ class test_VIM_network_operations(unittest.TestCase):
 
     @classmethod
     def setUpClass(cls):
-        logger.info("{}. {}".format(test_number, cls.__name__))
+        logger.info("{}. {}".format(test_config["test_number"], cls.__name__))
 
     @classmethod
     def tearDownClass(cls):
-        globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+        test_config["test_number"] += 1
 
     def tearDown(self):
         exec_info = sys.exc_info()
@@ -227,51 +228,52 @@ class test_VIM_network_operations(unittest.TestCase):
             logger.critical("{}".format(msg))
 
     def test_000_create_VIM_network(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.vim_network_name = _get_random_string(20)
         self.__class__.test_index += 1
-        network = client.vim_action("create", "networks", name=self.__class__.vim_network_name)
+        network = test_config["client"].vim_action("create", "networks", name=self.__class__.vim_network_name)
         logger.debug("{}".format(network))
         self.__class__.vim_network_uuid = network["network"]["id"]
         self.assertEqual(network.get('network', {}).get('name', ''), self.__class__.vim_network_name)
 
     def test_010_list_VIM_networks(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
-        networks = client.vim_action("list", "networks")
+        networks = test_config["client"].vim_action("list", "networks")
         logger.debug("{}".format(networks))
 
     def test_020_get_VIM_network_by_uuid(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
 
         self.__class__.test_index += 1
-        network = client.vim_action("show", "networks", uuid=self.__class__.vim_network_uuid)
+        network = test_config["client"].vim_action("show", "networks", uuid=self.__class__.vim_network_uuid)
         logger.debug("{}".format(network))
         self.assertEqual(network.get('network', {}).get('name', ''), self.__class__.vim_network_name)
 
     def test_030_delete_VIM_network_by_uuid(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
 
         self.__class__.test_index += 1
-        network = client.vim_action("delete", "networks", uuid=self.__class__.vim_network_uuid)
+        network = test_config["client"].vim_action("delete", "networks", uuid=self.__class__.vim_network_uuid)
         logger.debug("{}".format(network))
         assert ('deleted' in network.get('result', ""))
 
+
 class test_VIM_image_operations(unittest.TestCase):
     test_index = 1
     test_text = None
 
     @classmethod
     def setUpClass(cls):
-        logger.info("{}. {}".format(test_number, cls.__name__))
+        logger.info("{}. {}".format(test_config["test_number"], cls.__name__))
 
     @classmethod
     def tearDownClass(cls):
-        globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+        test_config["test_number"] += 1
 
     def tearDown(self):
         exec_info = sys.exc_info()
@@ -286,10 +288,10 @@ class test_VIM_image_operations(unittest.TestCase):
             logger.critical("{}".format(msg))
 
     def test_000_list_VIM_images(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
-        images = client.vim_action("list", "images")
+        images = test_config["client"].vim_action("list", "images")
         logger.debug("{}".format(images))
 
 '''
@@ -305,13 +307,13 @@ class test_VIM_tenant_operations(unittest.TestCase):
 
     @classmethod
     def setUpClass(cls):
-        logger.info("{}. {}".format(test_number, cls.__name__))
+        logger.info("{}. {}".format(test_config["test_number"], cls.__name__))
         logger.warning("In case of OpenStack datacenter these tests will only success "
                        "if RO has access to the admin endpoint")
 
     @classmethod
     def tearDownClass(cls):
-        globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+        test_config["test_number"] += 1
 
     def tearDown(self):
         exec_info = sys.exc_info()
@@ -326,37 +328,37 @@ class test_VIM_tenant_operations(unittest.TestCase):
             logger.critical("{}".format(msg))
 
     def test_000_create_VIM_tenant(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.vim_tenant_name = _get_random_string(20)
         self.__class__.test_index += 1
-        tenant = client.vim_action("create", "tenants", name=self.__class__.vim_tenant_name)
+        tenant = test_config["client"].vim_action("create", "tenants", name=self.__class__.vim_tenant_name)
         logger.debug("{}".format(tenant))
         self.__class__.vim_tenant_uuid = tenant["tenant"]["id"]
         self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.vim_tenant_name)
 
     def test_010_list_VIM_tenants(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
-        tenants = client.vim_action("list", "tenants")
+        tenants = test_config["client"].vim_action("list", "tenants")
         logger.debug("{}".format(tenants))
 
     def test_020_get_VIM_tenant_by_uuid(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
 
         self.__class__.test_index += 1
-        tenant = client.vim_action("show", "tenants", uuid=self.__class__.vim_tenant_uuid)
+        tenant = test_config["client"].vim_action("show", "tenants", uuid=self.__class__.vim_tenant_uuid)
         logger.debug("{}".format(tenant))
         self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.vim_tenant_name)
 
     def test_030_delete_VIM_tenant_by_uuid(self):
-        self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
 
         self.__class__.test_index += 1
-        tenant = client.vim_action("delete", "tenants", uuid=self.__class__.vim_tenant_uuid)
+        tenant = test_config["client"].vim_action("delete", "tenants", uuid=self.__class__.vim_tenant_uuid)
         logger.debug("{}".format(tenant))
         assert ('deleted' in tenant.get('result', ""))
 
@@ -377,12 +379,12 @@ class descriptor_based_scenario_test(unittest.TestCase):
     def setUpClass(cls):
         cls.test_index = 1
         cls.to_delete_list = []
-        cls.scenario_test_path = test_directory + '/' + scenario_test_folder
-        logger.info("{}. {} {}".format(test_number, cls.__name__, scenario_test_folder))
+        cls.scenario_test_path = test_config["test_directory"] + '/' + test_config["test_folder"]
+        logger.info("{}. {} {}".format(test_config["test_number"], cls.__name__, test_config["test_folder"]))
 
     @classmethod
     def tearDownClass(cls):
-        globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+         test_config["test_number"] += 1
 
     def tearDown(self):
         exec_info = sys.exc_info()
@@ -398,15 +400,15 @@ class descriptor_based_scenario_test(unittest.TestCase):
 
 
     def test_000_load_scenario(self):
-        self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {} {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name,
-                                                           scenario_test_folder)
+                                                           test_config["test_folder"])
         self.__class__.test_index += 1
         vnfd_files = glob.glob(self.__class__.scenario_test_path+'/vnfd_*.yaml')
         scenario_file = glob.glob(self.__class__.scenario_test_path + '/scenario_*.yaml')
         if len(vnfd_files) == 0 or len(scenario_file) > 1:
-            raise Exception('Test '+scenario_test_folder+' not valid. It must contain an scenario file and at least one'
-                                                         ' vnfd file')
+            raise Exception("Test '{}' not valid. It must contain an scenario file and at least one vnfd file'".format(
+                test_config["test_folder"]))
 
         #load all vnfd
         for vnfd in vnfd_files:
@@ -415,55 +417,56 @@ class descriptor_based_scenario_test(unittest.TestCase):
 
             vnfc_list = vnf_descriptor['vnf']['VNFC']
             for vnfc in vnfc_list:
-                vnfc['image name'] = test_image_name
+                vnfc['image name'] = test_config["image_name"]
                 devices = vnfc.get('devices',[])
                 for device in devices:
                     if device['type'] == 'disk' and 'image name' in device:
-                        device['image name'] = test_image_name
+                        device['image name'] = test_config["image_name"]
 
             logger.debug("VNF descriptor: {}".format(vnf_descriptor))
-            vnf = client.create_vnf(descriptor=vnf_descriptor)
+            vnf = test_config["client"].create_vnf(descriptor=vnf_descriptor)
             logger.debug(vnf)
-            self.__class__.to_delete_list.insert(0, {"item": "vnf", "function": client.delete_vnf,
+            self.__class__.to_delete_list.insert(0, {"item": "vnf", "function": test_config["client"].delete_vnf,
                                                      "params": {"uuid": vnf['vnf']['uuid']}})
 
         #load the scenario definition
         with open(scenario_file[0], 'r') as stream:
             scenario_descriptor = yaml.load(stream)
         networks = scenario_descriptor['scenario']['networks']
-        networks[management_network] = networks.pop('mgmt')
+        networks[test_config["mgmt_net"]] = networks.pop('mgmt')
         logger.debug("Scenario descriptor: {}".format(scenario_descriptor))
-        scenario = client.create_scenario(descriptor=scenario_descriptor)
+        scenario = test_config["client"].create_scenario(descriptor=scenario_descriptor)
         logger.debug(scenario)
-        self.__class__.to_delete_list.insert(0,{"item": "scenario", "function": client.delete_scenario,
+        self.__class__.to_delete_list.insert(0,{"item": "scenario", "function": test_config["client"].delete_scenario,
                                  "params":{"uuid": scenario['scenario']['uuid']} })
         self.__class__.scenario_uuid = scenario['scenario']['uuid']
 
     def test_010_instantiate_scenario(self):
-        self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {} {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name,
-                                                           scenario_test_folder)
+                                                           test_config["test_folder"])
         self.__class__.test_index += 1
 
-        instance = client.create_instance(scenario_id=self.__class__.scenario_uuid, name=self.__class__.test_text)
+        instance = test_config["client"].create_instance(scenario_id=self.__class__.scenario_uuid,
+                                                         name=self.__class__.test_text)
         self.__class__.instance_scenario_uuid = instance['uuid']
         logger.debug(instance)
-        self.__class__.to_delete_list.insert(0, {"item": "instance", "function": client.delete_instance,
+        self.__class__.to_delete_list.insert(0, {"item": "instance", "function": test_config["client"].delete_instance,
                                   "params": {"uuid": instance['uuid']}})
 
     def test_020_check_deployent(self):
-        self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {} {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name,
-                                                           scenario_test_folder)
+                                                           test_config["test_folder"])
         self.__class__.test_index += 1
 
-        if manual:
+        if test_config["manual"]:
             raw_input('Scenario has been deployed. Perform manual check and press any key to resume')
             return
 
-        keep_waiting = 50
+        keep_waiting = test_config["timeout"]
         instance_active = False
-        while(keep_waiting):
+        while True:
             result = check_instance_scenario_active(self.__class__.instance_scenario_uuid)
             if result[0]:
                 break
@@ -472,18 +475,21 @@ class descriptor_based_scenario_test(unittest.TestCase):
                 logging.error(msg)
                 raise Exception(msg)
 
-            keep_waiting -= 1
-            time.sleep(5)
-
-        if keep_waiting == 0:
-            msg = 'Timeout reached while waiting instance scenario to get active'
-            logging.error(msg)
-            raise Exception(msg)
+            if keep_waiting >= 5:
+                time.sleep(5)
+                keep_waiting -= 5
+            elif keep_waiting > 0:
+                time.sleep(keep_waiting)
+                keep_waiting = 0
+            else:
+                msg = 'Timeout reached while waiting instance scenario to get active'
+                logging.error(msg)
+                raise Exception(msg)
 
     def test_030_clean_deployment(self):
-        self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
+        self.__class__.test_text = "{}.{}. TEST {} {}".format(test_config["test_number"], self.__class__.test_index,
                                                               inspect.currentframe().f_code.co_name,
-                                                              scenario_test_folder)
+                                                              test_config["test_folder"])
         self.__class__.test_index += 1
         #At the moment if you delete an scenario right after creating it, in openstack datacenters
         #sometimes scenario ports get orphaned. This sleep is just a dirty workaround
@@ -492,6 +498,7 @@ class descriptor_based_scenario_test(unittest.TestCase):
             response = item["function"](**item["params"])
             logger.debug(response)
 
+
 def _get_random_string(maxLength):
     '''generates a string with random characters string.letters and string.digits
     with a random length up to maxLength characters. If maxLength is <15 it will be changed automatically to 15
@@ -504,169 +511,317 @@ def _get_random_string(maxLength):
     length = random.randint(minLength,maxLength)
     return 'testing_'+"".join([random.choice(string.letters+string.digits) for i in xrange(length)])
 
-if __name__=="__main__":
-    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-    import openmanoclient
-
-    parser = OptionParser()
-
-    #Optional arguments
-    parser.add_option("-v",'--version', help='Show current version', dest='version', action="store_true", default=False)
-    parser.add_option('--debug', help='Set logs to debug level', dest='debug', action="store_true", default=False)
-    parser.add_option('--failed', help='Set logs to show only failed tests. --debug disables this option',
-                      dest='failed', action="store_true", default=False)
-    parser.add_option('-u', '--url', dest='endpoint_url', help='Set the openmano server url. By default '
-                                                      'http://localhost:9090/openmano',
-                      default='http://localhost:9090/openmano')
-    default_logger_file = os.path.dirname(__file__)+'/'+os.path.splitext(os.path.basename(__file__))[0]+'.log'
-    parser.add_option('--logger_file', dest='logger_file', help='Set the logger file. By default '+default_logger_file,
-                      default=default_logger_file)
-    parser.add_option('--list-tests', help='List all available tests', dest='list-tests', action="store_true",
-                      default=False)
-    parser.add_option('-m', '--manual-check', help='Pause execution once deployed to allow manual checking of the deployed instance scenario', dest='manual', action="store_true", default=False)
-    parser.add_option('--test', '--tests', help='Specify the tests to run', dest='tests', default=None)
 
-    #Mandatory arguments
-    parser.add_option("-t", '--tenant', dest='tenant_name', help='MANDATORY. Set the tenant name to test')
-    parser.add_option('-d', '--datacenter', dest='datacenter_name', help='MANDATORY, Set the datacenter name to test')
-    parser.add_option("-i", '--image-name', dest='image-name', help='MANDATORY. Image name of an Ubuntu 16.04 image '
-                                                                    'that will be used for testing available in the '
-                                                                    'datacenter.')
-    parser.add_option("-n", '--mgmt-net-name', dest='mgmt-net', help='MANDATORY. Set the tenant name to test')
+def test_vimconnector(args):
+    global test_config
+    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + "/osm_ro")
+    if args.vimtype == "vmware":
+        import vimconn_vmware as vim
+    elif args.vimtype == "aws":
+        import vimconn_aws as vim
+    elif args.vimtype == "openstack":
+        import vimconn_openstack as vim
+    elif args.vimtype == "openvim":
+        import vimconn_openvim as vim
+    else:
+        logger.critical("vimtype '{}' not supported".format(args.vimtype))
+        sys.exit(1)
+    executed = 0
+    failed = 0
+    clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass)
+    # If only want to obtain a tests list print it and exit
+    if args.list_tests:
+        tests_names = []
+        for cls in clsmembers:
+            if cls[0].startswith('test_vimconnector'):
+                tests_names.append(cls[0])
 
-    (options, args) = parser.parse_args()
+        msg = "The 'vim' set tests are:\n\t" + ', '.join(sorted(tests_names))
+        print(msg)
+        logger.info(msg)
+        sys.exit(0)
 
-    # default logger level is INFO. Options --debug and --failed override this, being --debug prioritary
-    logger_level = 'INFO'
-    if options.__dict__['debug']:
-        logger_level = 'DEBUG'
-    elif options.__dict__['failed']:
-        logger_level = 'WARNING'
-    logger_name = os.path.basename(__file__)
-    logger = logging.getLogger(logger_name)
-    logger.setLevel(logger_level)
+    # Create the list of tests to be run
+    code_based_tests = []
+    if args.tests:
+        for test in args.tests:
+            for t in test.split(','):
+                matches_code_based_tests = [item for item in clsmembers if item[0] == t]
+                if len(matches_code_based_tests) > 0:
+                    code_based_tests.append(matches_code_based_tests[0][1])
+                else:
+                    logger.critical("Test '{}' is not among the possible ones".format(t))
+                    sys.exit(1)
+    if not code_based_tests:
+        # include all tests
+        for cls in clsmembers:
+            # We exclude 'test_VIM_tenant_operations' unless it is specifically requested by the user
+            if cls[0].startswith('test_vimconnector'):
+                code_based_tests.append(cls[1])
 
-    # Configure a logging handler to store in a logging file
-    fileHandler = logging.FileHandler(options.__dict__['logger_file'])
-    formatter_fileHandler = logging.Formatter('%(asctime)s %(name)s %(levelname)s: %(message)s')
-    fileHandler.setFormatter(formatter_fileHandler)
-    logger.addHandler(fileHandler)
+    logger.debug("tests to be executed: {}".format(code_based_tests))
 
-    # Configure a handler to print to stdout
-    consoleHandler = logging.StreamHandler(sys.stdout)
-    formatter_consoleHandler = logging.Formatter('%(message)s')
-    consoleHandler.setFormatter(formatter_consoleHandler)
-    logger.addHandler(consoleHandler)
+    # TextTestRunner stream is set to /dev/null in order to avoid the method to directly print the result of tests.
+    # This is handled in the tests using logging.
+    stream = open('/dev/null', 'w')
 
-    logger.debug('Program started with the following arguments: ' + str(options.__dict__))
+    # Run code based tests
+    basic_tests_suite = unittest.TestSuite()
+    for test in code_based_tests:
+        basic_tests_suite.addTest(unittest.makeSuite(test))
+    result = unittest.TextTestRunner(stream=stream, failfast=failfast).run(basic_tests_suite)
+    executed += result.testsRun
+    failed += len(result.failures) + len(result.errors)
+    if failfast and failed:
+        sys.exit(1)
+    if len(result.failures) > 0:
+        logger.debug("failures : {}".format(result.failures))
+    if len(result.errors) > 0:
+        logger.debug("errors : {}".format(result.errors))
+    return executed, failed
 
-    #If version is required print it and exit
-    if options.__dict__['version']:
-        logger.info("{}".format((sys.argv[0], __version__+" version", version_date)))
-        logger.info ("(c) Copyright Telefonica")
-        sys.exit(0)
 
-    test_directory = os.path.dirname(__file__) + "/RO_tests"
-    test_directory_content = os.listdir(test_directory)
+def test_vim(args):
+    global test_config
+    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + "/osm_ro")
+    import openmanoclient
+    executed = 0
+    failed = 0
+    test_config["client"] = openmanoclient.openmanoclient(
+        endpoint_url=args.endpoint_url,
+        tenant_name=args.tenant_name,
+        datacenter_name=args.datacenter,
+        debug=args.debug, logger=test_config["logger_name"])
     clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass)
-
     # If only want to obtain a tests list print it and exit
-    if options.__dict__['list-tests']:
+    if args.list_tests:
         tests_names = []
         for cls in clsmembers:
-            if cls[0].startswith('test_'):
+            if cls[0].startswith('test_VIM'):
                 tests_names.append(cls[0])
 
-        msg = "The code based tests are:\n\t" + ', '.join(sorted(tests_names))+'\n'+\
-              "The descriptor based tests are:\n\t"+ ', '.join(sorted(test_directory_content))+'\n'+\
-              "NOTE: The test test_VIM_tenant_operations will fail in case the used datacenter is type OpenStack " \
+        msg = "The 'vim' set tests are:\n\t" + ', '.join(sorted(tests_names)) +\
+              "\nNOTE: The test test_VIM_tenant_operations will fail in case the used datacenter is type OpenStack " \
               "unless RO has access to the admin endpoint. Therefore this test is excluded by default"
-
+        print(msg)
         logger.info(msg)
         sys.exit(0)
 
-    #Make sure required arguments are present
-    required = "tenant_name datacenter_name image-name mgmt-net".split()
-    error = False
-    for r in required:
-        if options.__dict__[r] is None:
-            print "ERROR: parameter "+r+" is required"
-            error = True
-    if error:
-        parser.print_help()
-        sys.exit(1)
-
-    # set test image name and management network
-    test_image_name = options.__dict__['image-name']
-    management_network = options.__dict__['mgmt-net']
-    manual = options.__dict__['manual']
-
-    #Create the list of tests to be run
-    descriptor_based_tests = []
+    # Create the list of tests to be run
     code_based_tests = []
-    if options.__dict__['tests'] != None:
-        tests = sorted(options.__dict__['tests'].split(','))
-        for test in tests:
-            matches_code_based_tests = [item for item in clsmembers if item[0] == test]
-            if test in test_directory_content:
-                descriptor_based_tests.append(test)
-            elif len(matches_code_based_tests) > 0:
-                code_based_tests.append(matches_code_based_tests[0][1])
-            else:
-                logger.critical("Test {} is not among the possible ones".format(test))
-                sys.exit(1)
-    else:
-        #include all tests
-        descriptor_based_tests = test_directory_content
+    if args.tests:
+        for test in args.tests:
+            for t in test.split(','):
+                matches_code_based_tests = [item for item in clsmembers if item[0] == t]
+                if len(matches_code_based_tests) > 0:
+                    code_based_tests.append(matches_code_based_tests[0][1])
+                else:
+                    logger.critical("Test '{}' is not among the possible ones".format(t))
+                    sys.exit(1)
+    if not code_based_tests:
+        # include all tests
         for cls in clsmembers:
-            #We exclude 'test_VIM_tenant_operations' unless it is specifically requested by the user
-            if cls[0].startswith('test_') and cls[0] != 'test_VIM_tenant_operations':
+            # We exclude 'test_VIM_tenant_operations' unless it is specifically requested by the user
+            if cls[0].startswith('test_VIM') and cls[0] != 'test_VIM_tenant_operations':
                 code_based_tests.append(cls[1])
 
-    logger.debug("descriptor_based_tests to be executed: {}".format(descriptor_based_tests))
-    logger.debug("code_based_tests to be executed: {}".format(code_based_tests))
-
-    # import openmanoclient from relative path
-    client = openmanoclient.openmanoclient(
-                            endpoint_url=options.__dict__['endpoint_url'],
-                            tenant_name=options.__dict__['tenant_name'],
-                            datacenter_name = options.__dict__['datacenter_name'],
-                            debug = options.__dict__['debug'], logger = logger_name)
+    logger.debug("tests to be executed: {}".format(code_based_tests))
 
     # TextTestRunner stream is set to /dev/null in order to avoid the method to directly print the result of tests.
     # This is handled in the tests using logging.
     stream = open('/dev/null', 'w')
-    test_number=1
-    executed = 0
-    failed = 0
 
-    #Run code based tests
+    # Run code based tests
     basic_tests_suite = unittest.TestSuite()
     for test in code_based_tests:
         basic_tests_suite.addTest(unittest.makeSuite(test))
-    result = unittest.TextTestRunner(stream=stream).run(basic_tests_suite)
+    result = unittest.TextTestRunner(stream=stream, failfast=failfast).run(basic_tests_suite)
     executed += result.testsRun
     failed += len(result.failures) + len(result.errors)
+    if failfast and failed:
+        sys.exit(1)
     if len(result.failures) > 0:
         logger.debug("failures : {}".format(result.failures))
     if len(result.errors) > 0:
         logger.debug("errors : {}".format(result.errors))
+    return executed, failed
+
 
-    # Additionally to the previous tests, scenario based tests will be executed.
+def test_deploy(args):
+    global test_config
+    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + "/osm_ro")
+    import openmanoclient
+    executed = 0
+    failed = 0
+    test_config["test_directory"] = os.path.dirname(__file__) + "/RO_tests"
+    test_config["image_name"] = args.image_name
+    test_config["mgmt_net"] = args.mgmt_net
+    test_config["manual"] = args.manual
+    test_directory_content = os.listdir(test_config["test_directory"])
+    # If only want to obtain a tests list print it and exit
+    if args.list_tests:
+        msg = "he 'deploy' set tests are:\n\t" + ', '.join(sorted(test_directory_content))
+        print(msg)
+        logger.info(msg)
+        sys.exit(0)
+
+    descriptor_based_tests = []
+    # Create the list of tests to be run
+    code_based_tests = []
+    if args.tests:
+        for test in args.tests:
+            for t in test.split(','):
+                if t in test_directory_content:
+                    descriptor_based_tests.append(t)
+                else:
+                    logger.critical("Test '{}' is not among the possible ones".format(t))
+                    sys.exit(1)
+    if not descriptor_based_tests:
+        # include all tests
+        descriptor_based_tests = test_directory_content
+
+    logger.debug("tests to be executed: {}".format(code_based_tests))
+
+    # import openmanoclient from relative path
+    test_config["client"] = openmanoclient.openmanoclient(
+        endpoint_url=args.endpoint_url,
+        tenant_name=args.tenant_name,
+        datacenter_name=args.datacenter,
+        debug=args.debug, logger=test_config["logger_name"])
+
+    # TextTestRunner stream is set to /dev/null in order to avoid the method to directly print the result of tests.
+    # This is handled in the tests using logging.
+    stream = open('/dev/null', 'w')
     # This scenario based tests are defined as directories inside the directory defined in 'test_directory'
     for test in descriptor_based_tests:
-        scenario_test_folder = test
+        test_config["test_folder"] = test
         test_suite = unittest.TestSuite()
         test_suite.addTest(unittest.makeSuite(descriptor_based_scenario_test))
-        result = unittest.TextTestRunner(stream=stream).run(test_suite)
+        result = unittest.TextTestRunner(stream=stream, failfast=False).run(test_suite)
         executed += result.testsRun
         failed += len(result.failures) + len(result.errors)
+        if failfast and failed:
+            sys.exit(1)
         if len(result.failures) > 0:
             logger.debug("failures : {}".format(result.failures))
         if len(result.errors) > 0:
             logger.debug("errors : {}".format(result.errors))
 
-    #Log summary
-    logger.warning("Total number of tests: {}; Total number of failures/errors: {}".format(executed, failed))
+    return executed, failed
+
+if __name__=="__main__":
+
+    parser = ArgumentParser(description='Test RO module')
+    parser.add_argument('-v','--version', action='version', help="Show current version",
+                             version='%(prog)s version ' + __version__  + ' ' + version_date)
 
-    sys.exit(0)
\ No newline at end of file
+    # Common parameters
+    parent_parser = ArgumentParser(add_help=False)
+    parent_parser.add_argument('--failfast', help='Stop when a test fails rather than execute all tests',
+                      dest='failfast', action="store_true", default=False)
+    parent_parser.add_argument('--failed', help='Set logs to show only failed tests. --debug disables this option',
+                      dest='failed', action="store_true", default=False)
+    default_logger_file = os.path.dirname(__file__)+'/'+os.path.splitext(os.path.basename(__file__))[0]+'.log'
+    parent_parser.add_argument('--list-tests', help='List all available tests', dest='list_tests', action="store_true",
+                      default=False)
+    parent_parser.add_argument('--logger_file', dest='logger_file', default=default_logger_file,
+                               help='Set the logger file. By default '+default_logger_file)
+    parent_parser.add_argument("-t", '--tenant', dest='tenant_name', default="osm",
+                               help="Set the openmano tenant to use for the test. By default 'osm'")
+    parent_parser.add_argument('--debug', help='Set logs to debug level', dest='debug', action="store_true")
+    parent_parser.add_argument('--timeout', help='Specify the instantiation timeout in seconds. By default 300',
+                          dest='timeout', type=int, default=300)
+    parent_parser.add_argument('--test', '--tests', help='Specify the tests to run', dest='tests', action="append")
+
+    subparsers = parser.add_subparsers(help='test sets')
+
+    # Deployment test set
+    # -------------------
+    deploy_parser = subparsers.add_parser('deploy', parents=[parent_parser],
+                                          help="test deployment using descriptors at RO_test folder ")
+    deploy_parser.set_defaults(func=test_deploy)
+
+    # Mandatory arguments
+    mandatory_arguments = deploy_parser.add_argument_group('mandatory arguments')
+    mandatory_arguments.add_argument('-d', '--datacenter', required=True, help='Set the datacenter to test')
+    mandatory_arguments.add_argument("-i", '--image-name', required=True, dest="image_name",
+                                     help='Image name available at datacenter used for the tests')
+    mandatory_arguments.add_argument("-n", '--mgmt-net-name', required=True, dest='mgmt_net',
+                                     help='Set the vim management network to use for tests')
+
+    # Optional arguments
+    deploy_parser.add_argument('-m', '--manual-check', dest='manual', action="store_true", default=False,
+                               help='Pause execution once deployed to allow manual checking of the '
+                                    'deployed instance scenario')
+    deploy_parser.add_argument('-u', '--url', dest='endpoint_url', default='http://localhost:9090/openmano',
+                               help="Set the openmano server url. By default 'http://localhost:9090/openmano'")
+
+    # Vimconn test set
+    # -------------------
+    vimconn_parser = subparsers.add_parser('vimconn', parents=[parent_parser], help="test vimconnector plugin")
+    vimconn_parser.set_defaults(func=test_vimconnector)
+    # Mandatory arguments
+    mandatory_arguments = vimconn_parser.add_argument_group('mandatory arguments')
+    mandatory_arguments.add_argument('--vimtype', choices=['vmware', 'aws', 'openstack', 'openvim'], required=True,
+                                     help='Set the vimconnector type to test')
+    # TODO add mandatory arguments for vimconn test
+    # mandatory_arguments.add_argument('-c', '--config', dest='config_param', required=True, help='<HELP>')
+
+    # Optional arguments
+    # TODO add optional arguments for vimconn tests
+    # vimconn_parser.add_argument("-i", '--image-name', dest='image_name', help='<HELP>'))
+
+    # Datacenter test set
+    # -------------------
+    vimconn_parser = subparsers.add_parser('vim', parents=[parent_parser], help="test vim")
+    vimconn_parser.set_defaults(func=test_vim)
+
+    # Mandatory arguments
+    mandatory_arguments = vimconn_parser.add_argument_group('mandatory arguments')
+    mandatory_arguments.add_argument('-d', '--datacenter', required=True, help='Set the datacenter to test')
+
+    # Optional arguments
+    vimconn_parser.add_argument('-u', '--url', dest='endpoint_url', default='http://localhost:9090/openmano',
+                               help="Set the openmano server url. By default 'http://localhost:9090/openmano'")
+
+    argcomplete.autocomplete(parser)
+    args = parser.parse_args()
+    # print str(args)
+    test_config = {}
+
+    # default logger level is INFO. Options --debug and --failed override this, being --debug prioritary
+    logger_level = 'INFO'
+    if args.debug:
+        logger_level = 'DEBUG'
+    elif args.failed:
+        logger_level = 'WARNING'
+    logger_name = os.path.basename(__file__)
+    test_config["logger_name"] = logger_name
+    logger = logging.getLogger(logger_name)
+    logger.setLevel(logger_level)
+    failfast = args.failfast
+
+    # Configure a logging handler to store in a logging file
+    if args.logger_file:
+        fileHandler = logging.FileHandler(args.logger_file)
+        formatter_fileHandler = logging.Formatter('%(asctime)s %(name)s %(levelname)s: %(message)s')
+        fileHandler.setFormatter(formatter_fileHandler)
+        logger.addHandler(fileHandler)
+
+    # Configure a handler to print to stdout
+    consoleHandler = logging.StreamHandler(sys.stdout)
+    formatter_consoleHandler = logging.Formatter('%(asctime)s %(name)s %(levelname)s: %(message)s')
+    consoleHandler.setFormatter(formatter_consoleHandler)
+    logger.addHandler(consoleHandler)
+
+    logger.debug('Program started with the following arguments: ' + str(args))
+
+    # set test config parameters
+    test_config["timeout"] = args.timeout
+    test_config["test_number"] = 1
+
+    executed, failed = args.func(args)
+
+    # Log summary
+    logger.warning("Total number of tests: {}; Total number of failures/errors: {}".format(executed, failed))
+    sys.exit(1 if failed else 0)