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