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