问题描述
在使用Ansible时遇到了一个问题:他希望能够在编写YAML文件时,定义一个数组,并且如果给定的值未定义,则跳过将这些值添加到数组中的操作。具体来说,他正在尝试定义一个IP地址数组,用于将一个服务(例如sshd)绑定到这些IP地址上,包括IPv4和IPv6地址。如果既有IPv4地址又有IPv6地址,那么数组应该包含这两个值。如果只有IPv4地址或只有IPv6地址,则数组应该包含其中一个值。用户尝试了一些方法,但出现了错误。以下是他尝试的一些代码片段:
ssh_listen_to:
- "{{ ansible_default_ipv4.address }}"
- "{{ ansible_default_ipv6.address }}"
以及:
ssh_listen_to:
- "{{ ansible_default_ipv4.address | default('') }}"
- "{{ ansible_default_ipv6.address | default('') }}"
请问如何更新上述代码块,以便在值未定义时,跳过将值添加到数组的操作?请注意,这些操作是在Playbook的vars
部分中进行的,因此不希望使用基于任务的解决方案。
解决方案
用户收到了几个回答,以下是其中一个可能的解决方案,以及一个最佳回答。
方案1
用户收到了一个使用Jinja2和Ansible变量来创建列表的解决方案。这个方法首先将定义和未定义的IP地址分别存储在一个Jinja2模板变量中,然后通过转换将其应用到Ansible变量中。这个方法的示例如下:
- hosts: localhost
gather_facts: true
tasks:
- set_fact:
ssh_listen_to: "{{ _ssh_listen_to|from_yaml }}"
vars:
_ssh_listen_to: |
{% if ansible_default_ipv4.address is defined %}
- {{ ansible_default_ipv4.address }}
{% endif %}
{% if ansible_default_ipv6.address is defined %}
- {{ ansible_default_ipv6.address }}
{% endif %}
这个解决方案通过创建Jinja2模板变量_ssh_listen_to
,在其中根据IP地址是否定义来添加相应的条目。然后,通过set_fact
任务将Jinja2模板变量应用到Ansible变量ssh_listen_to
中。
最佳方案
用户收到了一个被用户投票选为最佳答案的解决方案,这个方案使用了select()
函数和defined
测试。该解决方案的示例如下:
ssh_listen_to: "{{ [ansible_facts.default_ipv4.address, ansible_facts.default_ipv6.address] | select('defined') | list }}"
这个解决方案创建了一个包含默认IPv4地址和IPv6地址的列表,然后使用select()
函数来选择已定义的值,并使用list
函数将结果转换为列表。这个解决方案更加简洁且符合用户的需求。
在此之后,用户还有进一步的问题,询问第二个解决方案中的一些细节。最佳答案提供了对第二个解决方案中的正则表达式字符类[46]
的解释,以及相关的细节。最佳答案还对用户的问题进行了回答,给出了详细的解释和示例。
如果用户想要了解更多有关Ansible中变量和过滤器的信息,可以查阅Ansible官方文档以获得更多帮助。
注意:以上解决方案的代码在实际使用中可能需要根据具体情况进行调整和测试。
【评论1】:非常好的回答,谢谢!您能详细解释一下第二个命令吗?其中的46
是什么意思?
【回复】:[46]
是一个正则表达式字符类,它匹配字符串中的单个字符,可以是数字4或数字6。