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