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