date: 2020-03-15title: ansible变量 #标题
tags: ansible变量 #标签
categories: ansible # 分类
注册变量
ansible的模块在运行之后,其实都会返回一些”返回值”,只是默认情况下,这些”返回值”并不会显示而已,我们可以把这些返回值写入到某个变量中,这样我们就能够通过引用对应的变量从而获取到这些返回值了,这种将模块的返回值写入到变量中的方法被称为”注册变量”,我们可以在模块后通过register来注册变量,如下:
[root@nginx ansible]# cat a.yml- name: testhosts: test1gather_facts: falsetasks:- shell: echo 123 > /a.txtregister: 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: testhosts: test1gather_facts: falsevars_prompt:- name: "your_name"prompt: "what is your name"- name: "your_age"prompt: "how old are you"tasks:- name: output varsdebug:msg: Your name is {{your_name}},You are {{your_age}} years old
执行后如下:
[root@nginx ansible]# ansible-playbook a.ymlwhat 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: testhosts: test1gather_facts: falsevars_prompt:- name: "your_name"prompt: "what is your name"private: no # 增加此配置项即可显示用户输入的内容- name: "your_age"prompt: "how old are you"private: notasks:- name: output varsdebug: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: testhosts: test1gather_facts: falsevars_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 useruser: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.ymlEnter 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.ymlEnter user name: test3Enter 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: testhosts: test1gather_facts: falsetasks:- 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: test1pass_var2:- one- two- three[root@nginx ansible]# cat a.yml # yml文件如下- name: testhosts: test1gather_facts: falsetasks:- 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.test1var2=test1.test2[all:vars] # all的优先级生效范围是所有主机,优先级最小var1=all.test1var2=all.test2
执行结果如下:
ok: [192.168.20.2] => {"msg": "变量为: host.test1,第二个变量为: host.test2"}
内置变量
inventory_hostname
[root@nginx ansible]# cat a.yml # playbook如下- name: testhosts: test1gather_facts: falsetasks:- 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: testhosts: test1gather_facts: falsetasks:- 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"}
