hryamzik
hryamzik

Reputation: 995

ansible: pass variable to a handler

I use an "eye" as a supervisor and on changes in templates have to runs something like this:

eye load service.rb
eye restart service.rb

I want to define this as a single handler for all the apps and call it like

eye reload appname

And in a handler operate like this:

- name: reload eye service
command: eye load /path/{{ service }}.rb && eye restart {{ service }}

But I can't find a way to pass variable to a handler. Is it possible?

Upvotes: 20

Views: 23361

Answers (4)

Kound
Kound

Reputation: 2531

Alternative: Just don't use handler but register variables

I found another solution that suggest simply not using handler but tasks.

You will need an extra step initializing the list of services to restart and yet another step to append the services to the list but you are much more flexible when to do things.

Note the unique at the final step, which is simulating the restarting of the services, preventing duplicate calls.

---
- name: Restart Services if config changed
  hosts: localhost
  tasks:
    - name: Set empty list of services to restart
      set_fact:
        ServicesToRestart: []

    - name: Create some config for 'my_service'
      template: src=my_config.j2 dest=/tmp/my_config
      register: my_config

    - name: Add service 'my_service' to restart list if config was changed
      set_fact:
         ServicesToRestart: "{{ ServicesToRestart + ['my_service'] }}"
      when: my_config.changed

    - name: Create some config for 'other_service'
      template: src=my_config.j2 dest=/tmp/my_config2
      register: my_config

    - name: Add service 'other_service' to restart list if config was changed
      set_fact:
         ServicesToRestart: "{{ ServicesToRestart + ['other_service'] }}"
      when: my_config.changed

    - name: Create some other config for 'other_service'
      template: src=my_config.j2 dest=/tmp/my_config3
      register: my_config

    - name: Add service 'other_service' to restart list if config was changed
      set_fact:
         ServicesToRestart: "{{ ServicesToRestart + ['other_service'] }}"
      when: my_config.changed

    - name: RestartServices
      debug:
        msg: "Restarting {{ item }}"
      loop: "{{ ServicesToRestart | unique }}"
      when: ServicesToRestart

Upvotes: 1

sorin
sorin

Reputation: 170430

You cannot do this but you can use set_fact in order set facts that can be accessed by the handler.

Upvotes: 0

George Shuklin
George Shuklin

Reputation: 7877

Don't do this. I understand your desire to use Ansible as a programming tool, where 'handler' is a 'function' you 'call', but it's not.

You can invent a dozen of tricks to do what you want, but result would be a total mess, hard to read and even harder to debug.

The key issue is that ansible does not support 'argument passing' to anything (except for modules). All tricks you read about or invent by yourself will change global variable. If you ever wrote at least bit in any language , you know, that program where every function is using global variables (for read and write, and to pass arguments) is fundamentally flawed.

So, how to do this in a very good and readable Ansible?

Yes, just wrote a separate handler for each service. It's the cleanest and simplest Ansible. Easy to read, easy to change.

BTW: if you have to actions in a chain, do not join them with '&&'.

Use two separate handlers:

- foo:
  notify:
    - eye reload
    - eye restart foo

(note, that order of handlers is defined in the handlers list, not the 'notify' list).

Btw, if you have few services you will save on multiple reload operations - 'eye reload' would be called once.

Upvotes: 4

Valeriy Solovyov
Valeriy Solovyov

Reputation: 5648

handlers/main.yml:

- name: restart my service
  shell: eye load /path/{{ service }}.rb && eye restart {{ service }}

So you can setup variable through default defaults/main.yml:

service : "service"

or you can define {{ service }} though command line:

ansible-playbook -i xxx path/to/playbook -e "service=service"

http://docs.ansible.com/ansible/playbooks_variables.html

PS: http://docs.ansible.com/ansible/playbooks_intro.html#playbook-language-

example
---
- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum: name=httpd state=latest
  - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
    notify:
    - restart apache
  - name: ensure apache is running (and enable it at boot)
    service: name=httpd state=started enabled=yes
  handlers:
    - name: restart apache
      service: name=httpd state=restarted

http://docs.ansible.com/ansible/playbooks_intro.html#handlers-running-operations-on-change

If you ever want to flush all the handler commands immediately though, in 1.2 and later, you can:

tasks:
   - shell: some tasks go here
   - meta: flush_handlers
   - shell: some other tasks

Upvotes: 0

Related Questions