3 # Copyright (c) 2015 All rights reserved
4 # 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
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # 0.1: This script boots the VM1 and allocates IP address from Nova
11 # Later, the VM2 boots then execute cloud-init to ping VM1.
12 # After successful ping, both the VMs are deleted.
13 # 0.2: measure test duration and publish results under json format
14 # 0.3: adapt push 2 DB after Test API refacroting
26 from novaclient import client as novaclient
27 from neutronclient.v2_0 import client as neutronclient
28 from keystoneclient.v2_0 import client as keystoneclient
29 from glanceclient import client as glanceclient
31 import functest.utils.functest_logger as ft_logger
32 import functest.utils.functest_utils as functest_utils
33 import functest.utils.openstack_utils as openstack_utils
35 pp = pprint.PrettyPrinter(indent=4)
37 parser = argparse.ArgumentParser()
40 parser.add_argument("-d", "--debug", help="Debug mode", action="store_true")
41 parser.add_argument("-r", "--report",
42 help="Create json result file",
45 args = parser.parse_args()
47 """ logging configuration """
48 logger = ft_logger.Logger("vping_userdata").getLogger()
50 REPO_PATH = os.environ['repos_dir'] + '/functest/'
51 if not os.path.exists(REPO_PATH):
52 logger.error("Functest repository directory not found '%s'" % REPO_PATH)
55 with open(os.environ["CONFIG_FUNCTEST_YAML"]) as f:
56 functest_yaml = yaml.safe_load(f)
59 HOME = os.environ['HOME'] + "/"
62 VM_DELETE_TIMEOUT = 100
63 PING_TIMEOUT = functest_yaml.get("vping").get("ping_timeout")
64 TEST_DB = functest_yaml.get("results").get("test_db_url")
65 NAME_VM_1 = functest_yaml.get("vping").get("vm_name_1")
66 NAME_VM_2 = functest_yaml.get("vping").get("vm_name_2")
67 GLANCE_IMAGE_NAME = functest_yaml.get("vping").get("image_name")
68 GLANCE_IMAGE_FILENAME = functest_yaml.get("general").get(
69 "openstack").get("image_file_name")
70 GLANCE_IMAGE_FORMAT = functest_yaml.get("general").get(
71 "openstack").get("image_disk_format")
72 GLANCE_IMAGE_PATH = functest_yaml.get("general").get("directories").get(
73 "dir_functest_data") + "/" + GLANCE_IMAGE_FILENAME
76 FLAVOR = functest_yaml.get("vping").get("vm_flavor")
78 # NEUTRON Private Network parameters
80 PRIVATE_NET_NAME = functest_yaml.get("vping").get(
81 "vping_private_net_name")
82 PRIVATE_SUBNET_NAME = functest_yaml.get("vping").get(
83 "vping_private_subnet_name")
84 PRIVATE_SUBNET_CIDR = functest_yaml.get("vping").get(
85 "vping_private_subnet_cidr")
86 ROUTER_NAME = functest_yaml.get("vping").get("vping_router_name")
88 SECGROUP_NAME = functest_yaml.get("vping").get("vping_sg_name")
89 SECGROUP_DESCR = functest_yaml.get("vping").get("vping_sg_descr")
98 def waitVmActive(nova, vm):
100 # sleep and wait for VM status change
102 count = VM_BOOT_TIMEOUT / sleep_time
104 status = openstack_utils.get_instance_status(nova, vm)
105 logger.debug("Status: %s" % status)
106 if status == "ACTIVE":
108 if status == "ERROR" or status == "error":
111 logger.debug("Booting a VM timed out...")
114 time.sleep(sleep_time)
118 def waitVmDeleted(nova, vm):
120 # sleep and wait for VM status change
122 count = VM_DELETE_TIMEOUT / sleep_time
124 status = openstack_utils.get_instance_status(nova, vm)
128 logger.debug("Timeout")
133 time.sleep(sleep_time)
137 def create_security_group(neutron_client):
138 sg_id = openstack_utils.get_security_group_id(neutron_client,
141 logger.info("Using existing security group '%s'..." % SECGROUP_NAME)
143 logger.info("Creating security group '%s'..." % SECGROUP_NAME)
144 SECGROUP = openstack_utils.create_security_group(neutron_client,
148 logger.error("Failed to create the security group...")
151 sg_id = SECGROUP['id']
153 logger.debug("Security group '%s' with ID=%s created successfully."
154 % (SECGROUP['name'], sg_id))
156 logger.debug("Adding ICMP rules in security group '%s'..."
158 if not openstack_utils.create_secgroup_rule(neutron_client, sg_id,
160 logger.error("Failed to create the security group rule...")
163 logger.debug("Adding SSH rules in security group '%s'..."
165 if not openstack_utils.create_secgroup_rule(neutron_client, sg_id,
168 logger.error("Failed to create the security group rule...")
171 if not openstack_utils.create_secgroup_rule(neutron_client, sg_id,
174 logger.error("Failed to create the security group rule...")
181 creds_nova = openstack_utils.get_credentials("nova")
182 nova_client = novaclient.Client('2', **creds_nova)
183 creds_neutron = openstack_utils.get_credentials("neutron")
184 neutron_client = neutronclient.Client(**creds_neutron)
185 creds_keystone = openstack_utils.get_credentials("keystone")
186 keystone_client = keystoneclient.Client(**creds_keystone)
187 glance_endpoint = keystone_client.service_catalog.url_for(
188 service_type='image', endpoint_type='publicURL')
189 glance_client = glanceclient.Client(1, glance_endpoint,
190 token=keystone_client.auth_token)
196 # Check if the given image exists
197 image_id = openstack_utils.get_image_id(glance_client, GLANCE_IMAGE_NAME)
199 logger.info("Using existing image '%s'..." % GLANCE_IMAGE_NAME)
203 logger.info("Creating image '%s' from '%s'..." % (GLANCE_IMAGE_NAME,
205 image_id = openstack_utils.create_glance_image(glance_client,
209 logger.error("Failed to create a Glance image...")
211 logger.debug("Image '%s' with ID=%s created successfully."
212 % (GLANCE_IMAGE_NAME, image_id))
214 network_dic = openstack_utils.create_network_full(logger,
222 "There has been a problem when creating the neutron network")
224 network_id = network_dic["net_id"]
226 create_security_group(neutron_client)
228 # Check if the given flavor exists
230 flavor = nova_client.flavors.find(name=FLAVOR)
231 logger.info("Flavor found '%s'" % FLAVOR)
233 logger.error("Flavor '%s' not found." % FLAVOR)
234 logger.info("Available flavors are: ")
235 pMsg(nova_client.flavor.list())
238 # Deleting instances if they exist
239 servers = nova_client.servers.list()
240 for server in servers:
241 if server.name == NAME_VM_1 or server.name == NAME_VM_2:
242 logger.info("Instance %s found. Deleting..." % server.name)
247 # tune (e.g. flavor, images, network) to your specific
248 # openstack configuration here
249 # we consider start time at VM1 booting
250 start_time = time.time()
251 stop_time = start_time
252 logger.info("vPing Start Time:'%s'" % (
253 datetime.datetime.fromtimestamp(start_time).strftime(
254 '%Y-%m-%d %H:%M:%S')))
257 logger.info("Creating instance '%s'..." % NAME_VM_1)
259 "Configuration:\n name=%s \n flavor=%s \n image=%s \n "
260 "network=%s \n" % (NAME_VM_1, flavor, image_id, network_id))
261 vm1 = nova_client.servers.create(
266 nics=[{"net-id": network_id}]
269 # wait until VM status is active
270 if not waitVmActive(nova_client, vm1):
272 logger.error("Instance '%s' cannot be booted. Status is '%s'" % (
273 NAME_VM_1, openstack_utils.get_instance_status(nova_client, vm1)))
276 logger.info("Instance '%s' is ACTIVE." % NAME_VM_1)
278 # Retrieve IP of first VM
279 test_ip = vm1.networks.get(PRIVATE_NET_NAME)[0]
280 logger.debug("Instance '%s' got %s" % (NAME_VM_1, test_ip))
283 # we will boot then execute a ping script with cloud-init
284 # the long chain corresponds to the ping procedure converted with base 64
285 # tune (e.g. flavor, images, network) to your specific openstack
287 u = ("#!/bin/sh\n\nwhile true; do\n ping -c 1 %s 2>&1 >/dev/null\n "
288 "RES=$?\n if [ \"Z$RES\" = \"Z0\" ] ; then\n echo 'vPing OK'\n "
289 "break\n else\n echo 'vPing KO'\n fi\n sleep 1\ndone\n" % test_ip)
292 logger.info("Creating instance '%s'..." % NAME_VM_2)
294 "Configuration:\n name=%s \n flavor=%s \n image=%s \n network=%s "
295 "\n userdata= \n%s" % (
296 NAME_VM_2, flavor, image_id, network_id, u))
297 vm2 = nova_client.servers.create(
301 nics=[{"net-id": network_id}],
306 if not waitVmActive(nova_client, vm2):
307 logger.error("Instance '%s' cannot be booted. Status is '%s'" % (
308 NAME_VM_2, openstack_utils.get_instance_status(nova_client, vm2)))
311 logger.info("Instance '%s' is ACTIVE." % NAME_VM_2)
313 logger.info("Waiting for ping...")
316 console_log = vm2.get_console_output()
318 stop_time = time.time()
322 console_log = vm2.get_console_output()
323 # print "--"+console_log
324 # report if the test is failed
325 if "vPing OK" in console_log:
326 logger.info("vPing detected!")
328 # we consider start time at VM1 booting
329 stop_time = time.time()
330 duration = round(stop_time - start_time, 1)
331 logger.info("vPing duration:'%s'" % duration)
334 elif ("failed to read iid from metadata" in console_log or
338 elif sec == PING_TIMEOUT:
339 logger.info("Timeout reached.")
342 if "request failed" in console_log:
343 logger.debug("It seems userdata is not supported in "
344 "nova boot. Waiting a bit...")
347 logger.debug("Pinging %s. Waiting for response..." % test_ip)
352 logger.info("vPing OK")
354 elif EXIT_CODE == -2:
356 logger.info("Userdata is not supported in nova boot. Aborting test...")
359 logger.error("vPing FAILED")
363 logger.debug("Pushing vPing userdata results into DB...")
364 functest_utils.push_results_to_db("functest",
370 details={'timestart': start_time,
371 'duration': duration,
372 'status': test_status})
374 logger.error("Error pushing results into Database '%s'"
379 if __name__ == '__main__':