0
votes

All files is

# roles/a/defaults/main.yml
test: Role A

# roles/a/tasks/main.yml
- name: Things I dont want to run
  debug: msg="Not expected"


# hosts
host-1 host-1 ansible_connection=local test=Override


# test.yml
- hosts: all
  roles:
    - a # I only need the variable
  tasks:
    - name: action
      debug: var=test # Expected Override

How can I do this ?

I thought about this

roles/
    a-var # only include defaults variable definition
    a # depends on a-var
    b # depends on a-var, but do not run role a's task

Kind of cumbersome,but I think this might the only way to work around.

Why I want this is I don't want the user care about too many files (group_vars,host_vars,extra_vars) ,and they don't know ansible,I have to deploy our system as easy as possible, the only thing they need to care about is inventory files,like this

host-1
host-2

[a]
host-1 port=1234

[b]
host-2 # use default port defined in role

[all:vars]
install_path=/opt # override the default path

But the order to load variable is

  • role defaults
  • inventory vars
  • inventory group_vars
  • inventory host_vars
  • playbook group_vars
  • playbook host_vars
  • host facts
  • registered vars
  • set_facts
  • play vars
  • play vars_prompt
  • play vars_files
  • role and include vars
  • block vars (only for tasks in block)
  • task vars (only for the task)
  • extra vars (always win precedence)

this is hard for this organize,because I can't do this,var files will beat inventory config.

- host: b
  var_files:
    # I hope this is just default and not take over inventory config
    - roles/a/defaults/main.yml 
  tasks:
    - debug: var=install_path # become default not custom's
1

1 Answers

4
votes

I see nothing wrong with the plan you had in mind. It indeed is cumbersome but will work.

Another idea would be to use a condition:

roles:
  - role: a
    when: False

This will not execute any of the tasks inside role a, but its vars and defaults will be evaluated and later be available to other roles.

The ugly thing here is, that Ansible will pass on the condition to every single task of the role. It will still be visible in the output as skipped tasks then.


But just to make sure you know about the default() filter:

You can do something like this in your templates or tasks:

{{ port | default(42) }}

So if port was defined in the inventory file it will be used. If it was not defined it will be 42.

You even can combine this with a set_fact task.

- set_fact:
    port: "{{ port | default(42) }}"

This is the cleanest way to do what I think is your goal.

If you have more variables you need a default value for, you can all do that in a single task:

- set_fact:
    port: "{{ port | default(42) }}"
    install_path: "{{ install_path | default('/opt') }}"