Changes to import dynamically modules in ovim.py
[osm/openvim.git] / osm_openvim / ovim.py
index 39ab578..fb34552 100755 (executable)
 # contact with: nfvlabs@tid.es
 ##
 
 # contact with: nfvlabs@tid.es
 ##
 
-'''
+"""
 This is the thread for the http server North API. 
 Two thread will be launched, with normal and administrative permissions.
 This is the thread for the http server North API. 
 Two thread will be launched, with normal and administrative permissions.
-'''
-
-__author__ = "Alfonso Tierno, Leonardo Mirabal"
-__date__ = "$06-Feb-2017 12:07:15$"
-__version__ = "0.5.10-r526"
-version_date = "Apr 2017"
-database_version = "0.17"      #expected database schema version
+"""
 
 import threading
 
 import threading
-import osm_openvim.vim_db as vim_db
+import vim_db
 import logging
 import logging
-import imp
+# import imp
+import os.path
 import argparse
 from netaddr import IPNetwork
 from jsonschema import validate as js_v, exceptions as js_e
 import argparse
 from netaddr import IPNetwork
 from jsonschema import validate as js_v, exceptions as js_e
-import osm_openvim.host_thread as ht
-import osm_openvim.dhcp_thread as dt
-import osm_openvim.openflow_thread as oft
-import osm_openvim.openflow_conn as openflow_conn
+import host_thread as ht
+import dhcp_thread as dt
+import openflow_thread as oft
+import openflow_conn
 
 
+__author__ = "Alfonso Tierno, Leonardo Mirabal"
+__date__ = "$06-Feb-2017 12:07:15$"
+__version__ = "0.5.13-r529"
+version_date = "May 2017"
+database_version = 18      #needed database schema version
 
 HTTP_Bad_Request =          400
 HTTP_Unauthorized =         401
 
 HTTP_Bad_Request =          400
 HTTP_Unauthorized =         401
@@ -100,8 +100,6 @@ class ovim():
         self.logger = logging.getLogger(self.logger_name)
         self.db = None
         self.db = self._create_database_connection()
         self.logger = logging.getLogger(self.logger_name)
         self.db = None
         self.db = self._create_database_connection()
-        self.db_lock = None
-        self.db_of = None
         self.of_test_mode = False
 
     def _create_database_connection(self):
         self.of_test_mode = False
 
     def _create_database_connection(self):
@@ -172,19 +170,25 @@ class ovim():
         # if self.running_info:
         #    return  #TODO service can be checked and rebuild broken threads
         r = self.db.get_db_version()
         # if self.running_info:
         #    return  #TODO service can be checked and rebuild broken threads
         r = self.db.get_db_version()
+        db_path = __file__
+        db_path = db_path[:db_path.rfind("/")]
+        if os.path.exists(db_path + "/database_utils/migrate_vim_db.sh"):
+            db_path += "/database_utils"
+        else:
+            db_path += "/../database_utils"
+
         if r[0] < 0:
         if r[0] < 0:
-            raise ovimException("DATABASE is not a VIM one or it is a '0.0' version. Try to upgrade to version '{}' with "\
-                                "'./database_utils/migrate_vim_db.sh'".format(database_version) )
-        elif r[1] != database_version:
-            raise ovimException("DATABASE wrong version '{}'. Try to upgrade/downgrade to version '{}' with "\
-                                "'./database_utils/migrate_vim_db.sh'".format(r[1], database_version) )
+            raise ovimException("DATABASE is not valid. If you think it is corrupted, you can init it with"
+                                " '{db_path}/init_vim_db.sh' script".format(db_path=db_path))
+        elif r[0] != database_version:
+            raise ovimException("DATABASE wrong version '{current}'. Try to upgrade/downgrade to version '{target}'"
+                                " with '{db_path}/migrate_vim_db.sh {target}'".format(
+                                current=r[0], target=database_version,  db_path=db_path))
         self.logger.critical("Starting ovim server version: '{} {}' database version '{}'".format(
             self.get_version(), self.get_version_date(), self.get_database_version()))
         # create database connection for openflow threads
         self.logger.critical("Starting ovim server version: '{} {}' database version '{}'".format(
             self.get_version(), self.get_version_date(), self.get_database_version()))
         # create database connection for openflow threads
-        self.db_of = self._create_database_connection()
-        self.config["db"] = self.db_of
-        self.db_lock = threading.Lock()
-        self.config["db_lock"] = self.db_lock
+        self.config["db"] = self._create_database_connection()
+        self.config["db_lock"] = threading.Lock()
 
         self.of_test_mode = False if self.config['mode'] == 'normal' or self.config['mode'] == "OF only" else True
         # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge,
 
         self.of_test_mode = False if self.config['mode'] == 'normal' or self.config['mode'] == "OF only" else True
         # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge,
@@ -228,7 +232,8 @@ class ovim():
         dhcp_params = self.config.get("dhcp_server")
         if dhcp_params:
             thread = dt.dhcp_thread(dhcp_params=dhcp_params, test=host_test_mode, dhcp_nets=self.config["dhcp_nets"],
         dhcp_params = self.config.get("dhcp_server")
         if dhcp_params:
             thread = dt.dhcp_thread(dhcp_params=dhcp_params, test=host_test_mode, dhcp_nets=self.config["dhcp_nets"],
-                                    db=self.db_of, db_lock=self.db_lock, logger_name=self.logger_name + ".dhcp",
+                                    db=self.config["db"], db_lock=self.config["db_lock"],
+                                    logger_name=self.logger_name + ".dhcp",
                                     debug=self.config.get('log_level_of'))
             thread.start()
             self.config['dhcp_thread'] = thread
                                     debug=self.config.get('log_level_of'))
             thread.start()
             self.config['dhcp_thread'] = thread
@@ -246,10 +251,14 @@ class ovim():
         self.config['host_threads'] = {}
         for host in hosts:
             host['image_path'] = '/opt/VNF/images/openvim'
         self.config['host_threads'] = {}
         for host in hosts:
             host['image_path'] = '/opt/VNF/images/openvim'
-            thread = ht.host_thread(name=host['name'], user=host['user'], host=host['ip_name'], db=self.db_of,
-                                    db_lock=self.db_lock, test=host_test_mode, image_path=self.config['image_path'],
-                                    version=self.config['version'], host_id=host['uuid'], develop_mode=host_develop_mode,
-                                    develop_bridge_iface=host_develop_bridge_iface)
+            thread = ht.host_thread(name=host['name'], user=host['user'], host=host['ip_name'], db=self.config["db"],
+                                    db_lock=self.config["db_lock"], test=host_test_mode,
+                                    image_path=self.config['image_path'],
+                                    version=self.config['version'], host_id=host['uuid'],
+                                    develop_mode=host_develop_mode,
+                                    develop_bridge_iface=host_develop_bridge_iface,
+                                    logger_name=self.logger_name + ".host." + host['name'],
+                                    debug=self.config.get('log_level_host'))
             thread.start()
             self.config['host_threads'][host['uuid']] = thread
 
             thread.start()
             self.config['host_threads'][host['uuid']] = thread
 
@@ -369,27 +378,22 @@ class ovim():
                 module = temp_dict['of_controller']
 
             if module not in ovim.of_module:
                 module = temp_dict['of_controller']
 
             if module not in ovim.of_module:
-                module_info = imp.find_module(module)
-                of_conn_module = imp.load_module("OF_conn", *module_info)
-                ovim.of_module[module] = of_conn_module
+                try:
+                    pkg = __import__("osm_openvim." + module)
+                    of_conn_module = getattr(pkg, module)
+                    ovim.of_module[module] = of_conn_module
+                    self.logger.debug("Module load from {}".format("osm_openvim." + module))
+                except Exception as e:
+                    self.logger.error("Cannot open openflow controller module of type '%s'", module)
+                    raise ovimException("Cannot open openflow controller of type module '{}'"
+                                        "Revise it is installed".format(module),
+                                        HTTP_Internal_Server_Error)
             else:
                 of_conn_module = ovim.of_module[module]
             else:
                 of_conn_module = ovim.of_module[module]
-
-            try:
-                return of_conn_module.OF_conn(temp_dict)
-            except Exception as e:
-                self.logger.error("Cannot open the Openflow controller '%s': %s", type(e).__name__, str(e))
-                if module_info and module_info[0]:
-                    file.close(module_info[0])
-                raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e).__name__, str(e)),
-                                    HTTP_Internal_Server_Error)
-        except (IOError, ImportError) as e:
-            if module_info and module_info[0]:
-                file.close(module_info[0])
-            self.logger.error("Cannot open openflow controller module '%s'; %s: %s; revise 'of_controller' "
-                              "field of configuration file.", module, type(e).__name__, str(e))
-            raise ovimException("Cannot open openflow controller module '{}'; {}: {}; revise 'of_controller' "
-                                "field of configuration file.".format(module, type(e).__name__, str(e)),
+            return of_conn_module.OF_conn(temp_dict)
+        except Exception as e:
+            self.logger.error("Cannot open the Openflow controller '%s': %s", type(e).__name__, str(e))
+            raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e).__name__, str(e)),
                                 HTTP_Internal_Server_Error)
 
     def _create_ofc_thread(self, of_conn, ofc_uuid="Default"):
                                 HTTP_Internal_Server_Error)
 
     def _create_ofc_thread(self, of_conn, ofc_uuid="Default"):
@@ -405,8 +409,11 @@ class ovim():
         #    ofc_net_same_vlan = False
         ofc_net_same_vlan = False
 
         #    ofc_net_same_vlan = False
         ofc_net_same_vlan = False
 
-        thread = oft.openflow_thread(ofc_uuid, of_conn, of_test=self.of_test_mode, db=self.db_of, db_lock=self.db_lock,
-                                     pmp_with_same_vlan=ofc_net_same_vlan, debug=self.config['log_level_of'])
+        thread = oft.openflow_thread(ofc_uuid, of_conn, of_test=self.of_test_mode, db=self.config["db"],
+                                     db_lock=self.config["db_lock"],
+                                     pmp_with_same_vlan=ofc_net_same_vlan,
+                                     logger_name=self.logger_name + ".ofc." + ofc_uuid,
+                                     debug=self.config.get('log_level_of'))
         #r, c = thread.OF_connector.obtain_port_correspondence()
         #if r < 0:
         #    raise ovimException("Cannot get openflow information %s", c)
         #r, c = thread.OF_connector.obtain_port_correspondence()
         #if r < 0:
         #    raise ovimException("Cannot get openflow information %s", c)
@@ -495,6 +502,7 @@ class ovim():
         net_vlan = network.get("vlan")
         net_bind_net = network.get("bind_net")
         net_bind_type = network.get("bind_type")
         net_vlan = network.get("vlan")
         net_bind_net = network.get("bind_net")
         net_bind_type = network.get("bind_type")
+        net_region = network.get("region")
         name = network["name"]
 
         # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
         name = network["name"]
 
         # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
@@ -590,8 +598,13 @@ class ovim():
                 net_vlan = bridge_net[1]
         elif net_type == 'bridge_data' or net_type == 'bridge_man' and self.config['network_type'] == 'ovs':
             net_provider = 'OVS'
                 net_vlan = bridge_net[1]
         elif net_type == 'bridge_data' or net_type == 'bridge_man' and self.config['network_type'] == 'ovs':
             net_provider = 'OVS'
+        if not net_region:
+            if net_type == "data" or net_type == "ptp":
+                net_region = "__DATA__"
+            elif net_provider == "OVS":
+                net_region = "__OVS__"
         if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
         if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
-            net_vlan = self.db.get_free_net_vlan()
+            net_vlan = self.db.get_free_net_vlan(net_region)
             if net_vlan < 0:
                 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error)
         if net_provider == 'OVS':
             if net_vlan < 0:
                 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error)
         if net_provider == 'OVS':
@@ -600,6 +613,7 @@ class ovim():
         network['provider'] = net_provider
         network['type'] = net_type
         network['vlan'] = net_vlan
         network['provider'] = net_provider
         network['type'] = net_type
         network['vlan'] = net_vlan
+        network['region'] = net_region
         dhcp_integrity = True
         if 'enable_dhcp' in network and network['enable_dhcp']:
             dhcp_integrity = self._check_dhcp_data_integrity(network)
         dhcp_integrity = True
         if 'enable_dhcp' in network and network['enable_dhcp']:
             dhcp_integrity = self._check_dhcp_data_integrity(network)
@@ -1338,12 +1352,13 @@ class ovim():
         host_develop_mode = True if self.config['mode'] == 'development' else False
 
         dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip,
         host_develop_mode = True if self.config['mode'] == 'development' else False
 
         dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip,
-                                   db=self.db_of,
-                                   db_lock=self.db_lock, test=host_test_mode,
+                                   db=self.config["db"], db_lock=self.config["db_lock"], test=host_test_mode,
                                    image_path=self.config['image_path'], version=self.config['version'],
                                    host_id='openvim_controller', develop_mode=host_develop_mode,
                                    image_path=self.config['image_path'], version=self.config['version'],
                                    host_id='openvim_controller', develop_mode=host_develop_mode,
-                                   develop_bridge_iface=bridge_ifaces)
-
+                                   develop_bridge_iface=bridge_ifaces,
+                                   logger_name=self.logger_name + ".host.controller",
+                                   debug=self.config.get('log_level_host'))
+        dhcp_host.start()
         self.config['host_threads']['openvim_controller'] = dhcp_host
         if not host_test_mode:
             dhcp_host.ssh_connect()
         self.config['host_threads']['openvim_controller'] = dhcp_host
         if not host_test_mode:
             dhcp_host.ssh_connect()