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