Use glance to list images
[functest.git] / functest / utils / openstack_utils.py
old mode 100755 (executable)
new mode 100644 (file)
index a0d78ae..3e27d67
@@ -8,7 +8,7 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 #
 
-import os
+import logging
 import os.path
 import re
 import sys
@@ -18,16 +18,17 @@ from keystoneauth1 import loading
 from keystoneauth1 import session
 from cinderclient import client as cinderclient
 from glanceclient import client as glanceclient
+from heatclient import client as heatclient
 from novaclient import client as novaclient
 from keystoneclient import client as keystoneclient
 from neutronclient.neutron import client as neutronclient
 
-import functest.utils.functest_logger as ft_logger
 import functest.utils.functest_utils as ft_utils
 
-logger = ft_logger.Logger("openstack_utils").getLogger()
+logger = logging.getLogger(__name__)
 
 DEFAULT_API_VERSION = '2'
+DEFAULT_HEAT_API_VERSION = '1'
 
 
 # *********************************************
@@ -80,7 +81,8 @@ def get_env_cred_dict():
         'OS_PROJECT_DOMAIN_NAME': 'project_domain_name',
         'OS_PROJECT_NAME': 'project_name',
         'OS_ENDPOINT_TYPE': 'endpoint_type',
-        'OS_REGION_NAME': 'region_name'
+        'OS_REGION_NAME': 'region_name',
+        'OS_CACERT': 'https_cacert'
     }
     return env_cred_dict
 
@@ -115,8 +117,11 @@ def source_credentials(rc_file):
     with open(rc_file, "r") as f:
         for line in f:
             var = line.rstrip('"\n').replace('export ', '').split("=")
-            key = re.sub(r'^ *| *$', '', var[0])
-            value = re.sub(r'^[" ]*|[ "]*$', '', "".join(var[1:]))
+            # The two next lines should be modified as soon as rc_file
+            # conforms with common rules. Be aware that it could induce
+            # issues if value starts with '
+            key = re.sub(r'^["\' ]*|[ \'"]*$', '', var[0])
+            value = re.sub(r'^["\' ]*|[ \'"]*$', '', "".join(var[1:]))
             os.environ[key] = value
 
 
@@ -133,20 +138,33 @@ def get_credentials_for_rally():
     endpoint_types = [('internalURL', 'internal'),
                       ('publicURL', 'public'), ('adminURL', 'admin')]
 
-    endpoint_type = os.getenv('OS_ENDPOINT_TYPE')
+    endpoint_type = get_endpoint_type_from_env()
     if endpoint_type is not None:
         cred_key = env_cred_dict.get('OS_ENDPOINT_TYPE')
         for k, v in endpoint_types:
-            if endpoint_type == k:
+            if endpoint_type == v:
                 rally_conf[cred_key] = v
 
     region_name = os.getenv('OS_REGION_NAME')
     if region_name is not None:
         cred_key = env_cred_dict.get('OS_REGION_NAME')
         rally_conf[cred_key] = region_name
+
+    cacert = os.getenv('OS_CACERT')
+    if cacert is not None:
+        cred_key = env_cred_dict.get('OS_CACERT')
+        rally_conf[cred_key] = cacert
     return rally_conf
 
 
+def get_endpoint_type_from_env():
+    endpoint_type = os.environ.get("OS_ENDPOINT_TYPE",
+                                   os.environ.get("OS_INTERFACE"))
+    if endpoint_type and "URL" in endpoint_type:
+        endpoint_type = endpoint_type.replace("URL", "")
+    return endpoint_type
+
+
 def get_session_auth(other_creds={}):
     loader = loading.get_plugin_loader('password')
     creds = get_credentials(other_creds)
@@ -163,7 +181,14 @@ def get_endpoint(service_type, endpoint_type='publicURL'):
 
 def get_session(other_creds={}):
     auth = get_session_auth(other_creds)
-    return session.Session(auth=auth)
+    cacert = os.getenv('OS_CACERT')
+    if cacert is not None:
+        if not os.path.isfile(cacert):
+            raise Exception("The 'OS_CACERT' environment"
+                            "variable is set to %s but the file"
+                            "does not exist.", cacert)
+
+    return session.Session(auth=auth, verify=cacert)
 
 
 # *********************************************
@@ -180,7 +205,9 @@ def get_keystone_client_version():
 
 def get_keystone_client(other_creds={}):
     sess = get_session(other_creds)
-    return keystoneclient.Client(get_keystone_client_version(), session=sess)
+    return keystoneclient.Client(get_keystone_client_version(),
+                                 session=sess,
+                                 interface=os.getenv('OS_INTERFACE', 'admin'))
 
 
 def get_nova_client_version():
@@ -238,6 +265,36 @@ def get_glance_client(other_creds={}):
     return glanceclient.Client(get_glance_client_version(), session=sess)
 
 
+def get_heat_client_version():
+    api_version = os.getenv('OS_ORCHESTRATION_API_VERSION')
+    if api_version is not None:
+        logger.info("OS_ORCHESTRATION_API_VERSION is set in env as '%s'",
+                    api_version)
+        return api_version
+    return DEFAULT_HEAT_API_VERSION
+
+
+def get_heat_client(other_creds={}):
+    sess = get_session(other_creds)
+    return heatclient.Client(get_heat_client_version(), session=sess)
+
+
+def download_and_add_image_on_glance(glance, image_name, image_url, data_dir):
+    dest_path = data_dir
+    if not os.path.exists(dest_path):
+        os.makedirs(dest_path)
+    file_name = image_url.rsplit('/')[-1]
+    if not ft_utils.download_url(image_url, dest_path):
+        return False
+
+    image = create_glance_image(
+        glance, image_name, dest_path + file_name)
+    if not image:
+        return False
+
+    return image
+
+
 # *********************************************
 #   NOVA
 # *********************************************
@@ -245,7 +302,7 @@ def get_instances(nova_client):
     try:
         instances = nova_client.servers.list(search_opts={'all_tenants': 1})
         return instances
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_instances(nova_client)]: %s" % e)
         return None
 
@@ -254,7 +311,7 @@ def get_instance_status(nova_client, instance):
     try:
         instance = nova_client.servers.get(instance.id)
         return instance.status
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_instance_status(nova_client)]: %s" % e)
         return None
 
@@ -263,7 +320,7 @@ def get_instance_by_name(nova_client, instance_name):
     try:
         instance = nova_client.servers.find(name=instance_name)
         return instance
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_instance_by_name(nova_client, '%s')]: %s"
                      % (instance_name, e))
         return None
@@ -293,7 +350,7 @@ def get_aggregates(nova_client):
     try:
         aggregates = nova_client.aggregates.list()
         return aggregates
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_aggregates(nova_client)]: %s" % e)
         return None
 
@@ -303,7 +360,7 @@ def get_aggregate_id(nova_client, aggregate_name):
         aggregates = get_aggregates(nova_client)
         _id = [ag.id for ag in aggregates if ag.name == aggregate_name][0]
         return _id
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_aggregate_id(nova_client, %s)]:"
                      " %s" % (aggregate_name, e))
         return None
@@ -313,7 +370,7 @@ def get_availability_zones(nova_client):
     try:
         availability_zones = nova_client.availability_zones.list()
         return availability_zones
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_availability_zones(nova_client)]: %s" % e)
         return None
 
@@ -322,7 +379,7 @@ def get_availability_zone_names(nova_client):
     try:
         az_names = [az.zoneName for az in get_availability_zones(nova_client)]
         return az_names
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_availability_zone_names(nova_client)]:"
                      " %s" % e)
         return None
@@ -340,7 +397,7 @@ def create_flavor(nova_client, flavor_name, ram, disk, vcpus, public=True):
             # flavor extra specs are not configured, therefore skip the update
             pass
 
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_flavor(nova_client, '%s', '%s', '%s', "
                      "'%s')]: %s" % (flavor_name, ram, disk, vcpus, e))
         return None
@@ -373,7 +430,7 @@ def get_floating_ips(nova_client):
     try:
         floating_ips = nova_client.floating_ips.list()
         return floating_ips
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_floating_ips(nova_client)]: %s" % e)
         return None
 
@@ -386,7 +443,7 @@ def get_hypervisors(nova_client):
             if hypervisor.state == "up":
                 nodes.append(hypervisor.hypervisor_hostname)
         return nodes
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_hypervisors(nova_client)]: %s" % e)
         return None
 
@@ -395,7 +452,7 @@ def create_aggregate(nova_client, aggregate_name, av_zone):
     try:
         nova_client.aggregates.create(aggregate_name, av_zone)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_aggregate(nova_client, %s, %s)]: %s"
                      % (aggregate_name, av_zone, e))
         return None
@@ -406,7 +463,7 @@ def add_host_to_aggregate(nova_client, aggregate_name, compute_host):
         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
         nova_client.aggregates.add_host(aggregate_id, compute_host)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [add_host_to_aggregate(nova_client, %s, %s)]: %s"
                      % (aggregate_name, compute_host, e))
         return None
@@ -418,7 +475,7 @@ def create_aggregate_with_host(
         create_aggregate(nova_client, aggregate_name, av_zone)
         add_host_to_aggregate(nova_client, aggregate_name, compute_host)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_aggregate_with_host("
                      "nova_client, %s, %s, %s)]: %s"
                      % (aggregate_name, av_zone, compute_host, e))
@@ -511,7 +568,7 @@ def create_floating_ip(neutron_client):
         ip_json = neutron_client.create_floatingip({'floatingip': props})
         fip_addr = ip_json['floatingip']['floating_ip_address']
         fip_id = ip_json['floatingip']['id']
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_floating_ip(neutron_client)]: %s" % e)
         return None
     return {'fip_addr': fip_addr, 'fip_id': fip_id}
@@ -521,7 +578,7 @@ def add_floating_ip(nova_client, server_id, floatingip_addr):
     try:
         nova_client.servers.add_floating_ip(server_id, floatingip_addr)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [add_floating_ip(nova_client, '%s', '%s')]: %s"
                      % (server_id, floatingip_addr, e))
         return False
@@ -531,7 +588,7 @@ def delete_instance(nova_client, instance_id):
     try:
         nova_client.servers.force_delete(instance_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_instance(nova_client, '%s')]: %s"
                      % (instance_id, e))
         return False
@@ -541,7 +598,7 @@ def delete_floating_ip(nova_client, floatingip_id):
     try:
         nova_client.floating_ips.delete(floatingip_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_floating_ip(nova_client, '%s')]: %s"
                      % (floatingip_id, e))
         return False
@@ -552,7 +609,7 @@ def remove_host_from_aggregate(nova_client, aggregate_name, compute_host):
         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
         nova_client.aggregates.remove_host(aggregate_id, compute_host)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [remove_host_from_aggregate(nova_client, %s, %s)]:"
                      " %s" % (aggregate_name, compute_host, e))
         return False
@@ -571,7 +628,7 @@ def delete_aggregate(nova_client, aggregate_name):
         remove_hosts_from_aggregate(nova_client, aggregate_name)
         nova_client.aggregates.delete(aggregate_name)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_aggregate(nova_client, %s)]: %s"
                      % (aggregate_name, e))
         return False
@@ -674,7 +731,7 @@ def create_neutron_net(neutron_client, name):
         network = neutron_client.create_network(body=json_body)
         network_dict = network['network']
         return network_dict['id']
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_neutron_net(neutron_client, '%s')]: %s"
                      % (name, e))
         return None
@@ -686,7 +743,7 @@ def create_neutron_subnet(neutron_client, name, cidr, net_id):
     try:
         subnet = neutron_client.create_subnet(body=json_body)
         return subnet['subnets'][0]['id']
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_neutron_subnet(neutron_client, '%s', "
                      "'%s', '%s')]: %s" % (name, cidr, net_id, e))
         return None
@@ -697,7 +754,7 @@ def create_neutron_router(neutron_client, name):
     try:
         router = neutron_client.create_router(json_body)
         return router['router']['id']
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_neutron_router(neutron_client, '%s')]: %s"
                      % (name, e))
         return None
@@ -713,7 +770,7 @@ def create_neutron_port(neutron_client, name, network_id, ip):
     try:
         port = neutron_client.create_port(body=json_body)
         return port['port']['id']
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_neutron_port(neutron_client, '%s', '%s', "
                      "'%s')]: %s" % (name, network_id, ip, e))
         return None
@@ -724,7 +781,7 @@ def update_neutron_net(neutron_client, network_id, shared=False):
     try:
         neutron_client.update_network(network_id, body=json_body)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [update_neutron_net(neutron_client, '%s', '%s')]: "
                      "%s" % (network_id, str(shared), e))
         return False
@@ -738,7 +795,7 @@ def update_neutron_port(neutron_client, port_id, device_owner):
         port = neutron_client.update_port(port=port_id,
                                           body=json_body)
         return port['port']['id']
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [update_neutron_port(neutron_client, '%s', '%s')]:"
                      " %s" % (port_id, device_owner, e))
         return None
@@ -749,7 +806,7 @@ def add_interface_router(neutron_client, router_id, subnet_id):
     try:
         neutron_client.add_interface_router(router=router_id, body=json_body)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [add_interface_router(neutron_client, '%s', "
                      "'%s')]: %s" % (router_id, subnet_id, e))
         return False
@@ -761,7 +818,7 @@ def add_gateway_router(neutron_client, router_id):
     try:
         neutron_client.add_gateway_router(router_id, router_dict)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [add_gateway_router(neutron_client, '%s')]: %s"
                      % (router_id, e))
         return False
@@ -771,7 +828,7 @@ def delete_neutron_net(neutron_client, network_id):
     try:
         neutron_client.delete_network(network_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_neutron_net(neutron_client, '%s')]: %s"
                      % (network_id, e))
         return False
@@ -781,7 +838,7 @@ def delete_neutron_subnet(neutron_client, subnet_id):
     try:
         neutron_client.delete_subnet(subnet_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_neutron_subnet(neutron_client, '%s')]: %s"
                      % (subnet_id, e))
         return False
@@ -791,7 +848,7 @@ def delete_neutron_router(neutron_client, router_id):
     try:
         neutron_client.delete_router(router=router_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_neutron_router(neutron_client, '%s')]: %s"
                      % (router_id, e))
         return False
@@ -801,7 +858,7 @@ def delete_neutron_port(neutron_client, port_id):
     try:
         neutron_client.delete_port(port_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_neutron_port(neutron_client, '%s')]: %s"
                      % (port_id, e))
         return False
@@ -813,7 +870,7 @@ def remove_interface_router(neutron_client, router_id, subnet_id):
         neutron_client.remove_interface_router(router=router_id,
                                                body=json_body)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [remove_interface_router(neutron_client, '%s', "
                      "'%s')]: %s" % (router_id, subnet_id, e))
         return False
@@ -823,7 +880,7 @@ def remove_gateway_router(neutron_client, router_id):
     try:
         neutron_client.remove_gateway_router(router_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [remove_gateway_router(neutron_client, '%s')]: %s"
                      % (router_id, e))
         return False
@@ -953,7 +1010,7 @@ def get_security_groups(neutron_client):
         security_groups = neutron_client.list_security_groups()[
             'security_groups']
         return security_groups
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_security_groups(neutron_client)]: %s" % e)
         return None
 
@@ -974,7 +1031,7 @@ def create_security_group(neutron_client, sg_name, sg_description):
     try:
         secgroup = neutron_client.create_security_group(json_body)
         return secgroup['security_group']
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_security_group(neutron_client, '%s', "
                      "'%s')]: %s" % (sg_name, sg_description, e))
         return None
@@ -982,39 +1039,80 @@ def create_security_group(neutron_client, sg_name, sg_description):
 
 def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
                          port_range_min=None, port_range_max=None):
-    if port_range_min is None and port_range_max is None:
-        json_body = {'security_group_rule': {'direction': direction,
-                                             'security_group_id': sg_id,
-                                             'protocol': protocol}}
-    elif port_range_min is not None and port_range_max is not None:
-        json_body = {'security_group_rule': {'direction': direction,
-                                             'security_group_id': sg_id,
-                                             'port_range_min': port_range_min,
-                                             'port_range_max': port_range_max,
-                                             'protocol': protocol}}
+    # We create a security group in 2 steps
+    # 1 - we check the format and set the json body accordingly
+    # 2 - we call neturon client to create the security group
+
+    # Format check
+    json_body = {'security_group_rule': {'direction': direction,
+                                         'security_group_id': sg_id,
+                                         'protocol': protocol}}
+    # parameters may be
+    # - both None => we do nothing
+    # - both Not None => we add them to the json description
+    # but one cannot be None is the other is not None
+    if (port_range_min is not None and port_range_max is not None):
+        # add port_range in json description
+        json_body['security_group_rule']['port_range_min'] = port_range_min
+        json_body['security_group_rule']['port_range_max'] = port_range_max
+        logger.debug("Security_group format set (port range included)")
     else:
-        logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', "
-                     "'%s', '%s', '%s', '%s')]:" % (neutron_client,
-                                                    sg_id, direction,
-                                                    port_range_min,
-                                                    port_range_max,
-                                                    protocol),
-                     " Invalid values for port_range_min, port_range_max")
-        return False
+        # either both port range are set to None => do nothing
+        # or one is set but not the other => log it and return False
+        if port_range_min is None and port_range_max is None:
+            logger.debug("Security_group format set (no port range mentioned)")
+        else:
+            logger.error("Bad security group format."
+                         "One of the port range is not properly set:"
+                         "range min: {},"
+                         "range max: {}".format(port_range_min,
+                                                port_range_max))
+            return False
+
+    # Create security group using neutron client
     try:
         neutron_client.create_security_group_rule(json_body)
         return True
-    except Exception, e:
-        logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', "
-                     "'%s', '%s', '%s', '%s')]: %s" % (neutron_client,
-                                                       sg_id,
-                                                       direction,
-                                                       port_range_min,
-                                                       port_range_max,
-                                                       protocol, e))
+    except:
+        logger.exception("Impossible to create_security_group_rule,"
+                         "security group rule probably already exists")
         return False
 
 
+def get_security_group_rules(neutron_client, sg_id):
+    try:
+        security_rules = neutron_client.list_security_group_rules()[
+            'security_group_rules']
+        security_rules = [rule for rule in security_rules
+                          if rule["security_group_id"] == sg_id]
+        return security_rules
+    except Exception as e:
+        logger.error("Error [get_security_group_rules(neutron_client, sg_id)]:"
+                     " %s" % e)
+        return None
+
+
+def check_security_group_rules(neutron_client, sg_id, direction, protocol,
+                               port_min=None, port_max=None):
+    try:
+        security_rules = get_security_group_rules(neutron_client, sg_id)
+        security_rules = [rule for rule in security_rules
+                          if (rule["direction"].lower() == direction and
+                              rule["protocol"].lower() == protocol and
+                              rule["port_range_min"] == port_min and
+                              rule["port_range_max"] == port_max)]
+        if len(security_rules) == 0:
+            return True
+        else:
+            return False
+    except Exception as e:
+        logger.error("Error [check_security_group_rules("
+                     " neutron_client, sg_id, direction,"
+                     " protocol, port_min=None, port_max=None)]: "
+                     "%s" % e)
+        return None
+
+
 def create_security_group_full(neutron_client,
                                sg_name, sg_description):
     sg_id = get_security_group_id(neutron_client, sg_name)
@@ -1059,7 +1157,7 @@ def add_secgroup_to_instance(nova_client, instance_id, secgroup_id):
     try:
         nova_client.servers.add_security_group(instance_id, secgroup_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [add_secgroup_to_instance(nova_client, '%s', "
                      "'%s')]: %s" % (instance_id, secgroup_id, e))
         return False
@@ -1075,7 +1173,7 @@ def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
         neutron_client.update_quota(tenant_id=tenant_id,
                                     body=json_body)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [update_sg_quota(neutron_client, '%s', '%s', "
                      "'%s')]: %s" % (tenant_id, sg_quota, sg_rule_quota, e))
         return False
@@ -1085,7 +1183,7 @@ def delete_security_group(neutron_client, secgroup_id):
     try:
         neutron_client.delete_security_group(secgroup_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_security_group(neutron_client, '%s')]: %s"
                      % (secgroup_id, e))
         return False
@@ -1094,11 +1192,11 @@ def delete_security_group(neutron_client, secgroup_id):
 # *********************************************
 #   GLANCE
 # *********************************************
-def get_images(nova_client):
+def get_images(glance_client):
     try:
-        images = nova_client.images.list()
+        images = glance_client.images.list()
         return images
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_images]: %s" % e)
         return None
 
@@ -1134,7 +1232,7 @@ def create_glance_image(glance_client, image_name, file_path, disk="qcow2",
             with open(file_path) as image_data:
                 glance_client.images.upload(image_id, image_data)
         return image_id
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_glance_image(glance_client, '%s', '%s', "
                      "'%s')]: %s" % (image_name, file_path, public, e))
         return None
@@ -1160,12 +1258,12 @@ def get_or_create_image(name, path, format):
     return image_exists, image_id
 
 
-def delete_glance_image(nova_client, image_id):
+def delete_glance_image(glance_client, image_id):
     try:
-        nova_client.images.delete(image_id)
+        glance_client.images.delete(image_id)
         return True
-    except Exception, e:
-        logger.error("Error [delete_glance_image(nova_client, '%s')]: %s"
+    except Exception as e:
+        logger.error("Error [delete_glance_image(glance_client, '%s')]: %s"
                      % (image_id, e))
         return False
 
@@ -1177,7 +1275,7 @@ def get_volumes(cinder_client):
     try:
         volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
         return volumes
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_volumes(cinder_client)]: %s" % e)
         return None
 
@@ -1190,7 +1288,7 @@ def list_volume_types(cinder_client, public=True, private=True):
         if not private:
             volume_types = [vt for vt in volume_types if vt.is_public]
         return volume_types
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [list_volume_types(cinder_client)]: %s" % e)
         return None
 
@@ -1199,7 +1297,7 @@ def create_volume_type(cinder_client, name):
     try:
         volume_type = cinder_client.volume_types.create(name)
         return volume_type
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_volume_type(cinder_client, '%s')]: %s"
                      % (name, e))
         return None
@@ -1214,7 +1312,7 @@ def update_cinder_quota(cinder_client, tenant_id, vols_quota,
     try:
         cinder_client.quotas.update(tenant_id, **quotas_values)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [update_cinder_quota(cinder_client, '%s', '%s', "
                      "'%s' '%s')]: %s" % (tenant_id, vols_quota,
                                           snapshots_quota, gigabytes_quota, e))
@@ -1232,7 +1330,7 @@ def delete_volume(cinder_client, volume_id, forced=False):
         else:
             cinder_client.volumes.delete(volume_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_volume(cinder_client, '%s', '%s')]: %s"
                      % (volume_id, str(forced), e))
         return False
@@ -1242,7 +1340,7 @@ def delete_volume_type(cinder_client, volume_type):
     try:
         cinder_client.volume_types.delete(volume_type)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_volume_type(cinder_client, '%s')]: %s"
                      % (volume_type, e))
         return False
@@ -1258,7 +1356,7 @@ def get_tenants(keystone_client):
         else:
             tenants = keystone_client.tenants.list()
         return tenants
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_tenants(keystone_client)]: %s" % e)
         return None
 
@@ -1267,7 +1365,7 @@ def get_users(keystone_client):
     try:
         users = keystone_client.users.list()
         return users
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [get_users(keystone_client)]: %s" % e)
         return None
 
@@ -1315,12 +1413,47 @@ def create_tenant(keystone_client, tenant_name, tenant_description):
                                                     tenant_description,
                                                     enabled=True)
         return tenant.id
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_tenant(keystone_client, '%s', '%s')]: %s"
                      % (tenant_name, tenant_description, e))
         return None
 
 
+def get_or_create_tenant(keystone_client, tenant_name, tenant_description):
+    tenant_id = get_tenant_id(keystone_client, tenant_name)
+    if not tenant_id:
+        tenant_id = create_tenant(keystone_client, tenant_name,
+                                  tenant_description)
+
+    return tenant_id
+
+
+def get_or_create_tenant_for_vnf(keystone_client, tenant_name,
+                                 tenant_description):
+    """Get or Create a Tenant
+
+        Args:
+            keystone_client: keystone client reference
+            tenant_name: the name of the tenant
+            tenant_description: the description of the tenant
+
+        return False if tenant retrieved though get
+        return True if tenant created
+        raise Exception if error during processing
+    """
+    try:
+        tenant_id = get_tenant_id(keystone_client, tenant_name)
+        if not tenant_id:
+            tenant_id = create_tenant(keystone_client, tenant_name,
+                                      tenant_description)
+            return True
+        else:
+            return False
+    except:
+        raise Exception("Impossible to create a Tenant for the VNF {}".format(
+                            tenant_name))
+
+
 def create_user(keystone_client, user_name, user_password,
                 user_email, tenant_id):
     try:
@@ -1337,13 +1470,48 @@ def create_user(keystone_client, user_name, user_password,
                                                 tenant_id,
                                                 enabled=True)
         return user.id
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [create_user(keystone_client, '%s', '%s', '%s'"
                      "'%s')]: %s" % (user_name, user_password,
                                      user_email, tenant_id, e))
         return None
 
 
+def get_or_create_user(keystone_client, user_name, user_password,
+                       tenant_id, user_email=None):
+    user_id = get_user_id(keystone_client, user_name)
+    if not user_id:
+        user_id = create_user(keystone_client, user_name, user_password,
+                              user_email, tenant_id)
+    return user_id
+
+
+def get_or_create_user_for_vnf(keystone_client, vnf_ref):
+    """Get or Create user for VNF
+
+        Args:
+            keystone_client: keystone client reference
+            vnf_ref: VNF reference used as user name & password, tenant name
+
+        return False if user retrieved through get
+        return True if user created
+        raise Exception if error during processing
+    """
+    try:
+        user_id = get_user_id(keystone_client, vnf_ref)
+        tenant_id = get_tenant_id(keystone_client, vnf_ref)
+        if not user_id:
+            user_id = create_user(keystone_client, vnf_ref, vnf_ref,
+                                  "", tenant_id)
+            return True
+        else:
+            return False
+        add_role_user(keystone_client, user_id, 'admin', vnf_ref)
+    except:
+        raise Exception("Impossible to create a user for the VNF {}".format(
+            vnf_ref))
+
+
 def add_role_user(keystone_client, user_id, role_id, tenant_id):
     try:
         if is_keystone_v3():
@@ -1353,7 +1521,7 @@ def add_role_user(keystone_client, user_id, role_id, tenant_id):
         else:
             keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [add_role_user(keystone_client, '%s', '%s'"
                      "'%s')]: %s " % (user_id, role_id, tenant_id, e))
         return False
@@ -1366,7 +1534,7 @@ def delete_tenant(keystone_client, tenant_id):
         else:
             keystone_client.tenants.delete(tenant_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_tenant(keystone_client, '%s')]: %s"
                      % (tenant_id, e))
         return False
@@ -1376,7 +1544,19 @@ def delete_user(keystone_client, user_id):
     try:
         keystone_client.users.delete(user_id)
         return True
-    except Exception, e:
+    except Exception as e:
         logger.error("Error [delete_user(keystone_client, '%s')]: %s"
                      % (user_id, e))
         return False
+
+
+# *********************************************
+#   HEAT
+# *********************************************
+def get_resource(heat_client, stack_id, resource):
+    try:
+        resources = heat_client.resources.get(stack_id, resource)
+        return resources
+    except Exception as e:
+        logger.error("Error [get_resource]: %s" % e)
+        return None