Home > Software engineering >  Defining multiple cases for an Ansible variable based on multiple conditions
Defining multiple cases for an Ansible variable based on multiple conditions

Time:01-12

I have this variable here, set in a .yaml variables file

patch_plan: 'foo-{{ patch_plan_week_and_day }}-bar'

I want my patch_plan_week_and_day variable to be set dynamically, based on role and environment which are 2 other variables set elsewhere (doesn't matter now) outside this variables file.

For instance, I will explain 3 cases:

  • If role = 'master' and environment = 'srvb' then patch_plan_week_and_day = 'Week1_Monday' and thus the end result of patch_plan = 'foo-Week1_Monday-bar'.
  • If role != 'master' and environment = 'srvb' then patch_plan_week_and_day = 'Week1_Tuesday' and thus the end result of patch_plan = 'foo-Week1_Tuesday-bar'
  • If role = 'slave' and environment = 'pro' then patch_plan_week_and_day = 'Week3_Wednesday' and hus the end result of patch_plan = 'foo-Week3_Wednesday-bar'

This is the idea of the code:

patch_plan: 'foo-{{ patch_plan_week_and_day }}-bar'

# Patch Plans
## I want something like this:

# case 1
patch_plan_week_and_day: Week1_Monday
when: role == 'master' and environment == 'srvb'

# case 2
patch_plan_week_and_day: Week1_Tuesday
when: role != 'master' and environment == 'srvb'

# case 3
patch_plan_week_and_day: Week3_Wednesday
when: role == 'slave' and environment == 'pro'

I have 14 cases in total.

CodePudding user response:

Put the logic into a dictionary. For example,

  patch_plan_week_and_day_dict:
    srvb:
      master: Week1_Monday
      default: Week1_Tuesday
    pro:
      slave: Week3_Wednesday
      default: WeekX_Wednesday

Create the project for testing

shell> tree .
.
├── ansible.cfg
├── hosts
├── pb.yml
└── roles
    ├── master
    │   ├── defaults
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    ├── non_master
    │   ├── defaults
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    └── slave
        ├── defaults
        │   └── main.yml
        └── tasks
            └── main.yml

10 directories, 9 files
shell> cat ansible.cfg 
[defaults]
gathering = explicit
inventory = $PWD/hosts
roles_path = $PWD/roles
retry_files_enabled = false
stdout_callback = yaml
shell> cat hosts
localhost
shell> cat pb.yml 
- hosts: localhost
  vars:
    patch_plan_week_and_day_dict:
      srvb:
        master: Week1_Monday
        default: Week1_Tuesday
      pro:
        slave: Week3_Wednesday
        default: WeekX_Wednesday
  roles:
    - "{{ my_role }}"

The code of all roles is identical

shell> cat roles/master/defaults/main.yml 
patch_plan_role: "{{ (my_role in patch_plan_week_and_day_dict[env].keys()|list)|
                     ternary(my_role, 'default') }}"
patch_plan_week_and_day: "{{ patch_plan_week_and_day_dict[env][patch_plan_role] }}"

shell> cat roles/master/tasks/main.yml 
- debug:
    var: patch_plan_week_and_day

Example 1.

shell> ansible-playbook pb.yml -e env=srvb -e my_role=master
  ...
  patch_plan_week_and_day: Week1_Monday

Example 2.

shell> ansible-playbook pb.yml -e env=srvb -e my_role=non_master
  ...
  patch_plan_week_and_day: Week1_Tuesday

Example 3.

shell> ansible-playbook pb.yml -e env=pro -e my_role=slave
  ...
  patch_plan_week_and_day: Week3_Wednesday

CodePudding user response:

A lot of considerations here ...

It seems you try to use Ansible as a programming language which it isn't. You've started to implement something without any description about your use case and what is actually the problem. The given example looks like an anti-pattern.

... set dynamically, based on role and environmentv ...

It is in fact "static" and based on the properties of the systems. You only try to generate the values at runtime. Timeslots when patches can or should be applied (Patch Window) are facts about the system and usually configured within the Configuration Management Database (CMDB). So this kind of information should be already there, either in a database or within the Ansible inventory or as a Custom fact on the system itself.

... which are 2 other variables set elsewhere (doesn't matter now) outside this variables file. ...

Probably it does matter and maybe you could configure the Patch Cycle or Patch Window there.

By pursuing your approach further you'll mix up Playbook Logic with Infrastructure Description or Configuration Properties leading fast into less readable and probably future unmaintainable code. You'll deny yourself the opportunity to maintain the system configuration within a Version Control System (VCS), CMDB or the inventory.

Therefore avoid CASE, SWITCH and IF THEN ELSE ELSEIF structures and describe the desired state of your systems instead.

Some Further Readings

In addition to the sources already given.

  • Related