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
17 from keystoneauth1 import loading
18 from keystoneauth1 import session
19 from cinderclient import client as cinderclient
20 from glanceclient import client as glanceclient
21 from heatclient import client as heatclient
22 from novaclient import client as novaclient
23 from keystoneclient import client as keystoneclient
24 from neutronclient.neutron import client as neutronclient
26 from functest.utils.constants import CONST
27 import functest.utils.functest_utils as ft_utils
29 logger = logging.getLogger(__name__)
31 DEFAULT_API_VERSION = '2'
32 DEFAULT_HEAT_API_VERSION = '1'
35 # *********************************************
37 # *********************************************
38 class MissingEnvVar(Exception):
40 def __init__(self, var):
44 return str.format("Please set the mandatory env var: {}", self.var)
48 keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
49 if (keystone_api_version is None or
50 keystone_api_version == '2'):
56 def get_rc_env_vars():
57 env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD']
59 env_vars.extend(['OS_PROJECT_NAME',
60 'OS_USER_DOMAIN_NAME',
61 'OS_PROJECT_DOMAIN_NAME'])
63 env_vars.extend(['OS_TENANT_NAME'])
67 def check_credentials():
69 Check if the OpenStack credentials (openrc) are sourced
71 env_vars = get_rc_env_vars()
72 return all(map(lambda v: v in os.environ and os.environ[v], env_vars))
75 def get_env_cred_dict():
77 'OS_USERNAME': 'username',
78 'OS_PASSWORD': 'password',
79 'OS_AUTH_URL': 'auth_url',
80 'OS_TENANT_NAME': 'tenant_name',
81 'OS_USER_DOMAIN_NAME': 'user_domain_name',
82 'OS_PROJECT_DOMAIN_NAME': 'project_domain_name',
83 'OS_PROJECT_NAME': 'project_name',
84 'OS_ENDPOINT_TYPE': 'endpoint_type',
85 'OS_REGION_NAME': 'region_name',
86 'OS_CACERT': 'https_cacert',
87 'OS_INSECURE': 'https_insecure'
92 def get_credentials(other_creds={}):
93 """Returns a creds dictionary filled with parsed from env
96 env_vars = get_rc_env_vars()
97 env_cred_dict = get_env_cred_dict()
99 for envvar in env_vars:
100 if os.getenv(envvar) is None:
101 raise MissingEnvVar(envvar)
103 creds_key = env_cred_dict.get(envvar)
104 creds.update({creds_key: os.getenv(envvar)})
106 if 'tenant' in other_creds.keys():
108 tenant = 'project_name'
110 tenant = 'tenant_name'
111 other_creds[tenant] = other_creds.pop('tenant')
113 creds.update(other_creds)
118 def source_credentials(rc_file):
119 with open(rc_file, "r") as f:
121 var = (line.rstrip('"\n').replace('export ', '').split("=")
122 if re.search(r'(.*)=(.*)', line) else None)
123 # The two next lines should be modified as soon as rc_file
124 # conforms with common rules. Be aware that it could induce
125 # issues if value starts with '
127 key = re.sub(r'^["\' ]*|[ \'"]*$', '', var[0])
128 value = re.sub(r'^["\' ]*|[ \'"]*$', '', "".join(var[1:]))
129 os.environ[key] = value
130 CONST.__setattr__(key, value)
133 def get_session_auth(other_creds={}):
134 loader = loading.get_plugin_loader('password')
135 creds = get_credentials(other_creds)
136 auth = loader.load_from_options(**creds)
140 def get_endpoint(service_type, interface='public'):
141 auth = get_session_auth()
142 return get_session().get_endpoint(auth=auth,
143 service_type=service_type,
147 def get_session(other_creds={}):
148 auth = get_session_auth(other_creds)
149 https_cacert = os.getenv('OS_CACERT', '')
150 https_insecure = os.getenv('OS_INSECURE', '').lower() == 'true'
151 return session.Session(auth=auth,
152 verify=(https_cacert or not https_insecure))
155 # *********************************************
157 # *********************************************
158 def get_keystone_client_version():
159 api_version = os.getenv('OS_IDENTITY_API_VERSION')
160 if api_version is not None:
161 logger.info("OS_IDENTITY_API_VERSION is set in env as '%s'",
164 return DEFAULT_API_VERSION
167 def get_keystone_client(other_creds={}):
168 sess = get_session(other_creds)
169 return keystoneclient.Client(get_keystone_client_version(),
171 interface=os.getenv('OS_INTERFACE', 'admin'))
174 def get_nova_client_version():
175 api_version = os.getenv('OS_COMPUTE_API_VERSION')
176 if api_version is not None:
177 logger.info("OS_COMPUTE_API_VERSION is set in env as '%s'",
180 return DEFAULT_API_VERSION
183 def get_nova_client(other_creds={}):
184 sess = get_session(other_creds)
185 return novaclient.Client(get_nova_client_version(), session=sess)
188 def get_cinder_client_version():
189 api_version = os.getenv('OS_VOLUME_API_VERSION')
190 if api_version is not None:
191 logger.info("OS_VOLUME_API_VERSION is set in env as '%s'",
194 return DEFAULT_API_VERSION
197 def get_cinder_client(other_creds={}):
198 sess = get_session(other_creds)
199 return cinderclient.Client(get_cinder_client_version(), session=sess)
202 def get_neutron_client_version():
203 api_version = os.getenv('OS_NETWORK_API_VERSION')
204 if api_version is not None:
205 logger.info("OS_NETWORK_API_VERSION is set in env as '%s'",
208 return DEFAULT_API_VERSION
211 def get_neutron_client(other_creds={}):
212 sess = get_session(other_creds)
213 return neutronclient.Client(get_neutron_client_version(), session=sess)
216 def get_glance_client_version():
217 api_version = os.getenv('OS_IMAGE_API_VERSION')
218 if api_version is not None:
219 logger.info("OS_IMAGE_API_VERSION is set in env as '%s'", api_version)
221 return DEFAULT_API_VERSION
224 def get_glance_client(other_creds={}):
225 sess = get_session(other_creds)
226 return glanceclient.Client(get_glance_client_version(), session=sess)
229 def get_heat_client_version():
230 api_version = os.getenv('OS_ORCHESTRATION_API_VERSION')
231 if api_version is not None:
232 logger.info("OS_ORCHESTRATION_API_VERSION is set in env as '%s'",
235 return DEFAULT_HEAT_API_VERSION
238 def get_heat_client(other_creds={}):
239 sess = get_session(other_creds)
240 return heatclient.Client(get_heat_client_version(), session=sess)
243 def download_and_add_image_on_glance(glance, image_name, image_url, data_dir):
246 if not os.path.exists(dest_path):
247 os.makedirs(dest_path)
248 file_name = image_url.rsplit('/')[-1]
249 if not ft_utils.download_url(image_url, dest_path):
252 raise Exception("Impossible to download image from {}".format(
256 image = create_glance_image(
257 glance, image_name, dest_path + file_name)
263 raise Exception("Impossible to put image {} in glance".format(
267 # *********************************************
269 # *********************************************
270 def get_instances(nova_client):
272 instances = nova_client.servers.list(search_opts={'all_tenants': 1})
274 except Exception as e:
275 logger.error("Error [get_instances(nova_client)]: %s" % e)
279 def get_instance_status(nova_client, instance):
281 instance = nova_client.servers.get(instance.id)
282 return instance.status
283 except Exception as e:
284 logger.error("Error [get_instance_status(nova_client)]: %s" % e)
288 def get_instance_by_name(nova_client, instance_name):
290 instance = nova_client.servers.find(name=instance_name)
292 except Exception as e:
293 logger.error("Error [get_instance_by_name(nova_client, '%s')]: %s"
294 % (instance_name, e))
298 def get_flavor_id(nova_client, flavor_name):
299 flavors = nova_client.flavors.list(detailed=True)
302 if f.name == flavor_name:
308 def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram):
309 flavors = nova_client.flavors.list(detailed=True)
312 if min_ram <= f.ram and f.ram <= max_ram:
318 def get_aggregates(nova_client):
320 aggregates = nova_client.aggregates.list()
322 except Exception as e:
323 logger.error("Error [get_aggregates(nova_client)]: %s" % e)
327 def get_aggregate_id(nova_client, aggregate_name):
329 aggregates = get_aggregates(nova_client)
330 _id = [ag.id for ag in aggregates if ag.name == aggregate_name][0]
332 except Exception as e:
333 logger.error("Error [get_aggregate_id(nova_client, %s)]:"
334 " %s" % (aggregate_name, e))
338 def get_availability_zones(nova_client):
340 availability_zones = nova_client.availability_zones.list()
341 return availability_zones
342 except Exception as e:
343 logger.error("Error [get_availability_zones(nova_client)]: %s" % e)
347 def get_availability_zone_names(nova_client):
349 az_names = [az.zoneName for az in get_availability_zones(nova_client)]
351 except Exception as e:
352 logger.error("Error [get_availability_zone_names(nova_client)]:"
357 def create_flavor(nova_client, flavor_name, ram, disk, vcpus, public=True):
359 flavor = nova_client.flavors.create(
360 flavor_name, ram, vcpus, disk, is_public=public)
362 extra_specs = ft_utils.get_functest_config(
363 'general.flavor_extra_specs')
364 flavor.set_keys(extra_specs)
366 # flavor extra specs are not configured, therefore skip the update
369 except Exception as e:
370 logger.error("Error [create_flavor(nova_client, '%s', '%s', '%s', "
371 "'%s')]: %s" % (flavor_name, ram, disk, vcpus, e))
376 def get_or_create_flavor(flavor_name, ram, disk, vcpus, public=True):
377 flavor_exists = False
378 nova_client = get_nova_client()
380 flavor_id = get_flavor_id(nova_client, flavor_name)
382 logger.info("Using existing flavor '%s'..." % flavor_name)
385 logger.info("Creating flavor '%s' with '%s' RAM, '%s' disk size, "
386 "'%s' vcpus..." % (flavor_name, ram, disk, vcpus))
387 flavor_id = create_flavor(
388 nova_client, flavor_name, ram, disk, vcpus, public=public)
390 raise Exception("Failed to create flavor '%s'..." % (flavor_name))
392 logger.debug("Flavor '%s' with ID=%s created successfully."
393 % (flavor_name, flavor_id))
395 return flavor_exists, flavor_id
398 def get_floating_ips(neutron_client):
400 floating_ips = neutron_client.list_floatingips()
401 return floating_ips['floatingips']
402 except Exception as e:
403 logger.error("Error [get_floating_ips(neutron_client)]: %s" % e)
407 def get_hypervisors(nova_client):
410 hypervisors = nova_client.hypervisors.list()
411 for hypervisor in hypervisors:
412 if hypervisor.state == "up":
413 nodes.append(hypervisor.hypervisor_hostname)
415 except Exception as e:
416 logger.error("Error [get_hypervisors(nova_client)]: %s" % e)
420 def create_aggregate(nova_client, aggregate_name, av_zone):
422 nova_client.aggregates.create(aggregate_name, av_zone)
424 except Exception as e:
425 logger.error("Error [create_aggregate(nova_client, %s, %s)]: %s"
426 % (aggregate_name, av_zone, e))
430 def add_host_to_aggregate(nova_client, aggregate_name, compute_host):
432 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
433 nova_client.aggregates.add_host(aggregate_id, compute_host)
435 except Exception as e:
436 logger.error("Error [add_host_to_aggregate(nova_client, %s, %s)]: %s"
437 % (aggregate_name, compute_host, e))
441 def create_aggregate_with_host(
442 nova_client, aggregate_name, av_zone, compute_host):
444 create_aggregate(nova_client, aggregate_name, av_zone)
445 add_host_to_aggregate(nova_client, aggregate_name, compute_host)
447 except Exception as e:
448 logger.error("Error [create_aggregate_with_host("
449 "nova_client, %s, %s, %s)]: %s"
450 % (aggregate_name, av_zone, compute_host, e))
454 def create_instance(flavor_name,
457 instance_name="functest-vm",
463 nova_client = get_nova_client()
465 flavor = nova_client.flavors.find(name=flavor_name)
467 flavors = nova_client.flavors.list()
468 logger.error("Error: Flavor '%s' not found. Available flavors are: "
469 "\n%s" % (flavor_name, flavors))
471 if fixed_ip is not None:
472 nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip}
474 nics = {"net-id": network_id}
476 instance = nova_client.servers.create(
481 availability_zone=av_zone,
485 instance = nova_client.servers.create(
490 config_drive=confdrive,
492 availability_zone=av_zone,
498 def create_instance_and_wait_for_active(flavor_name,
508 VM_BOOT_TIMEOUT = 180
509 nova_client = get_nova_client()
510 instance = create_instance(flavor_name,
519 count = VM_BOOT_TIMEOUT / SLEEP
520 for n in range(count, -1, -1):
521 status = get_instance_status(nova_client, instance)
522 if status.lower() == "active":
524 elif status.lower() == "error":
525 logger.error("The instance %s went to ERROR status."
529 logger.error("Timeout booting the instance %s." % instance_name)
533 def create_floating_ip(neutron_client):
534 extnet_id = get_external_net_id(neutron_client)
535 props = {'floating_network_id': extnet_id}
537 ip_json = neutron_client.create_floatingip({'floatingip': props})
538 fip_addr = ip_json['floatingip']['floating_ip_address']
539 fip_id = ip_json['floatingip']['id']
540 except Exception as e:
541 logger.error("Error [create_floating_ip(neutron_client)]: %s" % e)
543 return {'fip_addr': fip_addr, 'fip_id': fip_id}
546 def add_floating_ip(nova_client, server_id, floatingip_addr):
548 nova_client.servers.add_floating_ip(server_id, floatingip_addr)
550 except Exception as e:
551 logger.error("Error [add_floating_ip(nova_client, '%s', '%s')]: %s"
552 % (server_id, floatingip_addr, e))
556 def delete_instance(nova_client, instance_id):
558 nova_client.servers.force_delete(instance_id)
560 except Exception as e:
561 logger.error("Error [delete_instance(nova_client, '%s')]: %s"
566 def delete_floating_ip(neutron_client, floatingip_id):
568 neutron_client.delete_floatingip(floatingip_id)
570 except Exception as e:
571 logger.error("Error [delete_floating_ip(neutron_client, '%s')]: %s"
572 % (floatingip_id, e))
576 def remove_host_from_aggregate(nova_client, aggregate_name, compute_host):
578 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
579 nova_client.aggregates.remove_host(aggregate_id, compute_host)
581 except Exception as e:
582 logger.error("Error [remove_host_from_aggregate(nova_client, %s, %s)]:"
583 " %s" % (aggregate_name, compute_host, e))
587 def remove_hosts_from_aggregate(nova_client, aggregate_name):
588 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
589 hosts = nova_client.aggregates.get(aggregate_id).hosts
591 all(remove_host_from_aggregate(nova_client, aggregate_name, host)
595 def delete_aggregate(nova_client, aggregate_name):
597 remove_hosts_from_aggregate(nova_client, aggregate_name)
598 nova_client.aggregates.delete(aggregate_name)
600 except Exception as e:
601 logger.error("Error [delete_aggregate(nova_client, %s)]: %s"
602 % (aggregate_name, e))
606 # *********************************************
608 # *********************************************
609 def get_network_list(neutron_client):
610 network_list = neutron_client.list_networks()['networks']
611 if len(network_list) == 0:
617 def get_router_list(neutron_client):
618 router_list = neutron_client.list_routers()['routers']
619 if len(router_list) == 0:
625 def get_port_list(neutron_client):
626 port_list = neutron_client.list_ports()['ports']
627 if len(port_list) == 0:
633 def get_network_id(neutron_client, network_name):
634 networks = neutron_client.list_networks()['networks']
637 if n['name'] == network_name:
643 def get_subnet_id(neutron_client, subnet_name):
644 subnets = neutron_client.list_subnets()['subnets']
647 if s['name'] == subnet_name:
653 def get_router_id(neutron_client, router_name):
654 routers = neutron_client.list_routers()['routers']
657 if r['name'] == router_name:
663 def get_private_net(neutron_client):
664 # Checks if there is an existing shared private network
665 networks = neutron_client.list_networks()['networks']
666 if len(networks) == 0:
669 if (net['router:external'] is False) and (net['shared'] is True):
674 def get_external_net(neutron_client):
675 if (hasattr(CONST, 'EXTERNAL_NETWORK')):
676 return CONST.__getattribute__('EXTERNAL_NETWORK')
677 for network in neutron_client.list_networks()['networks']:
678 if network['router:external']:
679 return network['name']
683 def get_external_net_id(neutron_client):
684 if (hasattr(CONST, 'EXTERNAL_NETWORK')):
685 networks = neutron_client.list_networks(
686 name=CONST.__getattribute__('EXTERNAL_NETWORK'))
687 net_id = networks['networks'][0]['id']
689 for network in neutron_client.list_networks()['networks']:
690 if network['router:external']:
695 def check_neutron_net(neutron_client, net_name):
696 for network in neutron_client.list_networks()['networks']:
697 if network['name'] == net_name:
698 for subnet in network['subnets']:
703 def create_neutron_net(neutron_client, name):
704 json_body = {'network': {'name': name,
705 'admin_state_up': True}}
707 network = neutron_client.create_network(body=json_body)
708 network_dict = network['network']
709 return network_dict['id']
710 except Exception as e:
711 logger.error("Error [create_neutron_net(neutron_client, '%s')]: %s"
716 def create_neutron_subnet(neutron_client, name, cidr, net_id,
717 dns=['8.8.8.8', '8.8.4.4']):
718 json_body = {'subnets': [{'name': name, 'cidr': cidr,
719 'ip_version': 4, 'network_id': net_id,
720 'dns_nameservers': dns}]}
723 subnet = neutron_client.create_subnet(body=json_body)
724 return subnet['subnets'][0]['id']
725 except Exception as e:
726 logger.error("Error [create_neutron_subnet(neutron_client, '%s', "
727 "'%s', '%s')]: %s" % (name, cidr, net_id, e))
731 def create_neutron_router(neutron_client, name):
732 json_body = {'router': {'name': name, 'admin_state_up': True}}
734 router = neutron_client.create_router(json_body)
735 return router['router']['id']
736 except Exception as e:
737 logger.error("Error [create_neutron_router(neutron_client, '%s')]: %s"
742 def create_neutron_port(neutron_client, name, network_id, ip):
743 json_body = {'port': {
744 'admin_state_up': True,
746 'network_id': network_id,
747 'fixed_ips': [{"ip_address": ip}]
750 port = neutron_client.create_port(body=json_body)
751 return port['port']['id']
752 except Exception as e:
753 logger.error("Error [create_neutron_port(neutron_client, '%s', '%s', "
754 "'%s')]: %s" % (name, network_id, ip, e))
758 def update_neutron_net(neutron_client, network_id, shared=False):
759 json_body = {'network': {'shared': shared}}
761 neutron_client.update_network(network_id, body=json_body)
763 except Exception as e:
764 logger.error("Error [update_neutron_net(neutron_client, '%s', '%s')]: "
765 "%s" % (network_id, str(shared), e))
769 def update_neutron_port(neutron_client, port_id, device_owner):
770 json_body = {'port': {
771 'device_owner': device_owner,
774 port = neutron_client.update_port(port=port_id,
776 return port['port']['id']
777 except Exception as e:
778 logger.error("Error [update_neutron_port(neutron_client, '%s', '%s')]:"
779 " %s" % (port_id, device_owner, e))
783 def add_interface_router(neutron_client, router_id, subnet_id):
784 json_body = {"subnet_id": subnet_id}
786 neutron_client.add_interface_router(router=router_id, body=json_body)
788 except Exception as e:
789 logger.error("Error [add_interface_router(neutron_client, '%s', "
790 "'%s')]: %s" % (router_id, subnet_id, e))
794 def add_gateway_router(neutron_client, router_id):
795 ext_net_id = get_external_net_id(neutron_client)
796 router_dict = {'network_id': ext_net_id}
798 neutron_client.add_gateway_router(router_id, router_dict)
800 except Exception as e:
801 logger.error("Error [add_gateway_router(neutron_client, '%s')]: %s"
806 def delete_neutron_net(neutron_client, network_id):
808 neutron_client.delete_network(network_id)
810 except Exception as e:
811 logger.error("Error [delete_neutron_net(neutron_client, '%s')]: %s"
816 def delete_neutron_subnet(neutron_client, subnet_id):
818 neutron_client.delete_subnet(subnet_id)
820 except Exception as e:
821 logger.error("Error [delete_neutron_subnet(neutron_client, '%s')]: %s"
826 def delete_neutron_router(neutron_client, router_id):
828 neutron_client.delete_router(router=router_id)
830 except Exception as e:
831 logger.error("Error [delete_neutron_router(neutron_client, '%s')]: %s"
836 def delete_neutron_port(neutron_client, port_id):
838 neutron_client.delete_port(port_id)
840 except Exception as e:
841 logger.error("Error [delete_neutron_port(neutron_client, '%s')]: %s"
846 def remove_interface_router(neutron_client, router_id, subnet_id):
847 json_body = {"subnet_id": subnet_id}
849 neutron_client.remove_interface_router(router=router_id,
852 except Exception as e:
853 logger.error("Error [remove_interface_router(neutron_client, '%s', "
854 "'%s')]: %s" % (router_id, subnet_id, e))
858 def remove_gateway_router(neutron_client, router_id):
860 neutron_client.remove_gateway_router(router_id)
862 except Exception as e:
863 logger.error("Error [remove_gateway_router(neutron_client, '%s')]: %s"
868 def create_network_full(neutron_client,
873 dns=['8.8.8.8', '8.8.4.4']):
875 # Check if the network already exists
876 network_id = get_network_id(neutron_client, net_name)
877 subnet_id = get_subnet_id(neutron_client, subnet_name)
878 router_id = get_router_id(neutron_client, router_name)
880 if network_id != '' and subnet_id != '' and router_id != '':
881 logger.info("A network with name '%s' already exists..." % net_name)
883 neutron_client.format = 'json'
884 logger.info('Creating neutron network %s...' % net_name)
885 network_id = create_neutron_net(neutron_client, net_name)
890 logger.debug("Network '%s' created successfully" % network_id)
891 logger.debug('Creating Subnet....')
892 subnet_id = create_neutron_subnet(neutron_client, subnet_name,
893 cidr, network_id, dns)
897 logger.debug("Subnet '%s' created successfully" % subnet_id)
898 logger.debug('Creating Router...')
899 router_id = create_neutron_router(neutron_client, router_name)
904 logger.debug("Router '%s' created successfully" % router_id)
905 logger.debug('Adding router to subnet...')
907 if not add_interface_router(neutron_client, router_id, subnet_id):
910 logger.debug("Interface added successfully.")
912 logger.debug('Adding gateway to router...')
913 if not add_gateway_router(neutron_client, router_id):
916 logger.debug("Gateway added successfully.")
918 network_dic = {'net_id': network_id,
919 'subnet_id': subnet_id,
920 'router_id': router_id}
924 def create_shared_network_full(net_name, subnt_name, router_name, subnet_cidr):
925 neutron_client = get_neutron_client()
927 network_dic = create_network_full(neutron_client,
933 if not update_neutron_net(neutron_client,
934 network_dic['net_id'],
936 logger.error("Failed to update network %s..." % net_name)
939 logger.debug("Network '%s' is available..." % net_name)
941 logger.error("Network %s creation failed" % net_name)
946 # *********************************************
948 # *********************************************
951 def get_security_groups(neutron_client):
953 security_groups = neutron_client.list_security_groups()[
955 return security_groups
956 except Exception as e:
957 logger.error("Error [get_security_groups(neutron_client)]: %s" % e)
961 def get_security_group_id(neutron_client, sg_name):
962 security_groups = get_security_groups(neutron_client)
964 for sg in security_groups:
965 if sg['name'] == sg_name:
971 def create_security_group(neutron_client, sg_name, sg_description):
972 json_body = {'security_group': {'name': sg_name,
973 'description': sg_description}}
975 secgroup = neutron_client.create_security_group(json_body)
976 return secgroup['security_group']
977 except Exception as e:
978 logger.error("Error [create_security_group(neutron_client, '%s', "
979 "'%s')]: %s" % (sg_name, sg_description, e))
983 def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
984 port_range_min=None, port_range_max=None):
985 # We create a security group in 2 steps
986 # 1 - we check the format and set the json body accordingly
987 # 2 - we call neturon client to create the security group
990 json_body = {'security_group_rule': {'direction': direction,
991 'security_group_id': sg_id,
992 'protocol': protocol}}
994 # - both None => we do nothing
995 # - both Not None => we add them to the json description
996 # but one cannot be None is the other is not None
997 if (port_range_min is not None and port_range_max is not None):
998 # add port_range in json description
999 json_body['security_group_rule']['port_range_min'] = port_range_min
1000 json_body['security_group_rule']['port_range_max'] = port_range_max
1001 logger.debug("Security_group format set (port range included)")
1003 # either both port range are set to None => do nothing
1004 # or one is set but not the other => log it and return False
1005 if port_range_min is None and port_range_max is None:
1006 logger.debug("Security_group format set (no port range mentioned)")
1008 logger.error("Bad security group format."
1009 "One of the port range is not properly set:"
1011 "range max: {}".format(port_range_min,
1015 # Create security group using neutron client
1017 neutron_client.create_security_group_rule(json_body)
1020 logger.exception("Impossible to create_security_group_rule,"
1021 "security group rule probably already exists")
1025 def get_security_group_rules(neutron_client, sg_id):
1027 security_rules = neutron_client.list_security_group_rules()[
1028 'security_group_rules']
1029 security_rules = [rule for rule in security_rules
1030 if rule["security_group_id"] == sg_id]
1031 return security_rules
1032 except Exception as e:
1033 logger.error("Error [get_security_group_rules(neutron_client, sg_id)]:"
1038 def check_security_group_rules(neutron_client, sg_id, direction, protocol,
1039 port_min=None, port_max=None):
1041 security_rules = get_security_group_rules(neutron_client, sg_id)
1042 security_rules = [rule for rule in security_rules
1043 if (rule["direction"].lower() == direction and
1044 rule["protocol"].lower() == protocol and
1045 rule["port_range_min"] == port_min and
1046 rule["port_range_max"] == port_max)]
1047 if len(security_rules) == 0:
1051 except Exception as e:
1052 logger.error("Error [check_security_group_rules("
1053 " neutron_client, sg_id, direction,"
1054 " protocol, port_min=None, port_max=None)]: "
1059 def create_security_group_full(neutron_client,
1060 sg_name, sg_description):
1061 sg_id = get_security_group_id(neutron_client, sg_name)
1063 logger.info("Using existing security group '%s'..." % sg_name)
1065 logger.info("Creating security group '%s'..." % sg_name)
1066 SECGROUP = create_security_group(neutron_client,
1070 logger.error("Failed to create the security group...")
1073 sg_id = SECGROUP['id']
1075 logger.debug("Security group '%s' with ID=%s created successfully."
1076 % (SECGROUP['name'], sg_id))
1078 logger.debug("Adding ICMP rules in security group '%s'..."
1080 if not create_secgroup_rule(neutron_client, sg_id,
1082 logger.error("Failed to create the security group rule...")
1085 logger.debug("Adding SSH rules in security group '%s'..."
1087 if not create_secgroup_rule(
1088 neutron_client, sg_id, 'ingress', 'tcp', '22', '22'):
1089 logger.error("Failed to create the security group rule...")
1092 if not create_secgroup_rule(
1093 neutron_client, sg_id, 'egress', 'tcp', '22', '22'):
1094 logger.error("Failed to create the security group rule...")
1099 def add_secgroup_to_instance(nova_client, instance_id, secgroup_id):
1101 nova_client.servers.add_security_group(instance_id, secgroup_id)
1103 except Exception as e:
1104 logger.error("Error [add_secgroup_to_instance(nova_client, '%s', "
1105 "'%s')]: %s" % (instance_id, secgroup_id, e))
1109 def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
1110 json_body = {"quota": {
1111 "security_group": sg_quota,
1112 "security_group_rule": sg_rule_quota
1116 neutron_client.update_quota(tenant_id=tenant_id,
1119 except Exception as e:
1120 logger.error("Error [update_sg_quota(neutron_client, '%s', '%s', "
1121 "'%s')]: %s" % (tenant_id, sg_quota, sg_rule_quota, e))
1125 def delete_security_group(neutron_client, secgroup_id):
1127 neutron_client.delete_security_group(secgroup_id)
1129 except Exception as e:
1130 logger.error("Error [delete_security_group(neutron_client, '%s')]: %s"
1135 # *********************************************
1137 # *********************************************
1138 def get_images(glance_client):
1140 images = glance_client.images.list()
1142 except Exception as e:
1143 logger.error("Error [get_images]: %s" % e)
1147 def get_image_id(glance_client, image_name):
1148 images = glance_client.images.list()
1151 if i.name == image_name:
1157 def create_glance_image(glance_client,
1161 extra_properties={},
1164 if not os.path.isfile(file_path):
1165 logger.error("Error: file %s does not exist." % file_path)
1168 image_id = get_image_id(glance_client, image_name)
1170 logger.info("Image %s already exists." % image_name)
1172 logger.info("Creating image '%s' from '%s'..." % (image_name,
1175 image = glance_client.images.create(name=image_name,
1178 container_format=container,
1181 with open(file_path) as image_data:
1182 glance_client.images.upload(image_id, image_data)
1184 except Exception as e:
1185 logger.error("Error [create_glance_image(glance_client, '%s', '%s', "
1186 "'%s')]: %s" % (image_name, file_path, public, e))
1190 def get_or_create_image(name, path, format, extra_properties):
1191 image_exists = False
1192 glance_client = get_glance_client()
1194 image_id = get_image_id(glance_client, name)
1196 logger.info("Using existing image '%s'..." % name)
1199 logger.info("Creating image '%s' from '%s'..." % (name, path))
1200 image_id = create_glance_image(glance_client,
1206 logger.error("Failed to create a Glance image...")
1208 logger.debug("Image '%s' with ID=%s created successfully."
1211 return image_exists, image_id
1214 def delete_glance_image(glance_client, image_id):
1216 glance_client.images.delete(image_id)
1218 except Exception as e:
1219 logger.error("Error [delete_glance_image(glance_client, '%s')]: %s"
1224 # *********************************************
1226 # *********************************************
1227 def get_volumes(cinder_client):
1229 volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
1231 except Exception as e:
1232 logger.error("Error [get_volumes(cinder_client)]: %s" % e)
1236 def update_cinder_quota(cinder_client, tenant_id, vols_quota,
1237 snapshots_quota, gigabytes_quota):
1238 quotas_values = {"volumes": vols_quota,
1239 "snapshots": snapshots_quota,
1240 "gigabytes": gigabytes_quota}
1243 cinder_client.quotas.update(tenant_id, **quotas_values)
1245 except Exception as e:
1246 logger.error("Error [update_cinder_quota(cinder_client, '%s', '%s', "
1247 "'%s' '%s')]: %s" % (tenant_id, vols_quota,
1248 snapshots_quota, gigabytes_quota, e))
1252 def delete_volume(cinder_client, volume_id, forced=False):
1256 cinder_client.volumes.detach(volume_id)
1258 logger.error(sys.exc_info()[0])
1259 cinder_client.volumes.force_delete(volume_id)
1261 cinder_client.volumes.delete(volume_id)
1263 except Exception as e:
1264 logger.error("Error [delete_volume(cinder_client, '%s', '%s')]: %s"
1265 % (volume_id, str(forced), e))
1269 # *********************************************
1271 # *********************************************
1272 def get_tenants(keystone_client):
1274 if is_keystone_v3():
1275 tenants = keystone_client.projects.list()
1277 tenants = keystone_client.tenants.list()
1279 except Exception as e:
1280 logger.error("Error [get_tenants(keystone_client)]: %s" % e)
1284 def get_users(keystone_client):
1286 users = keystone_client.users.list()
1288 except Exception as e:
1289 logger.error("Error [get_users(keystone_client)]: %s" % e)
1293 def get_tenant_id(keystone_client, tenant_name):
1294 tenants = get_tenants(keystone_client)
1297 if t.name == tenant_name:
1303 def get_user_id(keystone_client, user_name):
1304 users = get_users(keystone_client)
1307 if u.name == user_name:
1313 def get_role_id(keystone_client, role_name):
1314 roles = keystone_client.roles.list()
1317 if r.name == role_name:
1323 def get_domain_id(keystone_client, domain_name):
1324 domains = keystone_client.domains.list()
1327 if d.name == domain_name:
1333 def create_tenant(keystone_client, tenant_name, tenant_description):
1335 if is_keystone_v3():
1336 domain_name = CONST.__getattribute__('OS_PROJECT_DOMAIN_NAME')
1337 domain_id = get_domain_id(keystone_client, domain_name)
1338 tenant = keystone_client.projects.create(
1340 description=tenant_description,
1344 tenant = keystone_client.tenants.create(tenant_name,
1348 except Exception as e:
1349 logger.error("Error [create_tenant(keystone_client, '%s', '%s')]: %s"
1350 % (tenant_name, tenant_description, e))
1354 def get_or_create_tenant(keystone_client, tenant_name, tenant_description):
1355 tenant_id = get_tenant_id(keystone_client, tenant_name)
1357 tenant_id = create_tenant(keystone_client, tenant_name,
1363 def get_or_create_tenant_for_vnf(keystone_client, tenant_name,
1364 tenant_description):
1365 """Get or Create a Tenant
1368 keystone_client: keystone client reference
1369 tenant_name: the name of the tenant
1370 tenant_description: the description of the tenant
1372 return False if tenant retrieved though get
1373 return True if tenant created
1374 raise Exception if error during processing
1377 tenant_id = get_tenant_id(keystone_client, tenant_name)
1379 tenant_id = create_tenant(keystone_client, tenant_name,
1385 raise Exception("Impossible to create a Tenant for the VNF {}".format(
1389 def create_user(keystone_client, user_name, user_password,
1390 user_email, tenant_id):
1392 if is_keystone_v3():
1393 user = keystone_client.users.create(name=user_name,
1394 password=user_password,
1396 project_id=tenant_id,
1399 user = keystone_client.users.create(user_name,
1405 except Exception as e:
1406 logger.error("Error [create_user(keystone_client, '%s', '%s', '%s'"
1407 "'%s')]: %s" % (user_name, user_password,
1408 user_email, tenant_id, e))
1412 def get_or_create_user(keystone_client, user_name, user_password,
1413 tenant_id, user_email=None):
1414 user_id = get_user_id(keystone_client, user_name)
1416 user_id = create_user(keystone_client, user_name, user_password,
1417 user_email, tenant_id)
1421 def get_or_create_user_for_vnf(keystone_client, vnf_ref):
1422 """Get or Create user for VNF
1425 keystone_client: keystone client reference
1426 vnf_ref: VNF reference used as user name & password, tenant name
1428 return False if user retrieved through get
1429 return True if user created
1430 raise Exception if error during processing
1433 user_id = get_user_id(keystone_client, vnf_ref)
1434 tenant_id = get_tenant_id(keystone_client, vnf_ref)
1437 user_id = create_user(keystone_client, vnf_ref, vnf_ref,
1441 role_id = get_role_id(keystone_client, 'admin')
1442 tenant_id = get_tenant_id(keystone_client, vnf_ref)
1443 add_role_user(keystone_client, user_id, role_id, tenant_id)
1445 logger.warn("Cannot associate user to role admin on tenant")
1448 raise Exception("Impossible to create a user for the VNF {}".format(
1452 def add_role_user(keystone_client, user_id, role_id, tenant_id):
1454 if is_keystone_v3():
1455 keystone_client.roles.grant(role=role_id,
1459 keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
1461 except Exception as e:
1462 logger.error("Error [add_role_user(keystone_client, '%s', '%s'"
1463 "'%s')]: %s " % (user_id, role_id, tenant_id, e))
1467 def delete_tenant(keystone_client, tenant_id):
1469 if is_keystone_v3():
1470 keystone_client.projects.delete(tenant_id)
1472 keystone_client.tenants.delete(tenant_id)
1474 except Exception as e:
1475 logger.error("Error [delete_tenant(keystone_client, '%s')]: %s"
1480 def delete_user(keystone_client, user_id):
1482 keystone_client.users.delete(user_id)
1484 except Exception as e:
1485 logger.error("Error [delete_user(keystone_client, '%s')]: %s"
1490 # *********************************************
1492 # *********************************************
1493 def get_resource(heat_client, stack_id, resource):
1495 resources = heat_client.resources.get(stack_id, resource)
1497 except Exception as e:
1498 logger.error("Error [get_resource]: %s" % e)