使用 ansible 模板文件来为不同的主机获取不同的变量部分(通过其索引)

使用 ansible 模板文件来为不同的主机获取不同的变量部分(通过其索引)

我正在尝试将证书分发给其相应的主机(我仅给出私钥任务的示例):

- name: create certificate private key
  community.crypto.openssl_privatekey:
    path: "/root/client/{{ item }}.key"
    type: Ed25519
    backup: yes
    return_content: yes
  register: privatekey
  loop: "{{ ansible_play_hosts_all }}"
  when: "'prometheus1' in inventory_hostname"

我可以像这样为其他主机调用该变量:

{{ hostvars['prometheus1']['privatekey']['results'][0]['privatekey'] }}

索引指向某个键,因此 0 表示第一个主机(prometheus1),1 表示第二个主机,依此类推。

我认为模板化是可行的方法,但我不知道如何编写模板。我认为ansible_play_hosts_all解决方案的关键在于它的索引与私钥的索引相对应,例如: ansible_play_hosts_all[2]-->hostvars['prometheus1']['privatekey']['results'][2]['privatekey']

但逻辑是:

for i in index of ansible_play_hosts_all
add the  hostvars['prometheus1']['privatekey']['results'][i]['privatekey']
if ansible_play_hosts_all[i] in inventory_hostname

我想是这样的:) 任何帮助都将不胜感激。


更新

也许更准确一点:

{% for i in ansible_play_hosts_all|length) %}
{{ hostvars['prometheus1']['privatekey']['results'][i]['privatekey'] }}
{% endfor %}

并添加条件:

{% if ansible_play_hosts_all[i] in inventory_hostname %}

答案1

使用起来会更简单代表团创建密钥,prometheus1同时保留与正确主机关联的注册变量。然后,您就可以privatekey.privatekey在模板中使用。

- name: create certificate private key
  community.crypto.openssl_privatekey:
    path: /root/client/{{ inventory_hostname }}.key
    type: Ed25519
    backup: yes
    return_content: yes
  register: privatekey
  delegate_to: prometheus1

如果您确实想坚持当前的结构,则可以通过检查item结果中的值来找到与当前主机相对应的列表元素,该值包含item循环的该次迭代。

{{ (hostvars['prometheus1']['privatekey']['results'] | selectattr('item', '==', inventory_hostname) | list | first).privatekey }}

答案2

创建一个包含数据的字典,例如给定库存

shell> cat hosts
prometheus1 ansible_host=localhost
test_11     ansible_host=10.1.0.61 ansible_user=admin 
test_12     ansible_host=10.1.0.62 ansible_user=admin
test_13     ansible_host=10.1.0.63 ansible_user=admin

剧本

- hosts: all
  gather_facts: false
  tasks:
    - community.crypto.openssl_privatekey:
        path: "{{ playbook_dir }}/client/{{ item }}.key"
        type: Ed25519
        backup: yes
        return_content: yes
      register: privatekey
      loop: "{{ ansible_play_hosts_all|difference(['prometheus1']) }}"
      delegate_to: prometheus1
      run_once: true

    - set_fact:
        host_priv: "{{ privatekey.results|
                       json_query('[].{host: item,
                                       priv: privatekey}')|
                       items2dict(key_name='host', value_name='priv') }}"
      run_once: true

为每个主机生成私钥,但以下情况除外普罗米修斯1,将密钥存储在文件中,并根据注册的数据创建主机及其密钥的字典

shell> tree client/
client/
├── test_11.key
├── test_12.key
└── test_13.key
ok: [prometheus1] => 
  host_priv:
    test_11: |-
      -----BEGIN PRIVATE KEY-----
      MC4CAQAwBQYDK2VwBCIEIM7/BtpiM1EZxrrwtuE2VdSdr++3J/yxm/BnabnMqL3e
      -----END PRIVATE KEY-----
    test_12: |-
      -----BEGIN PRIVATE KEY-----
      MC4CAQAwBQYDK2VwBCIEIPr8VV2RDOggNxo6vpBiXjSTzclJHFHaTVSxlFFVKoU1
      -----END PRIVATE KEY-----
    test_13: |-
      -----BEGIN PRIVATE KEY-----
      MC4CAQAwBQYDK2VwBCIEIJjp2knmccffeEGvTNaP2f+ijXkeLmu89cGgkqFi771/
      -----END PRIVATE KEY-----

然后,您可以继续游戏并将密钥复制给主机,例如

    - name: copy private key
      copy:
        content: "{{ host_priv[inventory_hostname] }}"
        dest: /tmp/private.key
      when: inventory_hostname != 'prometheus1'
      become: true

使路径适合您的需要并设置所有权和权限。

答案3

我最终想出了解决方案:

{%  for i in range(ansible_play_hosts_all|length) %}
{% if ansible_play_hosts_all[i] in inventory_hostname -%}
{{ hostvars['prometheus1']['privatekey']['results'][i]['privatekey'] }}
{%- endif %}
{% endfor %}

这按预期工作。我循环遍历 ansible_play_hosts_all 的长度(以了解角色正在运行的主机数量),并在循环内部添加条件,即索引需要与清单中的主机名相对应。

if 条件中的and会删除输出中的空格。如果没有它们,-%%-每个文件都会添加一个空行(在本例中这似乎不会影响 openssl,当然,没有它会更好)

模板任务本身如下:

- name: copy certificate through templating
  template:
    src: certs.j2
    dest: "/root/{{ inventory_hostname }}.key"

相关内容