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