5f44e5e08a699342ea46eb26ecc026103245c482
[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 ip_address(string) : Static IP address to assign to the port
1397 vnic_type(string) : Possible values are "normal", "direct", "macvtap"
1398 }
1399 Returns:
1400 port_id (string) : UUID of the port
1401
1402 NOTE: Either subnet_id or ip_address need to be specified.
1403 """
1404 params = {
1405 "port": {
1406 "admin_state_up" : kwargs['admin_state_up'],
1407 "name" : kwargs['name'],
1408 "network_id" : kwargs['network_id'],
1409 "binding:vnic_type" : kwargs['port_type']}}
1410
1411 if 'ip_address' in kwargs:
1412 params["port"]["fixed_ips"] = [{"ip_address": kwargs['ip_address']}]
1413 else:
1414 params["port"]["fixed_ips"] = [{"subnet_id": kwargs['subnet_id']}]
1415
1416 logger.debug("Port create params: {}".format(params))
1417
1418 ntconn = self._get_neutron_connection()
1419 try:
1420 port = ntconn.create_port(params)
1421 except Exception as e:
1422 logger.error("OpenstackDriver: Port Create operation failed. Exception: %s" %(str(e)))
1423 raise
1424 return port['port']['id']
1425
1426 def _port_get(self, port_id):
1427 """
1428 Returns a dictionary object describing the attributes of the port
1429
1430 Arguments:
1431 port_id (string): UUID of the port
1432
1433 Returns:
1434 A dictionary object of the port attributes
1435 """
1436 ntconn = self._get_neutron_connection()
1437 port = ntconn.list_ports(id=port_id)['ports']
1438 if not port:
1439 raise NeutronException.NotFound("Could not find port_id %s" %(port_id))
1440 return port[0]
1441
1442 def port_get(self, port_id):
1443 """
1444 Returns a dictionary object describing the attributes of the port
1445
1446 Arguments:
1447 port_id (string): UUID of the port
1448
1449 Returns:
1450 A dictionary object of the port attributes
1451 """
1452 return self._port_get(port_id)
1453
1454 def port_delete(self, port_id):
1455 """
1456 Deletes a port identified by port_id
1457
1458 Arguments:
1459 port_id (string) : UUID of the port
1460
1461 Returns: None
1462 """
1463 assert port_id == self._port_get(port_id)['id']
1464 ntconn = self._get_neutron_connection()
1465 try:
1466 ntconn.delete_port(port_id)
1467 except Exception as e:
1468 logger.error("Port Delete operation failed for port_id : %s. Exception: %s" %(port_id, str(e)))
1469 raise
1470
1471 def security_group_list(self):
1472 """
1473 Returns a list of dictionaries. Each dictionary contains attributes describing the security group
1474
1475 Arguments:
1476 None
1477
1478 Returns:
1479 A dictionary of the objects of security group attributes
1480 """
1481 ntconn = self._get_neutron_connection()
1482 try:
1483 group_list = ntconn.list_security_groups(tenant_id=self.ks_drv.get_tenant_id())
1484 except Exception as e:
1485 logger.error("List Security group operation, Exception: %s" %(str(e)))
1486 raise
1487
1488 if 'security_groups' in group_list:
1489 return group_list['security_groups']
1490 else:
1491 return []
1492
1493 def subnetpool_list(self, **kwargs):
1494 """
1495 Returns a list of dictionaries. Each dictionary contains attributes describing a subnet prefix pool
1496
1497 Arguments:
1498 None
1499
1500 Returns:
1501 A dictionary of the objects of subnet prefix pool
1502 """
1503 ntconn = self._get_neutron_connection()
1504 try:
1505 pool_list = ntconn.list_subnetpools(**kwargs)
1506 except Exception as e:
1507 logger.error("List SubnetPool operation, Exception: %s" %(str(e)))
1508 raise
1509
1510 if 'subnetpools' in pool_list:
1511 return pool_list['subnetpools']
1512 else:
1513 return []
1514
1515 class NeutronDriverV2(NeutronDriver):
1516 """
1517 Driver for openstack neutron neutron-client v2
1518 """
1519 def __init__(self, ks_drv):
1520 """
1521 Constructor for NeutronDriver
1522 Arguments: KeystoneDriver class object
1523 """
1524 super(NeutronDriverV2, self).__init__(ks_drv, 'network', '2.0')
1525
1526
1527
1528 class CeilometerDriver(object):
1529 """
1530 Driver for openstack ceilometer client
1531 """
1532
1533 def __init__(self, ks_drv, service_name, version):
1534 """
1535 Constructor for CeilometerDriver
1536 Arguments: KeystoneDriver class object
1537 """
1538 self.ks_drv = ks_drv
1539 self._service_name = service_name
1540 self._version = version
1541 self._client = None
1542
1543 @property
1544 def version(self):
1545 """The version of the ceilometer client used by the driver"""
1546 return self._version
1547
1548 @property
1549 def client(self):
1550 """The instance of ceilometer client used by the driver"""
1551 if self._client is None or not self.ks_drv.is_auth_token_valid():
1552 self._client = ceilo_client.Client(**self.credentials)
1553
1554 return self._client
1555
1556 @property
1557 def auth_token(self):
1558 """The authorization token for the ceilometer client"""
1559 try:
1560 return self.ks_drv.get_auth_token()
1561 except KeystoneExceptions.EndpointNotFound as e:
1562 logger.error("OpenstackDriver: unable to get authorization token for ceilometer. Exception: %s" %(str(e)))
1563 raise
1564
1565 @property
1566 def security_mode(self):
1567 """The security mode for the ceilometer client"""
1568 try:
1569 return self.ks_drv.get_security_mode()
1570 except KeystoneExceptions.EndpointNotFound as e:
1571 logger.error("OpenstackDriver: unable to get security mode for ceilometer. Exception: %s" %(str(e)))
1572 raise
1573
1574 @property
1575 def endpoint(self):
1576 """The service endpoint for the ceilometer client"""
1577 try:
1578 return self.ks_drv.get_service_endpoint(self._service_name, "publicURL")
1579 except KeystoneExceptions.EndpointNotFound as e:
1580 logger.error("OpenstackDriver: unable to get endpoint for ceilometer. Exception: %s" %(str(e)))
1581 raise
1582
1583 @property
1584 def credentials(self):
1585 """A dictionary of credentials for the ceilometer client"""
1586 return dict(
1587 version=self.version,
1588 endpoint=self.endpoint,
1589 token=self.auth_token,
1590 insecure=self.security_mode,
1591 )
1592
1593 @property
1594 def meters(self):
1595 """A list of the available meters"""
1596 try:
1597 return self.client.meters.list()
1598 except Exception as e:
1599 logger.error("OpenstackDriver: List meters operation failed. Exception: %s" %(str(e)))
1600 raise
1601
1602 @property
1603 def alarms(self):
1604 """The ceilometer client alarms manager"""
1605 return self.client.alarms
1606
1607 def query_samples(self, vim_instance_id, counter_name, limit=1):
1608 """Returns a list of samples
1609
1610 Arguments:
1611 vim_instance_id - the ID of the VIM that the samples are from
1612 counter_name - the counter that the samples will come from
1613 limit - a limit on the number of samples to return
1614 (default: 1)
1615
1616 Returns:
1617 A list of samples
1618
1619 """
1620 try:
1621 filter = json.dumps({
1622 "and": [
1623 {"=": {"resource": vim_instance_id}},
1624 {"=": {"counter_name": counter_name}}
1625 ]
1626 })
1627 result = self.client.query_samples.query(filter=filter, limit=limit)
1628 return result[-limit:]
1629
1630 except Exception as e:
1631 logger.exception(e)
1632
1633 return []
1634
1635
1636 class CeilometerDriverV2(CeilometerDriver):
1637 """
1638 Driver for openstack ceilometer ceilometer-client
1639 """
1640 def __init__(self, ks_drv):
1641 """
1642 Constructor for CeilometerDriver
1643 Arguments: CeilometerDriver class object
1644 """
1645 super(CeilometerDriverV2, self).__init__(ks_drv, 'metering', '2')
1646
1647 class OpenstackDriver(object):
1648 """
1649 Driver for openstack nova, neutron, glance, keystone, swift, cinder services
1650 """
1651 def __init__(self, username, password, auth_url, tenant_name, mgmt_network = None, cert_validate = False):
1652 """
1653 OpenstackDriver Driver constructor
1654 Arguments:
1655 username (string) : Username for project/tenant.
1656 password (string) : Password
1657 auth_url (string) : Keystone Authentication URL.
1658 tenant_name (string) : Openstack project name
1659 mgmt_network(string, optional) : Management network name. Each VM created with this cloud-account will
1660 have a default interface into management network.
1661 cert_validate (boolean, optional) : In case of SSL/TLS connection if certificate validation is required or not.
1662
1663 """
1664 insecure = not cert_validate
1665 if auth_url.find('/v3') != -1:
1666 self.ks_drv = KeystoneDriverV3(username, password, auth_url, tenant_name, insecure)
1667 self.glance_drv = GlanceDriverV2(self.ks_drv)
1668 self.nova_drv = NovaDriverV21(self.ks_drv)
1669 self.neutron_drv = NeutronDriverV2(self.ks_drv)
1670 self.ceilo_drv = CeilometerDriverV2(self.ks_drv)
1671 elif auth_url.find('/v2') != -1:
1672 self.ks_drv = KeystoneDriverV2(username, password, auth_url, tenant_name, insecure)
1673 self.glance_drv = GlanceDriverV2(self.ks_drv)
1674 self.nova_drv = NovaDriverV2(self.ks_drv)
1675 self.neutron_drv = NeutronDriverV2(self.ks_drv)
1676 self.ceilo_drv = CeilometerDriverV2(self.ks_drv)
1677 else:
1678 logger.error("Could not identity the version information for openstack service endpoints. Auth_URL should contain \"/v2\" or \"/v3\" string in it")
1679 raise NotImplementedError("Auth URL is wrong or invalid. Only Keystone v2 & v3 supported")
1680
1681 self._mgmt_network_id = None
1682 if mgmt_network != None:
1683 self._mgmt_network = mgmt_network
1684
1685 networks = []
1686 try:
1687 ntconn = self.neutron_drv._get_neutron_connection()
1688 networks = ntconn.list_networks()
1689 except (KeystoneExceptions.Unauthorized, KeystoneExceptions.AuthorizationFailure) as e:
1690 raise
1691 except Exception as e:
1692 logger.error("OpenstackDriver: List Network operation failed. Exception: %s" %(str(e)))
1693 raise
1694
1695 network_list = [ network for network in networks['networks'] if network['name'] == mgmt_network ]
1696
1697 if not network_list:
1698 raise NeutronException.NotFound("Could not find network %s" %(mgmt_network))
1699 self._mgmt_network_id = network_list[0]['id']
1700
1701 def validate_account_creds(self):
1702 try:
1703 ksconn = self.ks_drv._get_keystone_connection()
1704 except KeystoneExceptions.AuthorizationFailure as e:
1705 logger.error("OpenstackDriver: Unable to authenticate or validate the existing credentials. Exception: %s" %(str(e)))
1706 raise ValidationError("Invalid Credentials: "+ str(e))
1707 except Exception as e:
1708 logger.error("OpenstackDriver: Could not connect to Openstack. Exception: %s" %(str(e)))
1709 raise ValidationError("Connection Error: "+ str(e))
1710
1711 def get_mgmt_network_id(self):
1712 return self._mgmt_network_id
1713
1714 def glance_image_create(self, **kwargs):
1715 if not 'disk_format' in kwargs:
1716 kwargs['disk_format'] = 'qcow2'
1717 if not 'container_format' in kwargs:
1718 kwargs['container_format'] = 'bare'
1719 if not 'min_disk' in kwargs:
1720 kwargs['min_disk'] = 0
1721 if not 'min_ram' in kwargs:
1722 kwargs['min_ram'] = 0
1723 return self.glance_drv.image_create(**kwargs)
1724
1725 def glance_image_upload(self, image_id, fd):
1726 self.glance_drv.image_upload(image_id, fd)
1727
1728 def glance_image_add_location(self, image_id, location):
1729 self.glance_drv.image_add_location(image_id, location)
1730
1731 def glance_image_delete(self, image_id):
1732 self.glance_drv.image_delete(image_id)
1733
1734 def glance_image_list(self):
1735 return self.glance_drv.image_list()
1736
1737 def glance_image_get(self, image_id):
1738 return self.glance_drv.image_get(image_id)
1739
1740
1741 def nova_flavor_list(self):
1742 return self.nova_drv.flavor_list()
1743
1744 def nova_flavor_create(self, name, ram, vcpus, disk, epa_specs):
1745 extra_specs = epa_specs if epa_specs else {}
1746 return self.nova_drv.flavor_create(name,
1747 ram = ram,
1748 vcpu = vcpus,
1749 disk = disk,
1750 extra_specs = extra_specs)
1751
1752 def nova_flavor_delete(self, flavor_id):
1753 self.nova_drv.flavor_delete(flavor_id)
1754
1755 def nova_flavor_get(self, flavor_id):
1756 return self.nova_drv.flavor_get(flavor_id)
1757
1758 def nova_server_create(self, **kwargs):
1759 def _verify_image(image_id):
1760 image = self.glance_drv.image_get(image_id)
1761 if image['status'] != 'active':
1762 raise GlanceException.NotFound("Image with image_id: %s not found in active state. Current State: %s" %(image['id'], image['status']))
1763
1764 assert kwargs['flavor_id'] == self.nova_drv.flavor_get(kwargs['flavor_id'])['id']
1765
1766 if kwargs['block_device_mapping_v2'] is not None:
1767 for block_map in kwargs['block_device_mapping_v2']:
1768 if 'uuid' in block_map:
1769 _verify_image(block_map['uuid'])
1770 else:
1771 _verify_image(kwargs['image_id'])
1772
1773 # if 'network_list' in kwargs:
1774 # kwargs['network_list'].append(self._mgmt_network_id)
1775 # else:
1776 # kwargs['network_list'] = [self._mgmt_network_id]
1777
1778 if 'security_groups' not in kwargs:
1779 nvconn = self.nova_drv._get_nova_connection()
1780 sec_groups = nvconn.security_groups.list()
1781 if sec_groups:
1782 ## Should we add VM in all availability security_groups ???
1783 kwargs['security_groups'] = [x.name for x in sec_groups]
1784 else:
1785 kwargs['security_groups'] = None
1786
1787 return self.nova_drv.server_create(**kwargs)
1788
1789 def nova_server_add_port(self, server_id, port_id):
1790 self.nova_drv.server_add_port(server_id, port_id)
1791
1792 def nova_server_delete_port(self, server_id, port_id):
1793 self.nova_drv.server_delete_port(server_id, port_id)
1794
1795 def nova_server_start(self, server_id):
1796 self.nova_drv.server_start(server_id)
1797
1798 def nova_server_stop(self, server_id):
1799 self.nova_drv.server_stop(server_id)
1800
1801 def nova_server_delete(self, server_id):
1802 self.nova_drv.server_delete(server_id)
1803
1804 def nova_server_reboot(self, server_id):
1805 self.nova_drv.server_reboot(server_id, reboot_type='HARD')
1806
1807 def nova_server_rebuild(self, server_id, image_id):
1808 self.nova_drv.server_rebuild(server_id, image_id)
1809
1810 def nova_floating_ip_list(self):
1811 return self.nova_drv.floating_ip_list()
1812
1813 def nova_floating_ip_create(self, pool = None):
1814 return self.nova_drv.floating_ip_create(pool)
1815
1816 def nova_floating_ip_delete(self, floating_ip):
1817 self.nova_drv.floating_ip_delete(floating_ip)
1818
1819 def nova_floating_ip_assign(self, server_id, floating_ip, fixed_ip):
1820 self.nova_drv.floating_ip_assign(server_id, floating_ip, fixed_ip)
1821
1822 def nova_floating_ip_release(self, server_id, floating_ip):
1823 self.nova_drv.floating_ip_release(server_id, floating_ip)
1824
1825 def nova_server_list(self):
1826 return self.nova_drv.server_list()
1827
1828 def nova_server_get(self, server_id):
1829 return self.nova_drv.server_get(server_id)
1830
1831 def nova_server_console(self, server_id):
1832 return self.nova_drv.server_console(server_id)
1833
1834 def nova_server_group_list(self):
1835 return self.nova_drv.group_list()
1836
1837 def nova_volume_list(self, server_id):
1838 return self.nova_drv.volume_list(server_id)
1839
1840 def neutron_network_list(self):
1841 return self.neutron_drv.network_list()
1842
1843 def neutron_network_get(self, network_id):
1844 return self.neutron_drv.network_get(network_id)
1845
1846 def neutron_network_create(self, **kwargs):
1847 return self.neutron_drv.network_create(**kwargs)
1848
1849 def neutron_network_delete(self, network_id):
1850 self.neutron_drv.network_delete(network_id)
1851
1852 def neutron_subnet_list(self):
1853 return self.neutron_drv.subnet_list()
1854
1855 def neutron_subnet_get(self, subnet_id):
1856 return self.neutron_drv.subnet_get(subnet_id)
1857
1858 def neutron_subnet_create(self, **kwargs):
1859 return self.neutron_drv.subnet_create(**kwargs)
1860
1861 def netruon_subnet_delete(self, subnet_id):
1862 self.neutron_drv.subnet_delete(subnet_id)
1863
1864 def neutron_subnetpool_list(self):
1865 return self.neutron_drv.subnetpool_list()
1866
1867 def netruon_subnetpool_by_name(self, pool_name):
1868 pool_list = self.neutron_drv.subnetpool_list(**{'name': pool_name})
1869 if pool_list:
1870 return pool_list[0]
1871 else:
1872 return None
1873
1874 def neutron_port_list(self, **kwargs):
1875 return self.neutron_drv.port_list(**kwargs)
1876
1877 def neutron_port_get(self, port_id):
1878 return self.neutron_drv.port_get(port_id)
1879
1880 def neutron_port_create(self, **kwargs):
1881
1882 if 'ip_address' not in kwargs:
1883 subnets = [subnet for subnet in self.neutron_drv.subnet_list()
1884 if subnet['network_id'] == kwargs['network_id']]
1885 assert len(subnets) == 1
1886 kwargs['subnet_id'] = subnets[0]['id']
1887
1888 if not 'admin_state_up' in kwargs:
1889 kwargs['admin_state_up'] = True
1890
1891 logger.debug("Port create params: {}".
1892 format(kwargs))
1893 port_id = self.neutron_drv.port_create(**kwargs)
1894
1895 if 'vm_id' in kwargs:
1896 self.nova_server_add_port(kwargs['vm_id'], port_id)
1897 return port_id
1898
1899 def neutron_security_group_list(self):
1900 return self.neutron_drv.security_group_list()
1901
1902 def neutron_security_group_by_name(self, group_name):
1903 group_list = self.neutron_drv.security_group_list()
1904 groups = [group for group in group_list if group['name'] == group_name]
1905 if groups:
1906 return groups[0]
1907 else:
1908 return None
1909
1910 def neutron_port_delete(self, port_id):
1911 self.neutron_drv.port_delete(port_id)
1912
1913 def ceilo_meter_endpoint(self):
1914 return self.ceilo_drv.endpoint
1915
1916 def ceilo_meter_list(self):
1917 return self.ceilo_drv.meters
1918
1919 def ceilo_nfvi_metrics(self, vim_id):
1920 """Returns a dict of NFVI metrics for a given VM
1921
1922 Arguments:
1923 vim_id - the VIM ID of the VM to retrieve the metrics for
1924
1925 Returns:
1926 A dict of NFVI metrics
1927
1928 """
1929 def query_latest_sample(counter_name):
1930 try:
1931 filter = json.dumps({
1932 "and": [
1933 {"=": {"resource": vim_id}},
1934 {"=": {"counter_name": counter_name}}
1935 ]
1936 })
1937 orderby = json.dumps([{"timestamp": "DESC"}])
1938 result = self.ceilo_drv.client.query_samples.query(
1939 filter=filter,
1940 orderby=orderby,
1941 limit=1,
1942 )
1943 return result[0]
1944
1945 except IndexError:
1946 pass
1947
1948 except Exception as e:
1949 logger.error("Got exception while querying ceilometer, exception details:%s " %str(e))
1950
1951 return None
1952
1953 memory_usage = query_latest_sample("memory.usage")
1954 disk_usage = query_latest_sample("disk.usage")
1955 cpu_util = query_latest_sample("cpu_util")
1956
1957 metrics = dict()
1958
1959 if memory_usage is not None:
1960 memory_usage.volume = 1e6 * memory_usage.volume
1961 metrics["memory_usage"] = memory_usage.to_dict()
1962
1963 if disk_usage is not None:
1964 metrics["disk_usage"] = disk_usage.to_dict()
1965
1966 if cpu_util is not None:
1967 metrics["cpu_util"] = cpu_util.to_dict()
1968
1969 return metrics
1970
1971 def ceilo_alarm_list(self):
1972 """Returns a list of ceilometer alarms"""
1973 return self.ceilo_drv.client.alarms.list()
1974
1975 def ceilo_alarm_create(self,
1976 name,
1977 meter,
1978 statistic,
1979 operation,
1980 threshold,
1981 period,
1982 evaluations,
1983 severity='low',
1984 repeat=True,
1985 enabled=True,
1986 actions=None,
1987 **kwargs):
1988 """Create a new Alarm
1989
1990 Arguments:
1991 name - the name of the alarm
1992 meter - the name of the meter to measure
1993 statistic - the type of statistic used to trigger the alarm
1994 ('avg', 'min', 'max', 'count', 'sum')
1995 operation - the relational operator that, combined with the
1996 threshold value, determines when the alarm is
1997 triggered ('lt', 'le', 'eq', 'ge', 'gt')
1998 threshold - the value of the statistic that will trigger the
1999 alarm
2000 period - the duration (seconds) over which to evaluate the
2001 specified statistic
2002 evaluations - the number of samples of the meter statistic to
2003 collect when evaluating the threshold
2004 severity - a measure of the urgency or importance of the alarm
2005 ('low', 'moderate', 'critical')
2006 repeat - a flag that indicates whether the alarm should be
2007 triggered once (False) or repeatedly while the alarm
2008 condition is true (True)
2009 enabled - a flag that indicates whether the alarm is enabled
2010 (True) or disabled (False)
2011 actions - a dict specifying the URLs for webhooks. The dict can
2012 have up to 3 keys: 'insufficient_data', 'alarm',
2013 'ok'. Each key is associated with a list of URLs to
2014 webhooks that will be invoked when one of the 3
2015 actions is taken.
2016 kwargs - an arbitrary dict of keyword arguments that are
2017 passed to the ceilometer client
2018
2019 """
2020 ok_actions = actions.get('ok') if actions is not None else None
2021 alarm_actions = actions.get('alarm') if actions is not None else None
2022 insufficient_data_actions = actions.get('insufficient_data') if actions is not None else None
2023
2024 return self.ceilo_drv.client.alarms.create(
2025 name=name,
2026 meter_name=meter,
2027 statistic=statistic,
2028 comparison_operator=operation,
2029 threshold=threshold,
2030 period=period,
2031 evaluation_periods=evaluations,
2032 severity=severity,
2033 repeat_actions=repeat,
2034 enabled=enabled,
2035 ok_actions=ok_actions,
2036 alarm_actions=alarm_actions,
2037 insufficient_data_actions=insufficient_data_actions,
2038 **kwargs
2039 )
2040
2041 def ceilo_alarm_update(self, alarm_id, **kwargs):
2042 """Updates an existing alarm
2043
2044 Arguments:
2045 alarm_id - the identifier of the alarm to update
2046 kwargs - a dict of the alarm attributes to update
2047
2048 """
2049 return self.ceilo_drv.client.alarms.update(alarm_id, **kwargs)
2050
2051 def ceilo_alarm_delete(self, alarm_id):
2052 self.ceilo_drv.client.alarms.delete(alarm_id)