New README.rst and requirements.txt files, setup.py and Makefile updated
[osm/RO.git] / vimconn_openstack.py
index 3a323a8..b501d9d 100644 (file)
 '''
 osconnector implements all the methods to interact with openstack using the python-client.
 '''
 '''
 osconnector implements all the methods to interact with openstack using the python-client.
 '''
-__author__="Alfonso Tierno, Gerardo Garcia"
+__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research"
 __date__ ="$22-jun-2014 11:19:29$"
 
 import vimconn
 import json
 import yaml
 __date__ ="$22-jun-2014 11:19:29$"
 
 import vimconn
 import json
 import yaml
+import logging
+import netaddr
+import time
+import yaml
+import random
 
 
-from novaclient import client as nClient, exceptions as nvExceptions
-import keystoneclient.v2_0.client as ksClient
+from novaclient import client as nClient_v2, exceptions as nvExceptions
+from novaclient import api_versions
+import keystoneclient.v2_0.client as ksClient_v2
+from novaclient.v2.client import Client as nClient
+import keystoneclient.v3.client as ksClient
 import keystoneclient.exceptions as ksExceptions
 import glanceclient.v2.client as glClient
 import glanceclient.client as gl1Client
 import glanceclient.exc as gl1Exceptions
 import keystoneclient.exceptions as ksExceptions
 import glanceclient.v2.client as glClient
 import glanceclient.client as gl1Client
 import glanceclient.exc as gl1Exceptions
+import cinderclient.v2.client as cClient_v2
 from httplib import HTTPException
 from httplib import HTTPException
-from neutronclient.neutron import client as neClient
+from neutronclient.neutron import client as neClient_v2
+from neutronclient.v2_0 import client as neClient
 from neutronclient.common import exceptions as neExceptions
 from requests.exceptions import ConnectionError
 
 from neutronclient.common import exceptions as neExceptions
 from requests.exceptions import ConnectionError
 
@@ -53,44 +63,94 @@ vmStatus2manoFormat={'ACTIVE':'ACTIVE',
 netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE','BUILD':'BUILD','ERROR':'ERROR','DELETED':'DELETED'
                      }
 
 netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE','BUILD':'BUILD','ERROR':'ERROR','DELETED':'DELETED'
                      }
 
+#global var to have a timeout creating and deleting volumes
+volume_timeout = 60
+server_timeout = 60
+
 class vimconnector(vimconn.vimconnector):
 class vimconnector(vimconn.vimconnector):
-    def __init__(self, uuid, name, tenant, url, url_admin=None, user=None, passwd=None, debug=True, config={}):
-        '''using common constructor parameters. In this case 
+    def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None,
+                 log_level=None, config={}, persistent_info={}):
+        '''using common constructor parameters. In this case
         'url' is the keystone authorization url,
         'url_admin' is not use
         '''
         'url' is the keystone authorization url,
         'url_admin' is not use
         '''
-        vimconn.vimconnector.__init__(self, uuid, name, tenant, url, url_admin, user, passwd, debug, config)
-        
+        self.osc_api_version = 'v2.0'
+        if config.get('APIversion') == 'v3.3':
+            self.osc_api_version = 'v3.3'
+        vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level, config)
+
+        self.persistent_info = persistent_info
         self.k_creds={}
         self.n_creds={}
         self.k_creds={}
         self.n_creds={}
+        if self.config.get("insecure"):
+            self.k_creds["insecure"] = True
+            self.n_creds["insecure"] = True
         if not url:
             raise TypeError, 'url param can not be NoneType'
         self.k_creds['auth_url'] = url
         self.n_creds['auth_url'] = url
         if not url:
             raise TypeError, 'url param can not be NoneType'
         self.k_creds['auth_url'] = url
         self.n_creds['auth_url'] = url
-        if tenant:
-            self.k_creds['tenant_name'] = tenant
-            self.n_creds['project_id']  = tenant
+        if tenant_name:
+            self.k_creds['tenant_name'] = tenant_name
+            self.n_creds['project_id']  = tenant_name
+        if tenant_id:
+            self.k_creds['tenant_id'] = tenant_id
+            self.n_creds['tenant_id']  = tenant_id
         if user:
             self.k_creds['username'] = user
             self.n_creds['username'] = user
         if passwd:
             self.k_creds['password'] = passwd
             self.n_creds['api_key']  = passwd
         if user:
             self.k_creds['username'] = user
             self.n_creds['username'] = user
         if passwd:
             self.k_creds['password'] = passwd
             self.n_creds['api_key']  = passwd
+        if self.osc_api_version == 'v3.3':
+            self.k_creds['project_name'] = tenant_name
+            self.k_creds['project_id'] = tenant_id
+        if config.get('region_name'):
+            self.k_creds['region_name'] = config.get('region_name')
+            self.n_creds['region_name'] = config.get('region_name')
+
         self.reload_client       = True
         self.reload_client       = True
+        self.logger = logging.getLogger('openmano.vim.openstack')
+        if log_level:
+            self.logger.setLevel( getattr(logging, log_level) )
     
     def __setitem__(self,index, value):
         '''Set individuals parameters 
         Throw TypeError, KeyError
         '''
     
     def __setitem__(self,index, value):
         '''Set individuals parameters 
         Throw TypeError, KeyError
         '''
-        if index=='tenant':
+        if index=='tenant_id':
             self.reload_client=True
             self.reload_client=True
-            self.tenant = value
-            if value:
-                self.k_creds['tenant_name'] = value
-                self.n_creds['project_id']  = value
+            self.tenant_id = value
+            if self.osc_api_version == 'v3.3':
+                if value:
+                    self.k_creds['project_id'] = value
+                    self.n_creds['project_id']  = value
+                else:
+                    del self.k_creds['project_id']
+                    del self.n_creds['project_id']
+            else:
+                if value:
+                    self.k_creds['tenant_id'] = value
+                    self.n_creds['tenant_id']  = value
+                else:
+                    del self.k_creds['tenant_id']
+                    del self.n_creds['tenant_id']
+        elif index=='tenant_name':
+            self.reload_client=True
+            self.tenant_name = value
+            if self.osc_api_version == 'v3.3':
+                if value:
+                    self.k_creds['project_name'] = value
+                    self.n_creds['project_name']  = value
+                else:
+                    del self.k_creds['project_name']
+                    del self.n_creds['project_name']
             else:
             else:
-                del self.k_creds['tenant_name']
-                del self.n_creds['project_id']
+                if value:
+                    self.k_creds['tenant_name'] = value
+                    self.n_creds['project_id']  = value
+                else:
+                    del self.k_creds['tenant_name']
+                    del self.n_creds['project_id']
         elif index=='user':
             self.reload_client=True
             self.user = value
         elif index=='user':
             self.reload_client=True
             self.user = value
@@ -129,115 +189,22 @@ class vimconnector(vimconn.vimconnector):
             #test valid params
             if len(self.n_creds) <4:
                 raise ksExceptions.ClientException("Not enough parameters to connect to openstack")
             #test valid params
             if len(self.n_creds) <4:
                 raise ksExceptions.ClientException("Not enough parameters to connect to openstack")
-            self.nova = nClient.Client(2, **self.n_creds)
-            self.keystone = ksClient.Client(**self.k_creds)
+            if self.osc_api_version == 'v3.3':
+                self.nova = nClient(api_version=api_versions.APIVersion(version_str='2.0'), **self.n_creds)
+                #TODO To be updated for v3
+                #self.cinder = cClient.Client(**self.n_creds)
+                self.keystone = ksClient.Client(**self.k_creds)
+                self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+                self.neutron = neClient.Client(api_version=api_versions.APIVersion(version_str='2.0'), endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
+            else:
+                self.nova = nClient_v2.Client(version='2', **self.n_creds)
+                self.cinder = cClient_v2.Client(**self.n_creds)
+                self.keystone = ksClient_v2.Client(**self.k_creds)
+                self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+                self.neutron = neClient_v2.Client('2.0', endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
             self.glance_endpoint = self.keystone.service_catalog.url_for(service_type='image', endpoint_type='publicURL')
             self.glance = glClient.Client(self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds)  #TODO check k_creds vs n_creds
             self.glance_endpoint = self.keystone.service_catalog.url_for(service_type='image', endpoint_type='publicURL')
             self.glance = glClient.Client(self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds)  #TODO check k_creds vs n_creds
-            self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
-            self.neutron = neClient.Client('2.0', endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
             self.reload_client = False
             self.reload_client = False
-    
-    def new_external_port(self, port_data):
-        #TODO openstack if needed
-        '''Adds a external port to VIM'''
-        '''Returns the port identifier'''
-        return -vimconn.HTTP_Internal_Server_Error, "osconnector.new_external_port() not implemented" 
-        
-    def connect_port_network(self, port_id, network_id, admin=False):
-        #TODO openstack if needed
-        '''Connects a external port to a network'''
-        '''Returns status code of the VIM response'''
-        return -vimconn.HTTP_Internal_Server_Error, "osconnector.connect_port_network() not implemented" 
-    
-    def new_user(self, user_name, user_passwd, tenant_id=None):
-        '''Adds a new user to openstack VIM'''
-        '''Returns the user identifier'''
-        if self.debug:
-            print "osconnector: Adding a new user to VIM"
-        try:
-            self._reload_connection()
-            user=self.keystone.users.create(user_name, user_passwd, tenant_id=tenant_id)
-            #self.keystone.tenants.add_user(self.k_creds["username"], #role)
-            return 1, user.id
-        except ksExceptions.ConnectionError as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except ksExceptions.ClientException as e: #TODO remove
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "new_tenant " + error_text
-        return error_value, error_text        
-
-    def delete_user(self, user_id):
-        '''Delete a user from openstack VIM'''
-        '''Returns the user identifier'''
-        if self.debug:
-            print "osconnector: Deleting  a  user from VIM"
-        try:
-            self._reload_connection()
-            self.keystone.users.delete(user_id)
-            return 1, user_id
-        except ksExceptions.ConnectionError as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except ksExceptions.NotFound as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except ksExceptions.ClientException as e: #TODO remove
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "delete_tenant " + error_text
-        return error_value, error_text
-        
-    def new_tenant(self,tenant_name,tenant_description):
-        '''Adds a new tenant to openstack VIM'''
-        '''Returns the tenant identifier'''
-        if self.debug:
-            print "osconnector: Adding a new tenant to VIM"
-        try:
-            self._reload_connection()
-            tenant=self.keystone.tenants.create(tenant_name, tenant_description)
-            #self.keystone.tenants.add_user(self.k_creds["username"], #role)
-            return 1, tenant.id
-        except ksExceptions.ConnectionError as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except ksExceptions.ClientException as e: #TODO remove
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "new_tenant " + error_text
-        return error_value, error_text
-
-    def delete_tenant(self,tenant_id):
-        '''Delete a tenant from openstack VIM'''
-        '''Returns the tenant identifier'''
-        if self.debug:
-            print "osconnector: Deleting  a  tenant from VIM"
-        try:
-            self._reload_connection()
-            self.keystone.tenants.delete(tenant_id)
-            #self.keystone.tenants.add_user(self.k_creds["username"], #role)
-            return 1, tenant_id
-        except ksExceptions.ConnectionError as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except ksExceptions.ClientException as e: #TODO remove
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "delete_tenant " + error_text
-        return error_value, error_text
 
     def __net_os2mano(self, net_list_dict):
         '''Transform the net openstack format to mano format
 
     def __net_os2mano(self, net_list_dict):
         '''Transform the net openstack format to mano format
@@ -253,47 +220,131 @@ class vimconnector(vimconn.vimconnector):
                 net['type']='data'
             else:
                 net['type']='bridge'
                 net['type']='data'
             else:
                 net['type']='bridge'
-        
-    def new_tenant_network(self,net_name,net_type,public=False,cidr=None,vlan=None):
-        '''Adds a tenant network to VIM'''
-        '''Returns the network identifier'''
-        if self.debug:
-            print "osconnector: Adding a new tenant network to VIM (tenant: " + self.tenant + ", type: " + net_type + "): "+ net_name
+                
+                
+            
+    def _format_exception(self, exception):
+        '''Transform a keystone, nova, neutron  exception into a vimconn exception'''
+        if isinstance(exception, (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError,
+                                  ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed
+                                  )):
+            raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))            
+        elif isinstance(exception, (nvExceptions.ClientException, ksExceptions.ClientException, 
+                                    neExceptions.NeutronException, nvExceptions.BadRequest)):
+            raise vimconn.vimconnUnexpectedResponse(type(exception).__name__ + ": " + str(exception))
+        elif isinstance(exception, (neExceptions.NetworkNotFoundClient, nvExceptions.NotFound)):
+            raise vimconn.vimconnNotFoundException(type(exception).__name__ + ": " + str(exception))
+        elif isinstance(exception, nvExceptions.Conflict):
+            raise vimconn.vimconnConflictException(type(exception).__name__ + ": " + str(exception))
+        else: # ()
+            raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))
+
+    def get_tenant_list(self, filter_dict={}):
+        '''Obtain tenants of VIM
+        filter_dict can contain the following keys:
+            name: filter by tenant name
+            id: filter by tenant uuid/id
+            <other VIM specific>
+        Returns the tenant list of dictionaries: [{'name':'<name>, 'id':'<id>, ...}, ...]
+        '''
+        self.logger.debug("Getting tenants from VIM filter: '%s'", str(filter_dict))
+        try:
+            self._reload_connection()
+            if self.osc_api_version == 'v3.3':
+                project_class_list=self.keystone.projects.findall(**filter_dict)
+            else:
+                project_class_list=self.keystone.tenants.findall(**filter_dict)
+            project_list=[]
+            for project in project_class_list:
+                project_list.append(project.to_dict())
+            return project_list
+        except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError)  as e:
+            self._format_exception(e)
+
+    def new_tenant(self, tenant_name, tenant_description):
+        '''Adds a new tenant to openstack VIM. Returns the tenant identifier'''
+        self.logger.debug("Adding a new tenant name: %s", tenant_name)
+        try:
+            self._reload_connection()
+            if self.osc_api_version == 'v3.3':
+                project=self.keystone.projects.create(tenant_name, tenant_description)
+            else:
+                project=self.keystone.tenants.create(tenant_name, tenant_description)
+            return project.id
+        except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError)  as e:
+            self._format_exception(e)
+
+    def delete_tenant(self, tenant_id):
+        '''Delete a tenant from openstack VIM. Returns the old tenant identifier'''
+        self.logger.debug("Deleting tenant %s from VIM", tenant_id)
         try:
         try:
+            self._reload_connection()
+            if self.osc_api_version == 'v3.3':
+                self.keystone.projects.delete(tenant_id)
+            else:
+                self.keystone.tenants.delete(tenant_id)
+            return tenant_id
+        except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError)  as e:
+            self._format_exception(e)
+
+    def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None):
+        '''Adds a tenant network to VIM. Returns the network identifier'''
+        self.logger.debug("Adding a new network to VIM name '%s', type '%s'", net_name, net_type)
+        #self.logger.debug(">>>>>>>>>>>>>>>>>> IP profile %s", str(ip_profile))
+        try:
+            new_net = None
             self._reload_connection()
             network_dict = {'name': net_name, 'admin_state_up': True}
             if net_type=="data" or net_type=="ptp":
                 if self.config.get('dataplane_physical_net') == None:
             self._reload_connection()
             network_dict = {'name': net_name, 'admin_state_up': True}
             if net_type=="data" or net_type=="ptp":
                 if self.config.get('dataplane_physical_net') == None:
-                    return -vimconn.HTTP_Bad_Request, "You must provide a 'dataplane_physical_net' at config value before creating sriov network "
-                    
+                    raise vimconn.vimconnConflictException("You must provide a 'dataplane_physical_net' at config value before creating sriov network")
                 network_dict["provider:physical_network"] = self.config['dataplane_physical_net'] #"physnet_sriov" #TODO physical
                 network_dict["provider:network_type"]     = "vlan"
                 if vlan!=None:
                     network_dict["provider:network_type"] = vlan
                 network_dict["provider:physical_network"] = self.config['dataplane_physical_net'] #"physnet_sriov" #TODO physical
                 network_dict["provider:network_type"]     = "vlan"
                 if vlan!=None:
                     network_dict["provider:network_type"] = vlan
-            network_dict["shared"]=public
+            network_dict["shared"]=shared
             new_net=self.neutron.create_network({'network':network_dict})
             #print new_net
             new_net=self.neutron.create_network({'network':network_dict})
             #print new_net
-            #create fake subnetwork
-            if not cidr:
-                cidr="192.168.111.0/24"
+            #create subnetwork, even if there is no profile
+            if not ip_profile:
+                ip_profile = {}
+            if 'subnet_address' not in ip_profile:
+                #Fake subnet is required
+                subnet_rand = random.randint(0, 255)
+                ip_profile['subnet_address'] = "192.168.{}.0/24".format(subnet_rand)
+            if 'ip_version' not in ip_profile: 
+                ip_profile['ip_version'] = "IPv4"
             subnet={"name":net_name+"-subnet",
                     "network_id": new_net["network"]["id"],
             subnet={"name":net_name+"-subnet",
                     "network_id": new_net["network"]["id"],
-                    "ip_version": 4,
-                    "cidr": cidr
+                    "ip_version": 4 if ip_profile['ip_version']=="IPv4" else 6,
+                    "cidr": ip_profile['subnet_address']
                     }
                     }
+            if 'gateway_address' in ip_profile:
+                subnet['gateway_ip'] = ip_profile['gateway_address']
+            if ip_profile.get('dns_address'):
+                #TODO: manage dns_address as a list of addresses separated by commas 
+                subnet['dns_nameservers'] = []
+                subnet['dns_nameservers'].append(ip_profile['dns_address'])
+            if 'dhcp_enabled' in ip_profile:
+                subnet['enable_dhcp'] = False if ip_profile['dhcp_enabled']=="false" else True
+            if 'dhcp_start_address' in ip_profile:
+                subnet['allocation_pools']=[]
+                subnet['allocation_pools'].append(dict())
+                subnet['allocation_pools'][0]['start'] = ip_profile['dhcp_start_address']
+            if 'dhcp_count' in ip_profile:
+                #parts = ip_profile['dhcp_start_address'].split('.')
+                #ip_int = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3])
+                ip_int = int(netaddr.IPAddress(ip_profile['dhcp_start_address']))
+                ip_int += ip_profile['dhcp_count'] - 1
+                ip_str = str(netaddr.IPAddress(ip_int))
+                subnet['allocation_pools'][0]['end'] = ip_str
+            #self.logger.debug(">>>>>>>>>>>>>>>>>> Subnet: %s", str(subnet))
             self.neutron.create_subnet({"subnet": subnet} )
             self.neutron.create_subnet({"subnet": subnet} )
-            return 1, new_net["network"]["id"]
-        except neExceptions.ConnectionFailed as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except (ksExceptions.ClientException, neExceptions.NeutronException) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "new_tenant_network " + error_text
-        return error_value, error_text
+            return new_net["network"]["id"]
+        except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
+            if new_net:
+                self.neutron.delete_network(new_net['network']['id'])
+            self._format_exception(e)
 
     def get_network_list(self, filter_dict={}):
         '''Obtain tenant networks of VIM
 
     def get_network_list(self, filter_dict={}):
         '''Obtain tenant networks of VIM
@@ -306,60 +357,43 @@ class vimconnector(vimconn.vimconnector):
             status: 'ACTIVE'
         Returns the network list of dictionaries
         '''
             status: 'ACTIVE'
         Returns the network list of dictionaries
         '''
-        if self.debug:
-            print "osconnector.get_network_list(): Getting network from VIM (filter: " + str(filter_dict) + "): "
+        self.logger.debug("Getting network from VIM filter: '%s'", str(filter_dict))
         try:
             self._reload_connection()
         try:
             self._reload_connection()
+            if self.osc_api_version == 'v3.3' and "tenant_id" in filter_dict:
+                filter_dict['project_id'] = filter_dict.pop('tenant_id')
             net_dict=self.neutron.list_networks(**filter_dict)
             net_list=net_dict["networks"]
             self.__net_os2mano(net_list)
             net_dict=self.neutron.list_networks(**filter_dict)
             net_list=net_dict["networks"]
             self.__net_os2mano(net_list)
-            return 1, net_list
-        except neClient.exceptions.ConnectionFailed as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except (ksExceptions.ClientException, neExceptions.NeutronException) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "get_network_list " + error_text
-        return error_value, error_text
+            return net_list
+        except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
+            self._format_exception(e)
 
 
-    def get_tenant_network(self, net_id, tenant_id=None):
-        '''Obtain tenant networks of VIM'''
-        '''Returns the network information from a network id'''
-        if self.debug:
-            print "osconnector.get_tenant_network(): Getting tenant network %s from VIM" % net_id
+    def get_network(self, net_id):
+        '''Obtain details of network from VIM
+        Returns the network information from a network id'''
+        self.logger.debug(" Getting tenant network %s from VIM", net_id)
         filter_dict={"id": net_id}
         filter_dict={"id": net_id}
-        if tenant_id:
-            filter_dict["tenant_id"] = tenant_id
-        r, net_list = self.get_network_list(filter_dict)
-        if r<0:
-            return r, net_list
+        net_list = self.get_network_list(filter_dict)
         if len(net_list)==0:
         if len(net_list)==0:
-            return -vimconn.HTTP_Not_Found, "Network '%s' not found" % net_id
+            raise vimconn.vimconnNotFoundException("Network '{}' not found".format(net_id))
         elif len(net_list)>1:
         elif len(net_list)>1:
-            return -vimconn.HTTP_Conflict, "Found more than one network with this criteria"
+            raise vimconn.vimconnConflictException("Found more than one network with this criteria")
         net = net_list[0]
         subnets=[]
         for subnet_id in net.get("subnets", () ):
             try:
                 subnet = self.neutron.show_subnet(subnet_id)
             except Exception as e:
         net = net_list[0]
         subnets=[]
         for subnet_id in net.get("subnets", () ):
             try:
                 subnet = self.neutron.show_subnet(subnet_id)
             except Exception as e:
-                error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-                print "osconnector.get_tenant_network(): Error getting subnet %s %s" % (net_id, error_text)
-                subnet = {"id": subnet_id, "fault": error_text}
+                self.logger.error("osconnector.get_network(): Error getting subnet %s %s" % (net_id, str(e)))
+                subnet = {"id": subnet_id, "fault": str(e)}
             subnets.append(subnet)
         net["subnets"] = subnets
             subnets.append(subnet)
         net["subnets"] = subnets
-        return 1, net
-
+        return net
 
 
-    def delete_tenant_network(self, net_id):
-        '''Deletes a tenant network from VIM'''
-        '''Returns the network identifier'''
-        if self.debug:
-            print "osconnector: Deleting a new tenant network from VIM tenant: " + self.tenant + ", id: " + net_id
+    def delete_network(self, net_id):
+        '''Deletes a tenant network from VIM. Returns the old network identifier'''
+        self.logger.debug("Deleting network '%s' from VIM", net_id)
         try:
             self._reload_connection()
             #delete VM ports attached to this networks before the network
         try:
             self._reload_connection()
             #delete VM ports attached to this networks before the network
@@ -368,55 +402,114 @@ class vimconnector(vimconn.vimconnector):
                 try:
                     self.neutron.delete_port(p["id"])
                 except Exception as e:
                 try:
                     self.neutron.delete_port(p["id"])
                 except Exception as e:
-                    print "Error deleting port: " + type(e).__name__ + ": "+  str(e)
+                    self.logger.error("Error deleting port %s: %s", p["id"], str(e))
             self.neutron.delete_network(net_id)
             self.neutron.delete_network(net_id)
-            return 1, net_id
-        except neClient.exceptions.ConnectionFailed as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except neExceptions.NetworkNotFoundClient as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= type(e).__name__ + ": "+  str(e.args[0])
-        except (ksExceptions.ClientException, neExceptions.NeutronException) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "delete_tenant_network " + error_text
-        return error_value, error_text
+            return net_id
+        except (neExceptions.ConnectionFailed, neExceptions.NetworkNotFoundClient, neExceptions.NeutronException,
+                ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
+            self._format_exception(e)
 
 
-    def get_tenant_flavor(self, flavor_id):
-        '''Obtain flavor details from the  VIM
-            Returns the flavor dict details
-        '''
-        print "VIMConnector: Getting flavor from VIM"
+    def refresh_nets_status(self, net_list):
+        '''Get the status of the networks
+           Params: the list of network identifiers
+           Returns a dictionary with:
+                net_id:         #VIM id of this network
+                    status:     #Mandatory. Text with one of:
+                                #  DELETED (not found at vim)
+                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
+                                #  OTHER (Vim reported other status not understood)
+                                #  ERROR (VIM indicates an ERROR status)
+                                #  ACTIVE, INACTIVE, DOWN (admin down), 
+                                #  BUILD (on building process)
+                                #
+                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
+                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+
+        '''        
+        net_dict={}
+        for net_id in net_list:
+            net = {}
+            try:
+                net_vim = self.get_network(net_id)
+                if net_vim['status'] in netStatus2manoFormat:
+                    net["status"] = netStatus2manoFormat[ net_vim['status'] ]
+                else:
+                    net["status"] = "OTHER"
+                    net["error_msg"] = "VIM status reported " + net_vim['status']
+                    
+                if net['status'] == "ACTIVE" and not net_vim['admin_state_up']:
+                    net['status'] = 'DOWN'
+                try:
+                    net['vim_info'] = yaml.safe_dump(net_vim, default_flow_style=True, width=256)
+                except yaml.representer.RepresenterError:
+                    net['vim_info'] = str(net_vim)
+                if net_vim.get('fault'):  #TODO
+                    net['error_msg'] = str(net_vim['fault'])
+            except vimconn.vimconnNotFoundException as e:
+                self.logger.error("Exception getting net status: %s", str(e))
+                net['status'] = "DELETED"
+                net['error_msg'] = str(e)
+            except vimconn.vimconnException as e:
+                self.logger.error("Exception getting net status: %s", str(e))
+                net['status'] = "VIM_ERROR"
+                net['error_msg'] = str(e)
+            net_dict[net_id] = net
+        return net_dict
+
+    def get_flavor(self, flavor_id):
+        '''Obtain flavor details from the  VIM. Returns the flavor dict details'''
+        self.logger.debug("Getting flavor '%s'", flavor_id)
         try:
             self._reload_connection()
             flavor = self.nova.flavors.find(id=flavor_id)
             #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
         try:
             self._reload_connection()
             flavor = self.nova.flavors.find(id=flavor_id)
             #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
-            return 1, {"flavor": flavor.to_dict()}
-        except nvExceptions.NotFound as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= "flavor instance %s not found" % flavor_id
-        except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "get_tenant_flavor " + error_text
-        return error_value, error_text        
+            return flavor.to_dict()
+        except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
+            self._format_exception(e)
+
+    def get_flavor_id_from_data(self, flavor_dict):
+        """Obtain flavor id that match the flavor description
+           Returns the flavor_id or raises a vimconnNotFoundException
+        """
+        try:
+            self._reload_connection()
+            numa=None
+            numas = flavor_dict.get("extended",{}).get("numas")
+            if numas:
+                #TODO
+                raise vimconn.vimconnNotFoundException("Flavor with EPA still not implemted")
+                # if len(numas) > 1:
+                #     raise vimconn.vimconnNotFoundException("Cannot find any flavor with more than one numa")
+                # numa=numas[0]
+                # numas = extended.get("numas")
+            for flavor in self.nova.flavors.list():
+                epa = flavor.get_keys()
+                if epa:
+                    continue
+                    #TODO 
+                if flavor.ram != flavor_dict["ram"]:
+                    continue
+                if flavor.vcpus != flavor_dict["vcpus"]:
+                    continue
+                if flavor.disk != flavor_dict["disk"]:
+                    continue
+                return flavor.id
+            raise vimconn.vimconnNotFoundException("Cannot find any flavor matching '{}'".format(str(flavor_dict)))
+        except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
+            self._format_exception(e)
 
 
-    def new_tenant_flavor(self, flavor_dict, change_name_if_used=True):
+
+    def new_flavor(self, flavor_data, change_name_if_used=True):
         '''Adds a tenant flavor to openstack VIM
         '''Adds a tenant flavor to openstack VIM
-        if change_name_if_used is True, it will change name in case of conflict
+        if change_name_if_used is True, it will change name in case of conflict, because it is not supported name repetition
         Returns the flavor identifier
         '''
         Returns the flavor identifier
         '''
+        self.logger.debug("Adding flavor '%s'", str(flavor_data))
         retry=0
         retry=0
+        max_retries=3
         name_suffix = 0
         name_suffix = 0
-        name=flavor_dict['name']
-        while retry<2:
+        name=flavor_data['name']
+        while retry<max_retries:
             retry+=1
             try:
                 self._reload_connection()
             retry+=1
             try:
                 self._reload_connection()
@@ -428,13 +521,13 @@ class vimconnector(vimconn.vimconnector):
                         fl_names.append(f.name)
                     while name in fl_names:
                         name_suffix += 1
                         fl_names.append(f.name)
                     while name in fl_names:
                         name_suffix += 1
-                        name = flavor_dict['name']+"-" + str(name_suffix)
+                        name = flavor_data['name']+"-" + str(name_suffix)
                         
                         
-                ram = flavor_dict.get('ram',64)
-                vcpus = flavor_dict.get('vcpus',1)
+                ram = flavor_data.get('ram',64)
+                vcpus = flavor_data.get('vcpus',1)
                 numa_properties=None
 
                 numa_properties=None
 
-                extended=flavor_dict.get("extended")
+                extended = flavor_data.get("extended")
                 if extended:
                     numas=extended.get("numas")
                     if numas:
                 if extended:
                     numas=extended.get("numas")
                     if numas:
@@ -459,83 +552,61 @@ class vimconnector(vimconn.vimconnector):
                                 numa_properties["hw:cpu_policy"] = "isolated"
                             for interface in numa.get("interfaces",() ):
                                 if interface["dedicated"]=="yes":
                                 numa_properties["hw:cpu_policy"] = "isolated"
                             for interface in numa.get("interfaces",() ):
                                 if interface["dedicated"]=="yes":
-                                    error_value=-vimconn.HTTP_Bad_Request
-                                    error_text= "Passthrough interfaces are not supported for the openstack connector"
-                                    break
+                                    raise vimconn.vimconnException("Passthrough interfaces are not supported for the openstack connector", http_code=vimconn.HTTP_Service_Unavailable)
                                 #TODO, add the key 'pci_passthrough:alias"="<label at config>:<number ifaces>"' when a way to connect it is available
                                 
                 #create flavor                 
                 new_flavor=self.nova.flavors.create(name, 
                                 ram, 
                                 vcpus, 
                                 #TODO, add the key 'pci_passthrough:alias"="<label at config>:<number ifaces>"' when a way to connect it is available
                                 
                 #create flavor                 
                 new_flavor=self.nova.flavors.create(name, 
                                 ram, 
                                 vcpus, 
-                                flavor_dict.get('disk',1),
-                                is_public=flavor_dict.get('is_public', True)
+                                flavor_data.get('disk',1),
+                                is_public=flavor_data.get('is_public', True)
                             ) 
                 #add metadata
                 if numa_properties:
                     new_flavor.set_keys(numa_properties)
                             ) 
                 #add metadata
                 if numa_properties:
                     new_flavor.set_keys(numa_properties)
-                return 1, new_flavor.id
+                return new_flavor.id
             except nvExceptions.Conflict as e:
             except nvExceptions.Conflict as e:
-                error_value=-vimconn.HTTP_Conflict
-                error_text= str(e)
-                if change_name_if_used:
+                if change_name_if_used and retry < max_retries:
                     continue
                     continue
-                break
+                self._format_exception(e)
             #except nvExceptions.BadRequest as e:
             except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
             #except nvExceptions.BadRequest as e:
             except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
-                error_value=-vimconn.HTTP_Bad_Request
-                error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-                break
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "new_tenant_flavor " + error_text
-        return error_value, error_text
+                self._format_exception(e)
 
 
-    def delete_tenant_flavor(self,flavor_id):
-        '''Deletes a tenant flavor from openstack VIM
-           Returns >0,id if ok; or <0,error_text if error
+    def delete_flavor(self,flavor_id):
+        '''Deletes a tenant flavor from openstack VIM. Returns the old flavor_id
         '''
         '''
-        retry=0
-        while retry<2:
-            retry+=1
-            try:
-                self._reload_connection()
-                self.nova.flavors.delete(flavor_id)
-                return 1, flavor_id
-            except nvExceptions.NotFound as e:
-                error_value = -vimconn.HTTP_Not_Found
-                error_text  = "flavor '%s' not found" % flavor_id
-                break
-            #except nvExceptions.BadRequest as e:
-            except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
-                error_value=-vimconn.HTTP_Bad_Request
-                error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-                break
-        if self.debug:
-            print "delete_tenant_flavor " + error_text
-        #if reaching here is because an exception
-        return error_value, error_text
+        try:
+            self._reload_connection()
+            self.nova.flavors.delete(flavor_id)
+            return flavor_id
+        #except nvExceptions.BadRequest as e:
+        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
+            self._format_exception(e)
 
 
-    def new_tenant_image(self,image_dict):
+    def new_image(self,image_dict):
         '''
         '''
-        Adds a tenant image to VIM
-        if change_name_if_used is True, it will change name in case of conflict
-        Returns:
-            >1, image-id        if the image is created
-            <0, message          if there is an error
+        Adds a tenant image to VIM. imge_dict is a dictionary with:
+            name: name
+            disk_format: qcow2, vhd, vmdk, raw (by default), ...
+            location: path or URI
+            public: "yes" or "no"
+            metadata: metadata of the image
+        Returns the image_id
         '''
         '''
-        retry=0
         #using version 1 of glance client
         glancev1 = gl1Client.Client('1',self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds)  #TODO check k_creds vs n_creds
         #using version 1 of glance client
         glancev1 = gl1Client.Client('1',self.glance_endpoint, token=self.keystone.auth_token, **self.k_creds)  #TODO check k_creds vs n_creds
-        while retry<2:
+        retry=0
+        max_retries=3
+        while retry<max_retries:
             retry+=1
             try:
                 self._reload_connection()
                 #determine format  http://docs.openstack.org/developer/glance/formats.html
                 if "disk_format" in image_dict:
                     disk_format=image_dict["disk_format"]
             retry+=1
             try:
                 self._reload_connection()
                 #determine format  http://docs.openstack.org/developer/glance/formats.html
                 if "disk_format" in image_dict:
                     disk_format=image_dict["disk_format"]
-                else: #autodiscover base on extention
+                else: #autodiscover based on extension
                     if image_dict['location'][-6:]==".qcow2":
                         disk_format="qcow2"
                     elif image_dict['location'][-4:]==".vhd":
                     if image_dict['location'][-6:]==".qcow2":
                         disk_format="qcow2"
                     elif image_dict['location'][-4:]==".vhd":
@@ -554,7 +625,7 @@ class vimconnector(vimconn.vimconnector):
                         disk_format="ami"
                     else:
                         disk_format="raw"
                         disk_format="ami"
                     else:
                         disk_format="raw"
-                print "new_tenant_image: '%s' loading from '%s'" % (image_dict['name'], image_dict['location'])
+                self.logger.debug("new_image: '%s' loading from '%s'", image_dict['name'], image_dict['location'])
                 if image_dict['location'][0:4]=="http":
                     new_image = glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
                             container_format="bare", location=image_dict['location'], disk_format=disk_format)
                 if image_dict['location'][0:4]=="http":
                     new_image = glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
                             container_format="bare", location=image_dict['location'], disk_format=disk_format)
@@ -570,55 +641,69 @@ class vimconnector(vimconn.vimconnector):
                 if metadata_to_load:
                     for k,v in yaml.load(metadata_to_load).iteritems():
                         new_image_nova.metadata.setdefault(k,v)
                 if metadata_to_load:
                     for k,v in yaml.load(metadata_to_load).iteritems():
                         new_image_nova.metadata.setdefault(k,v)
-                return 1, new_image.id
-            except nvExceptions.Conflict as e:
-                error_value=-vimconn.HTTP_Conflict
-                error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-                break
-            except (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError) as e:
-                error_value=-vimconn.HTTP_Bad_Request
-                error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-                continue
+                return new_image.id
+            except (nvExceptions.Conflict, ksExceptions.ClientException, nvExceptions.ClientException) as e:
+                self._format_exception(e)
+            except (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError, ConnectionError) as e:
+                if retry==max_retries:
+                    continue
+                self._format_exception(e)
             except IOError as e:  #can not open the file
             except IOError as e:  #can not open the file
-                error_value=-vimconn.HTTP_Bad_Request
-                error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0])) + " for " + image_dict['location']
-                break
-            except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
-                error_value=-vimconn.HTTP_Bad_Request
-                error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-                break
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "new_tenant_image " + error_text
-        return error_value, error_text
+                raise vimconn.vimconnConnectionException(type(e).__name__ + ": " + str(e)+ " for " + image_dict['location'],
+                                                         http_code=vimconn.HTTP_Bad_Request)
      
      
-    def delete_tenant_image(self, image_id):
-        '''Deletes a tenant image from openstack VIM
-        Returns >0,id if ok; or <0,error_text if error
+    def delete_image(self, image_id):
+        '''Deletes a tenant image from openstack VIM. Returns the old id
         '''
         '''
-        retry=0
-        while retry<2:
-            retry+=1
-            try:
-                self._reload_connection()
-                self.nova.images.delete(image_id)
-                return 1, image_id
-            except nvExceptions.NotFound as e:
-                error_value = -vimconn.HTTP_Not_Found
-                error_text  = "flavor '%s' not found" % image_id
-                break
-            #except nvExceptions.BadRequest as e:
-            except (ksExceptions.ClientException, nvExceptions.ClientException) as e: #TODO remove
-                error_value=-vimconn.HTTP_Bad_Request
-                error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-                break
-        if self.debug:
-            print "delete_tenant_image " + error_text
-        #if reaching here is because an exception
-        return error_value, error_text
+        try:
+            self._reload_connection()
+            self.nova.images.delete(image_id)
+            return image_id
+        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e: #TODO remove
+            self._format_exception(e)
+
+    def get_image_id_from_path(self, path):
+        '''Get the image id from image path in the VIM database. Returns the image_id''' 
+        try:
+            self._reload_connection()
+            images = self.nova.images.list()
+            for image in images:
+                if image.metadata.get("location")==path:
+                    return image.id
+            raise vimconn.vimconnNotFoundException("image with location '{}' not found".format( path))
+        except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
+            self._format_exception(e)
         
         
-    def new_tenant_vminstance(self,name,description,start,image_id,flavor_id,net_list):
+    def get_image_list(self, filter_dict={}):
+        '''Obtain tenant images from VIM
+        Filter_dict can be:
+            id: image id
+            name: image name
+            checksum: image checksum
+        Returns the image list of dictionaries:
+            [{<the fields at Filter_dict plus some VIM specific>}, ...]
+            List can be empty
+        '''
+        self.logger.debug("Getting image list from VIM filter: '%s'", str(filter_dict))
+        try:
+            self._reload_connection()
+            filter_dict_os=filter_dict.copy()
+            #First we filter by the available filter fields: name, id. The others are removed.
+            filter_dict_os.pop('checksum',None)
+            image_list=self.nova.images.findall(**filter_dict_os)
+            if len(image_list)==0:
+                return []
+            #Then we filter by the rest of filter fields: checksum
+            filtered_list = []
+            for image in image_list:
+                image_class=self.glance.images.get(image.id)
+                if 'checksum' not in filter_dict or image_class['checksum']==filter_dict.get('checksum'):
+                    filtered_list.append(image_class.copy())
+            return filtered_list
+        except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
+            self._format_exception(e)
+
+    def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None,disk_list=None):
         '''Adds a VM instance to VIM
         Params:
             start: indicates if VM must start or boot in pause mode. Ignored
         '''Adds a VM instance to VIM
         Params:
             start: indicates if VM must start or boot in pause mode. Ignored
@@ -632,118 +717,264 @@ class vimconnector(vimconn.vimconnector):
                 use: 'data', 'bridge',  'mgmt'
                 type: 'virtual', 'PF', 'VF', 'VFnotShared'
                 vim_id: filled/added by this function
                 use: 'data', 'bridge',  'mgmt'
                 type: 'virtual', 'PF', 'VF', 'VFnotShared'
                 vim_id: filled/added by this function
+                floating_ip: True/False (or it can be None)
                 #TODO ip, security groups
                 #TODO ip, security groups
-        Returns >=0, the instance identifier
-                <0, error_text
+        Returns the instance identifier
         '''
         '''
-        if self.debug:
-            print "osconnector: Creating VM into VIM"
-            print "   image %s  flavor %s   nics=%s" %(image_id, flavor_id,net_list)
+        self.logger.debug("new_vminstance input: image='%s' flavor='%s' nics='%s'",image_id, flavor_id,str(net_list))
         try:
         try:
-            metadata=[]
+            metadata={}
             net_list_vim=[]
             net_list_vim=[]
+            external_network=[] #list of external networks to be connected to instance, later on used to create floating_ip
             self._reload_connection()
             self._reload_connection()
-            metadata_vpci={}
+            metadata_vpci={} #For a specific neutron plugin 
             for net in net_list:
                 if not net.get("net_id"): #skip non connected iface
                     continue
             for net in net_list:
                 if not net.get("net_id"): #skip non connected iface
                     continue
-                if net["type"]=="virtual":
-                    net_list_vim.append({'net-id': net["net_id"]})
-                    if "vpci" in net:
-                        metadata_vpci[ net["net_id"] ] = [[ net["vpci"], "" ]]
-                elif net["type"]=="PF":
-                    print "new_tenant_vminstance: Warning, can not connect a passthrough interface "
-                    #TODO insert this when openstack consider passthrough ports as openstack neutron ports
-                else: #VF
-                    if "vpci" in net:
-                        if "VF" not in metadata_vpci:
-                            metadata_vpci["VF"]=[]
-                        metadata_vpci["VF"].append([ net["vpci"], "" ])
+                if net["type"]=="virtual" or net["type"]=="VF":
                     port_dict={
                     port_dict={
-                         "network_id": net["net_id"],
-                         "name": net.get("name"),
-                         "binding:vnic_type": "direct", 
-                         "admin_state_up": True
-                    }
+                        "network_id": net["net_id"],
+                        "name": net.get("name"),
+                        "admin_state_up": True
+                    }    
+                    if net["type"]=="virtual":
+                        if "vpci" in net:
+                            metadata_vpci[ net["net_id"] ] = [[ net["vpci"], "" ]]
+                    else: # for VF
+                        if "vpci" in net:
+                            if "VF" not in metadata_vpci:
+                                metadata_vpci["VF"]=[]
+                            metadata_vpci["VF"].append([ net["vpci"], "" ])
+                        port_dict["binding:vnic_type"]="direct"
                     if not port_dict["name"]:
                     if not port_dict["name"]:
-                        port_dict["name"] = name
+                        port_dict["name"]=name
                     if net.get("mac_address"):
                         port_dict["mac_address"]=net["mac_address"]
                     if net.get("mac_address"):
                         port_dict["mac_address"]=net["mac_address"]
-                    #TODO: manage having SRIOV without vlan tag
-                    #if net["type"] == "VFnotShared"
-                    #    port_dict["vlan"]=0
+                    if net.get("port_security") == False:
+                        port_dict["port_security_enabled"]=net["port_security"]
                     new_port = self.neutron.create_port({"port": port_dict })
                     net["mac_adress"] = new_port["port"]["mac_address"]
                     net["vim_id"] = new_port["port"]["id"]
                     new_port = self.neutron.create_port({"port": port_dict })
                     net["mac_adress"] = new_port["port"]["mac_address"]
                     net["vim_id"] = new_port["port"]["id"]
-                    net["ip"] = new_port["port"].get("fixed_ips",[{}])[0].get("ip_address")
+                    net["ip"] = new_port["port"].get("fixed_ips", [{}])[0].get("ip_address")
                     net_list_vim.append({"port-id": new_port["port"]["id"]})
                     net_list_vim.append({"port-id": new_port["port"]["id"]})
+                else:   # for PF
+                    self.logger.warn("new_vminstance: Warning, can not connect a passthrough interface ")
+                    #TODO insert this when openstack consider passthrough ports as openstack neutron ports
+                if net.get('floating_ip', False):
+                    net['exit_on_floating_ip_error'] = True
+                    external_network.append(net)
+                elif net['use'] == 'mgmt' and self.config.get('use_floating_ip'):
+                    net['exit_on_floating_ip_error'] = False
+                    external_network.append(net)
+
             if metadata_vpci:
                 metadata = {"pci_assignement": json.dumps(metadata_vpci)}
             if metadata_vpci:
                 metadata = {"pci_assignement": json.dumps(metadata_vpci)}
+                if len(metadata["pci_assignement"]) >255:
+                    #limit the metadata size
+                    #metadata["pci_assignement"] = metadata["pci_assignement"][0:255]
+                    self.logger.warn("Metadata deleted since it exceeds the expected length (255) ")
+                    metadata = {}
             
             
-            print "name '%s' image_id '%s'flavor_id '%s' net_list_vim '%s' description '%s' metadata %s"\
-                 % (name, image_id, flavor_id, str(net_list_vim), description, str(metadata))
+            self.logger.debug("name '%s' image_id '%s'flavor_id '%s' net_list_vim '%s' description '%s' metadata %s",
+                              name, image_id, flavor_id, str(net_list_vim), description, str(metadata))
             
             security_groups   = self.config.get('security_groups')
             if type(security_groups) is str:
                 security_groups = ( security_groups, )
             
             security_groups   = self.config.get('security_groups')
             if type(security_groups) is str:
                 security_groups = ( security_groups, )
+            #cloud config
+            userdata=None
+            config_drive = None
+            if isinstance(cloud_config, dict):
+                if cloud_config.get("user-data"):
+                    userdata=cloud_config["user-data"]
+                if cloud_config.get("boot-data-drive") != None:
+                    config_drive = cloud_config["boot-data-drive"]
+                if cloud_config.get("config-files") or cloud_config.get("users") or cloud_config.get("key-pairs"):
+                    if userdata:
+                        raise vimconn.vimconnConflictException("Cloud-config cannot contain both 'userdata' and 'config-files'/'users'/'key-pairs'")
+                    userdata_dict={}
+                    #default user
+                    if cloud_config.get("key-pairs"):
+                        userdata_dict["ssh-authorized-keys"] = cloud_config["key-pairs"]
+                        userdata_dict["users"] = [{"default": None, "ssh-authorized-keys": cloud_config["key-pairs"] }]
+                    if cloud_config.get("users"):
+                        if "users" not in userdata_dict:
+                            userdata_dict["users"] = [ "default" ]
+                        for user in cloud_config["users"]:
+                            user_info = {
+                                "name" : user["name"],
+                                "sudo": "ALL = (ALL)NOPASSWD:ALL"
+                            }
+                            if "user-info" in user:
+                                user_info["gecos"] = user["user-info"]
+                            if user.get("key-pairs"):
+                                user_info["ssh-authorized-keys"] = user["key-pairs"]
+                            userdata_dict["users"].append(user_info)
+
+                    if cloud_config.get("config-files"):
+                        userdata_dict["write_files"] = []
+                        for file in cloud_config["config-files"]:
+                            file_info = {
+                                "path" : file["dest"],
+                                "content": file["content"]
+                            }
+                            if file.get("encoding"):
+                                file_info["encoding"] = file["encoding"]
+                            if file.get("permissions"):
+                                file_info["permissions"] = file["permissions"]
+                            if file.get("owner"):
+                                file_info["owner"] = file["owner"]
+                            userdata_dict["write_files"].append(file_info)
+                    userdata = "#cloud-config\n"
+                    userdata += yaml.safe_dump(userdata_dict, indent=4, default_flow_style=False)
+                self.logger.debug("userdata: %s", userdata)
+            elif isinstance(cloud_config, str):
+                userdata = cloud_config
+
+            #Create additional volumes in case these are present in disk_list
+            block_device_mapping = None
+            base_disk_index = ord('b')
+            if disk_list != None:
+                block_device_mapping = dict()
+                for disk in disk_list:
+                    if 'image_id' in disk:
+                        volume = self.cinder.volumes.create(size = disk['size'],name = name + '_vd' +
+                                    chr(base_disk_index), imageRef = disk['image_id'])
+                    else:
+                        volume = self.cinder.volumes.create(size=disk['size'], name=name + '_vd' +
+                                    chr(base_disk_index))
+                    block_device_mapping['_vd' +  chr(base_disk_index)] = volume.id
+                    base_disk_index += 1
+
+                #wait until volumes are with status available
+                keep_waiting = True
+                elapsed_time = 0
+                while keep_waiting and elapsed_time < volume_timeout:
+                    keep_waiting = False
+                    for volume_id in block_device_mapping.itervalues():
+                        if self.cinder.volumes.get(volume_id).status != 'available':
+                            keep_waiting = True
+                    if keep_waiting:
+                        time.sleep(1)
+                        elapsed_time += 1
+
+                #if we exceeded the timeout rollback
+                if elapsed_time >= volume_timeout:
+                    #delete the volumes we just created
+                    for volume_id in block_device_mapping.itervalues():
+                        self.cinder.volumes.delete(volume_id)
+
+                    #delete ports we just created
+                    for net_item  in net_list_vim:
+                        if 'port-id' in net_item:
+                            self.neutron.delete_port(net_item['port-id'])
+
+                    raise vimconn.vimconnException('Timeout creating volumes for instance ' + name,
+                                                   http_code=vimconn.HTTP_Request_Timeout)
+
             server = self.nova.servers.create(name, image_id, flavor_id, nics=net_list_vim, meta=metadata,
             server = self.nova.servers.create(name, image_id, flavor_id, nics=net_list_vim, meta=metadata,
-                                              security_groups   = security_groups,
-                                              availability_zone = self.config.get('availability_zone'),
-                                              key_name          = self.config.get('keypair'),
-                                        ) #, description=description)
-            
-            
-            print "DONE :-)", server
-            
-#             #TODO   server.add_floating_ip("10.95.87.209")
-#             #To look for a free floating_ip
-#             free_floating_ip = None
-#             for floating_ip in self.neutron.list_floatingips().get("floatingips", () ):
-#                 if not floating_ip["port_id"]:
-#                     free_floating_ip = floating_ip["floating_ip_address"]
-#                     break
-#             if free_floating_ip:
-#                 server.add_floating_ip(free_floating_ip)
-                
-            
-            return 1, server.id
+                                              security_groups=security_groups,
+                                              availability_zone=self.config.get('availability_zone'),
+                                              key_name=self.config.get('keypair'),
+                                              userdata=userdata,
+                                              config_drive = config_drive,
+                                              block_device_mapping = block_device_mapping
+                                              )  # , description=description)
+            #print "DONE :-)", server
+            pool_id = None
+            floating_ips = self.neutron.list_floatingips().get("floatingips", ())
+            for floating_network in external_network:
+                try:
+                    # wait until vm is active
+                    elapsed_time = 0
+                    while elapsed_time < server_timeout:
+                        status = self.nova.servers.get(server.id).status
+                        if status == 'ACTIVE':
+                            break
+                        time.sleep(1)
+                        elapsed_time += 1
+
+                    #if we exceeded the timeout rollback
+                    if elapsed_time >= server_timeout:
+                        raise vimconn.vimconnException('Timeout creating instance ' + name,
+                                                       http_code=vimconn.HTTP_Request_Timeout)
+
+                    assigned = False
+                    while(assigned == False):
+                        if floating_ips:
+                            ip = floating_ips.pop(0)
+                            if not ip.get("port_id", False) and ip.get('tenant_id') == server.tenant_id:
+                                free_floating_ip = ip.get("floating_ip_address")
+                                try:
+                                    fix_ip = floating_network.get('ip')
+                                    server.add_floating_ip(free_floating_ip, fix_ip)
+                                    assigned = True
+                                except Exception as e:
+                                    raise vimconn.vimconnException(type(e).__name__ + ": Cannot create floating_ip "+  str(e), http_code=vimconn.HTTP_Conflict)
+                        else:
+                            #Find the external network
+                            external_nets = list()
+                            for net in self.neutron.list_networks()['networks']:
+                                if net['router:external']:
+                                        external_nets.append(net)
+
+                            if len(external_nets) == 0:
+                                raise vimconn.vimconnException("Cannot create floating_ip automatically since no external "
+                                                               "network is present",
+                                                                http_code=vimconn.HTTP_Conflict)
+                            if len(external_nets) > 1:
+                                raise vimconn.vimconnException("Cannot create floating_ip automatically since multiple "
+                                                               "external networks are present",
+                                                               http_code=vimconn.HTTP_Conflict)
+
+                            pool_id = external_nets[0].get('id')
+                            param = {'floatingip': {'floating_network_id': pool_id, 'tenant_id': server.tenant_id}}
+                            try:
+                                #self.logger.debug("Creating floating IP")
+                                new_floating_ip = self.neutron.create_floatingip(param)
+                                free_floating_ip = new_floating_ip['floatingip']['floating_ip_address']
+                                fix_ip = floating_network.get('ip')
+                                server.add_floating_ip(free_floating_ip, fix_ip)
+                                assigned=True
+                            except Exception as e:
+                                raise vimconn.vimconnException(type(e).__name__ + ": Cannot assign floating_ip "+  str(e), http_code=vimconn.HTTP_Conflict)
+                except Exception as e:
+                    if not floating_network['exit_on_floating_ip_error']:
+                        self.logger.warn("Cannot create floating_ip. %s", str(e))
+                        continue
+                    self.delete_vminstance(server.id)
+                    raise
+
+            return server.id
 #        except nvExceptions.NotFound as e:
 #            error_value=-vimconn.HTTP_Not_Found
 #            error_text= "vm instance %s not found" % vm_id
 #        except nvExceptions.NotFound as e:
 #            error_value=-vimconn.HTTP_Not_Found
 #            error_text= "vm instance %s not found" % vm_id
-        except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError, TypeError) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        except neClient.exceptions.ConnectionFailed as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "new_tenant_vminstance Exception",e, error_text
-        return error_value, error_text    
+        except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
+            # delete the volumes we just created
+            if block_device_mapping != None:
+                for volume_id in block_device_mapping.itervalues():
+                    self.cinder.volumes.delete(volume_id)
 
 
-    def get_tenant_vminstance(self,vm_id):
+            # delete ports we just created
+            for net_item in net_list_vim:
+                if 'port-id' in net_item:
+                    self.neutron.delete_port(net_item['port-id'])
+            self._format_exception(e)
+        except TypeError as e:
+            raise vimconn.vimconnException(type(e).__name__ + ": "+  str(e), http_code=vimconn.HTTP_Bad_Request)
+
+    def get_vminstance(self,vm_id):
         '''Returns the VM instance information from VIM'''
         '''Returns the VM instance information from VIM'''
-        if self.debug:
-            print "osconnector: Getting VM from VIM"
+        #self.logger.debug("Getting VM from VIM")
         try:
             self._reload_connection()
             server = self.nova.servers.find(id=vm_id)
             #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
         try:
             self._reload_connection()
             server = self.nova.servers.find(id=vm_id)
             #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
-            return 1, {"server": server.to_dict()}
-        except nvExceptions.NotFound as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= "vm instance %s not found" % vm_id
-        except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "get_tenant_vminstance " + error_text
-        return error_value, error_text        
-                
-    def get_tenant_vminstance_console(self,vm_id, console_type="vnc"):
+            return server.to_dict()
+        except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e:
+            self._format_exception(e)
+
+    def get_vminstance_console(self,vm_id, console_type="vnc"):
         '''
         Get a console for the virtual machine
         Params:
         '''
         Get a console for the virtual machine
         Params:
@@ -751,11 +982,13 @@ class vimconnector(vimconn.vimconnector):
             console_type, can be:
                 "novnc" (by default), "xvpvnc" for VNC types, 
                 "rdp-html5" for RDP types, "spice-html5" for SPICE types
             console_type, can be:
                 "novnc" (by default), "xvpvnc" for VNC types, 
                 "rdp-html5" for RDP types, "spice-html5" for SPICE types
-        Returns <0, text on error, for example not available
-                1, URL/text with the console parameters
+        Returns dict with the console parameters:
+                protocol: ssh, ftp, http, https, ...
+                server:   usually ip address 
+                port:     the http, ssh, ... port 
+                suffix:   extra text, e.g. the http path and query string   
         '''
         '''
-        if self.debug:
-            print "osconnector: Getting VM CONSOLE from VIM"
+        self.logger.debug("Getting VM CONSOLE from VIM")
         try:
             self._reload_connection()
             server = self.nova.servers.find(id=vm_id)
         try:
             self._reload_connection()
             server = self.nova.servers.find(id=vm_id)
@@ -768,7 +1001,7 @@ class vimconnector(vimconn.vimconnector):
             elif console_type == "spice-html5":
                 console_dict = server.get_spice_console(console_type)
             else:
             elif console_type == "spice-html5":
                 console_dict = server.get_spice_console(console_type)
             else:
-                return -vimconn.HTTP_Bad_Request, "console type '%s' not allowed" % console_type
+                raise vimconn.vimconnException("console type '{}' not allowed".format(console_type), http_code=vimconn.HTTP_Bad_Request)
             
             console_dict1 = console_dict.get("console")
             if console_dict1:
             
             console_dict1 = console_dict.get("console")
             if console_dict1:
@@ -786,31 +1019,16 @@ class vimconnector(vimconn.vimconnector):
                                   "suffix":   console_url[suffix_index+1:] 
                                   }
                     protocol_index += 2
                                   "suffix":   console_url[suffix_index+1:] 
                                   }
                     protocol_index += 2
-                    return 1, console_dict
-            return -vimconn.HTTP_Internal_Server_Error, "Unexpected response from VIM"
+                    return console_dict
+            raise vimconn.vimconnUnexpectedResponse("Unexpected response from VIM")
             
             
-            #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
-            return 1, {"server": server.to_dict()}
-        except nvExceptions.NotFound as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= "vm instance %s not found" % vm_id
-        except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.BadRequest) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        #TODO insert exception vimconn.HTTP_Unauthorized
-        #if reaching here is because an exception
-        if self.debug:
-            print "get_tenant_vminstance " + error_text
-        return error_value, error_text        
-
+        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.BadRequest, ConnectionError) as e:
+            self._format_exception(e)
 
 
-    def delete_tenant_vminstance(self, vm_id):
-        '''Removes a VM instance from VIM
-        Returns >0, the instance identifier
-                <0, error_text
+    def delete_vminstance(self, vm_id):
+        '''Removes a VM instance from VIM. Returns the old identifier
         '''
         '''
-        if self.debug:
-            print "osconnector: Getting VM from VIM"
+        #print "osconnector: Getting VM from VIM"
         try:
             self._reload_connection()
             #delete VM ports attached to this networks before the virtual machine
         try:
             self._reload_connection()
             #delete VM ports attached to this networks before the virtual machine
@@ -819,125 +1037,120 @@ class vimconnector(vimconn.vimconnector):
                 try:
                     self.neutron.delete_port(p["id"])
                 except Exception as e:
                 try:
                     self.neutron.delete_port(p["id"])
                 except Exception as e:
-                    print "Error deleting port: " + type(e).__name__ + ": "+  str(e)
+                    self.logger.error("Error deleting port: " + type(e).__name__ + ": "+  str(e))
+
+            #commented because detaching the volumes makes the servers.delete not work properly ?!?
+            #dettach volumes attached
+            server = self.nova.servers.get(vm_id)
+            volumes_attached_dict = server._info['os-extended-volumes:volumes_attached']
+            #for volume in volumes_attached_dict:
+            #    self.cinder.volumes.detach(volume['id'])
+
             self.nova.servers.delete(vm_id)
             self.nova.servers.delete(vm_id)
-            return 1, vm_id
-        except nvExceptions.NotFound as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= (str(e) if len(e.args)==0 else str(e.args[0]))
-        except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+
+            #delete volumes.
+            #Although having detached them should have them  in active status
+            #we ensure in this loop
+            keep_waiting = True
+            elapsed_time = 0
+            while keep_waiting and elapsed_time < volume_timeout:
+                keep_waiting = False
+                for volume in volumes_attached_dict:
+                    if self.cinder.volumes.get(volume['id']).status != 'available':
+                        keep_waiting = True
+                    else:
+                        self.cinder.volumes.delete(volume['id'])
+                if keep_waiting:
+                    time.sleep(1)
+                    elapsed_time += 1
+
+            return vm_id
+        except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
+            self._format_exception(e)
         #TODO insert exception vimconn.HTTP_Unauthorized
         #if reaching here is because an exception
         #TODO insert exception vimconn.HTTP_Unauthorized
         #if reaching here is because an exception
-        if self.debug:
-            print "get_tenant_vminstance " + error_text
-        return error_value, error_text        
 
 
-    def refresh_tenant_vms_and_nets(self, vmDict, netDict):
-        '''Refreshes the status of the dictionaries of VM instances and nets passed as arguments. It modifies the dictionaries
-        Returns:
-            - result: 0 if all elements could be refreshed (even if its status didn't change)
-                      n>0, the number of elements that couldn't be refreshed,
-                      <0 if error (foreseen)
-            - error_msg: text with reference to possible errors
+    def refresh_vms_status(self, vm_list):
+        '''Get the status of the virtual machines and their interfaces/ports
+           Params: the list of VM identifiers
+           Returns a dictionary with:
+                vm_id:          #VIM id of this Virtual Machine
+                    status:     #Mandatory. Text with one of:
+                                #  DELETED (not found at vim)
+                                #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...) 
+                                #  OTHER (Vim reported other status not understood)
+                                #  ERROR (VIM indicates an ERROR status)
+                                #  ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running), 
+                                #  CREATING (on building process), ERROR
+                                #  ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
+                                #
+                    error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR 
+                    vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+                    interfaces:
+                     -  vim_info:         #Text with plain information obtained from vim (yaml.safe_dump)
+                        mac_address:      #Text format XX:XX:XX:XX:XX:XX
+                        vim_net_id:       #network id where this interface is connected
+                        vim_interface_id: #interface/port VIM id
+                        ip_address:       #null, or text with IPv4, IPv6 address
         '''
         '''
-        #vms_refreshed = []
-        #nets_refreshed = []
-        vms_unrefreshed = []
-        nets_unrefreshed = []
-        if self.debug:
-            print "osconnector refresh_tenant_vms and nets: Getting tenant VM instance information from VIM"
-        for vm_id in vmDict:
-            vmDict[vm_id] = {'error_msg':None, 'vim_info':None}
-            r,c = self.get_tenant_vminstance(vm_id)
-            if r<0:
-                print "osconnector refresh_tenant_vm. Error getting vm_id '%s' status: %s" % (vm_id, c)
-                if r==-vimconn.HTTP_Not_Found:
-                    vmDict[vm_id]['status'] = "DELETED" 
+        vm_dict={}
+        self.logger.debug("refresh_vms status: Getting tenant VM instance information from VIM")
+        for vm_id in vm_list:
+            vm={}
+            try:
+                vm_vim = self.get_vminstance(vm_id)
+                if vm_vim['status'] in vmStatus2manoFormat:
+                    vm['status']    =  vmStatus2manoFormat[ vm_vim['status'] ]
                 else:
                 else:
-                    vmDict[vm_id]['status'] = "VIM_ERROR"
-                    vmDict[vm_id]['error_msg'] = c
-                    vms_unrefreshed.append(vm_id)
-            else:
+                    vm['status']    = "OTHER"
+                    vm['error_msg'] = "VIM status reported " + vm_vim['status']
                 try:
                 try:
-                    vmDict[vm_id]['status']    =  vmStatus2manoFormat[ c['server']['status'] ]
-                    vmDict[vm_id]['vim_info']  = yaml.safe_dump(c['server'])
-                    vmDict[vm_id]["interfaces"] = []
-                    if c['server'].get('fault'):
-                        vmDict[vm_id]['error_msg'] = str(c['server']['fault'])
-                    #get interfaces
-                    try:
-                        self._reload_connection()
-                        port_dict=self.neutron.list_ports(device_id=vm_id)
-                        for port in port_dict["ports"]:
-                            interface={}
-                            interface['vim_info']  = yaml.safe_dump(port)
-                            interface["mac_address"] = port.get("mac_address")
-                            interface["vim_net_id"] = port["network_id"]
-                            interface["vim_interface_id"] = port["id"]
-                            ips=[]
-                            #look for floating ip address
-                            floating_ip_dict = self.neutron.list_floatingips(port_id=port["id"])
-                            if floating_ip_dict.get("floatingips"):
-                                ips.append(floating_ip_dict["floatingips"][0].get("floating_ip_address") )
-
-                            for subnet in port["fixed_ips"]:
-                                ips.append(subnet["ip_address"])
-                            interface["ip_address"] = ";".join(ips)
-                            vmDict[vm_id]["interfaces"].append(interface)
-                    except Exception as e:
-                        print type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-                
-                    
-                    #error message at server.fault["message"]
-                except KeyError as e:
-                    print "osconnector refresh_tenant_elements KeyError %s getting vm_id '%s' status  %s" % (str(e), vm_id, c['server']['status'])
-                    vmDict[vm_id]['status'] = "VIM_ERROR"
-                    vmDict[vm_id]['error_msg'] = str(e)
-                    vms_unrefreshed.append(vm_id)
-        
-        #print "VMs refreshed: %s" % str(vms_refreshed)
-        for net_id in netDict:
-            netDict[net_id]={'error_msg':None, 'vim_info':None}
-            r,c = self.get_tenant_network(net_id)
-            if r<0:
-                print "osconnector refresh_tenant_network. Error getting net_id '%s' status: %s" % (net_id, c)
-                if r==-vimconn.HTTP_Not_Found:
-                    netDict[net_id]['status'] = "DELETED" #TODO check exit status
-                else:
-                    netDict[vm_id]['status'] = "VIM_ERROR"
-                    netDict[vm_id]['error_msg'] = c
-                    nets_unrefreshed.append(net_id)
-            else:
+                    vm['vim_info']  = yaml.safe_dump(vm_vim, default_flow_style=True, width=256)
+                except yaml.representer.RepresenterError:
+                    vm['vim_info'] = str(vm_vim)
+                vm["interfaces"] = []
+                if vm_vim.get('fault'):
+                    vm['error_msg'] = str(vm_vim['fault'])
+                #get interfaces
                 try:
                 try:
-                    netDict[net_id]['status'] = netStatus2manoFormat[ c['status'] ]
-                    if c['status'] == "ACIVE" and not c['admin_state_up']:
-                        netDict[net_id]['status'] = 'DOWN'
-                    netDict[net_id]['vim_info']  = yaml.safe_dump(c)
-                    if c.get('fault'):  #TODO
-                        netDict[net_id]['error_msg'] = str(c['fault'])
-                except KeyError as e:
-                    print "osconnector refresh_tenant_elements KeyError %s getting vm_id '%s' status  %s" % (str(e), vm_id, c['network']['status'])
-                    netDict[net_id]['status'] = "VIM_ERROR"
-                    netDict[net_id]['error_msg'] = str(e)
-                    nets_unrefreshed.append(net_id)
+                    self._reload_connection()
+                    port_dict=self.neutron.list_ports(device_id=vm_id)
+                    for port in port_dict["ports"]:
+                        interface={}
+                        try:
+                            interface['vim_info'] = yaml.safe_dump(port, default_flow_style=True, width=256)
+                        except yaml.representer.RepresenterError:
+                            interface['vim_info'] = str(port)
+                        interface["mac_address"] = port.get("mac_address")
+                        interface["vim_net_id"] = port["network_id"]
+                        interface["vim_interface_id"] = port["id"]
+                        ips=[]
+                        #look for floating ip address
+                        floating_ip_dict = self.neutron.list_floatingips(port_id=port["id"])
+                        if floating_ip_dict.get("floatingips"):
+                            ips.append(floating_ip_dict["floatingips"][0].get("floating_ip_address") )
 
 
-        #print "Nets refreshed: %s" % str(nets_refreshed)
-        
-        error_msg=""
-        if len(vms_unrefreshed)+len(nets_unrefreshed)>0:
-            error_msg += "VMs unrefreshed: " + str(vms_unrefreshed) + "; nets unrefreshed: " + str(nets_unrefreshed)
-            print error_msg
-
-        #return len(vms_unrefreshed)+len(nets_unrefreshed), error_msg, vms_refreshed, nets_refreshed
-        return len(vms_unrefreshed)+len(nets_unrefreshed), error_msg
+                        for subnet in port["fixed_ips"]:
+                            ips.append(subnet["ip_address"])
+                        interface["ip_address"] = ";".join(ips)
+                        vm["interfaces"].append(interface)
+                except Exception as e:
+                    self.logger.error("Error getting vm interface information " + type(e).__name__ + ": "+  str(e))
+            except vimconn.vimconnNotFoundException as e:
+                self.logger.error("Exception getting vm status: %s", str(e))
+                vm['status'] = "DELETED"
+                vm['error_msg'] = str(e)
+            except vimconn.vimconnException as e:
+                self.logger.error("Exception getting vm status: %s", str(e))
+                vm['status'] = "VIM_ERROR"
+                vm['error_msg'] = str(e)
+            vm_dict[vm_id] = vm
+        return vm_dict
     
     
-    def action_tenant_vminstance(self, vm_id, action_dict):
+    def action_vminstance(self, vm_id, action_dict):
         '''Send and action over a VM instance from VIM
         '''Send and action over a VM instance from VIM
-        Returns the status'''
-        if self.debug:
-            print "osconnector: Action over VM instance from VIM " + vm_id
+        Returns the vm_id if the action was successfully sent to the VIM'''
+        self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
         try:
             self._reload_connection()
             server = self.nova.servers.find(id=vm_id)
         try:
             self._reload_connection()
             server = self.nova.servers.find(id=vm_id)
@@ -984,8 +1197,8 @@ class vimconnector(vimconn.vimconnector):
                 elif console_type == "spice-html5":
                     console_dict = server.get_spice_console(console_type)
                 else:
                 elif console_type == "spice-html5":
                     console_dict = server.get_spice_console(console_type)
                 else:
-                    return -vimconn.HTTP_Bad_Request, "console type '%s' not allowed" % console_type
-                
+                    raise vimconn.vimconnException("console type '{}' not allowed".format(console_type), 
+                                                   http_code=vimconn.HTTP_Bad_Request)
                 try:
                     console_url = console_dict["console"]["url"]
                     #parse console_url
                 try:
                     console_url = console_dict["console"]["url"]
                     #parse console_url
@@ -993,32 +1206,80 @@ class vimconnector(vimconn.vimconnector):
                     suffix_index = console_url[protocol_index+2:].find("/") + protocol_index+2
                     port_index = console_url[protocol_index+2:suffix_index].find(":") + protocol_index+2
                     if protocol_index < 0 or port_index<0 or suffix_index<0:
                     suffix_index = console_url[protocol_index+2:].find("/") + protocol_index+2
                     port_index = console_url[protocol_index+2:suffix_index].find(":") + protocol_index+2
                     if protocol_index < 0 or port_index<0 or suffix_index<0:
-                        print "action_tenant_vminstance, console: response", str(console_dict)
-                        return -vimconn.HTTP_Internal_Server_Error, "Unexpected response from VIM"
+                        raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict))
                     console_dict2={"protocol": console_url[0:protocol_index],
                                   "server":   console_url[protocol_index+2 : port_index], 
                                   "port":     int(console_url[port_index+1 : suffix_index]), 
                                   "suffix":   console_url[suffix_index+1:] 
                                   }
                     console_dict2={"protocol": console_url[0:protocol_index],
                                   "server":   console_url[protocol_index+2 : port_index], 
                                   "port":     int(console_url[port_index+1 : suffix_index]), 
                                   "suffix":   console_url[suffix_index+1:] 
                                   }
-                    protocol_index += 2
-                    return 1, console_dict2               
-                except:
-                    print "action_tenant_vminstance, console: response", str(console_dict)
-                    return -vimconn.HTTP_Internal_Server_Error, "Unexpected response from VIM"
+                    return console_dict2               
+                except Exception as e:
+                    raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict))
             
             
-            return 1, vm_id
-        except nvExceptions.NotFound as e:
-            error_value=-vimconn.HTTP_Not_Found
-            error_text= (str(e) if len(e.args)==0 else str(e.args[0]))
-        except (ksExceptions.ClientException, nvExceptions.ClientException) as e:
+            return vm_id
+        except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e:
+            self._format_exception(e)
+        #TODO insert exception vimconn.HTTP_Unauthorized
+
+#NOT USED FUNCTIONS
+    
+    def new_external_port(self, port_data):
+        #TODO openstack if needed
+        '''Adds a external port to VIM'''
+        '''Returns the port identifier'''
+        return -vimconn.HTTP_Internal_Server_Error, "osconnector.new_external_port() not implemented" 
+        
+    def connect_port_network(self, port_id, network_id, admin=False):
+        #TODO openstack if needed
+        '''Connects a external port to a network'''
+        '''Returns status code of the VIM response'''
+        return -vimconn.HTTP_Internal_Server_Error, "osconnector.connect_port_network() not implemented" 
+    
+    def new_user(self, user_name, user_passwd, tenant_id=None):
+        '''Adds a new user to openstack VIM'''
+        '''Returns the user identifier'''
+        self.logger.debug("osconnector: Adding a new user to VIM")
+        try:
+            self._reload_connection()
+            user=self.keystone.users.create(user_name, user_passwd, tenant_id=tenant_id)
+            #self.keystone.tenants.add_user(self.k_creds["username"], #role)
+            return user.id
+        except ksExceptions.ConnectionError as e:
+            error_value=-vimconn.HTTP_Bad_Request
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        except ksExceptions.ClientException as e: #TODO remove
             error_value=-vimconn.HTTP_Bad_Request
             error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
         #TODO insert exception vimconn.HTTP_Unauthorized
         #if reaching here is because an exception
         if self.debug:
             error_value=-vimconn.HTTP_Bad_Request
             error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
         #TODO insert exception vimconn.HTTP_Unauthorized
         #if reaching here is because an exception
         if self.debug:
-            print "action_tenant_vminstance " + error_text
+            self.logger.debug("new_user " + error_text)
         return error_value, error_text        
         return error_value, error_text        
-        
+
+    def delete_user(self, user_id):
+        '''Delete a user from openstack VIM'''
+        '''Returns the user identifier'''
+        if self.debug:
+            print "osconnector: Deleting  a  user from VIM"
+        try:
+            self._reload_connection()
+            self.keystone.users.delete(user_id)
+            return 1, user_id
+        except ksExceptions.ConnectionError as e:
+            error_value=-vimconn.HTTP_Bad_Request
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        except ksExceptions.NotFound as e:
+            error_value=-vimconn.HTTP_Not_Found
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        except ksExceptions.ClientException as e: #TODO remove
+            error_value=-vimconn.HTTP_Bad_Request
+            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
+        #TODO insert exception vimconn.HTTP_Unauthorized
+        #if reaching here is because an exception
+        if self.debug:
+            print "delete_tenant " + error_text
+        return error_value, error_text
     def get_hosts_info(self):
         '''Get the information of deployed hosts
         Returns the hosts content'''
     def get_hosts_info(self):
         '''Get the information of deployed hosts
         Returns the hosts content'''
@@ -1072,26 +1333,4 @@ class vimconnector(vimconn.vimconnector):
             print "get_hosts " + error_text
         return error_value, error_text        
   
             print "get_hosts " + error_text
         return error_value, error_text        
   
-    def get_image_id_from_path(self, path):
-        '''Get the image id from image path in the VIM database'''
-        '''Returns:
-             0,"Image not found"   if there are no images with that path
-             1,image-id            if there is one image with that path
-             <0,message            if there was an error (Image not found, error contacting VIM, more than 1 image with that path, etc.) 
-        '''
-        try:
-            self._reload_connection()
-            images = self.nova.images.list()
-            for image in images:
-                if image.metadata.get("location")==path:
-                    return 1, image.id
-            return 0, "image with location '%s' not found" % path
-        except (ksExceptions.ClientException, nvExceptions.ClientException) as e: #TODO remove
-            error_value=-vimconn.HTTP_Bad_Request
-            error_text= type(e).__name__ + ": "+  (str(e) if len(e.args)==0 else str(e.args[0]))
-        if self.debug:
-            print "get_image_id_from_path " + error_text
-        #if reaching here is because an exception
-        return error_value, error_text
-