Added support for creating images and flavors with hugepages for fdio scenarios
[functest.git] / utils / openstack_utils.py
1 #!/usr/bin/env python
2 #
3 # jose.lausuch@ericsson.com
4 # valentin.boucher@orange.com
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10
11 import os
12 import os.path
13 import subprocess
14 import sys
15 import time
16
17 from cinderclient import client as cinderclient
18 import functest.utils.functest_logger as ft_logger
19 from glanceclient import client as glanceclient
20 from keystoneclient.v2_0 import client as keystoneclient
21 from neutronclient.v2_0 import client as neutronclient
22 from novaclient import client as novaclient
23
24 logger = ft_logger.Logger("openstack_utils").getLogger()
25
26
27 # *********************************************
28 #   CREDENTIALS
29 # *********************************************
30 def check_credentials():
31     """
32     Check if the OpenStack credentials (openrc) are sourced
33     """
34     env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD', 'OS_TENANT_NAME']
35     return all(map(lambda v: v in os.environ and os.environ[v], env_vars))
36
37
38 def get_credentials(service):
39     """Returns a creds dictionary filled with the following keys:
40     * username
41     * password/api_key (depending on the service)
42     * tenant_name/project_id (depending on the service)
43     * auth_url
44     :param service: a string indicating the name of the service
45                     requesting the credentials.
46     """
47     creds = {}
48
49     # Check that the env vars exists:
50     envvars = ('OS_USERNAME', 'OS_PASSWORD', 'OS_AUTH_URL', 'OS_TENANT_NAME')
51     for envvar in envvars:
52         if os.getenv(envvar) is None:
53             logger.error("'%s' is not exported as an env variable." % envvar)
54             exit(-1)
55
56     # Unfortunately, each of the OpenStack client will request slightly
57     # different entries in their credentials dict.
58     if service.lower() in ("nova", "cinder"):
59         password = "api_key"
60         tenant = "project_id"
61     else:
62         password = "password"
63         tenant = "tenant_name"
64
65     # The most common way to pass these info to the script is to do it through
66     # environment variables.
67     creds.update({
68         "username": os.environ.get("OS_USERNAME"),
69         password: os.environ.get("OS_PASSWORD"),
70         "auth_url": os.environ.get("OS_AUTH_URL"),
71         tenant: os.environ.get("OS_TENANT_NAME")
72     })
73     if os.getenv('OS_ENDPOINT_TYPE') is not None:
74         creds.update({
75             "endpoint_type": os.environ.get("OS_ENDPOINT_TYPE")
76         })
77     if os.getenv('OS_REGION_NAME') is not None:
78         creds.update({
79             "region_name": os.environ.get("OS_REGION_NAME")
80         })
81     cacert = os.environ.get("OS_CACERT")
82     if cacert is not None:
83         # each openstack client uses differnt kwargs for this
84         creds.update({"cacert": cacert,
85                       "ca_cert": cacert,
86                       "https_ca_cert": cacert,
87                       "https_cacert": cacert,
88                       "ca_file": cacert})
89         creds.update({"insecure": "True", "https_insecure": "True"})
90         if not os.path.isfile(cacert):
91             logger.info("WARNING: The 'OS_CACERT' environment variable is "
92                         "set to %s but the file does not exist." % cacert)
93     return creds
94
95
96 def source_credentials(rc_file):
97     pipe = subprocess.Popen(". %s; env" % rc_file, stdout=subprocess.PIPE,
98                             shell=True)
99     output = pipe.communicate()[0]
100     env = dict((line.split("=", 1) for line in output.splitlines()))
101     os.environ.update(env)
102     return env
103
104
105 def get_credentials_for_rally():
106     creds = get_credentials("keystone")
107     admin_keys = ['username', 'tenant_name', 'password']
108     endpoint_types = [('internalURL', 'internal'),
109                       ('publicURL', 'public'), ('adminURL', 'admin')]
110     if 'endpoint_type' in creds.keys():
111         for k, v in endpoint_types:
112             if creds['endpoint_type'] == k:
113                 creds['endpoint_type'] = v
114     rally_conf = {"type": "ExistingCloud", "admin": {}}
115     for key in creds:
116         if key in admin_keys:
117             rally_conf['admin'][key] = creds[key]
118         else:
119             rally_conf[key] = creds[key]
120     return rally_conf
121
122
123 # *********************************************
124 #   CLIENTS
125 # *********************************************
126 def get_keystone_client():
127     creds_keystone = get_credentials("keystone")
128     return keystoneclient.Client(**creds_keystone)
129
130
131 def get_nova_client():
132     creds_nova = get_credentials("nova")
133     return novaclient.Client('2', **creds_nova)
134
135
136 def get_cinder_client():
137     creds_cinder = get_credentials("cinder")
138     creds_cinder.update({
139         "service_type": "volume"
140     })
141     return cinderclient.Client('2', **creds_cinder)
142
143
144 def get_neutron_client():
145     creds_neutron = get_credentials("neutron")
146     return neutronclient.Client(**creds_neutron)
147
148
149 def get_glance_client():
150     keystone_client = get_keystone_client()
151     glance_endpoint_type = 'publicURL'
152     os_endpoint_type = os.getenv('OS_ENDPOINT_TYPE')
153     if os_endpoint_type is not None:
154         glance_endpoint_type = os_endpoint_type
155     glance_endpoint = keystone_client.service_catalog.url_for(
156         service_type='image', endpoint_type=glance_endpoint_type)
157     return glanceclient.Client(1, glance_endpoint,
158                                token=keystone_client.auth_token)
159
160 # *********************************************
161 #   NOVA
162 # *********************************************
163
164
165 def get_instances(nova_client):
166     try:
167         instances = nova_client.servers.list(search_opts={'all_tenants': 1})
168         return instances
169     except Exception, e:
170         logger.error("Error [get_instances(nova_client)]: %s" % e)
171         return None
172
173
174 def get_instance_status(nova_client, instance):
175     try:
176         instance = nova_client.servers.get(instance.id)
177         return instance.status
178     except Exception, e:
179         logger.error("Error [get_instance_status(nova_client)]: %s" % e)
180         return None
181
182
183 def get_instance_by_name(nova_client, instance_name):
184     try:
185         instance = nova_client.servers.find(name=instance_name)
186         return instance
187     except Exception, e:
188         logger.error("Error [get_instance_by_name(nova_client, '%s')]: %s"
189                      % (instance_name, e))
190         return None
191
192
193 def get_flavor_id(nova_client, flavor_name):
194     flavors = nova_client.flavors.list(detailed=True)
195     id = ''
196     for f in flavors:
197         if f.name == flavor_name:
198             id = f.id
199             break
200     return id
201
202
203 def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram):
204     flavors = nova_client.flavors.list(detailed=True)
205     id = ''
206     for f in flavors:
207         if min_ram <= f.ram and f.ram <= max_ram:
208             id = f.id
209             break
210     return id
211
212
213 def get_floating_ips(nova_client):
214     try:
215         floating_ips = nova_client.floating_ips.list()
216         return floating_ips
217     except Exception, e:
218         logger.error("Error [get_floating_ips(nova_client)]: %s" % e)
219         return None
220
221
222 def get_hypervisors(nova_client):
223     try:
224         nodes = []
225         hypervisors = nova_client.hypervisors.list()
226         for hypervisor in hypervisors:
227             if hypervisor.state == "up":
228                 nodes.append(hypervisor.hypervisor_hostname)
229         return nodes
230     except Exception, e:
231         logger.error("Error [get_hypervisors(nova_client)]: %s" % e)
232         return None
233
234
235 def create_flavor(nova_client, flavor_name, ram, disk, vcpus):
236     try:
237         flavor = nova_client.flavors.create(flavor_name, ram, vcpus, disk)
238         extra_specs = {}
239         deploy_scenario = os.environ.get('DEPLOY_SCENARIO')
240         if deploy_scenario is not None and 'fdio' in deploy_scenario:
241             extra_specs['hw:mem_page_size'] = 'large'
242             flavor.update(extra_specs)
243     except Exception, e:
244         logger.error("Error [create_flavor(nova_client, '%s', '%s', '%s', "
245                      "'%s')]: %s" % (flavor_name, ram, disk, vcpus, e))
246         return None
247     return flavor.id
248
249
250 def create_instance(flavor_name,
251                     image_id,
252                     network_id,
253                     instance_name="functest-vm",
254                     confdrive=True,
255                     userdata=None,
256                     av_zone='',
257                     fixed_ip=None,
258                     files=None):
259     nova_client = get_nova_client()
260     try:
261         flavor = nova_client.flavors.find(name=flavor_name)
262     except:
263         flavors = nova_client.flavors.list()
264         logger.error("Error: Flavor '%s' not found. Available flavors are: "
265                      "\n%s" % (flavor_name, flavors))
266         return None
267     if fixed_ip is not None:
268         nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip}
269     else:
270         nics = {"net-id": network_id}
271     if userdata is None:
272         instance = nova_client.servers.create(
273             name=instance_name,
274             flavor=flavor,
275             image=image_id,
276             nics=[nics],
277             availability_zone=av_zone,
278             files=files
279         )
280     else:
281         instance = nova_client.servers.create(
282             name=instance_name,
283             flavor=flavor,
284             image=image_id,
285             nics=[nics],
286             config_drive=confdrive,
287             userdata=userdata,
288             availability_zone=av_zone,
289             files=files
290         )
291     return instance
292
293
294 def create_instance_and_wait_for_active(flavor_name,
295                                         image_id,
296                                         network_id,
297                                         instance_name="",
298                                         config_drive=False,
299                                         userdata="",
300                                         av_zone='',
301                                         fixed_ip=None,
302                                         files=None):
303     SLEEP = 3
304     VM_BOOT_TIMEOUT = 180
305     nova_client = get_nova_client()
306     instance = create_instance(flavor_name,
307                                image_id,
308                                network_id,
309                                instance_name,
310                                config_drive,
311                                userdata,
312                                av_zone=av_zone,
313                                fixed_ip=fixed_ip,
314                                files=files)
315     count = VM_BOOT_TIMEOUT / SLEEP
316     for n in range(count, -1, -1):
317         status = get_instance_status(nova_client, instance)
318         if status.lower() == "active":
319             return instance
320         elif status.lower() == "error":
321             logger.error("The instance %s went to ERROR status."
322                          % instance_name)
323             return None
324         time.sleep(SLEEP)
325     logger.error("Timeout booting the instance %s." % instance_name)
326     return None
327
328
329 def create_floating_ip(neutron_client):
330     extnet_id = get_external_net_id(neutron_client)
331     props = {'floating_network_id': extnet_id}
332     try:
333         ip_json = neutron_client.create_floatingip({'floatingip': props})
334         fip_addr = ip_json['floatingip']['floating_ip_address']
335         fip_id = ip_json['floatingip']['id']
336     except Exception, e:
337         logger.error("Error [create_floating_ip(neutron_client)]: %s" % e)
338         return None
339     return {'fip_addr': fip_addr, 'fip_id': fip_id}
340
341
342 def add_floating_ip(nova_client, server_id, floatingip_id):
343     try:
344         nova_client.servers.add_floating_ip(server_id, floatingip_id)
345         return True
346     except Exception, e:
347         logger.error("Error [add_floating_ip(nova_client, '%s', '%s')]: %s"
348                      % (server_id, floatingip_id, e))
349         return False
350
351
352 def delete_instance(nova_client, instance_id):
353     try:
354         nova_client.servers.force_delete(instance_id)
355         return True
356     except Exception, e:
357         logger.error("Error [delete_instance(nova_client, '%s')]: %s"
358                      % (instance_id, e))
359         return False
360
361
362 def delete_floating_ip(nova_client, floatingip_id):
363     try:
364         nova_client.floating_ips.delete(floatingip_id)
365         return True
366     except Exception, e:
367         logger.error("Error [delete_floating_ip(nova_client, '%s')]:"
368                      % (floatingip_id, e))
369         return False
370
371
372 # *********************************************
373 #   NEUTRON
374 # *********************************************
375 def get_network_list(neutron_client):
376     network_list = neutron_client.list_networks()['networks']
377     if len(network_list) == 0:
378         return None
379     else:
380         return network_list
381
382
383 def get_router_list(neutron_client):
384     router_list = neutron_client.list_routers()['routers']
385     if len(router_list) == 0:
386         return None
387     else:
388         return router_list
389
390
391 def get_port_list(neutron_client):
392     port_list = neutron_client.list_ports()['ports']
393     if len(port_list) == 0:
394         return None
395     else:
396         return port_list
397
398
399 def get_network_id(neutron_client, network_name):
400     networks = neutron_client.list_networks()['networks']
401     id = ''
402     for n in networks:
403         if n['name'] == network_name:
404             id = n['id']
405             break
406     return id
407
408
409 def get_subnet_id(neutron_client, subnet_name):
410     subnets = neutron_client.list_subnets()['subnets']
411     id = ''
412     for s in subnets:
413         if s['name'] == subnet_name:
414             id = s['id']
415             break
416     return id
417
418
419 def get_router_id(neutron_client, router_name):
420     routers = neutron_client.list_routers()['routers']
421     id = ''
422     for r in routers:
423         if r['name'] == router_name:
424             id = r['id']
425             break
426     return id
427
428
429 def get_private_net(neutron_client):
430     # Checks if there is an existing shared private network
431     networks = neutron_client.list_networks()['networks']
432     if len(networks) == 0:
433         return None
434     for net in networks:
435         if (net['router:external'] is False) and (net['shared'] is True):
436             return net
437     return None
438
439
440 def get_external_net(neutron_client):
441     for network in neutron_client.list_networks()['networks']:
442         if network['router:external']:
443             return network['name']
444     return None
445
446
447 def get_external_net_id(neutron_client):
448     for network in neutron_client.list_networks()['networks']:
449         if network['router:external']:
450             return network['id']
451     return None
452
453
454 def check_neutron_net(neutron_client, net_name):
455     for network in neutron_client.list_networks()['networks']:
456         if network['name'] == net_name:
457             for subnet in network['subnets']:
458                 return True
459     return False
460
461
462 def create_neutron_net(neutron_client, name):
463     json_body = {'network': {'name': name,
464                              'admin_state_up': True}}
465     try:
466         network = neutron_client.create_network(body=json_body)
467         network_dict = network['network']
468         return network_dict['id']
469     except Exception, e:
470         logger.error("Error [create_neutron_net(neutron_client, '%s')]: %s"
471                      % (name, e))
472         return None
473
474
475 def create_neutron_subnet(neutron_client, name, cidr, net_id):
476     json_body = {'subnets': [{'name': name, 'cidr': cidr,
477                               'ip_version': 4, 'network_id': net_id}]}
478     try:
479         subnet = neutron_client.create_subnet(body=json_body)
480         return subnet['subnets'][0]['id']
481     except Exception, e:
482         logger.error("Error [create_neutron_subnet(neutron_client, '%s', "
483                      "'%s', '%s')]: %s" % (name, cidr, net_id, e))
484         return None
485
486
487 def create_neutron_router(neutron_client, name):
488     json_body = {'router': {'name': name, 'admin_state_up': True}}
489     try:
490         router = neutron_client.create_router(json_body)
491         return router['router']['id']
492     except Exception, e:
493         logger.error("Error [create_neutron_router(neutron_client, '%s')]: %s"
494                      % (name, e))
495         return None
496
497
498 def create_neutron_port(neutron_client, name, network_id, ip):
499     json_body = {'port': {
500                  'admin_state_up': True,
501                  'name': name,
502                  'network_id': network_id,
503                  'fixed_ips': [{"ip_address": ip}]
504                  }}
505     try:
506         port = neutron_client.create_port(body=json_body)
507         return port['port']['id']
508     except Exception, e:
509         logger.error("Error [create_neutron_port(neutron_client, '%s', '%s', "
510                      "'%s')]: %s" % (name, network_id, ip, e))
511         return None
512
513
514 def update_neutron_net(neutron_client, network_id, shared=False):
515     json_body = {'network': {'shared': shared}}
516     try:
517         neutron_client.update_network(network_id, body=json_body)
518         return True
519     except Exception, e:
520         logger.error("Error [update_neutron_net(neutron_client, '%s', '%s')]: "
521                      "%s" % (network_id, str(shared), e))
522         return False
523
524
525 def update_neutron_port(neutron_client, port_id, device_owner):
526     json_body = {'port': {
527                  'device_owner': device_owner,
528                  }}
529     try:
530         port = neutron_client.update_port(port=port_id,
531                                           body=json_body)
532         return port['port']['id']
533     except Exception, e:
534         logger.error("Error [update_neutron_port(neutron_client, '%s', '%s')]:"
535                      " %s" % (port_id, device_owner, e))
536         return None
537
538
539 def add_interface_router(neutron_client, router_id, subnet_id):
540     json_body = {"subnet_id": subnet_id}
541     try:
542         neutron_client.add_interface_router(router=router_id, body=json_body)
543         return True
544     except Exception, e:
545         logger.error("Error [add_interface_router(neutron_client, '%s', "
546                      "'%s')]: %s" % (router_id, subnet_id, e))
547         return False
548
549
550 def add_gateway_router(neutron_client, router_id):
551     ext_net_id = get_external_net_id(neutron_client)
552     router_dict = {'network_id': ext_net_id}
553     try:
554         neutron_client.add_gateway_router(router_id, router_dict)
555         return True
556     except Exception, e:
557         logger.error("Error [add_gateway_router(neutron_client, '%s')]: %s"
558                      % (router_id, e))
559         return False
560
561
562 def delete_neutron_net(neutron_client, network_id):
563     try:
564         neutron_client.delete_network(network_id)
565         return True
566     except Exception, e:
567         logger.error("Error [delete_neutron_net(neutron_client, '%s')]: %s"
568                      % (network_id, e))
569         return False
570
571
572 def delete_neutron_subnet(neutron_client, subnet_id):
573     try:
574         neutron_client.delete_subnet(subnet_id)
575         return True
576     except Exception, e:
577         logger.error("Error [delete_neutron_subnet(neutron_client, '%s')]: %s"
578                      % (subnet_id, e))
579         return False
580
581
582 def delete_neutron_router(neutron_client, router_id):
583     try:
584         neutron_client.delete_router(router=router_id)
585         return True
586     except Exception, e:
587         logger.error("Error [delete_neutron_router(neutron_client, '%s')]: %s"
588                      % (router_id, e))
589         return False
590
591
592 def delete_neutron_port(neutron_client, port_id):
593     try:
594         neutron_client.delete_port(port_id)
595         return True
596     except Exception, e:
597         logger.error("Error [delete_neutron_port(neutron_client, '%s')]: %s"
598                      % (port_id, e))
599         return False
600
601
602 def remove_interface_router(neutron_client, router_id, subnet_id):
603     json_body = {"subnet_id": subnet_id}
604     try:
605         neutron_client.remove_interface_router(router=router_id,
606                                                body=json_body)
607         return True
608     except Exception, e:
609         logger.error("Error [remove_interface_router(neutron_client, '%s', "
610                      "'%s')]: %s" % (router_id, subnet_id, e))
611         return False
612
613
614 def remove_gateway_router(neutron_client, router_id):
615     try:
616         neutron_client.remove_gateway_router(router_id)
617         return True
618     except Exception, e:
619         logger.error("Error [remove_gateway_router(neutron_client, '%s')]: %s"
620                      % (router_id, e))
621         return False
622
623
624 def create_network_full(neutron_client,
625                         net_name,
626                         subnet_name,
627                         router_name,
628                         cidr):
629
630     # Check if the network already exists
631     network_id = get_network_id(neutron_client, net_name)
632     subnet_id = get_subnet_id(neutron_client, subnet_name)
633     router_id = get_router_id(neutron_client, router_name)
634
635     if network_id != '' and subnet_id != '' and router_id != '':
636         logger.info("A network with name '%s' already exists..." % net_name)
637     else:
638         neutron_client.format = 'json'
639         logger.info('Creating neutron network %s...' % net_name)
640         network_id = create_neutron_net(neutron_client, net_name)
641
642         if not network_id:
643             return False
644
645         logger.debug("Network '%s' created successfully" % network_id)
646         logger.debug('Creating Subnet....')
647         subnet_id = create_neutron_subnet(neutron_client, subnet_name,
648                                           cidr, network_id)
649         if not subnet_id:
650             return None
651
652         logger.debug("Subnet '%s' created successfully" % subnet_id)
653         logger.debug('Creating Router...')
654         router_id = create_neutron_router(neutron_client, router_name)
655
656         if not router_id:
657             return None
658
659         logger.debug("Router '%s' created successfully" % router_id)
660         logger.debug('Adding router to subnet...')
661
662         if not add_interface_router(neutron_client, router_id, subnet_id):
663             return None
664
665         logger.debug("Interface added successfully.")
666
667         logger.debug('Adding gateway to router...')
668         if not add_gateway_router(neutron_client, router_id):
669             return None
670
671         logger.debug("Gateway added successfully.")
672
673     network_dic = {'net_id': network_id,
674                    'subnet_id': subnet_id,
675                    'router_id': router_id}
676     return network_dic
677
678
679 def create_shared_network_full(net_name, subnt_name, router_name, subnet_cidr):
680     neutron_client = get_neutron_client()
681
682     network_dic = create_network_full(neutron_client,
683                                       net_name,
684                                       subnt_name,
685                                       router_name,
686                                       subnet_cidr)
687     if network_dic:
688         if not update_neutron_net(neutron_client,
689                                   network_dic['net_id'],
690                                   shared=True):
691             logger.error("Failed to update network %s..." % net_name)
692             return None
693         else:
694             logger.debug("Network '%s' is available..." % net_name)
695     else:
696         logger.error("Network %s creation failed" % net_name)
697         return None
698     return network_dic
699
700
701 def create_bgpvpn(neutron_client, **kwargs):
702     # route_distinguishers
703     # route_targets
704     json_body = {"bgpvpn": kwargs}
705     return neutron_client.create_bgpvpn(json_body)
706
707
708 def create_network_association(neutron_client, bgpvpn_id, neutron_network_id):
709     json_body = {"network_association": {"network_id": neutron_network_id}}
710     return neutron_client.create_network_association(bgpvpn_id, json_body)
711
712
713 def create_router_association(neutron_client, bgpvpn_id, router_id):
714     json_body = {"router_association": {"router_id": router_id}}
715     return neutron_client.create_router_association(bgpvpn_id, json_body)
716
717
718 def update_bgpvpn(neutron_client, bgpvpn_id, **kwargs):
719     json_body = {"bgpvpn": kwargs}
720     return neutron_client.update_bgpvpn(bgpvpn_id, json_body)
721
722
723 def delete_bgpvpn(neutron_client, bgpvpn_id):
724     return neutron_client.delete_bgpvpn(bgpvpn_id)
725
726 # *********************************************
727 #   SEC GROUPS
728 # *********************************************
729
730
731 def get_security_groups(neutron_client):
732     try:
733         security_groups = neutron_client.list_security_groups()[
734             'security_groups']
735         return security_groups
736     except Exception, e:
737         logger.error("Error [get_security_groups(neutron_client)]: %s" % e)
738         return None
739
740
741 def get_security_group_id(neutron_client, sg_name):
742     security_groups = get_security_groups(neutron_client)
743     id = ''
744     for sg in security_groups:
745         if sg['name'] == sg_name:
746             id = sg['id']
747             break
748     return id
749
750
751 def create_security_group(neutron_client, sg_name, sg_description):
752     json_body = {'security_group': {'name': sg_name,
753                                     'description': sg_description}}
754     try:
755         secgroup = neutron_client.create_security_group(json_body)
756         return secgroup['security_group']
757     except Exception, e:
758         logger.error("Error [create_security_group(neutron_client, '%s', "
759                      "'%s')]: %s" % (sg_name, sg_description, e))
760         return None
761
762
763 def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
764                          port_range_min=None, port_range_max=None):
765     if port_range_min is None and port_range_max is None:
766         json_body = {'security_group_rule': {'direction': direction,
767                                              'security_group_id': sg_id,
768                                              'protocol': protocol}}
769     elif port_range_min is not None and port_range_max is not None:
770         json_body = {'security_group_rule': {'direction': direction,
771                                              'security_group_id': sg_id,
772                                              'port_range_min': port_range_min,
773                                              'port_range_max': port_range_max,
774                                              'protocol': protocol}}
775     else:
776         logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', "
777                      "'%s', '%s', '%s', '%s')]:" % (neutron_client,
778                                                     sg_id, direction,
779                                                     port_range_min,
780                                                     port_range_max,
781                                                     protocol),
782                      " Invalid values for port_range_min, port_range_max")
783         return False
784     try:
785         neutron_client.create_security_group_rule(json_body)
786         return True
787     except Exception, e:
788         logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', "
789                      "'%s', '%s', '%s', '%s')]: %s" % (neutron_client,
790                                                        sg_id,
791                                                        direction,
792                                                        port_range_min,
793                                                        port_range_max,
794                                                        protocol, e))
795         return False
796
797
798 def create_security_group_full(neutron_client,
799                                sg_name, sg_description):
800     sg_id = get_security_group_id(neutron_client, sg_name)
801     if sg_id != '':
802         logger.info("Using existing security group '%s'..." % sg_name)
803     else:
804         logger.info("Creating security group  '%s'..." % sg_name)
805         SECGROUP = create_security_group(neutron_client,
806                                          sg_name,
807                                          sg_description)
808         if not SECGROUP:
809             logger.error("Failed to create the security group...")
810             return None
811
812         sg_id = SECGROUP['id']
813
814         logger.debug("Security group '%s' with ID=%s created successfully."
815                      % (SECGROUP['name'], sg_id))
816
817         logger.debug("Adding ICMP rules in security group '%s'..."
818                      % sg_name)
819         if not create_secgroup_rule(neutron_client, sg_id,
820                                     'ingress', 'icmp'):
821             logger.error("Failed to create the security group rule...")
822             return None
823
824         logger.debug("Adding SSH rules in security group '%s'..."
825                      % sg_name)
826         if not create_secgroup_rule(
827                 neutron_client, sg_id, 'ingress', 'tcp', '22', '22'):
828             logger.error("Failed to create the security group rule...")
829             return None
830
831         if not create_secgroup_rule(
832                 neutron_client, sg_id, 'egress', 'tcp', '22', '22'):
833             logger.error("Failed to create the security group rule...")
834             return None
835     return sg_id
836
837
838 def add_secgroup_to_instance(nova_client, instance_id, secgroup_id):
839     try:
840         nova_client.servers.add_security_group(instance_id, secgroup_id)
841         return True
842     except Exception, e:
843         logger.error("Error [add_secgroup_to_instance(nova_client, '%s', "
844                      "'%s')]: %s" % (instance_id, secgroup_id, e))
845         return False
846
847
848 def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
849     json_body = {"quota": {
850         "security_group": sg_quota,
851         "security_group_rule": sg_rule_quota
852     }}
853
854     try:
855         neutron_client.update_quota(tenant_id=tenant_id,
856                                     body=json_body)
857         return True
858     except Exception, e:
859         logger.error("Error [update_sg_quota(neutron_client, '%s', '%s', "
860                      "'%s')]: %s" % (tenant_id, sg_quota, sg_rule_quota, e))
861         return False
862
863
864 def delete_security_group(neutron_client, secgroup_id):
865     try:
866         neutron_client.delete_security_group(secgroup_id)
867         return True
868     except Exception, e:
869         logger.error("Error [delete_security_group(neutron_client, '%s')]: %s"
870                      % (secgroup_id, e))
871         return False
872
873
874 # *********************************************
875 #   GLANCE
876 # *********************************************
877 def get_images(nova_client):
878     try:
879         images = nova_client.images.list()
880         return images
881     except Exception, e:
882         logger.error("Error [get_images]: %s" % e)
883         return None
884
885
886 def get_image_id(glance_client, image_name):
887     images = glance_client.images.list()
888     id = ''
889     for i in images:
890         if i.name == image_name:
891             id = i.id
892             break
893     return id
894
895
896 def create_glance_image(glance_client, image_name, file_path, disk="qcow2",
897                         container="bare", public=True):
898     if not os.path.isfile(file_path):
899         logger.error("Error: file %s does not exist." % file_path)
900         return None
901     try:
902         image_id = get_image_id(glance_client, image_name)
903         if image_id != '':
904             if logger:
905                 logger.info("Image %s already exists." % image_name)
906         else:
907             if logger:
908                 logger.info("Creating image '%s' from '%s'..." % (image_name,
909                                                                   file_path))
910             properties = {}
911             deploy_scenario = os.environ.get('DEPLOY_SCENARIO')
912             if deploy_scenario is not None and 'fdio' in deploy_scenario:
913                 properties['hw_mem_page_size'] = 'large'
914             with open(file_path) as fimage:
915                 image = glance_client.images.create(name=image_name,
916                                                     is_public=public,
917                                                     disk_format=disk,
918                                                     container_format=container,
919                                                     properties=properties,
920                                                     data=fimage)
921             image_id = image.id
922         return image_id
923     except Exception, e:
924         logger.error("Error [create_glance_image(glance_client, '%s', '%s', "
925                      "'%s')]: %s" % (image_name, file_path, str(public), e))
926         return None
927
928
929 def get_or_create_image(name, path, format):
930     image_exists = False
931     glance_client = get_glance_client()
932
933     image_id = get_image_id(glance_client, name)
934     if image_id != '':
935         logger.info("Using existing image '%s'..." % name)
936         image_exists = True
937     else:
938         logger.info("Creating image '%s' from '%s'..." % (name, path))
939         image_id = create_glance_image(glance_client, name, path, format)
940         if not image_id:
941             logger.error("Failed to create a Glance image...")
942         else:
943             logger.debug("Image '%s' with ID=%s created successfully."
944                          % (name, image_id))
945
946     return image_exists, image_id
947
948
949 def delete_glance_image(nova_client, image_id):
950     try:
951         nova_client.images.delete(image_id)
952         return True
953     except Exception, e:
954         logger.error("Error [delete_glance_image(nova_client, '%s')]: %s"
955                      % (image_id, e))
956         return False
957
958
959 # *********************************************
960 #   CINDER
961 # *********************************************
962 def get_volumes(cinder_client):
963     try:
964         volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
965         return volumes
966     except Exception, e:
967         logger.error("Error [get_volumes(cinder_client)]: %s" % e)
968         return None
969
970
971 def list_volume_types(cinder_client, public=True, private=True):
972     try:
973         volume_types = cinder_client.volume_types.list()
974         if not public:
975             volume_types = [vt for vt in volume_types if not vt.is_public]
976         if not private:
977             volume_types = [vt for vt in volume_types if vt.is_public]
978         return volume_types
979     except Exception, e:
980         logger.error("Error [list_volume_types(cinder_client)]: %s" % e)
981         return None
982
983
984 def create_volume_type(cinder_client, name):
985     try:
986         volume_type = cinder_client.volume_types.create(name)
987         return volume_type
988     except Exception, e:
989         logger.error("Error [create_volume_type(cinder_client, '%s')]: %s"
990                      % (name, e))
991         return None
992
993
994 def update_cinder_quota(cinder_client, tenant_id, vols_quota,
995                         snapshots_quota, gigabytes_quota):
996     quotas_values = {"volumes": vols_quota,
997                      "snapshots": snapshots_quota,
998                      "gigabytes": gigabytes_quota}
999
1000     try:
1001         cinder_client.quotas.update(tenant_id, **quotas_values)
1002         return True
1003     except Exception, e:
1004         logger.error("Error [update_cinder_quota(cinder_client, '%s', '%s', "
1005                      "'%s' '%s')]: %s" % (tenant_id, vols_quota,
1006                                           snapshots_quota, gigabytes_quota, e))
1007         return False
1008
1009
1010 def delete_volume(cinder_client, volume_id, forced=False):
1011     try:
1012         if forced:
1013             try:
1014                 cinder_client.volumes.detach(volume_id)
1015             except:
1016                 logger.error(sys.exc_info()[0])
1017             cinder_client.volumes.force_delete(volume_id)
1018         else:
1019             cinder_client.volumes.delete(volume_id)
1020         return True
1021     except Exception, e:
1022         logger.error("Error [delete_volume(cinder_client, '%s', '%s')]: %s"
1023                      % (volume_id, str(forced), e))
1024         return False
1025
1026
1027 def delete_volume_type(cinder_client, volume_type):
1028     try:
1029         cinder_client.volume_types.delete(volume_type)
1030         return True
1031     except Exception, e:
1032         logger.error("Error [delete_volume_type(cinder_client, '%s')]: %s"
1033                      % (volume_type, e))
1034         return False
1035
1036
1037 # *********************************************
1038 #   KEYSTONE
1039 # *********************************************
1040 def get_tenants(keystone_client):
1041     try:
1042         tenants = keystone_client.tenants.list()
1043         return tenants
1044     except Exception, e:
1045         logger.error("Error [get_tenants(keystone_client)]: %s" % e)
1046         return None
1047
1048
1049 def get_users(keystone_client):
1050     try:
1051         users = keystone_client.users.list()
1052         return users
1053     except Exception, e:
1054         logger.error("Error [get_users(keystone_client)]: %s" % e)
1055         return None
1056
1057
1058 def get_tenant_id(keystone_client, tenant_name):
1059     tenants = keystone_client.tenants.list()
1060     id = ''
1061     for t in tenants:
1062         if t.name == tenant_name:
1063             id = t.id
1064             break
1065     return id
1066
1067
1068 def get_user_id(keystone_client, user_name):
1069     users = keystone_client.users.list()
1070     id = ''
1071     for u in users:
1072         if u.name == user_name:
1073             id = u.id
1074             break
1075     return id
1076
1077
1078 def get_role_id(keystone_client, role_name):
1079     roles = keystone_client.roles.list()
1080     id = ''
1081     for r in roles:
1082         if r.name == role_name:
1083             id = r.id
1084             break
1085     return id
1086
1087
1088 def create_tenant(keystone_client, tenant_name, tenant_description):
1089     try:
1090         tenant = keystone_client.tenants.create(tenant_name,
1091                                                 tenant_description,
1092                                                 enabled=True)
1093         return tenant.id
1094     except Exception, e:
1095         logger.error("Error [create_tenant(keystone_client, '%s', '%s')]: %s"
1096                      % (tenant_name, tenant_description, e))
1097         return None
1098
1099
1100 def create_user(keystone_client, user_name, user_password,
1101                 user_email, tenant_id):
1102     try:
1103         user = keystone_client.users.create(user_name, user_password,
1104                                             user_email, tenant_id,
1105                                             enabled=True)
1106         return user.id
1107     except Exception, e:
1108         logger.error("Error [create_user(keystone_client, '%s', '%s', '%s'"
1109                      "'%s')]: %s" % (user_name, user_password,
1110                                      user_email, tenant_id, e))
1111         return None
1112
1113
1114 def add_role_user(keystone_client, user_id, role_id, tenant_id):
1115     try:
1116         keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
1117         return True
1118     except Exception, e:
1119         logger.error("Error [add_role_user(keystone_client, '%s', '%s'"
1120                      "'%s')]: %s " % (user_id, role_id, tenant_id, e))
1121         return False
1122
1123
1124 def delete_tenant(keystone_client, tenant_id):
1125     try:
1126         keystone_client.tenants.delete(tenant_id)
1127         return True
1128     except Exception, e:
1129         logger.error("Error [delete_tenant(keystone_client, '%s')]: %s"
1130                      % (tenant_id, e))
1131         return False
1132
1133
1134 def delete_user(keystone_client, user_id):
1135     try:
1136         keystone_client.users.delete(user_id)
1137         return True
1138     except Exception, e:
1139         logger.error("Error [delete_user(keystone_client, '%s')]: %s"
1140                      % (user_id, e))
1141         return False