Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.htmlphp
facts組件是用來收集被管理節點信息的,使用setup模塊能夠獲取這些信息。html
ansible-doc -s setup
- name: Gathers facts about remote hosts
如下是某次收集的信息示例。因爲收集的信息項很是多,因此截取了部份內容項。mysql
ansible 192.168.100.64 -m setup
192.168.100.64 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.100.64"
],
"ansible_all_ipv6_addresses": [
"fe80::20c:29ff:fe03:a452"
],
"ansible_apparmor": {
"status": "disabled"
},
"ansible_architecture": "x86_64",
"ansible_bios_date": "07/02/2015",
"ansible_bios_version": "6.00",
"ansible_cmdline": {
"BOOT_IMAGE": "/vmlinuz-3.10.0-327.el7.x86_64",
"LANG": "en_US.UTF-8",
"biosdevname": "0",
"crashkernel": "auto",
"net.ifnames": "0",
"quiet": true,
"ro": true,
"root": "UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8"
},
........................................
"ansible_default_ipv6": {},
"ansible_devices": {
"sda": {
"holders": [],
"host": "SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)",
"model": "VMware Virtual S",
"partitions": {
"sda1": {
"holders": [],
"sectors": "512000",
"sectorsize": 512,
"size": "250.00 MB",
"start": "2048",
"uuid": "367d6a77-033b-4037-bbcb-416705ead095"
},
"sda2": {
"holders": [],
"sectors": "37332992",
"sectorsize": 512,
"size": "17.80 GB",
"start": "514048",
"uuid": "b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8"
},
................................
"ansible_user_dir": "/root",
"ansible_user_gecos": "root",
"ansible_user_gid": 0,
"ansible_user_id": "root",
"ansible_user_shell": "/bin/bash",
"ansible_user_uid": 0,
"ansible_userspace_architecture": "x86_64",
"ansible_userspace_bits": "64",
"ansible_virtualization_role": "guest",
"ansible_virtualization_type": "VMware",
"module_setup": true
},
"changed": false
}
使用filter能夠篩選指定的facts信息。例如:ios
ansible 192.168.100.64 -m setup -a "filter=changed"
192.168.100.64 | SUCCESS => {
"ansible_facts": {},
"changed": false
}
ansible localhost -m setup -a "filter=*ipv4"
localhost | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "192.168.100.62",
"alias": "eth0",
"broadcast": "192.168.100.255",
"gateway": "192.168.100.2",
"interface": "eth0",
"macaddress": "00:0c:29:d9:0b:71",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "192.168.100.0",
"type": "ether"
}
},
"changed": false
}
facts收集的信息是json格式的,其內任一項均可以看成變量被直接引用(如在playbook、jinja2模板中)引用。見下文。nginx
在ansible中,任何一個模塊都會返回json格式的數據,即便是錯誤信息都是json格式的。sql
在ansible中,json格式的數據,其內每一項均可以經過變量來引用它。固然,引用的前提是先將其註冊爲變量。shell
例如,下面的playbook是將shell模塊中echo命令的結果註冊爲變量,並使用debug模塊輸出。數據庫
---
- hosts: 192.168.100.65
tasks:
- shell: echo hello world
register: say_hi
- debug: var=say_hi
debug輸出的結果以下:json
TASK [debug] *********************************************
ok: [192.168.100.65] => {
"say_hi": {
"changed": true,
"cmd": "echo hello world",
"delta": "0:00:00.002086",
"end": "2017-09-20 21:03:40.484507",
"rc": 0,
"start": "2017-09-20 21:03:40.482421",
"stderr": "",
"stderr_lines": [],
"stdout": "hello world",
"stdout_lines": [
"hello world"
]
}
}
能夠看出,結果是一段json格式的數據,最頂端的key爲say_hi
,其內是一大段的字典(即便用大括號包圍的),其中的stdout_lines
還包含了一個json數組,也就是所謂的yaml列表項(即便用中括號包圍的)。centos
若是想要輸出json數據的某一字典項,則應該使用"key.dict"或"key['dict']"的方式引用。例如最多見的stdout項"hello world"是想要輸出的項,如下兩種方式都能引用該字典變量。
---
- hosts: 192.168.100.65
tasks:
- shell: echo hello world
register: say_hi
- debug: var=say_hi.stdout
- debug: var=sya_hi['stdout']
ansible-playbook的部分輸出結果以下:
TASK [debug] ************************************************
ok: [192.168.100.65] => {
"say_hi.stdout": "hello world"
}
TASK [debug] ************************************************
ok: [192.168.100.65] => {
"say_hi['stdout']": "hello world"
}
"key.dict"或"key['dict']"的方式都能引用,但在dict字符串自己就包含"."的時候,應該使用中括號的方式引用。例如:
anykey['192.168.100.65']
若是想要輸出json數據中的某一數組項(列表項),則應該使用"key[N]"的方式引用數組中的第N項,其中N是數組的index,從0開始計算。若是不使用index,則輸出的是整個數組列表。
例如想要輸出上面的stdout_lines
中的"hello world",它是數組stdout_lines
中第一項因此使用stdout_lines[0]
來引用,再加上stdout_lines
上面的say_hi
,因而引用方式以下:
---
- hosts: 192.168.100.65
tasks:
- shell: echo hello world
register: say_hi
- debug: var=say_hi.stdout_lines[0]
因爲stdout_lines
中僅有一項,因此即便不使用index的方式即say_hi.stdout_lines
也能獲得指望的結果。輸出結果以下:
TASK [debug] *************************************************
ok: [192.168.100.65] => {
"say_hi.stdout_lines[0]": "hello world"
}
再看下面一段json數據。
"ipv6": [
{
"address": "fe80::20c:29ff:fe26:1498",
"prefix": "64",
"scope": "link"
}
]
其中key=ipv6,其內有且僅有是一個列表項,但該列表內包含了數個字典項。要引用列表內的字典,例如上面的address項。應該以下引用:
ipv6[0].address
既然已經瞭解了json數據中的字典和列表列表項的引用方式,顯然facts中的一大堆數據就能引用並派上用場了。例如如下是一段facts數據。
shell> ansible localhost -m setup -a "filter=*eth*"
localhost | SUCCESS => {
"ansible_facts": {
"ansible_eth0": {
"active": true,
"device": "eth0",
"features": {
"busy_poll": "off [fixed]",
"fcoe_mtu": "off [fixed]",
"generic_receive_offload": "on",
.........................
},
"ipv4": {
"address": "192.168.100.62",
"broadcast": "192.168.100.255",
"netmask": "255.255.255.0",
"network": "192.168.100.0"
},
"macaddress": "00:0c:29:d9:0b:71",
"module": "e1000",
............................
}
},
"changed": false
}
顯然,facts數據的頂級key爲ansible_facts
,在引用時應該將其包含在變量表達式中。但自動收集的facts比較特殊,它以ansible_facts
做爲key,ansible每次收集後會自動將其註冊爲變量,因此facts中的數據均可以直接經過變量引用,甚至連頂級key ansible_facts
都要省略。
例如引用上面的ipv4的地址address項。
ansible_eth0.ipv4.address
而不能寫成:
ansible_facts.ansible_eth0.ipv4.address
但其餘任意時候,都應該帶上全部的key。
在ansible收集facts時,還會自動收集/etc/ansible/facts.d/*.fact文件內的數據到facts中,且以ansible_local
作爲key。目前fact支持兩種類型的文件:ini和json。固然,若是fact文件的json或ini格式寫錯了致使沒法解析,那麼確定也沒法收集。
例如,在/etc/ansible/facts.d目錄下存在一個my.fact的文件,其內數據以下:
shell> cat /etc/ansible/facts.d/my.fact
{
"family": {
"father": {
"name": "Zhangsan",
"age": "39"
},
"mother": {
"name": "Lisi",
"age": "35"
}
}
}
ansible收集facts後的本地facts數據以下:
shell> ansible localhost -m setup -a "filter=ansible_local"
localhost | SUCCESS => {
"ansible_facts": {
"ansible_local": {
"my": {
"family": {
"father": {
"age": "39",
"name": "Zhangsan"
},
"mother": {
"age": "35",
"name": "Lisi"
}
}
}
}
},
"changed": false
}
可見,若是想要引用本地文件中的某個key,除了帶上ansible_local外,還必須得帶上fact文件的文件名。例如,引用father的name。
ansible_local.my.family.father.name
上文已經展現了一種變量的引用方式:使用debug的var參數。debug的另外一個參數msg也能輸出變量,且msg能夠輸出自定義信息,而var參數只能輸出變量。
另外,msg和var引用參數的方式有所不一樣。例如:
---
- hosts: 192.168.100.65
tasks:
- debug: 'msg="ipv4 address: {{ansible_eth0.ipv4.address}}"'
- debug: var=ansible_eth0.ipv4.address
msg引用變量須要加上雙大括號包圍,既然加了大括號,爲了防止被解析爲內聯字典,還得加引號包圍。這裏使用了兩段引號,由於其內還包括了一個": ",加引號能夠防止它被解析爲"key: "的格式。而var參數引用變量則直接指定變量名。
這就像bash中引用變量的方式是同樣的,有些時候須要加上$
,有些時候不能加$
。也就是說,當引用的是變量的值,就須要加雙大括號,就像加$
同樣,而引用變量自己,則不能加雙大括號。其實雙大括號是jinja2中的分隔符。
執行的部分結果以下:
TASK [debug] *****************************************************
ok: [192.168.100.65] => {
"msg": "ipv4 address: 192.168.100.65"
}
TASK [debug] *****************************************************
ok: [192.168.100.65] => {
"ansible_eth0.ipv4.address": "192.168.100.65"
}
幾乎全部地方均可以引用變量,例如循環、when語句、信息輸出語句、template文件等等。只不過有些地方不能使用雙大括號,有些地方須要使用。
ansible中定義變量的方式有不少種,大體有:(1)將模塊的執行結果註冊爲變量;(2)直接定義字典類型的變量;(3)role中文件內定義變量;(4)命令行傳遞變量;(5)藉助with_items迭代將多個task的結果賦值給一個變量;(6)inventory中的主機或主機組變量;(7)內置變量。
使用register選項,能夠將當前task的輸出結果賦值給一個變量。例如,下面的示例中將echo的結果"haha"賦值給say_hi變量。注意,模塊的輸出結果是json格式的,因此,引用變量時要指定引用的對象。
---
- hosts: localhost
tasks:
- shell: echo haha
register: say_hi
- debug: var=say_hi.stdout
set_fact和register的功能很類似,也是將值賦值給變量。它更像shell中變量的賦值方式,能夠將某個變量的值賦值給另外一個變量,也能夠將字符串賦值給變量。
例如:
---
- hosts: 192.168.100.65
tasks:
- shell: echo haha
register: say_hi
- set_fact: var1="{{say_hi.stdout}}"
- set_fact: var2="your name is"
- debug: msg="{{var2}} {{var1}}"
能夠在play或task層次使用vars定義字典型變量。若是同名,則task層次的變量覆蓋play層次的變量。
例如:
---
- hosts: localhost vars: var1: value1 var2: value2 tasks: - debug: msg="{{var1}} {{var2}}" vars: var2: value2.2
輸出結果爲:
TASK [debug] ********************************************
ok: [localhost] => {
"msg": "value1 value2.2"
}
和vars同樣,只不過它是將變量以字典格式定義在獨立的文件中,且vars_files
不能定義在task層次,只能定義在play層次。
---
- hosts: localhost
vars_files:
- /tmp/var_file1.yml
- var_file2.yml
tasks:
- debug: msg="{{var1}} {{var2}}"
上面var_file2.yml使用的是相對路徑,基於playbook所在的路徑。例如該playbook爲/tmp/x.yml,則var_file2.yml也應該在/tmp下。固然,徹底可使用絕對路徑。
因爲role是整合playbook的,它有默認的文件組織結構。其中有一個目錄vars,其內的main.yml用於定義變量。還有defaults目錄內的main.yml則是定義role默認變量的,默認變量的優先級最低。
shell> tree /yaml /yaml ├── roles │ └── nginx │ ├── defaults │ └── main.yml │ ├── files │ ├── handlers │ ├── meta │ ├── tasks │ ├── templates │ └── vars │ └── main.yml └── site.yml
main.yml中變量定義方式也是字典格式,例如:
---
mysql_port: 3306
ansible和ansible-playbook命令的"-e"選項均可以傳遞變量,傳遞的方式有兩種:-e key=value
和-e @var_file
。注意,當key=value方式傳遞變量時,若是變量中包含特殊字符,必須防止其被shell解析。
例如:
ansible localhost -m shell -a "echo {{say_hi}}" -e 'say_hi="hello world"'
ansible localhost -m shell -a "echo {{say_hi}}" -e @/tmp/var_file1.yml
其中/tmp/var_file1.yml中的內容以下:
---
say_hi: hello world
ansible中能夠藉助with_items實現列表迭代的功能,做用於變量註冊的行爲上,就能夠實現將多個結果賦值給同一個變量。
例以下面的playbook中,給出了3個item列表,並在shell模塊中經過固定變量"{{item}}"分別迭代,第一次迭代的是haha,第二次迭代的是heihei,第三次迭代的是hehe,也就實現了3次循環。最後,將結果註冊爲變量hi_var。
---
- hosts: localhost
remote_user: root
tasks:
- name: test #
shell: echo "{{item}}"
with_items:
- haha
- heihei
- hehe
register: hi_var
- debug: var=hi_var.results[0].stdout
- debug: var=hi_var.results[1].stdout
- debug: var=hi_var.results[2].stdout
每次迭代的過程當中,調用item的模塊都會將結果保存在一個key爲results的數組中。所以,引用迭代後註冊的變量時,須要在變量名中加上results,並指定數組名。例如上面的hi_var.results[N].stdout
。
還可使用for循環遍歷列表。例如:
- debug: msg="{% for i in hi_var.results %} {{i.stdout}} {% endfor %}"
其實,看一下hi_var的輸出就很容易理解了。如下是hi_var的第一個列表的輸出。
"hi_var": {
"changed": true,
"msg": "All items completed",
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "echo \"haha\"",
"delta": "0:00:00.001942",
"end": "2017-09-21 04:45:57.032946",
"invocation": {
"module_args": {
"_raw_params": "echo \"haha\"",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
}
},
"item": "haha",
"rc": 0,
"start": "2017-09-21 04:45:57.031004",
"stderr": "",
"stderr_lines": [],
"stdout": "haha",
"stdout_lines": [
"haha"
]
}
在inventory文件中能夠爲主機和主機組定義變量,不只包括內置變量賦值,還包括自定義變量賦值。例如如下inventory文件。
192.168.100.65 ansible_ssh_port=22 var1=1 [centos7]
192.168.100.63
192.168.100.64
192.168.100.65 var1=2 [centos7:vars]
var1=2.2
var2=3 [all:vars]
var2=4
其中ansible_ssh_port
是主機內置變量,爲其賦值22,這類變量是設置類變量,不能被引用。此外還在多處爲主機192.168.100.65進行了賦值。其中[centos7:vars]
和[all:vars]
表示爲主機組賦值,前者是爲centos7這個組賦值,後者是爲全部組賦值。
如下是執行語句:
shell> ansible 192.168.100.65 -i /tmp/hosts -m shell -a 'echo "{{var1}} {{var2}}"'
192.168.100.65 | SUCCESS | rc=0 >>
2 3
從結果可知,主機變量優先級高於主機組變量,給定的主機組變量優先級高於all特殊組。
除了在inventory文件中定義主機、主機組變量,還能夠將其定義在host_vars和group_vars目錄下的獨立的文件中,但要求這些host_vars或group_vars這兩個目錄和inventory文件或playbook文件在同一個目錄下,且變量的文件以對應的主機名或主機組名命名。
例如,inventory文件路徑爲/etc/ansible/hosts,playbook文件路徑爲/tmp/x.yml,則主機192.168.100.65和主機組centos7的變量文件路徑能夠爲如下幾種:
如下爲幾個host_vars和group_vars目錄下的文件內容。
shell> cat /etc/ansible/{host_vars/192.168.100.65,group_vars/centos7} \
/tmp/{host_vars/192.168.100.65,group_vars/centos7}
var1: 1
var2: 2
var3: 3
var4: 4
如下爲/tmp/x.yml的內容。
---
- hosts: 192.168.100.65 tasks: - debug: msg='{{var1}} {{var2}} {{var3}} {{var4}}'
執行結果以下:
TASK [debug] **********************************************
ok: [192.168.100.65] => {
"msg": "1 2 3 4"
}
ansible除了inventory中內置的一堆不可被引用的設置類變量,還有幾個全局均可以引用的內置變量,主要有如下幾個:
inventory_hostname、inventory_hostname_short、groups、group_names、hostvars、play_hosts、inventory_dir和ansible_version。
1.inventory_hostname和inventory_hostname_short
分表表明的是inventory中被控節點的主機名和主機名的第一部分,若是定義的是主機別名,則變量的值也是別名。
例如inventory中centos7主機組定義爲以下:
[centos7] 192.168.100.63 host1 ansible_ssh_host=192.168.100.64 www.host2.com ansible_ssh_host=192.168.100.65
分別輸出它們的inventory_hostname
和inventory_hostname_short
。
shell> ansible centos7 -m debug -a 'msg="{{inventory_hostname}} & {{inventory_hostname_short}}"'
192.168.100.63 | SUCCESS => {
"msg": "192.168.100.63 & 192"
}
host1 | SUCCESS => {
"msg": "host1 & host1"
}
www.host2.com | SUCCESS => {
"msg": "www.host2.com & www"
}
2.groups和group_names
group_names返回的是主機所屬主機組,若是該主機在多個組中,則返回多個組,若是它不在組中,則返回ungrouped這個特殊組。
例如,某個inventory文件以下:
192.168.100.60
192.168.100.63
192.168.100.64
192.168.100.65 [centos6]
192.168.100.60 [centos7]
192.168.100.63
host1 ansible_ssh_host=192.168.100.64
www.host2.com ansible_ssh_host=192.168.100.65 [centos:children]
centos6
centos7
其中100.60定義在centos6和centos中,因此返回這兩個組。同理100.63返回centos7和centos。100.64和100.65則返回ungrouped,雖然它們在centos7中都定義了別名,但至少將100.64和100.65做爲主機名時,它們是不在任何主機中的。另外一方面,host1和www.host2.com這兩個別名主機都返回centos7和centos兩個組。
groups變量則是返回其所在inventory文件中全部組和其內主機名。注意,該變量對每一個控制節點都返回一次,因此返回的內容可能很是多。例如,上面的inventory中,若是指定被控節點爲centos7,則會重複返回3次(由於有3臺被控主機)該inventory文件。其中的第三臺主機www.host2.com的返回結果爲:
www.host2.com | SUCCESS => {
"msg": {
"all": [
"192.168.100.60",
"192.168.100.63",
"192.168.100.64",
"192.168.100.65",
"host1",
"www.host2.com"
],
"centos": [
"192.168.100.60",
"192.168.100.63",
"host1",
"www.host2.com"
],
"centos6": [
"192.168.100.60"
],
"centos7": [
"192.168.100.63",
"host1",
"www.host2.com"
],
"ungrouped": [
"192.168.100.60",
"192.168.100.63",
"192.168.100.64",
"192.168.100.65"
]
}
}
3.hostvars
該變量用於引用其餘主機上收集的facts中的數據,或者引用其餘主機的主機變量、主機組變量。其key爲主機名或主機組名。
舉個例子,假如使用ansible部署一臺php服務器host1,且配置文件內須要指向另外一臺數據庫服務器host2的ip地址ip2,能夠直接在配置文件中指定ip2,但也能夠在模板配置文件中直接引用host2收集的facts數據中的ansible_eth0.ipv4.address變量。
例如,centos7主機組中包含了192.168.100.[63:65]共3臺主機。playbook內容以下:
---
- hosts: centos7 tasks: - debug: msg="{{hostvars['192.168.100.63'].ansible_eth0.ipv4.address}}"
執行結果以下:
TASK [debug] *********************************************************
ok: [192.168.100.63] => {
"msg": "192.168.100.63"
}
ok: [192.168.100.64] => {
"msg": "192.168.100.63"
}
ok: [192.168.100.65] => {
"msg": "192.168.100.63"
}
但注意,在引用其餘主機facts中數據時,要求被引用主機進行了facts收集動做,或者有facts緩存。不然都沒收集,固然沒法引用其facts數據。也就是說,當被引用主機沒有facts緩存時,ansible的控制節點中必須同時包含引用主機和被引用主機。
除了引用其餘主機的facts數據,還能夠引用其餘主機的主機變量和主機組變量,且不要求被引用主機有facts數據,由於主機變量和主機組變量是在ansible執行任務前加載的。
例如,inventory中格式以下:
192.168.100.59 [centos7]
192.168.100.63 var63=63
192.168.100.64
192.168.100.65 [centos7:vars]
var64=64
playbook內容以下:
---
- hosts: 192.168.100.59 tasks: - debug: msg="{{hostvars['192.168.100.63'].var63}} & {{hostvars['192.168.100.65'].var64}}"
執行結果以下:
TASK [debug] ***************************************
ok: [192.168.100.59] => {
"msg": "63 & 64"
}
4.play_hosts和inventory_dir
play_hosts表明的是當前play所涉及inventory內的全部主機名列表。
例如,inventory內容爲:
192.168.100.59
[centos6]
192.168.100.62
192.168.100.63
[centos7]
192.168.100.64
192.168.100.65
那麼,該inventory內的任意一或多臺主機做爲ansible或ansible-playbook的被控節點時,都會返回整個inventory內的全部主機名稱。
inventory_dir是所使用inventory所在的目錄。
5.ansible_version
表明的是ansible軟件的版本號。變量返回的內容以下:
{
"full": "2.3.1.0",
"major": 2,
"minor": 3,
"revision": 1,
"string": "2.3.1.0" }
最後,不得不說ansible的變量定義方式太豐富了,可是ansible的官方手冊真的噁心到吐,太爛了。