1

I'm quite new to ansible and I have been working on writing an ansible role to automate the incremental upgrade process for Jenkins. Part of this process has involved creating a loop which executes on the condition that the current version of Jenkins installed on the instance is older than the target version.

# Install the incremental upgraded version of Jenkins
- name: upgrade and restart jenkins on each iterative upgrade
  yum:
    name: "jenkins-{{ item.jenkins_target_version }}"
    state: present
  when: (jenkins_current_version | float) < "{{ item.jenkins_target_version_filtered }}"
  loop: "{{ packages }}"
  notify: restart jenkins
  when: (jenkins_current_version | float) < jenkins_target_filtered

The loop should cycle through the list of packages which looks like this

packages:
  - { jenkins_target_version: 2.176-1.1, jenkins_target_version_filtered: 2.176 }
  - { jenkins_target_version: 2.190-1.1, jenkins_target_version_filtered: 2.190 }
  - { jenkins_target_version: 2.204-1.1, jenkins_target_version_filtered: 2.204 }
  - { jenkins_target_version: 2.222-1.1, jenkins_target_version_filtered: 2.222 }
  - { jenkins_target_version: 2.235-1.1, jenkins_target_version_filtered: 2.235 }
  - { jenkins_target_version: 2.249-1.1, jenkins_target_version_filtered: 2.249 }
  - { jenkins_target_version: 2.263-1.1, jenkins_target_version_filtered: 2.263 }
  - { jenkins_target_version: 2.277-1.1, jenkins_target_version_filtered: 2.277 }
  - { jenkins_target_version: 2.289-1.1, jenkins_target_version_filtered: 2.289 }
  - { jenkins_target_version: 2.303-1.1, jenkins_target_version_filtered: 2.303 }
  - { jenkins_target_version: 2.319-1.1, jenkins_target_version_filtered: 2.319 }
  - { jenkins_target_version: 2.332-1.1, jenkins_target_version_filtered: 2.332 }
  - { jenkins_target_version: 2.343-1.1, jenkins_target_version_filtered: 2.343 }
  - { jenkins_target_version: 2.346-1.1, jenkins_target_version_filtered: 2.346 }

And only install the version on the target system if it is a newer iteration than what is currently installed. The loop seems to work correctly and installs the upgrade of jenkins on the target instance, the problem is that I want to execute a series of handler tasks whenever jenkins has been upgraded.

The handlers are a series of tasks stored in a file in the handlers folder that restart the service and check that things are back up and running ok (among other things). The problem is that the handler tasks are not called and executed upon completion of each iterative upgrade. I'm looking for advice on how I can make this happen, thanks in advance.

U880D
  • 8,601
  • 6
  • 24
  • 40
Bert
  • 83
  • 3
  • 1
    You cannot really do this via handlers, as handlers will only run [once per play](https://docs.ansible.com/ansible/latest/user_guide/playbooks_handlers.html#controlling-when-handlers-run). You can, probably bend handlers into achieve what you want, but the most probably is that what you really want is to loop on a set of tasks, which sequence will be _install, boot, checks_. – β.εηοιτ.βε Sep 15 '22 at 13:18
  • Thanks for your input, but isn't it true, that you can only execute one task in an ansible loop at a time? – Bert Sep 15 '22 at 13:34
  • 3
    You can loop on an `include_tasks`: https://stackoverflow.com/questions/33701369/how-can-ansible-loop-over-a-sequence-of-tasks – β.εηοιτ.βε Sep 15 '22 at 13:44
  • 3
    I suggest you have a look at existing tests for [comparing version](https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html#comparing-versions) – Zeitounator Sep 15 '22 at 13:51

1 Answers1

2

Q: "I want to execute a series of handler tasks."

A: Use the keyword listen to select more tasks. For example, given the handlers

shell> cat handlers/restart_jenkins.yml
- debug:
    msg: Restart service
  listen: restart jenkins

- debug:
    msg: Check that things are back up and running ok
  listen: restart jenkins

- debug:
    msg: |-
      Do whatever you want next
      {{ out.results|json_query('[].stdout') }}
  listen: restart jenkins

The playbook

- hosts: test_11
  gather_facts: false
  vars:
    packages:
      - {target: 2.176-1.1, current: 2.176}
      - {target: 2.190-1.1, current: 2.190}
      - {target: 2.204-1.1, current: 2.205}
  tasks:
    - command: "echo install {{ item.target }}"
      register: out
      notify: restart jenkins
      loop: "{{ packages }}"
      when: item.current is version(item.target, "<")
    - meta: flush_handlers
    - debug:
        msg: Continue ...
  handlers:
    - import_tasks: handlers/restart_jenkins.yml

gives

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

TASK [command] *******************************************************************************
changed: [test_11] => (item={'target': '2.176-1.1', 'current': 2.176})
changed: [test_11] => (item={'target': '2.190-1.1', 'current': 2.19})
skipping: [test_11] => (item={'target': '2.204-1.1', 'current': 2.205}) 

TASK [meta] **********************************************************************************

RUNNING HANDLER [debug] **********************************************************************
ok: [test_11] => 
  msg: Restart service

RUNNING HANDLER [debug] **********************************************************************
ok: [test_11] => 
  msg: Check that things are back up and running ok

RUNNING HANDLER [debug] **********************************************************************
ok: [test_11] => 
  msg: |-
    Do whatever you want next
    ['install 2.176-1.1', 'install 2.190-1.1']

TASK [debug] *********************************************************************************
ok: [test_11] => 
  msg: Continue ...

PLAY RECAP ***********************************************************************************
test_11                    : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Notes:

  • The use case of installing new versions in a loop doesn't make sense. The play here serves the only purpose of demonstrating the functionality of handlers.
  • Flush the handlers if you don't want to wait till the end of the playbook.
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • Thanks for the feedback on handlers, this was useful. I cant seem to apply the meta: flush_handlers within my loop though such that the service restart occurs between each iterative upgrade. Any suggestions? – Bert Sep 16 '22 at 13:15
  • Of course, you can't. Imagine how Ansible works. The controller packs the data (module, parameters, iteration, ...) and sends it to the remote hosts. At the remote hosts, the unpacked data control the execution. When finished the remote hosts send back the results. The controller knows nothing about the intermediate results of a loop at the remote host. You can't expect to trigger handlers within a loop. But, I'm sure there will be a solution to your problem. You have to describe it in detail. See [mre]. – Vladimir Botka Sep 16 '22 at 13:31