1 ##############################################################################
2 # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
10 from __future__ import absolute_import
16 from keystoneauth1 import loading
17 from keystoneauth1 import session
18 from cinderclient import client as cinderclient
19 from novaclient import client as novaclient
20 from glanceclient import client as glanceclient
21 from neutronclient.neutron import client as neutronclient
23 log = logging.getLogger(__name__)
25 DEFAULT_HEAT_API_VERSION = '1'
26 DEFAULT_API_VERSION = '2'
29 # *********************************************
31 # *********************************************
32 def get_credentials():
33 """Returns a creds dictionary filled with parsed from env"""
36 keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION')
38 if keystone_api_version is None or keystone_api_version == '2':
40 tenant_env = 'OS_TENANT_NAME'
41 tenant = 'tenant_name'
44 tenant_env = 'OS_PROJECT_NAME'
45 tenant = 'project_name'
47 # The most common way to pass these info to the script is to do it
48 # through environment variables.
50 "username": os.environ.get("OS_USERNAME"),
51 "password": os.environ.get("OS_PASSWORD"),
52 "auth_url": os.environ.get("OS_AUTH_URL"),
53 tenant: os.environ.get(tenant_env)
57 if os.getenv('OS_USER_DOMAIN_NAME') is not None:
59 "user_domain_name": os.getenv('OS_USER_DOMAIN_NAME')
61 if os.getenv('OS_PROJECT_DOMAIN_NAME') is not None:
63 "project_domain_name": os.getenv('OS_PROJECT_DOMAIN_NAME')
69 def get_session_auth():
70 loader = loading.get_plugin_loader('password')
71 creds = get_credentials()
72 auth = loader.load_from_options(**creds)
77 auth = get_session_auth()
79 cacert = os.environ['OS_CACERT']
81 return session.Session(auth=auth)
83 insecure = os.getenv('OS_INSECURE', '').lower() == 'true'
84 cacert = False if insecure else cacert
85 return session.Session(auth=auth, verify=cacert)
88 def get_endpoint(service_type, endpoint_type='publicURL'):
89 auth = get_session_auth()
90 # for multi-region, we need to specify region
91 # when finding the endpoint
92 return get_session().get_endpoint(auth=auth,
93 service_type=service_type,
94 endpoint_type=endpoint_type,
95 region_name=os.environ.get(
99 # *********************************************
101 # *********************************************
102 def get_heat_api_version(): # pragma: no cover
104 api_version = os.environ['HEAT_API_VERSION']
106 return DEFAULT_HEAT_API_VERSION
108 log.info("HEAT_API_VERSION is set in env as '%s'", api_version)
112 def get_cinder_client_version(): # pragma: no cover
114 api_version = os.environ['OS_VOLUME_API_VERSION']
116 return DEFAULT_API_VERSION
118 log.info("OS_VOLUME_API_VERSION is set in env as '%s'", api_version)
122 def get_cinder_client(): # pragma: no cover
124 return cinderclient.Client(get_cinder_client_version(), session=sess)
127 def get_nova_client_version(): # pragma: no cover
129 api_version = os.environ['OS_COMPUTE_API_VERSION']
131 return DEFAULT_API_VERSION
133 log.info("OS_COMPUTE_API_VERSION is set in env as '%s'", api_version)
137 def get_nova_client(): # pragma: no cover
139 return novaclient.Client(get_nova_client_version(), session=sess)
142 def get_neutron_client_version(): # pragma: no cover
144 api_version = os.environ['OS_NETWORK_API_VERSION']
146 return DEFAULT_API_VERSION
148 log.info("OS_NETWORK_API_VERSION is set in env as '%s'", api_version)
152 def get_neutron_client(): # pragma: no cover
154 return neutronclient.Client(get_neutron_client_version(), session=sess)
157 def get_glance_client_version(): # pragma: no cover
159 api_version = os.environ['OS_IMAGE_API_VERSION']
161 return DEFAULT_API_VERSION
163 log.info("OS_IMAGE_API_VERSION is set in env as '%s'", api_version)
167 def get_glance_client(): # pragma: no cover
169 return glanceclient.Client(get_glance_client_version(), session=sess)
172 # *********************************************
174 # *********************************************
175 def get_instances(nova_client): # pragma: no cover
177 return nova_client.servers.list(search_opts={'all_tenants': 1})
179 log.exception("Error [get_instances(nova_client)]")
182 def get_instance_status(nova_client, instance): # pragma: no cover
184 return nova_client.servers.get(instance.id).status
186 log.exception("Error [get_instance_status(nova_client)]")
189 def get_instance_by_name(nova_client, instance_name): # pragma: no cover
191 return nova_client.servers.find(name=instance_name)
193 log.exception("Error [get_instance_by_name(nova_client, '%s')]",
197 def get_aggregates(nova_client): # pragma: no cover
199 return nova_client.aggregates.list()
201 log.exception("Error [get_aggregates(nova_client)]")
204 def get_availability_zones(nova_client): # pragma: no cover
206 return nova_client.availability_zones.list()
208 log.exception("Error [get_availability_zones(nova_client)]")
211 def get_availability_zone_names(nova_client): # pragma: no cover
213 return [az.zoneName for az in get_availability_zones(nova_client)]
215 log.exception("Error [get_availability_zone_names(nova_client)]")
218 def create_aggregate(nova_client, aggregate_name, av_zone): # pragma: no cover
220 nova_client.aggregates.create(aggregate_name, av_zone)
222 log.exception("Error [create_aggregate(nova_client, %s, %s)]",
223 aggregate_name, av_zone)
229 def get_aggregate_id(nova_client, aggregate_name): # pragma: no cover
231 aggregates = get_aggregates(nova_client)
232 _id = next((ag.id for ag in aggregates if ag.name == aggregate_name))
234 log.exception("Error [get_aggregate_id(nova_client, %s)]",
240 def add_host_to_aggregate(nova_client, aggregate_name,
241 compute_host): # pragma: no cover
243 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
244 nova_client.aggregates.add_host(aggregate_id, compute_host)
246 log.exception("Error [add_host_to_aggregate(nova_client, %s, %s)]",
247 aggregate_name, compute_host)
253 def create_aggregate_with_host(nova_client, aggregate_name, av_zone,
254 compute_host): # pragma: no cover
256 create_aggregate(nova_client, aggregate_name, av_zone)
257 add_host_to_aggregate(nova_client, aggregate_name, compute_host)
259 log.exception("Error [create_aggregate_with_host("
260 "nova_client, %s, %s, %s)]",
261 aggregate_name, av_zone, compute_host)
267 def create_keypair(nova_client, name, key_path=None): # pragma: no cover
269 with open(key_path) as fpubkey:
270 keypair = get_nova_client().keypairs.create(name=name, public_key=fpubkey.read())
273 log.exception("Error [create_keypair(nova_client)]")
276 def create_instance(json_body): # pragma: no cover
278 return get_nova_client().servers.create(**json_body)
280 log.exception("Error create instance failed")
284 def create_instance_and_wait_for_active(json_body): # pragma: no cover
286 VM_BOOT_TIMEOUT = 180
287 nova_client = get_nova_client()
288 instance = create_instance(json_body)
289 count = VM_BOOT_TIMEOUT / SLEEP
290 for n in range(count, -1, -1):
291 status = get_instance_status(nova_client, instance)
292 if status.lower() == "active":
294 elif status.lower() == "error":
295 log.error("The instance went to ERROR status.")
298 log.error("Timeout booting the instance.")
302 def attach_server_volume(server_id, volume_id, device=None): # pragma: no cover
304 get_nova_client().volumes.create_server_volume(server_id, volume_id, device)
306 log.exception("Error [attach_server_volume(nova_client, '%s', '%s')]",
307 server_id, volume_id)
313 def delete_instance(nova_client, instance_id): # pragma: no cover
315 nova_client.servers.force_delete(instance_id)
317 log.exception("Error [delete_instance(nova_client, '%s')]",
324 def remove_host_from_aggregate(nova_client, aggregate_name,
325 compute_host): # pragma: no cover
327 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
328 nova_client.aggregates.remove_host(aggregate_id, compute_host)
330 log.exception("Error remove_host_from_aggregate(nova_client, %s, %s)",
331 aggregate_name, compute_host)
337 def remove_hosts_from_aggregate(nova_client,
338 aggregate_name): # pragma: no cover
339 aggregate_id = get_aggregate_id(nova_client, aggregate_name)
340 hosts = nova_client.aggregates.get(aggregate_id).hosts
342 all(remove_host_from_aggregate(nova_client, aggregate_name, host)
346 def delete_aggregate(nova_client, aggregate_name): # pragma: no cover
348 remove_hosts_from_aggregate(nova_client, aggregate_name)
349 nova_client.aggregates.delete(aggregate_name)
351 log.exception("Error [delete_aggregate(nova_client, %s)]",
358 def get_server_by_name(name): # pragma: no cover
360 return get_nova_client().servers.list(search_opts={'name': name})[0]
362 log.exception('Failed to get nova client')
366 def create_flavor(name, ram, vcpus, disk, **kwargs): # pragma: no cover
368 return get_nova_client().flavors.create(name, ram, vcpus, disk, **kwargs)
370 log.exception("Error [create_flavor(nova_client, %s, %s, %s, %s, %s)]",
371 name, ram, disk, vcpus, kwargs['is_public'])
375 def get_image_by_name(name): # pragma: no cover
376 images = get_nova_client().images.list()
378 return next((a for a in images if a.name == name))
379 except StopIteration:
380 log.exception('No image matched')
383 def get_flavor_id(nova_client, flavor_name): # pragma: no cover
384 flavors = nova_client.flavors.list(detailed=True)
387 if f.name == flavor_name:
393 def get_flavor_by_name(name): # pragma: no cover
394 flavors = get_nova_client().flavors.list()
396 return next((a for a in flavors if a.name == name))
397 except StopIteration:
398 log.exception('No flavor matched')
401 def check_status(status, name, iterations, interval): # pragma: no cover
402 for i in range(iterations):
404 server = get_server_by_name(name)
406 log.error('Cannot found %s server', name)
409 if server.status == status:
416 def delete_flavor(flavor_id): # pragma: no cover
418 get_nova_client().flavors.delete(flavor_id)
420 log.exception("Error [delete_flavor(nova_client, %s)]", flavor_id)
426 # *********************************************
428 # *********************************************
429 def get_network_id(neutron_client, network_name): # pragma: no cover
430 networks = neutron_client.list_networks()['networks']
431 return next((n['id'] for n in networks if n['name'] == network_name), None)
434 def get_port_id_by_ip(neutron_client, ip_address): # pragma: no cover
435 ports = neutron_client.list_ports()['ports']
436 return next((i['id'] for i in ports for j in i.get(
437 'fixed_ips') if j['ip_address'] == ip_address), None)
440 def create_neutron_net(neutron_client, json_body): # pragma: no cover
442 network = neutron_client.create_network(body=json_body)
443 return network['network']['id']
445 log.error("Error [create_neutron_net(neutron_client)]")
446 raise Exception("operation error")
450 def create_neutron_subnet(neutron_client, json_body): # pragma: no cover
452 subnet = neutron_client.create_subnet(body=json_body)
453 return subnet['subnets'][0]['id']
455 log.error("Error [create_neutron_subnet")
456 raise Exception("operation error")
460 def create_neutron_router(neutron_client, json_body): # pragma: no cover
462 router = neutron_client.create_router(json_body)
463 return router['router']['id']
465 log.error("Error [create_neutron_router(neutron_client)]")
466 raise Exception("operation error")
470 def create_floating_ip(neutron_client, extnet_id): # pragma: no cover
471 props = {'floating_network_id': extnet_id}
473 ip_json = neutron_client.create_floatingip({'floatingip': props})
474 fip_addr = ip_json['floatingip']['floating_ip_address']
475 fip_id = ip_json['floatingip']['id']
477 log.error("Error [create_floating_ip(neutron_client)]")
479 return {'fip_addr': fip_addr, 'fip_id': fip_id}
482 def get_security_groups(neutron_client): # pragma: no cover
484 security_groups = neutron_client.list_security_groups()[
486 return security_groups
488 log.error("Error [get_security_groups(neutron_client)]")
492 def get_security_group_id(neutron_client, sg_name): # pragma: no cover
493 security_groups = get_security_groups(neutron_client)
495 for sg in security_groups:
496 if sg['name'] == sg_name:
502 def create_security_group(neutron_client, sg_name, sg_description): # pragma: no cover
503 json_body = {'security_group': {'name': sg_name,
504 'description': sg_description}}
506 secgroup = neutron_client.create_security_group(json_body)
507 return secgroup['security_group']
509 log.error("Error [create_security_group(neutron_client, '%s', "
510 "'%s')]" % (sg_name, sg_description))
514 def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
515 port_range_min=None, port_range_max=None,
516 **json_body): # pragma: no cover
517 # We create a security group in 2 steps
518 # 1 - we check the format and set the json body accordingly
519 # 2 - we call neturon client to create the security group
522 json_body.update({'security_group_rule': {'direction': direction,
523 'security_group_id': sg_id, 'protocol': protocol}})
525 # - both None => we do nothing
526 # - both Not None => we add them to the json description
527 # but one cannot be None is the other is not None
528 if (port_range_min is not None and port_range_max is not None):
529 # add port_range in json description
530 json_body['security_group_rule']['port_range_min'] = port_range_min
531 json_body['security_group_rule']['port_range_max'] = port_range_max
532 log.debug("Security_group format set (port range included)")
534 # either both port range are set to None => do nothing
535 # or one is set but not the other => log it and return False
536 if port_range_min is None and port_range_max is None:
537 log.debug("Security_group format set (no port range mentioned)")
539 log.error("Bad security group format."
540 "One of the port range is not properly set:"
542 "range max: {}".format(port_range_min,
546 # Create security group using neutron client
548 neutron_client.create_security_group_rule(json_body)
551 log.exception("Impossible to create_security_group_rule,"
552 "security group rule probably already exists")
556 def create_security_group_full(neutron_client,
557 sg_name, sg_description): # pragma: no cover
558 sg_id = get_security_group_id(neutron_client, sg_name)
560 log.info("Using existing security group '%s'..." % sg_name)
562 log.info("Creating security group '%s'..." % sg_name)
563 SECGROUP = create_security_group(neutron_client,
567 log.error("Failed to create the security group...")
570 sg_id = SECGROUP['id']
572 log.debug("Security group '%s' with ID=%s created successfully."
573 % (SECGROUP['name'], sg_id))
575 log.debug("Adding ICMP rules in security group '%s'..."
577 if not create_secgroup_rule(neutron_client, sg_id,
579 log.error("Failed to create the security group rule...")
582 log.debug("Adding SSH rules in security group '%s'..."
584 if not create_secgroup_rule(
585 neutron_client, sg_id, 'ingress', 'tcp', '22', '22'):
586 log.error("Failed to create the security group rule...")
589 if not create_secgroup_rule(
590 neutron_client, sg_id, 'egress', 'tcp', '22', '22'):
591 log.error("Failed to create the security group rule...")
596 # *********************************************
598 # *********************************************
599 def get_image_id(glance_client, image_name): # pragma: no cover
600 images = glance_client.images.list()
601 return next((i.id for i in images if i.name == image_name), None)
604 def create_image(glance_client, image_name, file_path, disk_format,
605 container_format, min_disk, min_ram, protected, tag,
606 public, **kwargs): # pragma: no cover
607 if not os.path.isfile(file_path):
608 log.error("Error: file %s does not exist." % file_path)
611 image_id = get_image_id(glance_client, image_name)
612 if image_id is not None:
613 log.info("Image %s already exists." % image_name)
615 log.info("Creating image '%s' from '%s'...", image_name, file_path)
617 image = glance_client.images.create(name=image_name,
619 disk_format=disk_format,
620 container_format=container_format,
627 with open(file_path) as image_data:
628 glance_client.images.upload(image_id, image_data)
631 log.error("Error [create_glance_image(glance_client, '%s', '%s', '%s')]",
632 image_name, file_path, public)
636 def delete_image(glance_client, image_id): # pragma: no cover
638 glance_client.images.delete(image_id)
641 log.exception("Error [delete_flavor(glance_client, %s)]", image_id)
647 # *********************************************
649 # *********************************************
650 def get_volume_id(volume_name): # pragma: no cover
651 volumes = get_cinder_client().volumes.list()
652 return next((v.id for v in volumes if v.name == volume_name), None)
655 def create_volume(cinder_client, volume_name, volume_size,
656 volume_image=False): # pragma: no cover
659 volume = cinder_client.volumes.create(name=volume_name,
661 imageRef=volume_image)
663 volume = cinder_client.volumes.create(name=volume_name,
667 log.exception("Error [create_volume(cinder_client, %s)]",
668 (volume_name, volume_size))