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