From 38120c10754efdffb6bf55a9707167962149b486 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Wed, 10 Feb 2016 09:48:05 -0500 Subject: [PATCH] termination handling - moved to base cli class to handle centrally and duplicate less code - now avoids duplication and reiteration of signal handler by reassigning it - left note on how to do non-graceful in case we add in future as I won't remember everything i did here and don't want to 'relearn' it. --- lib/ansible/cli/__init__.py | 20 +++++++++++++++++++- lib/ansible/cli/adhoc.py | 9 --------- lib/ansible/executor/playbook_executor.py | 12 ------------ 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/lib/ansible/cli/__init__.py b/lib/ansible/cli/__init__.py index ed4a2dd5db..0ba370f273 100644 --- a/lib/ansible/cli/__init__.py +++ b/lib/ansible/cli/__init__.py @@ -27,6 +27,7 @@ import time import yaml import re import getpass +import signal import subprocess from ansible import __version__ @@ -44,7 +45,7 @@ except ImportError: class SortedOptParser(optparse.OptionParser): '''Optparser which sorts the options by opt before outputting --help''' - # TODO: epilog parsing: OptionParser.format_epilog = lambda self, formatter: self.epilog + #FIXME: epilog parsing: OptionParser.format_epilog = lambda self, formatter: self.epilog def format_help(self, formatter=None, epilog=None): self.option_list.sort(key=operator.methodcaller('get_opt_string')) @@ -77,6 +78,20 @@ class CLI(object): self.action = None self.callback = callback + def _terminate(self, signum=None, framenum=None): + if signum == signal.SIGTERM: + if hasattr(os, 'getppid'): + display.debug("Termination requested in parent, shutting down gracefully") + signal.signal(signal.SIGTERM, signal.SIG_DFL) + else: + display.debug("Term signal in child, harakiri!") + signal.signal(signal.SIGTERM, signal.SIG_IGN) + + raise SystemExit + + #NOTE: if ever want to make this immediately kill children use on parent: + #os.killpg(os.getpgid(0), signal.SIGTERM) + def set_action(self): """ Get the action the user wants to execute from the sys argv list. @@ -109,6 +124,9 @@ class CLI(object): else: display.display(u"No config file found; using defaults") + # Manage user interruptions + signal.signal(signal.SIGTERM, self._terminate) + @staticmethod def ask_vault_passwords(ask_new_vault_pass=False, rekey=False): ''' prompt for vault password and/or password change ''' diff --git a/lib/ansible/cli/adhoc.py b/lib/ansible/cli/adhoc.py index 4cba2be16c..7a3e208f36 100644 --- a/lib/ansible/cli/adhoc.py +++ b/lib/ansible/cli/adhoc.py @@ -21,7 +21,6 @@ __metaclass__ = type ######################################################## import os -import signal from ansible import constants as C from ansible.cli import CLI @@ -89,11 +88,6 @@ class AdHocCLI(CLI): tasks = [ dict(action=dict(module=self.options.module_name, args=parse_kv(self.options.module_args)), async=async, poll=poll) ] ) - def _terminate(self, signum=None, framenum=None): - if signum is not None: - display.debug("Termination signal detected, shutting down gracefully") - raise SystemExit - def run(self): ''' use Runner lib to do SSH things ''' @@ -176,9 +170,6 @@ class AdHocCLI(CLI): # now create a task queue manager to execute the play self._tqm = None try: - # Manage user interruptions - signal.signal(signal.SIGTERM, self._terminate) - self._tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, diff --git a/lib/ansible/executor/playbook_executor.py b/lib/ansible/executor/playbook_executor.py index 83449f1435..ce91b7f602 100644 --- a/lib/ansible/executor/playbook_executor.py +++ b/lib/ansible/executor/playbook_executor.py @@ -19,11 +19,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -import getpass -import locale import os -import signal -import sys from ansible.compat.six import string_types @@ -32,8 +28,6 @@ from ansible.executor.task_queue_manager import TaskQueueManager from ansible.playbook import Playbook from ansible.template import Templar -from ansible.utils.unicode import to_unicode - try: from __main__ import display except ImportError: @@ -69,8 +63,6 @@ class PlaybookExecutor: may limit the runs to serialized groups, etc. ''' - signal.signal(signal.SIGTERM, self._terminate) - result = 0 entrylist = [] entry = {} @@ -207,10 +199,6 @@ class PlaybookExecutor: return result - def _terminate(self, signum=None, framenum=None): - display.debug("Termination signal detected, shutting down gracefully") - raise SystemExit - def _get_serialized_batches(self, play): ''' Returns a list of hosts, subdivided into batches based on