4 # Copyright 2017 RIFT.IO Inc
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
19 from novaclient
import client
as nvclient
22 class NovaDrvAPIVersionException(Exception):
23 def __init__(self
, errors
):
25 super(NovaDrvAPIVersionException
, self
).__init
__("Multiple Exception Received")
28 return self
.__repr
__()
31 msg
= "{} : Following Exception(s) have occured during Nova API discovery".format(self
.__class
__)
32 for n
,e
in enumerate(self
.errors
):
34 msg
+= " {}: {}".format(n
, str(e
))
38 class NovaDriver(object):
40 NovaDriver Class for compute orchestration
42 ### List of supported API versions in prioritized order
43 supported_versions
= ["2.1", "2.0"]
47 region_name
= 'RegionOne',
48 service_type
= 'compute',
51 Constructor for NovaDriver class
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)
60 self
.log
= logging
.getLogger('rwcal.openstack.nova')
61 self
.log
.setLevel(logging
.DEBUG
)
65 self
._sess
_handle
= sess_handle
67 #### Attempt to use API versions in prioritized order defined in
68 #### NovaDriver.supported_versions
69 def select_version(version
):
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
,
77 except Exception as e
:
81 self
.log
.info("Nova API v%s selected", version
)
82 return (version
, nvdrv
)
85 for v
in NovaDriver
.supported_versions
:
87 (self
._version
, self
._nv
_drv
) = select_version(v
)
88 except Exception as e
:
93 raise NovaDrvAPIVersionException(errors
)
97 return self
._sess
_handle
.project_id
100 def nova_endpoint(self
):
101 return self
._nv
_drv
.client
.get_endpoint()
104 def nova_quota(self
):
106 Returns Nova Quota (a dictionary) for project
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
))
113 return quota
.to_dict()
115 def extensions_list(self
):
117 Returns a list of available nova extensions.
121 A list of dictionaries. Each dictionary contains attributes for a single NOVA extension
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
))
128 return [ ext
.to_dict() for ext
in extensions
]
131 def _get_nova_connection(self
):
133 Returns instance of object novaclient.client.Client
138 def _flavor_extra_spec_get(self
, flavor
):
140 Get extra_specs associated with a flavor
142 flavor: Object of novaclient.v2.flavors.Flavor
145 A dictionary of extra_specs (key-value pairs)
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",
155 def _flavor_get(self
, flavor_id
):
157 Get flavor by flavor_id
159 flavor_id(string): UUID of flavor_id
162 dictionary of flavor parameters
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
))
169 response
= flavor
.to_dict()
170 response
['extra_specs'] = self
._flavor
_extra
_spec
_get
(flavor
)
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",
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
185 def flavor_get(self
, flavor_id
):
187 Get flavor by flavor_id
189 flavor_id(string): UUID of flavor_id
192 dictionary of flavor parameters
194 return self
._flavor
_get
(flavor_id
)
196 def flavor_find(self
, **kwargs
):
198 Returns list of all flavors (dictionary) matching the filters provided in kwargs
201 A dictionary in following keys
203 "vcpus": Number of vcpus required
205 "disk" : Secondary storage in GB
208 A list of dictionaries. Each dictionary contains attributes for a single flavor instance
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
))
217 for f
in flavor_list
:
219 flavor
['extra_specs'] = self
._flavor
_extra
_spec
_get
(f
)
220 flavor_info
.append(flavor
)
224 def flavor_list(self
):
226 Returns list of all flavors (dictionary per flavor)
231 A list of dictionaries. Each dictionary contains attributes for a single flavor instance
237 flavors
= self
._nv
_drv
.flavors
.list()
238 except Exception as e
:
239 self
.log
.exception("List Flavor operation failed. Exception: %s",str(e
))
242 flavor_info
= [ self
.flavor_get(flv
.id) for flv
in flavors
]
245 def flavor_create(self
, name
, ram
, vcpu
, disk
, extra_specs
):
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
257 flavor_id (string): UUID of flavor created
260 flavor
= self
._nv
_drv
.flavors
.create(name
= name
,
269 except Exception as e
:
270 self
.log
.exception("Create Flavor operation failed. Exception: %s",str(e
))
275 flavor
.set_keys(extra_specs
)
276 except Exception as e
:
277 self
.log
.exception("Set Key operation failed for flavor: %s. Exception: %s",
282 def flavor_delete(self
, flavor_id
):
284 Deletes a flavor identified by flavor_id
287 flavor_id (string): UUID of flavor to be deleted
291 assert flavor_id
== self
._flavor
_get
(flavor_id
)['id']
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",
300 def server_list(self
):
302 Returns a list of available VMs for the project
307 A list of dictionaries. Each dictionary contains attributes associated
313 servers
= self
._nv
_drv
.servers
.list()
314 except Exception as e
:
315 self
.log
.exception("List Server operation failed. Exception: %s", str(e
))
317 server_info
= [ server
.to_dict() for server
in servers
]
320 def _nova_server_get(self
, server_id
):
322 Returns a dictionary of attributes associated with VM identified by service_id
325 server_id (string): UUID of the VM/server for which information is requested
328 A dictionary object with attributes associated with VM identified by server_id
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",
337 return server
.to_dict()
339 def server_get(self
, server_id
):
341 Returns a dictionary of attributes associated with VM identified by service_id
344 server_id (string): UUID of the VM/server for which information is requested
347 A dictionary object with attributes associated with VM identified by server_id
349 return self
._nova
_server
_get
(server_id
)
351 def server_create(self
, **kwargs
):
353 Creates a new VM/server instance
356 A dictionary of following key-value pairs
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
370 server_id (string): UUID of the VM/server created
374 if 'network_list' in kwargs
:
375 for network_id
in kwargs
['network_list']:
376 nics
.append({'net-id': network_id
})
378 if 'port_list' in kwargs
:
379 for port_id
in kwargs
['port_list']:
380 nics
.append({'port-id': port_id
})
383 server
= self
._nv
_drv
.servers
.create(
387 meta
= kwargs
['metadata'] if 'metadata' in kwargs
else None,
388 files
= kwargs
['files'] if 'files' in kwargs
else None,
389 reservation_id
= 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,
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
401 except Exception as e
:
402 self
.log
.exception("Create Server operation failed. Exception: %s", str(e
))
404 return server
.to_dict()['id']
406 def server_delete(self
, server_id
):
408 Deletes a server identified by server_id
411 server_id (string): UUID of the server to be deleted
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",
422 def server_start(self
, server_id
):
424 Starts a server identified by server_id
427 server_id (string): UUID of the server to be started
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",
438 def server_stop(self
, server_id
):
441 server_id (string): UUID of the server to be stopped
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",
452 def server_pause(self
, server_id
):
455 server_id (string): UUID of the server to be paused
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",
466 def server_unpause(self
, server_id
):
469 server_id (string): UUID of the server to be unpaused
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",
481 def server_suspend(self
, server_id
):
484 server_id (string): UUID of the server to be suspended
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",
495 def server_resume(self
, server_id
):
498 server_id (string): UUID of the server to be resumed
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",
509 def server_reboot(self
, server_id
, reboot_type
):
512 server_id (string) : UUID of the server to be rebooted
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",
525 def server_console(self
, server_id
, console_type
= 'novnc'):
528 server_id (string) : UUID of the server to be rebooted
529 console_type(string):
533 A dictionary object response for console information
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",
543 def server_rebuild(self
, server_id
, image_id
):
546 server_id (string) : UUID of the server to be rebooted
547 image_id (string) : UUID of the image to use
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",
559 def server_add_port(self
, server_id
, port_id
):
562 server_id (string): UUID of the server
563 port_id (string): UUID of the port to be attached
568 self
._nv
_drv
.servers
.interface_attach(server_id
,
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
))
577 def server_delete_port(self
, server_id
, port_id
):
580 server_id (string): UUID of the server
581 port_id (string): UUID of the port to be deleted
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
))
592 def floating_ip_list(self
):
597 List of objects of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
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
))
607 def floating_ip_create(self
, pool
):
610 pool (string): Name of the pool (optional)
612 An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
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
))
622 def floating_ip_delete(self
, floating_ip
):
625 floating_ip: An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
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
))
635 def floating_ip_assign(self
, server_id
, floating_ip
, fixed_ip
):
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
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
))
650 def floating_ip_release(self
, server_id
, floating_ip
):
653 server_id (string) : UUID of the server
654 floating_ip (string): IP address string for floating-ip
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
))
664 def volume_list(self
, server_id
):
666 List of volumes attached to the server
671 List of dictionary objects where dictionary is representation of class (novaclient.v2.volumes.Volume)
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
))
679 volume_info
= [v
.to_dict() for v
in volumes
]
683 def group_list(self
):
685 List of Server Affinity and Anti-Affinity Groups
690 List of dictionary objects where dictionary is representation of class (novaclient.v2.server_groups.ServerGroup)
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
))
698 group_info
= [ group
.to_dict() for group
in group_list
]
702 def security_group_list(self
):
704 List of Security Group
708 List of dictionary objects representating novaclient.v2.security_groups.SecurityGroup class
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
))
715 sec_info
= [ sec_group
.to_dict() for sec_group
in sec_groups
]