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
18 from keystoneauth1 import loading
19 from keystoneauth1 import session
20 from cinderclient import client as cinderclient
21 from glanceclient import client as glanceclient
22 from heatclient import client as heatclient
23 from novaclient import client as novaclient
24 from keystoneclient import client as keystoneclient
25 from neutronclient.neutron import client as neutronclient
27 from functest.utils import config
28 from functest.utils import env
30 logger = logging.getLogger(__name__)
32 DEFAULT_API_VERSION = '2'
33 DEFAULT_HEAT_API_VERSION = '1'
36 # *********************************************
38 # *********************************************
39 class MissingEnvVar(Exception):
41 def __init__(self, var):
45 return str.format("Please set the mandatory env var: {}", self.var)
49 keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
50 if (keystone_api_version is None or
51 keystone_api_version == '2'):
57 def get_rc_env_vars():
58 env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD']
60 env_vars.extend(['OS_PROJECT_NAME',
61 'OS_USER_DOMAIN_NAME',
62 'OS_PROJECT_DOMAIN_NAME'])
64 env_vars.extend(['OS_TENANT_NAME'])
68 def check_credentials():
70 Check if the OpenStack credentials (openrc) are sourced
72 env_vars = get_rc_env_vars()
73 return all(map(lambda v: v in os.environ and os.environ[v], env_vars))
76 def get_env_cred_dict():
78 'OS_USERNAME': 'username',
79 'OS_PASSWORD': 'password',
80 'OS_AUTH_URL': 'auth_url',
81 'OS_TENANT_NAME': 'tenant_name',
82 'OS_USER_DOMAIN_NAME': 'user_domain_name',
83 'OS_PROJECT_DOMAIN_NAME': 'project_domain_name',
84 'OS_PROJECT_NAME': 'project_name',
85 'OS_ENDPOINT_TYPE': 'endpoint_type',
86 'OS_REGION_NAME': 'region_name',
87 'OS_CACERT': 'https_cacert',
88 'OS_INSECURE': 'https_insecure'
93 def get_credentials(other_creds={}):
94 """Returns a creds dictionary filled with parsed from env
97 env_vars = get_rc_env_vars()
98 env_cred_dict = get_env_cred_dict()
100 for envvar in env_vars:
101 if os.getenv(envvar) is None:
102 raise MissingEnvVar(envvar)
104 creds_key = env_cred_dict.get(envvar)
105 creds.update({creds_key: os.getenv(envvar)})
107 if 'tenant' in other_creds.keys():
109 tenant = 'project_name'
111 tenant = 'tenant_name'
112 other_creds[tenant] = other_creds.pop('tenant')
114 creds.update(other_creds)
119 def get_session_auth(other_creds={}):
120 loader = loading.get_plugin_loader('password')
121 creds = get_credentials(other_creds)
122 auth = loader.load_from_options(**creds)
126 def get_endpoint(service_type, interface='public'):
127 auth = get_session_auth()
128 return get_session().get_endpoint(auth=auth,
129 service_type=service_type,
133 def get_session(other_creds={}):
134 auth = get_session_auth(other_creds)
135 https_cacert = os.getenv('OS_CACERT', '')
136 https_insecure = os.getenv('OS_INSECURE', '').lower() == 'true'
137 return session.Session(auth=auth,
138 verify=(https_cacert or not https_insecure))
141 # *********************************************
143 # *********************************************
144 def get_keystone_client_version():
145 api_version = os.getenv('OS_IDENTITY_API_VERSION')
146 if api_version is not None:
147 logger.info("OS_IDENTITY_API_VERSION is set in env as '%s'",
150 return DEFAULT_API_VERSION
153 def get_keystone_client(other_creds={}):
154 sess = get_session(other_creds)
155 return keystoneclient.Client(get_keystone_client_version(),
157 interface=os.getenv('OS_INTERFACE', 'admin'))
160 def get_nova_client_version():
161 api_version = os.getenv('OS_COMPUTE_API_VERSION')
162 if api_version is not None:
163 logger.info("OS_COMPUTE_API_VERSION is set in env as '%s'",
166 return DEFAULT_API_VERSION
169 def get_nova_client(other_creds={}):
170 sess = get_session(other_creds)
171 return novaclient.Client(get_nova_client_version(), session=sess)
174 def get_cinder_client_version():
175 api_version = os.getenv('OS_VOLUME_API_VERSION')
176 if api_version is not None:
177 logger.info("OS_VOLUME_API_VERSION is set in env as '%s'",
180 return DEFAULT_API_VERSION
183 def get_cinder_client(other_creds={}):
184 sess = get_session(other_creds)
185 return cinderclient.Client(get_cinder_client_version(), session=sess)
188 def get_neutron_client_version():
189 api_version = os.getenv('OS_NETWORK_API_VERSION')
190 if api_version is not None:
191 logger.info("OS_NETWORK_API_VERSION is set in env as '%s'",
194 return DEFAULT_API_VERSION
197 def get_neutron_client(other_creds={}):
198 sess = get_session(other_creds)
199 return neutronclient.Client(get_neutron_client_version(), session=sess)
202 def get_glance_client_version():
203 api_version = os.getenv('OS_IMAGE_API_VERSION')
204 if api_version is not None:
205 logger.info("OS_IMAGE_API_VERSION is set in env as '%s'", api_version)
207 return DEFAULT_API_VERSION
210 def get_glance_client(other_creds={}):
211 sess = get_session(other_creds)
212 return glanceclient.Client(get_glance_client_version(), session=sess)
215 def get_heat_client_version():
216 api_version = os.getenv('OS_ORCHESTRATION_API_VERSION')
217 if api_version is not None:
218 logger.info("OS_ORCHESTRATION_API_VERSION is set in env as '%s'",
221 return DEFAULT_HEAT_API_VERSION
224 def get_heat_client(other_creds={}):
225 sess = get_session(other_creds)
226 return heatclient.Client(get_heat_client_version(), session=sess)
229 def download_url(url, dest_path):
231 Download a file to a destination path given a URL
233 name = url.rsplit('/')[-1]
234 dest = dest_path + "/" + name
236 response = urllib.urlopen(url)
240 with open(dest, 'wb') as lfile:
241 shutil.copyfileobj(response, lfile)
245 def download_and_add_image_on_glance(glance, image_name, image_url, data_dir):
248 if not os.path.exists(dest_path):
249 os.makedirs(dest_path)
250 file_name = image_url.rsplit('/')[-1]
251 if not download_url(image_url, dest_path):
254 raise Exception("Impossible to download image from {}".format(
258 image = create_glance_image(
259 glance, image_name, dest_path + file_name)
265 raise Exception("Impossible to put image {} in glance".format(
269 # *********************************************
271 # *********************************************
272 def get_instances(nova_client):
274 instances = nova_client.servers.list(search_opts={'all_tenants': 1})
276 except Exception as e:
277 logger.error("Error [get_instances(nova_client)]: %s" % e)
281 def get_instance_status(nova_client, instance):
283 instance = nova_client.servers.get(instance.id)
284 return instance.status
285 except Exception as e:
286 logger.error("Error [get_instance_status(nova_client)]: %s" % e)
290 def get_instance_by_name(nova_client, instance_name):
292 instance = nova_client.servers.find(name=instance_name)
294 except Exception as e:
295 logger.error("Error [get_instance_by_name(nova_client, '%s')]: %s"
296 % (instance_name, e))
300 def get_flavor_id(nova_client, flavor_name):
301 flavors = nova_client.flavors.list(detailed=True)
304 if f.name == flavor_name:
310 def get_flavor_id_by_ram_range(nova_client, min_ram, max_ram):
311 flavors = nova_client.flavors.list(detailed=True)
314 if min_ram <= f.ram and f.ram <= max_ram:
320 def get_aggregates(nova_client):
322 aggregates = nova_client.aggregates.list()
324 except Exception as e:
325 logger.error("Error [get_aggregates(nova_client)]: %s" % e)
329 def get_aggregate_id(nova_client, aggregate_name):
331 aggregates = get_aggregates(nova_client)
332 _id = [ag.id for ag in aggregates if ag.name == aggregate_name][0]
334 except Exception as e:
335 logger.error("Error [get_aggregate_id(nova_client, %s)]:"
336 " %s" % (aggregate_name, e))
340 def get_availability_zones(nova_client):
342 availability_zones = nova_client.availability_zones.list()
343 return availability_zones
344 except Exception as e:
345 logger.error("Error [get_availability_zones(nova_client)]: %s" % e)
349 def get_availability_zone_names(nova_client):
351 az_names = [az.zoneName for az in get_availability_zones(nova_client)]
353 except Exception as e:
354 logger.error("Error [get_availability_zone_names(nova_client)]:"
359 def create_flavor(nova_client, flavor_name, ram, disk, vcpus, public=True):
361 flavor = nova_client.flavors.create(
362 flavor_name, ram, vcpus, disk, is_public=public)
364 extra_specs = getattr(config.CONF, 'flavor_extra_specs')
365 flavor.set_keys(extra_specs)
367 # flavor extra specs are not configured, therefore skip the update
370 except Exception as e:
371 logger.error("Error [create_flavor(nova_client, '%s', '%s', '%s', "
372 "'%s')]: %s" % (flavor_name, ram, disk, vcpus, e))
377 def get_or_create_flavor(flavor_name, ram, disk, vcpus, public=True):
378 flavor_exists = False
379 nova_client = get_nova_client()
381 flavor_id = get_flavor_id(nova_client, flavor_name)
383 logger.info("Using existing flavor '%s'..." % flavor_name)
386 logger.info("Creating flavor '%s' with '%s' RAM, '%s' disk size, "
387 "'%s' vcpus..." % (flavor_name, ram, disk, vcpus))
388 flavor_id = create_flavor(
389 nova_client, flavor_name, ram, disk, vcpus, public=public)
391 raise Exception("Failed to create flavor '%s'..." % (flavor_name))
393 logger.debug("Flavor '%s' with ID=%s created successfully."
394 % (flavor_name, flavor_id))
396 return flavor_exists, flavor_id
399 def get_floating_ips(neutron_client):
401 floating_ips = neutron_client.list_floatingips()
402 return floating_ips['floatingips']
403 except Exception as e:
404 logger.error("Error [get_floating_ips(neutron_client)]: %s" % e)
408 def get_hypervisors(nova_client):
411 hypervisors = nova_client.hypervisors.list()
412 for hypervisor in hypervisors:
413 if hypervisor.state == "up":
414 nodes.append(hypervisor.hypervisor_hostname)
416 except Exception as e:
417 logger.error("Error [get_hypervisors(nova_client)]: %s" % e)
421 def create_aggregate(nova_client, aggregate_name, av_zone):
423 nova_client.aggregates.create(aggregate_name, av_zone)
425 except Exception as e:
426 logger.error("Error [create_aggregate(nova_client, %s, %s)]: %s"
427 % (aggregate_name, av_zone, e))
431 def add_host_to_aggregate(nova_client, aggregate_name, compute_host):
433 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
434 nova_client.aggregates.add_host(aggregate_id, compute_host)
436 except Exception as e:
437 logger.error("Error [add_host_to_aggregate(nova_client, %s, %s)]: %s"
438 % (aggregate_name, compute_host, e))
442 def create_aggregate_with_host(
443 nova_client, aggregate_name, av_zone, compute_host):
445 create_aggregate(nova_client, aggregate_name, av_zone)
446 add_host_to_aggregate(nova_client, aggregate_name, compute_host)
448 except Exception as e:
449 logger.error("Error [create_aggregate_with_host("
450 "nova_client, %s, %s, %s)]: %s"
451 % (aggregate_name, av_zone, compute_host, e))
455 def create_instance(flavor_name,
458 instance_name="functest-vm",
464 nova_client = get_nova_client()
466 flavor = nova_client.flavors.find(name=flavor_name)
468 flavors = nova_client.flavors.list()
469 logger.error("Error: Flavor '%s' not found. Available flavors are: "
470 "\n%s" % (flavor_name, flavors))
472 if fixed_ip is not None:
473 nics = {"net-id": network_id, "v4-fixed-ip": fixed_ip}
475 nics = {"net-id": network_id}
477 instance = nova_client.servers.create(
482 availability_zone=av_zone,
486 instance = nova_client.servers.create(
491 config_drive=confdrive,
493 availability_zone=av_zone,
499 def create_instance_and_wait_for_active(flavor_name,
509 VM_BOOT_TIMEOUT = 180
510 nova_client = get_nova_client()
511 instance = create_instance(flavor_name,
520 count = VM_BOOT_TIMEOUT / SLEEP
521 for n in range(count, -1, -1):
522 status = get_instance_status(nova_client, instance)
526 elif status.lower() == "active":
528 elif status.lower() == "error":
529 logger.error("The instance %s went to ERROR status."
533 logger.error("Timeout booting the instance %s." % instance_name)
537 def create_floating_ip(neutron_client):
538 extnet_id = get_external_net_id(neutron_client)
539 props = {'floating_network_id': extnet_id}
541 ip_json = neutron_client.create_floatingip({'floatingip': props})
542 fip_addr = ip_json['floatingip']['floating_ip_address']
543 fip_id = ip_json['floatingip']['id']
544 except Exception as e:
545 logger.error("Error [create_floating_ip(neutron_client)]: %s" % e)
547 return {'fip_addr': fip_addr, 'fip_id': fip_id}
550 def add_floating_ip(nova_client, server_id, floatingip_addr):
552 nova_client.servers.add_floating_ip(server_id, floatingip_addr)
554 except Exception as e:
555 logger.error("Error [add_floating_ip(nova_client, '%s', '%s')]: %s"
556 % (server_id, floatingip_addr, e))
560 def delete_instance(nova_client, instance_id):
562 nova_client.servers.force_delete(instance_id)
564 except Exception as e:
565 logger.error("Error [delete_instance(nova_client, '%s')]: %s"
570 def delete_floating_ip(neutron_client, floatingip_id):
572 neutron_client.delete_floatingip(floatingip_id)
574 except Exception as e:
575 logger.error("Error [delete_floating_ip(neutron_client, '%s')]: %s"
576 % (floatingip_id, e))
580 def remove_host_from_aggregate(nova_client, aggregate_name, compute_host):
582 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
583 nova_client.aggregates.remove_host(aggregate_id, compute_host)
585 except Exception as e:
586 logger.error("Error [remove_host_from_aggregate(nova_client, %s, %s)]:"
587 " %s" % (aggregate_name, compute_host, e))
591 def remove_hosts_from_aggregate(nova_client, aggregate_name):
592 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
593 hosts = nova_client.aggregates.get(aggregate_id).hosts
595 all(remove_host_from_aggregate(nova_client, aggregate_name, host)
599 def delete_aggregate(nova_client, aggregate_name):
601 remove_hosts_from_aggregate(nova_client, aggregate_name)
602 nova_client.aggregates.delete(aggregate_name)
604 except Exception as e:
605 logger.error("Error [delete_aggregate(nova_client, %s)]: %s"
606 % (aggregate_name, e))
610 # *********************************************
612 # *********************************************
613 def get_network_list(neutron_client):
614 network_list = neutron_client.list_networks()['networks']
615 if len(network_list) == 0:
621 def get_router_list(neutron_client):
622 router_list = neutron_client.list_routers()['routers']
623 if len(router_list) == 0:
629 def get_port_list(neutron_client):
630 port_list = neutron_client.list_ports()['ports']
631 if len(port_list) == 0:
637 def get_network_id(neutron_client, network_name):
638 networks = neutron_client.list_networks()['networks']
641 if n['name'] == network_name:
647 def get_subnet_id(neutron_client, subnet_name):
648 subnets = neutron_client.list_subnets()['subnets']
651 if s['name'] == subnet_name:
657 def get_router_id(neutron_client, router_name):
658 routers = neutron_client.list_routers()['routers']
661 if r['name'] == router_name:
667 def get_private_net(neutron_client):
668 # Checks if there is an existing shared private network
669 networks = neutron_client.list_networks()['networks']
670 if len(networks) == 0:
673 if (net['router:external'] is False) and (net['shared'] is True):
678 def get_external_net(neutron_client):
679 if (env.get('EXTERNAL_NETWORK')):
680 return env.get('EXTERNAL_NETWORK')
681 for network in neutron_client.list_networks()['networks']:
682 if network['router:external']:
683 return network['name']
687 def get_external_net_id(neutron_client):
688 if (env.get('EXTERNAL_NETWORK')):
689 networks = neutron_client.list_networks(
690 name=env.get('EXTERNAL_NETWORK'))
691 net_id = networks['networks'][0]['id']
693 for network in neutron_client.list_networks()['networks']:
694 if network['router:external']:
699 def check_neutron_net(neutron_client, net_name):
700 for network in neutron_client.list_networks()['networks']:
701 if network['name'] == net_name:
702 for subnet in network['subnets']:
707 def create_neutron_net(neutron_client, name):
708 json_body = {'network': {'name': name,
709 'admin_state_up': True}}
711 network = neutron_client.create_network(body=json_body)
712 network_dict = network['network']
713 return network_dict['id']
714 except Exception as e:
715 logger.error("Error [create_neutron_net(neutron_client, '%s')]: %s"
720 def create_neutron_subnet(neutron_client, name, cidr, net_id,
721 dns=['8.8.8.8', '8.8.4.4']):
722 json_body = {'subnets': [{'name': name, 'cidr': cidr,
723 'ip_version': 4, 'network_id': net_id,
724 'dns_nameservers': dns}]}
727 subnet = neutron_client.create_subnet(body=json_body)
728 return subnet['subnets'][0]['id']
729 except Exception as e:
730 logger.error("Error [create_neutron_subnet(neutron_client, '%s', "
731 "'%s', '%s')]: %s" % (name, cidr, net_id, e))
735 def create_neutron_router(neutron_client, name):
736 json_body = {'router': {'name': name, 'admin_state_up': True}}
738 router = neutron_client.create_router(json_body)
739 return router['router']['id']
740 except Exception as e:
741 logger.error("Error [create_neutron_router(neutron_client, '%s')]: %s"
746 def create_neutron_port(neutron_client, name, network_id, ip):
747 json_body = {'port': {
748 'admin_state_up': True,
750 'network_id': network_id,
751 'fixed_ips': [{"ip_address": ip}]
754 port = neutron_client.create_port(body=json_body)
755 return port['port']['id']
756 except Exception as e:
757 logger.error("Error [create_neutron_port(neutron_client, '%s', '%s', "
758 "'%s')]: %s" % (name, network_id, ip, e))
762 def update_neutron_net(neutron_client, network_id, shared=False):
763 json_body = {'network': {'shared': shared}}
765 neutron_client.update_network(network_id, body=json_body)
767 except Exception as e:
768 logger.error("Error [update_neutron_net(neutron_client, '%s', '%s')]: "
769 "%s" % (network_id, str(shared), e))
773 def update_neutron_port(neutron_client, port_id, device_owner):
774 json_body = {'port': {
775 'device_owner': device_owner,
778 port = neutron_client.update_port(port=port_id,
780 return port['port']['id']
781 except Exception as e:
782 logger.error("Error [update_neutron_port(neutron_client, '%s', '%s')]:"
783 " %s" % (port_id, device_owner, e))
787 def add_interface_router(neutron_client, router_id, subnet_id):
788 json_body = {"subnet_id": subnet_id}
790 neutron_client.add_interface_router(router=router_id, body=json_body)
792 except Exception as e:
793 logger.error("Error [add_interface_router(neutron_client, '%s', "
794 "'%s')]: %s" % (router_id, subnet_id, e))
798 def add_gateway_router(neutron_client, router_id):
799 ext_net_id = get_external_net_id(neutron_client)
800 router_dict = {'network_id': ext_net_id}
802 neutron_client.add_gateway_router(router_id, router_dict)
804 except Exception as e:
805 logger.error("Error [add_gateway_router(neutron_client, '%s')]: %s"
810 def delete_neutron_net(neutron_client, network_id):
812 neutron_client.delete_network(network_id)
814 except Exception as e:
815 logger.error("Error [delete_neutron_net(neutron_client, '%s')]: %s"
820 def delete_neutron_subnet(neutron_client, subnet_id):
822 neutron_client.delete_subnet(subnet_id)
824 except Exception as e:
825 logger.error("Error [delete_neutron_subnet(neutron_client, '%s')]: %s"
830 def delete_neutron_router(neutron_client, router_id):
832 neutron_client.delete_router(router=router_id)
834 except Exception as e:
835 logger.error("Error [delete_neutron_router(neutron_client, '%s')]: %s"
840 def delete_neutron_port(neutron_client, port_id):
842 neutron_client.delete_port(port_id)
844 except Exception as e:
845 logger.error("Error [delete_neutron_port(neutron_client, '%s')]: %s"
850 def remove_interface_router(neutron_client, router_id, subnet_id):
851 json_body = {"subnet_id": subnet_id}
853 neutron_client.remove_interface_router(router=router_id,
856 except Exception as e:
857 logger.error("Error [remove_interface_router(neutron_client, '%s', "
858 "'%s')]: %s" % (router_id, subnet_id, e))
862 def remove_gateway_router(neutron_client, router_id):
864 neutron_client.remove_gateway_router(router_id)
866 except Exception as e:
867 logger.error("Error [remove_gateway_router(neutron_client, '%s')]: %s"
872 def create_network_full(neutron_client,
877 dns=['8.8.8.8', '8.8.4.4']):
879 # Check if the network already exists
880 network_id = get_network_id(neutron_client, net_name)
881 subnet_id = get_subnet_id(neutron_client, subnet_name)
882 router_id = get_router_id(neutron_client, router_name)
884 if network_id != '' and subnet_id != '' and router_id != '':
885 logger.info("A network with name '%s' already exists..." % net_name)
887 neutron_client.format = 'json'
888 logger.info('Creating neutron network %s...' % net_name)
889 network_id = create_neutron_net(neutron_client, net_name)
894 logger.debug("Network '%s' created successfully" % network_id)
895 logger.debug('Creating Subnet....')
896 subnet_id = create_neutron_subnet(neutron_client, subnet_name,
897 cidr, network_id, dns)
901 logger.debug("Subnet '%s' created successfully" % subnet_id)
902 logger.debug('Creating Router...')
903 router_id = create_neutron_router(neutron_client, router_name)
908 logger.debug("Router '%s' created successfully" % router_id)
909 logger.debug('Adding router to subnet...')
911 if not add_interface_router(neutron_client, router_id, subnet_id):
914 logger.debug("Interface added successfully.")
916 logger.debug('Adding gateway to router...')
917 if not add_gateway_router(neutron_client, router_id):
920 logger.debug("Gateway added successfully.")
922 network_dic = {'net_id': network_id,
923 'subnet_id': subnet_id,
924 'router_id': router_id}
928 def create_shared_network_full(net_name, subnt_name, router_name, subnet_cidr):
929 neutron_client = get_neutron_client()
931 network_dic = create_network_full(neutron_client,
937 if not update_neutron_net(neutron_client,
938 network_dic['net_id'],
940 logger.error("Failed to update network %s..." % net_name)
943 logger.debug("Network '%s' is available..." % net_name)
945 logger.error("Network %s creation failed" % net_name)
950 # *********************************************
952 # *********************************************
955 def get_security_groups(neutron_client):
957 security_groups = neutron_client.list_security_groups()[
959 return security_groups
960 except Exception as e:
961 logger.error("Error [get_security_groups(neutron_client)]: %s" % e)
965 def get_security_group_id(neutron_client, sg_name):
966 security_groups = get_security_groups(neutron_client)
968 for sg in security_groups:
969 if sg['name'] == sg_name:
975 def create_security_group(neutron_client, sg_name, sg_description):
976 json_body = {'security_group': {'name': sg_name,
977 'description': sg_description}}
979 secgroup = neutron_client.create_security_group(json_body)
980 return secgroup['security_group']
981 except Exception as e:
982 logger.error("Error [create_security_group(neutron_client, '%s', "
983 "'%s')]: %s" % (sg_name, sg_description, e))
987 def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
988 port_range_min=None, port_range_max=None):
989 # We create a security group in 2 steps
990 # 1 - we check the format and set the json body accordingly
991 # 2 - we call neturon client to create the security group
994 json_body = {'security_group_rule': {'direction': direction,
995 'security_group_id': sg_id,
996 'protocol': protocol}}
998 # - both None => we do nothing
999 # - both Not None => we add them to the json description
1000 # but one cannot be None is the other is not None
1001 if (port_range_min is not None and port_range_max is not None):
1002 # add port_range in json description
1003 json_body['security_group_rule']['port_range_min'] = port_range_min
1004 json_body['security_group_rule']['port_range_max'] = port_range_max
1005 logger.debug("Security_group format set (port range included)")
1007 # either both port range are set to None => do nothing
1008 # or one is set but not the other => log it and return False
1009 if port_range_min is None and port_range_max is None:
1010 logger.debug("Security_group format set (no port range mentioned)")
1012 logger.error("Bad security group format."
1013 "One of the port range is not properly set:"
1015 "range max: {}".format(port_range_min,
1019 # Create security group using neutron client
1021 neutron_client.create_security_group_rule(json_body)
1024 logger.exception("Impossible to create_security_group_rule,"
1025 "security group rule probably already exists")
1029 def get_security_group_rules(neutron_client, sg_id):
1031 security_rules = neutron_client.list_security_group_rules()[
1032 'security_group_rules']
1033 security_rules = [rule for rule in security_rules
1034 if rule["security_group_id"] == sg_id]
1035 return security_rules
1036 except Exception as e:
1037 logger.error("Error [get_security_group_rules(neutron_client, sg_id)]:"
1042 def check_security_group_rules(neutron_client, sg_id, direction, protocol,
1043 port_min=None, port_max=None):
1045 security_rules = get_security_group_rules(neutron_client, sg_id)
1046 security_rules = [rule for rule in security_rules
1047 if (rule["direction"].lower() == direction and
1048 rule["protocol"].lower() == protocol and
1049 rule["port_range_min"] == port_min and
1050 rule["port_range_max"] == port_max)]
1051 if len(security_rules) == 0:
1055 except Exception as e:
1056 logger.error("Error [check_security_group_rules("
1057 " neutron_client, sg_id, direction,"
1058 " protocol, port_min=None, port_max=None)]: "
1063 def create_security_group_full(neutron_client,
1064 sg_name, sg_description):
1065 sg_id = get_security_group_id(neutron_client, sg_name)
1067 logger.info("Using existing security group '%s'..." % sg_name)
1069 logger.info("Creating security group '%s'..." % sg_name)
1070 SECGROUP = create_security_group(neutron_client,
1074 logger.error("Failed to create the security group...")
1077 sg_id = SECGROUP['id']
1079 logger.debug("Security group '%s' with ID=%s created successfully."
1080 % (SECGROUP['name'], sg_id))
1082 logger.debug("Adding ICMP rules in security group '%s'..."
1084 if not create_secgroup_rule(neutron_client, sg_id,
1086 logger.error("Failed to create the security group rule...")
1089 logger.debug("Adding SSH rules in security group '%s'..."
1091 if not create_secgroup_rule(
1092 neutron_client, sg_id, 'ingress', 'tcp', '22', '22'):
1093 logger.error("Failed to create the security group rule...")
1096 if not create_secgroup_rule(
1097 neutron_client, sg_id, 'egress', 'tcp', '22', '22'):
1098 logger.error("Failed to create the security group rule...")
1103 def add_secgroup_to_instance(nova_client, instance_id, secgroup_id):
1105 nova_client.servers.add_security_group(instance_id, secgroup_id)
1107 except Exception as e:
1108 logger.error("Error [add_secgroup_to_instance(nova_client, '%s', "
1109 "'%s')]: %s" % (instance_id, secgroup_id, e))
1113 def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
1114 json_body = {"quota": {
1115 "security_group": sg_quota,
1116 "security_group_rule": sg_rule_quota
1120 neutron_client.update_quota(tenant_id=tenant_id,
1123 except Exception as e:
1124 logger.error("Error [update_sg_quota(neutron_client, '%s', '%s', "
1125 "'%s')]: %s" % (tenant_id, sg_quota, sg_rule_quota, e))
1129 def delete_security_group(neutron_client, secgroup_id):
1131 neutron_client.delete_security_group(secgroup_id)
1133 except Exception as e:
1134 logger.error("Error [delete_security_group(neutron_client, '%s')]: %s"
1139 # *********************************************
1141 # *********************************************
1142 def get_images(glance_client):
1144 images = glance_client.images.list()
1146 except Exception as e:
1147 logger.error("Error [get_images]: %s" % e)
1151 def get_image_id(glance_client, image_name):
1152 images = glance_client.images.list()
1155 if i.name == image_name:
1161 def create_glance_image(glance_client,
1165 extra_properties={},
1168 if not os.path.isfile(file_path):
1169 logger.error("Error: file %s does not exist." % file_path)
1172 image_id = get_image_id(glance_client, image_name)
1174 logger.info("Image %s already exists." % image_name)
1176 logger.info("Creating image '%s' from '%s'..." % (image_name,
1179 image = glance_client.images.create(name=image_name,
1182 container_format=container,
1185 with open(file_path) as image_data:
1186 glance_client.images.upload(image_id, image_data)
1188 except Exception as e:
1189 logger.error("Error [create_glance_image(glance_client, '%s', '%s', "
1190 "'%s')]: %s" % (image_name, file_path, public, e))
1194 def get_or_create_image(name, path, format, extra_properties):
1195 image_exists = False
1196 glance_client = get_glance_client()
1198 image_id = get_image_id(glance_client, name)
1200 logger.info("Using existing image '%s'..." % name)
1203 logger.info("Creating image '%s' from '%s'..." % (name, path))
1204 image_id = create_glance_image(glance_client,
1210 logger.error("Failed to create a Glance image...")
1212 logger.debug("Image '%s' with ID=%s created successfully."
1215 return image_exists, image_id
1218 def delete_glance_image(glance_client, image_id):
1220 glance_client.images.delete(image_id)
1222 except Exception as e:
1223 logger.error("Error [delete_glance_image(glance_client, '%s')]: %s"
1228 # *********************************************
1230 # *********************************************
1231 def get_volumes(cinder_client):
1233 volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
1235 except Exception as e:
1236 logger.error("Error [get_volumes(cinder_client)]: %s" % e)
1240 def update_cinder_quota(cinder_client, tenant_id, vols_quota,
1241 snapshots_quota, gigabytes_quota):
1242 quotas_values = {"volumes": vols_quota,
1243 "snapshots": snapshots_quota,
1244 "gigabytes": gigabytes_quota}
1247 cinder_client.quotas.update(tenant_id, **quotas_values)
1249 except Exception as e:
1250 logger.error("Error [update_cinder_quota(cinder_client, '%s', '%s', "
1251 "'%s' '%s')]: %s" % (tenant_id, vols_quota,
1252 snapshots_quota, gigabytes_quota, e))
1256 def delete_volume(cinder_client, volume_id, forced=False):
1260 cinder_client.volumes.detach(volume_id)
1262 logger.error(sys.exc_info()[0])
1263 cinder_client.volumes.force_delete(volume_id)
1265 cinder_client.volumes.delete(volume_id)
1267 except Exception as e:
1268 logger.error("Error [delete_volume(cinder_client, '%s', '%s')]: %s"
1269 % (volume_id, str(forced), e))
1273 # *********************************************
1275 # *********************************************
1276 def get_tenants(keystone_client):
1278 if is_keystone_v3():
1279 tenants = keystone_client.projects.list()
1281 tenants = keystone_client.tenants.list()
1283 except Exception as e:
1284 logger.error("Error [get_tenants(keystone_client)]: %s" % e)
1288 def get_users(keystone_client):
1290 users = keystone_client.users.list()
1292 except Exception as e:
1293 logger.error("Error [get_users(keystone_client)]: %s" % e)
1297 def get_tenant_id(keystone_client, tenant_name):
1298 tenants = get_tenants(keystone_client)
1301 if t.name == tenant_name:
1307 def get_user_id(keystone_client, user_name):
1308 users = get_users(keystone_client)
1311 if u.name == user_name:
1317 def get_role_id(keystone_client, role_name):
1318 roles = keystone_client.roles.list()
1321 if r.name == role_name:
1327 def get_domain_id(keystone_client, domain_name):
1328 domains = keystone_client.domains.list()
1331 if d.name == domain_name:
1337 def create_tenant(keystone_client, tenant_name, tenant_description):
1339 if is_keystone_v3():
1340 domain_name = os.environ['OS_PROJECT_DOMAIN_NAME']
1341 domain_id = get_domain_id(keystone_client, domain_name)
1342 tenant = keystone_client.projects.create(
1344 description=tenant_description,
1348 tenant = keystone_client.tenants.create(tenant_name,
1352 except Exception as e:
1353 logger.error("Error [create_tenant(keystone_client, '%s', '%s')]: %s"
1354 % (tenant_name, tenant_description, e))
1358 def get_or_create_tenant(keystone_client, tenant_name, tenant_description):
1359 tenant_id = get_tenant_id(keystone_client, tenant_name)
1361 tenant_id = create_tenant(keystone_client, tenant_name,
1367 def get_or_create_tenant_for_vnf(keystone_client, tenant_name,
1368 tenant_description):
1369 """Get or Create a Tenant
1372 keystone_client: keystone client reference
1373 tenant_name: the name of the tenant
1374 tenant_description: the description of the tenant
1376 return False if tenant retrieved though get
1377 return True if tenant created
1378 raise Exception if error during processing
1381 tenant_id = get_tenant_id(keystone_client, tenant_name)
1383 tenant_id = create_tenant(keystone_client, tenant_name,
1389 raise Exception("Impossible to create a Tenant for the VNF {}".format(
1393 def create_user(keystone_client, user_name, user_password,
1394 user_email, tenant_id):
1396 if is_keystone_v3():
1397 user = keystone_client.users.create(name=user_name,
1398 password=user_password,
1400 project_id=tenant_id,
1403 user = keystone_client.users.create(user_name,
1409 except Exception as e:
1410 logger.error("Error [create_user(keystone_client, '%s', '%s', '%s'"
1411 "'%s')]: %s" % (user_name, user_password,
1412 user_email, tenant_id, e))
1416 def get_or_create_user(keystone_client, user_name, user_password,
1417 tenant_id, user_email=None):
1418 user_id = get_user_id(keystone_client, user_name)
1420 user_id = create_user(keystone_client, user_name, user_password,
1421 user_email, tenant_id)
1425 def get_or_create_user_for_vnf(keystone_client, vnf_ref):
1426 """Get or Create user for VNF
1429 keystone_client: keystone client reference
1430 vnf_ref: VNF reference used as user name & password, tenant name
1432 return False if user retrieved through get
1433 return True if user created
1434 raise Exception if error during processing
1437 user_id = get_user_id(keystone_client, vnf_ref)
1438 tenant_id = get_tenant_id(keystone_client, vnf_ref)
1441 user_id = create_user(keystone_client, vnf_ref, vnf_ref,
1445 role_id = get_role_id(keystone_client, 'admin')
1446 tenant_id = get_tenant_id(keystone_client, vnf_ref)
1447 add_role_user(keystone_client, user_id, role_id, tenant_id)
1449 logger.warn("Cannot associate user to role admin on tenant")
1452 raise Exception("Impossible to create a user for the VNF {}".format(
1456 def add_role_user(keystone_client, user_id, role_id, tenant_id):
1458 if is_keystone_v3():
1459 keystone_client.roles.grant(role=role_id,
1463 keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
1465 except Exception as e:
1466 logger.error("Error [add_role_user(keystone_client, '%s', '%s'"
1467 "'%s')]: %s " % (user_id, role_id, tenant_id, e))
1471 def delete_tenant(keystone_client, tenant_id):
1473 if is_keystone_v3():
1474 keystone_client.projects.delete(tenant_id)
1476 keystone_client.tenants.delete(tenant_id)
1478 except Exception as e:
1479 logger.error("Error [delete_tenant(keystone_client, '%s')]: %s"
1484 def delete_user(keystone_client, user_id):
1486 keystone_client.users.delete(user_id)
1488 except Exception as e:
1489 logger.error("Error [delete_user(keystone_client, '%s')]: %s"
1494 # *********************************************
1496 # *********************************************
1497 def get_resource(heat_client, stack_id, resource):
1499 resources = heat_client.resources.get(stack_id, resource)
1501 except Exception as e:
1502 logger.error("Error [get_resource]: %s" % e)