
我試圖從使用者輸入的主機清單中取得主機名稱和 IP 位址,並將該資訊傳送到中央伺服器。我遇到的主要問題是主機數量可能相差很大。例如,在第一次執行時,使用者可以輸入 1 個主機名,第二次執行時輸入 30,下次執行時間輸入 5。
執行 Ansible Tower 範本時,透過「額外變數」提示收集主機名稱:
client_hosts: 'host1,host2'
然後在劇本中引用:
- name: Gather client information
hosts:
- "{{ client_hosts | default(omit) }}"
tasks:
- name: Grab client hostname
shell: cat /etc/hostname
register: client_hostname
- name: Grab client IP address
shell: hostname -i | sed -n '1 p'
register: client_ip
在劇本中,我想將這些 IP + 主機名稱新增至特定中央伺服器上的檔案(伺服器主機名稱不會變更):
- name: Update server
hosts: central.server
tasks:
- name: Update client host list
lineinfile:
path: /path/to/file
line: "{{ hostvars['client_hosts']['client_ip'] }} - {{ hostvars['client_hosts']['client_hostname'] }}"
上面的內容對於單一主機來說效果很好,但是當指定了多個主機(例如client_hostname[1,2,*]?)時,我如何循環註冊變量,並在我不知道如何時用這些值更新伺服器很多主持人要提前進入?
答案1
此用例分為三個部分:1) 管理庫存,2) 收集客戶端主機名和客戶端IP,以及3)向中央伺服器報告。
1. 管理庫存
關於如何管理庫存和收集有很多選擇客戶端主機名和客戶端IP。例如,使用新增主機範圍如果您打算建立數百個具有簡單名稱(例如host001, hosts002, ..., host999
.例如,在下方的庫存中添加中央伺服器,為了簡單起見,本地主機,以及群組中的一百台主機測試
shell> cat inventory/01-hosts
central_server ansible_host=localhost
[test]
host[001:100]
[test:vars]
ansible_connection=ssh
ansible_user=admin
ansible_become=yes
ansible_become_user=root
ansible_become_method=sudo
ansible_python_interpreter=/usr/local/bin/python3.8
簡單測試一下庫存
- hosts: all
gather_facts: false
tasks:
- debug:
var: ansible_play_hosts|length
run_once: true
給出刪節的
ansible_play_hosts|length: '101'
如果您想顯示完整的庫存,請執行以下命令
shell> ansible-inventory -i inventory --list --yaml
然後有很多選擇主機的選項。看模式:定位主機和群組。例如,限制特定主機或群組的清單。使用下面的簡單劇本進行測試
shell> cat pb1.yml
- hosts: all
gather_facts: false
tasks:
- debug:
var: inventory_hostname
給
shell> ansible-playbook -i inventory pb1.yml -l host001,host002
PLAY [all] ***********************************************************************************
TASK [debug] *********************************************************************************
ok: [host001] =>
inventory_hostname: host001
ok: [host002] =>
inventory_hostname: host002
PLAY RECAP ***********************************************************************************
host001: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host002: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
使用庫存插件建如果您想將清單限制為更大的主機群組。看
shell> ansible-doc -t inventory constructed
例如,額外的變數主機數在下面的範例中用於建立群組我的組包含受此變數值限制的主機
shell> cat inventory/02-constructed.yml
plugin: constructed
strict: true
use_extra_vars: true
compose:
my_group_count: count_hosts|default(0)
groups:
my_group: inventory_hostname[-2:]|int < my_group_count|int
測試一下
shell> ansible-playbook -i inventory pb.yml -e count_hosts=10 -l my_group
PLAY [all] ***********************************************************************************
TASK [debug] *********************************************************************************
ok: [host001] =>
ansible_play_hosts|length: '11'
PLAY RECAP ***********************************************************************************
host001: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如果您想顯示完整的庫存,請執行以下命令
shell> ansible-inventory -i inventory -e count_hosts=10 --list --yaml
在的幫助下建插件,您可以創建複雜的條件。例如,將主機限制在特定間隔並建立群組我的組2
shell> cat inventory/02-constructed.yml
plugin: constructed
strict: true
use_extra_vars: true
compose:
my_group_count: count_hosts|default(0)
my_group_start: start_hosts|default(0)
my_group_stop: stop_hosts|default(0)
groups:
my_group1: inventory_hostname[-2:]|int < my_group_count|int
my_group2: inventory_hostname[-2:]|int >= my_group_start|int and
inventory_hostname[-2:]|int < my_group_stop|int
測試一下
shell> ansible-playbook -i inventory pb1.yml -e start_hosts=10 -e stop_hosts=15 -l my_group2
PLAY [all] ***********************************************************************************
TASK [debug] *********************************************************************************
ok: [host010] =>
inventory_hostname: host010
ok: [host011] =>
inventory_hostname: host011
ok: [host012] =>
inventory_hostname: host012
ok: [host013] =>
inventory_hostname: host013
ok: [host014] =>
inventory_hostname: host014
...
2. 收集客戶端主機名和客戶端IP
您可以使用以下任一模組設定或自行收集事實。因為便攜性設定應該是首選。
查看模組設定關於如何收集有關遠端主機的事實。例如,下面的劇本收集了有關機器和網路並創建變數客戶端主機名和客戶端IP
shell> cat pb2.yml
- hosts: all
gather_facts: false
tasks:
- setup:
gather_subset:
- machine
- network
- set_fact:
client_hostname: "{{ ansible_hostname }}"
- debug:
var: client_hostname
- debug:
var: ansible_default_ipv4
- debug:
var: ansible_all_ipv4_addresses
- set_fact:
client_ip: "{{ ansible_all_ipv4_addresses|last }}"
- debug:
var: client_ip
給
shell> ansible-playbook -i inventory -l host011 pb2.yml
PLAY [all] ***********************************************************************************
TASK [setup] *********************************************************************************
ok: [host011]
TASK [set_fact] ******************************************************************************
ok: [host011]
TASK [debug] *********************************************************************************
ok: [host011] =>
client_hostname: test_11
TASK [debug] *********************************************************************************
ok: [host011] =>
ansible_default_ipv4: {}
TASK [debug] *********************************************************************************
ok: [host011] =>
ansible_all_ipv4_addresses:
- 10.1.0.61
TASK [set_fact] ******************************************************************************
ok: [host011]
TASK [debug] *********************************************************************************
ok: [host011] =>
client_ip: 10.1.0.61
PLAY RECAP ***********************************************************************************
host011: ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
事實的結構和格式可能因作業系統而異。
您可以自行收集事實。例如,下面的劇本
shell> cat pb3.yml
- hosts: all
gather_facts: false
tasks:
- name: Grab client hostname
command: cat /etc/hostname
register: out
- set_fact:
client_hostname: "{{ out.stdout }}"
- debug:
var: client_hostname
- name: Grab client IP address
shell: hostname -i | sed -n '1 p'
register: out
- set_fact:
client_ip: "{{ out.stdout|split|last }}"
- debug:
var: client_ip
給出在Linux上運行
shell> ansible-playbook -i inventory -l central_server pb3.yml
PLAY [all] ***********************************************************************************
TASK [Grab client hostname] ******************************************************************
changed: [central_server]
TASK [set_fact] ******************************************************************************
ok: [central_server]
TASK [debug] *********************************************************************************
ok: [central_server] =>
client_hostname: central_server
TASK [Grab client IP address] ****************************************************************
changed: [central_server]
TASK [set_fact] ******************************************************************************
ok: [central_server]
TASK [debug] *********************************************************************************
ok: [central_server] =>
client_ip: 10.1.0.22
PLAY RECAP ***********************************************************************************
central_server: ok=6 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
實用程式的輸出可能因作業系統而異。
3)向中央伺服器報告
使用 Jinja 建立結構。運行一次任務並將其委託給中央伺服器
shell> cat pb4.yml
- hosts: all
gather_facts: false
tasks:
- setup:
gather_subset:
- machine
- network
- set_fact:
client_hostname: "{{ ansible_hostname }}"
client_ip: "{{ ansible_all_ipv4_addresses|last }}"
- copy:
dest: /tmp/test_host_ip.txt
content: |
{% for host in ansible_play_hosts %}
{{ hostvars[host]['client_hostname'] }} - {{ hostvars[host]['client_ip'] }}
{% endfor %}
run_once: true
delegate_to: central_server
給
shell> ansible-playbook -i inventory -l host011,host013 pb4.yml
PLAY [all] ***********************************************************************************
TASK [setup] *********************************************************************************
ok: [host013]
ok: [host011]
TASK [set_fact] ******************************************************************************
ok: [host011]
ok: [host013]
TASK [copy] **********************************************************************************
changed: [host011 -> central_server(localhost)]
PLAY RECAP ***********************************************************************************
host011: ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host013: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
該劇本在以下位置創建了該文件中央伺服器
shell> cat /tmp/test_host_ip.txt
test_11 - 10.1.0.61
test_13 - 10.1.0.63
使用模組文件行如果您想為文件新增行。下面的劇本是冪等的
shell> cat pb5.yml
- hosts: all
gather_facts: false
tasks:
- setup:
gather_subset:
- machine
- network
- set_fact:
client_hostname: "{{ ansible_hostname }}"
client_ip: "{{ ansible_all_ipv4_addresses|last }}"
- lineinfile:
path: /tmp/test_host_ip.txt
line: |-
{{ hostvars[item]['client_hostname'] }} - {{ hostvars[item]['client_ip'] }}
loop: "{{ ansible_play_hosts }}"
run_once: true
delegate_to: central_server
在同一主機上重複運行不會有任何變化
shell> ansible-playbook -i inventory -l host011,host013 pb5.yml
PLAY [all] ***********************************************************************************
TASK [setup] *********************************************************************************
ok: [host011]
ok: [host013]
TASK [set_fact] ******************************************************************************
ok: [host011]
ok: [host013]
TASK [lineinfile] ****************************************************************************
ok: [host011 -> central_server(localhost)] => (item=host011)
ok: [host011 -> central_server(localhost)] => (item=host013)
PLAY RECAP ***********************************************************************************
host011: ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host013: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如果劇本在新主機上運行,則新行將新增至檔案中
shell> ansible-playbook -i inventory -l central_server pb5.yml
PLAY [all] ***********************************************************************************
TASK [setup] *********************************************************************************
ok: [central_server]
TASK [set_fact] ******************************************************************************
ok: [central_server]
TASK [lineinfile] ****************************************************************************
changed: [central_server] => (item=central_server)
PLAY RECAP ***********************************************************************************
central_server: ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
新行已附加到文件中
shell> cat /tmp/test_host_ip.txt
test_11 - 10.1.0.61
test_13 - 10.1.0.63
central_server - 10.1.0.184
答案2
您可以使用 playbook 中的 with_items 指令循環存取 client_hosts 變數。然後,您可以透過在循環中使用 item 變數來引用每個單獨的主機。
以下是如何修改 playbook 以處理多個主機的範例:
- name: Gather client information
hosts: "{{ client_hosts | default(omit) }}"
tasks:
- name: Grab client hostname and IP address
shell: |
hostname -i | sed -n '1 p' > /tmp/client_ip
cat /etc/hostname > /tmp/client_hostname
register: gather_client_info
become: true
- name: Set client hostname and IP address as variables
set_fact:
client_hostname: "{{ hostvars[item]['gather_client_info'].stdout_lines[1] }}"
client_ip: "{{ hostvars[item]['gather_client_info'].stdout_lines[0] }}"
with_items: "{{ client_hosts | default(omit) }}"
- name: Update server
hosts: central.server
tasks:
- name: Update client host list
lineinfile:
path: /path/to/file
line: "{{ client_ip }} - {{ client_hostname }}"
with_items: "{{ client_hosts | default(omit) }}"
劇本將循環存取 client_hosts 變數中的每個主機,並使用 shell 模組收集主機名稱和 IP 位址。然後它將使用 set_fact 模組將這些值設為變數。最後,它將再次循環 client_hosts 變量,並使用 lineinfile 模組使用每個主機的主機名稱和 IP 位址更新中央伺服器上的檔案。
希望這可以幫助。