CAL refactoring
[osm/SO.git] / rwcal / plugins / vala / rwcal_openstack / rift / rwcal / openstack / nova / nova_drv.py
1 #!/usr/bin/python
2
3 #
4 # Copyright 2017 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 import logging
19 from novaclient import client as nvclient
20
21
22 class NovaDrvAPIVersionException(Exception):
23 def __init__(self, errors):
24 self.errors = errors
25 super(NovaDrvAPIVersionException, self).__init__("Multiple Exception Received")
26
27 def __str__(self):
28 return self.__repr__()
29
30 def __repr__(self):
31 msg = "{} : Following Exception(s) have occured during Nova API discovery".format(self.__class__)
32 for n,e in enumerate(self.errors):
33 msg += "\n"
34 msg += " {}: {}".format(n, str(e))
35 return msg
36
37
38 class NovaDriver(object):
39 """
40 NovaDriver Class for compute orchestration
41 """
42 ### List of supported API versions in prioritized order
43 supported_versions = ["2.1", "2.0"]
44
45 def __init__(self,
46 sess_handle,
47 region_name = 'RegionOne',
48 service_type = 'compute',
49 logger = None):
50 """
51 Constructor for NovaDriver class
52 Arguments:
53 sess_handle (instance of class SessionDriver)
54 region_name (string): Region Name
55 service_type(string): Type of service in service catalog
56 logger (instance of logging.Logger)
57 """
58
59 if logger is None:
60 self.log = logging.getLogger('rwcal.openstack.nova')
61 self.log.setLevel(logging.DEBUG)
62 else:
63 self.log = logger
64
65 self._sess_handle = sess_handle
66
67 #### Attempt to use API versions in prioritized order defined in
68 #### NovaDriver.supported_versions
69 def select_version(version):
70 try:
71 self.log.info("Attempting to use Nova v%s APIs", version)
72 nvdrv = nvclient.Client(version=version,
73 region_name = region_name,
74 service_type = service_type,
75 session = self._sess_handle.session,
76 logger = self.log)
77 except Exception as e:
78 self.log.info(str(e))
79 raise
80 else:
81 self.log.info("Nova API v%s selected", version)
82 return (version, nvdrv)
83
84 errors = []
85 for v in NovaDriver.supported_versions:
86 try:
87 (self._version, self._nv_drv) = select_version(v)
88 except Exception as e:
89 errors.append(e)
90 else:
91 break
92 else:
93 raise NovaDrvAPIVersionException(errors)
94
95 @property
96 def project_id(self):
97 return self._sess_handle.project_id
98
99 @property
100 def nova_endpoint(self):
101 return self._nv_drv.client.get_endpoint()
102
103 @property
104 def nova_quota(self):
105 """
106 Returns Nova Quota (a dictionary) for project
107 """
108 try:
109 quota = self._nv_drv.quotas.get(self.project_id)
110 except Exception as e:
111 self.log.exception("Get Nova quota operation failed. Exception: %s", str(e))
112 raise
113 return quota.to_dict()
114
115 def extensions_list(self):
116 """
117 Returns a list of available nova extensions.
118 Arguments:
119 None
120 Returns:
121 A list of dictionaries. Each dictionary contains attributes for a single NOVA extension
122 """
123 try:
124 extensions = self._nv_drv.list_extensions.show_all()
125 except Exception as e:
126 self.log.exception("List extension operation failed. Exception: %s", str(e))
127 raise
128 return [ ext.to_dict() for ext in extensions ]
129
130
131 def _get_nova_connection(self):
132 """
133 Returns instance of object novaclient.client.Client
134 Use for DEBUG ONLY
135 """
136 return self._nv_drv
137
138 def _flavor_extra_spec_get(self, flavor):
139 """
140 Get extra_specs associated with a flavor
141 Arguments:
142 flavor: Object of novaclient.v2.flavors.Flavor
143
144 Returns:
145 A dictionary of extra_specs (key-value pairs)
146 """
147 try:
148 extra_specs = flavor.get_keys()
149 except Exception as e:
150 self.log.exception("Could not get the EPA attributes for flavor with flavor_id : %s. Exception: %s",
151 flavor.id, str(e))
152 raise
153 return extra_specs
154
155 def _flavor_get(self, flavor_id):
156 """
157 Get flavor by flavor_id
158 Arguments:
159 flavor_id(string): UUID of flavor_id
160
161 Returns:
162 dictionary of flavor parameters
163 """
164 try:
165 flavor = self._nv_drv.flavors.get(flavor_id)
166 except Exception as e:
167 self.log.exception("Did not find flavor with flavor_id : %s. Exception: %s",flavor_id, str(e))
168 raise
169 response = flavor.to_dict()
170 response['extra_specs'] = self._flavor_extra_spec_get(flavor)
171 return response
172
173 try:
174 extra_specs = flavor.get_keys()
175 except Exception as e:
176 self.log.exception("Could not get the EPA attributes for flavor with flavor_id : %s. Exception: %s",
177 flavor_id, str(e))
178 raise
179
180 response = flavor.to_dict()
181 assert 'extra_specs' not in response, "Key extra_specs present as flavor attribute"
182 response['extra_specs'] = extra_specs
183 return response
184
185 def flavor_get(self, flavor_id):
186 """
187 Get flavor by flavor_id
188 Arguments:
189 flavor_id(string): UUID of flavor_id
190
191 Returns:
192 dictionary of flavor parameters
193 """
194 return self._flavor_get(flavor_id)
195
196 def flavor_find(self, **kwargs):
197 """
198 Returns list of all flavors (dictionary) matching the filters provided in kwargs
199
200 Arguments:
201 A dictionary in following keys
202 {
203 "vcpus": Number of vcpus required
204 "ram" : Memory in MB
205 "disk" : Secondary storage in GB
206 }
207 Returns:
208 A list of dictionaries. Each dictionary contains attributes for a single flavor instance
209 """
210 try:
211 flavor_list = self._nv_drv.flavors.findall(**kwargs)
212 except Exception as e:
213 self.log.exception("Find Flavor operation failed. Exception: %s",str(e))
214 raise
215
216 flavor_info = list()
217 for f in flavor_list:
218 flavor = f.to_dict()
219 flavor['extra_specs'] = self._flavor_extra_spec_get(f)
220 flavor_info.append(flavor)
221
222 return flavor_info
223
224 def flavor_list(self):
225 """
226 Returns list of all flavors (dictionary per flavor)
227
228 Arguments:
229 None
230 Returns:
231 A list of dictionaries. Each dictionary contains attributes for a single flavor instance
232 """
233 flavors = []
234 flavor_info = []
235
236 try:
237 flavors = self._nv_drv.flavors.list()
238 except Exception as e:
239 self.log.exception("List Flavor operation failed. Exception: %s",str(e))
240 raise
241 if flavors:
242 flavor_info = [ self.flavor_get(flv.id) for flv in flavors ]
243 return flavor_info
244
245 def flavor_create(self, name, ram, vcpu, disk, extra_specs):
246 """
247 Create a new flavor
248
249 Arguments:
250 name (string): Name of the new flavor
251 ram (int) : Memory in MB
252 vcpus (int) : Number of VCPUs
253 disk (int) : Secondary storage size in GB
254 extra_specs (dictionary): EPA attributes dictionary
255
256 Returns:
257 flavor_id (string): UUID of flavor created
258 """
259 try:
260 flavor = self._nv_drv.flavors.create(name = name,
261 ram = ram,
262 vcpus = vcpu,
263 disk = disk,
264 flavorid = 'auto',
265 ephemeral = 0,
266 swap = 0,
267 rxtx_factor = 1.0,
268 is_public = True)
269 except Exception as e:
270 self.log.exception("Create Flavor operation failed. Exception: %s",str(e))
271 raise
272
273 if extra_specs:
274 try:
275 flavor.set_keys(extra_specs)
276 except Exception as e:
277 self.log.exception("Set Key operation failed for flavor: %s. Exception: %s",
278 flavor.id, str(e))
279 raise
280 return flavor.id
281
282 def flavor_delete(self, flavor_id):
283 """
284 Deletes a flavor identified by flavor_id
285
286 Arguments:
287 flavor_id (string): UUID of flavor to be deleted
288
289 Returns: None
290 """
291 assert flavor_id == self._flavor_get(flavor_id)['id']
292 try:
293 self._nv_drv.flavors.delete(flavor_id)
294 except Exception as e:
295 self.log.exception("Delete flavor operation failed for flavor: %s. Exception: %s",
296 flavor_id, str(e))
297 raise
298
299
300 def server_list(self):
301 """
302 Returns a list of available VMs for the project
303
304 Arguments: None
305
306 Returns:
307 A list of dictionaries. Each dictionary contains attributes associated
308 with individual VM
309 """
310 servers = []
311 server_info = []
312 try:
313 servers = self._nv_drv.servers.list()
314 except Exception as e:
315 self.log.exception("List Server operation failed. Exception: %s", str(e))
316 raise
317 server_info = [ server.to_dict() for server in servers]
318 return server_info
319
320 def _nova_server_get(self, server_id):
321 """
322 Returns a dictionary of attributes associated with VM identified by service_id
323
324 Arguments:
325 server_id (string): UUID of the VM/server for which information is requested
326
327 Returns:
328 A dictionary object with attributes associated with VM identified by server_id
329 """
330 try:
331 server = self._nv_drv.servers.get(server = server_id)
332 except Exception as e:
333 self.log.exception("Get Server operation failed for server_id: %s. Exception: %s",
334 server_id, str(e))
335 raise
336 else:
337 return server.to_dict()
338
339 def server_get(self, server_id):
340 """
341 Returns a dictionary of attributes associated with VM identified by service_id
342
343 Arguments:
344 server_id (string): UUID of the VM/server for which information is requested
345
346 Returns:
347 A dictionary object with attributes associated with VM identified by server_id
348 """
349 return self._nova_server_get(server_id)
350
351 def server_create(self, **kwargs):
352 """
353 Creates a new VM/server instance
354
355 Arguments:
356 A dictionary of following key-value pairs
357 {
358 server_name(string) : Name of the VM/Server
359 flavor_id (string) : UUID of the flavor to be used for VM
360 image_id (string) : UUID of the image to be used VM/Server instance,
361 This could be None if volumes (with images) are being used
362 network_list(List) : A List of network_ids. A port will be created in these networks
363 port_list (List) : A List of port-ids. These ports will be added to VM.
364 metadata (dict) : A dictionary of arbitrary key-value pairs associated with VM/server
365 userdata (string) : A script which shall be executed during first boot of the VM
366 availability_zone (string) : A name of the availability zone where instance should be launched
367 scheduler_hints (string) : Openstack scheduler_hints to be passed to nova scheduler
368 }
369 Returns:
370 server_id (string): UUID of the VM/server created
371
372 """
373 nics = []
374 if 'network_list' in kwargs:
375 for network_id in kwargs['network_list']:
376 nics.append({'net-id': network_id})
377
378 if 'port_list' in kwargs:
379 for port_id in kwargs['port_list']:
380 nics.append({'port-id': port_id})
381
382 try:
383 server = self._nv_drv.servers.create(
384 kwargs['name'],
385 kwargs['image_id'],
386 kwargs['flavor_id'],
387 meta = kwargs['metadata'] if 'metadata' in kwargs else None,
388 files = kwargs['files'] if 'files' in kwargs else None,
389 reservation_id = None,
390 min_count = None,
391 max_count = None,
392 userdata = kwargs['userdata'] if 'userdata' in kwargs else None,
393 security_groups = kwargs['security_groups'] if 'security_groups' in kwargs else None,
394 availability_zone = kwargs['availability_zone'] if 'availability_zone' in kwargs else None,
395 block_device_mapping_v2 = kwargs['block_device_mapping_v2'] if 'block_device_mapping_v2' in kwargs else None,
396 nics = nics,
397 scheduler_hints = kwargs['scheduler_hints'] if 'scheduler_hints' in kwargs else None,
398 config_drive = kwargs['config_drive'] if 'config_drive' in kwargs else None
399 )
400
401 except Exception as e:
402 self.log.exception("Create Server operation failed. Exception: %s", str(e))
403 raise
404 return server.to_dict()['id']
405
406 def server_delete(self, server_id):
407 """
408 Deletes a server identified by server_id
409
410 Arguments:
411 server_id (string): UUID of the server to be deleted
412
413 Returns: None
414 """
415 try:
416 self._nv_drv.servers.delete(server_id)
417 except Exception as e:
418 self.log.exception("Delete server operation failed for server_id: %s. Exception: %s",
419 server_id, str(e))
420 raise
421
422 def server_start(self, server_id):
423 """
424 Starts a server identified by server_id
425
426 Arguments:
427 server_id (string): UUID of the server to be started
428
429 Returns: None
430 """
431 try:
432 self._nv_drv.servers.start(server_id)
433 except Exception as e:
434 self.log.exception("Start Server operation failed for server_id : %s. Exception: %s",
435 server_id, str(e))
436 raise
437
438 def server_stop(self, server_id):
439 """
440 Arguments:
441 server_id (string): UUID of the server to be stopped
442
443 Returns: None
444 """
445 try:
446 self._nv_drv.servers.stop(server_id)
447 except Exception as e:
448 self.log.exception("Stop Server operation failed for server_id : %s. Exception: %s",
449 server_id, str(e))
450 raise
451
452 def server_pause(self, server_id):
453 """
454 Arguments:
455 server_id (string): UUID of the server to be paused
456
457 Returns: None
458 """
459 try:
460 self._nv_drv.servers.pause(server_id)
461 except Exception as e:
462 self.log.exception("Pause Server operation failed for server_id : %s. Exception: %s",
463 server_id, str(e))
464 raise
465
466 def server_unpause(self, server_id):
467 """
468 Arguments:
469 server_id (string): UUID of the server to be unpaused
470
471 Returns: None
472 """
473 try:
474 self._nv_drv.servers.unpause(server_id)
475 except Exception as e:
476 self.log.exception("Resume Server operation failed for server_id : %s. Exception: %s",
477 server_id, str(e))
478 raise
479
480
481 def server_suspend(self, server_id):
482 """
483 Arguments:
484 server_id (string): UUID of the server to be suspended
485
486 Returns: None
487 """
488 try:
489 self._nv_drv.servers.suspend(server_id)
490 except Exception as e:
491 self.log.exception("Suspend Server operation failed for server_id : %s. Exception: %s",
492 server_id, str(e))
493
494
495 def server_resume(self, server_id):
496 """
497 Arguments:
498 server_id (string): UUID of the server to be resumed
499
500 Returns: None
501 """
502 try:
503 self._nv_drv.servers.resume(server_id)
504 except Exception as e:
505 self.log.exception("Resume Server operation failed for server_id : %s. Exception: %s",
506 server_id, str(e))
507 raise
508
509 def server_reboot(self, server_id, reboot_type):
510 """
511 Arguments:
512 server_id (string) : UUID of the server to be rebooted
513 reboot_type(string):
514 'SOFT': Soft Reboot
515 'HARD': Hard Reboot
516 Returns: None
517 """
518 try:
519 self._nv_drv.servers.reboot(server_id, reboot_type)
520 except Exception as e:
521 self.log.exception("Reboot Server operation failed for server_id: %s. Exception: %s",
522 server_id, str(e))
523 raise
524
525 def server_console(self, server_id, console_type = 'novnc'):
526 """
527 Arguments:
528 server_id (string) : UUID of the server to be rebooted
529 console_type(string):
530 'novnc',
531 'xvpvnc'
532 Returns:
533 A dictionary object response for console information
534 """
535 try:
536 console_info = self._nv_drv.servers.get_vnc_console(server_id, console_type)
537 except Exception as e:
538 self.log.exception("Server Get-Console operation failed for server_id: %s. Exception: %s",
539 server_id, str(e))
540 raise
541 return console_info
542
543 def server_rebuild(self, server_id, image_id):
544 """
545 Arguments:
546 server_id (string) : UUID of the server to be rebooted
547 image_id (string) : UUID of the image to use
548 Returns: None
549 """
550
551 try:
552 self._nv_drv.servers.rebuild(server_id, image_id)
553 except Exception as e:
554 self.log.exception("Rebuild Server operation failed for server_id: %s. Exception: %s",
555 server_id, str(e))
556 raise
557
558
559 def server_add_port(self, server_id, port_id):
560 """
561 Arguments:
562 server_id (string): UUID of the server
563 port_id (string): UUID of the port to be attached
564
565 Returns: None
566 """
567 try:
568 self._nv_drv.servers.interface_attach(server_id,
569 port_id,
570 net_id = None,
571 fixed_ip = None)
572 except Exception as e:
573 self.log.exception("Server Port Add operation failed for server_id : %s, port_id : %s. Exception: %s",
574 server_id, port_id, str(e))
575 raise
576
577 def server_delete_port(self, server_id, port_id):
578 """
579 Arguments:
580 server_id (string): UUID of the server
581 port_id (string): UUID of the port to be deleted
582 Returns: None
583
584 """
585 try:
586 self._nv_drv.servers.interface_detach(server_id, port_id)
587 except Exception as e:
588 self.log.exception("Server Port Delete operation failed for server_id : %s, port_id : %s. Exception: %s",
589 server_id, port_id, str(e))
590 raise
591
592 def floating_ip_list(self):
593 """
594 Arguments:
595 None
596 Returns:
597 List of objects of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
598 """
599 try:
600 ip_list = self._nv_drv.floating_ips.list()
601 except Exception as e:
602 self.log.exception("Floating IP List operation failed. Exception: %s", str(e))
603 raise
604
605 return ip_list
606
607 def floating_ip_create(self, pool):
608 """
609 Arguments:
610 pool (string): Name of the pool (optional)
611 Returns:
612 An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
613 """
614 try:
615 floating_ip = self._nv_drv.floating_ips.create(pool)
616 except Exception as e:
617 self.log.exception("Floating IP Create operation failed. Exception: %s", str(e))
618 raise
619
620 return floating_ip
621
622 def floating_ip_delete(self, floating_ip):
623 """
624 Arguments:
625 floating_ip: An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
626 Returns:
627 None
628 """
629 try:
630 floating_ip = self._nv_drv.floating_ips.delete(floating_ip)
631 except Exception as e:
632 self.log.exception("Floating IP Delete operation failed. Exception: %s", str(e))
633 raise
634
635 def floating_ip_assign(self, server_id, floating_ip, fixed_ip):
636 """
637 Arguments:
638 server_id (string) : UUID of the server
639 floating_ip (string): IP address string for floating-ip
640 fixed_ip (string) : IP address string for the fixed-ip with which floating ip will be associated
641 Returns:
642 None
643 """
644 try:
645 self._nv_drv.servers.add_floating_ip(server_id, floating_ip, fixed_ip)
646 except Exception as e:
647 self.log.exception("Assign Floating IP operation failed. Exception: %s", str(e))
648 raise
649
650 def floating_ip_release(self, server_id, floating_ip):
651 """
652 Arguments:
653 server_id (string) : UUID of the server
654 floating_ip (string): IP address string for floating-ip
655 Returns:
656 None
657 """
658 try:
659 self._nv_drv.servers.remove_floating_ip(server_id, floating_ip)
660 except Exception as e:
661 self.log.exception("Release Floating IP operation failed. Exception: %s", str(e))
662 raise
663
664 def volume_list(self, server_id):
665 """
666 List of volumes attached to the server
667
668 Arguments:
669 None
670 Returns:
671 List of dictionary objects where dictionary is representation of class (novaclient.v2.volumes.Volume)
672 """
673 try:
674 volumes = self._nv_drv.volumes.get_server_volumes(server_id=server_id)
675 except Exception as e:
676 self.log.exception("Get volume information failed. Exception: %s", str(e))
677 raise
678
679 volume_info = [v.to_dict() for v in volumes]
680 return volume_info
681
682
683 def group_list(self):
684 """
685 List of Server Affinity and Anti-Affinity Groups
686
687 Arguments:
688 None
689 Returns:
690 List of dictionary objects where dictionary is representation of class (novaclient.v2.server_groups.ServerGroup)
691 """
692 try:
693 group_list = self._nv_drv.server_groups.list()
694 except Exception as e:
695 self.log.exception("Server Group List operation failed. Exception: %s", str(e))
696 raise
697
698 group_info = [ group.to_dict() for group in group_list ]
699 return group_info
700
701
702 def security_group_list(self):
703 """
704 List of Security Group
705 Arguments:
706 None
707 Returns:
708 List of dictionary objects representating novaclient.v2.security_groups.SecurityGroup class
709 """
710 try:
711 sec_groups = self._nv_drv.security_groups.list()
712 except Exception as e:
713 self.log.exception("Security Group List operation failed. Exception: %s", str(e))
714 raise
715 sec_info = [ sec_group.to_dict() for sec_group in sec_groups]
716 return sec_info
717