ansible: remove JobResultService, more compatible async jobs; closes #191.
And by "compatible" I mean "terrible". This does not implement async job timeouts, but I'm not going to bother, upstream async implementation is so buggy and inconsistent it resists even having its behaviour captured in tests.pull/197/head
parent
6ad18b6719
commit
85e1f5f515
@ -1,78 +0,0 @@
|
|||||||
# Copyright 2017, David Wilson
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer.
|
|
||||||
#
|
|
||||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
#
|
|
||||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
# may be used to endorse or promote products derived from this software without
|
|
||||||
# specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
# POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
import ansible.plugins.action
|
|
||||||
import mitogen.core
|
|
||||||
import mitogen.utils
|
|
||||||
import ansible_mitogen.services
|
|
||||||
import ansible_mitogen.target
|
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ansible.plugins.action.ActionBase):
|
|
||||||
def _get_async_result(self, job_id):
|
|
||||||
self._connection._connect()
|
|
||||||
return mitogen.service.call(
|
|
||||||
context=self._connection.parent,
|
|
||||||
handle=ansible_mitogen.services.JobResultService.handle,
|
|
||||||
method='get',
|
|
||||||
kwargs={
|
|
||||||
'job_id': job_id,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def _on_result_pending(self, job_id):
|
|
||||||
return {
|
|
||||||
'_ansible_parsed': True,
|
|
||||||
'ansible_job_id': job_id,
|
|
||||||
'started': 1,
|
|
||||||
'failed': 0,
|
|
||||||
'finished': 0,
|
|
||||||
'msg': '',
|
|
||||||
}
|
|
||||||
|
|
||||||
def _on_result_available(self, job_id, result):
|
|
||||||
dct = self._parse_returned_data(result)
|
|
||||||
dct['ansible_job_id'] = job_id
|
|
||||||
dct['started'] = 1
|
|
||||||
dct['finished'] = 1
|
|
||||||
|
|
||||||
# Cutpasted from the action.py.
|
|
||||||
if 'stdout' in dct and 'stdout_lines' not in dct:
|
|
||||||
dct['stdout_lines'] = (dct['stdout'] or u'').splitlines()
|
|
||||||
if 'stderr' in dct and 'stderr_lines' not in dct:
|
|
||||||
dct['stderr_lines'] = (dct['stderr'] or u'').splitlines()
|
|
||||||
return dct
|
|
||||||
|
|
||||||
def run(self, tmp=None, task_vars=None):
|
|
||||||
job_id = mitogen.utils.cast(self._task.args['jid'])
|
|
||||||
|
|
||||||
result = self._get_async_result(job_id)
|
|
||||||
if result is None:
|
|
||||||
return self._on_result_pending(job_id)
|
|
||||||
else:
|
|
||||||
return self._on_result_available(job_id, result)
|
|
@ -1,3 +1,5 @@
|
|||||||
- import_playbook: runner_job_timeout.yml
|
- import_playbook: result_binary_producing_json.yml
|
||||||
|
- import_playbook: result_binary_producing_junk.yml
|
||||||
|
- import_playbook: result_shell_echo_hi.yml
|
||||||
- import_playbook: runner_one_job.yml
|
- import_playbook: runner_one_job.yml
|
||||||
- import_playbook: runner_two_simultaneous_jobs.yml
|
- import_playbook: runner_two_simultaneous_jobs.yml
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
- name: integration/async/result_binary_producing_json.yml
|
||||||
|
gather_facts: true
|
||||||
|
hosts: all
|
||||||
|
any_errors_fatal: true
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- custom_binary_producing_json:
|
||||||
|
async: 100
|
||||||
|
poll: 0
|
||||||
|
register: job
|
||||||
|
|
||||||
|
- shell: sleep 1
|
||||||
|
|
||||||
|
- slurp:
|
||||||
|
src: "{{ansible_user_dir}}/.ansible_async/{{job.ansible_job_id}}"
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- debug: msg={{async_out}}
|
||||||
|
vars:
|
||||||
|
async_out: "{{result.content|b64decode|from_json}}"
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- async_out.changed == True
|
||||||
|
- async_out.failed == False
|
||||||
|
- async_out.msg == "Hello, world."
|
||||||
|
- 'async_out.stderr == "binary_producing_json: oh noes\n"'
|
||||||
|
vars:
|
||||||
|
async_out: "{{result.content|b64decode|from_json}}"
|
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
- name: integration/async/result_binary_producing_junk.yml
|
||||||
|
gather_facts: true
|
||||||
|
hosts: all
|
||||||
|
any_errors_fatal: true
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- custom_binary_producing_junk:
|
||||||
|
async: 100
|
||||||
|
poll: 0
|
||||||
|
register: job
|
||||||
|
|
||||||
|
- shell: sleep 1
|
||||||
|
|
||||||
|
- slurp:
|
||||||
|
src: "{{ansible_user_dir}}/.ansible_async/{{job.ansible_job_id}}"
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- debug: msg={{async_out}}
|
||||||
|
vars:
|
||||||
|
async_out: "{{result.content|b64decode|from_json}}"
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- async_out.ansible_job_id == job.ansible_job_id
|
||||||
|
- async_out.data == "Hello, world.\n"
|
||||||
|
- async_out.failed == 1
|
||||||
|
- async_out.msg.startswith("Traceback")
|
||||||
|
- '"ValueError: No start of json char found\n" in async_out.msg'
|
||||||
|
- 'async_out.stderr == "binary_producing_junk: oh noes\n"'
|
||||||
|
vars:
|
||||||
|
async_out: "{{result.content|b64decode|from_json}}"
|
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
- name: integration/async/result_shell_echo_hi.yml
|
||||||
|
gather_facts: true
|
||||||
|
hosts: all
|
||||||
|
any_errors_fatal: true
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- shell: echo hi
|
||||||
|
async: 100
|
||||||
|
poll: 0
|
||||||
|
register: job
|
||||||
|
|
||||||
|
- shell: sleep 1
|
||||||
|
|
||||||
|
- slurp:
|
||||||
|
src: "{{ansible_user_dir}}/.ansible_async/{{job.ansible_job_id}}"
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- debug: msg={{async_out}}
|
||||||
|
vars:
|
||||||
|
async_out: "{{result.content|b64decode|from_json}}"
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- async_out.changed == True
|
||||||
|
- async_out.cmd == "echo hi"
|
||||||
|
- 'async_out.delta.startswith("0:00:00")'
|
||||||
|
- async_out.end.startswith("20")
|
||||||
|
- async_out.invocation.module_args._raw_params == "echo hi"
|
||||||
|
- async_out.invocation.module_args._uses_shell == True
|
||||||
|
- async_out.invocation.module_args.chdir == None
|
||||||
|
- async_out.invocation.module_args.creates == None
|
||||||
|
- async_out.invocation.module_args.executable == None
|
||||||
|
- async_out.invocation.module_args.removes == None
|
||||||
|
- async_out.invocation.module_args.stdin == None
|
||||||
|
- async_out.invocation.module_args.warn == True
|
||||||
|
- async_out.rc == 0
|
||||||
|
- async_out.start.startswith("20")
|
||||||
|
- async_out.stderr == ""
|
||||||
|
- async_out.stdout == "hi"
|
||||||
|
vars:
|
||||||
|
async_out: "{{result.content|b64decode|from_json}}"
|
Loading…
Reference in New Issue