ce27e6a9e39b1cf3713fc16390252d978bd2850d
[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 json
20 import logging
21 import ipaddress
22
23 from keystoneclient import v3 as ksclientv3
24 from keystoneclient.v2_0 import client as ksclientv2
25 from novaclient import client as nova_client
26 from neutronclient.neutron import client as ntclient
27 from glanceclient.v2 import client as glclient
28 from ceilometerclient import client as ceilo_client
29 from cinderclient.v2 import client as cinder_client
30
31 # Exceptions
32 import novaclient.exceptions as NovaException
33 import keystoneclient.exceptions as KeystoneExceptions
34 import neutronclient.common.exceptions as NeutronException
35 import glanceclient.exc as GlanceException
36 import cinderclient.exceptions as CinderException
37
38 logger = logging.getLogger('rwcal.openstack.drv')
39 logger.setLevel(logging.DEBUG)
40
41 class ValidationError(Exception):
42 pass
43
44
45 class KeystoneDriver(object):
46 """
47 Driver base-class for keystoneclient APIs
48 """
49 def __init__(self, ksclient):
50 """
51 Constructor for KeystoneDriver base class
52 Arguments: None
53 Returns: None
54 """
55 self.ksclient = ksclient
56
57 def get_username(self):
58 """
59 Returns the username associated with keystoneclient connection
60 """
61 return self._username
62
63 def get_password(self):
64 """
65 Returns the password associated with keystoneclient connection
66 """
67 return self._password
68
69 def get_tenant_name(self):
70 """
71 Returns the tenant name associated with keystoneclient connection
72 """
73 return self._tenant_name
74
75 def _get_keystone_connection(self):
76 """
77 Returns object of class python-keystoneclient class
78 """
79 if not hasattr(self, '_keystone_connection'):
80 self._keystone_connection = self.ksclient(**self._get_keystone_credentials())
81 return self._keystone_connection
82
83 def is_auth_token_valid(self, token_expiry, time_fmt):
84 """
85 Performs validity on auth_token
86 Arguments:
87 token_expiry (string): Expiry time for token
88 time_fmt (string) : Format for expiry string in auth_ref
89
90 Returns:
91 True/False (Boolean): (auth_token is valid or auth_token is invalid)
92 """
93 import time
94 import datetime
95 import dateutil.parser
96 try:
97 now = datetime.datetime.timetuple(datetime.datetime.utcnow())
98 expires_at = dateutil.parser.parse(token_expiry)
99 t_now = time.mktime(now)
100 t_expiry = time.mktime(expires_at.timetuple())
101
102 if (t_expiry <= t_now) or ((t_expiry - t_now) < 300 ):
103 ### Token has expired or about to expire (5 minute)
104 delattr(self, '_keystone_connection')
105 return False
106 else:
107 return True
108 except Exception as e:
109 logger.error("Received except %s during auth_token validity check" %str(e))
110 logger.info("Can not validate the auth_token. Assuming invalid")
111 return False
112
113
114 def get_service_endpoint(self, service_type, endpoint_type):
115 """
116 Returns requested type of endpoint for requested service type
117 Arguments:
118 service_type (string): Service Type (e.g. computev3, image, network)
119 endpoint_type(string): Endpoint Type (e.g. publicURL,adminURL,internalURL)
120 Returns:
121 service_endpoint(string): Service endpoint string
122 """
123 endpoint_kwargs = {'service_type' : service_type,
124 'endpoint_type' : endpoint_type}
125 try:
126 ksconn = self._get_keystone_connection()
127 service_endpoint = ksconn.service_catalog.url_for(**endpoint_kwargs)
128 except (KeystoneExceptions.Unauthorized, KeystoneExceptions.AuthorizationFailure) as e:
129 raise
130 except Exception as e:
131 logger.error("OpenstackDriver: Service Catalog discovery operation failed for service_type: %s, endpoint_type: %s. Exception: %s" %(service_type, endpoint_type, str(e)))
132 raise
133 return service_endpoint
134
135
136 def get_raw_token(self):
137 """
138 Returns a valid raw_auth_token string
139
140 Returns (string): raw_auth_token string
141 """
142 ksconn = self._get_keystone_connection()
143 try:
144 raw_token = ksconn.get_raw_token_from_identity_service(auth_url = self._auth_url,
145 token = self.get_auth_token())
146 except KeystoneExceptions.AuthorizationFailure as e:
147 logger.error("OpenstackDriver: get_raw_token_from_identity_service Failure. Exception: %s" %(str(e)))
148 return None
149
150 except Exception as e:
151 logger.error("OpenstackDriver: Could not retrieve raw_token. Exception: %s" %(str(e)))
152
153 return raw_token
154
155 def get_tenant_id(self):
156 """
157 Returns tenant_id for the project/tenant. Tenant name is provided during
158 class instantiation
159
160 Returns (string): Tenant ID
161 """
162 ksconn = self._get_keystone_connection()
163 return ksconn.tenant_id
164
165 def get_security_mode(self):
166 """
167 Returns certificate_validation policy in case of SSL/TLS connection.
168 This policy is provided during class instantiation
169
170 Returns (boolean):
171 The boolean returned are designed to match the python-client class instantiation ("insecure") value.
172 for nova/neutron/glance/keystone clients
173
174 True: No certificate validation required -- Insecure mode
175 False: Certificate validation required -- Secure mode
176 """
177 return self._insecure
178
179 def tenant_list(self):
180 """
181 Returns list of tenants
182 """
183 pass
184
185 def tenant_create(self, name):
186 """
187 Create a new tenant
188 """
189 pass
190
191 def tenant_delete(self, tenant_id):
192 """
193 Deletes a tenant identified by tenant_id
194 """
195 pass
196
197 def roles_list(self):
198 pass
199
200 def roles_create(self):
201 pass
202
203 def roles_delete(self):
204 pass
205
206 class KeystoneDriverV2(KeystoneDriver):
207 """
208 Driver class for keystoneclient V2 APIs
209 """
210 def __init__(self, username, password, auth_url,tenant_name, insecure):
211 """
212 Constructor for KeystoneDriverV3 class
213 Arguments:
214 username (string) : Username
215 password (string) : Password
216 auth_url (string) : Authentication URL
217 tenant_name(string): Tenant Name
218
219 Returns: None
220 """
221 self._username = username
222 self._password = password
223 self._auth_url = auth_url
224 self._tenant_name = tenant_name
225 self._insecure = insecure
226 super(KeystoneDriverV2, self).__init__(ksclientv2.Client)
227
228 def _get_keystone_credentials(self):
229 """
230 Returns the dictionary of kwargs required to instantiate python-keystoneclient class
231 """
232 creds = {}
233 #creds['user_domain'] = self._domain_name
234 creds['username'] = self._username
235 creds['password'] = self._password
236 creds['auth_url'] = self._auth_url
237 creds['tenant_name'] = self._tenant_name
238 creds['insecure'] = self.get_security_mode()
239 return creds
240
241 def get_auth_token(self):
242 """
243 Returns a valid auth_token
244
245 Returns (string): auth_token string
246 """
247 ksconn = self._get_keystone_connection()
248 return ksconn.auth_token
249
250 def is_auth_token_valid(self):
251 """
252 Performs validity on auth_token
253 Arguments:
254
255 Returns:
256 True/False (Boolean): (auth_token is valid or auth_token is invalid)
257 """
258 ksconn = self._get_keystone_connection()
259 result = super(KeystoneDriverV2, self).is_auth_token_valid(ksconn.auth_ref['token']['expires'],
260 "%Y-%m-%dT%H:%M:%SZ")
261 return result
262
263
264 class KeystoneDriverV3(KeystoneDriver):
265 """
266 Driver class for keystoneclient V3 APIs
267 """
268 def __init__(self, username, password, auth_url,tenant_name, insecure):
269 """
270 Constructor for KeystoneDriverV3 class
271 Arguments:
272 username (string) : Username
273 password (string) : Password
274 auth_url (string) : Authentication URL
275 tenant_name(string): Tenant Name
276
277 Returns: None
278 """
279 self._username = username
280 self._password = password
281 self._auth_url = auth_url
282 self._tenant_name = tenant_name
283 self._insecure = insecure
284 super(KeystoneDriverV3, self).__init__(ksclientv3.Client)
285
286 def _get_keystone_credentials(self):
287 """
288 Returns the dictionary of kwargs required to instantiate python-keystoneclient class
289 """
290 creds = {}
291 #creds['user_domain'] = self._domain_name
292 creds['username'] = self._username
293 creds['password'] = self._password
294 creds['auth_url'] = self._auth_url
295 creds['project_name'] = self._tenant_name
296 creds['insecure'] = self._insecure
297 return creds
298
299 def get_auth_token(self):
300 """
301 Returns a valid auth_token
302
303 Returns (string): auth_token string
304 """
305 ksconn = self._get_keystone_connection()
306 return ksconn.auth_ref['auth_token']
307
308 def is_auth_token_valid(self):
309 """
310 Performs validity on auth_token
311 Arguments:
312
313 Returns:
314 True/False (Boolean): (auth_token is valid or auth_token is invalid)
315 """
316 ksconn = self._get_keystone_connection()
317 result = super(KeystoneDriverV3, self).is_auth_token_valid(ksconn.auth_ref['expires_at'],
318 "%Y-%m-%dT%H:%M:%S.%fZ")
319 return result
320
321 class NovaDriver(object):
322 """
323 Driver for openstack nova_client
324 """
325 def __init__(self, ks_drv, service_name, version):
326 """
327 Constructor for NovaDriver
328 Arguments: KeystoneDriver class object
329 """
330 self.ks_drv = ks_drv
331 self._service_name = service_name
332 self._version = version
333
334 def _get_nova_credentials(self):
335 """
336 Returns a dictionary of kwargs required to instantiate python-novaclient class
337 """
338 creds = {}
339 creds['version'] = self._version
340 creds['bypass_url'] = self.ks_drv.get_service_endpoint(self._service_name, "publicURL")
341 creds['username'] = self.ks_drv.get_username()
342 creds['project_id'] = self.ks_drv.get_tenant_name()
343 creds['auth_token'] = self.ks_drv.get_auth_token()
344 creds['insecure'] = self.ks_drv.get_security_mode()
345 return creds
346
347 def _get_nova_connection(self):
348 """
349 Returns an object of class python-novaclient
350 """
351 if not hasattr(self, '_nova_connection'):
352 self._nova_connection = nova_client.Client(**self._get_nova_credentials())
353 else:
354 # Reinitialize if auth_token is no longer valid
355 if not self.ks_drv.is_auth_token_valid():
356 self._nova_connection = nova_client.Client(**self._get_nova_credentials())
357 return self._nova_connection
358
359 def _flavor_get(self, flavor_id):
360 """
361 Get flavor by flavor_id
362 Arguments:
363 flavor_id(string): UUID of flavor_id
364
365 Returns:
366 dictionary of flavor parameters
367 """
368 nvconn = self._get_nova_connection()
369 try:
370 flavor = nvconn.flavors.get(flavor_id)
371 except Exception as e:
372 logger.info("OpenstackDriver: Did not find flavor with flavor_id : %s. Exception: %s"%(flavor_id, str(e)))
373 raise
374
375 try:
376 extra_specs = flavor.get_keys()
377 except Exception as e:
378 logger.info("OpenstackDriver: Could not get the EPA attributes for flavor with flavor_id : %s. Exception: %s"%(flavor_id, str(e)))
379 raise
380
381 response = flavor.to_dict()
382 assert 'extra_specs' not in response, "Key extra_specs present as flavor attribute"
383 response['extra_specs'] = extra_specs
384 return response
385
386 def flavor_get(self, flavor_id):
387 """
388 Get flavor by flavor_id
389 Arguments:
390 flavor_id(string): UUID of flavor_id
391
392 Returns:
393 dictionary of flavor parameters
394 """
395 return self._flavor_get(flavor_id)
396
397 def flavor_list(self):
398 """
399 Returns list of all flavors (dictionary per flavor)
400
401 Arguments:
402 None
403 Returns:
404 A list of dictionaries. Each dictionary contains attributes for a single flavor instance
405 """
406 flavors = []
407 flavor_info = []
408 nvconn = self._get_nova_connection()
409 try:
410 flavors = nvconn.flavors.list()
411 except Exception as e:
412 logger.error("OpenstackDriver: List Flavor operation failed. Exception: %s"%(str(e)))
413 raise
414 if flavors:
415 flavor_info = [ self.flavor_get(flv.id) for flv in flavors ]
416 return flavor_info
417
418 def flavor_create(self, name, ram, vcpu, disk, extra_specs):
419 """
420 Create a new flavor
421
422 Arguments:
423 name (string): Name of the new flavor
424 ram (int) : Memory in MB
425 vcpus (int) : Number of VCPUs
426 disk (int) : Secondary storage size in GB
427 extra_specs (dictionary): EPA attributes dictionary
428
429 Returns:
430 flavor_id (string): UUID of flavor created
431 """
432 nvconn = self._get_nova_connection()
433 try:
434 flavor = nvconn.flavors.create(name = name,
435 ram = ram,
436 vcpus = vcpu,
437 disk = disk,
438 flavorid = 'auto',
439 ephemeral = 0,
440 swap = 0,
441 rxtx_factor = 1.0,
442 is_public = True)
443 except Exception as e:
444 logger.error("OpenstackDriver: Create Flavor operation failed. Exception: %s"%(str(e)))
445 raise
446
447 if extra_specs:
448 try:
449 flavor.set_keys(extra_specs)
450 except Exception as e:
451 logger.error("OpenstackDriver: Set Key operation failed for flavor: %s. Exception: %s" %(flavor.id, str(e)))
452 raise
453 return flavor.id
454
455 def flavor_delete(self, flavor_id):
456 """
457 Deletes a flavor identified by flavor_id
458
459 Arguments:
460 flavor_id (string): UUID of flavor to be deleted
461
462 Returns: None
463 """
464 assert flavor_id == self._flavor_get(flavor_id)['id']
465 nvconn = self._get_nova_connection()
466 try:
467 nvconn.flavors.delete(flavor_id)
468 except Exception as e:
469 logger.error("OpenstackDriver: Delete flavor operation failed for flavor: %s. Exception: %s" %(flavor_id, str(e)))
470 raise
471
472
473 def server_list(self):
474 """
475 Returns a list of available VMs for the project
476
477 Arguments: None
478
479 Returns:
480 A list of dictionaries. Each dictionary contains attributes associated
481 with individual VM
482 """
483 servers = []
484 server_info = []
485 nvconn = self._get_nova_connection()
486 try:
487 servers = nvconn.servers.list()
488 except Exception as e:
489 logger.error("OpenstackDriver: List Server operation failed. Exception: %s" %(str(e)))
490 raise
491 server_info = [ server.to_dict() for server in servers]
492 return server_info
493
494 def _nova_server_get(self, server_id):
495 """
496 Returns a dictionary of attributes associated with VM identified by service_id
497
498 Arguments:
499 server_id (string): UUID of the VM/server for which information is requested
500
501 Returns:
502 A dictionary object with attributes associated with VM identified by server_id
503 """
504 nvconn = self._get_nova_connection()
505 try:
506 server = nvconn.servers.get(server = server_id)
507 except Exception as e:
508 logger.info("OpenstackDriver: Get Server operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
509 raise
510 else:
511 return server.to_dict()
512
513 def server_get(self, server_id):
514 """
515 Returns a dictionary of attributes associated with VM identified by service_id
516
517 Arguments:
518 server_id (string): UUID of the VM/server for which information is requested
519
520 Returns:
521 A dictionary object with attributes associated with VM identified by server_id
522 """
523 return self._nova_server_get(server_id)
524
525 def server_create(self, **kwargs):
526 """
527 Creates a new VM/server instance
528
529 Arguments:
530 A dictionary of following key-value pairs
531 {
532 server_name(string) : Name of the VM/Server
533 flavor_id (string) : UUID of the flavor to be used for VM
534 image_id (string) : UUID of the image to be used VM/Server instance,
535 This could be None if volumes (with images) are being used
536 network_list(List) : A List of network_ids. A port will be created in these networks
537 port_list (List) : A List of port-ids. These ports will be added to VM.
538 metadata (dict) : A dictionary of arbitrary key-value pairs associated with VM/server
539 userdata (string) : A script which shall be executed during first boot of the VM
540 availability_zone (string) : A name of the availability zone where instance should be launched
541 scheduler_hints (string) : Openstack scheduler_hints to be passed to nova scheduler
542 }
543 Returns:
544 server_id (string): UUID of the VM/server created
545
546 """
547 nics = []
548 if 'network_list' in kwargs:
549 for network_id in kwargs['network_list']:
550 nics.append({'net-id': network_id})
551
552 if 'port_list' in kwargs:
553 for port_id in kwargs['port_list']:
554 nics.append({'port-id': port_id})
555
556 nvconn = self._get_nova_connection()
557
558
559 try:
560 server = nvconn.servers.create(kwargs['name'],
561 kwargs['image_id'],
562 kwargs['flavor_id'],
563 meta = kwargs['metadata'],
564 files = kwargs['files'],
565 reservation_id = None,
566 min_count = None,
567 max_count = None,
568 userdata = kwargs['userdata'],
569 security_groups = kwargs['security_groups'],
570 availability_zone = kwargs['availability_zone'],
571 block_device_mapping_v2 = kwargs['block_device_mapping_v2'],
572 nics = nics,
573 scheduler_hints = kwargs['scheduler_hints'],
574 config_drive = kwargs['config_drive'])
575 except Exception as e:
576 logger.info("OpenstackDriver: Create Server operation failed. Exception: %s" %(str(e)))
577 raise
578 return server.to_dict()['id']
579
580 def server_delete(self, server_id):
581 """
582 Deletes a server identified by server_id
583
584 Arguments:
585 server_id (string): UUID of the server to be deleted
586
587 Returns: None
588 """
589 nvconn = self._get_nova_connection()
590 try:
591 nvconn.servers.delete(server_id)
592 except Exception as e:
593 logger.error("OpenstackDriver: Delete server operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
594 raise
595
596 def server_start(self, server_id):
597 """
598 Starts a server identified by server_id
599
600 Arguments:
601 server_id (string): UUID of the server to be started
602
603 Returns: None
604 """
605 nvconn = self._get_nova_connection()
606 try:
607 nvconn.servers.start(server_id)
608 except Exception as e:
609 logger.error("OpenstackDriver: Start Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
610 raise
611
612 def server_stop(self, server_id):
613 """
614 Arguments:
615 server_id (string): UUID of the server to be stopped
616
617 Returns: None
618 """
619 nvconn = self._get_nova_connection()
620 try:
621 nvconn.servers.stop(server_id)
622 except Exception as e:
623 logger.error("OpenstackDriver: Stop Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
624 raise
625
626 def server_pause(self, server_id):
627 """
628 Arguments:
629 server_id (string): UUID of the server to be paused
630
631 Returns: None
632 """
633 nvconn = self._get_nova_connection()
634 try:
635 nvconn.servers.pause(server_id)
636 except Exception as e:
637 logger.error("OpenstackDriver: Pause Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
638 raise
639
640 def server_unpause(self, server_id):
641 """
642 Arguments:
643 server_id (string): UUID of the server to be unpaused
644
645 Returns: None
646 """
647 nvconn = self._get_nova_connection()
648 try:
649 nvconn.servers.unpause(server_id)
650 except Exception as e:
651 logger.error("OpenstackDriver: Resume Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
652 raise
653
654
655 def server_suspend(self, server_id):
656 """
657 Arguments:
658 server_id (string): UUID of the server to be suspended
659
660 Returns: None
661 """
662 nvconn = self._get_nova_connection()
663 try:
664 nvconn.servers.suspend(server_id)
665 except Exception as e:
666 logger.error("OpenstackDriver: Suspend Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
667
668
669 def server_resume(self, server_id):
670 """
671 Arguments:
672 server_id (string): UUID of the server to be resumed
673
674 Returns: None
675 """
676 nvconn = self._get_nova_connection()
677 try:
678 nvconn.servers.resume(server_id)
679 except Exception as e:
680 logger.error("OpenstackDriver: Resume Server operation failed for server_id : %s. Exception: %s" %(server_id, str(e)))
681 raise
682
683 def server_reboot(self, server_id, reboot_type):
684 """
685 Arguments:
686 server_id (string) : UUID of the server to be rebooted
687 reboot_type(string):
688 'SOFT': Soft Reboot
689 'HARD': Hard Reboot
690 Returns: None
691 """
692 nvconn = self._get_nova_connection()
693 try:
694 nvconn.servers.reboot(server_id, reboot_type)
695 except Exception as e:
696 logger.error("OpenstackDriver: Reboot Server operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
697 raise
698
699 def server_console(self, server_id, console_type = 'novnc'):
700 """
701 Arguments:
702 server_id (string) : UUID of the server to be rebooted
703 console_type(string):
704 'novnc',
705 'xvpvnc'
706 Returns:
707 A dictionary object response for console information
708 """
709 nvconn = self._get_nova_connection()
710 try:
711 console_info = nvconn.servers.get_vnc_console(server_id, console_type)
712 except Exception as e:
713 logger.error("OpenstackDriver: Server Get-Console operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
714 raise
715 return console_info
716
717 def server_rebuild(self, server_id, image_id):
718 """
719 Arguments:
720 server_id (string) : UUID of the server to be rebooted
721 image_id (string) : UUID of the image to use
722 Returns: None
723 """
724
725 nvconn = self._get_nova_connection()
726 try:
727 nvconn.servers.rebuild(server_id, image_id)
728 except Exception as e:
729 logger.error("OpenstackDriver: Rebuild Server operation failed for server_id: %s. Exception: %s" %(server_id, str(e)))
730 raise
731
732
733 def server_add_port(self, server_id, port_id):
734 """
735 Arguments:
736 server_id (string): UUID of the server
737 port_id (string): UUID of the port to be attached
738
739 Returns: None
740 """
741 nvconn = self._get_nova_connection()
742 try:
743 nvconn.servers.interface_attach(server_id,
744 port_id,
745 net_id = None,
746 fixed_ip = None)
747 except Exception as e:
748 logger.error("OpenstackDriver: Server Port Add operation failed for server_id : %s, port_id : %s. Exception: %s" %(server_id, port_id, str(e)))
749 raise
750
751 def server_delete_port(self, server_id, port_id):
752 """
753 Arguments:
754 server_id (string): UUID of the server
755 port_id (string): UUID of the port to be deleted
756 Returns: None
757
758 """
759 nvconn = self._get_nova_connection()
760 try:
761 nvconn.servers.interface_detach(server_id, port_id)
762 except Exception as e:
763 logger.error("OpenstackDriver: Server Port Delete operation failed for server_id : %s, port_id : %s. Exception: %s" %(server_id, port_id, str(e)))
764 raise
765
766 def floating_ip_list(self):
767 """
768 Arguments:
769 None
770 Returns:
771 List of objects of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
772 """
773 nvconn = self._get_nova_connection()
774 try:
775 ip_list = nvconn.floating_ips.list()
776 except Exception as e:
777 logger.error("OpenstackDriver: Floating IP List operation failed. Exception: %s" %str(e))
778 raise
779
780 return ip_list
781
782 def floating_ip_create(self, pool):
783 """
784 Arguments:
785 pool (string): Name of the pool (optional)
786 Returns:
787 An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
788 """
789 nvconn = self._get_nova_connection()
790 try:
791 floating_ip = nvconn.floating_ips.create(pool)
792 except Exception as e:
793 logger.error("OpenstackDriver: Floating IP Create operation failed. Exception: %s" %str(e))
794 raise
795
796 return floating_ip
797
798 def floating_ip_delete(self, floating_ip):
799 """
800 Arguments:
801 floating_ip: An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
802 Returns:
803 None
804 """
805 nvconn = self._get_nova_connection()
806 try:
807 floating_ip = nvconn.floating_ips.delete(floating_ip)
808 except Exception as e:
809 logger.error("OpenstackDriver: Floating IP Delete operation failed. Exception: %s" %str(e))
810 raise
811
812 def floating_ip_assign(self, server_id, floating_ip, fixed_ip):
813 """
814 Arguments:
815 server_id (string) : UUID of the server
816 floating_ip (string): IP address string for floating-ip
817 fixed_ip (string) : IP address string for the fixed-ip with which floating ip will be associated
818 Returns:
819 None
820 """
821 nvconn = self._get_nova_connection()
822 try:
823 nvconn.servers.add_floating_ip(server_id, floating_ip, fixed_ip)
824 except Exception as e:
825 logger.error("OpenstackDriver: Assign Floating IP operation failed. Exception: %s" %str(e))
826 raise
827
828 def floating_ip_release(self, server_id, floating_ip):
829 """
830 Arguments:
831 server_id (string) : UUID of the server
832 floating_ip (string): IP address string for floating-ip
833 Returns:
834 None
835 """
836 nvconn = self._get_nova_connection()
837 try:
838 nvconn.servers.remove_floating_ip(server_id, floating_ip)
839 except Exception as e:
840 logger.error("OpenstackDriver: Release Floating IP operation failed. Exception: %s" %str(e))
841 raise
842
843 def volume_list(self, server_id):
844 """
845 List of volumes attached to the server
846
847 Arguments:
848 None
849 Returns:
850 List of dictionary objects where dictionary is representation of class (novaclient.v2.volumes.Volume)
851 """
852 nvconn = self._get_nova_connection()
853 try:
854 volumes = nvconn.volumes.get_server_volumes(server_id=server_id)
855 except Exception as e:
856 logger.error("OpenstackDriver: Get volume information failed. Exception: %s" %str(e))
857 raise
858
859 volume_info = [v.to_dict() for v in volumes]
860 return volume_info
861
862
863 def group_list(self):
864 """
865 List of Server Affinity and Anti-Affinity Groups
866
867 Arguments:
868 None
869 Returns:
870 List of dictionary objects where dictionary is representation of class (novaclient.v2.server_groups.ServerGroup)
871 """
872 nvconn = self._get_nova_connection()
873 try:
874 group_list = nvconn.server_groups.list()
875 except Exception as e:
876 logger.error("OpenstackDriver: Server Group List operation failed. Exception: %s" %str(e))
877 raise
878
879 group_info = [ group.to_dict() for group in group_list ]
880 return group_info
881
882
883
884 class NovaDriverV2(NovaDriver):
885 """
886 Driver class for novaclient V2 APIs
887 """
888 def __init__(self, ks_drv):
889 """
890 Constructor for NovaDriver
891 Arguments: KeystoneDriver class object
892 """
893 super(NovaDriverV2, self).__init__(ks_drv, 'compute', '2.0')
894
895 class NovaDriverV21(NovaDriver):
896 """
897 Driver class for novaclient V2 APIs
898 """
899 def __init__(self, ks_drv):
900 """
901 Constructor for NovaDriver
902 Arguments: KeystoneDriver class object
903 """
904 super(NovaDriverV21, self).__init__(ks_drv, 'computev21', '2.1')
905
906 class GlanceDriver(object):
907 """
908 Driver for openstack glance-client
909 """
910 def __init__(self, ks_drv, service_name, version):
911 """
912 Constructor for GlanceDriver
913 Arguments: KeystoneDriver class object
914 """
915 self.ks_drv = ks_drv
916 self._service_name = service_name
917 self._version = version
918
919 def _get_glance_credentials(self):
920 """
921 Returns a dictionary of kwargs required to instantiate python-glanceclient class
922
923 Arguments: None
924
925 Returns:
926 A dictionary object of arguments
927 """
928 creds = {}
929 creds['version'] = self._version
930 creds['endpoint'] = self.ks_drv.get_service_endpoint(self._service_name, 'publicURL')
931 creds['token'] = self.ks_drv.get_auth_token()
932 creds['insecure'] = self.ks_drv.get_security_mode()
933 return creds
934
935 def _get_glance_connection(self):
936 """
937 Returns a object of class python-glanceclient
938 """
939 if not hasattr(self, '_glance_connection'):
940 self._glance_connection = glclient.Client(**self._get_glance_credentials())
941 else:
942 # Reinitialize if auth_token is no longer valid
943 if not self.ks_drv.is_auth_token_valid():
944 self._glance_connection = glclient.Client(**self._get_glance_credentials())
945 return self._glance_connection
946
947 def image_list(self):
948 """
949 Returns list of dictionaries. Each dictionary contains attributes associated with
950 image
951
952 Arguments: None
953
954 Returns: List of dictionaries.
955 """
956 glconn = self._get_glance_connection()
957 images = []
958 try:
959 image_info = glconn.images.list()
960 except Exception as e:
961 logger.error("OpenstackDriver: List Image operation failed. Exception: %s" %(str(e)))
962 raise
963 images = [ img for img in image_info ]
964 return images
965
966 def image_create(self, **kwargs):
967 """
968 Creates an image
969 Arguments:
970 A dictionary of kwargs with following keys
971 {
972 'name'(string) : Name of the image
973 'location'(string) : URL (http://....) where image is located
974 'disk_format'(string) : Disk format
975 Possible values are 'ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso'
976 'container_format'(string): Container format
977 Possible values are 'ami', 'ari', 'aki', 'bare', 'ovf'
978 'tags' : A list of user tags
979 'checksum' : The image md5 checksum
980 }
981 Returns:
982 image_id (string) : UUID of the image
983
984 """
985 glconn = self._get_glance_connection()
986 try:
987 image = glconn.images.create(**kwargs)
988 except Exception as e:
989 logger.error("OpenstackDriver: Create Image operation failed. Exception: %s" %(str(e)))
990 raise
991
992 return image.id
993
994 def image_upload(self, image_id, fd):
995 """
996 Upload the image
997
998 Arguments:
999 image_id: UUID of the image
1000 fd : File descriptor for the image file
1001 Returns: None
1002 """
1003 glconn = self._get_glance_connection()
1004 try:
1005 glconn.images.upload(image_id, fd)
1006 except Exception as e:
1007 logger.error("OpenstackDriver: Image upload operation failed. Exception: %s" %(str(e)))
1008 raise
1009
1010 def image_add_location(self, image_id, location, metadata):
1011 """
1012 Add image URL location
1013
1014 Arguments:
1015 image_id : UUID of the image
1016 location : http URL for the image
1017
1018 Returns: None
1019 """
1020 glconn = self._get_glance_connection()
1021 try:
1022 image = glconn.images.add_location(image_id, location, metadata)
1023 except Exception as e:
1024 logger.error("OpenstackDriver: Image location add operation failed. Exception: %s" %(str(e)))
1025 raise
1026
1027 def image_update(self):
1028 pass
1029
1030 def image_delete(self, image_id):
1031 """
1032 Delete an image
1033
1034 Arguments:
1035 image_id: UUID of the image
1036
1037 Returns: None
1038
1039 """
1040 assert image_id == self._image_get(image_id)['id']
1041 glconn = self._get_glance_connection()
1042 try:
1043 glconn.images.delete(image_id)
1044 except Exception as e:
1045 logger.error("OpenstackDriver: Delete Image operation failed for image_id : %s. Exception: %s" %(image_id, str(e)))
1046 raise
1047
1048
1049 def _image_get(self, image_id):
1050 """
1051 Returns a dictionary object of VM image attributes
1052
1053 Arguments:
1054 image_id (string): UUID of the image
1055
1056 Returns:
1057 A dictionary of the image attributes
1058 """
1059 glconn = self._get_glance_connection()
1060 try:
1061 image = glconn.images.get(image_id)
1062 except GlanceException.HTTPBadRequest:
1063 # RIFT-14241: The get image request occasionally returns the below message. Retry in case of bad request exception.
1064 # Error code 400.: Message: Bad request syntax ('0').: Error code explanation: 400 = Bad request syntax or unsupported method. (HTTP 400)
1065 logger.warning("OpenstackDriver: Got bad request response during get_image request. Retrying.")
1066 image = glconn.images.get(image_id)
1067 except Exception as e:
1068 logger.error("OpenstackDriver: Get Image operation failed for image_id : %s. Exception: %s" %(image_id, str(e)))
1069 raise
1070
1071 return image
1072
1073 def image_get(self, image_id):
1074 """
1075 Returns a dictionary object of VM image attributes
1076
1077 Arguments:
1078 image_id (string): UUID of the image
1079
1080 Returns:
1081 A dictionary of the image attributes
1082 """
1083 return self._image_get(image_id)
1084
1085 class GlanceDriverV2(GlanceDriver):
1086 """
1087 Driver for openstack glance-client V2
1088 """
1089 def __init__(self, ks_drv):
1090 super(GlanceDriverV2, self).__init__(ks_drv, 'image', 2)
1091
1092 class NeutronDriver(object):
1093 """
1094 Driver for openstack neutron neutron-client
1095 """
1096 def __init__(self, ks_drv, service_name, version):
1097 """
1098 Constructor for NeutronDriver
1099 Arguments: KeystoneDriver class object
1100 """
1101 self.ks_drv = ks_drv
1102 self._service_name = service_name
1103 self._version = version
1104
1105 def _get_neutron_credentials(self):
1106 """
1107 Returns a dictionary of kwargs required to instantiate python-neutronclient class
1108
1109 Returns:
1110 Dictionary of kwargs
1111 """
1112 creds = {}
1113 creds['api_version'] = self._version
1114 creds['endpoint_url'] = self.ks_drv.get_service_endpoint(self._service_name, 'publicURL')
1115 creds['token'] = self.ks_drv.get_auth_token()
1116 creds['tenant_name'] = self.ks_drv.get_tenant_name()
1117 creds['insecure'] = self.ks_drv.get_security_mode()
1118 return creds
1119
1120 def _get_neutron_connection(self):
1121 """
1122 Returns an object of class python-neutronclient
1123 """
1124 if not hasattr(self, '_neutron_connection'):
1125 self._neutron_connection = ntclient.Client(**self._get_neutron_credentials())
1126 else:
1127 # Reinitialize if auth_token is no longer valid
1128 if not self.ks_drv.is_auth_token_valid():
1129 self._neutron_connection = ntclient.Client(**self._get_neutron_credentials())
1130 return self._neutron_connection
1131
1132 def network_list(self):
1133 """
1134 Returns list of dictionaries. Each dictionary contains the attributes for a network
1135 under project
1136
1137 Arguments: None
1138
1139 Returns:
1140 A list of dictionaries
1141 """
1142 networks = []
1143 ntconn = self._get_neutron_connection()
1144 try:
1145 networks = ntconn.list_networks()
1146 except Exception as e:
1147 logger.error("OpenstackDriver: List Network operation failed. Exception: %s" %(str(e)))
1148 raise
1149 return networks['networks']
1150
1151 def network_create(self, **kwargs):
1152 """
1153 Creates a new network for the project
1154
1155 Arguments:
1156 A dictionary with following key-values
1157 {
1158 name (string) : Name of the network
1159 admin_state_up(Boolean) : True/False (Defaults: True)
1160 external_router(Boolean) : Connectivity with external router. True/False (Defaults: False)
1161 shared(Boolean) : Shared among tenants. True/False (Defaults: False)
1162 physical_network(string) : The physical network where this network object is implemented (optional).
1163 network_type : The type of physical network that maps to this network resource (optional).
1164 Possible values are: 'flat', 'vlan', 'vxlan', 'gre'
1165 segmentation_id : An isolated segment on the physical network. The network_type attribute
1166 defines the segmentation model. For example, if the network_type value
1167 is vlan, this ID is a vlan identifier. If the network_type value is gre,
1168 this ID is a gre key.
1169 }
1170 """
1171 params = {'network':
1172 {'name' : kwargs['name'],
1173 'admin_state_up' : kwargs['admin_state_up'],
1174 'tenant_id' : self.ks_drv.get_tenant_id(),
1175 'shared' : kwargs['shared'],
1176 #'port_security_enabled': port_security_enabled,
1177 'router:external' : kwargs['external_router']}}
1178
1179 if 'physical_network' in kwargs:
1180 params['network']['provider:physical_network'] = kwargs['physical_network']
1181 if 'network_type' in kwargs:
1182 params['network']['provider:network_type'] = kwargs['network_type']
1183 if 'segmentation_id' in kwargs:
1184 params['network']['provider:segmentation_id'] = kwargs['segmentation_id']
1185
1186 ntconn = self._get_neutron_connection()
1187 try:
1188 logger.debug("Calling neutron create_network() with params: %s", str(params))
1189 net = ntconn.create_network(params)
1190 except Exception as e:
1191 logger.error("OpenstackDriver: Create Network operation failed. Exception: %s" %(str(e)))
1192 raise
1193 logger.debug("Got create_network response from neutron connection: %s", str(net))
1194 network_id = net['network']['id']
1195 if not network_id:
1196 raise Exception("Empty network id returned from create_network. (params: %s)" % str(params))
1197
1198 return network_id
1199
1200 def network_delete(self, network_id):
1201 """
1202 Deletes a network identified by network_id
1203
1204 Arguments:
1205 network_id (string): UUID of the network
1206
1207 Returns: None
1208 """
1209 assert network_id == self._network_get(network_id)['id']
1210 ntconn = self._get_neutron_connection()
1211 try:
1212 ntconn.delete_network(network_id)
1213 except Exception as e:
1214 logger.error("OpenstackDriver: Delete Network operation failed. Exception: %s" %(str(e)))
1215 raise
1216
1217 def _network_get(self, network_id):
1218 """
1219 Returns a dictionary object describing the attributes of the network
1220
1221 Arguments:
1222 network_id (string): UUID of the network
1223
1224 Returns:
1225 A dictionary object of the network attributes
1226 """
1227 ntconn = self._get_neutron_connection()
1228 network = ntconn.list_networks(id = network_id)['networks']
1229 if not network:
1230 raise NeutronException.NotFound("Network with id %s not found"%(network_id))
1231
1232 return network[0]
1233
1234 def network_get(self, network_id):
1235 """
1236 Returns a dictionary object describing the attributes of the network
1237
1238 Arguments:
1239 network_id (string): UUID of the network
1240
1241 Returns:
1242 A dictionary object of the network attributes
1243 """
1244 return self._network_get(network_id)
1245
1246 def subnet_create(self, **kwargs):
1247 """
1248 Creates a subnet on the network
1249
1250 Arguments:
1251 A dictionary with following key value pairs
1252 {
1253 network_id(string) : UUID of the network where subnet needs to be created
1254 subnet_cidr(string) : IPv4 address prefix (e.g. '1.1.1.0/24') for the subnet
1255 ip_version (integer): 4 for IPv4 and 6 for IPv6
1256
1257 }
1258
1259 Returns:
1260 subnet_id (string): UUID of the created subnet
1261 """
1262 params = {}
1263 params['network_id'] = kwargs['network_id']
1264 params['ip_version'] = kwargs['ip_version']
1265
1266 # if params['ip_version'] == 6:
1267 # assert 0, "IPv6 is not supported"
1268
1269 if 'subnetpool_id' in kwargs:
1270 params['subnetpool_id'] = kwargs['subnetpool_id']
1271 else:
1272 params['cidr'] = kwargs['cidr']
1273
1274 if 'gateway_ip' in kwargs:
1275 params['gateway_ip'] = kwargs['gateway_ip']
1276 else:
1277 params['gateway_ip'] = None
1278
1279 if 'dhcp_params' in kwargs:
1280 params['enable_dhcp'] = kwargs['dhcp_params']['enable_dhcp']
1281 if 'start_address' in kwargs['dhcp_params'] and 'count' in kwargs['dhcp_params']:
1282 end_address = (ipaddress.IPv4Address(kwargs['dhcp_params']['start_address']) + kwargs['dhcp_params']['count']).compressed
1283 params['allocation_pools'] = [ {'start': kwargs['dhcp_params']['start_address'] ,
1284 'end' : end_address} ]
1285
1286 if 'dns_server' in kwargs:
1287 params['dns_nameservers'] = []
1288 for server in kwargs['dns_server']:
1289 params['dns_nameservers'].append(server)
1290
1291 ntconn = self._get_neutron_connection()
1292 try:
1293 subnet = ntconn.create_subnet({'subnets': [params]})
1294 except Exception as e:
1295 logger.error("OpenstackDriver: Create Subnet operation failed. Exception: %s" %(str(e)))
1296 raise
1297
1298 return subnet['subnets'][0]['id']
1299
1300 def subnet_list(self):
1301 """
1302 Returns a list of dictionaries. Each dictionary contains attributes describing the subnet
1303
1304 Arguments: None
1305
1306 Returns:
1307 A dictionary of the objects of subnet attributes
1308 """
1309 ntconn = self._get_neutron_connection()
1310 try:
1311 subnets = ntconn.list_subnets()['subnets']
1312 except Exception as e:
1313 logger.error("OpenstackDriver: List Subnet operation failed. Exception: %s" %(str(e)))
1314 raise
1315 return subnets
1316
1317 def _subnet_get(self, subnet_id):
1318 """
1319 Returns a dictionary object describing the attributes of a subnet.
1320
1321 Arguments:
1322 subnet_id (string): UUID of the subnet
1323
1324 Returns:
1325 A dictionary object of the subnet attributes
1326 """
1327 ntconn = self._get_neutron_connection()
1328 subnets = ntconn.list_subnets(id=subnet_id)
1329 if not subnets['subnets']:
1330 logger.error("OpenstackDriver: Get subnet operation failed for subnet_id: %s" %(subnet_id))
1331 #raise NeutronException.NotFound("Could not find subnet_id %s" %(subnet_id))
1332 return {'cidr': ''}
1333 else:
1334 return subnets['subnets'][0]
1335
1336 def subnet_get(self, subnet_id):
1337 """
1338 Returns a dictionary object describing the attributes of a subnet.
1339
1340 Arguments:
1341 subnet_id (string): UUID of the subnet
1342
1343 Returns:
1344 A dictionary object of the subnet attributes
1345 """
1346 return self._subnet_get(subnet_id)
1347
1348 def subnet_delete(self, subnet_id):
1349 """
1350 Deletes a subnet identified by subnet_id
1351
1352 Arguments:
1353 subnet_id (string): UUID of the subnet to be deleted
1354
1355 Returns: None
1356 """
1357 ntconn = self._get_neutron_connection()
1358 assert subnet_id == self._subnet_get(self,subnet_id)
1359 try:
1360 ntconn.delete_subnet(subnet_id)
1361 except Exception as e:
1362 logger.error("OpenstackDriver: Delete Subnet operation failed for subnet_id : %s. Exception: %s" %(subnet_id, str(e)))
1363 raise
1364
1365 def port_list(self, **kwargs):
1366 """
1367 Returns a list of dictionaries. Each dictionary contains attributes describing the port
1368
1369 Arguments:
1370 kwargs (dictionary): A dictionary for filters for port_list operation
1371
1372 Returns:
1373 A dictionary of the objects of port attributes
1374
1375 """
1376 ports = []
1377 ntconn = self._get_neutron_connection()
1378
1379 kwargs['tenant_id'] = self.ks_drv.get_tenant_id()
1380
1381 try:
1382 ports = ntconn.list_ports(**kwargs)
1383 except Exception as e:
1384 logger.info("OpenstackDriver: List Port operation failed. Exception: %s" %(str(e)))
1385 raise
1386 return ports['ports']
1387
1388 def port_create(self, **kwargs):
1389 """
1390 Create a port in network
1391
1392 Arguments:
1393 A dictionary of following
1394 {
1395 name (string) : Name of the port
1396 network_id(string) : UUID of the network_id identifying the network to which port belongs
1397 subnet_id(string) : UUID of the subnet_id from which IP-address will be assigned to port
1398 vnic_type(string) : Possible values are "normal", "direct", "macvtap"
1399 }
1400 Returns:
1401 port_id (string) : UUID of the port
1402 """
1403 params = {
1404 "port": {
1405 "admin_state_up" : kwargs['admin_state_up'],
1406 "name" : kwargs['name'],
1407 "network_id" : kwargs['network_id'],
1408 "fixed_ips" : [ {"subnet_id": kwargs['subnet_id']}],
1409 "binding:vnic_type" : kwargs['port_type']}}
1410
1411 ntconn = self._get_neutron_connection()
1412 try:
1413 port = ntconn.create_port(params)
1414 except Exception as e:
1415 logger.error("OpenstackDriver: Port Create operation failed. Exception: %s" %(str(e)))
1416 raise
1417 return port['port']['id']
1418
1419 def _port_get(self, port_id):
1420 """
1421 Returns a dictionary object describing the attributes of the port
1422
1423 Arguments:
1424 port_id (string): UUID of the port
1425
1426 Returns:
1427 A dictionary object of the port attributes
1428 """
1429 ntconn = self._get_neutron_connection()
1430 port = ntconn.list_ports(id=port_id)['ports']
1431 if not port:
1432 raise NeutronException.NotFound("Could not find port_id %s" %(port_id))
1433 return port[0]
1434
1435 def port_get(self, port_id):
1436 """
1437 Returns a dictionary object describing the attributes of the port
1438
1439 Arguments:
1440 port_id (string): UUID of the port
1441
1442 Returns:
1443 A dictionary object of the port attributes
1444 """
1445 return self._port_get(port_id)
1446
1447 def port_delete(self, port_id):
1448 """
1449 Deletes a port identified by port_id
1450
1451 Arguments:
1452 port_id (string) : UUID of the port
1453
1454 Returns: None
1455 """
1456 assert port_id == self._port_get(port_id)['id']
1457 ntconn = self._get_neutron_connection()
1458 try:
1459 ntconn.delete_port(port_id)
1460 except Exception as e:
1461 logger.error("Port Delete operation failed for port_id : %s. Exception: %s" %(port_id, str(e)))
1462 raise
1463
1464 def security_group_list(self):
1465 """
1466 Returns a list of dictionaries. Each dictionary contains attributes describing the security group
1467
1468 Arguments:
1469 None
1470
1471 Returns:
1472 A dictionary of the objects of security group attributes
1473 """
1474 ntconn = self._get_neutron_connection()
1475 try:
1476 group_list = ntconn.list_security_groups(tenant_id=self.ks_drv.get_tenant_id())
1477 except Exception as e:
1478 logger.error("List Security group operation, Exception: %s" %(str(e)))
1479 raise
1480
1481 if 'security_groups' in group_list:
1482 return group_list['security_groups']
1483 else:
1484 return []
1485
1486 def subnetpool_list(self, **kwargs):
1487 """
1488 Returns a list of dictionaries. Each dictionary contains attributes describing a subnet prefix pool
1489
1490 Arguments:
1491 None
1492
1493 Returns:
1494 A dictionary of the objects of subnet prefix pool
1495 """
1496 ntconn = self._get_neutron_connection()
1497 try:
1498 pool_list = ntconn.list_subnetpools(**kwargs)
1499 except Exception as e:
1500 logger.error("List SubnetPool operation, Exception: %s" %(str(e)))
1501 raise
1502
1503 if 'subnetpools' in pool_list:
1504 return pool_list['subnetpools']
1505 else:
1506 return []
1507
1508 class NeutronDriverV2(NeutronDriver):
1509 """
1510 Driver for openstack neutron neutron-client v2
1511 """
1512 def __init__(self, ks_drv):
1513 """
1514 Constructor for NeutronDriver
1515 Arguments: KeystoneDriver class object
1516 """
1517 super(NeutronDriverV2, self).__init__(ks_drv, 'network', '2.0')
1518
1519
1520
1521 class CeilometerDriver(object):
1522 """
1523 Driver for openstack ceilometer client
1524 """
1525
1526 def __init__(self, ks_drv, service_name, version):
1527 """
1528 Constructor for CeilometerDriver
1529 Arguments: KeystoneDriver class object
1530 """
1531 self.ks_drv = ks_drv
1532 self._service_name = service_name
1533 self._version = version
1534 self._client = None
1535
1536 @property
1537 def version(self):
1538 """The version of the ceilometer client used by the driver"""
1539 return self._version
1540
1541 @property
1542 def client(self):
1543 """The instance of ceilometer client used by the driver"""
1544 if self._client is None or not self.ks_drv.is_auth_token_valid():
1545 self._client = ceilo_client.Client(**self.credentials)
1546
1547 return self._client
1548
1549 @property
1550 def auth_token(self):
1551 """The authorization token for the ceilometer client"""
1552 try:
1553 return self.ks_drv.get_auth_token()
1554 except KeystoneExceptions.EndpointNotFound as e:
1555 logger.error("OpenstackDriver: unable to get authorization token for ceilometer. Exception: %s" %(str(e)))
1556 raise
1557
1558 @property
1559 def security_mode(self):
1560 """The security mode for the ceilometer client"""
1561 try:
1562 return self.ks_drv.get_security_mode()
1563 except KeystoneExceptions.EndpointNotFound as e:
1564 logger.error("OpenstackDriver: unable to get security mode for ceilometer. Exception: %s" %(str(e)))
1565 raise
1566
1567 @property
1568 def endpoint(self):
1569 """The service endpoint for the ceilometer client"""
1570 try:
1571 return self.ks_drv.get_service_endpoint(self._service_name, "publicURL")
1572 except KeystoneExceptions.EndpointNotFound as e:
1573 logger.error("OpenstackDriver: unable to get endpoint for ceilometer. Exception: %s" %(str(e)))
1574 raise
1575
1576 @property
1577 def credentials(self):
1578 """A dictionary of credentials for the ceilometer client"""
1579 return dict(
1580 version=self.version,
1581 endpoint=self.endpoint,
1582 token=self.auth_token,
1583 insecure=self.security_mode,
1584 )
1585
1586 @property
1587 def meters(self):
1588 """A list of the available meters"""
1589 try:
1590 return self.client.meters.list()
1591 except Exception as e:
1592 logger.error("OpenstackDriver: List meters operation failed. Exception: %s" %(str(e)))
1593 raise
1594
1595 @property
1596 def alarms(self):
1597 """The ceilometer client alarms manager"""
1598 return self.client.alarms
1599
1600 def query_samples(self, vim_instance_id, counter_name, limit=1):
1601 """Returns a list of samples
1602
1603 Arguments:
1604 vim_instance_id - the ID of the VIM that the samples are from
1605 counter_name - the counter that the samples will come from
1606 limit - a limit on the number of samples to return
1607 (default: 1)
1608
1609 Returns:
1610 A list of samples
1611
1612 """
1613 try:
1614 filter = json.dumps({
1615 "and": [
1616 {"=": {"resource": vim_instance_id}},
1617 {"=": {"counter_name": counter_name}}
1618 ]
1619 })
1620 result = self.client.query_samples.query(filter=filter, limit=limit)
1621 return result[-limit:]
1622
1623 except Exception as e:
1624 logger.exception(e)
1625
1626 return []
1627
1628
1629 class CeilometerDriverV2(CeilometerDriver):
1630 """
1631 Driver for openstack ceilometer ceilometer-client
1632 """
1633 def __init__(self, ks_drv):
1634 """
1635 Constructor for CeilometerDriver
1636 Arguments: CeilometerDriver class object
1637 """
1638 super(CeilometerDriverV2, self).__init__(ks_drv, 'metering', '2')
1639
1640 class OpenstackDriver(object):
1641 """
1642 Driver for openstack nova, neutron, glance, keystone, swift, cinder services
1643 """
1644 def __init__(self, username, password, auth_url, tenant_name, mgmt_network = None, cert_validate = False):
1645 """
1646 OpenstackDriver Driver constructor
1647 Arguments:
1648 username (string) : Username for project/tenant.
1649 password (string) : Password
1650 auth_url (string) : Keystone Authentication URL.
1651 tenant_name (string) : Openstack project name
1652 mgmt_network(string, optional) : Management network name. Each VM created with this cloud-account will
1653 have a default interface into management network.
1654 cert_validate (boolean, optional) : In case of SSL/TLS connection if certificate validation is required or not.
1655
1656 """
1657 insecure = not cert_validate
1658 if auth_url.find('/v3') != -1:
1659 self.ks_drv = KeystoneDriverV3(username, password, auth_url, tenant_name, insecure)
1660 self.glance_drv = GlanceDriverV2(self.ks_drv)
1661 self.nova_drv = NovaDriverV21(self.ks_drv)
1662 self.neutron_drv = NeutronDriverV2(self.ks_drv)
1663 self.ceilo_drv = CeilometerDriverV2(self.ks_drv)
1664 self.cinder_drv = CinderDriverV2(self.ks_drv)
1665 elif auth_url.find('/v2') != -1:
1666 self.ks_drv = KeystoneDriverV2(username, password, auth_url, tenant_name, insecure)
1667 self.glance_drv = GlanceDriverV2(self.ks_drv)
1668 self.nova_drv = NovaDriverV2(self.ks_drv)
1669 self.neutron_drv = NeutronDriverV2(self.ks_drv)
1670 self.ceilo_drv = CeilometerDriverV2(self.ks_drv)
1671 self.cinder_drv = CinderDriverV2(self.ks_drv)
1672 else:
1673 logger.error("Could not identity the version information for openstack service endpoints. Auth_URL should contain \"/v2\" or \"/v3\" string in it")
1674 raise NotImplementedError("Auth URL is wrong or invalid. Only Keystone v2 & v3 supported")
1675
1676 self._mgmt_network_id = None
1677 if mgmt_network != None:
1678 self._mgmt_network = mgmt_network
1679
1680 networks = []
1681 try:
1682 ntconn = self.neutron_drv._get_neutron_connection()
1683 networks = ntconn.list_networks()
1684 except (KeystoneExceptions.Unauthorized, KeystoneExceptions.AuthorizationFailure) as e:
1685 raise
1686 except Exception as e:
1687 logger.error("OpenstackDriver: List Network operation failed. Exception: %s" %(str(e)))
1688 raise
1689
1690 network_list = [ network for network in networks['networks'] if network['name'] == mgmt_network ]
1691
1692 if not network_list:
1693 raise NeutronException.NotFound("Could not find network %s" %(mgmt_network))
1694 self._mgmt_network_id = network_list[0]['id']
1695
1696 def validate_account_creds(self):
1697 try:
1698 ksconn = self.ks_drv._get_keystone_connection()
1699 except KeystoneExceptions.AuthorizationFailure as e:
1700 logger.error("OpenstackDriver: Unable to authenticate or validate the existing credentials. Exception: %s" %(str(e)))
1701 raise ValidationError("Invalid Credentials: "+ str(e))
1702 except Exception as e:
1703 logger.error("OpenstackDriver: Could not connect to Openstack. Exception: %s" %(str(e)))
1704 raise ValidationError("Connection Error: "+ str(e))
1705
1706 def get_mgmt_network_id(self):
1707 return self._mgmt_network_id
1708
1709 def glance_image_create(self, **kwargs):
1710 if not 'disk_format' in kwargs:
1711 kwargs['disk_format'] = 'qcow2'
1712 if not 'container_format' in kwargs:
1713 kwargs['container_format'] = 'bare'
1714 if not 'min_disk' in kwargs:
1715 kwargs['min_disk'] = 0
1716 if not 'min_ram' in kwargs:
1717 kwargs['min_ram'] = 0
1718 return self.glance_drv.image_create(**kwargs)
1719
1720 def glance_image_upload(self, image_id, fd):
1721 self.glance_drv.image_upload(image_id, fd)
1722
1723 def glance_image_add_location(self, image_id, location):
1724 self.glance_drv.image_add_location(image_id, location)
1725
1726 def glance_image_delete(self, image_id):
1727 self.glance_drv.image_delete(image_id)
1728
1729 def glance_image_list(self):
1730 return self.glance_drv.image_list()
1731
1732 def glance_image_get(self, image_id):
1733 return self.glance_drv.image_get(image_id)
1734
1735
1736 def nova_flavor_list(self):
1737 return self.nova_drv.flavor_list()
1738
1739 def nova_flavor_create(self, name, ram, vcpus, disk, epa_specs):
1740 extra_specs = epa_specs if epa_specs else {}
1741 return self.nova_drv.flavor_create(name,
1742 ram = ram,
1743 vcpu = vcpus,
1744 disk = disk,
1745 extra_specs = extra_specs)
1746
1747 def nova_flavor_delete(self, flavor_id):
1748 self.nova_drv.flavor_delete(flavor_id)
1749
1750 def nova_flavor_get(self, flavor_id):
1751 return self.nova_drv.flavor_get(flavor_id)
1752
1753 def nova_server_create(self, **kwargs):
1754 def _verify_image(image_id):
1755 image = self.glance_drv.image_get(image_id)
1756 if image['status'] != 'active':
1757 raise GlanceException.NotFound("Image with image_id: %s not found in active state. Current State: %s" %(image['id'], image['status']))
1758
1759 assert kwargs['flavor_id'] == self.nova_drv.flavor_get(kwargs['flavor_id'])['id']
1760
1761 if kwargs['block_device_mapping_v2'] is not None:
1762 for block_map in kwargs['block_device_mapping_v2']:
1763 if 'uuid' in block_map:
1764 _verify_image(block_map['uuid'])
1765 else:
1766 _verify_image(kwargs['image_id'])
1767
1768 # if 'network_list' in kwargs:
1769 # kwargs['network_list'].append(self._mgmt_network_id)
1770 # else:
1771 # kwargs['network_list'] = [self._mgmt_network_id]
1772
1773 if 'security_groups' not in kwargs:
1774 nvconn = self.nova_drv._get_nova_connection()
1775 sec_groups = nvconn.security_groups.list()
1776 if sec_groups:
1777 ## Should we add VM in all availability security_groups ???
1778 kwargs['security_groups'] = [x.name for x in sec_groups]
1779 else:
1780 kwargs['security_groups'] = None
1781
1782 return self.nova_drv.server_create(**kwargs)
1783
1784 def nova_server_add_port(self, server_id, port_id):
1785 self.nova_drv.server_add_port(server_id, port_id)
1786
1787 def nova_server_delete_port(self, server_id, port_id):
1788 self.nova_drv.server_delete_port(server_id, port_id)
1789
1790 def nova_server_start(self, server_id):
1791 self.nova_drv.server_start(server_id)
1792
1793 def nova_server_stop(self, server_id):
1794 self.nova_drv.server_stop(server_id)
1795
1796 def nova_server_delete(self, server_id):
1797 self.nova_drv.server_delete(server_id)
1798
1799 def nova_server_reboot(self, server_id):
1800 self.nova_drv.server_reboot(server_id, reboot_type='HARD')
1801
1802 def nova_server_rebuild(self, server_id, image_id):
1803 self.nova_drv.server_rebuild(server_id, image_id)
1804
1805 def nova_floating_ip_list(self):
1806 return self.nova_drv.floating_ip_list()
1807
1808 def nova_floating_ip_create(self, pool = None):
1809 return self.nova_drv.floating_ip_create(pool)
1810
1811 def nova_floating_ip_delete(self, floating_ip):
1812 self.nova_drv.floating_ip_delete(floating_ip)
1813
1814 def nova_floating_ip_assign(self, server_id, floating_ip, fixed_ip):
1815 self.nova_drv.floating_ip_assign(server_id, floating_ip, fixed_ip)
1816
1817 def nova_floating_ip_release(self, server_id, floating_ip):
1818 self.nova_drv.floating_ip_release(server_id, floating_ip)
1819
1820 def nova_server_list(self):
1821 return self.nova_drv.server_list()
1822
1823 def nova_server_get(self, server_id):
1824 return self.nova_drv.server_get(server_id)
1825
1826 def nova_server_console(self, server_id):
1827 return self.nova_drv.server_console(server_id)
1828
1829 def nova_server_group_list(self):
1830 return self.nova_drv.group_list()
1831
1832 def nova_volume_list(self, server_id):
1833 return self.nova_drv.volume_list(server_id)
1834
1835 def neutron_network_list(self):
1836 return self.neutron_drv.network_list()
1837
1838 def neutron_network_get(self, network_id):
1839 return self.neutron_drv.network_get(network_id)
1840
1841 def neutron_network_create(self, **kwargs):
1842 return self.neutron_drv.network_create(**kwargs)
1843
1844 def neutron_network_delete(self, network_id):
1845 self.neutron_drv.network_delete(network_id)
1846
1847 def neutron_subnet_list(self):
1848 return self.neutron_drv.subnet_list()
1849
1850 def neutron_subnet_get(self, subnet_id):
1851 return self.neutron_drv.subnet_get(subnet_id)
1852
1853 def neutron_subnet_create(self, **kwargs):
1854 return self.neutron_drv.subnet_create(**kwargs)
1855
1856 def netruon_subnet_delete(self, subnet_id):
1857 self.neutron_drv.subnet_delete(subnet_id)
1858
1859 def neutron_subnetpool_list(self):
1860 return self.neutron_drv.subnetpool_list()
1861
1862 def netruon_subnetpool_by_name(self, pool_name):
1863 pool_list = self.neutron_drv.subnetpool_list(**{'name': pool_name})
1864 if pool_list:
1865 return pool_list[0]
1866 else:
1867 return None
1868
1869 def neutron_port_list(self, **kwargs):
1870 return self.neutron_drv.port_list(**kwargs)
1871
1872 def neutron_port_get(self, port_id):
1873 return self.neutron_drv.port_get(port_id)
1874
1875 def neutron_port_create(self, **kwargs):
1876 subnets = [subnet for subnet in self.neutron_drv.subnet_list() if subnet['network_id'] == kwargs['network_id']]
1877 assert len(subnets) == 1
1878 kwargs['subnet_id'] = subnets[0]['id']
1879 if not 'admin_state_up' in kwargs:
1880 kwargs['admin_state_up'] = True
1881 port_id = self.neutron_drv.port_create(**kwargs)
1882
1883 if 'vm_id' in kwargs:
1884 self.nova_server_add_port(kwargs['vm_id'], port_id)
1885 return port_id
1886
1887 def neutron_security_group_list(self):
1888 return self.neutron_drv.security_group_list()
1889
1890 def neutron_security_group_by_name(self, group_name):
1891 group_list = self.neutron_drv.security_group_list()
1892 groups = [group for group in group_list if group['name'] == group_name]
1893 if groups:
1894 return groups[0]
1895 else:
1896 return None
1897
1898 def neutron_port_delete(self, port_id):
1899 self.neutron_drv.port_delete(port_id)
1900
1901 def ceilo_meter_endpoint(self):
1902 return self.ceilo_drv.endpoint
1903
1904 def ceilo_meter_list(self):
1905 return self.ceilo_drv.meters
1906
1907 def ceilo_nfvi_metrics(self, vim_id):
1908 """Returns a dict of NFVI metrics for a given VM
1909
1910 Arguments:
1911 vim_id - the VIM ID of the VM to retrieve the metrics for
1912
1913 Returns:
1914 A dict of NFVI metrics
1915
1916 """
1917 def query_latest_sample(counter_name):
1918 try:
1919 filter = json.dumps({
1920 "and": [
1921 {"=": {"resource": vim_id}},
1922 {"=": {"counter_name": counter_name}}
1923 ]
1924 })
1925 orderby = json.dumps([{"timestamp": "DESC"}])
1926 result = self.ceilo_drv.client.query_samples.query(
1927 filter=filter,
1928 orderby=orderby,
1929 limit=1,
1930 )
1931 return result[0]
1932
1933 except IndexError:
1934 pass
1935
1936 except Exception as e:
1937 logger.error("Got exception while querying ceilometer, exception details:%s " %str(e))
1938
1939 return None
1940
1941 memory_usage = query_latest_sample("memory.usage")
1942 disk_usage = query_latest_sample("disk.usage")
1943 cpu_util = query_latest_sample("cpu_util")
1944
1945 metrics = dict()
1946
1947 if memory_usage is not None:
1948 memory_usage.volume = 1e6 * memory_usage.volume
1949 metrics["memory_usage"] = memory_usage.to_dict()
1950
1951 if disk_usage is not None:
1952 metrics["disk_usage"] = disk_usage.to_dict()
1953
1954 if cpu_util is not None:
1955 metrics["cpu_util"] = cpu_util.to_dict()
1956
1957 return metrics
1958
1959 def ceilo_alarm_list(self):
1960 """Returns a list of ceilometer alarms"""
1961 return self.ceilo_drv.client.alarms.list()
1962
1963 def ceilo_alarm_create(self,
1964 name,
1965 meter,
1966 statistic,
1967 operation,
1968 threshold,
1969 period,
1970 evaluations,
1971 severity='low',
1972 repeat=True,
1973 enabled=True,
1974 actions=None,
1975 **kwargs):
1976 """Create a new Alarm
1977
1978 Arguments:
1979 name - the name of the alarm
1980 meter - the name of the meter to measure
1981 statistic - the type of statistic used to trigger the alarm
1982 ('avg', 'min', 'max', 'count', 'sum')
1983 operation - the relational operator that, combined with the
1984 threshold value, determines when the alarm is
1985 triggered ('lt', 'le', 'eq', 'ge', 'gt')
1986 threshold - the value of the statistic that will trigger the
1987 alarm
1988 period - the duration (seconds) over which to evaluate the
1989 specified statistic
1990 evaluations - the number of samples of the meter statistic to
1991 collect when evaluating the threshold
1992 severity - a measure of the urgency or importance of the alarm
1993 ('low', 'moderate', 'critical')
1994 repeat - a flag that indicates whether the alarm should be
1995 triggered once (False) or repeatedly while the alarm
1996 condition is true (True)
1997 enabled - a flag that indicates whether the alarm is enabled
1998 (True) or disabled (False)
1999 actions - a dict specifying the URLs for webhooks. The dict can
2000 have up to 3 keys: 'insufficient_data', 'alarm',
2001 'ok'. Each key is associated with a list of URLs to
2002 webhooks that will be invoked when one of the 3
2003 actions is taken.
2004 kwargs - an arbitrary dict of keyword arguments that are
2005 passed to the ceilometer client
2006
2007 """
2008 ok_actions = actions.get('ok') if actions is not None else None
2009 alarm_actions = actions.get('alarm') if actions is not None else None
2010 insufficient_data_actions = actions.get('insufficient_data') if actions is not None else None
2011
2012 return self.ceilo_drv.client.alarms.create(
2013 name=name,
2014 meter_name=meter,
2015 statistic=statistic,
2016 comparison_operator=operation,
2017 threshold=threshold,
2018 period=period,
2019 evaluation_periods=evaluations,
2020 severity=severity,
2021 repeat_actions=repeat,
2022 enabled=enabled,
2023 ok_actions=ok_actions,
2024 alarm_actions=alarm_actions,
2025 insufficient_data_actions=insufficient_data_actions,
2026 **kwargs
2027 )
2028
2029 def ceilo_alarm_update(self, alarm_id, **kwargs):
2030 """Updates an existing alarm
2031
2032 Arguments:
2033 alarm_id - the identifier of the alarm to update
2034 kwargs - a dict of the alarm attributes to update
2035
2036 """
2037 return self.ceilo_drv.client.alarms.update(alarm_id, **kwargs)
2038
2039 def ceilo_alarm_delete(self, alarm_id):
2040 self.ceilo_drv.client.alarms.delete(alarm_id)
2041
2042 def cinder_volume_list(self):
2043 return self.cinder_drv.volume_list()
2044
2045 def cinder_volume_get(self,vol_id):
2046 return self.cinder_drv.volume_get(vol_id)
2047
2048 def cinder_volume_set_metadata(self, volumeid, metadata):
2049 return self.cinder_drv.volume_set_metadata(volumeid, metadata)
2050
2051 def cinder_volume_delete_metadata(self, volumeid, metadata):
2052 return self.cinder_drv.volume_delete_metadata(volumeid, metadata)
2053
2054
2055
2056 class CinderDriver(object):
2057 """
2058 Driver for openstack cinder-client
2059 """
2060 def __init__(self, ks_drv, service_name, version):
2061 """
2062 Constructor for CinderDriver
2063 Arguments: KeystoneDriver class object
2064 """
2065 self.ks_drv = ks_drv
2066 self._service_name = service_name
2067 self._version = version
2068
2069 def _get_cinder_credentials(self):
2070 """
2071 Returns a dictionary of kwargs required to instantiate python-cinderclient class
2072
2073 Arguments: None
2074
2075 Returns:
2076 A dictionary object of arguments
2077 """
2078 creds = {}
2079 creds['version'] = self._version
2080 creds['username'] = self.ks_drv.get_username()
2081 creds['api_key'] = self.ks_drv.get_password()
2082 creds['auth_url'] = self.ks_drv.get_service_endpoint("identity", "publicURL")
2083 creds['project_id'] = self.ks_drv.get_tenant_name()
2084 creds['insecure'] = self.ks_drv.get_security_mode()
2085
2086 return creds
2087
2088 def _get_cinder_connection(self):
2089 """
2090 Returns a object of class python-cinderclient
2091 """
2092 if not hasattr(self, '_cinder_connection'):
2093 self._cinder_connection = cinder_client.Client(**self._get_cinder_credentials())
2094 else:
2095 # Reinitialize if auth_token is no longer valid
2096 if not self.ks_drv.is_auth_token_valid():
2097 self._cinder_connection = cinder_client.Client(**self._get_cinder_credentials())
2098 return self._cinder_connection
2099
2100 def volume_list(self):
2101 """
2102 Returns list of dictionaries. Each dictionary contains attributes associated with
2103 volumes
2104
2105 Arguments: None
2106
2107 Returns: List of dictionaries.
2108 """
2109 cinderconn = self._get_cinder_connection()
2110 volumes = []
2111 try:
2112 volume_info = cinderconn.volumes.list()
2113 except Exception as e:
2114 logger.error("OpenstackDriver: List volumes operation failed. Exception: %s" %(str(e)))
2115 raise
2116 volumes = [ volume for volume in volume_info ]
2117 return volumes
2118
2119 def volume_get(self, volume_id):
2120 """
2121 Get details volume
2122
2123 Arguments: None
2124
2125 Returns: List of dictionaries.
2126 """
2127 cinderconn = self._get_cinder_connection()
2128 try:
2129 vol = cinderconn.volumes.get(volume_id)
2130 except Exception as e:
2131 logger.error("OpenstackDriver: Get volume operation failed. Exception: %s" %(str(e)))
2132 raise
2133 return vol
2134
2135 def volume_set_metadata(self, volume_id, metadata):
2136 """
2137 Set metadata for volume
2138 Metadata is a dictionary of key-value pairs
2139
2140 Arguments: None
2141
2142 Returns: List of dictionaries.
2143 """
2144 cinderconn = self._get_cinder_connection()
2145 try:
2146 cinderconn.volumes.set_metadata(volume_id, metadata)
2147 except Exception as e:
2148 logger.error("OpenstackDriver: Set metadata operation failed. Exception: %s" %(str(e)))
2149 raise
2150
2151 def volume_delete_metadata(self, volume_id, metadata):
2152 """
2153 Delete metadata for volume
2154 Metadata is a dictionary of key-value pairs
2155
2156 Arguments: None
2157
2158 Returns: List of dictionaries.
2159 """
2160 cinderconn = self._get_cinder_connection()
2161 try:
2162 cinderconn.volumes.delete_metadata(volume_id, metadata)
2163 except Exception as e:
2164 logger.error("OpenstackDriver: Delete metadata operation failed. Exception: %s" %(str(e)))
2165 raise
2166
2167 class CinderDriverV2(CinderDriver):
2168 """
2169 Driver for openstack cinder-client V2
2170 """
2171 def __init__(self, ks_drv):
2172 super(CinderDriverV2, self).__init__(ks_drv, 'volumev2', 2)
2173