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