Ansible Playbook开发求助:主机在线检查与循环结果获取
解决Ansible Playbook中基于主机在线状态的任务控制问题
看起来你卡在了如何正确引用循环中每个主机的ping结果上,而且需要调整逻辑来实现「主机在线就跳过/中止,不在线才执行后续角色」的需求。我来帮你修正Playbook并解释清楚关键点:
场景1:针对单个主机,在线则跳过该主机的后续任务
如果你的需求是每个主机独立判断:该主机在线就跳过它的角色安装,不在线才执行,那么可以这样写:
--- - name: Install nameserver from scratch hosts: ns gather_facts: no vars: role: BIND type: host msg: "Successfully installed from scratch" tasks: - name: Check accessibility of all target hosts run_once: true shell: ping -c 1 -w 2 {{ item }} 2>&1 > /dev/null register: online_check delegate_to: localhost with_items: "{{ ansible_play_batch }}" failed_when: false - name: Set fact for current host's online status set_fact: # 筛选出当前主机对应的ping结果,判断返回码是否为0(ping通=在线) is_online: "{{ online_check.results | selectattr('item', 'equalto', inventory_hostname) | map(attribute='rc') | first == 0 }}" - name: Notify and skip if host is online debug: msg: "Host {{ inventory_hostname }} is online, skipping role installation" when: is_online - name: Install required roles only if host is offline include_role: name: "{{ pl_role }}" when: not is_online with_items: - scratch - default - bind - jabber_notifier loop_control: loop_var: pl_role
关键解释:
- 我们用
online_check存储所有主机的ping结果,每个结果包含item(目标主机名)和rc(ping命令的返回码:0=在线,非0=不在线)。 - 通过
set_fact结合Ansible的过滤器,为当前执行任务的主机单独设置is_online变量:selectattr('item', 'equalto', inventory_hostname):从结果列表中筛选出当前主机的ping记录map(attribute='rc'):提取该记录的返回码first == 0:判断返回码是否为0(即是否在线)
- 后续任务通过
when: not is_online控制,只有主机不在线时才执行角色安装。
场景2:只要有一个主机在线,就中止整个Playbook
如果你的需求是全局判断:只要有任何一个目标主机在线,就直接中止整个Playbook执行,那么可以这样调整:
--- - name: Install nameserver from scratch hosts: ns gather_facts: no vars: role: BIND type: host msg: "Successfully installed from scratch" tasks: - name: Check accessibility of all target hosts run_once: true shell: ping -c 1 -w 2 {{ item }} 2>&1 > /dev/null register: online_check delegate_to: localhost with_items: "{{ ansible_play_batch }}" failed_when: false - name: Check if any host is online run_once: true set_fact: # 判断是否存在至少一个ping通的主机(rc=0) any_online: "{{ online_check.results | map(attribute='rc') | select('equalto', 0) | list | length > 0 }}" - name: Abort playbook if any host is online run_once: true debug: msg: "One or more hosts are online, aborting playbook execution" when: any_online # 两种中止方式选其一: # 方式1:标记任务失败来中止 failed_when: any_online # 方式2:用meta模块直接结束Play(无失败标记) # meta: end_play - name: Install required roles (only if all hosts are offline) include_role: name: "{{ pl_role }}" with_items: - scratch - default - bind - jabber_notifier loop_control: loop_var: pl_role when: not any_online
关键解释:
any_online变量通过过滤器判断:从所有ping结果中提取返回码,筛选出等于0的记录,如果数量大于0,说明有主机在线。- 用
failed_when: any_online或者meta: end_play来中止整个Playbook,二选一即可:failed_when会标记任务失败,Playbook终止并返回失败状态meta: end_play会静默终止Playbook,不会标记失败
原代码的核心问题
你之前的when: online.results.item.rc !=0是错误的,原因是:
online.results是一个列表,每个元素是一个主机的ping结果,不能直接用item来引用,必须通过过滤器筛选出对应主机的结果才能获取rc值。- 逻辑上需要明确是针对单个主机判断,还是全局判断,两种场景的变量引用方式完全不同。
内容的提问来源于stack exchange,提问作者twimer nbsp
相关产品推荐
相关产品推荐

