Merge "Replace assert statements in tests"
[yardstick.git] / yardstick / common / openstack_utils.py
index f027b79..84bfbbb 100644 (file)
@@ -7,19 +7,22 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
-from __future__ import absolute_import
-
 import os
 import time
 import os
 import time
+import sys
 import logging
 
 from keystoneauth1 import loading
 from keystoneauth1 import session
 import logging
 
 from keystoneauth1 import loading
 from keystoneauth1 import session
+import shade
+from shade import exc
+
 from cinderclient import client as cinderclient
 from novaclient import client as novaclient
 from glanceclient import client as glanceclient
 from neutronclient.neutron import client as neutronclient
 
 from cinderclient import client as cinderclient
 from novaclient import client as novaclient
 from glanceclient import client as glanceclient
 from neutronclient.neutron import client as neutronclient
 
+
 log = logging.getLogger(__name__)
 
 DEFAULT_HEAT_API_VERSION = '1'
 log = logging.getLogger(__name__)
 
 DEFAULT_HEAT_API_VERSION = '1'
@@ -30,38 +33,22 @@ DEFAULT_API_VERSION = '2'
 #   CREDENTIALS
 # *********************************************
 def get_credentials():
 #   CREDENTIALS
 # *********************************************
 def get_credentials():
-    """Returns a creds dictionary filled with parsed from env"""
-    creds = {}
-
-    keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
-
-    if keystone_api_version is None or keystone_api_version == '2':
-        keystone_v3 = False
-        tenant_env = 'OS_TENANT_NAME'
-        tenant = 'tenant_name'
-    else:
-        keystone_v3 = True
-        tenant_env = 'OS_PROJECT_NAME'
-        tenant = 'project_name'
-
-    # The most common way to pass these info to the script is to do it
-    # through environment variables.
-    creds.update({
-        "username": os.environ.get("OS_USERNAME"),
-        "password": os.environ.get("OS_PASSWORD"),
-        "auth_url": os.environ.get("OS_AUTH_URL"),
-        tenant: os.environ.get(tenant_env)
-    })
-
-    if keystone_v3:
-        if os.getenv('OS_USER_DOMAIN_NAME') is not None:
-            creds.update({
-                "user_domain_name": os.getenv('OS_USER_DOMAIN_NAME')
-            })
-        if os.getenv('OS_PROJECT_DOMAIN_NAME') is not None:
-            creds.update({
-                "project_domain_name": os.getenv('OS_PROJECT_DOMAIN_NAME')
-            })
+    """Returns a creds dictionary filled with parsed from env
+
+    Keystone API version used is 3; v2 was deprecated in 2014 (Icehouse). Along
+    with this deprecation, environment variable 'OS_TENANT_NAME' is replaced by
+    'OS_PROJECT_NAME'.
+    """
+    creds = {'username': os.environ.get('OS_USERNAME'),
+             'password': os.environ.get('OS_PASSWORD'),
+             'auth_url': os.environ.get('OS_AUTH_URL'),
+             'project_name': os.environ.get('OS_PROJECT_NAME')
+             }
+
+    if os.getenv('OS_USER_DOMAIN_NAME'):
+        creds['user_domain_name'] = os.getenv('OS_USER_DOMAIN_NAME')
+    if os.getenv('OS_PROJECT_DOMAIN_NAME'):
+        creds['project_domain_name'] = os.getenv('OS_PROJECT_DOMAIN_NAME')
 
     return creds
 
 
     return creds
 
@@ -169,27 +156,31 @@ def get_glance_client():    # pragma: no cover
     return glanceclient.Client(get_glance_client_version(), session=sess)
 
 
     return glanceclient.Client(get_glance_client_version(), session=sess)
 
 
+def get_shade_client():
+    return shade.openstack_cloud()
+
+
 # *********************************************
 #   NOVA
 # *********************************************
 # *********************************************
 #   NOVA
 # *********************************************
-def get_instances(nova_client):     # pragma: no cover
+def get_instances(nova_client):
     try:
         return nova_client.servers.list(search_opts={'all_tenants': 1})
     try:
         return nova_client.servers.list(search_opts={'all_tenants': 1})
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [get_instances(nova_client)]")
 
 
 def get_instance_status(nova_client, instance):     # pragma: no cover
     try:
         return nova_client.servers.get(instance.id).status
         log.exception("Error [get_instances(nova_client)]")
 
 
 def get_instance_status(nova_client, instance):     # pragma: no cover
     try:
         return nova_client.servers.get(instance.id).status
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [get_instance_status(nova_client)]")
 
 
 def get_instance_by_name(nova_client, instance_name):   # pragma: no cover
     try:
         return nova_client.servers.find(name=instance_name)
         log.exception("Error [get_instance_status(nova_client)]")
 
 
 def get_instance_by_name(nova_client, instance_name):   # pragma: no cover
     try:
         return nova_client.servers.find(name=instance_name)
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [get_instance_by_name(nova_client, '%s')]",
                       instance_name)
 
         log.exception("Error [get_instance_by_name(nova_client, '%s')]",
                       instance_name)
 
@@ -197,28 +188,28 @@ def get_instance_by_name(nova_client, instance_name):   # pragma: no cover
 def get_aggregates(nova_client):    # pragma: no cover
     try:
         return nova_client.aggregates.list()
 def get_aggregates(nova_client):    # pragma: no cover
     try:
         return nova_client.aggregates.list()
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [get_aggregates(nova_client)]")
 
 
 def get_availability_zones(nova_client):    # pragma: no cover
     try:
         return nova_client.availability_zones.list()
         log.exception("Error [get_aggregates(nova_client)]")
 
 
 def get_availability_zones(nova_client):    # pragma: no cover
     try:
         return nova_client.availability_zones.list()
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [get_availability_zones(nova_client)]")
 
 
 def get_availability_zone_names(nova_client):   # pragma: no cover
     try:
         return [az.zoneName for az in get_availability_zones(nova_client)]
         log.exception("Error [get_availability_zones(nova_client)]")
 
 
 def get_availability_zone_names(nova_client):   # pragma: no cover
     try:
         return [az.zoneName for az in get_availability_zones(nova_client)]
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [get_availability_zone_names(nova_client)]")
 
 
 def create_aggregate(nova_client, aggregate_name, av_zone):  # pragma: no cover
     try:
         nova_client.aggregates.create(aggregate_name, av_zone)
         log.exception("Error [get_availability_zone_names(nova_client)]")
 
 
 def create_aggregate(nova_client, aggregate_name, av_zone):  # pragma: no cover
     try:
         nova_client.aggregates.create(aggregate_name, av_zone)
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [create_aggregate(nova_client, %s, %s)]",
                       aggregate_name, av_zone)
         return False
         log.exception("Error [create_aggregate(nova_client, %s, %s)]",
                       aggregate_name, av_zone)
         return False
@@ -230,7 +221,7 @@ def get_aggregate_id(nova_client, aggregate_name):      # pragma: no cover
     try:
         aggregates = get_aggregates(nova_client)
         _id = next((ag.id for ag in aggregates if ag.name == aggregate_name))
     try:
         aggregates = get_aggregates(nova_client)
         _id = next((ag.id for ag in aggregates if ag.name == aggregate_name))
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [get_aggregate_id(nova_client, %s)]",
                       aggregate_name)
     else:
         log.exception("Error [get_aggregate_id(nova_client, %s)]",
                       aggregate_name)
     else:
@@ -242,7 +233,7 @@ def add_host_to_aggregate(nova_client, aggregate_name,
     try:
         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
         nova_client.aggregates.add_host(aggregate_id, compute_host)
     try:
         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
         nova_client.aggregates.add_host(aggregate_id, compute_host)
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [add_host_to_aggregate(nova_client, %s, %s)]",
                       aggregate_name, compute_host)
         return False
         log.exception("Error [add_host_to_aggregate(nova_client, %s, %s)]",
                       aggregate_name, compute_host)
         return False
@@ -255,7 +246,7 @@ def create_aggregate_with_host(nova_client, aggregate_name, av_zone,
     try:
         create_aggregate(nova_client, aggregate_name, av_zone)
         add_host_to_aggregate(nova_client, aggregate_name, compute_host)
     try:
         create_aggregate(nova_client, aggregate_name, av_zone)
         add_host_to_aggregate(nova_client, aggregate_name, compute_host)
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [create_aggregate_with_host("
                       "nova_client, %s, %s, %s)]",
                       aggregate_name, av_zone, compute_host)
         log.exception("Error [create_aggregate_with_host("
                       "nova_client, %s, %s, %s)]",
                       aggregate_name, av_zone, compute_host)
@@ -264,88 +255,58 @@ def create_aggregate_with_host(nova_client, aggregate_name, av_zone,
         return True
 
 
         return True
 
 
-def create_instance(flavor_name,
-                    image_id,
-                    network_id,
-                    instance_name="instance-vm",
-                    confdrive=True,
-                    userdata=None,
-                    av_zone='',
-                    fixed_ip=None,
-                    files=None):    # pragma: no cover
-    nova_client = get_nova_client()
+def create_keypair(name, key_path=None):    # pragma: no cover
+    try:
+        with open(key_path) as fpubkey:
+            keypair = get_nova_client().keypairs.create(
+                name=name, public_key=fpubkey.read())
+            return keypair
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error [create_keypair(nova_client)]")
+
+
+def create_instance(json_body):    # pragma: no cover
     try:
     try:
-        flavor = nova_client.flavors.find(name=flavor_name)
-    except:
-        flavors = nova_client.flavors.list()
-        log.exception("Error: Flavor '%s' not found. Available flavors are: "
-                      "\n%s", flavor_name, flavors)
+        return get_nova_client().servers.create(**json_body)
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error create instance failed")
         return None
         return None
-    if fixed_ip is not None:
-        nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip}
-    else:
-        nics = {"net-id": network_id}
-    if userdata is None:
-        instance = nova_client.servers.create(
-            name=instance_name,
-            flavor=flavor,
-            image=image_id,
-            nics=[nics],
-            availability_zone=av_zone,
-            files=files
-        )
-    else:
-        instance = nova_client.servers.create(
-            name=instance_name,
-            flavor=flavor,
-            image=image_id,
-            nics=[nics],
-            config_drive=confdrive,
-            userdata=userdata,
-            availability_zone=av_zone,
-            files=files
-        )
-    return instance
-
-
-def create_instance_and_wait_for_active(flavor_name,
-                                        image_id,
-                                        network_id,
-                                        instance_name="instance-vm",
-                                        config_drive=False,
-                                        userdata="",
-                                        av_zone='',
-                                        fixed_ip=None,
-                                        files=None):    # pragma: no cover
+
+
+def create_instance_and_wait_for_active(json_body):    # pragma: no cover
     SLEEP = 3
     VM_BOOT_TIMEOUT = 180
     nova_client = get_nova_client()
     SLEEP = 3
     VM_BOOT_TIMEOUT = 180
     nova_client = get_nova_client()
-    instance = create_instance(flavor_name,
-                               image_id,
-                               network_id,
-                               instance_name,
-                               config_drive,
-                               userdata,
-                               av_zone=av_zone,
-                               fixed_ip=fixed_ip,
-                               files=files)
-    count = VM_BOOT_TIMEOUT / SLEEP
-    for n in range(count, -1, -1):
+    instance = create_instance(json_body)
+    for _ in range(int(VM_BOOT_TIMEOUT / SLEEP)):
         status = get_instance_status(nova_client, instance)
         if status.lower() == "active":
             return instance
         elif status.lower() == "error":
         status = get_instance_status(nova_client, instance)
         if status.lower() == "active":
             return instance
         elif status.lower() == "error":
-            log.error("The instance %s went to ERROR status.", instance_name)
+            log.error("The instance went to ERROR status.")
             return None
         time.sleep(SLEEP)
             return None
         time.sleep(SLEEP)
-    log.error("Timeout booting the instance %s.", instance_name)
+    log.error("Timeout booting the instance.")
     return None
 
 
     return None
 
 
+def attach_server_volume(server_id, volume_id,
+                         device=None):    # pragma: no cover
+    try:
+        get_nova_client().volumes.create_server_volume(server_id,
+                                                       volume_id, device)
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error [attach_server_volume(nova_client, '%s', '%s')]",
+                      server_id, volume_id)
+        return False
+    else:
+        return True
+
+
 def delete_instance(nova_client, instance_id):      # pragma: no cover
     try:
         nova_client.servers.force_delete(instance_id)
 def delete_instance(nova_client, instance_id):      # pragma: no cover
     try:
         nova_client.servers.force_delete(instance_id)
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [delete_instance(nova_client, '%s')]",
                       instance_id)
         return False
         log.exception("Error [delete_instance(nova_client, '%s')]",
                       instance_id)
         return False
@@ -358,7 +319,7 @@ def remove_host_from_aggregate(nova_client, aggregate_name,
     try:
         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
         nova_client.aggregates.remove_host(aggregate_id, compute_host)
     try:
         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
         nova_client.aggregates.remove_host(aggregate_id, compute_host)
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error remove_host_from_aggregate(nova_client, %s, %s)",
                       aggregate_name, compute_host)
         return False
         log.exception("Error remove_host_from_aggregate(nova_client, %s, %s)",
                       aggregate_name, compute_host)
         return False
@@ -379,7 +340,7 @@ def delete_aggregate(nova_client, aggregate_name):  # pragma: no cover
     try:
         remove_hosts_from_aggregate(nova_client, aggregate_name)
         nova_client.aggregates.delete(aggregate_name)
     try:
         remove_hosts_from_aggregate(nova_client, aggregate_name)
         nova_client.aggregates.delete(aggregate_name)
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
         log.exception("Error [delete_aggregate(nova_client, %s)]",
                       aggregate_name)
         return False
         log.exception("Error [delete_aggregate(nova_client, %s)]",
                       aggregate_name)
         return False
@@ -395,6 +356,16 @@ def get_server_by_name(name):   # pragma: no cover
         raise
 
 
         raise
 
 
+def create_flavor(name, ram, vcpus, disk, **kwargs):   # pragma: no cover
+    try:
+        return get_nova_client().flavors.create(name, ram, vcpus,
+                                                disk, **kwargs)
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error [create_flavor(nova_client, %s, %s, %s, %s, %s)]",
+                      name, ram, disk, vcpus, kwargs['is_public'])
+        return None
+
+
 def get_image_by_name(name):    # pragma: no cover
     images = get_nova_client().images.list()
     try:
 def get_image_by_name(name):    # pragma: no cover
     images = get_nova_client().images.list()
     try:
@@ -403,6 +374,16 @@ def get_image_by_name(name):    # pragma: no cover
         log.exception('No image matched')
 
 
         log.exception('No image matched')
 
 
+def get_flavor_id(nova_client, flavor_name):    # pragma: no cover
+    flavors = nova_client.flavors.list(detailed=True)
+    flavor_id = ''
+    for f in flavors:
+        if f.name == flavor_name:
+            flavor_id = f.id
+            break
+    return flavor_id
+
+
 def get_flavor_by_name(name):   # pragma: no cover
     flavors = get_nova_client().flavors.list()
     try:
 def get_flavor_by_name(name):   # pragma: no cover
     flavors = get_nova_client().flavors.list()
     try:
@@ -412,7 +393,7 @@ def get_flavor_by_name(name):   # pragma: no cover
 
 
 def check_status(status, name, iterations, interval):   # pragma: no cover
 
 
 def check_status(status, name, iterations, interval):   # pragma: no cover
-    for i in range(iterations):
+    for _ in range(iterations):
         try:
             server = get_server_by_name(name)
         except IndexError:
         try:
             server = get_server_by_name(name)
         except IndexError:
@@ -426,18 +407,291 @@ def check_status(status, name, iterations, interval):   # pragma: no cover
     return False
 
 
     return False
 
 
+def delete_flavor(flavor_id):    # pragma: no cover
+    try:
+        get_nova_client().flavors.delete(flavor_id)
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error [delete_flavor(nova_client, %s)]", flavor_id)
+        return False
+    else:
+        return True
+
+
+def delete_keypair(nova_client, key):     # pragma: no cover
+    try:
+        nova_client.keypairs.delete(key=key)
+        return True
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error [delete_keypair(nova_client)]")
+        return False
+
+
 # *********************************************
 #   NEUTRON
 # *********************************************
 # *********************************************
 #   NEUTRON
 # *********************************************
-def get_network_id(neutron_client, network_name):       # pragma: no cover
-    networks = neutron_client.list_networks()['networks']
-    return next((n['id'] for n in networks if n['name'] == network_name), None)
+def get_network_id(shade_client, network_name):
+    networks = shade_client.list_networks({'name': network_name})
+    if networks:
+        return networks[0]['id']
+
+
+def create_neutron_net(shade_client, network_name, shared=False,
+                       admin_state_up=True, external=False, provider=None,
+                       project_id=None):
+    """Create a neutron network.
+
+    :param network_name:(string) name of the network being created.
+    :param shared:(bool) whether the network is shared.
+    :param admin_state_up:(bool) set the network administrative state.
+    :param external:(bool) whether this network is externally accessible.
+    :param provider:(dict) a dict of network provider options.
+    :param project_id:(string) specify the project ID this network
+                      will be created on (admin-only).
+    :returns:(string) the network id.
+    """
+    try:
+        networks = shade_client.create_network(
+            name=network_name, shared=shared, admin_state_up=admin_state_up,
+            external=external, provider=provider, project_id=project_id)
+        return networks['id']
+    except exc.OpenStackCloudException as o_exc:
+        log.error("Error [create_neutron_net(shade_client)]."
+                  "Exception message, '%s'", o_exc.orig_message)
+        return None
+
+
+def delete_neutron_net(shade_client, network_id):
+    try:
+        return shade_client.delete_network(network_id)
+    except exc.OpenStackCloudException:
+        log.error("Error [delete_neutron_net(shade_client, '%s')]", network_id)
+        return False
+
+
+def create_neutron_subnet(shade_client, network_name_or_id, cidr=None,
+                          ip_version=4, enable_dhcp=False, subnet_name=None,
+                          tenant_id=None, allocation_pools=None,
+                          gateway_ip=None, disable_gateway_ip=False,
+                          dns_nameservers=None, host_routes=None,
+                          ipv6_ra_mode=None, ipv6_address_mode=None,
+                          use_default_subnetpool=False):
+    """Create a subnet on a specified network.
+
+    :param network_name_or_id:(string) the unique name or ID of the
+                              attached network. If a non-unique name is
+                              supplied, an exception is raised.
+    :param cidr:(string) the CIDR.
+    :param ip_version:(int) the IP version.
+    :param enable_dhcp:(bool) whether DHCP is enable.
+    :param subnet_name:(string) the name of the subnet.
+    :param tenant_id:(string) the ID of the tenant who owns the network.
+    :param allocation_pools: A list of dictionaries of the start and end
+                            addresses for the allocation pools.
+    :param gateway_ip:(string) the gateway IP address.
+    :param disable_gateway_ip:(bool) whether gateway IP address is enabled.
+    :param dns_nameservers: A list of DNS name servers for the subnet.
+    :param host_routes: A list of host route dictionaries for the subnet.
+    :param ipv6_ra_mode:(string) IPv6 Router Advertisement mode.
+                        Valid values are: 'dhcpv6-stateful',
+                        'dhcpv6-stateless', or 'slaac'.
+    :param ipv6_address_mode:(string) IPv6 address mode.
+                             Valid values are: 'dhcpv6-stateful',
+                             'dhcpv6-stateless', or 'slaac'.
+    :param use_default_subnetpool:(bool) use the default subnetpool for
+                                  ``ip_version`` to obtain a CIDR. It is
+                                  required to pass ``None`` to the ``cidr``
+                                  argument when enabling this option.
+    :returns:(string) the subnet id.
+    """
+    try:
+        subnet = shade_client.create_subnet(
+            network_name_or_id, cidr=cidr, ip_version=ip_version,
+            enable_dhcp=enable_dhcp, subnet_name=subnet_name,
+            tenant_id=tenant_id, allocation_pools=allocation_pools,
+            gateway_ip=gateway_ip, disable_gateway_ip=disable_gateway_ip,
+            dns_nameservers=dns_nameservers, host_routes=host_routes,
+            ipv6_ra_mode=ipv6_ra_mode, ipv6_address_mode=ipv6_address_mode,
+            use_default_subnetpool=use_default_subnetpool)
+        return subnet['id']
+    except exc.OpenStackCloudException as o_exc:
+        log.error("Error [create_neutron_subnet(shade_client)]. "
+                  "Exception message: %s", o_exc.orig_message)
+        return None
+
+
+def create_neutron_router(neutron_client, json_body):      # pragma: no cover
+    try:
+        router = neutron_client.create_router(json_body)
+        return router['router']['id']
+    except Exception:  # pylint: disable=broad-except
+        log.error("Error [create_neutron_router(neutron_client)]")
+        raise Exception("operation error")
+
+
+def delete_neutron_router(shade_client, router_id):
+    try:
+        return shade_client.delete_router(router_id)
+    except exc.OpenStackCloudException as o_exc:
+        log.error("Error [delete_neutron_router(shade_client, '%s')]. "
+                  "Exception message: %s", router_id, o_exc.orig_message)
+        return False
 
 
 
 
-def get_port_id_by_ip(neutron_client, ip_address):      # pragma: no cover
-    ports = neutron_client.list_ports()['ports']
-    return next((i['id'] for i in ports for j in i.get(
-        'fixed_ips') if j['ip_address'] == ip_address), None)
+def remove_gateway_router(neutron_client, router_id):      # pragma: no cover
+    try:
+        neutron_client.remove_gateway_router(router_id)
+        return True
+    except Exception:  # pylint: disable=broad-except
+        log.error("Error [remove_gateway_router(neutron_client, '%s')]",
+                  router_id)
+        return False
+
+
+def remove_interface_router(neutron_client, router_id, subnet_id,
+                            **json_body):      # pragma: no cover
+    json_body.update({"subnet_id": subnet_id})
+    try:
+        neutron_client.remove_interface_router(router=router_id,
+                                               body=json_body)
+        return True
+    except Exception:  # pylint: disable=broad-except
+        log.error("Error [remove_interface_router(neutron_client, '%s', "
+                  "'%s')]", router_id, subnet_id)
+        return False
+
+
+def create_floating_ip(neutron_client, extnet_id):      # pragma: no cover
+    props = {'floating_network_id': extnet_id}
+    try:
+        ip_json = neutron_client.create_floatingip({'floatingip': props})
+        fip_addr = ip_json['floatingip']['floating_ip_address']
+        fip_id = ip_json['floatingip']['id']
+    except Exception:  # pylint: disable=broad-except
+        log.error("Error [create_floating_ip(neutron_client)]")
+        return None
+    return {'fip_addr': fip_addr, 'fip_id': fip_id}
+
+
+def delete_floating_ip(nova_client, floatingip_id):      # pragma: no cover
+    try:
+        nova_client.floating_ips.delete(floatingip_id)
+        return True
+    except Exception:  # pylint: disable=broad-except
+        log.error("Error [delete_floating_ip(nova_client, '%s')]",
+                  floatingip_id)
+        return False
+
+
+def get_security_groups(neutron_client):      # pragma: no cover
+    try:
+        security_groups = neutron_client.list_security_groups()[
+            'security_groups']
+        return security_groups
+    except Exception:  # pylint: disable=broad-except
+        log.error("Error [get_security_groups(neutron_client)]")
+        return None
+
+
+def get_security_group_id(neutron_client, sg_name):      # pragma: no cover
+    security_groups = get_security_groups(neutron_client)
+    id = ''
+    for sg in security_groups:
+        if sg['name'] == sg_name:
+            id = sg['id']
+            break
+    return id
+
+
+def create_security_group(neutron_client, sg_name,
+                          sg_description):      # pragma: no cover
+    json_body = {'security_group': {'name': sg_name,
+                                    'description': sg_description}}
+    try:
+        secgroup = neutron_client.create_security_group(json_body)
+        return secgroup['security_group']
+    except Exception:  # pylint: disable=broad-except
+        log.error("Error [create_security_group(neutron_client, '%s', "
+                  "'%s')]", sg_name, sg_description)
+        return None
+
+
+def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
+                         port_range_min=None, port_range_max=None,
+                         **json_body):      # pragma: no cover
+    # 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.update({'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
+        log.debug("Security_group format set (port range included)")
+    else:
+        # 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:
+            log.debug("Security_group format set (no port range mentioned)")
+        else:
+            log.error("Bad security group format."
+                      "One of the port range is not properly set:"
+                      "range min: %s, range max: %s", 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:  # pylint: disable=broad-except
+        log.exception("Impossible to create_security_group_rule,"
+                      "security group rule probably already exists")
+        return False
+
+
+def create_security_group_full(neutron_client, sg_name,
+                               sg_description):      # pragma: no cover
+    sg_id = get_security_group_id(neutron_client, sg_name)
+    if sg_id != '':
+        log.info("Using existing security group '%s'...", sg_name)
+    else:
+        log.info("Creating security group  '%s'...", sg_name)
+        SECGROUP = create_security_group(neutron_client,
+                                         sg_name,
+                                         sg_description)
+        if not SECGROUP:
+            log.error("Failed to create the security group...")
+            return None
+
+        sg_id = SECGROUP['id']
+
+        log.debug("Security group '%s' with ID=%s created successfully.",
+                  SECGROUP['name'], sg_id)
+
+        log.debug("Adding ICMP rules in security group '%s'...", sg_name)
+        if not create_secgroup_rule(neutron_client, sg_id,
+                                    'ingress', 'icmp'):
+            log.error("Failed to create the security group rule...")
+            return None
+
+        log.debug("Adding SSH rules in security group '%s'...", sg_name)
+        if not create_secgroup_rule(
+                neutron_client, sg_id, 'ingress', 'tcp', '22', '22'):
+            log.error("Failed to create the security group rule...")
+            return None
+
+        if not create_secgroup_rule(
+                neutron_client, sg_id, 'egress', 'tcp', '22', '22'):
+            log.error("Failed to create the security group rule...")
+            return None
+    return sg_id
 
 
 # *********************************************
 
 
 # *********************************************
@@ -448,9 +702,96 @@ def get_image_id(glance_client, image_name):    # pragma: no cover
     return next((i.id for i in images if i.name == image_name), None)
 
 
     return next((i.id for i in images if i.name == image_name), None)
 
 
+def create_image(glance_client, image_name, file_path, disk_format,
+                 container_format, min_disk, min_ram, protected, tag,
+                 public, **kwargs):    # pragma: no cover
+    if not os.path.isfile(file_path):
+        log.error("Error: file %s does not exist.", file_path)
+        return None
+    try:
+        image_id = get_image_id(glance_client, image_name)
+        if image_id is not None:
+            log.info("Image %s already exists.", image_name)
+        else:
+            log.info("Creating image '%s' from '%s'...", image_name, file_path)
+
+            image = glance_client.images.create(
+                name=image_name, visibility=public, disk_format=disk_format,
+                container_format=container_format, min_disk=min_disk,
+                min_ram=min_ram, tags=tag, protected=protected, **kwargs)
+            image_id = image.id
+            with open(file_path) as image_data:
+                glance_client.images.upload(image_id, image_data)
+        return image_id
+    except Exception:  # pylint: disable=broad-except
+        log.error(
+            "Error [create_glance_image(glance_client, '%s', '%s', '%s')]",
+            image_name, file_path, public)
+        return None
+
+
+def delete_image(glance_client, image_id):    # pragma: no cover
+    try:
+        glance_client.images.delete(image_id)
+
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error [delete_flavor(glance_client, %s)]", image_id)
+        return False
+    else:
+        return True
+
+
 # *********************************************
 #   CINDER
 # *********************************************
 def get_volume_id(volume_name):    # pragma: no cover
     volumes = get_cinder_client().volumes.list()
     return next((v.id for v in volumes if v.name == volume_name), None)
 # *********************************************
 #   CINDER
 # *********************************************
 def get_volume_id(volume_name):    # pragma: no cover
     volumes = get_cinder_client().volumes.list()
     return next((v.id for v in volumes if v.name == volume_name), None)
+
+
+def create_volume(cinder_client, volume_name, volume_size,
+                  volume_image=False):    # pragma: no cover
+    try:
+        if volume_image:
+            volume = cinder_client.volumes.create(name=volume_name,
+                                                  size=volume_size,
+                                                  imageRef=volume_image)
+        else:
+            volume = cinder_client.volumes.create(name=volume_name,
+                                                  size=volume_size)
+        return volume
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error [create_volume(cinder_client, %s)]",
+                      (volume_name, volume_size))
+        return None
+
+
+def delete_volume(cinder_client, volume_id,
+                  forced=False):      # pragma: no cover
+    try:
+        if forced:
+            try:
+                cinder_client.volumes.detach(volume_id)
+            except Exception:  # pylint: disable=broad-except
+                log.error(sys.exc_info()[0])
+            cinder_client.volumes.force_delete(volume_id)
+        else:
+            while True:
+                volume = get_cinder_client().volumes.get(volume_id)
+                if volume.status.lower() == 'available':
+                    break
+            cinder_client.volumes.delete(volume_id)
+        return True
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error [delete_volume(cinder_client, '%s')]", volume_id)
+        return False
+
+
+def detach_volume(server_id, volume_id):      # pragma: no cover
+    try:
+        get_nova_client().volumes.delete_server_volume(server_id, volume_id)
+        return True
+    except Exception:  # pylint: disable=broad-except
+        log.exception("Error [detach_server_volume(nova_client, '%s', '%s')]",
+                      server_id, volume_id)
+        return False