1

I have a role, foo that installs a file {{ foo_path }} that's defined in roles/defaults/main.yml.

I have a second role, bar that depends on that file being there. I could put foo in the roles/meta/main.yml dependencies but then it will run the entire role which is not ideal. I could potentially tag the task in the role that creates the file, but that's not really scalable, and introduces problems when I'm not the owner of that role's code.

I could just assert that the file is there, but the problem is that I don't know where "there" is.

How can I load the foo_path var from a different role without the overhead of running the play?

1 Answer 1

2

Given the foo defaults

shell> cat roles/foo/defaults/main.yml 
foo_path: /tmp/test.txt

There are more options:

  1. Include the foo defaults into a dictionary and get the variable foo_path
shell> cat pb_bar.yml
- hosts: localhost
  pre_tasks:
    - include_vars:
        file: roles/foo/defaults/main.yml
        name: foo_defaults
    - debug:
        var: foo_defaults.foo_path
      when: debug|d(false)|bool
    - set_fact:
        foo_path: "{{ foo_defaults.foo_path }}"
  roles:
    - bar

Use the variable in the role bar

shell> cat roles/bar/tasks/main.yml
- stat:
    path: "{{ foo_path }}"
  register: foo_path_st
- debug:
    var: foo_path_st
  when: debug|d(false)|bool
- assert:
    that: foo_path_st.stat.exists

gives

shell> ansible-playbook pb_bar.yml -e debug=true

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

TASK [include_vars] **************************************************************************
ok: [localhost]

TASK [debug] *********************************************************************************
ok: [localhost] => 
  foo_defaults.foo_path: /tmp/test.txt

TASK [set_fact] ******************************************************************************
ok: [localhost]

TASK [Assert foo_path] ***********************************************************************
skipping: [localhost]

TASK [bar : stat] ****************************************************************************
ok: [localhost]

TASK [bar : debug] ***************************************************************************
ok: [localhost] => 
  foo_path_st:
    ansible_facts:
      discovered_interpreter_python: /usr/bin/python3
    changed: false
    failed: false
    stat:
      ...
      exists: true
      ...
      path: /tmp/test.txt

TASK [bar : assert] **************************************************************************
ok: [localhost] => changed=false 
  msg: All assertions passed

PLAY RECAP ***********************************************************************************
localhost: ok=6    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

  1. Structure the roles' tasks
shell> tree roles
roles
├── bar
│   └── tasks
│       └── main.yml
└── foo
    ├── defaults
    │   └── main.yml
    └── tasks
        ├── assert_foo_path.yml
        ├── install_foo_path.yml
        └── main.yml

5 directories, 5 files
shell> cat roles/foo/tasks/assert_foo_path.yml 
- stat:
    path: "{{ foo_path }}"
  register: foo_path_st
- debug:
    var: foo_path_st
  when: debug|d(false)|bool
- assert:
    that: foo_path_st.stat.exists

shell> cat roles/foo/tasks/install_foo_path.yml 
- file:
    path: "{{ foo_path }}"
    state: touch

shell> cat roles/foo/tasks/main.yml 
- name: Install foo_path
  include_tasks: install_foo_path.yml
- name: Assert foo_path
  include_tasks: assert_foo_path.yml

and use the module include_role

shell> cat roles/bar/tasks/main.yml 
- name: Assert foo_path
  include_role:
    name: foo
    tasks_from: assert_foo_path.yml

Create playbooks for testing

shell> cat pb_foo.yml 
- hosts: localhost
  roles:
    - foo

shell> cat pb_bar.yml 
- hosts: localhost
  roles:
    - bar

The play will fail if the file is missing

shell> ansible-playbook pb_bar.yml -e debug=false

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

TASK [Assert foo_path] ***********************************************************************

TASK [foo : stat] ****************************************************************************
ok: [localhost]

TASK [foo : debug] ***************************************************************************
skipping: [localhost]

TASK [foo : assert] **************************************************************************
fatal: [localhost]: FAILED! => changed=false 
  assertion: foo_path_st.stat.exists
  evaluated_to: false
  msg: Assertion failed

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

Create the file

shell> ansible-playbook pb_foo.yml -e debug=false

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

TASK [foo : Install foo_path] ****************************************************************
included: /export/scratch/tmp7/test-321/roles/foo/tasks/install_foo_path.yml for localhost

TASK [foo : file] ****************************************************************************
changed: [localhost]

TASK [foo : Assert foo_path] *****************************************************************
included: /export/scratch/tmp7/test-321/roles/foo/tasks/assert_foo_path.yml for localhost

TASK [foo : stat] ****************************************************************************
ok: [localhost]

TASK [foo : debug] ***************************************************************************
skipping: [localhost]

TASK [foo : assert] **************************************************************************
ok: [localhost] => changed=false 
  msg: All assertions passed

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

The assert task will succeed now

TASK [foo : assert] **************************************************************************
ok: [localhost] => changed=false 
  msg: All assertions passed
1
  • The splitting of the tasks is interesting, I hadn't thought of that. I don't necessarily like #1 because the foo role will always need that variable to be defined and that is not apparent when creating the play. It'd also be cumbersome and redundant to have to do that for every playbook that decides to include that role. May 4, 2023 at 14:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.