Ansible系列基础篇 1.7.2、PlayBook之变量
一、变量定义及使用
定义:变量名应该由字母、数字、下划线组成,变量名需要以字母开头,ansible内置的关键字不能作为变量名。
1.1、基础变量
变量基础使用示例(红色字体为关键字部分):
--- - hosts: test70 vars: testvar1: testfile remote_user: root tasks: - name: task1 file: path: /testdir/{{ testvar1 }} state: touch
1.2、定义多个变量
方式一:
vars: testvar1: testfile testvar2: testfile2
方式二:
vars: - testvar1: testfile - testvar2: testfile2
方式三:
nginx: conf80: /etc/nginx/conf.d/80.conf conf8080: /etc/nginx/conf.d/8080.conf
1.3、属性方式定义变量
--- - hosts: test70 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
1.4、变量引用时 引号使用
变量在被引用时,变量出"开头的位置,变量引用,一定要加上冒号,否则报语法错误;当变量引用并没有处于"开头的位置",则不需要加上冒号。具体用法示例如下:
file: # 变量不在开头位置 path: /testdir/{{ testvar1 }} state: touch file: # 变量在开头位置 path: "{{nginx.conf80}}" state: touch
在playbook中为模块的参数赋值时,可以使用"冒号",也可以使用"等号",当使用"等号"为模块的参数赋值时,则不用考虑引用变量时是否使用"引号"的问题,示例如下:
--- - hosts: test70 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
1.5、文件中定义变量 var_files
# cat nginx_vars.yml nginx: conf80: /etc/nginx/conf.d/80.conf conf8080: /etc/nginx/conf.d/8080.conf
在nginx_vars.yml中定义完相关变量后,即可在playbook中引入文件中的变量,在playbook中引入包含变量的文件时,需要使用"vars_files"关键字,被引入的文件需要以"- "开头,以YAML中块序列的语法引入,示例如下:
---
- hosts: test70
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引入多个变量文件,每个被引入的文件都需要以"- "开头,示例如下:
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
二、注册变量
ansible的模块在运行之后,其实都会返回一些"返回值",只是默认情况下,这些"返回值"并不会显示而已,我们可以把这些返回值写入到某个变量中,这样我们就能够通过引用对应的变量从而获取到这些返回值了,这种将模块的返回值写入到变量中的方法被称为"注册变量",那么怎样将返回值注册到变量中呢?我们来看一个playbook示例:
--- - hosts: test70 remote_user: root tasks: - name: test shell shell: "echo test > /var/testshellfile" register: testvar - name: shell module return values debug: var: testvar
示例结果:
TASK [shell module return values] **********************************************************************
ok: [test70] => {
"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": []
}
}
如果想获取上述返回信息的特定key值,则可以:
语法一 - name: shell module return values debug: msg: "{{testvar.cmd}}" 语法二 - name: shell module return values debug: msg: "{{testvar['cmd']}}"
三、用户输入信息的变量
用户输入的信息,存储到变量中(默认情况下private: yes,用户输入,并不会显示,类似linux输入密码),示例代码如下:
---
- hosts: test70
remote_user: root
vars_prompt:
- name: "your_name"
prompt: "What is your name"
- name: "your_age"
prompt: "How old are you"
tasks:
- name: output vars
debug:
msg: Your name is {{your_name}},You are {{your_age}} years old.
显示用户的输入信息,示例代码如下:
vars_prompt: - name: "your_name" prompt: "What is your name" private: no - name: "your_age" prompt: "How old are you" private: no
输入变量设置默认值,示例代码如下:
---
- hosts: test70
remote_user: root
vars_prompt:
- name: "solution"
prompt: "Choose the solution you want \n
A: solutionA\n
B: solutionB\n
C: solutionC\n"
private: no
default: A
tasks:
- name: output vars
debug:
msg: The final solution is {{solution}}.
user模块,加密解密语法,示例代码如下:
# user模块的password字段,会默认对密码进行加密,如果用变量传递,最后主机的密码会变成加密后的字符串,这时候需要encrypt语法糖 --- - hosts: test70 remote_user: root vars_prompt: - name: "user_name" prompt: "Enter user name" private: no - name: "user_password" prompt: "Enter user password" tasks: - name: create user user: name: "{{user_name}}" password: "{{user_password}}"
entrypt依赖passlib库,需要python先安装, pip install passlib。
---
- hosts: test70
remote_user: root
vars_prompt:
- name: "hash_string"
prompt: "Enter something"
private: no
encrypt: "sha512_crypt"
tasks:
- name: Output the string after hash
debug:
msg: "{{hash_string}}"
还有confirm关键字进行密码二次确认
vars_prompt:
- name: "user_password"
prompt: "Enter user password"
encrypt: "sha512_crypt"
confirm: yes
四、通过命令传递变量
- 命令传递变量,是在执行脚本(ansible-playbook)或命令(ansible)时,通过'--extra-vars' 或 '-e' 来传递变量
- 命令行传入的变量的优先级要高于playbook中的变量
- 命令传递变量,除了支持'key=vaule'的形式,还支持json的传递( ‘{'key': 'vaule', 'key2': 'vaule2'}’ )
# 标准示例 ansible-playbook cmdvar.yml --extra-vars "pass_var=cmdline pass var" # -e简化,多个变量 ansible-playbook cmdvar.yml -e 'pass_var="test" pass_var1="test1"' # 传递json格式变量 ansible-playbook cmdvar.yml -e '{"testvar":"test","testvar1":"test1"}' # 传递复杂json格式变量,想要获取one值,使用如下两种语法引用变量{{countlist[0]}} 或者 {{countlist.0}} ansible-playbook cmdvar.yml -e '{"countlist":["one","two","three","four"]}' # 传递文件中的变量,文件内容按照标准变量来写即可 ansible-playbook cmdvar.yml -e "@/testdir/ansible/varfile"
五、主机变量
Inventory文件内主机组定义的变量,可以直接在命令或剧本上,引用变量
可以参考本教程:https://www.cnblogs.com/wangsl1204/p/13649218.html
六、Gathering Facts
功能:搜集系统信息。
参考setup debug模块使用:https://www.cnblogs.com/wangsl1204/p/14177537.html
七、set_fact定义变量
set_fact是一个模块,我们可以通过set_fact模块在tasks中定义变量,主要用在跨playbook之间的同一台主机变量的传递,基础示例:
---
- hosts: test70
remote_user: root
tasks:
- set_fact:
testvar: "testtest"
- debug:
msg: "{{testvar}}"
复杂方式使用,从一个task的执行结果输出,赋给set_fact变量,在后续task上执行。
--- - hosts: test70 remote_user: root vars: testvar1: test1_string tasks: - shell: "echo test2_string" register: shellreturn - set_fact: testsf1: "{{testvar1}}" testsf2: "{{shellreturn.stdout}}" - debug: msg: "{{testsf1}} {{testsf2}}"
set_fact设置的变量,可以给同个yml文件中,不同的剧本使用,具体示例如下:
# 执行该playbook # 第一个playbook中,testvar1 testvar2变量都能正常输出; # 第二个playbook中,testvar1输出异常,testvar2输出正常; # 每个play执行之前都会执行一个名为"[Gathering Facts]"的默认任务,这个任务会收集对应主机的相关信息,我们可以称这些信息为facts信息,我们已经总结过怎样通过变量引用这些facts信息,此处不再赘述,而通过set_fact模块创建的变量可以在之后play中被引用,就好像主机的facts信息可以在play中引用一样。 # 第一个play中针对test70主机进行操作时,testvar1是通过vars关键字创建的,而testvar2是通过set_fact创建的,所以testvar2就好像test70的facts信息一样,可以在第二个play中引用到,而创建testvar1变量的方式则不能达到这种效果,虽然testvar2就像facts信息一样能被之后的play引用,但是在facts信息中并不能找到testvar2,只是"效果上"与facts信息相同罢了。 --- - hosts: test70 remote_user: root vars: testvar1: tv1 tasks: - set_fact: testvar2: tv2 - debug: msg: "{{testvar1}} ----- {{testvar2}}" - hosts: test70 remote_user: root tasks: - name: other play get testvar2 debug: msg: "{{testvar2}}" - name: other play get testvar1 debug: msg: "{{testvar1}}"
register的变量效果范围,和set_fact一样,示例代码如下:
# 第二个playbook中,testvar3 testvar4可以正常输出 # 第二个playbook中,testvar3不能正常输出,testvar4可以正常输出 --- - hosts: test70 remote_user: root vars: testvar3: tv3 tasks: - shell: "echo tv4" register: testvar4 - debug: msg: "{{testvar3}} -- {{testvar4.stdout}}" - hosts: test70 remote_user: root tasks: - name: other play get testvar4 debug: msg: "{{testvar4.stdout}}" - name: other play get testvar3 debug: msg: "{{testvar3}}"
八、内置变量
8.1、ansible_version
功能:获取ansble的版本号
ansible test -m debug -a "msg={{ansible_version}}"
8.2、hostvars
功能:获取主机的各个变量
假设,我想要在操作test70主机时获取到test71主机中的facts信息,示例如下:
hostvars在操作 当前主机调用"[Gathering Facts]"任务 输出其他主机中的facts信息,示例中使用hostvars加上清单中的主机名称再加上facts的key,即可获取到对应的facts信息。如果示例中test71主机设置 ‘gather_facts: no’,则示例执行失败。
--- - name: "play 1: Gather facts of test71" hosts: test71 remote_user: root - name: "play 2: Get facts of test71 when operating on test70" hosts: test70 remote_user: root tasks: - debug: msg: "{{hostvars['test71'].ansible_ens35.ipv4}}" #或者 msg: "{{hostvars.test71.ansible_ens35.ipv4}}"
除了facts信息,我们还能够利用hostvars内置变量从别的主机中获取到其他类型的一些变量信息,比如,其他主机的注册变量、主机变量、组变量等信息,我们先来看一个获取其他主机的注册变量的小示例,如下:
--- - hosts: test71 remote_user: root gather_facts: no tasks: - shell: "echo register_var_in_play1" register: shellreturn - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{hostvars.test71.shellreturn.stdout}}"
如上例所示,通过hostvars内置变量可以直接获取到其他主机中的注册变量,你一定发现了,注册变量并不用像facts信息那样需要事先收集,即可直接通过hostvars跨主机被引用到,同理,如果你在清单中为test71主机配置了主机变量,或者为test71主机所在的组配置了组变量,也是可以通过hostvars直接跨主机引用的。
play中为当前主机定义一个变量,可以在之后的play中操作其他主机时被引用到吗?那么我们来做个实验,示例如下:
结论:不能被引用到
--- - hosts: test71 remote_user: root gather_facts: no vars: testvar: testvar_in_71 tasks: - debug: msg: "{{testvar}}" - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{hostvars.test71.testvar}}"
解决上述问题,可以使用set_fact,示例如下:
--- - hosts: test71 remote_user: root gather_facts: no tasks: - set_fact: testvar: "testvar_in_71" - debug: msg: "{{testvar}}" - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{hostvars.test71.testvar}}"
8.3、inventory_hostname
功能:获取到被管节点当前主机的主机名称,是Inventory文件中配置的名称(可能是IP,也可能是主机名)。
8.4、inventory_hostname_short
功能:与内置变量inventory_hostname类似,通过inventory_hostname_short也可以获取当前play操作的主机在清单中对应的名称,但是这个名称更加简短。无论是IP还是主机名,如果清单的主机名称中包含".",inventory_hostname_short都会取得主机名中第一个"."之前的字符作为主机的简短名称。
8.5、play_hosts
功能:获取到当前play所操作的所有主机的主机名列表。
8.6、groups
功能:获取inventory文件的分组情况,包括用户的分组、all组、单独的机器组(未分类组)。
8.7、group_names
功能:获取到当前主机所在分组的组名(当一台主机在多个组下,可以有多个组名)。
8.8、inventory_dir
功能:获取到当前ansible主机中清单文件的存放路径。