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