500f10cb7fbdf7a2f595a7e3ffbd945da7d8ca53
[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 portchain as port_drv
29 from . import utils as drv_utils
30
31 # Exceptions
32 import keystoneclient.exceptions as KeystoneExceptions
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'], logger = self.log)
113 (major, minor) = discover.get_version()
114
115 self.sess_drv = sess_drv.SessionDriver(auth_method = 'password',
116 version = str(major),
117 cert_validate = cert_validate,
118 logger = self.log,
119 **args)
120
121 self.ks_drv = ks_drv.KeystoneDriver(str(major),
122 self.sess_drv,
123 logger = self.log)
124
125 self.nova_drv = nv_drv.NovaDriver(self.sess_drv,
126 region_name = region,
127 logger = self.log)
128
129 self.neutron_drv = nt_drv.NeutronDriver(self.sess_drv,
130 region_name = region,
131 logger = self.log)
132
133 self.glance_drv = gl_drv.GlanceDriver(self.sess_drv,
134 region_name = region,
135 logger = self.log)
136
137 self.cinder_drv = ci_drv.CinderDriver(self.sess_drv,
138 region_name = region,
139 logger = self.log)
140
141 self.ceilo_drv = ce_drv.CeilometerDriver(self.sess_drv,
142 region_name = region,
143 logger = self.log)
144
145 self.portchain_drv = port_drv.L2PortChainDriver(self.sess_drv,
146 self.neutron_drv,
147 logger = self.log)
148 self.utils = DriverUtilities(self)
149
150 self._mgmt_network = mgmt_network
151
152 self._cache = dict(neutron = dict(),
153 nova = dict(),
154 cinder = dict(),
155 glance = dict())
156 self.build_resource_cache()
157
158 @property
159 def nova_cache(self):
160 return self._cache['nova']
161
162 @property
163 def neutron_cache(self):
164 return self._cache['neutron']
165
166 @property
167 def glance_cache(self):
168 return self._cache['glance']
169
170 @property
171 def cinder_cache(self):
172 return self._cache['cinder']
173
174 def build_resource_cache(self):
175 self.build_network_resource_cache()
176 self.build_nova_resource_cache()
177 self.build_cinder_resource_cache()
178 self.build_glance_resource_cache()
179
180 def _cache_populate(self, method, datatype, *args, **kwargs):
181 try:
182 rsp = method(*args, **kwargs)
183 except Exception as e:
184 self.log.exception("Exception %s occured during execution of %s",
185 str(e), method)
186 return datatype
187 else:
188 return rsp
189
190 def _build_nova_security_group_list(self):
191 self.log.info("Building Nova security group cache")
192 self.nova_cache['security_groups'] = self._cache_populate(self.nova_drv.security_group_list,
193 list())
194 return self.nova_cache['security_groups']
195
196 def _build_nova_affinity_group_list(self):
197 self.log.info("Building Nova affinity/anti-affinity group cache")
198 self.nova_cache['affinity_groups'] = self._cache_populate(self.nova_server_group_list,
199 list())
200 return self.nova_cache['affinity_groups']
201
202 def _build_neutron_security_group_list(self):
203 self.log.info("Discovering neutron security group")
204 self.neutron_cache['security_groups'] = self._cache_populate(self.neutron_security_group_list,
205 list())
206 return self.neutron_cache['security_groups']
207
208 def _build_neutron_subnet_prefix_list(self):
209 self.log.info("Discovering subnet prefix pools")
210 self.neutron_cache['subnet_pool'] = self._cache_populate(self.neutron_subnetpool_list,
211 list())
212 return self.neutron_cache['subnet_pool']
213
214 def _get_neutron_mgmt_network(self):
215 if self._mgmt_network:
216 self.log.info("Discovering management network %s", self._mgmt_network)
217 network_list = self._cache_populate(self.neutron_drv.network_get,
218 None,
219 **{'network_name':self._mgmt_network})
220 if network_list:
221 self.neutron_cache['mgmt_net'] = network_list['id']
222 else:
223 raise KeyError("Error")
224
225
226 def _build_glance_image_list(self):
227 self.log.info("Discovering images")
228 self.glance_cache['images'] = self._cache_populate(self.glance_image_list,
229 list())
230 return self.glance_cache['images']
231
232
233 def build_nova_resource_cache(self):
234 self.log.info("Building nova resource cache")
235 self._build_nova_security_group_list()
236 self._build_nova_affinity_group_list()
237
238
239 def build_network_resource_cache(self):
240 self.log.info("Building network resource cache")
241 self._get_neutron_mgmt_network()
242 self._build_neutron_security_group_list()
243 self._build_neutron_subnet_prefix_list()
244
245 def build_cinder_resource_cache(self):
246 pass
247
248
249 def build_glance_resource_cache(self):
250 self.log.info("Building glance resource cache")
251 self._build_glance_image_list()
252
253
254 @property
255 def _nova_affinity_group(self):
256 if 'affinity_groups' in self.nova_cache:
257 return self.nova_cache['affinity_groups']
258 else:
259 return self._build_nova_affinity_group_list()
260
261 @property
262 def _nova_security_groups(self):
263 if 'security_groups' in self.nova_cache:
264 return self.nova_cache['security_groups']
265 else:
266 return self._build_nova_security_group_list()
267
268 @property
269 def mgmt_network(self):
270 return self._mgmt_network
271
272 @property
273 def _mgmt_network_id(self):
274 if 'mgmt_net' in self.neutron_cache:
275 return self.neutron_cache['mgmt_net']
276 else:
277 return list()
278
279 @property
280 def _neutron_security_groups(self):
281 if 'security_groups' in self.neutron_cache:
282 return self.neutron_cache['security_groups']
283 else:
284 return self._build_neutron_security_group_list()
285
286 @property
287 def _neutron_subnet_prefix_pool(self):
288 if 'subnet_pool' in self.neutron_cache:
289 return self.neutron_cache['subnet_pool']
290 else:
291 return self._build_neutron_subnet_prefix_list()
292
293 @property
294 def _glance_image_list(self):
295 if 'images' in self.glance_cache:
296 return self.glance_cache['images']
297 else:
298 return self._build_glance_image_list()
299
300 def validate_account_creds(self):
301 try:
302 self.sess_drv.invalidate_auth_token()
303 self.sess_drv.auth_token
304 self.build_resource_cache()
305 except KeystoneExceptions.AuthorizationFailure as e:
306 self.log.error("Unable to authenticate or validate the existing credentials. Exception: %s", str(e))
307 raise ValidationError("Invalid Credentials: "+ str(e))
308 except Exception as e:
309 self.log.error("Could not connect to Openstack. Exception: %s", str(e))
310 raise ValidationError("Connection Error: "+ str(e))
311
312
313 def glance_image_create(self, **kwargs):
314 if not 'disk_format' in kwargs:
315 kwargs['disk_format'] = 'qcow2'
316 if not 'container_format' in kwargs:
317 kwargs['container_format'] = 'bare'
318 if not 'min_disk' in kwargs:
319 kwargs['min_disk'] = 0
320 if not 'min_ram' in kwargs:
321 kwargs['min_ram'] = 0
322 return self.glance_drv.image_create(**kwargs)
323
324 def glance_image_upload(self, image_id, fd):
325 self.glance_drv.image_upload(image_id, fd)
326
327 def glance_image_add_location(self, image_id, location):
328 self.glance_drv.image_add_location(image_id, location)
329
330 def glance_image_update(self, image_id, remove_props = None, **kwargs):
331 self.glance_drv.image_update(image_id, remove_props=remove_props, **kwargs)
332
333 def glance_image_delete(self, image_id):
334 self.glance_drv.image_delete(image_id)
335
336 def glance_image_list(self):
337 return self.glance_drv.image_list()
338
339 def glance_image_get(self, image_id):
340 return self.glance_drv.image_get(image_id)
341
342 def nova_flavor_list(self):
343 return self.nova_drv.flavor_list()
344
345 def nova_flavor_find(self, **kwargs):
346 return self.nova_drv.flavor_find(**kwargs)
347
348 def nova_flavor_create(self, name, ram, vcpus, disk, epa_specs = dict()):
349 return self.nova_drv.flavor_create(name,
350 ram = ram,
351 vcpu = vcpus,
352 disk = disk,
353 extra_specs = epa_specs)
354
355 def nova_flavor_delete(self, flavor_id):
356 self.nova_drv.flavor_delete(flavor_id)
357
358 def nova_flavor_get(self, flavor_id):
359 return self.nova_drv.flavor_get(flavor_id)
360
361 def nova_server_create(self, **kwargs):
362 if 'security_groups' not in kwargs:
363 kwargs['security_groups'] = [ s['name'] for s in self._nova_security_groups ]
364 return self.nova_drv.server_create(**kwargs)
365
366 def nova_server_add_port(self, server_id, port_id):
367 self.nova_drv.server_add_port(server_id, port_id)
368
369 def nova_server_delete_port(self, server_id, port_id):
370 self.nova_drv.server_delete_port(server_id, port_id)
371
372 def nova_server_start(self, server_id):
373 self.nova_drv.server_start(server_id)
374
375 def nova_server_stop(self, server_id):
376 self.nova_drv.server_stop(server_id)
377
378 def nova_server_delete(self, server_id):
379 self.nova_drv.server_delete(server_id)
380
381 def nova_server_reboot(self, server_id):
382 self.nova_drv.server_reboot(server_id, reboot_type='HARD')
383
384 def nova_server_rebuild(self, server_id, image_id):
385 self.nova_drv.server_rebuild(server_id, image_id)
386
387 def nova_floating_ip_list(self):
388 return self.nova_drv.floating_ip_list()
389
390 def nova_floating_ip_create(self, pool = None):
391 return self.nova_drv.floating_ip_create(pool)
392
393 def nova_floating_ip_delete(self, floating_ip):
394 self.nova_drv.floating_ip_delete(floating_ip)
395
396 def nova_floating_ip_assign(self, server_id, floating_ip, fixed_ip):
397 self.nova_drv.floating_ip_assign(server_id, floating_ip, fixed_ip)
398
399 def nova_floating_ip_release(self, server_id, floating_ip):
400 self.nova_drv.floating_ip_release(server_id, floating_ip)
401
402 def nova_server_list(self):
403 return self.nova_drv.server_list()
404
405 def nova_server_get(self, server_id):
406 return self.nova_drv.server_get(server_id)
407
408 def nova_server_console(self, server_id):
409 return self.nova_drv.server_console(server_id)
410
411 def nova_server_group_list(self):
412 return self.nova_drv.group_list()
413
414 def nova_volume_list(self, server_id):
415 return self.nova_drv.volume_list(server_id)
416
417 def neutron_network_list(self):
418 return self.neutron_drv.network_list()
419
420 def neutron_network_get(self, network_id):
421 return self.neutron_drv.network_get(network_id=network_id)
422
423 def neutron_network_create(self, **kwargs):
424 return self.neutron_drv.network_create(**kwargs)
425
426 def neutron_network_delete(self, network_id):
427 self.neutron_drv.network_delete(network_id)
428
429 def neutron_subnet_list(self):
430 return self.neutron_drv.subnet_list(**{})
431
432 def neutron_subnet_get(self, subnet_id):
433 return self.neutron_drv.subnet_get(subnet_id)
434
435 def neutron_subnet_create(self, **kwargs):
436 return self.neutron_drv.subnet_create(**kwargs)
437
438 def netruon_subnet_delete(self, subnet_id):
439 self.neutron_drv.subnet_delete(subnet_id)
440
441 def neutron_subnetpool_list(self):
442 return self.neutron_drv.subnetpool_list()
443
444 def netruon_subnetpool_by_name(self, pool_name):
445 pool_list = self.neutron_drv.subnetpool_list(**{'name': pool_name})
446 if pool_list:
447 return pool_list[0]
448 else:
449 return None
450
451 def neutron_port_list(self, **kwargs):
452 return self.neutron_drv.port_list(**kwargs)
453
454 def neutron_port_get(self, port_id):
455 return self.neutron_drv.port_get(port_id)
456
457 def neutron_port_create(self, **kwargs):
458 port_id = self.neutron_drv.port_create([kwargs])[0]
459 if 'vm_id' in kwargs:
460 self.nova_server_add_port(kwargs['vm_id'], port_id)
461 return port_id
462
463 def neutron_multi_port_create(self, ports):
464 return self.neutron_drv.port_create(ports)
465
466 def neutron_security_group_list(self):
467 return self.neutron_drv.security_group_list(**{})
468
469 def neutron_security_group_by_name(self, group_name):
470 group_list = self.neutron_drv.security_group_list(**{'name': group_name})
471 if group_list:
472 return group_list[0]
473 else:
474 return None
475
476 def neutron_port_delete(self, port_id):
477 self.neutron_drv.port_delete(port_id)
478
479 def ceilo_meter_endpoint(self):
480 return self.ceilo_drv.endpoint
481
482 def ceilo_meter_list(self):
483 return self.ceilo_drv.meters
484
485 def ceilo_nfvi_metrics(self, vim_id):
486 """Returns a dict of NFVI metrics for a given VM
487
488 Arguments:
489 vim_id - the VIM ID of the VM to retrieve the metrics for
490
491 Returns:
492 A dict of NFVI metrics
493
494 """
495 return self.ceilo_drv.nfvi_metrics(vim_id)
496
497 def ceilo_alarm_list(self):
498 """Returns a list of ceilometer alarms"""
499 return self.ceilo_drv.client.alarms.list()
500
501 def ceilo_alarm_create(self,
502 name,
503 meter,
504 statistic,
505 operation,
506 threshold,
507 period,
508 evaluations,
509 severity='low',
510 repeat=True,
511 enabled=True,
512 actions=None,
513 **kwargs):
514 """Create a new Alarm
515
516 Arguments:
517 name - the name of the alarm
518 meter - the name of the meter to measure
519 statistic - the type of statistic used to trigger the alarm
520 ('avg', 'min', 'max', 'count', 'sum')
521 operation - the relational operator that, combined with the
522 threshold value, determines when the alarm is
523 triggered ('lt', 'le', 'eq', 'ge', 'gt')
524 threshold - the value of the statistic that will trigger the
525 alarm
526 period - the duration (seconds) over which to evaluate the
527 specified statistic
528 evaluations - the number of samples of the meter statistic to
529 collect when evaluating the threshold
530 severity - a measure of the urgency or importance of the alarm
531 ('low', 'moderate', 'critical')
532 repeat - a flag that indicates whether the alarm should be
533 triggered once (False) or repeatedly while the alarm
534 condition is true (True)
535 enabled - a flag that indicates whether the alarm is enabled
536 (True) or disabled (False)
537 actions - a dict specifying the URLs for webhooks. The dict can
538 have up to 3 keys: 'insufficient_data', 'alarm',
539 'ok'. Each key is associated with a list of URLs to
540 webhooks that will be invoked when one of the 3
541 actions is taken.
542 kwargs - an arbitrary dict of keyword arguments that are
543 passed to the ceilometer client
544
545 """
546 ok_actions = actions.get('ok') if actions is not None else None
547 alarm_actions = actions.get('alarm') if actions is not None else None
548 insufficient_data_actions = actions.get('insufficient_data') if actions is not None else None
549
550 return self.ceilo_drv.client.alarms.create(name=name,
551 meter_name=meter,
552 statistic=statistic,
553 comparison_operator=operation,
554 threshold=threshold,
555 period=period,
556 evaluation_periods=evaluations,
557 severity=severity,
558 repeat_actions=repeat,
559 enabled=enabled,
560 ok_actions=ok_actions,
561 alarm_actions=alarm_actions,
562 insufficient_data_actions=insufficient_data_actions,
563 **kwargs)
564
565 def ceilo_alarm_update(self, alarm_id, **kwargs):
566 """Updates an existing alarm
567
568 Arguments:
569 alarm_id - the identifier of the alarm to update
570 kwargs - a dict of the alarm attributes to update
571
572 """
573 return self.ceilo_drv.client.alarms.update(alarm_id, **kwargs)
574
575 def ceilo_alarm_delete(self, alarm_id):
576 self.ceilo_drv.client.alarms.delete(alarm_id)
577
578 def create_port_chain(self,name,port_lists):
579 "Create port chain"
580 #Create port pair
581 ppgrp_list = list()
582 for index,port_pair in enumerate(port_lists):
583 ppair_list = list()
584 ingress_port,egress_port = port_pair
585 #Disable security group and port security for the port
586 self.neutron_drv.port_update(ingress_port,no_security_groups=True,port_security_enabled=False)
587 if ingress_port != egress_port:
588 self.neutron_drv.port_update(egress_port,no_security_groups=True,port_security_enabled=False)
589
590 ppair_id = self.portchain_drv.create_port_pair(name+'ppair'+str(index),ingress_port,egress_port)
591 ppair_list.append(ppair_id)
592 # Create port pair group
593 ppgrp_id = self.portchain_drv.create_port_pair_group(name+'_ppgrp_'+str(index),ppair_list)
594 ppgrp_list.append(ppgrp_id)
595 #Create port chain
596 port_chain_id = self.portchain_drv.create_port_chain(name,ppgrp_list)
597 return port_chain_id
598
599 def delete_port_chain(self,port_chain_id):
600 "Delete port chain"
601 try:
602 result = self.portchain_drv.get_port_chain(port_chain_id)
603 port_chain = result.json()
604 self.log.debug("Port chain result is %s", port_chain)
605 port_pair_groups = port_chain["port_chain"]["port_pair_groups"]
606 self.portchain_drv.delete_port_chain(port_chain_id)
607
608 # Get port pairs and delete port pair groups
609 port_pairs = list()
610 self.log.debug("Port pair groups during delete is %s", port_pair_groups)
611 for port_pair_group_id in port_pair_groups:
612 result = self.portchain_drv.get_port_pair_group(port_pair_group_id)
613 port_pair_group = result.json()
614 self.log.debug("Port pair group result is %s", port_pair_group)
615 port_pairs.extend(port_pair_group["port_pair_group"]["port_pairs"])
616 self.portchain_drv.delete_port_pair_group(port_pair_group_id)
617
618 self.log.debug("Port pairs during delete is %s",port_pairs)
619
620 for port_pair_id in port_pairs:
621 self.portchain_drv.delete_port_pair(port_pair_id)
622 pass
623 except Exception as e:
624 self.log.error("Error while delete port chain with id %s, exception %s", port_chain_id,str(e))
625
626 def update_port_chain(self,port_chain_id,flow_classifier_list):
627 result = self.portchain_drv.get_port_chain(port_chain_id)
628 result.raise_for_status()
629 port_chain = result.json()['port_chain']
630 new_flow_classifier_list = list()
631 if port_chain and port_chain['flow_classifiers']:
632 new_flow_classifier_list.extend(port_chain['flow_classifiers'])
633 new_flow_classifier_list.extend(flow_classifier_list)
634 port_chain_id = self.portchain_drv.update_port_chain(port_chain['id'],flow_classifiers=new_flow_classifier_list)
635 return port_chain_id
636
637 def create_flow_classifer(self,classifier_name,classifier_dict):
638 "Create flow classifier"
639 flow_classifier_id = self.portchain_drv.create_flow_classifier(classifier_name,classifier_dict)
640 return flow_classifier_id
641
642 def delete_flow_classifier(self,classifier_id):
643 "Create flow classifier"
644 try:
645 self.portchain_drv.delete_flow_classifier(classifier_id)
646 except Exception as e:
647 self.log.error("Error while deleting flow classifier with id %s, exception %s", classifier_id,str(e))
648
649 def get_port_chain_list(self):
650 result = self.portchain_drv.get_port_chain_list()
651 port_chain_list = result.json()
652 if 'port_chains' in port_chain_list:
653 return port_chain_list['port_chains']
654
655 def cinder_volume_list(self):
656 return self.cinder_drv.volume_list()
657
658 def cinder_volume_get(self,vol_id):
659 return self.cinder_drv.volume_get(vol_id)
660
661 def cinder_volume_set_metadata(self, volumeid, metadata):
662 return self.cinder_drv.volume_set_metadata(volumeid, metadata)
663
664 def cinder_volume_delete_metadata(self, volumeid, metadata):
665 return self.cinder_drv.volume_delete_metadata(volumeid, metadata)
666
667
668