使用 HTTP 获取 YAML 文件并将其用作 Ansible 剧本中的变量

Get a YAML file with HTTP and use it as a variable in an Ansible playbook

背景

我在网络服务器上有一个这样的 YAML 文件。我正在尝试阅读它并使用 Ansible 剧本在文件中创建用户帐户。

users:
  - number: 20210001
    name: Aoki Alice
    id: alice
  - number: 20210002
    name: Bob Bryant
    id: bob
  - number: 20210003
    name: Charlie Cox
    id: charlie

我试过的

为了确认如何使用 include_vars 动态读取下载的 YAML 文件,我写了一个这样的剧本:

- name: Add users from list
  hosts: workstation
  tasks:
    - name: Download yaml
      get_url:
        url: http://fqdn.of.webserver/path/to/yaml.yml
        dest: "/tmp/tmp.yml"
      notify:
        - Read yaml
        - List usernames

  handlers:
    - name: Read yaml
      include_vars:
        file: /tmp/tmp.yml
        name: userlist

    - name: List usernames
      debug:
        var: "{{ item }}"
      loop: "{{ userlist.users }}"

问题

在处理程序 Read yaml 中,我收到以下错误消息。在目标机器 (workstation.example.com) 上,/tmp/tmp.yml 被正确下载。

RUNNING HANDLER [Read yaml] *****
fatal: [workstation.example.com]: FAILED! => {"ansible facts": {"userlist": []},
"ansible included var files": [], "changed": false, "message": "Could not find o
r access '/tmp/tmp. yml' on the Ansible Controller.\nIf you are using a module a
nd expect the file to exist on the remote, see the remote src option"}

问题

如何使用 HTTP 获取 YAML 文件并将其用作 include_vars 的变量?

include_vars 任务在本地(控制)主机上查找文件,但您已将文件下载到远程主机上的 /tmp/tmp.yml。有多种方法可以让它发挥作用。

也许最简单的方法就是 运行在控制机器上执行下载任务(注意 delegate_to 的使用):

  tasks:
    - name: Download yaml
      delegate_to: localhost
      get_url:
        url: http://fqdn.of.webserver/path/to/yaml.yml
        dest: "/tmp/tmp.yml"
      notify:
        - Read yaml
        - List usernames

这会将文件下载到本地系统上的 /tmp/tmp.yml,供 include_vars 使用。例如,如果我 运行 这个剧本(从我刚刚创建的示例要点中获取 YAML 内容)...

- hosts: target
  gather_facts: false
  tasks:
    - name: Download yaml
      delegate_to: localhost
      get_url:
        url: https://gist.githubusercontent.com/larsks/70d8ac27399cb51fde150902482acf2e/raw/676a1d17bcfc01b1a947f7f87e807125df5910c1/example.yaml
        dest: "/tmp/tmp.yml"
      notify:
        - Read yaml
        - List usernames

  handlers:
    - name: Read yaml
      include_vars:
        file: /tmp/tmp.yml
        name: userlist

    - name: List usernames
      debug:
        var: item
      loop: "{{ userlist.users }}"

...它产生以下输出:

RUNNING HANDLER [Read yaml] ******************************************************************
ok: [target]

RUNNING HANDLER [List usernames] *************************************************************
ok: [target] => (item=bob) => {
    "ansible_loop_var": "item",
    "item": "bob"
}
ok: [target] => (item=alice) => {
    "ansible_loop_var": "item",
    "item": "alice"
}
ok: [target] => (item=mallory) => {
    "ansible_loop_var": "item",
    "item": "mallory"
}

旁注:根据我在你的剧本中看到的内容,我不确定你想要 在这里使用 notify 和处理程序。如果你 运行 你的剧本 第二次,什么都不会发生,因为文件 /tmp/tmp.yml 已经存在,因此不会调用处理程序。

另一种选择是使用 uri 模块将值检索到 Ansible 变量中,然后 from_yaml 过滤器对其进行解析。

类似于:

- name: Add users from list
  hosts: workstation
  tasks:
    - name: Download YAML userlist
      uri:
        url: http://fqdn.of.webserver/path/to/yaml.yml
        return_content: yes
      register: downloaded_yaml
    - name: Decode YAML userlist
      set_fact:
        userlist: "{{ downloaded_yaml.content | from_yaml }}"

注意uri在Ansible Controller上工作,而get_url在目标主机(或delegate_to中指定的主机)上工作;根据您的网络配置,您可能需要使用不同的代理设置或防火墙规则来允许下载。

根据@Larsks 的回答,我制作了这个在我的环境中可以正常工作的剧本:

- name: Download users list
  hosts: 127.0.0.1
  connection: local
  become: no
  tasks:
  - name: Download yaml
    get_url:
      url: http://fqdn.of.webserver/path/to/yaml/users.yml
      dest: ./users.yml

- name: Add users from list
  hosts: workstation
  tasks:
  - name: Read yaml
    include_vars:
      file: users.yml
  - name: List usernames
    debug:
      msg: "{{ item.id }}"
    loop: "{{ users }}"

运行 get_url 在控制主机上

如@Larsks 所说,您必须 运行 控制主机上的 get_url 模块,而不是目标主机。

在控制主机

上将become: no添加到任务运行

没有"become: no",你会得到如下错误信息:

TASK [Gathering Facts] ******************************************************
fatal: [127.0.0.1]: FAILED! => {"ansible_facts": {}, "changed": false, "msg":
 "The following modules failed to execute: setup\n setup: MODULE FAILURE\nSee
 stdout/stderr for the exact error\n"}

使用connection: local而不是local_action

如果像这样使用 local_action 而不是 connection: local

- name: test get_url
  hosts: workstation
  tasks:
  - name: Download yaml
    local_action:
      module: get_url
      url: http://fqdn.of.webserver/path/to/yaml/users.yml
      dest: ./users.yml
  - name: Read yaml
    include_vars:
      file: users.yml
  - name: output remote yaml
    debug:
      msg: "{{ item.id }}"
    loop: "{{ users }}"

您将收到以下错误消息:

TASK [Download yaml] ********************************************************
fatal: [workstation.example.com]: FAILED! => {"changed": false, "module_stde
rr": "sudo: a password is required\n", "module_stdout":"", "msg":"MODULE FAIL
URE\nSee stdout/stderr for the exact error", "rc": 1}

get_url 在控制主机上存储一个文件

在这种情况下,get_url 模块将 users.yml 存储在控制主机上(在当前目录中)。所以你必须删除 users.yml 如果你不想离开它。