Allow graceful exiting with SIGINT and SIGTERM

The test_loop function was only gracefully interrupted with a keyboard
interrupt before. This is fine for interactive testing, but in an
automated scenario the script may be running in the background and need
to receive a signal from some other process, such as Ansible.

This patch adds a handler for SIGINT and SIGTERM that will allow the
current iteration of the loop to finish, then exit the program cleanly
by putting the test_loop function into a class. The test_loop function
is not refactored other than to add the `stop_now` flag, though the
internal variables may be amenable to later refactoring to use the
class.

Change-Id: I0667d2c7093e2821afdfcea987cec6b58515885f
This commit is contained in:
Nolan Brubaker 2017-05-22 11:35:11 -04:00
parent 56ac318f21
commit 325076bef6
1 changed files with 39 additions and 20 deletions

View File

@ -25,6 +25,7 @@ from keystoneauth1.exceptions.http import InternalServerError
from keystoneclient.v3 import client as key_client
import logging
import os
import signal
import sys
import time
from glanceclient import Client
@ -145,7 +146,7 @@ class KeystoneTest(ServiceTest):
# the test_loop function
try:
keystone.projects.list()
msg = "Project lest retrieved"
msg = "Project list retrieved"
except InternalServerError:
msg = "Failed to get project list"
return msg
@ -196,23 +197,38 @@ class GlanceTest(ServiceTest):
return glance_endpoint.url
def test_loop(test):
"""Main loop to execute tests
class TestRunner(object):
"""Run a test in a loop, with the option to gracefully exit"""
stop_now = False
Executes and times interactions with OpenStack services to gather timing
data.
:param: test - on object that performs some action
against an OpenStack service API.
"""
disconnected = None
# Has to be a tuple for python syntax reasons.
# This is currently the set needed for glance; should probably
# provide some way of letting a test say which exceptions should
# be caught for a service.
exc_list = (ConnectFailure, InternalServerError, BadGateway,
glance_exc.CommunicationError,
glance_exc.HTTPInternalServerError)
try:
def __init__(self):
signal.signal(signal.SIGINT, self.prep_exit)
signal.signal(signal.SIGTERM, self.prep_exit)
def prep_exit(self, signum, frame):
self.stop_now = True
logger.info("Received signal, stopping")
def test_loop(self, test):
"""Main loop to execute tests
Executes and times interactions with OpenStack services to gather
timing data.
Execution can be ended by sending SIGINT or SIGTERM and the running
test will finish.
:param: test - on object that performs some action
against an OpenStack service API.
"""
disconnected = None
# Has to be a tuple for python syntax reasons.
# This is currently the set needed for glance; should probably
# provide some way of letting a test say which exceptions should
# be caught for a service.
exc_list = (ConnectFailure, InternalServerError, BadGateway,
glance_exc.CommunicationError,
glance_exc.HTTPInternalServerError)
while True:
try:
# Pause for a bit so we're not generating more data than we
@ -249,8 +265,9 @@ def test_loop(test):
except (exc_list):
if not disconnected:
disconnected = datetime.datetime.now()
except KeyboardInterrupt:
sys.exit()
if self.stop_now:
sys.exit()
available_tests = {
@ -294,4 +311,6 @@ if __name__ == "__main__":
target_test = target_test_class()
target_test.configure_logger(logger)
test_loop(target_test)
runner = TestRunner()
runner.test_loop(target_test)