【问题标题】:Select host to execute task based on multiple conditions根据多个条件选择主机执行任务
【发布时间】:2020-08-28 18:58:34
【问题描述】:

使用 Ansible v2.9.12

想象一个游戏中有 4 个主机,具有以下变量:

# 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

我想在单个主机上执行一个任务,该主机具有 my_var.two == 'master' 并将 my_var.one 设置为 false。在这种情况下,它将与 host2 或 host3 相关。

现在,这行不通了:

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

因为 Ansible 仅在组中的第一台主机上执行任务,这很可能与 host1 相关,这是不受欢迎的。我也在摆弄the answer described in my previous question,这有点相关,但无济于事。

【问题讨论】:

    标签: ansible


    【解决方案1】:

    没有什么能阻止你在剧本中进行多次剧本:

    - 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"
    

    回顾一下:

    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 
    

    或者,对于更动态的解决方案,您可以选择正确的主机,通过魔术变量 hostvars 循环访问主机变量,然后使用 delegate_to 将任务委托给该主机。

    鉴于剧本:

    - 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
    

    它给出了回顾:

    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
    

    此回顾的重要部分是 [host1 -> host2],它表示任务已被委派,因此在 host2 上运行。


    甚至,在同样的思路上,跳过与具有上述条件的主机不匹配的主机:

    - 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
    

    回顾一下:

    
    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   
    

    【讨论】:

    • 我真的很喜欢这个答案。简单,干净,而且有效!谢谢
    • 可能将 hostvars 更改为 ansible_play_hosts,以将其仅限于当前播放,而不是所有可用的 hostvars。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    相关资源
    最近更新 更多