如何在ansible中创建一次性用户提示输入?

How to create a one-time user prompt input in ansible?

我有以下过于简化的 ansible 剧本:


- name: Prepare worker nodes
  hosts: "{{ hosts }}"
  serial:
    - 1
    - 3
  remote_user: root
  any_errors_fatal: true
  vars:
    hosts: nodes
    reboot: false
  tasks:

    - pause:
        prompt: "Reboot server(s) to make sure things are working during setup? (Y/n)"
        echo: true
      register: confirm_reboot
      tags: [ untagged, hostname, netplan, firewalld ]

    - set_fact:
        reboot: "{{ (confirm_reboot.user_input == '' or confirm_reboot.user_input == 'Y' or confirm_reboot.user_input == 'y' ) | ternary('True', 'False') }}"
      tags: [ untagged, hostname, netplan, firewalld, firewalld-install, firewalld-config ]

    - debug:
        msg: "{{ reboot }}"

它要求用户输入,以便它可以决定一些重启策略。 当你只有一个节点时,这工作得很好,但当你有多个节点时,它会提示 each 一个。假设你有 42 个节点——它会问你 42 次。

我想弄清楚是否有一种简单的方法可以让提示只出现一次并在节点之间共享结果。也许我遗漏了文档中的某些内容?

看起来唯一可行的方法是使用 delegate_todelegate_facts。我想到了这样的事情:

- name: Prepare worker nodes
  hosts: "{{ hosts }}"
  serial:
    - 1
    - 3
  remote_user: root
  any_errors_fatal: true
  vars:
    hosts: nodes
    reboot: true
  pre_tasks:
    - pause:
        prompt: "Reboot server(s) to make sure things are working during setup? (Y/n)"
        echo: true
      register: confirm_reboot
      run_once: true
      delegate_to: localhost
      delegate_facts: true
      tags: [ untagged, hostname, netplan, firewalld, firewalld-install, firewalld-config ]
      when: "'reboot' not in hostvars['localhost']"

    - set_fact:
        reboot: "{{ (confirm_reboot.user_input == '' or confirm_reboot.user_input == 'Y' or confirm_reboot.user_input == 'y' ) | ternary('True', 'False') }}"
      run_once: true
      delegate_to: localhost
      delegate_facts: true
      tags: [ untagged, hostname, netplan, firewalld, firewalld-install, firewalld-config ]
      when: "'reboot' not in hostvars['localhost']"

    - set_fact:
        reboot: "{{ hostvars['localhost']['reboot'] }}"
      run_once: true

  tasks:
    - debug:
        msg: "{{ hostvars['localhost'] }}"
      tags: [ untagged, hostname, netplan, firewalld, firewalld-install, firewalld-config ]

    - debug:
        msg: "{{ reboot }}"
      tags: [ untagged, hostname, netplan, firewalld, firewalld-install, firewalld-config ]

这是通过将事实委托给 localhost(控制节点)来实现的,然后它通过似乎保存在不同节点之间的引用来使用它。这对我来说是一个 hackish 的解决方法,但由于我没有那么多时间来深入研究“为什么”,所以现在必须这样做。

如果有人想出更好的方法 - 请随时 post 您的回答。

鉴于库存

shell> cat hosts
[test]
host1
host2
host3
host4
host5

剧本

shell> cat playbook.yml
---
- hosts: test
  serial:
    - 1
    - 3
  gather_facts: false
  tasks:
    - pause:
        prompt: "Reboot? (Y/n)"
        echo: true
      register: confirm_reboot
      run_once: true
    - debug:
        msg: "Reboot {{ inventory_hostname }}"
      when: confirm_reboot.user_input|lower == 'y'

按预期工作

shell> ansible-playbook -i hosts playbook.yml

PLAY [test] *********************************

TASK [pause] ********************************
[pause]
Reboot? (Y/n):
ok: [host1]

TASK [debug] ********************************
ok: [host1] => 
  msg: Reboot host1

PLAY [test] *********************************

TASK [pause] ********************************
[pause]
Reboot? (Y/n):
ok: [host2]

TASK [debug] ********************************
ok: [host2] => 
  msg: Reboot host2
ok: [host3] => 
  msg: Reboot host3
ok: [host4] => 
  msg: Reboot host4

PLAY [test] *********************************

TASK [pause] ********************************
[pause]
Reboot? (Y/n):
ok: [host5]

TASK [debug] ********************************
ok: [host5] => 
  msg: Reboot host5

问:"整个剧本只需要输入一次并传播到所有主机。"

A:拆分剧本,例如

shell> cat playbook.yml
---
- hosts: test
  gather_facts: false
  tasks:
    - pause:
        prompt: "Reboot? (Y/n)"
        echo: true
      register: confirm_reboot
      run_once: true

- hosts: test
  serial:
    - 1
    - 3
  gather_facts: false
  tasks:
    - debug:
        msg: "Reboot {{ inventory_hostname }}"
      when: confirm_reboot.user_input|lower == 'y'

第一次播放的变量将在第二次播放中共享给所有主机

shell> ansible-playbook -i hosts playbook.yml

PLAY [test] *********************************

TASK [pause] ********************************
[pause]
Reboot? (Y/n):
ok: [host1]

PLAY [test] *********************************

TASK [debug] ********************************
ok: [host1] =>
  msg: Reboot host1

PLAY [test] *********************************

TASK [debug] ********************************
ok: [host3] =>
  msg: Reboot host3
ok: [host2] =>
  msg: Reboot host2
ok: [host4] =>
  msg: Reboot host4

PLAY [test] *********************************

TASK [debug] ********************************
ok: [host5] =>
  msg: Reboot host5