added 'task timeout' feature (#69284)
* added 'task timeout' feature Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
This commit is contained in:
parent
ac533403e3
commit
df4e83deda
6 changed files with 46 additions and 0 deletions
|
@ -68,6 +68,7 @@ serial: |
|
|||
strategy: Allows you to choose the connection plugin to use for the play.
|
||||
tags: Tags applied to the task or included tasks, this allows selecting subsets of tasks from the command line.
|
||||
tasks: Main list of tasks to execute in the play, they run after :term:`roles` and before :term:`post_tasks`.
|
||||
timeout: Time limit for task to execute in, if exceeded Ansible will interrupt and fail the task.
|
||||
throttle: Limit number of concurrent task runs on task, block and playbook level. This is independent of the forks and serial settings, but cannot be set higher than those limits. For example, if forks is set to 10 and the throttle is set to 15, at most 10 hosts will be operated on in parallel.
|
||||
until: "This keyword implies a ':term:`retries` loop' that will go on until the condition supplied here is met or we hit the :term:`retries` limit."
|
||||
vars: Dictionary/map of variables
|
||||
|
|
|
@ -1844,6 +1844,17 @@ TAGS_SKIP:
|
|||
ini:
|
||||
- {key: skip, section: tags}
|
||||
version_added: "2.5"
|
||||
TASK_TIMEOUT:
|
||||
name: Task Timeout
|
||||
default: 0
|
||||
description:
|
||||
- Set the maximum time (in seconds) that a task can run for.
|
||||
- If set to 0 (the default) there is no timeout.
|
||||
env: [{name: ANSIBLE_TASK_TIMEOUT}]
|
||||
ini:
|
||||
- {key: task_timeout, section: defaults}
|
||||
type: integer
|
||||
version_added: '2.10'
|
||||
WORKER_SHUTDOWN_POLL_COUNT:
|
||||
name: Worker Shutdown Poll Count
|
||||
default: 0
|
||||
|
|
|
@ -9,6 +9,7 @@ import re
|
|||
import pty
|
||||
import time
|
||||
import json
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import termios
|
||||
|
@ -39,6 +40,14 @@ display = Display()
|
|||
__all__ = ['TaskExecutor']
|
||||
|
||||
|
||||
class TaskTimeoutError(BaseException):
|
||||
pass
|
||||
|
||||
|
||||
def task_timeout(signum, frame):
|
||||
raise TaskTimeoutError
|
||||
|
||||
|
||||
def remove_omit(task_args, omit_token):
|
||||
'''
|
||||
Remove args with a value equal to the ``omit_token`` recursively
|
||||
|
@ -651,6 +660,9 @@ class TaskExecutor:
|
|||
for attempt in xrange(1, retries + 1):
|
||||
display.debug("running the handler")
|
||||
try:
|
||||
if self._task.timeout:
|
||||
old_sig = signal.signal(signal.SIGALRM, task_timeout)
|
||||
signal.alarm(self._task.timeout)
|
||||
result = self._handler.run(task_vars=variables)
|
||||
except AnsibleActionSkip as e:
|
||||
return dict(skipped=True, msg=to_text(e))
|
||||
|
@ -658,7 +670,13 @@ class TaskExecutor:
|
|||
return dict(failed=True, msg=to_text(e))
|
||||
except AnsibleConnectionFailure as e:
|
||||
return dict(unreachable=True, msg=to_text(e))
|
||||
except TaskTimeoutError as e:
|
||||
msg = 'The %s action failed to execute in the expected time frame (%d) and was terminated' % (self._task.action, self._task.timeout)
|
||||
return dict(failed=True, msg=msg)
|
||||
finally:
|
||||
if self._task.timeout:
|
||||
signal.alarm(0)
|
||||
old_sig = signal.signal(signal.SIGALRM, old_sig)
|
||||
self._handler.cleanup()
|
||||
display.debug("handler run complete")
|
||||
|
||||
|
|
|
@ -614,6 +614,7 @@ class Base(FieldAttributeBase):
|
|||
_diff = FieldAttribute(isa='bool', default=context.cliargs_deferred_get('diff'))
|
||||
_any_errors_fatal = FieldAttribute(isa='bool', default=C.ANY_ERRORS_FATAL)
|
||||
_throttle = FieldAttribute(isa='int', default=0)
|
||||
_timeout = FieldAttribute(isa='int', default=C.TASK_TIMEOUT)
|
||||
|
||||
# explicitly invoke a debugger on tasks
|
||||
_debugger = FieldAttribute(isa='string')
|
||||
|
|
|
@ -4,3 +4,6 @@ set -eux
|
|||
|
||||
# run type tests
|
||||
ansible-playbook -i ../../inventory types.yml -v "$@"
|
||||
|
||||
# test timeout
|
||||
ansible-playbook -i ../../inventory timeout.yml -v "$@"
|
||||
|
|
12
test/integration/targets/playbook/timeout.yml
Normal file
12
test/integration/targets/playbook/timeout.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
- hosts: localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- shell: sleep 100
|
||||
timeout: 1
|
||||
ignore_errors: true
|
||||
register: time
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- time is failed
|
||||
- '"The command action failed to execute in the expected time frame" in time["msg"]'
|
Loading…
Reference in a new issue