refactor create shared network process to eliminate reduplicate
[functest.git] / 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 cinderclient import client as cinderclient
18 import functest.utils.functest_logger as ft_logger
19 from glanceclient import client as glanceclient
20 from keystoneclient.v2_0 import client as keystoneclient
21 from neutronclient.v2_0 import client as neutronclient
22 from novaclient import client as novaclient
23
24 logger = ft_logger.Logger("openstack_utils").getLogger()
25
26
27 # *********************************************
28 #   CREDENTIALS
29 # *********************************************
30 def check_credentials():
31     """
32     Check if the OpenStack credentials (openrc) are sourced
33     """
34     env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD', 'OS_TENANT_NAME']
35     return all(map(lambda v: v in os.environ and os.environ[v], env_vars))
36
37
38 def get_credentials(service):
39     """Returns a creds dictionary filled with the following keys:
40     * username
41     * password/api_key (depending on the service)
42     * tenant_name/project_id (depending on the service)
43     * auth_url
44     :param service: a string indicating the name of the service
45                     requesting the credentials.
46     """
47     creds = {}
48
49     # Check that the env vars exists:
50     envvars = ('OS_USERNAME', 'OS_PASSWORD', 'OS_AUTH_URL', 'OS_TENANT_NAME')
51     for envvar in envvars:
52         if os.getenv(envvar) is None:
53             logger.error("'%s' is not exported as an env variable." % envvar)
54             exit(-1)
55
56     # Unfortunately, each of the OpenStack client will request slightly
57     # different entries in their credentials dict.
58     if service.lower() in ("nova", "cinder"):
59         password = "api_key"
60         tenant = "project_id"
61     else:
62         password = "password"
63         tenant = "tenant_name"
64
65     # The most common way to pass these info to the script is to do it through
66     # environment variables.
67     creds.update({
68         "username": os.environ.get("OS_USERNAME"),
69         password: os.environ.get("OS_PASSWORD"),
70         "auth_url": os.environ.get("OS_AUTH_URL"),
71         tenant: os.environ.get("OS_TENANT_NAME")
72     })
73     if os.getenv('OS_ENDPOINT_TYPE') is not None:
74         creds.update({
75             "endpoint_type": os.environ.get("OS_ENDPOINT_TYPE")
76         })
77     if os.getenv('OS_REGION_NAME') is not None:
78         creds.update({
79             "region_name": os.environ.get("OS_REGION_NAME")
80         })
81     cacert = os.environ.get("OS_CACERT")
82     if cacert is not None:
83         # each openstack client uses differnt kwargs for this
84         creds.update({"cacert": cacert,
85                       "ca_cert": cacert,
86                       "https_ca_cert": cacert,
87                       "https_cacert": cacert,
88                       "ca_file": cacert})
89         creds.update({"insecure": "True", "https_insecure": "True"})
90         if not os.path.isfile(cacert):
91             logger.info("WARNING: The 'OS_CACERT' environment variable is "
92                         "set to %s but the file does not exist." % cacert)
93     return creds
94
95
96 def source_credentials(rc_file):
97     pipe = subprocess.Popen(". %s; env" % rc_file, stdout=subprocess.PIPE,
98                             shell=True)
99     output = pipe.communicate()[0]
100     env = dict((line.split("=", 1) for line in output.splitlines()))
101     os.environ.update(env)
102     return env
103
104
105 def get_credentials_for_rally():
106     creds = get_credentials("keystone")
107     admin_keys = ['username', 'tenant_name', 'password']
108     endpoint_types = [('internalURL', 'internal'),
109                       ('publicURL', 'public'), ('adminURL', 'admin')]
110     if 'endpoint_type' in creds.keys():
111         for k, v in endpoint_types:
112             if creds['endpoint_type'] == k:
113                 creds['endpoint_type'] = v
114     rally_conf = {"type": "ExistingCloud", "admin": {}}
115     for key in creds:
116         if key in admin_keys:
117             rally_conf['admin'][key] = creds[key]
118         else:
119             rally_conf[key] = creds[key]
120     return rally_conf
121
122
123 # *********************************************
124 #   CLIENTS
125 # *********************************************
126 def get_keystone_client():
127     creds_keystone = get_credentials("keystone")
128     return keystoneclient.Client(**creds_keystone)
129
130
131 def get_nova_client():
132     creds_nova = get_credentials("nova")
133     return novaclient.Client('2', **creds_nova)
134
135
136 def get_cinder_client():
137     creds_cinder = get_credentials("cinder")
138     creds_cinder.update({
139         "service_type": "volume"
140     })
141     return cinderclient.Client('2', **creds_cinder)
142
143
144 def get_neutron_client():
145     creds_neutron = get_credentials("neutron")
146     return neutronclient.Client(**creds_neutron)
147
148
149 def get_glance_client():
150     keystone_client = get_keystone_client()
151     glance_endpoint_type = 'publicURL'
152     os_endpoint_type = os.getenv('OS_ENDPOINT_TYPE')
153     if os_endpoint_type is not None:
154         glance_endpoint_type = os_endpoint_type
155     glance_endpoint = keystone_client.service_catalog.url_for(
156         service_type='image', endpoint_type=glance_endpoint_type)
157     return glanceclient.Client(1, glance_endpoint,
158                                token=keystone_client.auth_token)
159
160 # *********************************************
161 #   NOVA
162 # *********************************************
163
164
165 def get_instances(nova_client):
166     try:
167         instances = nova_client.servers.list(search_opts={'all_tenants': 1})
168         return instances
169     except Exception, e:
170         logger.error("Error [get_instances(nova_client)]: %s" % e)
171         return None
172
173
174 def get_instance_status(nova_client, instance):
175     try:
176         instance = nova_client.servers.get(instance.id)
177         return instance.status
178     except Exception, e:
179         logger.error("Error [get_instance_status(nova_client)]: %s" % e)
180         return None
181
182
183 def get_instance_by_name(nova_client, instance_name):
184     try:
185         instance = nova_client.servers.find(name=instance_name)
186         return instance
187     except Exception, e:
188         logger.error("Error [get_instance_by_name(nova_client, '%s')]: %s"
189                      % (instance_name, e))
190         return None
191
192
193 def get_flavor_id(nova_client, flavor_name):
194     flavors = nova_client.flavors.list(detailed=True)
195     id = ''
196     for f in flavors:
197         if f.name == flavor_name:
198             id = f.id
199             break
200     return id
201
202
203 def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram):
204     flavors = nova_client.flavors.list(detailed=True)
205     id = ''
206     for f in flavors:
207         if min_ram <= f.ram and f.ram <= max_ram:
208             id = f.id
209             break
210     return id
211
212
213 def get_floating_ips(nova_client):
214     try:
215         floating_ips = nova_client.floating_ips.list()
216         return floating_ips
217     except Exception, e:
218         logger.error("Error [get_floating_ips(nova_client)]: %s" % e)
219         return None
220
221
222 def get_hypervisors(nova_client):
223     try:
224         nodes = []
225         hypervisors = nova_client.hypervisors.list()
226         for hypervisor in hypervisors:
227             if hypervisor.state == "up":
228                 nodes.append(hypervisor.hypervisor_hostname)
229         return nodes
230     except Exception, e:
231         logger.error("Error [get_hypervisors(nova_client)]: %s" % e)
232         return None
233
234
235 def create_flavor(nova_client, flavor_name, ram, disk, vcpus):
236     try:
237         flavor = nova_client.flavors.create(flavor_name, ram, vcpus, disk)
238     except Exception, e:
239         logger.error("Error [create_flavor(nova_client, '%s', '%s', '%s', "
240                      "'%s')]: %s" % (flavor_name, ram, disk, vcpus, e))
241         return None
242     return flavor.id
243
244
245 def create_instance(flavor_name,
246                     image_id,
247                     network_id,
248                     instance_name="functest-vm",
249                     confdrive=True,
250                     userdata=None,
251                     av_zone='',
252                     fixed_ip=None,
253                     files=None):
254     nova_client = get_nova_client()
255     try:
256         flavor = nova_client.flavors.find(name=flavor_name)
257     except:
258         flavors = nova_client.flavors.list()
259         logger.error("Error: Flavor '%s' not found. Available flavors are: "
260                      "\n%s" % (flavor_name, flavors))
261         return None
262     if fixed_ip is not None:
263         nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip}
264     else:
265         nics = {"net-id": network_id}
266     if userdata is None:
267         instance = nova_client.servers.create(
268             name=instance_name,
269             flavor=flavor,
270             image=image_id,
271             nics=[nics],
272             availability_zone=av_zone,
273             files=files
274         )
275     else:
276         instance = nova_client.servers.create(
277             name=instance_name,
278             flavor=flavor,
279             image=image_id,
280             nics=[nics],
281             config_drive=confdrive,
282             userdata=userdata,
283             availability_zone=av_zone,
284             files=files
285         )
286     return instance
287
288
289 def create_instance_and_wait_for_active(flavor_name,
290                                         image_id,
291                                         network_id,
292                                         instance_name="",
293                                         config_drive=False,
294                                         userdata="",
295                                         av_zone='',
296                                         fixed_ip=None,
297                                         files=None):
298     SLEEP = 3
299     VM_BOOT_TIMEOUT = 180
300     nova_client = get_nova_client()
301     instance = create_instance(flavor_name,
302                                image_id,
303                                network_id,
304                                instance_name,
305                                config_drive,
306                                userdata,
307                                av_zone=av_zone,
308                                fixed_ip=fixed_ip,
309                                files=files)
310     count = VM_BOOT_TIMEOUT / SLEEP
311     for n in range(count, -1, -1):
312         status = get_instance_status(nova_client, instance)
313         if status.lower() == "active":
314             return instance
315         elif status.lower() == "error":
316             logger.error("The instance %s went to ERROR status."
317                          % instance_name)
318             return None
319         time.sleep(SLEEP)
320     logger.error("Timeout booting the instance %s." % instance_name)
321     return None
322
323
324 def create_floating_ip(neutron_client):
325     extnet_id = get_external_net_id(neutron_client)
326     props = {'floating_network_id': extnet_id}
327     try:
328         ip_json = neutron_client.create_floatingip({'floatingip': props})
329         fip_addr = ip_json['floatingip']['floating_ip_address']
330         fip_id = ip_json['floatingip']['id']
331     except Exception, e:
332         logger.error("Error [create_floating_ip(neutron_client)]: %s" % e)
333         return None
334     return {'fip_addr': fip_addr, 'fip_id': fip_id}
335
336
337 def add_floating_ip(nova_client, server_id, floatingip_id):
338     try:
339         nova_client.servers.add_floating_ip(server_id, floatingip_id)
340         return True
341     except Exception, e:
342         logger.error("Error [add_floating_ip(nova_client, '%s', '%s')]: %s"
343                      % (server_id, floatingip_id, e))
344         return False
345
346
347 def delete_instance(nova_client, instance_id):
348     try:
349         nova_client.servers.force_delete(instance_id)
350         return True
351     except Exception, e:
352         logger.error("Error [delete_instance(nova_client, '%s')]: %s"
353                      % (instance_id, e))
354         return False
355
356
357 def delete_floating_ip(nova_client, floatingip_id):
358     try:
359         nova_client.floating_ips.delete(floatingip_id)
360         return True
361     except Exception, e:
362         logger.error("Error [delete_floating_ip(nova_client, '%s')]:"
363                      % (floatingip_id, e))
364         return False
365
366
367 # *********************************************
368 #   NEUTRON
369 # *********************************************
370 def get_network_list(neutron_client):
371     network_list = neutron_client.list_networks()['networks']
372     if len(network_list) == 0:
373         return None
374     else:
375         return network_list
376
377
378 def get_router_list(neutron_client):
379     router_list = neutron_client.list_routers()['routers']
380     if len(router_list) == 0:
381         return None
382     else:
383         return router_list
384
385
386 def get_port_list(neutron_client):
387     port_list = neutron_client.list_ports()['ports']
388     if len(port_list) == 0:
389         return None
390     else:
391         return port_list
392
393
394 def get_network_id(neutron_client, network_name):
395     networks = neutron_client.list_networks()['networks']
396     id = ''
397     for n in networks:
398         if n['name'] == network_name:
399             id = n['id']
400             break
401     return id
402
403
404 def get_subnet_id(neutron_client, subnet_name):
405     subnets = neutron_client.list_subnets()['subnets']
406     id = ''
407     for s in subnets:
408         if s['name'] == subnet_name:
409             id = s['id']
410             break
411     return id
412
413
414 def get_router_id(neutron_client, router_name):
415     routers = neutron_client.list_routers()['routers']
416     id = ''
417     for r in routers:
418         if r['name'] == router_name:
419             id = r['id']
420             break
421     return id
422
423
424 def get_private_net(neutron_client):
425     # Checks if there is an existing shared private network
426     networks = neutron_client.list_networks()['networks']
427     if len(networks) == 0:
428         return None
429     for net in networks:
430         if (net['router:external'] is False) and (net['shared'] is True):
431             return net
432     return None
433
434
435 def get_external_net(neutron_client):
436     for network in neutron_client.list_networks()['networks']:
437         if network['router:external']:
438             return network['name']
439     return None
440
441
442 def get_external_net_id(neutron_client):
443     for network in neutron_client.list_networks()['networks']:
444         if network['router:external']:
445             return network['id']
446     return None
447
448
449 def check_neutron_net(neutron_client, net_name):
450     for network in neutron_client.list_networks()['networks']:
451         if network['name'] == net_name:
452             for subnet in network['subnets']:
453                 return True
454     return False
455
456
457 def create_neutron_net(neutron_client, name):
458     json_body = {'network': {'name': name,
459                              'admin_state_up': True}}
460     try:
461         network = neutron_client.create_network(body=json_body)
462         network_dict = network['network']
463         return network_dict['id']
464     except Exception, e:
465         logger.error("Error [create_neutron_net(neutron_client, '%s')]: %s"
466                      % (name, e))
467         return None
468
469
470 def create_neutron_subnet(neutron_client, name, cidr, net_id):
471     json_body = {'subnets': [{'name': name, 'cidr': cidr,
472                               'ip_version': 4, 'network_id': net_id}]}
473     try:
474         subnet = neutron_client.create_subnet(body=json_body)
475         return subnet['subnets'][0]['id']
476     except Exception, e:
477         logger.error("Error [create_neutron_subnet(neutron_client, '%s', "
478                      "'%s', '%s')]: %s" % (name, cidr, net_id, e))
479         return None
480
481
482 def create_neutron_router(neutron_client, name):
483     json_body = {'router': {'name': name, 'admin_state_up': True}}
484     try:
485         router = neutron_client.create_router(json_body)
486         return router['router']['id']
487     except Exception, e:
488         logger.error("Error [create_neutron_router(neutron_client, '%s')]: %s"
489                      % (name, e))
490         return None
491
492
493 def create_neutron_port(neutron_client, name, network_id, ip):
494     json_body = {'port': {
495                  'admin_state_up': True,
496                  'name': name,
497                  'network_id': network_id,
498                  'fixed_ips': [{"ip_address": ip}]
499                  }}
500     try:
501         port = neutron_client.create_port(body=json_body)
502         return port['port']['id']
503     except Exception, e:
504         logger.error("Error [create_neutron_port(neutron_client, '%s', '%s', "
505                      "'%s')]: %s" % (name, network_id, ip, e))
506         return None
507
508
509 def update_neutron_net(neutron_client, network_id, shared=False):
510     json_body = {'network': {'shared': shared}}
511     try:
512         neutron_client.update_network(network_id, body=json_body)
513         return True
514     except Exception, e:
515         logger.error("Error [update_neutron_net(neutron_client, '%s', '%s')]: "
516                      "%s" % (network_id, str(shared), e))
517         return False
518
519
520 def update_neutron_port(neutron_client, port_id, device_owner):
521     json_body = {'port': {
522                  'device_owner': device_owner,
523                  }}
524     try:
525         port = neutron_client.update_port(port=port_id,
526                                           body=json_body)
527         return port['port']['id']
528     except Exception, e:
529         logger.error("Error [update_neutron_port(neutron_client, '%s', '%s')]:"
530                      " %s" % (port_id, device_owner, e))
531         return None
532
533
534 def add_interface_router(neutron_client, router_id, subnet_id):
535     json_body = {"subnet_id": subnet_id}
536     try:
537         neutron_client.add_interface_router(router=router_id, body=json_body)
538         return True
539     except Exception, e:
540         logger.error("Error [add_interface_router(neutron_client, '%s', "
541                      "'%s')]: %s" % (router_id, subnet_id, e))
542         return False
543
544
545 def add_gateway_router(neutron_client, router_id):
546     ext_net_id = get_external_net_id(neutron_client)
547     router_dict = {'network_id': ext_net_id}
548     try:
549         neutron_client.add_gateway_router(router_id, router_dict)
550         return True
551     except Exception, e:
552         logger.error("Error [add_gateway_router(neutron_client, '%s')]: %s"
553                      % (router_id, e))
554         return False
555
556
557 def delete_neutron_net(neutron_client, network_id):
558     try:
559         neutron_client.delete_network(network_id)
560         return True
561     except Exception, e:
562         logger.error("Error [delete_neutron_net(neutron_client, '%s')]: %s"
563                      % (network_id, e))
564         return False
565
566
567 def delete_neutron_subnet(neutron_client, subnet_id):
568     try:
569         neutron_client.delete_subnet(subnet_id)
570         return True
571     except Exception, e:
572         logger.error("Error [delete_neutron_subnet(neutron_client, '%s')]: %s"
573                      % (subnet_id, e))
574         return False
575
576
577 def delete_neutron_router(neutron_client, router_id):
578     try:
579         neutron_client.delete_router(router=router_id)
580         return True
581     except Exception, e:
582         logger.error("Error [delete_neutron_router(neutron_client, '%s')]: %s"
583                      % (router_id, e))
584         return False
585
586
587 def delete_neutron_port(neutron_client, port_id):
588     try:
589         neutron_client.delete_port(port_id)
590         return True
591     except Exception, e:
592         logger.error("Error [delete_neutron_port(neutron_client, '%s')]: %s"
593                      % (port_id, e))
594         return False
595
596
597 def remove_interface_router(neutron_client, router_id, subnet_id):
598     json_body = {"subnet_id": subnet_id}
599     try:
600         neutron_client.remove_interface_router(router=router_id,
601                                                body=json_body)
602         return True
603     except Exception, e:
604         logger.error("Error [remove_interface_router(neutron_client, '%s', "
605                      "'%s')]: %s" % (router_id, subnet_id, e))
606         return False
607
608
609 def remove_gateway_router(neutron_client, router_id):
610     try:
611         neutron_client.remove_gateway_router(router_id)
612         return True
613     except Exception, e:
614         logger.error("Error [remove_gateway_router(neutron_client, '%s')]: %s"
615                      % (router_id, e))
616         return False
617
618
619 def create_network_full(neutron_client,
620                         net_name,
621                         subnet_name,
622                         router_name,
623                         cidr):
624
625     # Check if the network already exists
626     network_id = get_network_id(neutron_client, net_name)
627     subnet_id = get_subnet_id(neutron_client, subnet_name)
628     router_id = get_router_id(neutron_client, router_name)
629
630     if network_id != '' and subnet_id != '' and router_id != '':
631         logger.info("A network with name '%s' already exists..." % net_name)
632     else:
633         neutron_client.format = 'json'
634         logger.info('Creating neutron network %s...' % net_name)
635         network_id = create_neutron_net(neutron_client, net_name)
636
637         if not network_id:
638             return False
639
640         logger.debug("Network '%s' created successfully" % network_id)
641         logger.debug('Creating Subnet....')
642         subnet_id = create_neutron_subnet(neutron_client, subnet_name,
643                                           cidr, network_id)
644         if not subnet_id:
645             return None
646
647         logger.debug("Subnet '%s' created successfully" % subnet_id)
648         logger.debug('Creating Router...')
649         router_id = create_neutron_router(neutron_client, router_name)
650
651         if not router_id:
652             return None
653
654         logger.debug("Router '%s' created successfully" % router_id)
655         logger.debug('Adding router to subnet...')
656
657         if not add_interface_router(neutron_client, router_id, subnet_id):
658             return None
659
660         logger.debug("Interface added successfully.")
661
662         logger.debug('Adding gateway to router...')
663         if not add_gateway_router(neutron_client, router_id):
664             return None
665
666         logger.debug("Gateway added successfully.")
667
668     network_dic = {'net_id': network_id,
669                    'subnet_id': subnet_id,
670                    'router_id': router_id}
671     return network_dic
672
673
674 def create_shared_network_full(net_name, subnt_name, router_name, subnet_cidr):
675     neutron_client = get_neutron_client()
676
677     network_dic = create_network_full(neutron_client,
678                                       net_name,
679                                       subnt_name,
680                                       router_name,
681                                       subnet_cidr)
682     if network_dic:
683         if not update_neutron_net(neutron_client,
684                                   network_dic['net_id'],
685                                   shared=True):
686             logger.error("Failed to update network %s..." % net_name)
687             return None
688         else:
689             logger.debug("Network '%s' is available..." % net_name)
690     else:
691         logger.error("Network %s creation failed" % net_name)
692         return None
693     return network_dic
694
695
696 def create_bgpvpn(neutron_client, **kwargs):
697     # route_distinguishers
698     # route_targets
699     json_body = {"bgpvpn": kwargs}
700     return neutron_client.create_bgpvpn(json_body)
701
702
703 def create_network_association(neutron_client, bgpvpn_id, neutron_network_id):
704     json_body = {"network_association": {"network_id": neutron_network_id}}
705     return neutron_client.create_network_association(bgpvpn_id, json_body)
706
707
708 def update_bgpvpn(neutron_client, bgpvpn_id, **kwargs):
709     json_body = {"bgpvpn": kwargs}
710     return neutron_client.update_bgpvpn(bgpvpn_id, json_body)
711
712
713 def delete_bgpvpn(neutron_client, bgpvpn_id):
714     return neutron_client.delete_bgpvpn(bgpvpn_id)
715
716 # *********************************************
717 #   SEC GROUPS
718 # *********************************************
719
720
721 def get_security_groups(neutron_client):
722     try:
723         security_groups = neutron_client.list_security_groups()[
724             'security_groups']
725         return security_groups
726     except Exception, e:
727         logger.error("Error [get_security_groups(neutron_client)]: %s" % e)
728         return None
729
730
731 def get_security_group_id(neutron_client, sg_name):
732     security_groups = get_security_groups(neutron_client)
733     id = ''
734     for sg in security_groups:
735         if sg['name'] == sg_name:
736             id = sg['id']
737             break
738     return id
739
740
741 def create_security_group(neutron_client, sg_name, sg_description):
742     json_body = {'security_group': {'name': sg_name,
743                                     'description': sg_description}}
744     try:
745         secgroup = neutron_client.create_security_group(json_body)
746         return secgroup['security_group']
747     except Exception, e:
748         logger.error("Error [create_security_group(neutron_client, '%s', "
749                      "'%s')]: %s" % (sg_name, sg_description, e))
750         return None
751
752
753 def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
754                          port_range_min=None, port_range_max=None):
755     if port_range_min is None and port_range_max is None:
756         json_body = {'security_group_rule': {'direction': direction,
757                                              'security_group_id': sg_id,
758                                              'protocol': protocol}}
759     elif port_range_min is not None and port_range_max is not None:
760         json_body = {'security_group_rule': {'direction': direction,
761                                              'security_group_id': sg_id,
762                                              'port_range_min': port_range_min,
763                                              'port_range_max': port_range_max,
764                                              'protocol': protocol}}
765     else:
766         logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', "
767                      "'%s', '%s', '%s', '%s')]:" % (neutron_client,
768                                                     sg_id, direction,
769                                                     port_range_min,
770                                                     port_range_max,
771                                                     protocol),
772                      " Invalid values for port_range_min, port_range_max")
773         return False
774     try:
775         neutron_client.create_security_group_rule(json_body)
776         return True
777     except Exception, e:
778         logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', "
779                      "'%s', '%s', '%s', '%s')]: %s" % (neutron_client,
780                                                        sg_id,
781                                                        direction,
782                                                        port_range_min,
783                                                        port_range_max,
784                                                        protocol, e))
785         return False
786
787
788 def create_security_group_full(neutron_client,
789                                sg_name, sg_description):
790     sg_id = get_security_group_id(neutron_client, sg_name)
791     if sg_id != '':
792         logger.info("Using existing security group '%s'..." % sg_name)
793     else:
794         logger.info("Creating security group  '%s'..." % sg_name)
795         SECGROUP = create_security_group(neutron_client,
796                                          sg_name,
797                                          sg_description)
798         if not SECGROUP:
799             logger.error("Failed to create the security group...")
800             return None
801
802         sg_id = SECGROUP['id']
803
804         logger.debug("Security group '%s' with ID=%s created successfully."
805                      % (SECGROUP['name'], sg_id))
806
807         logger.debug("Adding ICMP rules in security group '%s'..."
808                      % sg_name)
809         if not create_secgroup_rule(neutron_client, sg_id,
810                                     'ingress', 'icmp'):
811             logger.error("Failed to create the security group rule...")
812             return None
813
814         logger.debug("Adding SSH rules in security group '%s'..."
815                      % sg_name)
816         if not create_secgroup_rule(
817                 neutron_client, sg_id, 'ingress', 'tcp', '22', '22'):
818             logger.error("Failed to create the security group rule...")
819             return None
820
821         if not create_secgroup_rule(
822                 neutron_client, sg_id, 'egress', 'tcp', '22', '22'):
823             logger.error("Failed to create the security group rule...")
824             return None
825     return sg_id
826
827
828 def add_secgroup_to_instance(nova_client, instance_id, secgroup_id):
829     try:
830         nova_client.servers.add_security_group(instance_id, secgroup_id)
831         return True
832     except Exception, e:
833         logger.error("Error [add_secgroup_to_instance(nova_client, '%s', "
834                      "'%s')]: %s" % (instance_id, secgroup_id, e))
835         return False
836
837
838 def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
839     json_body = {"quota": {
840         "security_group": sg_quota,
841         "security_group_rule": sg_rule_quota
842     }}
843
844     try:
845         neutron_client.update_quota(tenant_id=tenant_id,
846                                     body=json_body)
847         return True
848     except Exception, e:
849         logger.error("Error [update_sg_quota(neutron_client, '%s', '%s', "
850                      "'%s')]: %s" % (tenant_id, sg_quota, sg_rule_quota, e))
851         return False
852
853
854 def delete_security_group(neutron_client, secgroup_id):
855     try:
856         neutron_client.delete_security_group(secgroup_id)
857         return True
858     except Exception, e:
859         logger.error("Error [delete_security_group(neutron_client, '%s')]: %s"
860                      % (secgroup_id, e))
861         return False
862
863
864 # *********************************************
865 #   GLANCE
866 # *********************************************
867 def get_images(nova_client):
868     try:
869         images = nova_client.images.list()
870         return images
871     except Exception, e:
872         logger.error("Error [get_images]: %s" % e)
873         return None
874
875
876 def get_image_id(glance_client, image_name):
877     images = glance_client.images.list()
878     id = ''
879     for i in images:
880         if i.name == image_name:
881             id = i.id
882             break
883     return id
884
885
886 def create_glance_image(glance_client, image_name, file_path, disk="qcow2",
887                         container="bare", public=True):
888     if not os.path.isfile(file_path):
889         logger.error("Error: file %s does not exist." % file_path)
890         return None
891     try:
892         image_id = get_image_id(glance_client, image_name)
893         if image_id != '':
894             if logger:
895                 logger.info("Image %s already exists." % image_name)
896         else:
897             if logger:
898                 logger.info("Creating image '%s' from '%s'..." % (image_name,
899                                                                   file_path))
900             with open(file_path) as fimage:
901                 image = glance_client.images.create(name=image_name,
902                                                     is_public=public,
903                                                     disk_format=disk,
904                                                     container_format=container,
905                                                     data=fimage)
906             image_id = image.id
907         return image_id
908     except Exception, e:
909         logger.error("Error [create_glance_image(glance_client, '%s', '%s', "
910                      "'%s')]: %s" % (image_name, file_path, str(public), e))
911         return None
912
913
914 def get_or_create_image(name, path, format):
915     image_exists = False
916     glance_client = get_glance_client()
917
918     image_id = get_image_id(glance_client, name)
919     if image_id != '':
920         logger.info("Using existing image '%s'..." % name)
921         image_exists = True
922     else:
923         logger.info("Creating image '%s' from '%s'..." % (name, path))
924         image_id = create_glance_image(glance_client, name, path, format)
925         if not image_id:
926             logger.error("Failed to create a Glance image...")
927         else:
928             logger.debug("Image '%s' with ID=%s created successfully."
929                          % (name, image_id))
930
931     return image_exists, image_id
932
933
934 def delete_glance_image(nova_client, image_id):
935     try:
936         nova_client.images.delete(image_id)
937         return True
938     except Exception, e:
939         logger.error("Error [delete_glance_image(nova_client, '%s')]: %s"
940                      % (image_id, e))
941         return False
942
943
944 # *********************************************
945 #   CINDER
946 # *********************************************
947 def get_volumes(cinder_client):
948     try:
949         volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
950         return volumes
951     except Exception, e:
952         logger.error("Error [get_volumes(cinder_client)]: %s" % e)
953         return None
954
955
956 def list_volume_types(cinder_client, public=True, private=True):
957     try:
958         volume_types = cinder_client.volume_types.list()
959         if not public:
960             volume_types = [vt for vt in volume_types if not vt.is_public]
961         if not private:
962             volume_types = [vt for vt in volume_types if vt.is_public]
963         return volume_types
964     except Exception, e:
965         logger.error("Error [list_volume_types(cinder_client)]: %s" % e)
966         return None
967
968
969 def create_volume_type(cinder_client, name):
970     try:
971         volume_type = cinder_client.volume_types.create(name)
972         return volume_type
973     except Exception, e:
974         logger.error("Error [create_volume_type(cinder_client, '%s')]: %s"
975                      % (name, e))
976         return None
977
978
979 def update_cinder_quota(cinder_client, tenant_id, vols_quota,
980                         snapshots_quota, gigabytes_quota):
981     quotas_values = {"volumes": vols_quota,
982                      "snapshots": snapshots_quota,
983                      "gigabytes": gigabytes_quota}
984
985     try:
986         cinder_client.quotas.update(tenant_id, **quotas_values)
987         return True
988     except Exception, e:
989         logger.error("Error [update_cinder_quota(cinder_client, '%s', '%s', "
990                      "'%s' '%s')]: %s" % (tenant_id, vols_quota,
991                                           snapshots_quota, gigabytes_quota, e))
992         return False
993
994
995 def delete_volume(cinder_client, volume_id, forced=False):
996     try:
997         if forced:
998             try:
999                 cinder_client.volumes.detach(volume_id)
1000             except:
1001                 logger.error(sys.exc_info()[0])
1002             cinder_client.volumes.force_delete(volume_id)
1003         else:
1004             cinder_client.volumes.delete(volume_id)
1005         return True
1006     except Exception, e:
1007         logger.error("Error [delete_volume(cinder_client, '%s', '%s')]: %s"
1008                      % (volume_id, str(forced), e))
1009         return False
1010
1011
1012 def delete_volume_type(cinder_client, volume_type):
1013     try:
1014         cinder_client.volume_types.delete(volume_type)
1015         return True
1016     except Exception, e:
1017         logger.error("Error [delete_volume_type(cinder_client, '%s')]: %s"
1018                      % (volume_type, e))
1019         return False
1020
1021
1022 # *********************************************
1023 #   KEYSTONE
1024 # *********************************************
1025 def get_tenants(keystone_client):
1026     try:
1027         tenants = keystone_client.tenants.list()
1028         return tenants
1029     except Exception, e:
1030         logger.error("Error [get_tenants(keystone_client)]: %s" % e)
1031         return None
1032
1033
1034 def get_users(keystone_client):
1035     try:
1036         users = keystone_client.users.list()
1037         return users
1038     except Exception, e:
1039         logger.error("Error [get_users(keystone_client)]: %s" % e)
1040         return None
1041
1042
1043 def get_tenant_id(keystone_client, tenant_name):
1044     tenants = keystone_client.tenants.list()
1045     id = ''
1046     for t in tenants:
1047         if t.name == tenant_name:
1048             id = t.id
1049             break
1050     return id
1051
1052
1053 def get_user_id(keystone_client, user_name):
1054     users = keystone_client.users.list()
1055     id = ''
1056     for u in users:
1057         if u.name == user_name:
1058             id = u.id
1059             break
1060     return id
1061
1062
1063 def get_role_id(keystone_client, role_name):
1064     roles = keystone_client.roles.list()
1065     id = ''
1066     for r in roles:
1067         if r.name == role_name:
1068             id = r.id
1069             break
1070     return id
1071
1072
1073 def create_tenant(keystone_client, tenant_name, tenant_description):
1074     try:
1075         tenant = keystone_client.tenants.create(tenant_name,
1076                                                 tenant_description,
1077                                                 enabled=True)
1078         return tenant.id
1079     except Exception, e:
1080         logger.error("Error [create_tenant(cinder_client, '%s', '%s')]: %s"
1081                      % (tenant_name, tenant_description, e))
1082         return None
1083
1084
1085 def create_user(keystone_client, user_name, user_password,
1086                 user_email, tenant_id):
1087     try:
1088         user = keystone_client.users.create(user_name, user_password,
1089                                             user_email, tenant_id,
1090                                             enabled=True)
1091         return user.id
1092     except Exception, e:
1093         logger.error("Error [create_user(keystone_client, '%s', '%s', '%s'"
1094                      "'%s')]: %s" % (user_name, user_password,
1095                                      user_email, tenant_id, e))
1096         return None
1097
1098
1099 def add_role_user(keystone_client, user_id, role_id, tenant_id):
1100     try:
1101         keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
1102         return True
1103     except Exception, e:
1104         logger.error("Error [add_role_user(keystone_client, '%s', '%s'"
1105                      "'%s')]: %s " % (user_id, role_id, tenant_id, e))
1106         return False
1107
1108
1109 def delete_tenant(keystone_client, tenant_id):
1110     try:
1111         keystone_client.tenants.delete(tenant_id)
1112         return True
1113     except Exception, e:
1114         logger.error("Error [delete_tenant(keystone_client, '%s')]: %s"
1115                      % (tenant_id, e))
1116         return False
1117
1118
1119 def delete_user(keystone_client, user_id):
1120     try:
1121         keystone_client.users.delete(user_id)
1122         return True
1123     except Exception, e:
1124         logger.error("Error [delete_user(keystone_client, '%s')]: %s"
1125                      % (user_id, e))
1126         return False