【问题标题】:Ansible increment variable globally for all hosts所有主机的全局 Ansible 增量变量
【发布时间】:2016-03-19 03:57:54
【问题描述】:

我的库存中有两台服务器(主机)

[server]
10.23.12.33
10.23.12.40

和剧本(play.yml)

---
- hosts: all
  roles:
    web

在 vars 目录中的 web 角色中,我有 main.yml

---
file_number : 0

在任务目录中的网络角色里面我有 main.yml

---
- name: Increment variable
  set_fact: file_number={{ file_number | int + 1 }}

- name: create file
  command: 'touch file{{ file_number }}'

现在我希望在第一台机器上我会有 file1 并且在第二台机器上我会有 file2 但在两台机器上我都有 file1

所以这个变量对于每台机器都是本地的,我怎样才能让它对所有机器都是全局的。

我的文件结构是:

hosts
play.yml
roles/
  web/
    tasks/
      main.yml
    vars/
      main.yml

【问题讨论】:

  • 它是一个全局变量,但 Ansible 仅在 set_fact 任务上评估一次 file_number,因此无论您针对多少个节点运行它,它都只会设置为 1。你能稍微更广泛地解释一下你的用例吗?可能有更好的方法来做你想做的事情(看起来你想要一个所有主机的唯一文件名)?
  • @ydaetskcoR 我正在做的是更改文件中的配置行,在第一台机器上它将有'username = client1',在第二台机器上它将有'username = client2'等等主机。因此我需要为每台机器增加变量。
  • 但是您不知道任务将在哪个主机顺序中运行。每次运行可能会有不同的主机顺序。除非我遗漏了有关您的用例的某些内容,否则您可能最好将其分配为主机 var

标签: ansible


【解决方案1】:

虽然我已经解决了使用 shell 为所有主机创建全局变量的工作,但我还没有找到 ansible 的解决方案。

  1. 在 localhost 的 /tmp 中创建临时文件并将起始计数放入其中
  2. 读取每个主机的文件并增加文件内的数字

我创建了文件并在 playbook (play.yml) 中对其进行了初始化

- name: Manage localhost working area
  hosts: 127.0.0.1
  connection: local
  tasks:
    - name: Create localhost tmp file
      file: path={{ item.path }} state={{ item.state }}
      with_items:
       - { path: '/tmp/file_num', state: 'absent' }
       - { path: '/tmp/file_num', state: 'touch' }

    - name: Managing tmp files
      lineinfile: dest=/tmp/file_num line='0'

然后在 main.tml 任务中的网络角色中,我读取文件并增加它。

- name: Get file number
  local_action: shell file=$((`cat /tmp/file_num` + 1)); echo $file | tee /tmp/file_num
  register: file_num

- name: Set file name
  command: 'touch file{{ file_num.stdout }}'

现在我在第一台主机 file1 和第二台主机 file2

【讨论】:

    【解决方案2】:

    现在我希望在第一台机器上我会有 file1,在第二台机器上我会有 file2 但在两台机器上我都有 file1

    您需要记住 Ansible 中的变量不是全局变量。变量(又名“事实”)唯一地应用于每个主机,因此 host1 的 file_number 与 host2 的 file_number 不同。这是一个基于您发布的内容的示例:

    roles/test/vars/main.yml:

    ---
    file_number: 0
    

    roles/test/tasks/main.yml:

    ---
    - name: Increment variable
      set_fact: file_number={{ file_number | int + 1 }}
    
    - name: debug
      debug: msg="file_number is {{ file_number }} on host {{ inventory_hostname }}"
    

    现在假设您只定义了两个主机,并且您在剧本中多次运行该角色,如下所示:

    ---
    - hosts: all
      roles:
        - { role: test }
    
    - hosts: host1
      roles:
        - { role: test }
    
    - hosts: all
      roles:
        - { role: test }
    

    因此,在第一次播放中,该角色适用于 host1 和 host2。在第二个游戏中,它只针对 host1,而在第三个游戏中,它再次针对 host1 和 host2。这个剧本的输出是:

    PLAY [all] ********************************************************************
    
    TASK: [test | Increment variable] *********************************************
    ok: [host1]
    ok: [host2]
    
    TASK: [test | debug] **********************************************************
    ok: [host1] => {
        "msg": "file_number is 1 on host host1"
    }
    ok: [host2] => {
        "msg": "file_number is 1 on host host2"
    }
    
    PLAY [host1] **************************************************
    
    TASK: [test | Increment variable] *********************************************
    ok: [host1]
    
    TASK: [test | debug] **********************************************************
    ok: [host1] => {
        "msg": "file_number is 2 on host host1"
    }
    
    PLAY [all] ********************************************************************
    
    TASK: [test | Increment variable] *********************************************
    ok: [host1]
    ok: [host2]
    
    TASK: [test | debug] **********************************************************
    ok: [host1] => {
        "msg": "file_number is 3 on host host1"
    }
    ok: [host2] => {
        "msg": "file_number is 2 on host host2"
    }
    

    如您所见,file_number 的值对于 host1 和 host2 是不同的,因为增加值的角色对 host1 的运行次数比对 host2 的运行次数多。

    不幸的是,在 Ansible 中创建变量 global 确实没有一种干净的方法。 Ansible 能够针对大量主机并行运行任务的整个性质使得这样的事情非常棘手。除非您对并行环境中的全局变量非常小心,否则您很容易触发race condition,这可能会导致不可预测(不一致)的结果。

    【讨论】:

      【解决方案3】:

      您可以使用来自here 的 Matt Martz 的解决方案。

      基本上你的任务是这样的:

      - name: Set file name
      command: 'touch file{{ play_hosts.index(inventory_hostname) }}'
      

      您可以删除所有用于维护全局变量和外部文件的代码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多