Usando Ansible v2.9.12

Imagina 4 hosts en una jugada, con las siguientes variables:

# host1
my_var:
  one: true
  two: master

# host2
my_var:
  one: false
  two: master

# host3
my_var:
  one: false
  two: master

# host4
my_var:
  one: false
  two: arbiter

Quiero ejecutar una tarea en un solo host, que tiene my_var.two == 'master' y my_var.one está configurado en false. En este caso, estaría relacionado con host2 o host3.

Ahora, esto no funcionará:

- shell: echo
  when: 
    - my_var.two == 'master'
    - not my_var.one
   run_once: true

Porque Ansible ejecuta la tarea solo en el primer host del grupo, que probablemente se relaciona con host1, lo cual no es deseado. También estoy jugando en la respuesta descrita en mi pregunta anterior, que está algo relacionada, pero sin resultado.

2
Kevin C 28 ago. 2020 a las 21:58

1 respuesta

La mejor respuesta

Nada te detiene, en un libro de jugadas, para tener múltiples jugadas:

- hosts: all
  gather_facts: no
      
  tasks:
    - debug: 
        msg: "{{ my_var }}"

- hosts: host2
  gather_facts: no
      
  tasks:
    - debug: 
        msg: "{{ my_var }}"
      # ^--- Off course, now the when become superfluous, 
      #      since we target a host that we know have those conditions

- hosts: all
  gather_facts: no

  tasks:
    - debug:
        msg: "Keep on going with all hosts"

Daría el resumen:

PLAY [all] **********************************************************************************************************

TASK [debug] ********************************************************************************************************
ok: [host1] => {
    "msg": {
        "one": true,
        "two": "master"
    }
}
ok: [host2] => {
    "msg": {
        "one": false,
        "two": "master"
    }
}
ok: [host3] => {
    "msg": {
        "one": false,
        "two": "master"
    }
}
ok: [host4] => {
    "msg": {
        "one": false,
        "two": "arbiter"
    }
}

PLAY [host2] ********************************************************************************************************

TASK [debug] ********************************************************************************************************
ok: [host2] => {
    "msg": {
        "one": false,
        "two": "master"
    }
}

PLAY [all] **********************************************************************************************************

TASK [debug] ********************************************************************************************************
ok: [host1] => {
    "msg": "Keep on going with all hosts"
}
ok: [host2] => {
    "msg": "Keep on going with all hosts"
}
ok: [host3] => {
    "msg": "Keep on going with all hosts"
}
ok: [host4] => {
    "msg": "Keep on going with all hosts"
}

PLAY RECAP **********************************************************************************************************
host1                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host2                      : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host3                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host4                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

Alternativamente, para una solución más dinámica, puede seleccionar el host correcto, recorriendo sus variables de hosts mediante la variable mágica hostvars y, luego, delega la tarea a este host con delegate_to.

Dado el libro de jugadas:

- hosts: all
  gather_facts: no
      
  tasks:
    - set_fact: 
        host_master_not_one: "{{ item }}"
      when:
        - host_master_not_one is not defined
        - not hostvars[item].my_var.one
        - "'master' == hostvars[item].my_var.two"
      run_once: true
      loop: "{{ ansible_play_hosts }}" 
    
    - debug: 
        msg: "Running only once, on host {{ host_master_not_one }}"
      delegate_to: "{{ host_master_not_one }}"
      run_once: true

Da el resumen:

PLAY [all] **********************************************************************************************************

TASK [set_fact] *****************************************************************************************************
skipping: [host1] => (item=host1) 
ok: [host1] => (item=host2)
skipping: [host1] => (item=host3) 
skipping: [host1] => (item=host4) 

TASK [debug] ********************************************************************************************************
ok: [host1 -> host2] => {
    "msg": "Running only once, on host host2"
}

PLAY RECAP **********************************************************************************************************
host1                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

La parte importante de este resumen sería el [host1 -> host2] que indica que la tarea fue delegada y, por lo tanto, se ejecutó en host2.


O incluso, en el mismo tren de pensamientos, omita los hosts que no coincidan con el que tiene esas condiciones mencionadas:

- hosts: all
  gather_facts: no
      
  tasks:
    - set_fact: 
        host_master_not_one: "{{ item }}"
      when:
        - host_master_not_one is not defined
        - not hostvars[item].my_var.one
        - "'master' == hostvars[item].my_var.two"
      run_once: true
      loop: "{{ ansible_play_hosts }}" 
    
    - debug: 
        msg: "Running only once, on host {{ host_master_not_one }}"
      when: inventory_hostname == host_master_not_one

Da el resumen:


PLAY [all] **********************************************************************************************************

TASK [set_fact] *****************************************************************************************************
skipping: [host1] => (item=host1) 
ok: [host1] => (item=host2)
skipping: [host1] => (item=host3) 
skipping: [host1] => (item=host4) 

TASK [debug] ********************************************************************************************************
skipping: [host1]
ok: [host2] => {
    "msg": "Running only once, on host host2"
}
skipping: [host3]
skipping: [host4]

PLAY RECAP **********************************************************************************************************
host1                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
host2                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host3                      : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
host4                      : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
3
β.εηοιτ.βε 2 sep. 2020 a las 20:36