How to loop thru win_updates until no updates left

Hi,

I’m using win_updates module to carry out windows patching and it works pretty good.
Sometime, updates have dependencies and multiple playbook execution required.

I was thinking, if possible, to loop the playbook until “found_update_count > 0” without the need of running ansible-playbook multiple time after each finish.

My playbook looks like this:

`

  • hosts: win_server_1
    ignore_errors: true
    gather_facts: true

tasks:

  • name: search wu
    win_updates:
    category_names:

  • UpdateRollups

  • CriticalUpdates

  • SecurityUpdates
    state:

  • searched
    log_path:

  • c:/temp/ansible_wu.txt
    register: searched

  • name: install wu
    win_updates:
    category_names:

  • UpdateRollups

  • CriticalUpdates

  • SecurityUpdates
    state:

  • installed
    log_path:

  • c:/temp/ansible_wu.txt
    register: installed
    when: searched.found_update_count > 0

  • name: reboot
    win_reboot:
    pre_reboot_delay_sec: 0
    test_command: whoami
    reboot_timeout_sec: 300
    when: installed.reboot_required = ‘true’
    register: reboot

`

I cant figure out how to put this in playbook by myself, seeking for some guidance.

Thanks,

I can’t from the top of my head recall if the “block” feature supports loops, but if it does I guess that’s the best way to do this.

As far as I can remember, Microsoft’s own config management tool for clients (SCCM) gets around this by simply doing 2 “passes” of patching. You could do that aswell, with some conditionals to only kick the second pass if it’s needed.

Hi,

Thank for the heads up but it seems like Block does not support ‘until’

`
ERROR! ‘until’ is not a valid attribute for a Block

`

I’ve also read a post by Brian Coca which stated that “blocks do not support any type of loop”.
What other options can be used to re-run multiple tasks (one that checks/installs updates and the other reboots the server) until no updates available?

Anyone? :frowning:

Never tried it myself, but wouldn't this work ?

- include: update-windows.yml
   until: <condition>
   retries: 10

You will have to make sure that the condition is based on facts from the tasks in your taskbook, which include win_updates and win_reboot.

The only other option I see is to add win_reboot capabilities to win_updates, which would be a shame if that's what is needed.

I actually tried this and it didn’t work.

Later, found this post https://groups.google.com/forum/#!topic/ansible-project/xGGe6WADtH0

I’ve found a working solution, it’s ugly and probably will cause more headache but it works.

My solution looks like this:

`

Nice trick, thank you for sharing this.

Jon

The solution Dag posted is what I’ve always done, and it works great for me. I’ve been advocating for block loop support (as a cleaner solution to exactly this issue) since before it shipped, but I don’t have the bandwidth to implement myself right now, and around here it’s kinda “put up or shut up”. :wink: If it doesn’t work for you, let us know why and maybe we can get it figured out.

I really wouldn’t recommend the “run the playbook in a loop” thing- you lose a lot of output fidelity and error handling, and it’s really just a way more expensive way to do what Dag suggested.

I actually originally wrote win_updates with a wrapper action that would handle the reboots automatically, but for various reasons (that I can’t recall) decided to abandon the wrapper before I shipped it…

-Matt

Hi Matt,

Dag’s solution was something I really hoped to work but then I found this post by Brian Coca - https://groups.google.com/forum/#!topic/ansible-project/xGGe6WADtH0

Seems like this is not possible because “Include is not a module, more like a preprocessing macro.”

Hi Danny,

Did you come across this post - https://groups.google.com/d/msg/ansible-project/E1ETAVoG6d0/6vC0PGCpAwAJ ?

Right now looping over includes is doable by doing a with_ statement. What I trying to achieve right now would look like:

  • include: run-in-loop.yml

with_sequence: start=0 end=<+INFINITE>
loop_control:
loop_var: main_item

You would need to break execution in the included playbook if you detect that updates are done using - http://stackoverflow.com/a/22760829

Regards,
Jinesh

That post is really old- include looping has worked for a long time…

Then I cannot figure out what am I doing wrong, can you please assist?

main.yml:

`

The example below is a hack but it has a useful property whereby tasks in the inner taskbook will not be run if the play was ended. i.e.

calling inner-taskbook 1st time

  • running tasks

calling inner-taskbook 2nd time

  • running tasks

calling inner-taskbook 3rd time

  • running tasks
  • play ended because we’ve determined that we’ve finished the work

calling inner-taskbook 4th time

  • noop

calling inner-taskbook 5th time

  • noop

calling inner-taskbook nth time

  • noop

So if you configure the with_sequence parameters as you would have done the “until:” command’s “retries” attribute then you kinda simulate the retry functionality with the example below.

You will notice that the taskbook does get “included” 100 times but the tasks in it are ONLY executed the number of times actually required.

run.sh:
—snip—
#!/usr/bin/env bash

ansible-playbook -vvv -i ‘localhost,’ -c local main.yml
—snip—

main.yml:

`

Ack. I just noticed that the example below is not a good solution since it never did run the “Performing tasks after windows updates.” task in the main.yml file.

Sorry. Please ignore the example.

Bummer, this was the best solution so far!