540d8d64171853dd6c767bbfd760fa3d2871da9e
[yardstick.git] / yardstick / common / openstack_utils.py
1 ##############################################################################
2 # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 from __future__ import absolute_import
11
12 import os
13 import time
14 import logging
15
16 from keystoneauth1 import loading
17 from keystoneauth1 import session
18 from cinderclient import client as cinderclient
19 from novaclient import client as novaclient
20 from glanceclient import client as glanceclient
21 from neutronclient.neutron import client as neutronclient
22
23 log = logging.getLogger(__name__)
24
25 DEFAULT_HEAT_API_VERSION = '1'
26 DEFAULT_API_VERSION = '2'
27
28
29 # *********************************************
30 #   CREDENTIALS
31 # *********************************************
32 def get_credentials():
33     """Returns a creds dictionary filled with parsed from env"""
34     creds = {}
35
36     keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
37
38     if keystone_api_version is None or keystone_api_version == '2':
39         keystone_v3 = False
40         tenant_env = 'OS_TENANT_NAME'
41         tenant = 'tenant_name'
42     else:
43         keystone_v3 = True
44         tenant_env = 'OS_PROJECT_NAME'
45         tenant = 'project_name'
46
47     # The most common way to pass these info to the script is to do it
48     # through environment variables.
49     creds.update({
50         "username": os.environ.get("OS_USERNAME"),
51         "password": os.environ.get("OS_PASSWORD"),
52         "auth_url": os.environ.get("OS_AUTH_URL"),
53         tenant: os.environ.get(tenant_env)
54     })
55
56     if keystone_v3:
57         if os.getenv('OS_USER_DOMAIN_NAME') is not None:
58             creds.update({
59                 "user_domain_name": os.getenv('OS_USER_DOMAIN_NAME')
60             })
61         if os.getenv('OS_PROJECT_DOMAIN_NAME') is not None:
62             creds.update({
63                 "project_domain_name": os.getenv('OS_PROJECT_DOMAIN_NAME')
64             })
65
66     return creds
67
68
69 def get_session_auth():
70     loader = loading.get_plugin_loader('password')
71     creds = get_credentials()
72     auth = loader.load_from_options(**creds)
73     return auth
74
75
76 def get_session():
77     auth = get_session_auth()
78     try:
79         cacert = os.environ['OS_CACERT']
80     except KeyError:
81         return session.Session(auth=auth)
82     else:
83         insecure = os.getenv('OS_INSECURE', '').lower() == 'true'
84         cacert = False if insecure else cacert
85         return session.Session(auth=auth, verify=cacert)
86
87
88 def get_endpoint(service_type, endpoint_type='publicURL'):
89     auth = get_session_auth()
90     # for multi-region, we need to specify region
91     # when finding the endpoint
92     return get_session().get_endpoint(auth=auth,
93                                       service_type=service_type,
94                                       endpoint_type=endpoint_type,
95                                       region_name=os.environ.get(
96                                           "OS_REGION_NAME"))
97
98
99 # *********************************************
100 #   CLIENTS
101 # *********************************************
102 def get_heat_api_version():     # pragma: no cover
103     try:
104         api_version = os.environ['HEAT_API_VERSION']
105     except KeyError:
106         return DEFAULT_HEAT_API_VERSION
107     else:
108         log.info("HEAT_API_VERSION is set in env as '%s'", api_version)
109         return api_version
110
111
112 def get_cinder_client_version():      # pragma: no cover
113     try:
114         api_version = os.environ['OS_VOLUME_API_VERSION']
115     except KeyError:
116         return DEFAULT_API_VERSION
117     else:
118         log.info("OS_VOLUME_API_VERSION is set in env as '%s'", api_version)
119         return api_version
120
121
122 def get_cinder_client():      # pragma: no cover
123     sess = get_session()
124     return cinderclient.Client(get_cinder_client_version(), session=sess)
125
126
127 def get_nova_client_version():      # pragma: no cover
128     try:
129         api_version = os.environ['OS_COMPUTE_API_VERSION']
130     except KeyError:
131         return DEFAULT_API_VERSION
132     else:
133         log.info("OS_COMPUTE_API_VERSION is set in env as '%s'", api_version)
134         return api_version
135
136
137 def get_nova_client():      # pragma: no cover
138     sess = get_session()
139     return novaclient.Client(get_nova_client_version(), session=sess)
140
141
142 def get_neutron_client_version():   # pragma: no cover
143     try:
144         api_version = os.environ['OS_NETWORK_API_VERSION']
145     except KeyError:
146         return DEFAULT_API_VERSION
147     else:
148         log.info("OS_NETWORK_API_VERSION is set in env as '%s'", api_version)
149         return api_version
150
151
152 def get_neutron_client():   # pragma: no cover
153     sess = get_session()
154     return neutronclient.Client(get_neutron_client_version(), session=sess)
155
156
157 def get_glance_client_version():    # pragma: no cover
158     try:
159         api_version = os.environ['OS_IMAGE_API_VERSION']
160     except KeyError:
161         return DEFAULT_API_VERSION
162     else:
163         log.info("OS_IMAGE_API_VERSION is set in env as '%s'", api_version)
164         return api_version
165
166
167 def get_glance_client():    # pragma: no cover
168     sess = get_session()
169     return glanceclient.Client(get_glance_client_version(), session=sess)
170
171
172 # *********************************************
173 #   NOVA
174 # *********************************************
175 def get_instances(nova_client):     # pragma: no cover
176     try:
177         return nova_client.servers.list(search_opts={'all_tenants': 1})
178     except Exception:
179         log.exception("Error [get_instances(nova_client)]")
180
181
182 def get_instance_status(nova_client, instance):     # pragma: no cover
183     try:
184         return nova_client.servers.get(instance.id).status
185     except Exception:
186         log.exception("Error [get_instance_status(nova_client)]")
187
188
189 def get_instance_by_name(nova_client, instance_name):   # pragma: no cover
190     try:
191         return nova_client.servers.find(name=instance_name)
192     except Exception:
193         log.exception("Error [get_instance_by_name(nova_client, '%s')]",
194                       instance_name)
195
196
197 def get_aggregates(nova_client):    # pragma: no cover
198     try:
199         return nova_client.aggregates.list()
200     except Exception:
201         log.exception("Error [get_aggregates(nova_client)]")
202
203
204 def get_availability_zones(nova_client):    # pragma: no cover
205     try:
206         return nova_client.availability_zones.list()
207     except Exception:
208         log.exception("Error [get_availability_zones(nova_client)]")
209
210
211 def get_availability_zone_names(nova_client):   # pragma: no cover
212     try:
213         return [az.zoneName for az in get_availability_zones(nova_client)]
214     except Exception:
215         log.exception("Error [get_availability_zone_names(nova_client)]")
216
217
218 def create_aggregate(nova_client, aggregate_name, av_zone):  # pragma: no cover
219     try:
220         nova_client.aggregates.create(aggregate_name, av_zone)
221     except Exception:
222         log.exception("Error [create_aggregate(nova_client, %s, %s)]",
223                       aggregate_name, av_zone)
224         return False
225     else:
226         return True
227
228
229 def get_aggregate_id(nova_client, aggregate_name):      # pragma: no cover
230     try:
231         aggregates = get_aggregates(nova_client)
232         _id = next((ag.id for ag in aggregates if ag.name == aggregate_name))
233     except Exception:
234         log.exception("Error [get_aggregate_id(nova_client, %s)]",
235                       aggregate_name)
236     else:
237         return _id
238
239
240 def add_host_to_aggregate(nova_client, aggregate_name,
241                           compute_host):    # pragma: no cover
242     try:
243         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
244         nova_client.aggregates.add_host(aggregate_id, compute_host)
245     except Exception:
246         log.exception("Error [add_host_to_aggregate(nova_client, %s, %s)]",
247                       aggregate_name, compute_host)
248         return False
249     else:
250         return True
251
252
253 def create_aggregate_with_host(nova_client, aggregate_name, av_zone,
254                                compute_host):    # pragma: no cover
255     try:
256         create_aggregate(nova_client, aggregate_name, av_zone)
257         add_host_to_aggregate(nova_client, aggregate_name, compute_host)
258     except Exception:
259         log.exception("Error [create_aggregate_with_host("
260                       "nova_client, %s, %s, %s)]",
261                       aggregate_name, av_zone, compute_host)
262         return False
263     else:
264         return True
265
266
267 def create_keypair(nova_client, name, key_path=None):    # pragma: no cover
268     try:
269         with open(key_path) as fpubkey:
270             keypair = get_nova_client().keypairs.create(name=name, public_key=fpubkey.read())
271             return keypair
272     except Exception:
273         log.exception("Error [create_keypair(nova_client)]")
274
275
276 def create_instance(json_body):    # pragma: no cover
277     try:
278         return get_nova_client().servers.create(**json_body)
279     except Exception:
280         log.exception("Error create instance failed")
281         return None
282
283
284 def create_instance_and_wait_for_active(json_body):    # pragma: no cover
285     SLEEP = 3
286     VM_BOOT_TIMEOUT = 180
287     nova_client = get_nova_client()
288     instance = create_instance(json_body)
289     count = VM_BOOT_TIMEOUT / SLEEP
290     for n in range(count, -1, -1):
291         status = get_instance_status(nova_client, instance)
292         if status.lower() == "active":
293             return instance
294         elif status.lower() == "error":
295             log.error("The instance went to ERROR status.")
296             return None
297         time.sleep(SLEEP)
298     log.error("Timeout booting the instance.")
299     return None
300
301
302 def attach_server_volume(server_id, volume_id, device=None):    # pragma: no cover
303     try:
304         get_nova_client().volumes.create_server_volume(server_id, volume_id, device)
305     except Exception:
306         log.exception("Error [attach_server_volume(nova_client, '%s', '%s')]",
307                       server_id, volume_id)
308         return False
309     else:
310         return True
311
312
313 def delete_instance(nova_client, instance_id):      # pragma: no cover
314     try:
315         nova_client.servers.force_delete(instance_id)
316     except Exception:
317         log.exception("Error [delete_instance(nova_client, '%s')]",
318                       instance_id)
319         return False
320     else:
321         return True
322
323
324 def remove_host_from_aggregate(nova_client, aggregate_name,
325                                compute_host):  # pragma: no cover
326     try:
327         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
328         nova_client.aggregates.remove_host(aggregate_id, compute_host)
329     except Exception:
330         log.exception("Error remove_host_from_aggregate(nova_client, %s, %s)",
331                       aggregate_name, compute_host)
332         return False
333     else:
334         return True
335
336
337 def remove_hosts_from_aggregate(nova_client,
338                                 aggregate_name):   # pragma: no cover
339     aggregate_id = get_aggregate_id(nova_client, aggregate_name)
340     hosts = nova_client.aggregates.get(aggregate_id).hosts
341     assert(
342         all(remove_host_from_aggregate(nova_client, aggregate_name, host)
343             for host in hosts))
344
345
346 def delete_aggregate(nova_client, aggregate_name):  # pragma: no cover
347     try:
348         remove_hosts_from_aggregate(nova_client, aggregate_name)
349         nova_client.aggregates.delete(aggregate_name)
350     except Exception:
351         log.exception("Error [delete_aggregate(nova_client, %s)]",
352                       aggregate_name)
353         return False
354     else:
355         return True
356
357
358 def get_server_by_name(name):   # pragma: no cover
359     try:
360         return get_nova_client().servers.list(search_opts={'name': name})[0]
361     except IndexError:
362         log.exception('Failed to get nova client')
363         raise
364
365
366 def create_flavor(name, ram, vcpus, disk, **kwargs):   # pragma: no cover
367     try:
368         return get_nova_client().flavors.create(name, ram, vcpus, disk, **kwargs)
369     except Exception:
370         log.exception("Error [create_flavor(nova_client, %s, %s, %s, %s, %s)]",
371                       name, ram, disk, vcpus, kwargs['is_public'])
372         return None
373
374
375 def get_image_by_name(name):    # pragma: no cover
376     images = get_nova_client().images.list()
377     try:
378         return next((a for a in images if a.name == name))
379     except StopIteration:
380         log.exception('No image matched')
381
382
383 def get_flavor_id(nova_client, flavor_name):    # pragma: no cover
384     flavors = nova_client.flavors.list(detailed=True)
385     flavor_id = ''
386     for f in flavors:
387         if f.name == flavor_name:
388             flavor_id = f.id
389             break
390     return flavor_id
391
392
393 def get_flavor_by_name(name):   # pragma: no cover
394     flavors = get_nova_client().flavors.list()
395     try:
396         return next((a for a in flavors if a.name == name))
397     except StopIteration:
398         log.exception('No flavor matched')
399
400
401 def check_status(status, name, iterations, interval):   # pragma: no cover
402     for i in range(iterations):
403         try:
404             server = get_server_by_name(name)
405         except IndexError:
406             log.error('Cannot found %s server', name)
407             raise
408
409         if server.status == status:
410             return True
411
412         time.sleep(interval)
413     return False
414
415
416 def delete_flavor(flavor_id):    # pragma: no cover
417     try:
418         get_nova_client().flavors.delete(flavor_id)
419     except Exception:
420         log.exception("Error [delete_flavor(nova_client, %s)]", flavor_id)
421         return False
422     else:
423         return True
424
425
426 # *********************************************
427 #   NEUTRON
428 # *********************************************
429 def get_network_id(neutron_client, network_name):       # pragma: no cover
430     networks = neutron_client.list_networks()['networks']
431     return next((n['id'] for n in networks if n['name'] == network_name), None)
432
433
434 def get_port_id_by_ip(neutron_client, ip_address):      # pragma: no cover
435     ports = neutron_client.list_ports()['ports']
436     return next((i['id'] for i in ports for j in i.get(
437         'fixed_ips') if j['ip_address'] == ip_address), None)
438
439
440 def create_floating_ip(neutron_client, extnet_id):      # pragma: no cover
441     props = {'floating_network_id': extnet_id}
442     try:
443         ip_json = neutron_client.create_floatingip({'floatingip': props})
444         fip_addr = ip_json['floatingip']['floating_ip_address']
445         fip_id = ip_json['floatingip']['id']
446     except Exception:
447         log.error("Error [create_floating_ip(neutron_client)]")
448         return None
449     return {'fip_addr': fip_addr, 'fip_id': fip_id}
450
451
452 # *********************************************
453 #   GLANCE
454 # *********************************************
455 def get_image_id(glance_client, image_name):    # pragma: no cover
456     images = glance_client.images.list()
457     return next((i.id for i in images if i.name == image_name), None)
458
459
460 def create_image(glance_client, image_name, file_path, disk_format,
461                  container_format, min_disk, min_ram, protected, tag,
462                  public, **kwargs):    # pragma: no cover
463     if not os.path.isfile(file_path):
464         log.error("Error: file %s does not exist." % file_path)
465         return None
466     try:
467         image_id = get_image_id(glance_client, image_name)
468         if image_id is not None:
469             log.info("Image %s already exists." % image_name)
470         else:
471             log.info("Creating image '%s' from '%s'...", image_name, file_path)
472
473             image = glance_client.images.create(name=image_name,
474                                                 visibility=public,
475                                                 disk_format=disk_format,
476                                                 container_format=container_format,
477                                                 min_disk=min_disk,
478                                                 min_ram=min_ram,
479                                                 tags=tag,
480                                                 protected=protected,
481                                                 **kwargs)
482             image_id = image.id
483             with open(file_path) as image_data:
484                 glance_client.images.upload(image_id, image_data)
485         return image_id
486     except Exception:
487         log.error("Error [create_glance_image(glance_client, '%s', '%s', '%s')]",
488                   image_name, file_path, public)
489         return None
490
491
492 def delete_image(glance_client, image_id):    # pragma: no cover
493     try:
494         glance_client.images.delete(image_id)
495
496     except Exception:
497         log.exception("Error [delete_flavor(glance_client, %s)]", image_id)
498         return False
499     else:
500         return True
501
502
503 # *********************************************
504 #   CINDER
505 # *********************************************
506 def get_volume_id(volume_name):    # pragma: no cover
507     volumes = get_cinder_client().volumes.list()
508     return next((v.id for v in volumes if v.name == volume_name), None)
509
510
511 def create_volume(cinder_client, volume_name, volume_size,
512                   volume_image=False):    # pragma: no cover
513     try:
514         if volume_image:
515             volume = cinder_client.volumes.create(name=volume_name,
516                                                   size=volume_size,
517                                                   imageRef=volume_image)
518         else:
519             volume = cinder_client.volumes.create(name=volume_name,
520                                                   size=volume_size)
521         return volume
522     except Exception:
523         log.exception("Error [create_volume(cinder_client, %s)]",
524                       (volume_name, volume_size))
525         return None