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
132 def get_credentials_for_rally():
133 creds = get_credentials()
134 env_cred_dict = get_env_cred_dict()
135 rally_conf = {"type": "ExistingCloud", "admin": {}}
137 if key == 'auth_url':
138 rally_conf[key] = creds[key]
140 rally_conf['admin'][key] = creds[key]
142 endpoint_types = [('internalURL', 'internal'),
143 ('publicURL', 'public'), ('adminURL', 'admin')]
145 endpoint_type = get_endpoint_type_from_env()
146 if endpoint_type is not None:
147 cred_key = env_cred_dict.get('OS_ENDPOINT_TYPE')
148 for k, v in endpoint_types:
149 if endpoint_type == v:
150 rally_conf[cred_key] = v
152 region_name = os.getenv('OS_REGION_NAME')
153 if region_name is not None:
154 cred_key = env_cred_dict.get('OS_REGION_NAME')
155 rally_conf[cred_key] = region_name
157 cred_key = env_cred_dict.get('OS_CACERT')
158 rally_conf[cred_key] = os.getenv('OS_CACERT', '')
160 insecure_key = env_cred_dict.get('OS_INSECURE')
161 rally_conf[insecure_key] = os.getenv('OS_INSECURE', '').lower() == 'true'
166 def get_endpoint_type_from_env():
167 endpoint_type = os.environ.get("OS_ENDPOINT_TYPE",
168 os.environ.get("OS_INTERFACE"))
169 if endpoint_type and "URL" in endpoint_type:
170 endpoint_type = endpoint_type.replace("URL", "")
174 def get_session_auth(other_creds={}):
175 loader = loading.get_plugin_loader('password')
176 creds = get_credentials(other_creds)
177 auth = loader.load_from_options(**creds)
181 def get_endpoint(service_type, interface='public'):
182 auth = get_session_auth()
183 return get_session().get_endpoint(auth=auth,
184 service_type=service_type,
188 def get_session(other_creds={}):
189 auth = get_session_auth(other_creds)
190 https_cacert = os.getenv('OS_CACERT', '')
191 https_insecure = os.getenv('OS_INSECURE', '').lower() == 'true'
192 return session.Session(auth=auth,
193 verify=(https_cacert or not https_insecure))
196 # *********************************************
198 # *********************************************
199 def get_keystone_client_version():
200 api_version = os.getenv('OS_IDENTITY_API_VERSION')
201 if api_version is not None:
202 logger.info("OS_IDENTITY_API_VERSION is set in env as '%s'",
205 return DEFAULT_API_VERSION
208 def get_keystone_client(other_creds={}):
209 sess = get_session(other_creds)
210 return keystoneclient.Client(get_keystone_client_version(),
212 interface=os.getenv('OS_INTERFACE', 'admin'))
215 def get_nova_client_version():
216 api_version = os.getenv('OS_COMPUTE_API_VERSION')
217 if api_version is not None:
218 logger.info("OS_COMPUTE_API_VERSION is set in env as '%s'",
221 return DEFAULT_API_VERSION
224 def get_nova_client(other_creds={}):
225 sess = get_session(other_creds)
226 return novaclient.Client(get_nova_client_version(), session=sess)
229 def get_cinder_client_version():
230 api_version = os.getenv('OS_VOLUME_API_VERSION')
231 if api_version is not None:
232 logger.info("OS_VOLUME_API_VERSION is set in env as '%s'",
235 return DEFAULT_API_VERSION
238 def get_cinder_client(other_creds={}):
239 sess = get_session(other_creds)
240 return cinderclient.Client(get_cinder_client_version(), session=sess)
243 def get_neutron_client_version():
244 api_version = os.getenv('OS_NETWORK_API_VERSION')
245 if api_version is not None:
246 logger.info("OS_NETWORK_API_VERSION is set in env as '%s'",
249 return DEFAULT_API_VERSION
252 def get_neutron_client(other_creds={}):
253 sess = get_session(other_creds)
254 return neutronclient.Client(get_neutron_client_version(), session=sess)
257 def get_glance_client_version():
258 api_version = os.getenv('OS_IMAGE_API_VERSION')
259 if api_version is not None:
260 logger.info("OS_IMAGE_API_VERSION is set in env as '%s'", api_version)
262 return DEFAULT_API_VERSION
265 def get_glance_client(other_creds={}):
266 sess = get_session(other_creds)
267 return glanceclient.Client(get_glance_client_version(), session=sess)
270 def get_heat_client_version():
271 api_version = os.getenv('OS_ORCHESTRATION_API_VERSION')
272 if api_version is not None:
273 logger.info("OS_ORCHESTRATION_API_VERSION is set in env as '%s'",
276 return DEFAULT_HEAT_API_VERSION
279 def get_heat_client(other_creds={}):
280 sess = get_session(other_creds)
281 return heatclient.Client(get_heat_client_version(), session=sess)
284 def download_and_add_image_on_glance(glance, image_name, image_url, data_dir):
287 if not os.path.exists(dest_path):
288 os.makedirs(dest_path)
289 file_name = image_url.rsplit('/')[-1]
290 if not ft_utils.download_url(image_url, dest_path):
293 raise Exception("Impossible to download image from {}".format(
297 image = create_glance_image(
298 glance, image_name, dest_path + file_name)
304 raise Exception("Impossible to put image {} in glance".format(
308 # *********************************************
310 # *********************************************
311 def get_instances(nova_client):
313 instances = nova_client.servers.list(search_opts={'all_tenants': 1})
315 except Exception as e:
316 logger.error("Error [get_instances(nova_client)]: %s" % e)
320 def get_instance_status(nova_client, instance):
322 instance = nova_client.servers.get(instance.id)
323 return instance.status
324 except Exception as e:
325 logger.error("Error [get_instance_status(nova_client)]: %s" % e)
329 def get_instance_by_name(nova_client, instance_name):
331 instance = nova_client.servers.find(name=instance_name)
333 except Exception as e:
334 logger.error("Error [get_instance_by_name(nova_client, '%s')]: %s"
335 % (instance_name, e))
339 def get_flavor_id(nova_client, flavor_name):
340 flavors = nova_client.flavors.list(detailed=True)
343 if f.name == flavor_name:
349 def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram):
350 flavors = nova_client.flavors.list(detailed=True)
353 if min_ram <= f.ram and f.ram <= max_ram:
359 def get_aggregates(nova_client):
361 aggregates = nova_client.aggregates.list()
363 except Exception as e:
364 logger.error("Error [get_aggregates(nova_client)]: %s" % e)
368 def get_aggregate_id(nova_client, aggregate_name):
370 aggregates = get_aggregates(nova_client)
371 _id = [ag.id for ag in aggregates if ag.name == aggregate_name][0]
373 except Exception as e:
374 logger.error("Error [get_aggregate_id(nova_client, %s)]:"
375 " %s" % (aggregate_name, e))
379 def get_availability_zones(nova_client):
381 availability_zones = nova_client.availability_zones.list()
382 return availability_zones
383 except Exception as e:
384 logger.error("Error [get_availability_zones(nova_client)]: %s" % e)
388 def get_availability_zone_names(nova_client):
390 az_names = [az.zoneName for az in get_availability_zones(nova_client)]
392 except Exception as e:
393 logger.error("Error [get_availability_zone_names(nova_client)]:"
398 def create_flavor(nova_client, flavor_name, ram, disk, vcpus, public=True):
400 flavor = nova_client.flavors.create(
401 flavor_name, ram, vcpus, disk, is_public=public)
403 extra_specs = ft_utils.get_functest_config(
404 'general.flavor_extra_specs')
405 flavor.set_keys(extra_specs)
407 # flavor extra specs are not configured, therefore skip the update
410 except Exception as e:
411 logger.error("Error [create_flavor(nova_client, '%s', '%s', '%s', "
412 "'%s')]: %s" % (flavor_name, ram, disk, vcpus, e))
417 def get_or_create_flavor(flavor_name, ram, disk, vcpus, public=True):
418 flavor_exists = False
419 nova_client = get_nova_client()
421 flavor_id = get_flavor_id(nova_client, flavor_name)
423 logger.info("Using existing flavor '%s'..." % flavor_name)
426 logger.info("Creating flavor '%s' with '%s' RAM, '%s' disk size, "
427 "'%s' vcpus..." % (flavor_name, ram, disk, vcpus))
428 flavor_id = create_flavor(
429 nova_client, flavor_name, ram, disk, vcpus, public=public)
431 raise Exception("Failed to create flavor '%s'..." % (flavor_name))
433 logger.debug("Flavor '%s' with ID=%s created successfully."
434 % (flavor_name, flavor_id))
436 return flavor_exists, flavor_id
439 def get_floating_ips(neutron_client):
441 floating_ips = neutron_client.list_floatingips()
442 return floating_ips['floatingips']
443 except Exception as e:
444 logger.error("Error [get_floating_ips(neutron_client)]: %s" % e)
448 def get_hypervisors(nova_client):
451 hypervisors = nova_client.hypervisors.list()
452 for hypervisor in hypervisors:
453 if hypervisor.state == "up":
454 nodes.append(hypervisor.hypervisor_hostname)
456 except Exception as e:
457 logger.error("Error [get_hypervisors(nova_client)]: %s" % e)
461 def create_aggregate(nova_client, aggregate_name, av_zone):
463 nova_client.aggregates.create(aggregate_name, av_zone)
465 except Exception as e:
466 logger.error("Error [create_aggregate(nova_client, %s, %s)]: %s"
467 % (aggregate_name, av_zone, e))
471 def add_host_to_aggregate(nova_client, aggregate_name, compute_host):
473 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
474 nova_client.aggregates.add_host(aggregate_id, compute_host)
476 except Exception as e:
477 logger.error("Error [add_host_to_aggregate(nova_client, %s, %s)]: %s"
478 % (aggregate_name, compute_host, e))
482 def create_aggregate_with_host(
483 nova_client, aggregate_name, av_zone, compute_host):
485 create_aggregate(nova_client, aggregate_name, av_zone)
486 add_host_to_aggregate(nova_client, aggregate_name, compute_host)
488 except Exception as e:
489 logger.error("Error [create_aggregate_with_host("
490 "nova_client, %s, %s, %s)]: %s"
491 % (aggregate_name, av_zone, compute_host, e))
495 def create_instance(flavor_name,
498 instance_name="functest-vm",
504 nova_client = get_nova_client()
506 flavor = nova_client.flavors.find(name=flavor_name)
508 flavors = nova_client.flavors.list()
509 logger.error("Error: Flavor '%s' not found. Available flavors are: "
510 "\n%s" % (flavor_name, flavors))
512 if fixed_ip is not None:
513 nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip}
515 nics = {"net-id": network_id}
517 instance = nova_client.servers.create(
522 availability_zone=av_zone,
526 instance = nova_client.servers.create(
531 config_drive=confdrive,
533 availability_zone=av_zone,
539 def create_instance_and_wait_for_active(flavor_name,
549 VM_BOOT_TIMEOUT = 180
550 nova_client = get_nova_client()
551 instance = create_instance(flavor_name,
560 count = VM_BOOT_TIMEOUT / SLEEP
561 for n in range(count, -1, -1):
562 status = get_instance_status(nova_client, instance)
563 if status.lower() == "active":
565 elif status.lower() == "error":
566 logger.error("The instance %s went to ERROR status."
570 logger.error("Timeout booting the instance %s." % instance_name)
574 def create_floating_ip(neutron_client):
575 extnet_id = get_external_net_id(neutron_client)
576 props = {'floating_network_id': extnet_id}
578 ip_json = neutron_client.create_floatingip({'floatingip': props})
579 fip_addr = ip_json['floatingip']['floating_ip_address']
580 fip_id = ip_json['floatingip']['id']
581 except Exception as e:
582 logger.error("Error [create_floating_ip(neutron_client)]: %s" % e)
584 return {'fip_addr': fip_addr, 'fip_id': fip_id}
587 def add_floating_ip(nova_client, server_id, floatingip_addr):
589 nova_client.servers.add_floating_ip(server_id, floatingip_addr)
591 except Exception as e:
592 logger.error("Error [add_floating_ip(nova_client, '%s', '%s')]: %s"
593 % (server_id, floatingip_addr, e))
597 def delete_instance(nova_client, instance_id):
599 nova_client.servers.force_delete(instance_id)
601 except Exception as e:
602 logger.error("Error [delete_instance(nova_client, '%s')]: %s"
607 def delete_floating_ip(neutron_client, floatingip_id):
609 neutron_client.delete_floatingip(floatingip_id)
611 except Exception as e:
612 logger.error("Error [delete_floating_ip(neutron_client, '%s')]: %s"
613 % (floatingip_id, e))
617 def remove_host_from_aggregate(nova_client, aggregate_name, compute_host):
619 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
620 nova_client.aggregates.remove_host(aggregate_id, compute_host)
622 except Exception as e:
623 logger.error("Error [remove_host_from_aggregate(nova_client, %s, %s)]:"
624 " %s" % (aggregate_name, compute_host, e))
628 def remove_hosts_from_aggregate(nova_client, aggregate_name):
629 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
630 hosts = nova_client.aggregates.get(aggregate_id).hosts
632 all(remove_host_from_aggregate(nova_client, aggregate_name, host)
636 def delete_aggregate(nova_client, aggregate_name):
638 remove_hosts_from_aggregate(nova_client, aggregate_name)
639 nova_client.aggregates.delete(aggregate_name)
641 except Exception as e:
642 logger.error("Error [delete_aggregate(nova_client, %s)]: %s"
643 % (aggregate_name, e))
647 # *********************************************
649 # *********************************************
650 def get_network_list(neutron_client):
651 network_list = neutron_client.list_networks()['networks']
652 if len(network_list) == 0:
658 def get_router_list(neutron_client):
659 router_list = neutron_client.list_routers()['routers']
660 if len(router_list) == 0:
666 def get_port_list(neutron_client):
667 port_list = neutron_client.list_ports()['ports']
668 if len(port_list) == 0:
674 def get_network_id(neutron_client, network_name):
675 networks = neutron_client.list_networks()['networks']
678 if n['name'] == network_name:
684 def get_subnet_id(neutron_client, subnet_name):
685 subnets = neutron_client.list_subnets()['subnets']
688 if s['name'] == subnet_name:
694 def get_router_id(neutron_client, router_name):
695 routers = neutron_client.list_routers()['routers']
698 if r['name'] == router_name:
704 def get_private_net(neutron_client):
705 # Checks if there is an existing shared private network
706 networks = neutron_client.list_networks()['networks']
707 if len(networks) == 0:
710 if (net['router:external'] is False) and (net['shared'] is True):
715 def get_external_net(neutron_client):
716 if (hasattr(CONST, 'EXTERNAL_NETWORK')):
717 return CONST.__getattribute__('EXTERNAL_NETWORK')
718 for network in neutron_client.list_networks()['networks']:
719 if network['router:external']:
720 return network['name']
724 def get_external_net_id(neutron_client):
725 if (hasattr(CONST, 'EXTERNAL_NETWORK')):
726 networks = neutron_client.list_networks(
727 name=CONST.__getattribute__('EXTERNAL_NETWORK'))
728 net_id = networks['networks'][0]['id']
730 for network in neutron_client.list_networks()['networks']:
731 if network['router:external']:
736 def check_neutron_net(neutron_client, net_name):
737 for network in neutron_client.list_networks()['networks']:
738 if network['name'] == net_name:
739 for subnet in network['subnets']:
744 def create_neutron_net(neutron_client, name):
745 json_body = {'network': {'name': name,
746 'admin_state_up': True}}
748 network = neutron_client.create_network(body=json_body)
749 network_dict = network['network']
750 return network_dict['id']
751 except Exception as e:
752 logger.error("Error [create_neutron_net(neutron_client, '%s')]: %s"
757 def create_neutron_subnet(neutron_client, name, cidr, net_id,
758 dns=['8.8.8.8', '8.8.4.4']):
759 json_body = {'subnets': [{'name': name, 'cidr': cidr,
760 'ip_version': 4, 'network_id': net_id,
761 'dns_nameservers': dns}]}
764 subnet = neutron_client.create_subnet(body=json_body)
765 return subnet['subnets'][0]['id']
766 except Exception as e:
767 logger.error("Error [create_neutron_subnet(neutron_client, '%s', "
768 "'%s', '%s')]: %s" % (name, cidr, net_id, e))
772 def create_neutron_router(neutron_client, name):
773 json_body = {'router': {'name': name, 'admin_state_up': True}}
775 router = neutron_client.create_router(json_body)
776 return router['router']['id']
777 except Exception as e:
778 logger.error("Error [create_neutron_router(neutron_client, '%s')]: %s"
783 def create_neutron_port(neutron_client, name, network_id, ip):
784 json_body = {'port': {
785 'admin_state_up': True,
787 'network_id': network_id,
788 'fixed_ips': [{"ip_address": ip}]
791 port = neutron_client.create_port(body=json_body)
792 return port['port']['id']
793 except Exception as e:
794 logger.error("Error [create_neutron_port(neutron_client, '%s', '%s', "
795 "'%s')]: %s" % (name, network_id, ip, e))
799 def update_neutron_net(neutron_client, network_id, shared=False):
800 json_body = {'network': {'shared': shared}}
802 neutron_client.update_network(network_id, body=json_body)
804 except Exception as e:
805 logger.error("Error [update_neutron_net(neutron_client, '%s', '%s')]: "
806 "%s" % (network_id, str(shared), e))
810 def update_neutron_port(neutron_client, port_id, device_owner):
811 json_body = {'port': {
812 'device_owner': device_owner,
815 port = neutron_client.update_port(port=port_id,
817 return port['port']['id']
818 except Exception as e:
819 logger.error("Error [update_neutron_port(neutron_client, '%s', '%s')]:"
820 " %s" % (port_id, device_owner, e))
824 def add_interface_router(neutron_client, router_id, subnet_id):
825 json_body = {"subnet_id": subnet_id}
827 neutron_client.add_interface_router(router=router_id, body=json_body)
829 except Exception as e:
830 logger.error("Error [add_interface_router(neutron_client, '%s', "
831 "'%s')]: %s" % (router_id, subnet_id, e))
835 def add_gateway_router(neutron_client, router_id):
836 ext_net_id = get_external_net_id(neutron_client)
837 router_dict = {'network_id': ext_net_id}
839 neutron_client.add_gateway_router(router_id, router_dict)
841 except Exception as e:
842 logger.error("Error [add_gateway_router(neutron_client, '%s')]: %s"
847 def delete_neutron_net(neutron_client, network_id):
849 neutron_client.delete_network(network_id)
851 except Exception as e:
852 logger.error("Error [delete_neutron_net(neutron_client, '%s')]: %s"
857 def delete_neutron_subnet(neutron_client, subnet_id):
859 neutron_client.delete_subnet(subnet_id)
861 except Exception as e:
862 logger.error("Error [delete_neutron_subnet(neutron_client, '%s')]: %s"
867 def delete_neutron_router(neutron_client, router_id):
869 neutron_client.delete_router(router=router_id)
871 except Exception as e:
872 logger.error("Error [delete_neutron_router(neutron_client, '%s')]: %s"
877 def delete_neutron_port(neutron_client, port_id):
879 neutron_client.delete_port(port_id)
881 except Exception as e:
882 logger.error("Error [delete_neutron_port(neutron_client, '%s')]: %s"
887 def remove_interface_router(neutron_client, router_id, subnet_id):
888 json_body = {"subnet_id": subnet_id}
890 neutron_client.remove_interface_router(router=router_id,
893 except Exception as e:
894 logger.error("Error [remove_interface_router(neutron_client, '%s', "
895 "'%s')]: %s" % (router_id, subnet_id, e))
899 def remove_gateway_router(neutron_client, router_id):
901 neutron_client.remove_gateway_router(router_id)
903 except Exception as e:
904 logger.error("Error [remove_gateway_router(neutron_client, '%s')]: %s"
909 def create_network_full(neutron_client,
914 dns=['8.8.8.8', '8.8.4.4']):
916 # Check if the network already exists
917 network_id = get_network_id(neutron_client, net_name)
918 subnet_id = get_subnet_id(neutron_client, subnet_name)
919 router_id = get_router_id(neutron_client, router_name)
921 if network_id != '' and subnet_id != '' and router_id != '':
922 logger.info("A network with name '%s' already exists..." % net_name)
924 neutron_client.format = 'json'
925 logger.info('Creating neutron network %s...' % net_name)
926 network_id = create_neutron_net(neutron_client, net_name)
931 logger.debug("Network '%s' created successfully" % network_id)
932 logger.debug('Creating Subnet....')
933 subnet_id = create_neutron_subnet(neutron_client, subnet_name,
934 cidr, network_id, dns)
938 logger.debug("Subnet '%s' created successfully" % subnet_id)
939 logger.debug('Creating Router...')
940 router_id = create_neutron_router(neutron_client, router_name)
945 logger.debug("Router '%s' created successfully" % router_id)
946 logger.debug('Adding router to subnet...')
948 if not add_interface_router(neutron_client, router_id, subnet_id):
951 logger.debug("Interface added successfully.")
953 logger.debug('Adding gateway to router...')
954 if not add_gateway_router(neutron_client, router_id):
957 logger.debug("Gateway added successfully.")
959 network_dic = {'net_id': network_id,
960 'subnet_id': subnet_id,
961 'router_id': router_id}
965 def create_shared_network_full(net_name, subnt_name, router_name, subnet_cidr):
966 neutron_client = get_neutron_client()
968 network_dic = create_network_full(neutron_client,
974 if not update_neutron_net(neutron_client,
975 network_dic['net_id'],
977 logger.error("Failed to update network %s..." % net_name)
980 logger.debug("Network '%s' is available..." % net_name)
982 logger.error("Network %s creation failed" % net_name)
987 # *********************************************
989 # *********************************************
992 def get_security_groups(neutron_client):
994 security_groups = neutron_client.list_security_groups()[
996 return security_groups
997 except Exception as e:
998 logger.error("Error [get_security_groups(neutron_client)]: %s" % e)
1002 def get_security_group_id(neutron_client, sg_name):
1003 security_groups = get_security_groups(neutron_client)
1005 for sg in security_groups:
1006 if sg['name'] == sg_name:
1012 def create_security_group(neutron_client, sg_name, sg_description):
1013 json_body = {'security_group': {'name': sg_name,
1014 'description': sg_description}}
1016 secgroup = neutron_client.create_security_group(json_body)
1017 return secgroup['security_group']
1018 except Exception as e:
1019 logger.error("Error [create_security_group(neutron_client, '%s', "
1020 "'%s')]: %s" % (sg_name, sg_description, e))
1024 def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
1025 port_range_min=None, port_range_max=None):
1026 # We create a security group in 2 steps
1027 # 1 - we check the format and set the json body accordingly
1028 # 2 - we call neturon client to create the security group
1031 json_body = {'security_group_rule': {'direction': direction,
1032 'security_group_id': sg_id,
1033 'protocol': protocol}}
1035 # - both None => we do nothing
1036 # - both Not None => we add them to the json description
1037 # but one cannot be None is the other is not None
1038 if (port_range_min is not None and port_range_max is not None):
1039 # add port_range in json description
1040 json_body['security_group_rule']['port_range_min'] = port_range_min
1041 json_body['security_group_rule']['port_range_max'] = port_range_max
1042 logger.debug("Security_group format set (port range included)")
1044 # either both port range are set to None => do nothing
1045 # or one is set but not the other => log it and return False
1046 if port_range_min is None and port_range_max is None:
1047 logger.debug("Security_group format set (no port range mentioned)")
1049 logger.error("Bad security group format."
1050 "One of the port range is not properly set:"
1052 "range max: {}".format(port_range_min,
1056 # Create security group using neutron client
1058 neutron_client.create_security_group_rule(json_body)
1061 logger.exception("Impossible to create_security_group_rule,"
1062 "security group rule probably already exists")
1066 def get_security_group_rules(neutron_client, sg_id):
1068 security_rules = neutron_client.list_security_group_rules()[
1069 'security_group_rules']
1070 security_rules = [rule for rule in security_rules
1071 if rule["security_group_id"] == sg_id]
1072 return security_rules
1073 except Exception as e:
1074 logger.error("Error [get_security_group_rules(neutron_client, sg_id)]:"
1079 def check_security_group_rules(neutron_client, sg_id, direction, protocol,
1080 port_min=None, port_max=None):
1082 security_rules = get_security_group_rules(neutron_client, sg_id)
1083 security_rules = [rule for rule in security_rules
1084 if (rule["direction"].lower() == direction and
1085 rule["protocol"].lower() == protocol and
1086 rule["port_range_min"] == port_min and
1087 rule["port_range_max"] == port_max)]
1088 if len(security_rules) == 0:
1092 except Exception as e:
1093 logger.error("Error [check_security_group_rules("
1094 " neutron_client, sg_id, direction,"
1095 " protocol, port_min=None, port_max=None)]: "
1100 def create_security_group_full(neutron_client,
1101 sg_name, sg_description):
1102 sg_id = get_security_group_id(neutron_client, sg_name)
1104 logger.info("Using existing security group '%s'..." % sg_name)
1106 logger.info("Creating security group '%s'..." % sg_name)
1107 SECGROUP = create_security_group(neutron_client,
1111 logger.error("Failed to create the security group...")
1114 sg_id = SECGROUP['id']
1116 logger.debug("Security group '%s' with ID=%s created successfully."
1117 % (SECGROUP['name'], sg_id))
1119 logger.debug("Adding ICMP rules in security group '%s'..."
1121 if not create_secgroup_rule(neutron_client, sg_id,
1123 logger.error("Failed to create the security group rule...")
1126 logger.debug("Adding SSH rules in security group '%s'..."
1128 if not create_secgroup_rule(
1129 neutron_client, sg_id, 'ingress', 'tcp', '22', '22'):
1130 logger.error("Failed to create the security group rule...")
1133 if not create_secgroup_rule(
1134 neutron_client, sg_id, 'egress', 'tcp', '22', '22'):
1135 logger.error("Failed to create the security group rule...")
1140 def add_secgroup_to_instance(nova_client, instance_id, secgroup_id):
1142 nova_client.servers.add_security_group(instance_id, secgroup_id)
1144 except Exception as e:
1145 logger.error("Error [add_secgroup_to_instance(nova_client, '%s', "
1146 "'%s')]: %s" % (instance_id, secgroup_id, e))
1150 def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
1151 json_body = {"quota": {
1152 "security_group": sg_quota,
1153 "security_group_rule": sg_rule_quota
1157 neutron_client.update_quota(tenant_id=tenant_id,
1160 except Exception as e:
1161 logger.error("Error [update_sg_quota(neutron_client, '%s', '%s', "
1162 "'%s')]: %s" % (tenant_id, sg_quota, sg_rule_quota, e))
1166 def delete_security_group(neutron_client, secgroup_id):
1168 neutron_client.delete_security_group(secgroup_id)
1170 except Exception as e:
1171 logger.error("Error [delete_security_group(neutron_client, '%s')]: %s"
1176 # *********************************************
1178 # *********************************************
1179 def get_images(glance_client):
1181 images = glance_client.images.list()
1183 except Exception as e:
1184 logger.error("Error [get_images]: %s" % e)
1188 def get_image_id(glance_client, image_name):
1189 images = glance_client.images.list()
1192 if i.name == image_name:
1198 def create_glance_image(glance_client, image_name, file_path, disk="qcow2",
1199 container="bare", public="public"):
1200 if not os.path.isfile(file_path):
1201 logger.error("Error: file %s does not exist." % file_path)
1204 image_id = get_image_id(glance_client, image_name)
1206 logger.info("Image %s already exists." % image_name)
1208 logger.info("Creating image '%s' from '%s'..." % (image_name,
1211 image = glance_client.images.create(name=image_name,
1214 container_format=container)
1216 with open(file_path) as image_data:
1217 glance_client.images.upload(image_id, image_data)
1219 except Exception as e:
1220 logger.error("Error [create_glance_image(glance_client, '%s', '%s', "
1221 "'%s')]: %s" % (image_name, file_path, public, e))
1225 def get_or_create_image(name, path, format):
1226 image_exists = False
1227 glance_client = get_glance_client()
1229 image_id = get_image_id(glance_client, name)
1231 logger.info("Using existing image '%s'..." % name)
1234 logger.info("Creating image '%s' from '%s'..." % (name, path))
1235 image_id = create_glance_image(glance_client, name, path, format)
1237 logger.error("Failed to create a Glance image...")
1239 logger.debug("Image '%s' with ID=%s created successfully."
1242 return image_exists, image_id
1245 def delete_glance_image(glance_client, image_id):
1247 glance_client.images.delete(image_id)
1249 except Exception as e:
1250 logger.error("Error [delete_glance_image(glance_client, '%s')]: %s"
1255 # *********************************************
1257 # *********************************************
1258 def get_volumes(cinder_client):
1260 volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
1262 except Exception as e:
1263 logger.error("Error [get_volumes(cinder_client)]: %s" % e)
1267 def list_volume_types(cinder_client, public=True, private=True):
1269 volume_types = cinder_client.volume_types.list()
1271 volume_types = [vt for vt in volume_types if not vt.is_public]
1273 volume_types = [vt for vt in volume_types if vt.is_public]
1275 except Exception as e:
1276 logger.error("Error [list_volume_types(cinder_client)]: %s" % e)
1280 def create_volume_type(cinder_client, name):
1282 volume_type = cinder_client.volume_types.create(name)
1284 except Exception as e:
1285 logger.error("Error [create_volume_type(cinder_client, '%s')]: %s"
1290 def update_cinder_quota(cinder_client, tenant_id, vols_quota,
1291 snapshots_quota, gigabytes_quota):
1292 quotas_values = {"volumes": vols_quota,
1293 "snapshots": snapshots_quota,
1294 "gigabytes": gigabytes_quota}
1297 cinder_client.quotas.update(tenant_id, **quotas_values)
1299 except Exception as e:
1300 logger.error("Error [update_cinder_quota(cinder_client, '%s', '%s', "
1301 "'%s' '%s')]: %s" % (tenant_id, vols_quota,
1302 snapshots_quota, gigabytes_quota, e))
1306 def delete_volume(cinder_client, volume_id, forced=False):
1310 cinder_client.volumes.detach(volume_id)
1312 logger.error(sys.exc_info()[0])
1313 cinder_client.volumes.force_delete(volume_id)
1315 cinder_client.volumes.delete(volume_id)
1317 except Exception as e:
1318 logger.error("Error [delete_volume(cinder_client, '%s', '%s')]: %s"
1319 % (volume_id, str(forced), e))
1323 def delete_volume_type(cinder_client, volume_type):
1325 cinder_client.volume_types.delete(volume_type)
1327 except Exception as e:
1328 logger.error("Error [delete_volume_type(cinder_client, '%s')]: %s"
1333 # *********************************************
1335 # *********************************************
1336 def get_tenants(keystone_client):
1338 if is_keystone_v3():
1339 tenants = keystone_client.projects.list()
1341 tenants = keystone_client.tenants.list()
1343 except Exception as e:
1344 logger.error("Error [get_tenants(keystone_client)]: %s" % e)
1348 def get_users(keystone_client):
1350 users = keystone_client.users.list()
1352 except Exception as e:
1353 logger.error("Error [get_users(keystone_client)]: %s" % e)
1357 def get_tenant_id(keystone_client, tenant_name):
1358 tenants = get_tenants(keystone_client)
1361 if t.name == tenant_name:
1367 def get_user_id(keystone_client, user_name):
1368 users = get_users(keystone_client)
1371 if u.name == user_name:
1377 def get_role_id(keystone_client, role_name):
1378 roles = keystone_client.roles.list()
1381 if r.name == role_name:
1387 def get_domain_id(keystone_client, domain_name):
1388 domains = keystone_client.domains.list()
1391 if d.name == domain_name:
1397 def create_tenant(keystone_client, tenant_name, tenant_description):
1399 if is_keystone_v3():
1400 domain_name = CONST.__getattribute__('OS_PROJECT_DOMAIN_NAME')
1401 domain_id = get_domain_id(keystone_client, domain_name)
1402 tenant = keystone_client.projects.create(
1404 description=tenant_description,
1408 tenant = keystone_client.tenants.create(tenant_name,
1412 except Exception as e:
1413 logger.error("Error [create_tenant(keystone_client, '%s', '%s')]: %s"
1414 % (tenant_name, tenant_description, e))
1418 def get_or_create_tenant(keystone_client, tenant_name, tenant_description):
1419 tenant_id = get_tenant_id(keystone_client, tenant_name)
1421 tenant_id = create_tenant(keystone_client, tenant_name,
1427 def get_or_create_tenant_for_vnf(keystone_client, tenant_name,
1428 tenant_description):
1429 """Get or Create a Tenant
1432 keystone_client: keystone client reference
1433 tenant_name: the name of the tenant
1434 tenant_description: the description of the tenant
1436 return False if tenant retrieved though get
1437 return True if tenant created
1438 raise Exception if error during processing
1441 tenant_id = get_tenant_id(keystone_client, tenant_name)
1443 tenant_id = create_tenant(keystone_client, tenant_name,
1449 raise Exception("Impossible to create a Tenant for the VNF {}".format(
1453 def create_user(keystone_client, user_name, user_password,
1454 user_email, tenant_id):
1456 if is_keystone_v3():
1457 user = keystone_client.users.create(name=user_name,
1458 password=user_password,
1460 project_id=tenant_id,
1463 user = keystone_client.users.create(user_name,
1469 except Exception as e:
1470 logger.error("Error [create_user(keystone_client, '%s', '%s', '%s'"
1471 "'%s')]: %s" % (user_name, user_password,
1472 user_email, tenant_id, e))
1476 def get_or_create_user(keystone_client, user_name, user_password,
1477 tenant_id, user_email=None):
1478 user_id = get_user_id(keystone_client, user_name)
1480 user_id = create_user(keystone_client, user_name, user_password,
1481 user_email, tenant_id)
1485 def get_or_create_user_for_vnf(keystone_client, vnf_ref):
1486 """Get or Create user for VNF
1489 keystone_client: keystone client reference
1490 vnf_ref: VNF reference used as user name & password, tenant name
1492 return False if user retrieved through get
1493 return True if user created
1494 raise Exception if error during processing
1497 user_id = get_user_id(keystone_client, vnf_ref)
1498 tenant_id = get_tenant_id(keystone_client, vnf_ref)
1501 user_id = create_user(keystone_client, vnf_ref, vnf_ref,
1505 role_id = get_role_id(keystone_client, 'admin')
1506 tenant_id = get_tenant_id(keystone_client, vnf_ref)
1507 add_role_user(keystone_client, user_id, role_id, tenant_id)
1509 logger.warn("Cannot associate user to role admin on tenant")
1512 raise Exception("Impossible to create a user for the VNF {}".format(
1516 def add_role_user(keystone_client, user_id, role_id, tenant_id):
1518 if is_keystone_v3():
1519 keystone_client.roles.grant(role=role_id,
1523 keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
1525 except Exception as e:
1526 logger.error("Error [add_role_user(keystone_client, '%s', '%s'"
1527 "'%s')]: %s " % (user_id, role_id, tenant_id, e))
1531 def delete_tenant(keystone_client, tenant_id):
1533 if is_keystone_v3():
1534 keystone_client.projects.delete(tenant_id)
1536 keystone_client.tenants.delete(tenant_id)
1538 except Exception as e:
1539 logger.error("Error [delete_tenant(keystone_client, '%s')]: %s"
1544 def delete_user(keystone_client, user_id):
1546 keystone_client.users.delete(user_id)
1548 except Exception as e:
1549 logger.error("Error [delete_user(keystone_client, '%s')]: %s"
1554 # *********************************************
1556 # *********************************************
1557 def get_resource(heat_client, stack_id, resource):
1559 resources = heat_client.resources.get(stack_id, resource)
1561 except Exception as e:
1562 logger.error("Error [get_resource]: %s" % e)
1566 # *********************************************
1568 # *********************************************
1569 def init_tempest_cleanup(tempest_config_dir=None,
1570 tempest_config_filename='tempest.conf',
1573 Initialize the Tempest Cleanup utility.
1574 See https://docs.openstack.org/tempest/latest/cleanup.html for docs.
1576 :param tempest_config_dir: The directory where the Tempest config file is
1577 located. If not specified, we let Tempest pick both the directory
1578 and the filename (i.e. second parameter is ignored)
1579 :param tempest_config_filename: The filename of the Tempest config file
1580 :param output_file: Optional file where to save output
1582 # The Tempest cleanup utility currently offers no cmd argument to specify
1583 # the config file, therefore it has to be configured with env variables
1585 if tempest_config_dir:
1586 env = os.environ.copy()
1587 env['TEMPEST_CONFIG_DIR'] = tempest_config_dir
1588 env['TEMPEST_CONFIG'] = tempest_config_filename
1590 # If this command fails, an exception must be raised to stop the script
1591 # otherwise the later cleanup would destroy also other resources
1592 cmd_line = "tempest cleanup --init-saved-state"
1593 ft_utils.execute_command_raise(cmd_line, env=env, output_file=output_file,
1594 error_msg="Tempest cleanup init failed")
1597 def perform_tempest_cleanup(tempest_config_dir=None,
1598 tempest_config_filename='tempest.conf',
1601 Perform cleanup using the Tempest Cleanup utility.
1602 See https://docs.openstack.org/tempest/latest/cleanup.html for docs.
1604 :param tempest_config_dir: The directory where the Tempest config file is
1605 located. If not specified, we let Tempest pick both the directory
1606 and the filename (i.e. second parameter is ignored)
1607 :param tempest_config_filename: The filename of the Tempest config file
1608 :param output_file: Optional file where to save output
1610 # The Tempest cleanup utility currently offers no cmd argument to specify
1611 # the config file, therefore it has to be configured with env variables
1613 if tempest_config_dir:
1614 env = os.environ.copy()
1615 env['TEMPEST_CONFIG_DIR'] = tempest_config_dir
1616 env['TEMPEST_CONFIG'] = tempest_config_filename
1618 # If this command fails, an exception must be raised to stop the script
1619 # otherwise the later cleanup would destroy also other resources
1620 cmd_line = "tempest cleanup"
1621 ft_utils.execute_command(cmd_line, env=env, output_file=output_file,
1622 error_msg="Tempest cleanup failed")