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