tbox
tbox

Reputation: 199

Getting the status of Ansible import_tasks to satisfy an until loop's condition

I'm attempting to get an until loop working for an import_tasks, and to break the loop when it meets a condition within the import_tasks. Not sure if this is even possible, or if there's a better way to acheive this? Making it slightly more tricky is one of the tasks in include_tasks is a powershell script which returns a status message which is used to satisfy the until requirement.

So yeah, the goal is to run check_output.yml until there is no longer any RUNNING status reported by the script.

main.yml:

- import_tasks: check_output.yml
    until: "'RUNNING' not in {{outputStatus}}"
    retries: 100
    delay: 120

check_output.yml

---
- name: "Output Check"
  shell: ./get_output.ps1" # this will return `RUNNING` in std_out if it's still running
  args:
    executable: /usr/bin/pwsh
  register: output

- name: "Debug output"
  debug: outputStatus=output.stdout_lines

For the record, this works just fine if I don't use import_tasks and just use an until loop on the "Output Check" task. The problem with that approach is you have to run Ansible with -vvv to get the status message for each of the loops which causes a ton of extra, unwanted debug messages. I'm trying to get the same status for each loop without having to add verbosity.

Ansible version is 2.11

Upvotes: 1

Views: 326

Answers (1)

Vladimir Botka
Vladimir Botka

Reputation: 68004

Q: "(Wait) until there is no longer any RUNNING status reported by the script."

A: An option might be the usage of the module wait_for.

For example, create the script on the remote host. The script takes two parameters. The PID of a process to be monitored and DELAY monitoring interval in seconds. The script writes the status to /tmp/$PID.status

# cat /root/bin/get_status.sh 
#!/bin/sh
PID=$1
DELAY=$2
ps -p $PID > /dev/null 2>&1
STATUS=$?
while [ "$STATUS" -eq "0" ]
do
   echo "$PID is RUNNING" > /tmp/$PID.status
   sleep $DELAY
   ps -p $PID > /dev/null 2>&1
   STATUS=$?
done
echo "$PID is NONEXIST" > /tmp/$PID.status
exit 0

Start the script asynchronously

    - command: "/root/bin/get_status.sh {{ _pid }} {{ _delay }}"
      async: "{{ _timeout }}"
      poll: 0
      register: get_status

In the next step wait for the process to stop running

    - wait_for:
        path: "/tmp/{{ _pid }}.status"
        search_regex: NONEXIST
      retries: "{{ _retries }}"
      delay: "{{ _delay }}"

After the condition passed or the module wait_for reached the timeout run async_status to make sure the script terminated

    - async_status:
        jid: "{{ get_status.ansible_job_id }}"
      register: job_result
      until: job_result.finished
      retries: "{{ _retries }}"
      delay: "{{ _delay }}"

Example of a complete playbook

- hosts: test_11

  vars:
    _timeout: 60
    _retries: "{{ (_timeout/_delay|int)|int }}"

  tasks:
    - debug:
        msg: |-
          time: {{ '%H:%M:%S'|strftime }}
          _pid: {{ _pid }}
          _delay: {{ _delay }}
          _timeout: {{ _timeout }}
          _retries: {{ _retries }}
      when: debug|d(false)|bool
    - command: "/root/bin/get_status.sh {{ _pid }} {{ _delay }}"
      async: "{{ _timeout }}"
      poll: 0
      register: get_status
    - debug:
        var: get_status
      when: debug|d(false)|bool
    - wait_for:
        path: "/tmp/{{ _pid }}.status"
        search_regex: NONEXIST
      retries: "{{ _retries }}"
      delay: "{{ _delay }}"
    - debug:
        msg: "time: {{ '%H:%M:%S'|strftime }}"
      when: debug|d(false)|bool
    - async_status:
        jid: "{{ get_status.ansible_job_id }}"
      register: job_result
      until: job_result.finished
      retries: "{{ _retries }}"
      delay: "{{ _delay }}"
    - debug:
        msg: "time: {{ '%H:%M:%S'|strftime }}"
      when: debug|d(false)|bool
    - file:
        path: "/tmp/{{ _pid }}.status"
        state: absent
      when: _cleanup|d(true)|bool

On the remote, start a process to be monitored. For example,

root@test_11:/ # sleep 60 &
[1] 28704

Run the playbook. Fit _timeout and _delay to your needs

shell> ansible-playbook pb.yml -e debug=true -e _delay=3 -e _pid=28704

PLAY [test_11] *******************************************************************************

TASK [debug] *********************************************************************************
ok: [test_11] => 
  msg: |-
    time: 09:06:34
    _pid: 28704
    _delay: 3
    _timeout: 60
    _retries: 20

TASK [command] *******************************************************************************
changed: [test_11]

TASK [debug] *********************************************************************************
ok: [test_11] => 
  get_status:
    ansible_job_id: '331975762819.28719'
    changed: true
    failed: 0
    finished: 0
    results_file: /root/.ansible_async/331975762819.28719
    started: 1

TASK [wait_for] ******************************************************************************
ok: [test_11]

TASK [debug] *********************************************************************************
ok: [test_11] => 
  msg: 'time: 09:07:27'

TASK [async_status] **************************************************************************
changed: [test_11]

TASK [debug] *********************************************************************************
ok: [test_11] => 
  msg: 'time: 09:07:28'

TASK [file] **********************************************************************************
changed: [test_11]

PLAY RECAP ***********************************************************************************
test_11: ok=8    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Upvotes: 1

Related Questions