我正在为以下库存主机列表写一本剧本:-
如果主机可访问,则将“ connection = 1”写入文件。如果主机不可访问,请写入同一文件“ connection = 0”
据我了解,Ansible不会以可访问的方式存储无法访问的热点(当ssh失败时)的信息。
能帮我吗? 我的剧本粘贴在下面。 由于主机不可访问,因此根本不执行shell任务
- hosts: '{{ host }}'
gather_facts: False
vars:
dest: /tmp/trace
tasks:
- copy:
content: ''
dest: "{{ dest }}"
run_once: yes
delegate_to: 127.0.0.1
- shell: ping {{ inventory_hostname }} -c 1
register: ping_status
ignore_errors: yes
- setup:
filter: ansible_*
- lineinfile:
dest: "{{ dest }}"
line: 'Host:{{ inventory_hostname }},OS:{{ ansible_distribution }},Kernel:{{ansible_kernel}},OSVersion:{{ansible_distribution_version}},FreeMemory:{{ansible_memfree_mb}},connection:{{ping_status.rc}}'
ignore_errors: true
delegate_to: 127.0.0.1
答案 0 :(得分:2)
您的剧本存在一些问题。首先是您要在远程主机上同时执行shell
和setup
任务,如果该主机不可用,那当然是行不通的。
在远程主机上运行ping
任务甚至没有意义:您想使用委派在本地主机上运行该任务。我们可以这样做,将每个主机的可用性记录为主机变量:
---
- hosts: all
gather_facts: false
tasks:
- delegate_to: localhost
command: ping -c1 "{{ hostvars[inventory_hostname].ansible_host|default(inventory_hostname) }}"
register: ping
ignore_errors: true
- set_fact:
available: "{{ ping.rc == 0 }}"
您正在尝试对远程主机运行setup
模块,但这仅在远程主机可用时才有意义,因此我们需要以ping
的结果为条件任务:
- setup:
filter: "ansible_*"
when: ping.rc == 0
有了这个,我们可以生成一个文件,其中包含有关每个主机的可用性的信息。我在这里使用lineinfile
是因为您在示例中使用了该语言,但是如果我自己编写此代码,则可能会使用template
任务:
- hosts: localhost
gather_facts: false
tasks:
- lineinfile:
dest: ./available.txt
line: "Host: {{ item }}, connection={{ hostvars[item].available }}"
regexp: "Host: {{ item }}"
create: true
loop: "{{ groups.all }}"
当然,在您的示例中,您尝试包括有关主机的其他各种事实:
line: 'Host:{{ inventory_hostname }},OS:{{ ansible_distribution }},Kernel:{{ansible_kernel}},OSVersion:{{ansible_distribution_version}},FreeMemory:{{ansible_memfree_mb}},connection:{{ping_status.rc}}'
如果目标主机不可用,则这些事实将不可用,因此您需要使用{% if <condition> %}...{% endif %}
构造使所有这些条件成为条件:
line: "Host:{{ item }},connection:{{ hostvars[item].available }}{% if hostvars[item].available %},OS:{{ hostvars[item].ansible_distribution }},Kernel:{{ hostvars[item].ansible_kernel }},OSVersion:{{ hostvars[item].ansible_distribution_version }},FreeMemory:{{ hostvars[item].ansible_memfree_mb }}{% endif %}"
这使最终的剧本看起来像这样:
---
- hosts: all
gather_facts: false
tasks:
- delegate_to: localhost
command: ping -c1 "{{ hostvars[inventory_hostname].ansible_host|default(inventory_hostname) }}"
register: ping
ignore_errors: true
- set_fact:
available: "{{ ping.rc == 0 }}"
- setup:
when: ping.rc == 0
- hosts: localhost
gather_facts: false
tasks:
- lineinfile:
dest: ./available.txt
line: "Host:{{ item }},connection:{{ hostvars[item].available }}{% if hostvars[item].available %},OS:{{ hostvars[item].ansible_distribution }},Kernel:{{ hostvars[item].ansible_kernel }},OSVersion:{{ hostvars[item].ansible_distribution_version }},FreeMemory:{{ hostvars[item].ansible_memfree_mb }}{% endif %}"
regexp: "Host: {{ item }}"
create: true
loop: "{{ groups.all }}"
答案 1 :(得分:0)
无法访问的主机可以访问。您可以从魔术变量间接获得它们。
基本上,如果安装模块发生故障,则最有可能是因为服务器无法访问。在这种情况下,甚至我使用的“ always”块都不会捕获此错误,因为故障/不可达主机不被视为“活动”(https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html)。
但是,我用来获取无法访问的主机的方法是循环 groups ['all']魔术变量。此变量包含剧本的所有主机,无论主机是否可达。
因此,主要思想是为所有主机编写变量(分布,内核等),如果未定义变量,那是因为安装任务失败。您可以利用此功能,并使用 default()过滤器将值默认为所需的值(在这种情况下,我使用的是“ NA”,最后一个变量使用“ unreachable”)。 / p>
请让我知道您对此有何看法。
- hosts: all
gather_facts: False
vars:
dest: /tmp/trace
tasks:
- block:
- copy:
content: ''
dest: "{{ dest }}"
run_once: yes
delegate_to: 127.0.0.1
- setup:
filter: ansible_*
- set_fact: connection_status="reachable"
always:
- lineinfile:
dest: "{{ dest }}"
line: 'Host:{{ item }},OS:{{ hostvars[item][ansible_distribution] | default('NA') }},Kernel:{{ hostvars[item][ansible_kernel] | default('NA') }},OSVersion:{{ hostvars[item][ansible_distribution_version] | default('NA') }},FreeMemory:{{ hostvars[item][ansible_memfree_mb] | default('NA') }},connection:{{ hostvars[item][connection_status] | default('unreachable') }}'
loop: "{{ groups['all'] }}"
run_once: true
delegate_to: 127.0.0.1