4
votes

Does ansible pass Role Default variables to the Handlers within the same Role?

Here's a minimal excerpt of the playbook that has the issue:

Role hierarchy

- playbook.yml
- roles/
  - gunicorn/
    - defaults/
      - main.yml
    - handlers/
      - main.yml
  - code-checkout/
    - tasks/
      - main.yml

Here's the file contents

gunicorn/defaults/main.yml

---
gu_log: "/tmp/gunicorn.log"

gunicorn/handlers/main.yml

---
- name: Clear Gunicorn Log
  shell: rm {{ gu_log }}

finalize/tasks/main.yml

---
- name: Test Handlers
  shell: ls
  notify:
    - Restart Gunicorn

playbook.yml

---
  - name: Deploy
    hosts: webservers
    tasks:
      - include: roles/finalize/tasks/main.yml
    handlers:
      - include: roles/gunicorn/handlers/main.yml

AFAIK everything looks good. However, I get this error during the playbook execution

FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'gu_log' is undefined\n\nThe error appears to have been in '/roles/gunicorn/handlers/main.yml': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Restart Gunicorn\n ^ here\n"}

Using Ansible 2.2 on Ubuntu 12.04 LTS

Here's a modified version of techraf's script that creates all the directories and demonstrates my issue

#!/bin/bash

mkdir -p ./rtindru-test/roles/gunicorn
mkdir -p ./rtindru-test/roles/gunicorn/defaults
mkdir -p ./rtindru-test/roles/gunicorn/handlers
mkdir -p ./rtindru-test/roles/finalize/tasks

cat >./rtindru-test/roles/finalize/tasks/main.yml <<HANDLERS_END
---
- name: Test Handlers
  shell: rm {{ gu_log }}
HANDLERS_END

cat >./rtindru-test/roles/gunicorn/handlers/main.yml <<HANDLERS_END
---
- name: Clear Gunicorn Log
  shell: rm {{ gu_log }}
HANDLERS_END

cat >./rtindru-test/roles/gunicorn/defaults/main.yml <<DEFAULTS_END
---
gu_log: "/tmp/gunicorn.log"
DEFAULTS_END

cat >./rtindru-test/playbook.yml <<PLAYBOOK_END
---
  - name: Deploy
    hosts: localhost
    tasks:
      - include: roles/finalize/tasks/main.yml
    handlers:
      - include: roles/gunicorn/handlers/main.yml
PLAYBOOK_END

touch /tmp/gunicorn.log
ls -l /tmp/gunicorn.log
ansible-playbook ./rtindru-test/playbook.yml
ls -l /tmp/gunicorn.log

Output

PLAY [Deploy]


TASK [setup] ******************************************************************* ok: [localhost]

TASK [Test Handlers] *********************************************************** fatal: [localhost]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'gu_log' is undefined\n\nThe error appears to have been in '/rtindru-test/roles/finalize/tasks/main.yml': line 2, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n---\n- name: Test Handlers\n ^ here\n"} to retry, use: --limit @/rtindru-test/playbook.retry

PLAY RECAP ********************************************************************* localhost : ok=1 changed=0 unreachable=0
failed=1

1
@techraf Ansible roles are intended to be fairly independent - and this is my "Complete" role. What more information would you need to respond?rtindru
try gu_log = "/tmp/gunicorn.log" just a guessqwazer
your inventory and/or playbook is missingJojo
Now that you included the missing parts, it is clear you are neither defining nor using any role. You are just including a few files from subdirectories which you named to mimic the directory names inside a role. The answer as I posted before is even more valid - notice roles: inside the playbook.techraf
I already replied in the answer - if you want to use roles, you need to use roles. You can't include one file and expect that the functionality of roles magically appears. I don't understand what you want to achieve by copying the code from the answer to the question, modifying the code to break it, and claiming it does not work. Yes, if you break the code, it does not work.techraf

1 Answers

2
votes

You are neither defining nor using any roles. With the following task:

- include: roles/finalize/tasks/main.yml

you are only including a tasks file into your playbook. It has nothing to do with roles.

To assign a role you should specify a list of roles for a play (one or more):

role:
  - my_role1
  - my_role2

Please have a look at the documentation on roles and feel free to use the playbook and structure as created by the below script.

Does ansible pass Role Default variables to the Handlers within the same Role?

Yes it does.

For a proof run the following bash script which creates and runs a minimal example. It takes the contents of gunicorn/defaults/main.yml and gunicorn/handlers/main.yml from the question intact and adds missing components: the tasks and the playbook. It creates a file to be removed and runs the playbook.

#!/bin/bash

mkdir -p ./so41285033/roles/gunicorn
mkdir -p ./so41285033/roles/gunicorn/defaults
mkdir -p ./so41285033/roles/gunicorn/handlers
mkdir -p ./so41285033/roles/gunicorn/tasks

cat >./so41285033/roles/gunicorn/tasks/main.yml <<TASKS_END
---
- debug:
  changed_when: true
  notify: Clear Gunicorn Log
TASKS_END

cat >./so41285033/roles/gunicorn/handlers/main.yml <<HANDLERS_END
---
- name: Clear Gunicorn Log
  shell: rm {{ gu_log }}
  when: "'apiservers' not in group_names"
HANDLERS_END

cat >./so41285033/roles/gunicorn/defaults/main.yml <<DEFAULTS_END
---
gu_log: "/tmp/gunicorn.log"
DEFAULTS_END

cat >./so41285033/playbook.yml <<PLAYBOOK_END
---
- hosts: localhost
  gather_facts: no
  connection: local
  roles:
    - gunicorn
PLAYBOOK_END

touch /tmp/gunicorn.log
ls -l /tmp/gunicorn.log
ansible-playbook ./so41285033/playbook.yml
ls -l /tmp/gunicorn.log

The result:

-rw-r--r--  1 techraf  wheel  0 Dec 23 07:57 /tmp/gunicorn.log
 [WARNING]: Host file not found: /etc/ansible/hosts

 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [localhost] ***************************************************************

TASK [gunicorn : debug] ********************************************************
ok: [localhost] => {
    "msg": "Hello world!"
}

RUNNING HANDLER [gunicorn : Clear Gunicorn Log] ********************************
changed: [localhost]
 [WARNING]: Consider using file module with state=absent rather than running rm


PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0

ls: /tmp/gunicorn.log: No such file or directory

Interpretation:

  • Before running the playbook the file /tmp/gunicorn.log was created and its existence verified:

    -rw-r--r--  1 techraf  wheel  0 Dec 23 07:57 /tmp/gunicorn.log
    
  • After running the playbook the file /tmp/gunicorn.log does not exist:

    ls: /tmp/gunicorn.log: No such file or directory
    
  • Ansible correctly passed the variable gu_log value to the Clear Gunicorn Log handler which removed the file.

Final remark:

The problem described in question is impossible to reproduce, because the question does not contain complete nor verifiable example in the meaning of MCVE.