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