# http://www.apache.org/licenses/LICENSE-2.0
#
-import os
+import logging
import os.path
-import subprocess
+import re
import sys
import time
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'
# *********************************************
return str.format("Please set the mandatory env var: {}", self.var)
+def is_keystone_v3():
+ keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
+ if (keystone_api_version is None or
+ keystone_api_version == '2'):
+ return False
+ else:
+ return True
+
+
+def get_rc_env_vars():
+ env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD']
+ if is_keystone_v3():
+ env_vars.extend(['OS_PROJECT_NAME',
+ 'OS_USER_DOMAIN_NAME',
+ 'OS_PROJECT_DOMAIN_NAME'])
+ else:
+ env_vars.extend(['OS_TENANT_NAME'])
+ return env_vars
+
+
def check_credentials():
"""
Check if the OpenStack credentials (openrc) are sourced
"""
- env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD', 'OS_TENANT_NAME']
+ env_vars = get_rc_env_vars()
return all(map(lambda v: v in os.environ and os.environ[v], env_vars))
-def get_credentials():
+def get_env_cred_dict():
+ env_cred_dict = {
+ 'OS_USERNAME': 'username',
+ 'OS_PASSWORD': 'password',
+ 'OS_AUTH_URL': 'auth_url',
+ 'OS_TENANT_NAME': 'tenant_name',
+ 'OS_USER_DOMAIN_NAME': 'user_domain_name',
+ 'OS_PROJECT_DOMAIN_NAME': 'project_domain_name',
+ 'OS_PROJECT_NAME': 'project_name',
+ 'OS_ENDPOINT_TYPE': 'endpoint_type',
+ 'OS_REGION_NAME': 'region_name',
+ 'OS_CACERT': 'https_cacert'
+ }
+ return env_cred_dict
+
+
+def get_credentials(other_creds={}):
"""Returns a creds dictionary filled with parsed from env
"""
creds = {}
+ env_vars = get_rc_env_vars()
+ env_cred_dict = get_env_cred_dict()
- 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'
-
- # Check that the env vars exists:
- envvars = ('OS_USERNAME', 'OS_PASSWORD', 'OS_AUTH_URL', tenant_env)
- for envvar in envvars:
+ for envvar in env_vars:
if os.getenv(envvar) is None:
raise MissingEnvVar(envvar)
+ else:
+ creds_key = env_cred_dict.get(envvar)
+ creds.update({creds_key: os.getenv(envvar)})
+
+ if 'tenant' in other_creds.keys():
+ if is_keystone_v3():
+ tenant = 'project_name'
+ else:
+ tenant = 'tenant_name'
+ other_creds[tenant] = other_creds.pop('tenant')
+
+ creds.update(other_creds)
- # 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')
- })
-
- if os.getenv('OS_ENDPOINT_TYPE') is not None:
- creds.update({
- "endpoint_type": os.environ.get("OS_ENDPOINT_TYPE")
- })
- if os.getenv('OS_REGION_NAME') is not None:
- creds.update({
- "region_name": os.environ.get("OS_REGION_NAME")
- })
- cacert = os.environ.get("OS_CACERT")
- if cacert is not None:
- # each openstack client uses differnt kwargs for this
- creds.update({"cacert": cacert,
- "ca_cert": cacert,
- "https_ca_cert": cacert,
- "https_cacert": cacert,
- "ca_file": cacert})
- creds.update({"insecure": "True", "https_insecure": "True"})
- if not os.path.isfile(cacert):
- logger.info("WARNING: The 'OS_CACERT' environment variable is "
- "set to %s but the file does not exist." % cacert)
return creds
def source_credentials(rc_file):
- pipe = subprocess.Popen(". %s; env" % rc_file, stdout=subprocess.PIPE,
- shell=True)
- output = pipe.communicate()[0]
- env = dict((line.split("=", 1) for line in output.splitlines()))
- os.environ.update(env)
- return env
+ with open(rc_file, "r") as f:
+ for line in f:
+ var = line.rstrip('"\n').replace('export ', '').split("=")
+ # 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
def get_credentials_for_rally():
creds = get_credentials()
- keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
- if (keystone_api_version is None or
- keystone_api_version == '2'):
- admin_keys = ['username', 'tenant_name', 'password']
- else:
- admin_keys = ['username', 'password', 'user_domain_name',
- 'project_name', 'project_domain_name']
+ env_cred_dict = get_env_cred_dict()
+ rally_conf = {"type": "ExistingCloud", "admin": {}}
+ for key in creds:
+ if key == 'auth_url':
+ rally_conf[key] = creds[key]
+ else:
+ rally_conf['admin'][key] = creds[key]
endpoint_types = [('internalURL', 'internal'),
('publicURL', 'public'), ('adminURL', 'admin')]
- if 'endpoint_type' in creds.keys():
+
+ 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 creds['endpoint_type'] == k:
- creds['endpoint_type'] = v
- rally_conf = {"type": "ExistingCloud", "admin": {}}
- for key in creds:
- if key in admin_keys:
- rally_conf['admin'][key] = creds[key]
- else:
- rally_conf[key] = creds[key]
+ 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_session_auth():
+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()
+ creds = get_credentials(other_creds)
auth = loader.load_from_options(**creds)
return auth
endpoint_type=endpoint_type)
-def get_session():
- auth = get_session_auth()
- return session.Session(auth=auth)
+def get_session(other_creds={}):
+ auth = get_session_auth(other_creds)
+ 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)
# *********************************************
return DEFAULT_API_VERSION
-def get_keystone_client():
- sess = get_session()
- return keystoneclient.Client(get_keystone_client_version(), session=sess)
+def get_keystone_client(other_creds={}):
+ sess = get_session(other_creds)
+ return keystoneclient.Client(get_keystone_client_version(),
+ session=sess,
+ interface=os.getenv('OS_INTERFACE', 'admin'))
def get_nova_client_version():
return DEFAULT_API_VERSION
-def get_nova_client():
- sess = get_session()
+def get_nova_client(other_creds={}):
+ sess = get_session(other_creds)
return novaclient.Client(get_nova_client_version(), session=sess)
return DEFAULT_API_VERSION
-def get_cinder_client():
- sess = get_session()
+def get_cinder_client(other_creds={}):
+ sess = get_session(other_creds)
return cinderclient.Client(get_cinder_client_version(), session=sess)
return DEFAULT_API_VERSION
-def get_neutron_client():
- sess = get_session()
+def get_neutron_client(other_creds={}):
+ sess = get_session(other_creds)
return neutronclient.Client(get_neutron_client_version(), session=sess)
return DEFAULT_API_VERSION
-def get_glance_client():
- sess = get_session()
+def get_glance_client(other_creds={}):
+ sess = get_session(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)
+
+
# *********************************************
# NOVA
# *********************************************
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, 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, 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)
# *********************************************
def get_tenants(keystone_client):
try:
- tenants = keystone_client.tenants.list()
+ if is_keystone_v3():
+ tenants = keystone_client.projects.list()
+ else:
+ tenants = keystone_client.tenants.list()
return tenants
except Exception, e:
logger.error("Error [get_tenants(keystone_client)]: %s" % e)
def get_tenant_id(keystone_client, tenant_name):
- tenants = keystone_client.tenants.list()
+ tenants = get_tenants(keystone_client)
id = ''
for t in tenants:
if t.name == tenant_name:
def get_user_id(keystone_client, user_name):
- users = keystone_client.users.list()
+ users = get_users(keystone_client)
id = ''
for u in users:
if u.name == user_name:
def create_tenant(keystone_client, tenant_name, tenant_description):
try:
- tenant = keystone_client.tenants.create(tenant_name,
- tenant_description,
- enabled=True)
+ if is_keystone_v3():
+ tenant = keystone_client.projects.create(
+ name=tenant_name,
+ description=tenant_description,
+ domain="default",
+ enabled=True)
+ else:
+ tenant = keystone_client.tenants.create(tenant_name,
+ tenant_description,
+ enabled=True)
return tenant.id
except Exception, e:
logger.error("Error [create_tenant(keystone_client, '%s', '%s')]: %s"
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 create_user(keystone_client, user_name, user_password,
user_email, tenant_id):
try:
- user = keystone_client.users.create(user_name, user_password,
- user_email, tenant_id,
- enabled=True)
+ if is_keystone_v3():
+ user = keystone_client.users.create(name=user_name,
+ password=user_password,
+ email=user_email,
+ project_id=tenant_id,
+ enabled=True)
+ else:
+ user = keystone_client.users.create(user_name,
+ user_password,
+ user_email,
+ tenant_id,
+ enabled=True)
return user.id
except Exception, e:
logger.error("Error [create_user(keystone_client, '%s', '%s', '%s'"
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 add_role_user(keystone_client, user_id, role_id, tenant_id):
try:
- keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
+ if is_keystone_v3():
+ keystone_client.roles.grant(role=role_id,
+ user=user_id,
+ project=tenant_id)
+ else:
+ keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
return True
except Exception, e:
logger.error("Error [add_role_user(keystone_client, '%s', '%s'"
def delete_tenant(keystone_client, tenant_id):
try:
- keystone_client.tenants.delete(tenant_id)
+ if is_keystone_v3():
+ keystone_client.projects.delete(tenant_id)
+ else:
+ keystone_client.tenants.delete(tenant_id)
return True
except Exception, e:
logger.error("Error [delete_tenant(keystone_client, '%s')]: %s"
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, e:
+ logger.error("Error [get_resource]: %s" % e)
+ return None