Ansible变量名不能与Python属性和方法名冲突
否则报错
---
- hosts: test70
remote_user: root
tasks:
- name: "Passing Variables On The Command Line"
debug:
msg: "{{pass_var}}"
ansible-playbook cmdvar.yml --extra-vars "pass_var=cmdline pass var"
ansible-playbook cmdvar.yml -e 'pass_var="test" pass_var1="test1"'
---
- hosts: test70
remote_user: root
vars:
pass_var: test_default
tasks:
- name: "Passing Variables On The Command Line"
debug:
msg: "{{pass_var}}"
ansible-playbook cmdvar.yml -e 'pass_var="test"'
输出test,也就是说,命令行的变量优先级高于yaml文件中的同名变量。
ansible test70 -e "testvar=test" -m shell -a "echo {{testvar}}"
ansible-playbook cmdvar.yml -e '{"testvar":"test","testvar1":"test1"}'
ansible-playbook cmdvar.yml -e '{"countlist":["one","two","three","four"]}'
{{countlist.n}}或{{countlist[n]}}
# cat /testdir/ansible/testvar
testvar: testvarinfile
countlist:
- one
- two
- three
- four
---
- hosts: test70
remote_user: root
tasks:
- name: "Passing Variables On The Command Line"
debug:
msg: "{{testvar}} {{countlist[0]}}"
ansible-playbook cmdvar.yml -e "@/testdir/ansible/testvar"
[root@test2 playbook]# cat /etc/ansible/hosts
[all]
10.0.102.212 test_var=212
10.0.102.200 test_var=200
10.0.102.162 test_var=162
[root@test2 playbook]# cat test.yml
---
- hosts: all
remote_user: root
gather_facts: no
tasks:
- name: test playbook variables
command: echo {{ test_var }}
[root@test2 playbook]# ansible-playbook test.yml -v
作用范围为整个主机组。
[root@test2 playbook]# cat /etc/ansible/hosts
[all]
10.0.102.212
10.0.102.200
10.0.102.162
[all:vars] #给主机组定义变量
test_var=Hello World
在执行ansbile命令时,ansible默认会从/etc/ansible/host_vars/和/etc/amsible/group_vars/两个目录下读取变量定义,如果/etc/ansible下面没有这两个目录,可以直接手动创建,并且可以在这两个目录中创建与hosts(这里是指inventory文件)文件中主机名或组名同名的文件来定义变量。
[root@test2 playbook]# cd /etc/ansible/
[root@test2 ansible]# tree
.
├── group_vars
├── hosts
└── host_vars #定义与主机名同名的文件
├── 10.0.102.162
├── 10.0.102.200
└── 10.0.102.212
2 directories, 4 files
文件中的内容
[root@test2 ansible]# cat host_vars/10.0.102.162
---
test_var: 162
[root@test2 ansible]# cat host_vars/10.0.102.200
---
test_var: 200
[root@test2 ansible]# cat host_vars/10.0.102.212
---
test_var: 212
[root@test2 playbook]# cat test.yml
---
- hosts: all
remote_user: root
gather_facts: no
tasks:
- name: test playbook variables
command: echo {{ test_var }}
[root@test2 playbook]# ansible-playbook test.yml -v
创建与组名同名的文件
[root@test2 ansible]# tree
.
├── group_vars
│ └── all #创建与组名同名的文件
├── hosts
└── host_vars
├── 10.0.102.162
├── 10.0.102.200
└── 10.0.102.212
2 directories, 5 files
[root@test2 ansible]# cat group_vars/all
---
test_group_var: from group
[root@test2 playbook]# cat test.yml
---
- hosts: all
remote_user: root
gather_facts: no
tasks:
- name: test the host variables
command: echo {{ test_var }}
- name: test host group variables #写入测试组变量的task
command: echo {{ test_group_var }}
[root@test2 playbook]# ansible-playbook test.yml -v
vars:
testvar1: testfile
testvar2: testfile2
vars:
- testvar1: testfile
- testvar2: testfile2
---
- hosts: master
remote_user: root
vars:
nginx:
conf80: /etc/nginx/conf.d/80.conf
conf8080: /etc/nginx/conf.d/8080.conf
tasks:
- name: task1
file:
path: "{{nginx.conf80}}"
state: touch
- name: task2
file:
path: "{{nginx.conf8080}}"
state: touch
引用这两个变量时,有两种语法
语法一
"{{nginx.conf80}}"
语法二
"{{nginx['conf8080']}}"
引用变量时使用双引号,变量在被引用时,并没有处于"开头的位置"
path: /testdir/{{ testvar1 }}
当file模块的path参数引用对应的变量时,先写入了’/testdir/’,然后才引用了"testvar1"变量,{{ testvar1 }}并没有处于"开头的位置",换句话说就是,{{ testvar1 }}前面还有字符串’/testdir/’
变量被引用时如下,处于"开头的位置"
path: "{{nginx.conf80}}"
这种情况下,引用变量时必须使用双引号引起被引用的变量,否则会报语法错误。
---
- hosts: master
vars:
testvar1: testfile
remote_user: root
tasks:
- name: task1
file:
path: /testdir/{{ testvar1 }}
state: touch
当在playbook中为模块的参数赋值时,可以使用"冒号",也可以使用"等号",当使用"等号"为模块的参数赋值时,则不用考虑引用变量时是否使用"引号"的问题。
---
- hosts: master
remote_user: root
vars:
nginx:
conf80: /etc/nginx/conf.d/80.conf
conf8080: /etc/nginx/conf.d/8080.conf
tasks:
- name: task1
file:
path={{nginx.conf80}}
state=touch
- name: task2
file:
path={{nginx['conf8080']}}
state=touch
变量文件语法
语法一:
testvar1: testfile
testvar2: testfile2
语法二:
- testvar1: testfile
- testvar2: testfile2
语法三:
nginx:
conf80: /etc/nginx/conf.d/80.conf
conf8080: /etc/nginx/conf.d/8080.conf
---
- hosts: master
remote_user: root
vars_files:
- /testdir/ansible/nginx_vars.yml
tasks:
- name: task1
file:
path={{nginx.conf80}}
state=touch
- name: task2
file:
path={{nginx['conf8080']}}
state=touch
引入多个变量文件
vars_files:
- /testdir/ansible/nginx_vars.yml
- /testdir/ansible/other_vars.yml
vars和vars_files混用
vars:
- conf90: /etc/nginx/conf.d/90.conf
vars_files:
- /testdir/ansible/nginx_vars.yml
vim /testdir/ansible/testfile
testvar1: aaa
testvar2: bbb
定义了三个任务,第二个任务中,使用lineinfile模块在变量文件中增加了testvar3变量,然后在第三个任务 中调用了testvar3变量,执行上例playbook,你会发现,执行出错了,因为在playbook载入vars_files对应的变量文件时,文 件中只有两个变量,在执行第三个任务执行,并没有重新载入对应的变量文件,所以执行报错了。
---
- hosts: test71
remote_user: root
gather_facts: no
vars_files:
- /testdir/ansible/testfile
tasks:
- debug:
msg: "{{testvar1}},{{testvar2}}"
- lineinfile:
path: "/testdir/ansible/testfile"
line: "testvar3: ccc"
- debug:
msg: "{{testvar1}},{{testvar2}},{{testvar3}}"
由于testvar3已经加入到了变量文件中,第一个任务中就能调用到testvar3,第二个任务中, 我们在变量文件中新增了一个变量testvar4,第三个任务调用了’include_vars’模块,'include_vars’模块重新加载了变量 文件,第四个任务中,调用了testvar4变量。
---
- hosts: test71
remote_user: root
gather_facts: no
vars_files:
- /testdir/ansible/testfile
tasks:
- debug:
msg: "{{testvar3}}"
- lineinfile:
path: "/testdir/ansible/testfile"
line: "testvar4: ddd"
- include_vars: "/testdir/ansible/testfile"
- debug:
msg: "{{testvar4}}"
有些时候,变量文件可能并没有位于ansible主机中,而是位于远程主机中,所以,需要先把变量文件从远程主机中拉取到ansible主机 中,当通过前面的task拉取到变量文件以后,也可以使用’include_vars’模块加载刚才拉取到的变量文件,以便后面的task可以使用变量文 件中的变量。
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- include_vars:
file: /testdir/ansible/testfile
- debug:
msg: "{{testvar4}}"
file参数可以指定要包含的变量文件,其实与如下写法效果相同
- include_vars: "/testdir/ansible/testfile"
include_vars可以把变量文件中的变量全部赋值给另外一个变量
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- include_vars:
file: /testdir/ansible/testfile
name: trans_var
- debug:
msg: "{{trans_var}}"
如果想要获取到文件中的某一个变量的值,则可以使用如下方法
tasks:
- include_vars:
file: /testdir/ansible/testfile
name: trans_var
- debug:
msg: "{{trans_var.testvar4}}"
include_vars不仅能够加载指定的变量文件,还能够一次性将指定目录下的所有变量文件中的变量加载,使用dir参数即可指定对应的目录。
- include_vars:
dir: /testdir/ansible/test/
name: trans_var
- debug:
msg: "{{trans_var}}"
使用dir参数指定了"/testdir/ansible/test/"目录,此目录中的所有变量文件都会被加载,但是在使用dir参数时,需要注意如下三点
第一:指定目录中的所有文件的文件后缀必须是 ‘.yaml’ 、’.yml’ 、’.json’中的一种,默认只有这三种后缀是合法后缀,如果目录中存在非合法后缀的文件,执行playbook时则会报错。
第二:如果此目录中的子目录中包含变量文件,子目录中的变量文件也会被递归的加载,而且子目录中的文件也必须遵守上述第一条规则。
第三:dir参数与file参数不能同时使用。
第一点与第二点都是默认设置,可以通过其他选项修改, 当使用dir参数时,指定目录中的所有文件必须以 ‘.yaml’ 、’.yml’ 、’.json’ 作为文件的后缀,如果想要手动指定合法的文件后缀名,则可以使用extensions参数指定哪些后缀是合法的文件后缀,extensions参数的值需 要是一个列表。
tasks:
- include_vars:
dir: /testdir/ansible/test/
extensions: [yaml,yml,json,varfile]
name: trans_var
- debug:
msg: "{{trans_var}}"
当使用dir参数时,默认情况下会递归的加载指定目录及其子目录中的所有变量文件,如果想要控制递归的深度,则可以借助depth参数。
tasks:
- include_vars:
dir: /testdir/ansible/test/
depth: 1
name: trans_var
- debug:
msg: "{{trans_var}}"
在使用dir参数时,还可以借助正则表达式,匹配那些我们想要加载的变量文件,比如,我们只想加载指定目录中以"var_"开头的变量文件,使用’files_matching’参数可以指定正则表达式,当指定目录中的文件名称符合正则时,则可以被加载。
tasks:
- include_vars:
dir: /testdir/ansible/test/
files_matching: "^var_.*"
name: trans_var
- debug:
msg: "{{trans_var}}"
其实,不仅能够使用正则去匹配需要加载的变量文件名,还可以明确指定,哪些变量文件不能被加载,使用’ignore_files’参数可以明确指定需要忽略的变量文件名称,'ignore_files’参数的值是需要是一个列表,加载 /testdir/ansible/test/目录中的变量文件,但是所有以"var_"开头的变量文件和varintest.yaml变量文件将不会被加载, 'files_matching’参数和’ignore_files’参数能够同时使用,当它们同时出现时,会先找出正则匹配到的文件,然后从中排除那些 需要忽略的文件。
tasks:
- include_vars:
dir: /testdir/ansible/test/
ignore_files: ["^var_.*",varintest.yaml]
name: trans_var
- debug:
msg: "{{trans_var}}"
在2.4版本以后的ansible中,当执行了include_vars模块以后,include_vars模块会将载入的变量文件列表写入到自己 的返回值中,这个返回值的关键字为ansible_included_var_files。
tasks:
- include_vars:
dir: /testdir/ansible/test/
register: return_val
- debug:
msg: "{{return_val.ansible_included_var_files}}"
roles:
{ role: app_user, name: alex }
ansible localhost -m setup -a 'filter=ansible_memory_mb'
"ansible_all_ipv4_addresses"表示远程主机中的所有ipv4地址,从其对应的值可以看出,master主机上一共有4个ipv4地址。
"ansible_distribution"表示远程主机的系统发行版,从其对应的值可以看出master主机的系统发行版为centos
"ansible_distribution_version"表示远程主机的系统版本号,从其对应的值与 "ansible_distribution" 的值可以看出master主机的系统版本为centos7.4
"ansible_ens35"表示远程主机ens35网卡的相关信息,细心如你一定也发现了,我还有两个名为"ens33"和"ens34"的网卡,只不过为了方便示例,这两个网卡的信息被我省略了。
"ansible_memory_mb"表示远程主机的内存配置信息。
使用通配符,进行相对模糊的过滤
ansible master -m setup -a "filter=*mb*"
文件位置/etc/ansible/facts.d/下:
[root@master facts.d]# cat testinfo.fact
[testmsg]
msg1=This is the first custom test message
msg2=This is the second custom test message
[root@master facts.d]# cat testinfo.fact
"testmsg":{
"msg1":"This is the first custom test message",
"msg2":"This is the second custom test message"
}
}
ansible master -m setup -a "filter=ansible_local filter=ansible_local "
---
- hosts: test70
remote_user: root
vars:
testvar: value of test variable
tasks:
- name: debug demo
debug:
var: testvar
---
- hosts: test70
remote_user: root
vars:
testvar: testv
tasks:
- name: debug demo
debug:
msg: "value of testvar is : {{testvar}}"
---
- hosts: test70
remote_user: root
tasks:
- name: debug demo
debug:
msg: "Remote host memory information: {{ansible_memory_mb}}"
vim /etc/ansible/facts.d/custom.fact
[general]
package = httpd
service = httpd
state = started
vim setup_facts.yml
---
- name: Install remote facts
hosts: test
vars:
remote_dir: /etc/ansible/facts.d
facts_file: custom.fact
tasks:
- name: Create the remote directory
file:
state: directory
recurse: yes
path: "{{ remote_dir }}"
- name: Install the new facts
copy:
src: "{{ facts_file }}"
dest: "{{ remote_dir }}"
执行该playbook,完成facts的推送:
[root@master ~]#ansible-playbook setup_facts.yml
验证新的facts已经生成:
[root@master ~]# ansible test -m setup
10.1.61.187 | SUCCESS => {
"ansible_facts": {
...output omitted...
"ansible_local": {
"custom": {
"general": {
"package": "httpd",
"service": "httpd",
"state": "started"
}
}
},
...output omitted...
}
在playbook中使用自定义的fact变量:
- name: Install Apache and starts the service
hosts: test
tasks:
- name: Install the required package
yum:
name: "{{ ansible_facts.ansible_local.custom.general.package }}"
state: latest
- name: Start the service
service:
name: "{{ ansible_facts.ansible_local.custom.general.service }}"
state: "{{ ansible_facts.ansible_local.custom.general.state }}"
在playbook中使用set_fact模块定义新的变量:
- name: set_fact example
hosts: test
tasks:
- name: Calculate InnoDB buffer pool size
set_fact: innodb_buffer_pool_size_mb="{{ ansible_memtotal_mb / 2 |int }}"
- debug: var=innodb_buffer_pool_size_mb
[root@master ~]#ansible-playbook set_fact_ex.yaml
这种设置方式只在当前playbook当中有效
- name: Deploy apps
hosts: webservers
gather_facts: False
tasks:
- name: wait for ssh to be running
local_action: wait_for port=22 host="{{ inventory_hostname }}" search_regex=OpenSSH
- name: gather facts
setup:
......
在playbook中需要引入fact,可以开启fact缓存。fact缓存支持三种存储方式:JSON、memcached、redis。
使用JSON文件作为fact缓存后端的时候,ansible将会把采集的fact写入到控制主机的文件中。
/etc/ansible/ansible.cfg配置如下:
[defaults]
gathering = smart
#缓存时间,单位为秒
fact_caching_timeout = 86400
fact_caching = jsonfile
#指定ansible包含fact的json文件位置,如果目录不存在,会自动创建
fact_caching_connection = /tmp/ansible_fact_cache
使用redis作为fact缓存后端,需要控制主机安装redis服务并保持运行。需要安装python操作redis的软件包。
/etc/ansible/ansible.cfg配置如下:
[defaults]
gathering = smart
fact_caching_timeout = 86400
fact_caching = redis
使用memcached作为fact缓存后端,需要控制主机安装Memcached服务并保持运行,需要安装python操作memcached的软件包。
/etc/ansible/ansible.cfg配置如下:
[defaults]
gathering = smart
fact_caching_timeout = 86400
fact_caching = memcached
关闭fact以提升执行效率
- hosts: test
gather_facts: no
也可以在/etc/ansible/ansible.cfg中关闭。
[defaults]
gathering = explicit
ansible的模块在运行之后,其实都会返回一些返回值,默认情况下,返回值并不会显示而已,我们可以把这些返回值写入到某个变 量中,通过引用对应的变量从而获取到这些返回值了,这种将模块的返回值写入到变量中的方法被称为注册变量。
---
- hosts: test70
remote_user: root
tasks:
- name: test shell
shell: "echo test > /var/testshellfile"
register: testvar
- name: shell module return values
debug:
var: testvar
返回的部分信息
...........
"testvar": {
"changed": true,
"cmd": "echo test > /var/testshellfile",
"delta": "0:00:00.003808",
"end": "2018-06-17 20:42:37.675382",
"failed": false,
"rc": 0,
"start": "2018-06-17 20:42:37.671574",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
...........
取得具体属性值
语法一
- name: shell module return values
debug:
msg: "{{testvar.cmd}}"
语法二
- name: shell module return values
debug:
msg: "{{testvar['cmd']}}"
注册变量,其实就是将操作结果,包括标准输出和标准错误输出,保存到变量中,然后再根据这个变量的内容来决定下一步的操作,在这个过程中用来保存操作结果的变量就叫注册变量。
[root@test2 playbook]# cat test.yml
---
- hosts: all
remote_user: root
gather_facts: no
tasks:
- name: test the register variables
shell: uptime
register: results #使用关键字register声明注册变量,上面uptime命令产生的结果,存入到results中。结果是字典形式。
- name: print the register result
debug: msg="{{ results.stdout }}" #使用debug模块,打印出上面命令的输出结果。
一个注册变量通常会有以下4个属性:
changed:任务是否对远程主机造成的变更。
delta:任务运行所用的时间。
stdout:正常的输出信息。
stderr:错误信息。
对于普通变量,在ansible命令行设定的,在hosts文件中定义的,或者在playbook中定义的等,这些都是普通变量,在引用时,可以使用使用{{ variable }}的形式。ansible是用python语言写的,因此也支持一种叫做列表的变量,形式如下:
[root@test2 playbook]# cat test.yml
---
- hosts: all
remote_user: root
gather_facts: no
vars:
var_list: #注意形式,定义了var_list列表,取值方法和列表取值一样,不推荐使用jinja2的方法取值。
- one
- two
- three
tasks:
- name: test the list variables
shell: echo {{ var_list[0] }} #取列表中的第一个字,也就是one
register: results
- name: print the register result
debug: msg="{{ results.stdout }}"
收集的主机信息可以使用setup模块查看
[root@test2 playbook]# ansible 10.0.102.162 -m setup
在实际应用中,运用的比较多的facts变量有ansible_os_family,ansible_hostname等,这些变量通常会被拿来作为when条件语句的判断条件,来决定下一步的操作。
[root@test2 playbook]# cat test.yml
---
- hosts: all
remote_user: root
tasks:
- name: test the list variables
shell: echo {{ ansible_os_family }}
register: results
- name: print the register result
debug: msg="{{ results.stdout }}"
————Blueicex 2020/2/2 10:20 [email protected]