Merge "Use glance to list images"
[functest.git] / functest / utils / openstack_utils.py
1 #!/usr/bin/env python
2 #
3 # jose.lausuch@ericsson.com
4 # valentin.boucher@orange.com
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10
11 import logging
12 import os.path
13 import re
14 import sys
15 import time
16
17 from keystoneauth1 import loading
18 from keystoneauth1 import session
19 from cinderclient import client as cinderclient
20 from glanceclient import client as glanceclient
21 from heatclient import client as heatclient
22 from novaclient import client as novaclient
23 from keystoneclient import client as keystoneclient
24 from neutronclient.neutron import client as neutronclient
25
26 import functest.utils.functest_utils as ft_utils
27
28 logger = logging.getLogger(__name__)
29
30 DEFAULT_API_VERSION = '2'
31 DEFAULT_HEAT_API_VERSION = '1'
32
33
34 # *********************************************
35 #   CREDENTIALS
36 # *********************************************
37 class MissingEnvVar(Exception):
38
39     def __init__(self, var):
40         self.var = var
41
42     def __str__(self):
43         return str.format("Please set the mandatory env var: {}", self.var)
44
45
46 def is_keystone_v3():
47     keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
48     if (keystone_api_version is None or
49             keystone_api_version == '2'):
50         return False
51     else:
52         return True
53
54
55 def get_rc_env_vars():
56     env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD']
57     if is_keystone_v3():
58         env_vars.extend(['OS_PROJECT_NAME',
59                          'OS_USER_DOMAIN_NAME',
60                          'OS_PROJECT_DOMAIN_NAME'])
61     else:
62         env_vars.extend(['OS_TENANT_NAME'])
63     return env_vars
64
65
66 def check_credentials():
67     """
68     Check if the OpenStack credentials (openrc) are sourced
69     """
70     env_vars = get_rc_env_vars()
71     return all(map(lambda v: v in os.environ and os.environ[v], env_vars))
72
73
74 def get_env_cred_dict():
75     env_cred_dict = {
76         'OS_USERNAME': 'username',
77         'OS_PASSWORD': 'password',
78         'OS_AUTH_URL': 'auth_url',
79         'OS_TENANT_NAME': 'tenant_name',
80         'OS_USER_DOMAIN_NAME': 'user_domain_name',
81         'OS_PROJECT_DOMAIN_NAME': 'project_domain_name',
82         'OS_PROJECT_NAME': 'project_name',
83         'OS_ENDPOINT_TYPE': 'endpoint_type',
84         'OS_REGION_NAME': 'region_name',
85         'OS_CACERT': 'https_cacert'
86     }
87     return env_cred_dict
88
89
90 def get_credentials(other_creds={}):
91     """Returns a creds dictionary filled with parsed from env
92     """
93     creds = {}
94     env_vars = get_rc_env_vars()
95     env_cred_dict = get_env_cred_dict()
96
97     for envvar in env_vars:
98         if os.getenv(envvar) is None:
99             raise MissingEnvVar(envvar)
100         else:
101             creds_key = env_cred_dict.get(envvar)
102             creds.update({creds_key: os.getenv(envvar)})
103
104     if 'tenant' in other_creds.keys():
105         if is_keystone_v3():
106             tenant = 'project_name'
107         else:
108             tenant = 'tenant_name'
109         other_creds[tenant] = other_creds.pop('tenant')
110
111     creds.update(other_creds)
112
113     return creds
114
115
116 def source_credentials(rc_file):
117     with open(rc_file, "r") as f:
118         for line in f:
119             var = line.rstrip('"\n').replace('export ', '').split("=")
120             # The two next lines should be modified as soon as rc_file
121             # conforms with common rules. Be aware that it could induce
122             # issues if value starts with '
123             key = re.sub(r'^["\' ]*|[ \'"]*$', '', var[0])
124             value = re.sub(r'^["\' ]*|[ \'"]*$', '', "".join(var[1:]))
125             os.environ[key] = value
126
127
128 def get_credentials_for_rally():
129     creds = get_credentials()
130     env_cred_dict = get_env_cred_dict()
131     rally_conf = {"type": "ExistingCloud", "admin": {}}
132     for key in creds:
133         if key == 'auth_url':
134             rally_conf[key] = creds[key]
135         else:
136             rally_conf['admin'][key] = creds[key]
137
138     endpoint_types = [('internalURL', 'internal'),
139                       ('publicURL', 'public'), ('adminURL', 'admin')]
140
141     endpoint_type = get_endpoint_type_from_env()
142     if endpoint_type is not None:
143         cred_key = env_cred_dict.get('OS_ENDPOINT_TYPE')
144         for k, v in endpoint_types:
145             if endpoint_type == v:
146                 rally_conf[cred_key] = v
147
148     region_name = os.getenv('OS_REGION_NAME')
149     if region_name is not None:
150         cred_key = env_cred_dict.get('OS_REGION_NAME')
151         rally_conf[cred_key] = region_name
152
153     cacert = os.getenv('OS_CACERT')
154     if cacert is not None:
155         cred_key = env_cred_dict.get('OS_CACERT')
156         rally_conf[cred_key] = cacert
157     return rally_conf
158
159
160 def get_endpoint_type_from_env():
161     endpoint_type = os.environ.get("OS_ENDPOINT_TYPE",
162                                    os.environ.get("OS_INTERFACE"))
163     if endpoint_type and "URL" in endpoint_type:
164         endpoint_type = endpoint_type.replace("URL", "")
165     return endpoint_type
166
167
168 def get_session_auth(other_creds={}):
169     loader = loading.get_plugin_loader('password')
170     creds = get_credentials(other_creds)
171     auth = loader.load_from_options(**creds)
172     return auth
173
174
175 def get_endpoint(service_type, endpoint_type='publicURL'):
176     auth = get_session_auth()
177     return get_session().get_endpoint(auth=auth,
178                                       service_type=service_type,
179                                       endpoint_type=endpoint_type)
180
181
182 def get_session(other_creds={}):
183     auth = get_session_auth(other_creds)
184     https_cacert = os.getenv('OS_CACERT', '')
185     https_insecure = os.getenv('OS_INSECURE', '').lower() == 'true'
186     return session.Session(auth=auth,
187                            verify=(https_cacert or not https_insecure))
188
189
190 # *********************************************
191 #   CLIENTS
192 # *********************************************
193 def get_keystone_client_version():
194     api_version = os.getenv('OS_IDENTITY_API_VERSION')
195     if api_version is not None:
196         logger.info("OS_IDENTITY_API_VERSION is set in env as '%s'",
197                     api_version)
198         return api_version
199     return DEFAULT_API_VERSION
200
201
202 def get_keystone_client(other_creds={}):
203     sess = get_session(other_creds)
204     return keystoneclient.Client(get_keystone_client_version(),
205                                  session=sess,
206                                  interface=os.getenv('OS_INTERFACE', 'admin'))
207
208
209 def get_nova_client_version():
210     api_version = os.getenv('OS_COMPUTE_API_VERSION')
211     if api_version is not None:
212         logger.info("OS_COMPUTE_API_VERSION is set in env as '%s'",
213                     api_version)
214         return api_version
215     return DEFAULT_API_VERSION
216
217
218 def get_nova_client(other_creds={}):
219     sess = get_session(other_creds)
220     return novaclient.Client(get_nova_client_version(), session=sess)
221
222
223 def get_cinder_client_version():
224     api_version = os.getenv('OS_VOLUME_API_VERSION')
225     if api_version is not None:
226         logger.info("OS_VOLUME_API_VERSION is set in env as '%s'",
227                     api_version)
228         return api_version
229     return DEFAULT_API_VERSION
230
231
232 def get_cinder_client(other_creds={}):
233     sess = get_session(other_creds)
234     return cinderclient.Client(get_cinder_client_version(), session=sess)
235
236
237 def get_neutron_client_version():
238     api_version = os.getenv('OS_NETWORK_API_VERSION')
239     if api_version is not None:
240         logger.info("OS_NETWORK_API_VERSION is set in env as '%s'",
241                     api_version)
242         return api_version
243     return DEFAULT_API_VERSION
244
245
246 def get_neutron_client(other_creds={}):
247     sess = get_session(other_creds)
248     return neutronclient.Client(get_neutron_client_version(), session=sess)
249
250
251 def get_glance_client_version():
252     api_version = os.getenv('OS_IMAGE_API_VERSION')
253     if api_version is not None:
254         logger.info("OS_IMAGE_API_VERSION is set in env as '%s'", api_version)
255         return api_version
256     return DEFAULT_API_VERSION
257
258
259 def get_glance_client(other_creds={}):
260     sess = get_session(other_creds)
261     return glanceclient.Client(get_glance_client_version(), session=sess)
262
263
264 def get_heat_client_version():
265     api_version = os.getenv('OS_ORCHESTRATION_API_VERSION')
266     if api_version is not None:
267         logger.info("OS_ORCHESTRATION_API_VERSION is set in env as '%s'",
268                     api_version)
269         return api_version
270     return DEFAULT_HEAT_API_VERSION
271
272
273 def get_heat_client(other_creds={}):
274     sess = get_session(other_creds)
275     return heatclient.Client(get_heat_client_version(), session=sess)
276
277
278 def download_and_add_image_on_glance(glance, image_name, image_url, data_dir):
279     dest_path = data_dir
280     if not os.path.exists(dest_path):
281         os.makedirs(dest_path)
282     file_name = image_url.rsplit('/')[-1]
283     if not ft_utils.download_url(image_url, dest_path):
284         return False
285
286     image = create_glance_image(
287         glance, image_name, dest_path + file_name)
288     if not image:
289         return False
290
291     return image
292
293
294 # *********************************************
295 #   NOVA
296 # *********************************************
297 def get_instances(nova_client):
298     try:
299         instances = nova_client.servers.list(search_opts={'all_tenants': 1})
300         return instances
301     except Exception as e:
302         logger.error("Error [get_instances(nova_client)]: %s" % e)
303         return None
304
305
306 def get_instance_status(nova_client, instance):
307     try:
308         instance = nova_client.servers.get(instance.id)
309         return instance.status
310     except Exception as e:
311         logger.error("Error [get_instance_status(nova_client)]: %s" % e)
312         return None
313
314
315 def get_instance_by_name(nova_client, instance_name):
316     try:
317         instance = nova_client.servers.find(name=instance_name)
318         return instance
319     except Exception as e:
320         logger.error("Error [get_instance_by_name(nova_client, '%s')]: %s"
321                      % (instance_name, e))
322         return None
323
324
325 def get_flavor_id(nova_client, flavor_name):
326     flavors = nova_client.flavors.list(detailed=True)
327     id = ''
328     for f in flavors:
329         if f.name == flavor_name:
330             id = f.id
331             break
332     return id
333
334
335 def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram):
336     flavors = nova_client.flavors.list(detailed=True)
337     id = ''
338     for f in flavors:
339         if min_ram <= f.ram and f.ram <= max_ram:
340             id = f.id
341             break
342     return id
343
344
345 def get_aggregates(nova_client):
346     try:
347         aggregates = nova_client.aggregates.list()
348         return aggregates
349     except Exception as e:
350         logger.error("Error [get_aggregates(nova_client)]: %s" % e)
351         return None
352
353
354 def get_aggregate_id(nova_client, aggregate_name):
355     try:
356         aggregates = get_aggregates(nova_client)
357         _id = [ag.id for ag in aggregates if ag.name == aggregate_name][0]
358         return _id
359     except Exception as e:
360         logger.error("Error [get_aggregate_id(nova_client, %s)]:"
361                      " %s" % (aggregate_name, e))
362         return None
363
364
365 def get_availability_zones(nova_client):
366     try:
367         availability_zones = nova_client.availability_zones.list()
368         return availability_zones
369     except Exception as e:
370         logger.error("Error [get_availability_zones(nova_client)]: %s" % e)
371         return None
372
373
374 def get_availability_zone_names(nova_client):
375     try:
376         az_names = [az.zoneName for az in get_availability_zones(nova_client)]
377         return az_names
378     except Exception as e:
379         logger.error("Error [get_availability_zone_names(nova_client)]:"
380                      " %s" % e)
381         return None
382
383
384 def create_flavor(nova_client, flavor_name, ram, disk, vcpus, public=True):
385     try:
386         flavor = nova_client.flavors.create(
387             flavor_name, ram, vcpus, disk, is_public=public)
388         try:
389             extra_specs = ft_utils.get_functest_config(
390                 'general.flavor_extra_specs')
391             flavor.set_keys(extra_specs)
392         except ValueError:
393             # flavor extra specs are not configured, therefore skip the update
394             pass
395
396     except Exception as e:
397         logger.error("Error [create_flavor(nova_client, '%s', '%s', '%s', "
398                      "'%s')]: %s" % (flavor_name, ram, disk, vcpus, e))
399         return None
400     return flavor.id
401
402
403 def get_or_create_flavor(flavor_name, ram, disk, vcpus, public=True):
404     flavor_exists = False
405     nova_client = get_nova_client()
406
407     flavor_id = get_flavor_id(nova_client, flavor_name)
408     if flavor_id != '':
409         logger.info("Using existing flavor '%s'..." % flavor_name)
410         flavor_exists = True
411     else:
412         logger.info("Creating flavor '%s' with '%s' RAM, '%s' disk size, "
413                     "'%s' vcpus..." % (flavor_name, ram, disk, vcpus))
414         flavor_id = create_flavor(
415             nova_client, flavor_name, ram, disk, vcpus, public=public)
416         if not flavor_id:
417             logger.error("Failed to create flavor '%s'..." % (flavor_name))
418         else:
419             logger.debug("Flavor '%s' with ID=%s created successfully."
420                          % (flavor_name, flavor_id))
421
422     return flavor_exists, flavor_id
423
424
425 def get_floating_ips(neutron_client):
426     try:
427         floating_ips = neutron_client.list_floatingips()
428         return floating_ips['floatingips']
429     except Exception as e:
430         logger.error("Error [get_floating_ips(neutron_client)]: %s" % e)
431         return None
432
433
434 def get_hypervisors(nova_client):
435     try:
436         nodes = []
437         hypervisors = nova_client.hypervisors.list()
438         for hypervisor in hypervisors:
439             if hypervisor.state == "up":
440                 nodes.append(hypervisor.hypervisor_hostname)
441         return nodes
442     except Exception as e:
443         logger.error("Error [get_hypervisors(nova_client)]: %s" % e)
444         return None
445
446
447 def create_aggregate(nova_client, aggregate_name, av_zone):
448     try:
449         nova_client.aggregates.create(aggregate_name, av_zone)
450         return True
451     except Exception as e:
452         logger.error("Error [create_aggregate(nova_client, %s, %s)]: %s"
453                      % (aggregate_name, av_zone, e))
454         return None
455
456
457 def add_host_to_aggregate(nova_client, aggregate_name, compute_host):
458     try:
459         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
460         nova_client.aggregates.add_host(aggregate_id, compute_host)
461         return True
462     except Exception as e:
463         logger.error("Error [add_host_to_aggregate(nova_client, %s, %s)]: %s"
464                      % (aggregate_name, compute_host, e))
465         return None
466
467
468 def create_aggregate_with_host(
469         nova_client, aggregate_name, av_zone, compute_host):
470     try:
471         create_aggregate(nova_client, aggregate_name, av_zone)
472         add_host_to_aggregate(nova_client, aggregate_name, compute_host)
473         return True
474     except Exception as e:
475         logger.error("Error [create_aggregate_with_host("
476                      "nova_client, %s, %s, %s)]: %s"
477                      % (aggregate_name, av_zone, compute_host, e))
478         return None
479
480
481 def create_instance(flavor_name,
482                     image_id,
483                     network_id,
484                     instance_name="functest-vm",
485                     confdrive=True,
486                     userdata=None,
487                     av_zone='',
488                     fixed_ip=None,
489                     files=None):
490     nova_client = get_nova_client()
491     try:
492         flavor = nova_client.flavors.find(name=flavor_name)
493     except:
494         flavors = nova_client.flavors.list()
495         logger.error("Error: Flavor '%s' not found. Available flavors are: "
496                      "\n%s" % (flavor_name, flavors))
497         return None
498     if fixed_ip is not None:
499         nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip}
500     else:
501         nics = {"net-id": network_id}
502     if userdata is None:
503         instance = nova_client.servers.create(
504             name=instance_name,
505             flavor=flavor,
506             image=image_id,
507             nics=[nics],
508             availability_zone=av_zone,
509             files=files
510         )
511     else:
512         instance = nova_client.servers.create(
513             name=instance_name,
514             flavor=flavor,
515             image=image_id,
516             nics=[nics],
517             config_drive=confdrive,
518             userdata=userdata,
519             availability_zone=av_zone,
520             files=files
521         )
522     return instance
523
524
525 def create_instance_and_wait_for_active(flavor_name,
526                                         image_id,
527                                         network_id,
528                                         instance_name="",
529                                         config_drive=False,
530                                         userdata="",
531                                         av_zone='',
532                                         fixed_ip=None,
533                                         files=None):
534     SLEEP = 3
535     VM_BOOT_TIMEOUT = 180
536     nova_client = get_nova_client()
537     instance = create_instance(flavor_name,
538                                image_id,
539                                network_id,
540                                instance_name,
541                                config_drive,
542                                userdata,
543                                av_zone=av_zone,
544                                fixed_ip=fixed_ip,
545                                files=files)
546     count = VM_BOOT_TIMEOUT / SLEEP
547     for n in range(count, -1, -1):
548         status = get_instance_status(nova_client, instance)
549         if status.lower() == "active":
550             return instance
551         elif status.lower() == "error":
552             logger.error("The instance %s went to ERROR status."
553                          % instance_name)
554             return None
555         time.sleep(SLEEP)
556     logger.error("Timeout booting the instance %s." % instance_name)
557     return None
558
559
560 def create_floating_ip(neutron_client):
561     extnet_id = get_external_net_id(neutron_client)
562     props = {'floating_network_id': extnet_id}
563     try:
564         ip_json = neutron_client.create_floatingip({'floatingip': props})
565         fip_addr = ip_json['floatingip']['floating_ip_address']
566         fip_id = ip_json['floatingip']['id']
567     except Exception as e:
568         logger.error("Error [create_floating_ip(neutron_client)]: %s" % e)
569         return None
570     return {'fip_addr': fip_addr, 'fip_id': fip_id}
571
572
573 def add_floating_ip(nova_client, server_id, floatingip_addr):
574     try:
575         nova_client.servers.add_floating_ip(server_id, floatingip_addr)
576         return True
577     except Exception as e:
578         logger.error("Error [add_floating_ip(nova_client, '%s', '%s')]: %s"
579                      % (server_id, floatingip_addr, e))
580         return False
581
582
583 def delete_instance(nova_client, instance_id):
584     try:
585         nova_client.servers.force_delete(instance_id)
586         return True
587     except Exception as e:
588         logger.error("Error [delete_instance(nova_client, '%s')]: %s"
589                      % (instance_id, e))
590         return False
591
592
593 def delete_floating_ip(neutron_client, floatingip_id):
594     try:
595         neutron_client.delete_floatingip(floatingip_id)
596         return True
597     except Exception as e:
598         logger.error("Error [delete_floating_ip(neutron_client, '%s')]: %s"
599                      % (floatingip_id, e))
600         return False
601
602
603 def remove_host_from_aggregate(nova_client, aggregate_name, compute_host):
604     try:
605         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
606         nova_client.aggregates.remove_host(aggregate_id, compute_host)
607         return True
608     except Exception as e:
609         logger.error("Error [remove_host_from_aggregate(nova_client, %s, %s)]:"
610                      " %s" % (aggregate_name, compute_host, e))
611         return False
612
613
614 def remove_hosts_from_aggregate(nova_client, aggregate_name):
615     aggregate_id = get_aggregate_id(nova_client, aggregate_name)
616     hosts = nova_client.aggregates.get(aggregate_id).hosts
617     assert(
618         all(remove_host_from_aggregate(nova_client, aggregate_name, host)
619             for host in hosts))
620
621
622 def delete_aggregate(nova_client, aggregate_name):
623     try:
624         remove_hosts_from_aggregate(nova_client, aggregate_name)
625         nova_client.aggregates.delete(aggregate_name)
626         return True
627     except Exception as e:
628         logger.error("Error [delete_aggregate(nova_client, %s)]: %s"
629                      % (aggregate_name, e))
630         return False
631
632
633 # *********************************************
634 #   NEUTRON
635 # *********************************************
636 def get_network_list(neutron_client):
637     network_list = neutron_client.list_networks()['networks']
638     if len(network_list) == 0:
639         return None
640     else:
641         return network_list
642
643
644 def get_router_list(neutron_client):
645     router_list = neutron_client.list_routers()['routers']
646     if len(router_list) == 0:
647         return None
648     else:
649         return router_list
650
651
652 def get_port_list(neutron_client):
653     port_list = neutron_client.list_ports()['ports']
654     if len(port_list) == 0:
655         return None
656     else:
657         return port_list
658
659
660 def get_network_id(neutron_client, network_name):
661     networks = neutron_client.list_networks()['networks']
662     id = ''
663     for n in networks:
664         if n['name'] == network_name:
665             id = n['id']
666             break
667     return id
668
669
670 def get_subnet_id(neutron_client, subnet_name):
671     subnets = neutron_client.list_subnets()['subnets']
672     id = ''
673     for s in subnets:
674         if s['name'] == subnet_name:
675             id = s['id']
676             break
677     return id
678
679
680 def get_router_id(neutron_client, router_name):
681     routers = neutron_client.list_routers()['routers']
682     id = ''
683     for r in routers:
684         if r['name'] == router_name:
685             id = r['id']
686             break
687     return id
688
689
690 def get_private_net(neutron_client):
691     # Checks if there is an existing shared private network
692     networks = neutron_client.list_networks()['networks']
693     if len(networks) == 0:
694         return None
695     for net in networks:
696         if (net['router:external'] is False) and (net['shared'] is True):
697             return net
698     return None
699
700
701 def get_external_net(neutron_client):
702     for network in neutron_client.list_networks()['networks']:
703         if network['router:external']:
704             return network['name']
705     return None
706
707
708 def get_external_net_id(neutron_client):
709     for network in neutron_client.list_networks()['networks']:
710         if network['router:external']:
711             return network['id']
712     return None
713
714
715 def check_neutron_net(neutron_client, net_name):
716     for network in neutron_client.list_networks()['networks']:
717         if network['name'] == net_name:
718             for subnet in network['subnets']:
719                 return True
720     return False
721
722
723 def create_neutron_net(neutron_client, name):
724     json_body = {'network': {'name': name,
725                              'admin_state_up': True}}
726     try:
727         network = neutron_client.create_network(body=json_body)
728         network_dict = network['network']
729         return network_dict['id']
730     except Exception as e:
731         logger.error("Error [create_neutron_net(neutron_client, '%s')]: %s"
732                      % (name, e))
733         return None
734
735
736 def create_neutron_subnet(neutron_client, name, cidr, net_id):
737     json_body = {'subnets': [{'name': name, 'cidr': cidr,
738                               'ip_version': 4, 'network_id': net_id}]}
739     try:
740         subnet = neutron_client.create_subnet(body=json_body)
741         return subnet['subnets'][0]['id']
742     except Exception as e:
743         logger.error("Error [create_neutron_subnet(neutron_client, '%s', "
744                      "'%s', '%s')]: %s" % (name, cidr, net_id, e))
745         return None
746
747
748 def create_neutron_router(neutron_client, name):
749     json_body = {'router': {'name': name, 'admin_state_up': True}}
750     try:
751         router = neutron_client.create_router(json_body)
752         return router['router']['id']
753     except Exception as e:
754         logger.error("Error [create_neutron_router(neutron_client, '%s')]: %s"
755                      % (name, e))
756         return None
757
758
759 def create_neutron_port(neutron_client, name, network_id, ip):
760     json_body = {'port': {
761                  'admin_state_up': True,
762                  'name': name,
763                  'network_id': network_id,
764                  'fixed_ips': [{"ip_address": ip}]
765                  }}
766     try:
767         port = neutron_client.create_port(body=json_body)
768         return port['port']['id']
769     except Exception as e:
770         logger.error("Error [create_neutron_port(neutron_client, '%s', '%s', "
771                      "'%s')]: %s" % (name, network_id, ip, e))
772         return None
773
774
775 def update_neutron_net(neutron_client, network_id, shared=False):
776     json_body = {'network': {'shared': shared}}
777     try:
778         neutron_client.update_network(network_id, body=json_body)
779         return True
780     except Exception as e:
781         logger.error("Error [update_neutron_net(neutron_client, '%s', '%s')]: "
782                      "%s" % (network_id, str(shared), e))
783         return False
784
785
786 def update_neutron_port(neutron_client, port_id, device_owner):
787     json_body = {'port': {
788                  'device_owner': device_owner,
789                  }}
790     try:
791         port = neutron_client.update_port(port=port_id,
792                                           body=json_body)
793         return port['port']['id']
794     except Exception as e:
795         logger.error("Error [update_neutron_port(neutron_client, '%s', '%s')]:"
796                      " %s" % (port_id, device_owner, e))
797         return None
798
799
800 def add_interface_router(neutron_client, router_id, subnet_id):
801     json_body = {"subnet_id": subnet_id}
802     try:
803         neutron_client.add_interface_router(router=router_id, body=json_body)
804         return True
805     except Exception as e:
806         logger.error("Error [add_interface_router(neutron_client, '%s', "
807                      "'%s')]: %s" % (router_id, subnet_id, e))
808         return False
809
810
811 def add_gateway_router(neutron_client, router_id):
812     ext_net_id = get_external_net_id(neutron_client)
813     router_dict = {'network_id': ext_net_id}
814     try:
815         neutron_client.add_gateway_router(router_id, router_dict)
816         return True
817     except Exception as e:
818         logger.error("Error [add_gateway_router(neutron_client, '%s')]: %s"
819                      % (router_id, e))
820         return False
821
822
823 def delete_neutron_net(neutron_client, network_id):
824     try:
825         neutron_client.delete_network(network_id)
826         return True
827     except Exception as e:
828         logger.error("Error [delete_neutron_net(neutron_client, '%s')]: %s"
829                      % (network_id, e))
830         return False
831
832
833 def delete_neutron_subnet(neutron_client, subnet_id):
834     try:
835         neutron_client.delete_subnet(subnet_id)
836         return True
837     except Exception as e:
838         logger.error("Error [delete_neutron_subnet(neutron_client, '%s')]: %s"
839                      % (subnet_id, e))
840         return False
841
842
843 def delete_neutron_router(neutron_client, router_id):
844     try:
845         neutron_client.delete_router(router=router_id)
846         return True
847     except Exception as e:
848         logger.error("Error [delete_neutron_router(neutron_client, '%s')]: %s"
849                      % (router_id, e))
850         return False
851
852
853 def delete_neutron_port(neutron_client, port_id):
854     try:
855         neutron_client.delete_port(port_id)
856         return True
857     except Exception as e:
858         logger.error("Error [delete_neutron_port(neutron_client, '%s')]: %s"
859                      % (port_id, e))
860         return False
861
862
863 def remove_interface_router(neutron_client, router_id, subnet_id):
864     json_body = {"subnet_id": subnet_id}
865     try:
866         neutron_client.remove_interface_router(router=router_id,
867                                                body=json_body)
868         return True
869     except Exception as e:
870         logger.error("Error [remove_interface_router(neutron_client, '%s', "
871                      "'%s')]: %s" % (router_id, subnet_id, e))
872         return False
873
874
875 def remove_gateway_router(neutron_client, router_id):
876     try:
877         neutron_client.remove_gateway_router(router_id)
878         return True
879     except Exception as e:
880         logger.error("Error [remove_gateway_router(neutron_client, '%s')]: %s"
881                      % (router_id, e))
882         return False
883
884
885 def create_network_full(neutron_client,
886                         net_name,
887                         subnet_name,
888                         router_name,
889                         cidr):
890
891     # Check if the network already exists
892     network_id = get_network_id(neutron_client, net_name)
893     subnet_id = get_subnet_id(neutron_client, subnet_name)
894     router_id = get_router_id(neutron_client, router_name)
895
896     if network_id != '' and subnet_id != '' and router_id != '':
897         logger.info("A network with name '%s' already exists..." % net_name)
898     else:
899         neutron_client.format = 'json'
900         logger.info('Creating neutron network %s...' % net_name)
901         network_id = create_neutron_net(neutron_client, net_name)
902
903         if not network_id:
904             return False
905
906         logger.debug("Network '%s' created successfully" % network_id)
907         logger.debug('Creating Subnet....')
908         subnet_id = create_neutron_subnet(neutron_client, subnet_name,
909                                           cidr, network_id)
910         if not subnet_id:
911             return None
912
913         logger.debug("Subnet '%s' created successfully" % subnet_id)
914         logger.debug('Creating Router...')
915         router_id = create_neutron_router(neutron_client, router_name)
916
917         if not router_id:
918             return None
919
920         logger.debug("Router '%s' created successfully" % router_id)
921         logger.debug('Adding router to subnet...')
922
923         if not add_interface_router(neutron_client, router_id, subnet_id):
924             return None
925
926         logger.debug("Interface added successfully.")
927
928         logger.debug('Adding gateway to router...')
929         if not add_gateway_router(neutron_client, router_id):
930             return None
931
932         logger.debug("Gateway added successfully.")
933
934     network_dic = {'net_id': network_id,
935                    'subnet_id': subnet_id,
936                    'router_id': router_id}
937     return network_dic
938
939
940 def create_shared_network_full(net_name, subnt_name, router_name, subnet_cidr):
941     neutron_client = get_neutron_client()
942
943     network_dic = create_network_full(neutron_client,
944                                       net_name,
945                                       subnt_name,
946                                       router_name,
947                                       subnet_cidr)
948     if network_dic:
949         if not update_neutron_net(neutron_client,
950                                   network_dic['net_id'],
951                                   shared=True):
952             logger.error("Failed to update network %s..." % net_name)
953             return None
954         else:
955             logger.debug("Network '%s' is available..." % net_name)
956     else:
957         logger.error("Network %s creation failed" % net_name)
958         return None
959     return network_dic
960
961
962 def create_bgpvpn(neutron_client, **kwargs):
963     # route_distinguishers
964     # route_targets
965     json_body = {"bgpvpn": kwargs}
966     return neutron_client.create_bgpvpn(json_body)
967
968
969 def create_network_association(neutron_client, bgpvpn_id, neutron_network_id):
970     json_body = {"network_association": {"network_id": neutron_network_id}}
971     return neutron_client.create_network_association(bgpvpn_id, json_body)
972
973
974 def create_router_association(neutron_client, bgpvpn_id, router_id):
975     json_body = {"router_association": {"router_id": router_id}}
976     return neutron_client.create_router_association(bgpvpn_id, json_body)
977
978
979 def update_bgpvpn(neutron_client, bgpvpn_id, **kwargs):
980     json_body = {"bgpvpn": kwargs}
981     return neutron_client.update_bgpvpn(bgpvpn_id, json_body)
982
983
984 def delete_bgpvpn(neutron_client, bgpvpn_id):
985     return neutron_client.delete_bgpvpn(bgpvpn_id)
986
987
988 def get_bgpvpn(neutron_client, bgpvpn_id):
989     return neutron_client.show_bgpvpn(bgpvpn_id)
990
991
992 def get_bgpvpn_routers(neutron_client, bgpvpn_id):
993     return get_bgpvpn(neutron_client, bgpvpn_id)['bgpvpn']['routers']
994
995
996 def get_bgpvpn_networks(neutron_client, bgpvpn_id):
997     return get_bgpvpn(neutron_client, bgpvpn_id)['bgpvpn']['networks']
998
999 # *********************************************
1000 #   SEC GROUPS
1001 # *********************************************
1002
1003
1004 def get_security_groups(neutron_client):
1005     try:
1006         security_groups = neutron_client.list_security_groups()[
1007             'security_groups']
1008         return security_groups
1009     except Exception as e:
1010         logger.error("Error [get_security_groups(neutron_client)]: %s" % e)
1011         return None
1012
1013
1014 def get_security_group_id(neutron_client, sg_name):
1015     security_groups = get_security_groups(neutron_client)
1016     id = ''
1017     for sg in security_groups:
1018         if sg['name'] == sg_name:
1019             id = sg['id']
1020             break
1021     return id
1022
1023
1024 def create_security_group(neutron_client, sg_name, sg_description):
1025     json_body = {'security_group': {'name': sg_name,
1026                                     'description': sg_description}}
1027     try:
1028         secgroup = neutron_client.create_security_group(json_body)
1029         return secgroup['security_group']
1030     except Exception as e:
1031         logger.error("Error [create_security_group(neutron_client, '%s', "
1032                      "'%s')]: %s" % (sg_name, sg_description, e))
1033         return None
1034
1035
1036 def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
1037                          port_range_min=None, port_range_max=None):
1038     # We create a security group in 2 steps
1039     # 1 - we check the format and set the json body accordingly
1040     # 2 - we call neturon client to create the security group
1041
1042     # Format check
1043     json_body = {'security_group_rule': {'direction': direction,
1044                                          'security_group_id': sg_id,
1045                                          'protocol': protocol}}
1046     # parameters may be
1047     # - both None => we do nothing
1048     # - both Not None => we add them to the json description
1049     # but one cannot be None is the other is not None
1050     if (port_range_min is not None and port_range_max is not None):
1051         # add port_range in json description
1052         json_body['security_group_rule']['port_range_min'] = port_range_min
1053         json_body['security_group_rule']['port_range_max'] = port_range_max
1054         logger.debug("Security_group format set (port range included)")
1055     else:
1056         # either both port range are set to None => do nothing
1057         # or one is set but not the other => log it and return False
1058         if port_range_min is None and port_range_max is None:
1059             logger.debug("Security_group format set (no port range mentioned)")
1060         else:
1061             logger.error("Bad security group format."
1062                          "One of the port range is not properly set:"
1063                          "range min: {},"
1064                          "range max: {}".format(port_range_min,
1065                                                 port_range_max))
1066             return False
1067
1068     # Create security group using neutron client
1069     try:
1070         neutron_client.create_security_group_rule(json_body)
1071         return True
1072     except:
1073         logger.exception("Impossible to create_security_group_rule,"
1074                          "security group rule probably already exists")
1075         return False
1076
1077
1078 def get_security_group_rules(neutron_client, sg_id):
1079     try:
1080         security_rules = neutron_client.list_security_group_rules()[
1081             'security_group_rules']
1082         security_rules = [rule for rule in security_rules
1083                           if rule["security_group_id"] == sg_id]
1084         return security_rules
1085     except Exception as e:
1086         logger.error("Error [get_security_group_rules(neutron_client, sg_id)]:"
1087                      " %s" % e)
1088         return None
1089
1090
1091 def check_security_group_rules(neutron_client, sg_id, direction, protocol,
1092                                port_min=None, port_max=None):
1093     try:
1094         security_rules = get_security_group_rules(neutron_client, sg_id)
1095         security_rules = [rule for rule in security_rules
1096                           if (rule["direction"].lower() == direction and
1097                               rule["protocol"].lower() == protocol and
1098                               rule["port_range_min"] == port_min and
1099                               rule["port_range_max"] == port_max)]
1100         if len(security_rules) == 0:
1101             return True
1102         else:
1103             return False
1104     except Exception as e:
1105         logger.error("Error [check_security_group_rules("
1106                      " neutron_client, sg_id, direction,"
1107                      " protocol, port_min=None, port_max=None)]: "
1108                      "%s" % e)
1109         return None
1110
1111
1112 def create_security_group_full(neutron_client,
1113                                sg_name, sg_description):
1114     sg_id = get_security_group_id(neutron_client, sg_name)
1115     if sg_id != '':
1116         logger.info("Using existing security group '%s'..." % sg_name)
1117     else:
1118         logger.info("Creating security group  '%s'..." % sg_name)
1119         SECGROUP = create_security_group(neutron_client,
1120                                          sg_name,
1121                                          sg_description)
1122         if not SECGROUP:
1123             logger.error("Failed to create the security group...")
1124             return None
1125
1126         sg_id = SECGROUP['id']
1127
1128         logger.debug("Security group '%s' with ID=%s created successfully."
1129                      % (SECGROUP['name'], sg_id))
1130
1131         logger.debug("Adding ICMP rules in security group '%s'..."
1132                      % sg_name)
1133         if not create_secgroup_rule(neutron_client, sg_id,
1134                                     'ingress', 'icmp'):
1135             logger.error("Failed to create the security group rule...")
1136             return None
1137
1138         logger.debug("Adding SSH rules in security group '%s'..."
1139                      % sg_name)
1140         if not create_secgroup_rule(
1141                 neutron_client, sg_id, 'ingress', 'tcp', '22', '22'):
1142             logger.error("Failed to create the security group rule...")
1143             return None
1144
1145         if not create_secgroup_rule(
1146                 neutron_client, sg_id, 'egress', 'tcp', '22', '22'):
1147             logger.error("Failed to create the security group rule...")
1148             return None
1149     return sg_id
1150
1151
1152 def add_secgroup_to_instance(nova_client, instance_id, secgroup_id):
1153     try:
1154         nova_client.servers.add_security_group(instance_id, secgroup_id)
1155         return True
1156     except Exception as e:
1157         logger.error("Error [add_secgroup_to_instance(nova_client, '%s', "
1158                      "'%s')]: %s" % (instance_id, secgroup_id, e))
1159         return False
1160
1161
1162 def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
1163     json_body = {"quota": {
1164         "security_group": sg_quota,
1165         "security_group_rule": sg_rule_quota
1166     }}
1167
1168     try:
1169         neutron_client.update_quota(tenant_id=tenant_id,
1170                                     body=json_body)
1171         return True
1172     except Exception as e:
1173         logger.error("Error [update_sg_quota(neutron_client, '%s', '%s', "
1174                      "'%s')]: %s" % (tenant_id, sg_quota, sg_rule_quota, e))
1175         return False
1176
1177
1178 def delete_security_group(neutron_client, secgroup_id):
1179     try:
1180         neutron_client.delete_security_group(secgroup_id)
1181         return True
1182     except Exception as e:
1183         logger.error("Error [delete_security_group(neutron_client, '%s')]: %s"
1184                      % (secgroup_id, e))
1185         return False
1186
1187
1188 # *********************************************
1189 #   GLANCE
1190 # *********************************************
1191 def get_images(glance_client):
1192     try:
1193         images = glance_client.images.list()
1194         return images
1195     except Exception as e:
1196         logger.error("Error [get_images]: %s" % e)
1197         return None
1198
1199
1200 def get_image_id(glance_client, image_name):
1201     images = glance_client.images.list()
1202     id = ''
1203     for i in images:
1204         if i.name == image_name:
1205             id = i.id
1206             break
1207     return id
1208
1209
1210 def create_glance_image(glance_client, image_name, file_path, disk="qcow2",
1211                         container="bare", public="public"):
1212     if not os.path.isfile(file_path):
1213         logger.error("Error: file %s does not exist." % file_path)
1214         return None
1215     try:
1216         image_id = get_image_id(glance_client, image_name)
1217         if image_id != '':
1218             logger.info("Image %s already exists." % image_name)
1219         else:
1220             logger.info("Creating image '%s' from '%s'..." % (image_name,
1221                                                               file_path))
1222
1223             image = glance_client.images.create(name=image_name,
1224                                                 visibility=public,
1225                                                 disk_format=disk,
1226                                                 container_format=container)
1227             image_id = image.id
1228             with open(file_path) as image_data:
1229                 glance_client.images.upload(image_id, image_data)
1230         return image_id
1231     except Exception as e:
1232         logger.error("Error [create_glance_image(glance_client, '%s', '%s', "
1233                      "'%s')]: %s" % (image_name, file_path, public, e))
1234         return None
1235
1236
1237 def get_or_create_image(name, path, format):
1238     image_exists = False
1239     glance_client = get_glance_client()
1240
1241     image_id = get_image_id(glance_client, name)
1242     if image_id != '':
1243         logger.info("Using existing image '%s'..." % name)
1244         image_exists = True
1245     else:
1246         logger.info("Creating image '%s' from '%s'..." % (name, path))
1247         image_id = create_glance_image(glance_client, name, path, format)
1248         if not image_id:
1249             logger.error("Failed to create a Glance image...")
1250         else:
1251             logger.debug("Image '%s' with ID=%s created successfully."
1252                          % (name, image_id))
1253
1254     return image_exists, image_id
1255
1256
1257 def delete_glance_image(glance_client, image_id):
1258     try:
1259         glance_client.images.delete(image_id)
1260         return True
1261     except Exception as e:
1262         logger.error("Error [delete_glance_image(glance_client, '%s')]: %s"
1263                      % (image_id, e))
1264         return False
1265
1266
1267 # *********************************************
1268 #   CINDER
1269 # *********************************************
1270 def get_volumes(cinder_client):
1271     try:
1272         volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
1273         return volumes
1274     except Exception as e:
1275         logger.error("Error [get_volumes(cinder_client)]: %s" % e)
1276         return None
1277
1278
1279 def list_volume_types(cinder_client, public=True, private=True):
1280     try:
1281         volume_types = cinder_client.volume_types.list()
1282         if not public:
1283             volume_types = [vt for vt in volume_types if not vt.is_public]
1284         if not private:
1285             volume_types = [vt for vt in volume_types if vt.is_public]
1286         return volume_types
1287     except Exception as e:
1288         logger.error("Error [list_volume_types(cinder_client)]: %s" % e)
1289         return None
1290
1291
1292 def create_volume_type(cinder_client, name):
1293     try:
1294         volume_type = cinder_client.volume_types.create(name)
1295         return volume_type
1296     except Exception as e:
1297         logger.error("Error [create_volume_type(cinder_client, '%s')]: %s"
1298                      % (name, e))
1299         return None
1300
1301
1302 def update_cinder_quota(cinder_client, tenant_id, vols_quota,
1303                         snapshots_quota, gigabytes_quota):
1304     quotas_values = {"volumes": vols_quota,
1305                      "snapshots": snapshots_quota,
1306                      "gigabytes": gigabytes_quota}
1307
1308     try:
1309         cinder_client.quotas.update(tenant_id, **quotas_values)
1310         return True
1311     except Exception as e:
1312         logger.error("Error [update_cinder_quota(cinder_client, '%s', '%s', "
1313                      "'%s' '%s')]: %s" % (tenant_id, vols_quota,
1314                                           snapshots_quota, gigabytes_quota, e))
1315         return False
1316
1317
1318 def delete_volume(cinder_client, volume_id, forced=False):
1319     try:
1320         if forced:
1321             try:
1322                 cinder_client.volumes.detach(volume_id)
1323             except:
1324                 logger.error(sys.exc_info()[0])
1325             cinder_client.volumes.force_delete(volume_id)
1326         else:
1327             cinder_client.volumes.delete(volume_id)
1328         return True
1329     except Exception as e:
1330         logger.error("Error [delete_volume(cinder_client, '%s', '%s')]: %s"
1331                      % (volume_id, str(forced), e))
1332         return False
1333
1334
1335 def delete_volume_type(cinder_client, volume_type):
1336     try:
1337         cinder_client.volume_types.delete(volume_type)
1338         return True
1339     except Exception as e:
1340         logger.error("Error [delete_volume_type(cinder_client, '%s')]: %s"
1341                      % (volume_type, e))
1342         return False
1343
1344
1345 # *********************************************
1346 #   KEYSTONE
1347 # *********************************************
1348 def get_tenants(keystone_client):
1349     try:
1350         if is_keystone_v3():
1351             tenants = keystone_client.projects.list()
1352         else:
1353             tenants = keystone_client.tenants.list()
1354         return tenants
1355     except Exception as e:
1356         logger.error("Error [get_tenants(keystone_client)]: %s" % e)
1357         return None
1358
1359
1360 def get_users(keystone_client):
1361     try:
1362         users = keystone_client.users.list()
1363         return users
1364     except Exception as e:
1365         logger.error("Error [get_users(keystone_client)]: %s" % e)
1366         return None
1367
1368
1369 def get_tenant_id(keystone_client, tenant_name):
1370     tenants = get_tenants(keystone_client)
1371     id = ''
1372     for t in tenants:
1373         if t.name == tenant_name:
1374             id = t.id
1375             break
1376     return id
1377
1378
1379 def get_user_id(keystone_client, user_name):
1380     users = get_users(keystone_client)
1381     id = ''
1382     for u in users:
1383         if u.name == user_name:
1384             id = u.id
1385             break
1386     return id
1387
1388
1389 def get_role_id(keystone_client, role_name):
1390     roles = keystone_client.roles.list()
1391     id = ''
1392     for r in roles:
1393         if r.name == role_name:
1394             id = r.id
1395             break
1396     return id
1397
1398
1399 def create_tenant(keystone_client, tenant_name, tenant_description):
1400     try:
1401         if is_keystone_v3():
1402             tenant = keystone_client.projects.create(
1403                 name=tenant_name,
1404                 description=tenant_description,
1405                 domain="default",
1406                 enabled=True)
1407         else:
1408             tenant = keystone_client.tenants.create(tenant_name,
1409                                                     tenant_description,
1410                                                     enabled=True)
1411         return tenant.id
1412     except Exception as e:
1413         logger.error("Error [create_tenant(keystone_client, '%s', '%s')]: %s"
1414                      % (tenant_name, tenant_description, e))
1415         return None
1416
1417
1418 def get_or_create_tenant(keystone_client, tenant_name, tenant_description):
1419     tenant_id = get_tenant_id(keystone_client, tenant_name)
1420     if not tenant_id:
1421         tenant_id = create_tenant(keystone_client, tenant_name,
1422                                   tenant_description)
1423
1424     return tenant_id
1425
1426
1427 def get_or_create_tenant_for_vnf(keystone_client, tenant_name,
1428                                  tenant_description):
1429     """Get or Create a Tenant
1430
1431         Args:
1432             keystone_client: keystone client reference
1433             tenant_name: the name of the tenant
1434             tenant_description: the description of the tenant
1435
1436         return False if tenant retrieved though get
1437         return True if tenant created
1438         raise Exception if error during processing
1439     """
1440     try:
1441         tenant_id = get_tenant_id(keystone_client, tenant_name)
1442         if not tenant_id:
1443             tenant_id = create_tenant(keystone_client, tenant_name,
1444                                       tenant_description)
1445             return True
1446         else:
1447             return False
1448     except:
1449         raise Exception("Impossible to create a Tenant for the VNF {}".format(
1450                             tenant_name))
1451
1452
1453 def create_user(keystone_client, user_name, user_password,
1454                 user_email, tenant_id):
1455     try:
1456         if is_keystone_v3():
1457             user = keystone_client.users.create(name=user_name,
1458                                                 password=user_password,
1459                                                 email=user_email,
1460                                                 project_id=tenant_id,
1461                                                 enabled=True)
1462         else:
1463             user = keystone_client.users.create(user_name,
1464                                                 user_password,
1465                                                 user_email,
1466                                                 tenant_id,
1467                                                 enabled=True)
1468         return user.id
1469     except Exception as e:
1470         logger.error("Error [create_user(keystone_client, '%s', '%s', '%s'"
1471                      "'%s')]: %s" % (user_name, user_password,
1472                                      user_email, tenant_id, e))
1473         return None
1474
1475
1476 def get_or_create_user(keystone_client, user_name, user_password,
1477                        tenant_id, user_email=None):
1478     user_id = get_user_id(keystone_client, user_name)
1479     if not user_id:
1480         user_id = create_user(keystone_client, user_name, user_password,
1481                               user_email, tenant_id)
1482     return user_id
1483
1484
1485 def get_or_create_user_for_vnf(keystone_client, vnf_ref):
1486     """Get or Create user for VNF
1487
1488         Args:
1489             keystone_client: keystone client reference
1490             vnf_ref: VNF reference used as user name & password, tenant name
1491
1492         return False if user retrieved through get
1493         return True if user created
1494         raise Exception if error during processing
1495     """
1496     try:
1497         user_id = get_user_id(keystone_client, vnf_ref)
1498         tenant_id = get_tenant_id(keystone_client, vnf_ref)
1499         if not user_id:
1500             user_id = create_user(keystone_client, vnf_ref, vnf_ref,
1501                                   "", tenant_id)
1502             return True
1503         else:
1504             return False
1505         add_role_user(keystone_client, user_id, 'admin', vnf_ref)
1506     except:
1507         raise Exception("Impossible to create a user for the VNF {}".format(
1508             vnf_ref))
1509
1510
1511 def add_role_user(keystone_client, user_id, role_id, tenant_id):
1512     try:
1513         if is_keystone_v3():
1514             keystone_client.roles.grant(role=role_id,
1515                                         user=user_id,
1516                                         project=tenant_id)
1517         else:
1518             keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
1519         return True
1520     except Exception as e:
1521         logger.error("Error [add_role_user(keystone_client, '%s', '%s'"
1522                      "'%s')]: %s " % (user_id, role_id, tenant_id, e))
1523         return False
1524
1525
1526 def delete_tenant(keystone_client, tenant_id):
1527     try:
1528         if is_keystone_v3():
1529             keystone_client.projects.delete(tenant_id)
1530         else:
1531             keystone_client.tenants.delete(tenant_id)
1532         return True
1533     except Exception as e:
1534         logger.error("Error [delete_tenant(keystone_client, '%s')]: %s"
1535                      % (tenant_id, e))
1536         return False
1537
1538
1539 def delete_user(keystone_client, user_id):
1540     try:
1541         keystone_client.users.delete(user_id)
1542         return True
1543     except Exception as e:
1544         logger.error("Error [delete_user(keystone_client, '%s')]: %s"
1545                      % (user_id, e))
1546         return False
1547
1548
1549 # *********************************************
1550 #   HEAT
1551 # *********************************************
1552 def get_resource(heat_client, stack_id, resource):
1553     try:
1554         resources = heat_client.resources.get(stack_id, resource)
1555         return resources
1556     except Exception as e:
1557         logger.error("Error [get_resource]: %s" % e)
1558         return None