Babbi
Babbi

Reputation: 37

Ansible acessing vars prompt value to check with multiple values in a dict

I have a vars data type file:

foo:
  foo_root_path: faaa
  foo_dest_path: baa
bar:
  bar_root_path: xyz
  bar_dest_path: wxy
baz:
  baz_root_path: abc
  baz_dest_path: def

I have a playbook which prompts user to see the type of data I am getting, if it is a foo, a bar or a baz.

I am creating a role to check if vars prompt == foo then access values in foo and use them to execute a copy command.

I am new to Ansible and trying to understand

What I have now is this, where for every when condition I am repeating my commands but I want to use loops and conditionals:

role:
when: "'foo' == {{ data_type }}"

- name: move foo data from source to destination

  copy:
    src: '{{ foo_root_path }}/{{ name }}'
    dest: '{{foo_destination_path}}'
    owner: foo
    group: foo
    mode: '0644'

  when: "'bar' == {{ type }}"

- name: move bar

  copy:
    src: '{{ bar_root_path }}/{{ name }}'
    dest: '{{bar_destination_path}}'
    owner: bar
    group: bar
    mode: '0644'

  when: "'baz' == {{ type }}"

- name: move baz 

  copy:
    src: '{{ baz_root_path }}/{{ name }}'
    dest: '{{baz_destination_path}}'
    owner: baz
    group: baz
    mode: '0000'

What I want to achieve is to use conditionals to find out what the vars prompt is and then access the vars section to do the copy command once substituting the params from vars file instead of three commands.

Upvotes: 1

Views: 1346

Answers (1)

β.εηοιτ.βε
β.εηοιτ.βε

Reputation: 39314

You can use the vars lookup in order to achieve such a task.
Note that all variables, accessible to that host are accessible via that lookup, might there be from play variables, task variable, inventory variable or imported via var_files, the syntax stays the same.

This ables you to look for a variable based on a variable, for example:

lookup('vars', type)

Would give you the dictionary

foo_root_path: faaa
foo_dest_path: baa

When type is foo.

And since your type is also part of your dictionary keys, you will also need to use the tilde symbol ~, which is the concatenation operator in Jinja:

"{{ type ~ '_root_path' }}"

Would give you the string

foo_root_path

When type is foo.

So given the playbook:

- hosts: all
  gather_facts: no
  
  vars: 
    foo:
      foo_root_path: faaa
      foo_dest_path: baa
    bar:
      bar_root_path: xyz
      bar_dest_path: wxy
    baz:
      baz_root_path: abc
      baz_dest_path: def

  vars_prompt:
    - name: type
      prompt: "What variable type do you want to use?"
      private: no  

  pre_tasks:
    - assert:
        that: lookup('vars', type, default='') | length
      
  tasks:
    - debug:
        msg: 
          root_path: "{{ lookup('vars', type)[type ~ '_root_path'] }}"
          dest_path: "{{ lookup('vars', type)[type ~ '_dest_path'] }}"

Here are some runs of it:

  • What variable type do you want to use?: foo
    
    PLAY [all] *******************************************************************************************************
    
    TASK [assert] ****************************************************************************************************
    ok: [localhost] => {
        "changed": false,
        "msg": "All assertions passed"
    }
    
    TASK [debug] *****************************************************************************************************
    ok: [localhost] => {
        "msg": {
            "dest_path": "baa",
            "root_path": "faaa"
        }
    }
    
    PLAY RECAP *******************************************************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    
  • What variable type do you want to use?: bar
    
    PLAY [all] *******************************************************************************************************
    
    TASK [assert] ****************************************************************************************************
    ok: [localhost] => {
        "changed": false,
        "msg": "All assertions passed"
    }
    
    TASK [debug] *****************************************************************************************************
    ok: [localhost] => {
        "msg": {
            "dest_path": "wxy",
            "root_path": "xyz"
        }
    }
    
    PLAY RECAP *******************************************************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    
  • This is making the playbook gracefully fail, in case the prompted variable is not defined, thanks to the assert module defined as pre_tasks.
    You need to use a default='' if the variable is undefined, otherwise, the vars lookup will error, as prompted in the documentation.
    Then, when you have an empty string from the default, testing its length, via the Jinja filter, would evaluate to false, if the string happens to be empty, making length return 0, otherwise, if it is a dictionary, the length would be a value > 0 and so, evaluate to true.
    What variable type do you want to use?: evil
    
    PLAY [all] *******************************************************************************************************
    
    TASK [assert] ****************************************************************************************************
    fatal: [localhost]: FAILED! => {
        "assertion": "lookup('vars', type, default='') | length",
        "changed": false,
        "evaluated_to": false,
        "msg": "Assertion failed"
    }
    
    PLAY RECAP *******************************************************************************************************
    localhost                  : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0  
    

So adapting all this to your case gives this playbook:

- hosts: all
  gather_facts: no
  
  vars: 
    name: file.ext
    foo:
      foo_root_path: faaa
      foo_dest_path: baa
    bar:
      bar_root_path: xyz
      bar_dest_path: wxy
    baz:
      baz_root_path: abc
      baz_dest_path: def

  vars_prompt:
    - name: type
      prompt: "What variable type do you want to use?"
      private: no  

  pre_tasks:
    - assert:
        that: lookup('vars', type, default='') | length
      
  tasks:
    - name: "Move {{ type }} data from source to destination"
      copy:
        src: "{{ lookup('vars', type)[type ~ '_root_path'] }}/{{ name }}"
        dest: "{{ lookup('vars', type)[type ~ '_dest_path'] }}"
        owner: "{{ type }}"
        group: "{{ type }}"
        mode: "0644"


Upvotes: 2

Related Questions