update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / rwcal / plugins / vala / rwcal_openstack / rift / rwcal / openstack / openstack_drv.py
1 #!/usr/bin/python
2
3 #
4 # Copyright 2016 RIFT.IO Inc
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18
19 import logging
20
21 from . import session as sess_drv
22 from . import keystone as ks_drv
23 from . import nova as nv_drv
24 from . import neutron as nt_drv
25 from . import glance as gl_drv
26 from . import ceilometer as ce_drv
27 from . import cinder as ci_drv
28 from . import utils as drv_utils
29
30 # Exceptions
31 import keystoneclient.exceptions as KeystoneExceptions
32 import neutronclient.common.exceptions as NeutronException
33
34
35 class ValidationError(Exception):
36 pass
37
38
39 class DriverUtilities(object):
40 """
41 Class with utility method
42 """
43 def __init__(self, driver):
44 """
45 Constructor of DriverUtilities class
46 Arguments:
47 driver: Object of OpenstackDriver
48 """
49 self.flavor_utils = drv_utils.FlavorUtils(driver)
50 self.network_utils = drv_utils.NetworkUtils(driver)
51 self.image_utils = drv_utils.ImageUtils(driver)
52 self.compute_utils = drv_utils.ComputeUtils(driver)
53
54 @property
55 def flavor(self):
56 return self.flavor_utils
57
58 @property
59 def compute(self):
60 return self.compute_utils
61
62 @property
63 def network(self):
64 return self.network_utils
65
66 @property
67 def image(self):
68 return self.image_utils
69
70
71 class OpenstackDriver(object):
72 """
73 Driver for openstack nova, neutron, glance, keystone, swift, cinder services
74 """
75 def __init__(self, logger = None, **kwargs):
76 """
77 OpenstackDriver Driver constructor
78 Arguments:
79 logger: (instance of logging.Logger)
80 kwargs: A dictionary of
81 {
82 username (string) : Username for project/tenant.
83 password (string) : Password
84 auth_url (string) : Keystone Authentication URL.
85 project (string) : Openstack project name
86 mgmt_network(string, optional) : Management network name. Each VM created with this cloud-account will
87 have a default interface into management network.
88 cert_validate (boolean, optional) : In case of SSL/TLS connection if certificate validation is required or not.
89 user_domain : Domain name for user
90 project_domain : Domain name for project
91 region : Region name
92 }
93 """
94
95 if logger is None:
96 self.log = logging.getLogger('rwcal.openstack.driver')
97 self.log.setLevel(logging.DEBUG)
98 else:
99 self.log = logger
100
101 args = dict(auth_url = kwargs['auth_url'],
102 username = kwargs['username'],
103 password = kwargs['password'],
104 project_name = kwargs['project'],
105 project_domain_name = kwargs['project_domain'] if 'project_domain' in kwargs else None,
106 user_domain_name = kwargs['user_domain'] if 'user_domain' in kwargs else None,)
107
108 cert_validate = kwargs['cert_validate'] if 'cert_validate' in kwargs else False
109 region = kwargs['region_name'] if 'region_name' in kwargs else False
110 mgmt_network = kwargs['mgmt_network'] if 'mgmt_network' in kwargs else None
111
112 discover = ks_drv.KeystoneVersionDiscover(kwargs['auth_url'],
113 cert_validate,
114 logger = self.log)
115 (major, minor) = discover.get_version()
116
117 self.sess_drv = sess_drv.SessionDriver(auth_method = 'password',
118 version = str(major),
119 cert_validate = cert_validate,
120 logger = self.log,
121 **args)
122
123 self.ks_drv = ks_drv.KeystoneDriver(str(major),
124 self.sess_drv,
125 logger = self.log)
126
127 self.nova_drv = nv_drv.NovaDriver(self.sess_drv,
128 region_name = region,
129 logger = self.log)
130
131 self.neutron_drv = nt_drv.NeutronDriver(self.sess_drv,
132 region_name = region,
133 logger = self.log)
134
135 self.glance_drv = gl_drv.GlanceDriver(self.sess_drv,
136 region_name = region,
137 logger = self.log)
138
139 try:
140 self.cinder_drv = ci_drv.CinderDriver(self.sess_drv,
141 region_name = region,
142 logger = self.log)
143 except Exception:
144 self.cinder_drv = None
145
146 self.ceilo_drv = ce_drv.CeilometerDriver(self.sess_drv,
147 region_name = region,
148 logger = self.log)
149
150 self.utils = DriverUtilities(self)
151
152 self._mgmt_network = mgmt_network
153
154 self._cache = dict(neutron = dict(),
155 nova = dict(),
156 cinder = dict(),
157 glance = dict())
158 self.build_resource_cache()
159
160 @property
161 def nova_cache(self):
162 return self._cache['nova']
163
164 @property
165 def neutron_cache(self):
166 return self._cache['neutron']
167
168 @property
169 def glance_cache(self):
170 return self._cache['glance']
171
172 @property
173 def cinder_cache(self):
174 return self._cache['cinder']
175
176 def build_resource_cache(self):
177 try:
178 self.build_network_resource_cache()
179 except KeyError:
180 raise
181 self.build_nova_resource_cache()
182 self.build_cinder_resource_cache()
183 self.build_glance_resource_cache()
184
185 def _cache_populate(self, method, datatype, *args, **kwargs):
186 try:
187 rsp = method(*args, **kwargs)
188 except Exception as e:
189 self.log.exception("Exception %s occured during execution of %s",
190 str(e), method)
191 return datatype
192 else:
193 return rsp
194
195 def _build_nova_security_group_list(self):
196 self.log.info("Building Nova security group cache")
197 self.nova_cache['security_groups'] = self._cache_populate(self.nova_drv.security_group_list,
198 list())
199 return self.nova_cache['security_groups']
200
201 def _build_nova_affinity_group_list(self):
202 self.log.info("Building Nova affinity/anti-affinity group cache")
203 self.nova_cache['affinity_groups'] = self._cache_populate(self.nova_server_group_list,
204 list())
205 return self.nova_cache['affinity_groups']
206
207 def _build_neutron_security_group_list(self):
208 self.log.info("Discovering neutron security group")
209 self.neutron_cache['security_groups'] = self._cache_populate(self.neutron_security_group_list,
210 list())
211 return self.neutron_cache['security_groups']
212
213 def _build_neutron_subnet_prefix_list(self):
214 self.log.info("Discovering subnet prefix pools")
215 self.neutron_cache['subnet_pool'] = self._cache_populate(self.neutron_subnetpool_list,
216 list())
217 return self.neutron_cache['subnet_pool']
218
219 def _get_neutron_mgmt_network(self):
220 if self._mgmt_network:
221 self.log.info("Discovering management network %s", self._mgmt_network)
222 network_list = self._cache_populate(self.neutron_drv.network_get,
223 None,
224 **{'network_name': self._mgmt_network})
225 if network_list:
226 self.neutron_cache['mgmt_net'] = network_list['id']
227 else:
228 msg = "Could not find management network %s" % self._mgmt_network
229 self.log.error(msg)
230 raise KeyError(msg)
231
232
233 def _build_glance_image_list(self):
234 self.log.info("Discovering images")
235 self.glance_cache['images'] = self._cache_populate(self.glance_image_list,
236 list())
237
238 return self.glance_cache['images']
239
240 def _build_cinder_volume_list(self):
241 self.log.info("Discovering volumes")
242 self.cinder_cache['volumes'] = self._cache_populate(self.cinder_volume_list,
243 list())
244 return self.cinder_cache['volumes']
245
246 def build_nova_resource_cache(self):
247 self.log.info("Building nova resource cache")
248 self._build_nova_security_group_list()
249 self._build_nova_affinity_group_list()
250
251
252 def build_network_resource_cache(self):
253 self.log.info("Building network resource cache")
254 try:
255 self._get_neutron_mgmt_network()
256 except KeyError:
257 raise
258 self._build_neutron_security_group_list()
259 self._build_neutron_subnet_prefix_list()
260
261 def build_cinder_resource_cache(self):
262 self.log.info("Building cinder resource cache")
263 if self.cinder_drv is not None:
264 self._build_cinder_volume_list()
265
266 def build_glance_resource_cache(self):
267 self.log.info("Building glance resource cache")
268 self._build_glance_image_list()
269
270
271 @property
272 def _nova_affinity_group(self):
273 if 'affinity_groups' in self.nova_cache:
274 return self.nova_cache['affinity_groups']
275 else:
276 return self._build_nova_affinity_group_list()
277
278 @property
279 def _nova_security_groups(self):
280 if 'security_groups' in self.nova_cache:
281 return self.nova_cache['security_groups']
282 else:
283 return self._build_nova_security_group_list()
284
285 @property
286 def mgmt_network(self):
287 return self._mgmt_network
288
289 @property
290 def _mgmt_network_id(self):
291 if 'mgmt_net' in self.neutron_cache:
292 return self.neutron_cache['mgmt_net']
293 else:
294 return list()
295
296 @property
297 def _neutron_security_groups(self):
298 if 'security_groups' in self.neutron_cache:
299 return self.neutron_cache['security_groups']
300 else:
301 return self._build_neutron_security_group_list()
302
303 @property
304 def _neutron_subnet_prefix_pool(self):
305 if 'subnet_pool' in self.neutron_cache:
306 return self.neutron_cache['subnet_pool']
307 else:
308 return self._build_neutron_subnet_prefix_list()
309
310 @property
311 def _glance_image_list(self):
312 if 'images' in self.glance_cache:
313 return self.glance_cache['images']
314 else:
315 return self._build_glance_image_list()
316
317 @property
318 def _cinder_volume_list(self):
319 if 'volumes' in self.cinder_cache:
320 return self.cinder_cache['volumes']
321 else:
322 return self._build_cinder_volume_list()
323
324 def validate_account_creds(self):
325 try:
326 self.sess_drv.invalidate_auth_token()
327 self.sess_drv.auth_token
328 self.build_resource_cache()
329 except KeystoneExceptions.Unauthorized as e:
330 self.log.error("Invalid credentials ")
331 raise ValidationError("Invalid Credentials: "+ str(e))
332 except KeystoneExceptions.AuthorizationFailure as e:
333 self.log.error("Unable to authenticate or validate the existing credentials. Exception: %s", str(e))
334 raise ValidationError("Invalid Credentials: "+ str(e))
335 except NeutronException.NotFound as e:
336 self.log.error("Given management network could not be found for Openstack account ")
337 raise ValidationError("Neutron network not found "+ str(e))
338 except Exception as e:
339 self.log.error("Could not connect to Openstack. Exception: %s", str(e))
340 raise ValidationError("Connection Error: "+ str(e))
341
342
343 def glance_image_create(self, **kwargs):
344 if 'disk_format' not in kwargs:
345 kwargs['disk_format'] = 'qcow2'
346 if 'container_format' not in kwargs:
347 kwargs['container_format'] = 'bare'
348 if 'min_disk' not in kwargs:
349 kwargs['min_disk'] = 0
350 if 'min_ram' not in kwargs:
351 kwargs['min_ram'] = 0
352 return self.glance_drv.image_create(**kwargs)
353
354 def glance_image_upload(self, image_id, fd):
355 self.glance_drv.image_upload(image_id, fd)
356
357 def glance_image_add_location(self, image_id, location):
358 self.glance_drv.image_add_location(image_id, location)
359
360 def glance_image_update(self, image_id, remove_props = None, **kwargs):
361 self.glance_drv.image_update(image_id, remove_props=remove_props, **kwargs)
362
363 def glance_image_delete(self, image_id):
364 self.glance_drv.image_delete(image_id)
365
366 def glance_image_list(self):
367 return self.glance_drv.image_list()
368
369 def glance_image_get(self, image_id):
370 return self.glance_drv.image_get(image_id)
371
372 def nova_flavor_list(self):
373 return self.nova_drv.flavor_list()
374
375 def nova_flavor_find(self, **kwargs):
376 return self.nova_drv.flavor_find(**kwargs)
377
378 def nova_flavor_create(self, name, ram, vcpus, disk, epa_specs = dict()):
379 return self.nova_drv.flavor_create(name,
380 ram = ram,
381 vcpu = vcpus,
382 disk = disk,
383 extra_specs = epa_specs)
384
385 def nova_flavor_delete(self, flavor_id):
386 self.nova_drv.flavor_delete(flavor_id)
387
388 def nova_flavor_get(self, flavor_id):
389 return self.nova_drv.flavor_get(flavor_id)
390
391 def nova_server_create(self, **kwargs):
392 if 'security_groups' not in kwargs:
393 security_groups = [s['name'] for s in self._nova_security_groups]
394 #Remove the security group names that are duplicate - RIFT-17035
395 valid_security_groups = list(filter(lambda s: security_groups.count(s) == 1, security_groups))
396 kwargs['security_groups'] = valid_security_groups
397 return self.nova_drv.server_create(**kwargs)
398
399 def nova_server_add_port(self, server_id, port_id):
400 self.nova_drv.server_add_port(server_id, port_id)
401
402 def nova_server_delete_port(self, server_id, port_id):
403 self.nova_drv.server_delete_port(server_id, port_id)
404
405 def nova_server_start(self, server_id):
406 self.nova_drv.server_start(server_id)
407
408 def nova_server_stop(self, server_id):
409 self.nova_drv.server_stop(server_id)
410
411 def nova_server_delete(self, server_id):
412 self.nova_drv.server_delete(server_id)
413
414 def nova_server_reboot(self, server_id):
415 self.nova_drv.server_reboot(server_id, reboot_type='HARD')
416
417 def nova_server_rebuild(self, server_id, image_id):
418 self.nova_drv.server_rebuild(server_id, image_id)
419
420 def nova_floating_ip_list(self):
421 return self.nova_drv.floating_ip_list()
422
423 def nova_floating_ip_create(self, pool = None):
424 return self.nova_drv.floating_ip_create(pool)
425
426 def nova_floating_ip_delete(self, floating_ip):
427 self.nova_drv.floating_ip_delete(floating_ip)
428
429 def nova_floating_ip_assign(self, server_id, floating_ip, fixed_ip):
430 self.nova_drv.floating_ip_assign(server_id, floating_ip, fixed_ip)
431
432 def nova_floating_ip_release(self, server_id, floating_ip):
433 self.nova_drv.floating_ip_release(server_id, floating_ip)
434
435 def nova_server_list(self):
436 return self.nova_drv.server_list()
437
438 def nova_server_get(self, server_id):
439 return self.nova_drv.server_get(server_id)
440
441 def nova_server_console(self, server_id):
442 return self.nova_drv.server_console(server_id)
443
444 def nova_server_group_list(self):
445 return self.nova_drv.group_list()
446
447 def nova_volume_list(self, server_id):
448 return self.nova_drv.volume_list(server_id)
449
450 def neutron_extensions_list(self):
451 return self.neutron_drv.extensions_list()
452
453 def neutron_network_list(self):
454 return self.neutron_drv.network_list()
455
456 def neutron_network_get(self, network_id):
457 return self.neutron_drv.network_get(network_id=network_id)
458
459 def neutron_network_get_by_name(self, network_name):
460 return self.neutron_drv.network_get(network_name=network_name)
461
462 def neutron_network_create(self, **kwargs):
463 return self.neutron_drv.network_create(**kwargs)
464
465 def neutron_network_delete(self, network_id):
466 self.neutron_drv.network_delete(network_id)
467
468 def neutron_subnet_list(self):
469 return self.neutron_drv.subnet_list(**{})
470
471 def neutron_subnet_get(self, subnet_id):
472 return self.neutron_drv.subnet_get(subnet_id)
473
474 def neutron_subnet_create(self, **kwargs):
475 return self.neutron_drv.subnet_create(**kwargs)
476
477 def netruon_subnet_delete(self, subnet_id):
478 self.neutron_drv.subnet_delete(subnet_id)
479
480 def neutron_subnetpool_list(self):
481 return self.neutron_drv.subnetpool_list()
482
483 def netruon_subnetpool_by_name(self, pool_name):
484 pool_list = self.neutron_drv.subnetpool_list(**{'name': pool_name})
485 if pool_list:
486 return pool_list[0]
487 else:
488 return None
489
490 def neutron_port_list(self, **kwargs):
491 return self.neutron_drv.port_list(**kwargs)
492
493 def neutron_port_get(self, port_id):
494 return self.neutron_drv.port_get(port_id)
495
496 def neutron_port_create(self, **kwargs):
497 port_id = self.neutron_drv.port_create([kwargs])[0]
498 if 'vm_id' in kwargs:
499 self.nova_server_add_port(kwargs['vm_id'], port_id)
500 return port_id
501
502 def neutron_multi_port_create(self, ports):
503 return self.neutron_drv.port_create(ports)
504
505 def neutron_security_group_list(self):
506 return self.neutron_drv.security_group_list(**{})
507
508 def neutron_security_group_by_name(self, group_name):
509 group_list = self.neutron_drv.security_group_list(**{'name': group_name})
510 if group_list:
511 return group_list[0]
512 else:
513 return None
514
515 def neutron_port_delete(self, port_id):
516 self.neutron_drv.port_delete(port_id)
517
518 def ceilo_meter_endpoint(self):
519 return self.ceilo_drv.endpoint
520
521 def ceilo_meter_list(self):
522 return self.ceilo_drv.meters
523
524 def ceilo_nfvi_metrics(self, vim_id):
525 """Returns a dict of NFVI metrics for a given VM
526
527 Arguments:
528 vim_id - the VIM ID of the VM to retrieve the metrics for
529
530 Returns:
531 A dict of NFVI metrics
532
533 """
534 return self.ceilo_drv.nfvi_metrics(vim_id)
535
536 def ceilo_alarm_list(self):
537 """Returns a list of ceilometer alarms"""
538 return self.ceilo_drv.client.alarms.list()
539
540 def ceilo_alarm_create(self,
541 name,
542 meter,
543 statistic,
544 operation,
545 threshold,
546 period,
547 evaluations,
548 severity='low',
549 repeat=True,
550 enabled=True,
551 actions=None,
552 **kwargs):
553 """Create a new Alarm
554
555 Arguments:
556 name - the name of the alarm
557 meter - the name of the meter to measure
558 statistic - the type of statistic used to trigger the alarm
559 ('avg', 'min', 'max', 'count', 'sum')
560 operation - the relational operator that, combined with the
561 threshold value, determines when the alarm is
562 triggered ('lt', 'le', 'eq', 'ge', 'gt')
563 threshold - the value of the statistic that will trigger the
564 alarm
565 period - the duration (seconds) over which to evaluate the
566 specified statistic
567 evaluations - the number of samples of the meter statistic to
568 collect when evaluating the threshold
569 severity - a measure of the urgency or importance of the alarm
570 ('low', 'moderate', 'critical')
571 repeat - a flag that indicates whether the alarm should be
572 triggered once (False) or repeatedly while the alarm
573 condition is true (True)
574 enabled - a flag that indicates whether the alarm is enabled
575 (True) or disabled (False)
576 actions - a dict specifying the URLs for webhooks. The dict can
577 have up to 3 keys: 'insufficient_data', 'alarm',
578 'ok'. Each key is associated with a list of URLs to
579 webhooks that will be invoked when one of the 3
580 actions is taken.
581 kwargs - an arbitrary dict of keyword arguments that are
582 passed to the ceilometer client
583
584 """
585 ok_actions = actions.get('ok') if actions is not None else None
586 alarm_actions = actions.get('alarm') if actions is not None else None
587 insufficient_data_actions = actions.get('insufficient_data') if actions is not None else None
588
589 return self.ceilo_drv.client.alarms.create(name=name,
590 meter_name=meter,
591 statistic=statistic,
592 comparison_operator=operation,
593 threshold=threshold,
594 period=period,
595 evaluation_periods=evaluations,
596 severity=severity,
597 repeat_actions=repeat,
598 enabled=enabled,
599 ok_actions=ok_actions,
600 alarm_actions=alarm_actions,
601 insufficient_data_actions=insufficient_data_actions,
602 **kwargs)
603
604 def ceilo_alarm_update(self, alarm_id, **kwargs):
605 """Updates an existing alarm
606
607 Arguments:
608 alarm_id - the identifier of the alarm to update
609 kwargs - a dict of the alarm attributes to update
610
611 """
612 return self.ceilo_drv.client.alarms.update(alarm_id, **kwargs)
613
614 def ceilo_alarm_delete(self, alarm_id):
615 self.ceilo_drv.client.alarms.delete(alarm_id)
616
617 def cinder_volume_list(self):
618 return self.cinder_drv.volume_list()
619
620 def cinder_volume_get(self, vol_id):
621 return self.cinder_drv.volume_get(vol_id)
622
623 def cinder_volume_set_metadata(self, volumeid, metadata):
624 return self.cinder_drv.volume_set_metadata(volumeid, metadata)
625
626 def cinder_volume_delete_metadata(self, volumeid, metadata):
627 return self.cinder_drv.volume_delete_metadata(volumeid, metadata)
628
629
630