date: 2020-03-15title: ansible变量 #标题
tags: ansible变量 #标签
categories: ansible # 分类
注册变量
ansible的模块在运行之后,其实都会返回一些”返回值”,只是默认情况下,这些”返回值”并不会显示而已,我们可以把这些返回值写入到某个变量中,这样我们就能够通过引用对应的变量从而获取到这些返回值了,这种将模块的返回值写入到变量中的方法被称为”注册变量”,我们可以在模块后通过register来注册变量,如下:
[root@nginx ansible]# cat a.yml
- name: test
hosts: test1
gather_facts: false
tasks:
- shell: echo 123 > /a.txt
register: testvar
- debug:
msg: "{{ testvar }}"
执行结果如下:
TASK [shell] *******************************************************************
changed: [192.168.20.2]
TASK [debug] *******************************************************************
ok: [192.168.20.2] => { # 我们可以通过{{ testvar.xxxx }}来调用某个变量值,如:{{ testvar.cmd }}
"msg": {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"cmd": "echo 123 > /a.txt",
"delta": "0:00:00.007632",
"end": "2020-03-15 09:29:00.830874",
"failed": false,
"rc": 0,
"start": "2020-03-15 09:29:00.823242",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
不同的模块,返回值也不尽相同。
交互式输入变量
在运行某些脚本时,有时候脚本会提示用户输入一些信息,脚本需要根据用户输入的信息决定下一步的动作,这种”交互”有时候是必须的,那么,在playbook中该怎样实现这种交互呢?我们可以这样做,提示用户输入信息,然后将用户输入的信息存入到指定的变量中,当我们需要使用这些”输入的信息”时,只要引用对应的变量即可。
例如:
[root@nginx ansible]# cat a.yml
- name: test
hosts: test1
gather_facts: false
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
执行后如下:
[root@nginx ansible]# ansible-playbook a.yml
what is your name: # 输入的值将赋值到playbook文件中
how old are you:
# 输出如下:
TASK [output vars] ************************
ok: [192.168.20.2] => {
"msg": "Your name is lvjianzhao,You are 18 years old."
}
如你所见,输入的值并不会显示在屏幕中,这种方式比较适合用户输入密码的场景,如果想要显示用户输入的信息,你可以增加private选项,如下:
[root@nginx ansible]# cat a.yml
- name: test
hosts: test1
gather_facts: false
vars_prompt:
- name: "your_name"
prompt: "what is your name"
private: no # 增加此配置项即可显示用户输入的内容
- name: "your_age"
prompt: "how old are you"
private: no
tasks:
- name: output vars
debug:
msg: Your name is {{your_name}},You are {{your_age}} years old.
在上面的注册变量和交互式写入变量可以发现,有时引入变量带了双引号,有时不带,总结来说,如果是以变量开头的,那么需要带双引号,如果变量前还有其他字符,则不需要双引号。千万不要想着不管引用变量前有没有字符都写上双引号,那就错了,比如上面的示例,如果加上双引号,则输出如下:
TASK [output vars] **************************************************
ok: [192.168.20.2] => {
"msg": "Your name is \"dfdfd\",You are \"dfdfd\" years old."
}
交互式输入创建用户并设置密码
[root@nginx ansible]# cat a.yml
- name: test
hosts: test1
gather_facts: false
vars_prompt:
- name: "user_name" # 准备接受用户名
prompt: "Enter user name" # 提示语句
private: no # 用户输入的信息可以显示在屏幕上
- name: "user_password" # 准备接受用户密码
prompt: "Enter user password" # 提示语句
encrypt: "sha512_crypt" # encrypt关键字表示对用户输入的信息进行哈希, “sha512_crypt”表示使用sha512算法对用户输入的信息进行哈希
confirm: yes # 提示第二次输入确认密码
tasks:
- name: create user
user:
name: "{{user_name}}"
password: "{{user_password}}"
需要注意,当使用”encrypt”关键字对字符串进行哈希时,ansible需要依赖passlib库完成哈希操作,如果未安装passlib库(一个用于哈希明文密码的python库),执行playbook时会报如下错误ERROR! passlib must be installed to encrypt vars_prompt values
解决办法:
# pip install passlib # 使用pip命令安装passlib库即可
上面的playbook文件中,任何配置都是存在既合理,如果不对用户输入的密码进行加密,那么保存在/etc/shadow文件中的密码就是一个未经过加密的字符,新用户也不能使用密码进行登录,所以才需要自行加密。
最后执行如下:
[root@nginx ansible]# ansible-playbook a.yml
Enter user name: test2 # 输入的用户名会显示在终端
Enter user password: # 第一次输入密码
confirm Enter user password: # 第二次确认密码
PLAY [test] ********************************************************************
TASK [create user] *************************************************************
changed: [192.168.20.2]
PLAY RECAP *********************************************************************
192.168.20.2 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 如果两次输入的值不一致,则会提示重新输入,如下:
[root@nginx ansible]# ansible-playbook a.yml
Enter user name: test3
Enter user password:
confirm Enter user password:
***** VALUES ENTERED DO NOT MATCH ****
Enter user password:
confirm Enter user password:
通过命令行传入变量
[root@nginx ansible]# cat a.yml # playbook文件如下
- name: test
hosts: test1
gather_facts: false
tasks:
- debug:
msg: "第一个变量为: {{pass_var1}},第二个变量为: {{pass_var2}}"
执行结果如下:
# 通过命令行传入变量,多个变量名以空格相隔即可
[root@nginx ansible]# ansible-playbook a.yml -e 'pass_var1="test1" pass_var2="test2"'
PLAY [test] ********************************************************************
TASK [debug] *******************************************************************
ok: [192.168.20.2] => {
"msg": "第一个变量为: test1,第二个变量为: test2"
}
注:即使playbook文件中定义了相应的变量,命令行依然可以传入相同名称的变量对其进行覆盖,因为命令行传入变量比在playbook中的优先级要高。
还可以使用json格式传入变量,如下:
[root@nginx ansible]# ansible-playbook a.yml -e '{"pass_var1":"test1","pass_var2":"test2"}'
对应的playbook文件正常引入变量即可。
通过json格式传入稍微复杂些的变量
[root@nginx ansible]# ansible-playbook a.yml -e '{"pass_var1":["test1","test2"]}'
# playbook中引用test1这个值的话,需要使用{{ pass_var1.0 }}
# 如果要引用test2这个值,就是{{ pass_var1.1 }},以此类推。。。
在命令行中引入变量文件
命令行不仅能够传入变量,还能传入变量文件,变量文件中的变量都会一并被传入,变量文件可以是json格式的,也可以是YAML格式的,此处使用YAML格式的变量文件进行示例,示例文件内容如下:
[root@nginx ansible]# cat variables # 变量文件如下
pass_var1: test1
pass_var2:
- one
- two
- three
[root@nginx ansible]# cat a.yml # yml文件如下
- name: test
hosts: test1
gather_facts: false
tasks:
- debug:
msg: "第一个变量为: {{pass_var1}},第二个变量为: {{pass_var2.1}}"
[root@nginx ansible]# ansible-playbook a.yml -e "@variables" # @后面可以是绝对路径,也可以是相对路径。
TASK [debug] *******************************************************************
ok: [192.168.20.2] => {
"msg": "第一个变量为: test1,第二个变量为: two"
}
在清单中定义变量
[root@nginx ansible]# tail -8 hosts
[test1]
192.168.20.2 var1=host.test1 var2=host.test2 # 直接写在主机后面,优先级最高
[test1:vars] # 通过主机组:vars来定义变量,优先级次于主机后面定义的变量
var1=test1.test1
var2=test1.test2
[all:vars] # all的优先级生效范围是所有主机,优先级最小
var1=all.test1
var2=all.test2
执行结果如下:
ok: [192.168.20.2] => {
"msg": "变量为: host.test1,第二个变量为: host.test2"
}
内置变量
inventory_hostname
[root@nginx ansible]# cat a.yml # playbook如下
- name: test
hosts: test1
gather_facts: false
tasks:
- debug:
msg: "{{inventory_hostname}}"
# 执行结果如下
TASK [debug] *******************************************************************
ok: [192.168.20.2] => {
"msg": "192.168.20.2"
}
ok: [192.168.20.3] => {
"msg": "192.168.20.3"
}
返回的是hosts文件中定义的主机名称,如果定义的是IP,则返回IP。
play_hosts
[root@nginx ansible]# cat a.yml # playbook如下
- name: test
hosts: test1
gather_facts: false
tasks:
- debug:
msg: "{{play_hosts}}"
# 执行结果如下
TASK [debug] *******************************************************************
ok: [192.168.20.3] => {
"msg": [
"192.168.20.2",
"192.168.20.3"
]
}
ok: [192.168.20.2] => {
"msg": [
"192.168.20.2",
"192.168.20.3"
]
}
细心如你,一定可以看出来play_hosts和inventory_hostname的区别是什么,没错,inventory_hostname返回的是当前正在执行的节点主机名,play_hosts每次返回的是主机组中所有的主机名。
group_names
用于返回主机所在的主机组名称,如下:
[root@nginx ansible]# ansible 192.168.20.2 -m debug -a "msg={{group_names}}"
192.168.20.2 | SUCCESS => {
"msg": [
"test1" # 192.168.20.2属于test1主机组
]
}
inventory_dir
用于返回主机清单所在的绝对路径,如下:
[root@nginx ansible]# ansible 192.168.20.2 -m debug -a "msg={{inventory_dir}}"
192.168.20.2 | SUCCESS => {
"msg": "/etc/ansible"
}