我有3个远程VM和1个ansible节点。
我通过ansible shell模块在这些远程VM上运行hostname命令并在 hostname_output 变量中注册该输出来获取某些VM的主机名。
然后我想将这些VM的IP (使用gather_facts收集:True,{{ansible_default_ipv4.address}})添加到主机名中,并将其附加到文件 temp_hostname 在localhost上,因此我将任务委托给localhost。
但问题是,当我在控制台上看到时,lineinfile模块表示在为每个节点执行模块并将其委托给localhost时添加了该行,但是当我检查localhost上的文件时,只显示了1个条目在localhost而不是3。
---
- name: get hostnames of dynamically created VMs
hosts: all
remote_user: "{{ remote_user }}"
gather_facts: True
tasks:
- name: save hostname in variable, as this command is executed remotely, and we want the value on the ansible node
shell: hostname
register: hostname_output
- name: writing hostname_output in ansible node in file on ansible node
lineinfile:
line: "{{ ansible_default_ipv4.address }} {{ hostname_output.stdout }}"
dest: temp_hostname
state: present
delegate_to: 127.0.0.1
我甚至尝试使用Ansible writing output from multiple task to a single file中指定的复制模块,但也给出了相同的结果,即仅1个条目。
---
- name: get hostnames of dynamically created VMs
hosts: all
remote_user: "{{ remote_user }}"
gather_facts: True
tasks:
- name: save hostname in variable, as this command is executed remotely, and we want the value on the ansible node
shell: hostname
register: hostname_output
- name: writing hostname_output in ansible node in file on ansible node
copy:
content: "{{ ansible_default_ipv4.address }} {{ hostname_output.stdout }}"
dest: /volume200gb/sushil/test/code_hostname/temp_hostname
delegate_to: 127.0.0.1
最后,当我使用带有重定向操作符的shell模块时,它按照我想要的方式工作,即localhost上的3个文件。
---
- name: get hostnames of dynamically created VMs
hosts: all
remote_user: "{{ remote_user }}"
gather_facts: True
tasks:
- name: save hostname in variable, as this command is executed remotely, and we want the value on the ansible node
shell: hostname
register: hostname_output
- name: writing hostname_output in ansible node in file on ansible node
shell: echo -e "{{ ansible_default_ipv4.address }} {{ hostname_output.stdout }}" >> temp_hostname
delegate_to: 127.0.0.1
我使用命令调用此ansible-playbook get_hostname.yml:
ansible-playbook -i hosts get_hostname.yml --ssh-extra-args =“ - o StrictHostKeyChecking = no”--extra-vars“remote_user = cloud-user”-vvv
我的主机文件是:
10.194.11.86 private_key_file=/root/.ssh/id_rsa
10.194.11.87 private_key_file=/root/.ssh/id_rsa
10.194.11.88 private_key_file=/root/.ssh/id_rsa
我使用的是ansible 2.1.0.0
我只使用默认的ansible.cfg,没有修改
我的问题是为什么lineinfile和copy模块不起作用?我错过了什么或写错了吗
答案 0 :(得分:0)
使用第一个带有lineinfile的代码块,我得到了不一致的结果。有时我在目标文件中获得所有3个IP和主机名,有时我只得到2.我不确定为什么会这样,但我的猜测是Ansible正在尝试同时保存对文件的更改而且只是一个变化被接受了。
第二个代码块无法正常工作,因为复制将覆盖该文件,除非内容与已存在的内容相匹配。运行的最后一个主机将是目标文件中唯一的IP /主机名。
要解决此问题,您可以循环播放play_hosts
(当前播放中的活动主持人)并使用hostvars
引用其变量。
- name: writing hostname_output in ansible node in file on ansible node
lineinfile:
line: "{{ hostvars[item]['ansible_default_ipv4'].address }} {{ hostvars[item]['hostname_output'].stdout }}"
dest: temp_hostname
state: present
delegate_to: 127.0.0.1
run_once: True
with_items: "{{ play_hosts }}"
或者您可以使用具有相同逻辑的模板
- name: writing hostname_output in ansible node in file on ansible node
template:
src: IP_hostname.j2
dest: temp_hostname
delegate_to: 127.0.0.1
run_once: True
IP_hostname.j2
{% for host in play_hosts %}
{{ hostvars[host]['ansible_default_ipv4'].address }} {{ hostvars[host]['hostname_output'].stdout }}
{% endfor %}
答案 1 :(得分:0)
我试图重现你的问题并且它没有发生在我身上,我怀疑这是你的ansible版本的问题,尝试使用最新版本。
话虽如此,我认为您可以使用serial: 1
使其工作,这可能是文件锁定的一个问题,我不会在ansible 2.3中看到发生。我还认为,不是使用shell任务来收集主机名,而是可以使用作为安全事实提供的ansible_hostname
变量,如果你想要的只是主机名,你还可以避免收集所有事实。具体的任务。最后,它看起来像这样:
---
- name: get hostnames of dynamically created VMs
hosts: all
serial: 1
remote_user: "{{ remote_user }}"
tasks:
- name: Get hostnames
setup:
filter: ansible_hostname
- name: writing hostname_output in ansible node in file on ansible node
lineinfile:
line: "{{ ansible_default_ipv4.address }} {{ ansible_hostname }}"
dest: temp_hostname
state: present
delegate_to: 127.0.0.1
答案 2 :(得分:0)
问题就在这里,只有一个文件有多个并发写入。这会导致意想不到的结果:
对此的解决方案是在您的游戏中使用 serial: 1
,这会强制您的主机之间非并行执行。
但它可能会成为性能杀手,具体取决于主机数量。
我建议使用另一种解决方案:不是只写入一个文件,每个主机代表团都可以写入自己的文件(此处使用 inventory_hostname
值)。因此,它将没有更多的并发写入。
之后,您可以使用模块 assemble
将所有文件合并为一个。这是一个示例(未经测试):
---
- name: get hostnames of dynamically created VMs
hosts: all
remote_user: "{{ remote_user }}"
gather_facts: True
tasks:
- name: save hostname in variable, as this command is executed remotely, and we want the value on the ansible node
shell: hostname
register: hostname_output
- name: deleting tmp folder
file: path=/tmp/temp_hostname state=absent
delegate_to: 127.0.0.1
run_once: true
- name: create tmp folder
file: path=/tmp/temp_hostname state=directory
delegate_to: 127.0.0.1
run_once: true
- name: writing hostname_output in ansible node in file on ansible node
template: path=tpl.j2 dest=/tmp/temp_hostname/{{ inventory_hostname }}
delegate_to: 127.0.0.1
- name: assemble hostnames
assemble: src=/tmp/temp_hostname/ dest=temp_hostname
delegate_to: '{{ base_rundeck_server }}'
run_once: true
显然您必须创建 tpl.j2
文件。