在列表中获取特定的事实

Getting specific ansible facts in a list

我目前正在尝试自动创建反亲和性规则以在 VMware 中部署各种应用程序。我一直在像这样使用 drs_rule 模块:

- name: Create DRS Anti-Affinity Rule for appX
  vmware_vm_vm_drs_rule:
    hostname: '{{ vcenter_hostname }}'
    username: '{{ vcenter_username }}'
    password: '{{ vcenter_password }}'
    cluster_name: '{{ vsphere_cluster }}'
    enabled: True
    vms:
      -appXa
      -appXb
      -appXc
    drs_rule_name: appX_rule
    mandatory: True
    affinity_rule: False
  delegate_to: localhost
  run_once: True

但是,VM 的确切数量可能因部署而异。因此,我需要能够动态地提取这些信息。这是我能找到的最接近我需要的东西:

- name: Create DRS Anti-Affinity Rule for appX
  vmware_vm_vm_drs_rule:
    hostname: '{{ vcenter_hostname }}'
    username: '{{ vcenter_username }}'
    password: '{{ vcenter_password }}'
    cluster_name: '{{ vsphere_cluster }}'
    enabled: True
    vms: "{{ item }}"
    drs_rule_name: appX_rule
    mandatory: True
    affinity_rule: False
  loop: "{{ groups['appX'] }}"
  delegate_to: localhost
  run_once: True

虽然这确实会从我的清单文件中为该组提取 IP 地址,但我需要提取 VM 名称(即主机名)才能与此模块一起使用。有没有办法在剧本中制作这样的作品?基本上是让它 return 主机名字符串列表,这样我就可以将它插入到这个模块中。

# ansible appX-i inventory -m setup -a "filter=ansible_hostname"

xxx.xxx.xxx.xxx | SUCCESS => {
    "ansible_facts": {
        "ansible_hostname": "appXa"
    },
    "changed": false
}
xxx.xxx.xxx.xxx | SUCCESS => {
    "ansible_facts": {
        "ansible_hostname": "appXb"
    },
    "changed": false
}
xxx.xxx.xxx.xxx | SUCCESS => {
    "ansible_facts": {
        "ansible_hostname": "appXc"
    },
    "changed": false
}

非常感谢:-)

编辑:我能够提取主机名。这归功于 mdaniel

- name: Create DRS Anti-Affinity Rule for appX
  vmware_vm_vm_drs_rule:
    hostname: '{{ vcenter_hostname }}'
    username: '{{ vcenter_username }}'
    password: '{{ vcenter_password }}'
    cluster_name: '{{ vsphere_cluster }}'
    enabled: True
    vms: "{{ item }}"
    drs_rule_name: appX_rule
    mandatory: True
    affinity_rule: False
    loop: "{{ groups['appX'] | map('extract', hostvars, 'ansible_hostname') }}"
  delegate_to: localhost
  run_once: True

然而,我们实际上需要格式为“hostname_IP”的项目,例如“appXa_192.168.1.100”。有没有办法提取 IP 地址并将它们之间的下划线连接在同一行上?

此外,使用 map/extract 提取 IP 时遇到一些问题,因为 ansible facts 以字典格式提供。即

"ansible_default_ipv4": {
  "address": "192.169.1.100",

我可以使用列表中的 ansible_all_ipv4_addresses,但如果我们将多个 IP 附加到同一台机器,这可能会带来复杂性。

However, we actually need the items in the format of "hostname_IP" e.g. "appXa_192.168.1.100". Is there a way to pull the IP address and concatenate an underscore in between them all on the same line?

是也不是;一次完成会有些愚蠢,因为在 jinja2 中没有 lambda: 等价物,但是使用 with_together: lookup 可能会做你想做的,因为它会给任务访问主机名,匹配 ip,然后允许您根据需要廉价地将它们一起加入。 together 查找应该可以安全地用于将它们配对,因为(据我所知)groups["appX"] 是确定性排序的,因此每个 map 应用程序将发生在同一个列表

- debug:
    msg: |
      the hostname is '{{ item.0 }}'
      its IP is '{{ item.1 }}'
      composite key is '{{ item.0 ~ "_" ~ item.1 }}'
  with_together:
  - '{{ groups["appX"] | map("extract", hostvars, "ansible_hostname") | list }}'
  - '{{ groups["appX"] | map("extract", hostvars, ["ansible_default_ipv4", "address"]) | list }}'