ansible / ansible-runner

A tool and python library that helps when interfacing with Ansible directly or as part of another system whether that be through a container image interface, as a standalone tool, or as a Python module that can be imported. The goal is to provide a stable and consistent interface abstraction to Ansible.
Other
969 stars 357 forks source link

Runner's stats and playbook pause (ctrl+c) combination #1359

Open mkyrc opened 6 months ago

mkyrc commented 6 months ago

Hello, I'd like to solve the issue with playbook with pause task combined with calling playbook by ansible_runner.run_command(). We need to call ansible-playbook from python code and read playbook results/stats (not scanning stdout and reading lines after "RECAP").

Based on run_command() documentation - "Run an (Ansible) commands in the foreground and return a Runner object when complete." I'd like to get Runner's stats value. Note: Method description is wrong, because this method doesn't return Runner, it returns only a tuple of response, error string and return code.

Based on source code I prepared my custom Python code (a very limited part of the code - just to show the problem):

    def runner_run_command_test(self):

        runner_opts = {
            "executable_cmd": "ansible-playbook",
            "cmdline_args": ["ansible/playbooks/test.pb.yaml"],
            # "envvars": env,
            # "input_fd": sys.stdin,
            # "error_fd": sys.stderr,
            # "output_fd": sys.stdout,
            # "runner_mode": "pexpect",
            # "runner_mode": "subprocess",
        }

        resp = {}
        try:
            runner = ansible_runner.interface.init_command_config(**runner_opts)
            runner.run()

            resp = {
                "stats": runner.stats,  # << focus on stats
                "rc": runner.rc,
                "satus": runner.status,
                # "response": runner.stdout.read(),
                "error": runner.stderr.read(),
            }
        except KeyboardInterrupt:
            print("User interrupted.")

        print(f"result:\n{resp}")

        return resp

test playbook:

---
- name: "F5: test PB"
  hosts: localhost
  gather_facts: false

  tasks:
    - name: "TSK #1: test message"
      ansible.builtin.debug:
        msg: "this is test message"

    - name: "TSK #2: continue?"
      ansible.builtin.pause:
        seconds: 5

    - name: "TSK #3: test message"
      ansible.builtin.debug:
        msg: "this is test message"

With above runner_opts settings I got this response (including correct stats):

PLAY [F5: test PB] *************************************************************

TASK [TSK #1: test message] ****************************************************
ok: [localhost] => {
    "msg": "this is test message"
}

TASK [TSK #2: continue?] *******************************************************
Pausing for 5 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [localhost]

TASK [TSK #3: test message] ****************************************************
ok: [localhost] => {
    "msg": "this is test message"
}

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
Result: {'stats': {'skipped': {}, 'ok': {'localhost': 3}, 'dark': {}, 'failures': {}, 'ignored': {}, 'rescued': {}, 'processed': {'localhost': 1}, 'changed': {}}, 'rc': 0, 'satus': 'successful', 'error': ''}

problem: 'Ctrl+C' within pause task is interrupting playbook process and it's not send to pause task as expected

TASK [TSK #2: continue?] *******************************************************
Pausing for 5 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
^CUser interrupted.
Result: {}

problem with input_fb setting: when we add input_fd settings the all playbook outputs are not displaying continuously but at ones after all tasks are called. there is no possibility to see/stop pause task part. requested stats are there:

runner_opts = {
            "executable_cmd": "ansible-playbook",
            "cmdline_args": ["ansible/playbooks/test.pb.yaml"],
            "input_fd": sys.stdin,
        }

result summary:

Result: {'stats': {'skipped': {}, 'ok': {'localhost': 3}, 'dark': {}, 'failures': {}, 'ignored': {}, 'rescued': {}, 'processed': {'localhost': 1}, 'changed': {}}, 'rc': 0, 'satus': 'successful', 'error':  '' }

problem with input_fd and output_fd setting: with this settings is pause working as expected, also playbook output is displayed continuously, but stats is missing (it's None)

runner_opts = {
            "executable_cmd": "ansible-playbook",
            "cmdline_args": ["ansible/playbooks/test.pb.yaml"],
            "input_fd": sys.stdin,
            "output_fd": sys.stdout,
        }

result summary (stats is None):

Result: {'stats': None, 'rc': 0, 'satus': 'successful', 'error': ''}

stats property source code is not very helpful (for me).

Result It seems, that "runner_mode": "subprocess" setting (enabled with input_fd) is required to send 'Ctrl+C' to task. But I need also output_fd for continuously output and this setting 'currupt' stats data. Documentation is not very clear why it happens.

Any ideas how to solve this issue?

Versions:

UPDATE: When we use run() instead of run_command() we can get stats correctly, but no input to stdin is possible to send (ctrl+c imn pause task is not working)