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