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