coding
coding

Reputation: 181

Ansible how to set_fact with condition or var base on condition

I have 3 types of servers: dev, qa and prod. I need to send files to server specific home directories, i.e:

Dev Home Directory: /dev/home

QA Home Directory:/qa/home

PROD Home Directory: /prod/home

I have var set as boolean to determine the server type and think of using set_fact with condition to assign home directories for the servers. My playbook looks like this:

---
- hosts: localhost
  var:
    dev: "{{ True if <hostname matches dev> | else False }}"
    qa: "{{ True if <hostname matches qa> | else False }}"
    prod: "{{ True if <hostname matches prod> | else False }}"

  tasks:
  - set_facts:
      home_dir: "{{'/dev/home/' if dev | '/qa/home' if qa | default('prod')}}"

However, then I ran the playbook, I was getting error about 'template expected token 'name', got string> Anyone know what I did wrong? Thanks!

Upvotes: 3

Views: 8736

Answers (2)

seshadri_c
seshadri_c

Reputation: 7340

Adding an alternative method to achieve this. This kind of extends the group_vars suggestion given by @mdaniel in his comment.

Ansible has a ready-made mechanism to build the variables based on the inventory hosts and groups. If you organize your inventory, you can avoid a lot of complication in trying to match host patterns.

Below is a simplified example, please go through the link above for more options.

Consider an inventory file /home/user/ansible/hosts:

[dev]
srv01.dev.example
srv02.dev.example

[qa]
srv01.qa.example
srv02.qa.example

[prod]
srv01.prod.example
srv02.prod.example

Using group_vars:

Then you can have below group_var files in /home/user/ansible/group_vars/ (matching inventory group names):

dev.yml
qa.yml
prod.yml

In dev.yml:

home_dir: "/dev/home"

In qa.yml:

home_dir: "/qa/home"

In prod.yml:

home_dir: "/prod/home"

Using host_vars:

Or you can have variables specific to hosts in host_vars directory /home/user/ansible/host_vars/:

srv01.dev.example.yml
srv01.prod.example.yml
# and so on

In srv01.dev.example.yml:

home_dir: "/dev/home"

In srv01.prod.example.yml:

home_dir: "/prod/home"

These variables will be picked based on which hosts you run the playbook, for example the below playbook:

---
- hosts: dev

  tasks:
  - debug:
      var: home_dir
    # will be "/dev/home"

- hosts: prod

  tasks:
  - debug:
      var: home_dir
    # will be "/prod/home"

- hosts: srv01.dev.example

  tasks:
  - debug:
      var: home_dir
    # will be "/dev/home"

- hosts: srv01.prod.example

  tasks:
  - debug:
      var: home_dir
    # will be "/prod/home"

Upvotes: 1

Vladimir Botka
Vladimir Botka

Reputation: 68034

Use match test. For example, the playbook

shell> cat pb.yml
- hosts: localhost
  vars:
    dev_pattern: '^dev_.+$'
    qa_pattern: '^qa_.+$'
    prod_pattern: '^prod_.+$'
    dev: "{{ hostname is match(dev_pattern) }}"
    qa: "{{ hostname is match(qa_pattern) }}"
    prod: "{{ hostname is match(prod_pattern) }}"
  tasks:
    - set_fact:
        home_dir: /prod/home
    - set_fact:
        home_dir: /dev/home
      when: dev|bool
    - set_fact:
        home_dir: /qa/home
      when: qa|bool
    - debug:
        var: home_dir

gives (abridged)

shell> ansible-playbook pb.yml -e hostname=dev_007

  home_dir: /dev/home

Notes:

  • The variable prod is not used because /prod/home is default.
  • prod/home is assigned to home_dir first because it's the default. Next tasks can conditionally overwrite home_dirs.
  • Without the variable hostname defined the playbook will crash.

A simpler solution that gives the same result is creating a dictionary of 'pattern: home_dir'. For example

- hosts: localhost
  vars:
    home_dirs:
      dev_: /dev/home
      qa_: /qa/home
      prod_: /prod/home
  tasks:
    - set_fact:
        home_dir: "{{ home_dirs|
                      dict2items|
                      selectattr('key', 'in' , hostname)|
                      map(attribute='value')|
                      list|
                      first|default('/prod/home') }}"
    - debug:
        var: home_dir

Upvotes: 1

Related Questions