Merge "Yardstick install storperf update"
[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 novaclient import client as novaclient
19 from glanceclient import client as glanceclient
20 from neutronclient.neutron import client as neutronclient
21
22 log = logging.getLogger(__name__)
23
24 DEFAULT_HEAT_API_VERSION = '1'
25 DEFAULT_API_VERSION = '2'
26
27
28 # *********************************************
29 #   CREDENTIALS
30 # *********************************************
31 def get_credentials():
32     """Returns a creds dictionary filled with parsed from env"""
33     creds = {}
34
35     keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
36
37     if keystone_api_version is None or keystone_api_version == '2':
38         keystone_v3 = False
39         tenant_env = 'OS_TENANT_NAME'
40         tenant = 'tenant_name'
41     else:
42         keystone_v3 = True
43         tenant_env = 'OS_PROJECT_NAME'
44         tenant = 'project_name'
45
46     # The most common way to pass these info to the script is to do it
47     # through environment variables.
48     creds.update({
49         "username": os.environ.get("OS_USERNAME"),
50         "password": os.environ.get("OS_PASSWORD"),
51         "auth_url": os.environ.get("OS_AUTH_URL"),
52         tenant: os.environ.get(tenant_env)
53     })
54
55     if keystone_v3:
56         if os.getenv('OS_USER_DOMAIN_NAME') is not None:
57             creds.update({
58                 "user_domain_name": os.getenv('OS_USER_DOMAIN_NAME')
59             })
60         if os.getenv('OS_PROJECT_DOMAIN_NAME') is not None:
61             creds.update({
62                 "project_domain_name": os.getenv('OS_PROJECT_DOMAIN_NAME')
63             })
64
65     return creds
66
67
68 def get_session_auth():
69     loader = loading.get_plugin_loader('password')
70     creds = get_credentials()
71     auth = loader.load_from_options(**creds)
72     return auth
73
74
75 def get_session():
76     auth = get_session_auth()
77     try:
78         cacert = os.environ['OS_CACERT']
79     except KeyError:
80         return session.Session(auth=auth)
81     else:
82         insecure = os.getenv('OS_INSECURE', '').lower() == 'true'
83         cacert = False if insecure else cacert
84         return session.Session(auth=auth, verify=cacert)
85
86
87 def get_endpoint(service_type, endpoint_type='publicURL'):
88     auth = get_session_auth()
89     # for multi-region, we need to specify region
90     # when finding the endpoint
91     return get_session().get_endpoint(auth=auth,
92                                       service_type=service_type,
93                                       endpoint_type=endpoint_type,
94                                       region_name=os.environ.get(
95                                           "OS_REGION_NAME"))
96
97
98 # *********************************************
99 #   CLIENTS
100 # *********************************************
101 def get_heat_api_version():     # pragma: no cover
102     try:
103         api_version = os.environ['HEAT_API_VERSION']
104     except KeyError:
105         return DEFAULT_HEAT_API_VERSION
106     else:
107         log.info("HEAT_API_VERSION is set in env as '%s'", api_version)
108         return api_version
109
110
111 def get_nova_client_version():      # pragma: no cover
112     try:
113         api_version = os.environ['OS_COMPUTE_API_VERSION']
114     except KeyError:
115         return DEFAULT_API_VERSION
116     else:
117         log.info("OS_COMPUTE_API_VERSION is set in env as '%s'", api_version)
118         return api_version
119
120
121 def get_nova_client():      # pragma: no cover
122     sess = get_session()
123     return novaclient.Client(get_nova_client_version(), session=sess)
124
125
126 def get_neutron_client_version():   # pragma: no cover
127     try:
128         api_version = os.environ['OS_NETWORK_API_VERSION']
129     except KeyError:
130         return DEFAULT_API_VERSION
131     else:
132         log.info("OS_NETWORK_API_VERSION is set in env as '%s'", api_version)
133         return api_version
134
135
136 def get_neutron_client():   # pragma: no cover
137     sess = get_session()
138     return neutronclient.Client(get_neutron_client_version(), session=sess)
139
140
141 def get_glance_client_version():    # pragma: no cover
142     try:
143         api_version = os.environ['OS_IMAGE_API_VERSION']
144     except KeyError:
145         return DEFAULT_API_VERSION
146     else:
147         log.info("OS_IMAGE_API_VERSION is set in env as '%s'", api_version)
148         return api_version
149
150
151 def get_glance_client():    # pragma: no cover
152     sess = get_session()
153     return glanceclient.Client(get_glance_client_version(), session=sess)
154
155
156 # *********************************************
157 #   NOVA
158 # *********************************************
159 def get_instances(nova_client):     # pragma: no cover
160     try:
161         return nova_client.servers.list(search_opts={'all_tenants': 1})
162     except Exception:
163         log.exception("Error [get_instances(nova_client)]")
164
165
166 def get_instance_status(nova_client, instance):     # pragma: no cover
167     try:
168         return nova_client.servers.get(instance.id).status
169     except Exception:
170         log.exception("Error [get_instance_status(nova_client)]")
171
172
173 def get_instance_by_name(nova_client, instance_name):   # pragma: no cover
174     try:
175         return nova_client.servers.find(name=instance_name)
176     except Exception:
177         log.exception("Error [get_instance_by_name(nova_client, '%s')]",
178                       instance_name)
179
180
181 def get_aggregates(nova_client):    # pragma: no cover
182     try:
183         return nova_client.aggregates.list()
184     except Exception:
185         log.exception("Error [get_aggregates(nova_client)]")
186
187
188 def get_availability_zones(nova_client):    # pragma: no cover
189     try:
190         return nova_client.availability_zones.list()
191     except Exception:
192         log.exception("Error [get_availability_zones(nova_client)]")
193
194
195 def get_availability_zone_names(nova_client):   # pragma: no cover
196     try:
197         return [az.zoneName for az in get_availability_zones(nova_client)]
198     except Exception:
199         log.exception("Error [get_availability_zone_names(nova_client)]")
200
201
202 def create_aggregate(nova_client, aggregate_name, av_zone):  # pragma: no cover
203     try:
204         nova_client.aggregates.create(aggregate_name, av_zone)
205     except Exception:
206         log.exception("Error [create_aggregate(nova_client, %s, %s)]",
207                       aggregate_name, av_zone)
208         return False
209     else:
210         return True
211
212
213 def get_aggregate_id(nova_client, aggregate_name):      # pragma: no cover
214     try:
215         aggregates = get_aggregates(nova_client)
216         _id = next((ag.id for ag in aggregates if ag.name == aggregate_name))
217     except Exception:
218         log.exception("Error [get_aggregate_id(nova_client, %s)]",
219                       aggregate_name)
220     else:
221         return _id
222
223
224 def add_host_to_aggregate(nova_client, aggregate_name,
225                           compute_host):    # pragma: no cover
226     try:
227         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
228         nova_client.aggregates.add_host(aggregate_id, compute_host)
229     except Exception:
230         log.exception("Error [add_host_to_aggregate(nova_client, %s, %s)]",
231                       aggregate_name, compute_host)
232         return False
233     else:
234         return True
235
236
237 def create_aggregate_with_host(nova_client, aggregate_name, av_zone,
238                                compute_host):    # pragma: no cover
239     try:
240         create_aggregate(nova_client, aggregate_name, av_zone)
241         add_host_to_aggregate(nova_client, aggregate_name, compute_host)
242     except Exception:
243         log.exception("Error [create_aggregate_with_host("
244                       "nova_client, %s, %s, %s)]",
245                       aggregate_name, av_zone, compute_host)
246         return False
247     else:
248         return True
249
250
251 def create_instance(flavor_name,
252                     image_id,
253                     network_id,
254                     instance_name="instance-vm",
255                     confdrive=True,
256                     userdata=None,
257                     av_zone='',
258                     fixed_ip=None,
259                     files=None):    # pragma: no cover
260     nova_client = get_nova_client()
261     try:
262         flavor = nova_client.flavors.find(name=flavor_name)
263     except:
264         flavors = nova_client.flavors.list()
265         log.exception("Error: Flavor '%s' not found. Available flavors are: "
266                       "\n%s", flavor_name, flavors)
267         return None
268     if fixed_ip is not None:
269         nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip}
270     else:
271         nics = {"net-id": network_id}
272     if userdata is None:
273         instance = nova_client.servers.create(
274             name=instance_name,
275             flavor=flavor,
276             image=image_id,
277             nics=[nics],
278             availability_zone=av_zone,
279             files=files
280         )
281     else:
282         instance = nova_client.servers.create(
283             name=instance_name,
284             flavor=flavor,
285             image=image_id,
286             nics=[nics],
287             config_drive=confdrive,
288             userdata=userdata,
289             availability_zone=av_zone,
290             files=files
291         )
292     return instance
293
294
295 def create_instance_and_wait_for_active(flavor_name,
296                                         image_id,
297                                         network_id,
298                                         instance_name="instance-vm",
299                                         config_drive=False,
300                                         userdata="",
301                                         av_zone='',
302                                         fixed_ip=None,
303                                         files=None):    # pragma: no cover
304     SLEEP = 3
305     VM_BOOT_TIMEOUT = 180
306     nova_client = get_nova_client()
307     instance = create_instance(flavor_name,
308                                image_id,
309                                network_id,
310                                instance_name,
311                                config_drive,
312                                userdata,
313                                av_zone=av_zone,
314                                fixed_ip=fixed_ip,
315                                files=files)
316     count = VM_BOOT_TIMEOUT / SLEEP
317     for n in range(count, -1, -1):
318         status = get_instance_status(nova_client, instance)
319         if status.lower() == "active":
320             return instance
321         elif status.lower() == "error":
322             log.error("The instance %s went to ERROR status.", instance_name)
323             return None
324         time.sleep(SLEEP)
325     log.error("Timeout booting the instance %s.", instance_name)
326     return None
327
328
329 def delete_instance(nova_client, instance_id):      # pragma: no cover
330     try:
331         nova_client.servers.force_delete(instance_id)
332     except Exception:
333         log.exception("Error [delete_instance(nova_client, '%s')]",
334                       instance_id)
335         return False
336     else:
337         return True
338
339
340 def remove_host_from_aggregate(nova_client, aggregate_name,
341                                compute_host):  # pragma: no cover
342     try:
343         aggregate_id = get_aggregate_id(nova_client, aggregate_name)
344         nova_client.aggregates.remove_host(aggregate_id, compute_host)
345     except Exception:
346         log.exception("Error remove_host_from_aggregate(nova_client, %s, %s)",
347                       aggregate_name, compute_host)
348         return False
349     else:
350         return True
351
352
353 def remove_hosts_from_aggregate(nova_client,
354                                 aggregate_name):   # pragma: no cover
355     aggregate_id = get_aggregate_id(nova_client, aggregate_name)
356     hosts = nova_client.aggregates.get(aggregate_id).hosts
357     assert(
358         all(remove_host_from_aggregate(nova_client, aggregate_name, host)
359             for host in hosts))
360
361
362 def delete_aggregate(nova_client, aggregate_name):  # pragma: no cover
363     try:
364         remove_hosts_from_aggregate(nova_client, aggregate_name)
365         nova_client.aggregates.delete(aggregate_name)
366     except Exception:
367         log.exception("Error [delete_aggregate(nova_client, %s)]",
368                       aggregate_name)
369         return False
370     else:
371         return True
372
373
374 def get_server_by_name(name):   # pragma: no cover
375     try:
376         return get_nova_client().servers.list(search_opts={'name': name})[0]
377     except IndexError:
378         log.exception('Failed to get nova client')
379         raise
380
381
382 def get_image_by_name(name):    # pragma: no cover
383     images = get_nova_client().images.list()
384     try:
385         return next((a for a in images if a.name == name))
386     except StopIteration:
387         log.exception('No image matched')
388
389
390 def get_flavor_by_name(name):   # pragma: no cover
391     flavors = get_nova_client().flavors.list()
392     try:
393         return next((a for a in flavors if a.name == name))
394     except StopIteration:
395         log.exception('No flavor matched')
396
397
398 def check_status(status, name, iterations, interval):   # pragma: no cover
399     for i in range(iterations):
400         try:
401             server = get_server_by_name(name)
402         except IndexError:
403             log.error('Cannot found %s server', name)
404             raise
405
406         if server.status == status:
407             return True
408
409         time.sleep(interval)
410     return False
411
412
413 # *********************************************
414 #   NEUTRON
415 # *********************************************
416 def get_network_id(neutron_client, network_name):       # pragma: no cover
417     networks = neutron_client.list_networks()['networks']
418     return next((n['id'] for n in networks if n['name'] == network_name), None)
419
420
421 def get_port_id_by_ip(neutron_client, ip_address):      # pragma: no cover
422     ports = neutron_client.list_ports()['ports']
423     return next((i['id'] for i in ports for j in i.get(
424         'fixed_ips') if j['ip_address'] == ip_address), None)
425
426
427 # *********************************************
428 #   GLANCE
429 # *********************************************
430 def get_image_id(glance_client, image_name):    # pragma: no cover
431     images = glance_client.images.list()
432     return next((i.id for i in images if i.name == image_name), None)