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