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