使用过ansible的同学都知道,注册变量并使用,是一个很常见的场景。今天就总结下常见的一些情况,了解ansible变量定义、引用及格式化相关内容。
当playbook运行的时候,经常需要中途收集一些数据,后面使用它。使用register注册变量是最简单、最常用的一种方式。
我们最常用的是,执行一条shell命令,并将返回结果注册为一个变量,例如:
tasks:
- name: define a var1
shell: "whoami"
register: whoami
- debug:
msg: "whoami: {{ whoami }}"
- debug:
msg: "whoami.stdout: {{whoami.stdout}}"
这里要注意,ansible执行结果一般都会返回一个字典类型的数据,你会看到很多你不关心的字段,可以通过指定字典的key,例如stdout或stdout_lines,只看到你关心的数据。
请看返回结果:
TASK [define a var1] ************************************************************************************************************************************************************************
changed: [vagrant1]
TASK [debug] ********************************************************************************************************************************************************************************
ok: [vagrant1] => {
"msg": "whoami: {'stderr_lines': [], u'changed': True, u'end': u'2020-04-19 15:18:18.278098', 'failed': False, u'stdout': u'vagrant', u'cmd': u'whoami', u'rc': 0, u'start': u'2020-04-19 15:18:18.274052', u'stderr': u'', u'delta': u'0:00:00.004046', 'stdout_lines': [u'vagrant']}"
}
TASK [debug] ********************************************************************************************************************************************************************************
ok: [vagrant1] => {
"msg": "whoami.stdout: vagrant"
}
这种场景,一般是列表中的元素逐个要参与运算,将运算后的结果存入一个变量,看一个示例:
---
- hosts: "{{ hosts_group }}"
remote_user: vagrant
vars:
userss: []
tasks:
- name: define users in a loop
shell: "grep {{ item }} /etc/passwd|cat"
register: users
with_items:
- vagrant
- root
- nginx
- name: show users
debug:
msg: "{{ users }}"
- name: show users.results
debug:
msg: "{{ users.results }}"
- name: define userss by set_fact
set_fact:
userss: "{{userss +item.stdout_lines}}"
with_list: "{{ users.results }}"
- name: print userss
debug:
msg: "{{ userss }}"
- name: print userss one by one
debug:
msg: "{{ item }}"
with_list: "{{ userss}}"
- name: print part of userss one by one
debug:
msg: "{{ item.split(':')[6] }}"
with_list: "{{ userss}}"
该示例是通过关键字是查询系统的用户及shell信息,ansible会返回一个字典,查询的结果存储在字典名称为results的key对应的value中,这个value本身是一个list。因为我们都不知道到底会查到几个用户,所以再把结果list遍历一遍,存储到另外一个变量中。我们使用set_fact实现了循环给空list变量添加数据的效果。最后,我们分别获取每行的数据,并且进行拆分,获取到了第7个字段。
请看返回结果:
TASK [define users in a loop] ***************************************************************************************************************************************************************
changed: [vagrant1] => (item=vagrant)
changed: [vagrant1] => (item=root)
changed: [vagrant1] => (item=nginx)
TASK [show users] ***************************************************************************************************************************************************************************
ok: [vagrant1] => {
"msg": {
"changed": true,
"msg": "All items completed",
"results": [
{
"_ansible_ignore_errors": null,
"_ansible_item_label": "vagrant",
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "grep vagrant /etc/passwd|cat",
"delta": "0:00:00.004695",
"end": "2020-04-19 15:18:19.129083",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "grep vagrant /etc/passwd|cat",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": "vagrant",
"rc": 0,
"start": "2020-04-19 15:18:19.124388",
"stderr": "",
"stderr_lines": [],
"stdout": "vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash",
"stdout_lines": [
"vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash"
]
},
{
"_ansible_ignore_errors": null,
"_ansible_item_label": "root",
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "grep root /etc/passwd|cat",
"delta": "0:00:00.004695",
"end": "2020-04-19 15:18:19.421598",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "grep root /etc/passwd|cat",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": "root",
"rc": 0,
"start": "2020-04-19 15:18:19.416903",
"stderr": "",
"stderr_lines": [],
"stdout": "root:x:0:0:root:/root:/bin/bash\noperator:x:11:0:operator:/root:/sbin/nologin",
"stdout_lines": [
"root:x:0:0:root:/root:/bin/bash",
"operator:x:11:0:operator:/root:/sbin/nologin"
]
},
{
"_ansible_ignore_errors": null,
"_ansible_item_label": "nginx",
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "grep nginx /etc/passwd|cat",
"delta": "0:00:00.004500",
"end": "2020-04-19 15:18:19.714496",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "grep nginx /etc/passwd|cat",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": "nginx",
"rc": 0,
"start": "2020-04-19 15:18:19.709996",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
]
}
}
TASK [show users.results] *******************************************************************************************************************************************************************
ok: [vagrant1] => {
"msg": [
{
"_ansible_ignore_errors": null,
"_ansible_item_label": "vagrant",
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "grep vagrant /etc/passwd|cat",
"delta": "0:00:00.004695",
"end": "2020-04-19 15:18:19.129083",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "grep vagrant /etc/passwd|cat",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": "vagrant",
"rc": 0,
"start": "2020-04-19 15:18:19.124388",
"stderr": "",
"stderr_lines": [],
"stdout": "vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash",
"stdout_lines": [
"vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash"
]
},
{
"_ansible_ignore_errors": null,
"_ansible_item_label": "root",
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "grep root /etc/passwd|cat",
"delta": "0:00:00.004695",
"end": "2020-04-19 15:18:19.421598",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "grep root /etc/passwd|cat",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": "root",
"rc": 0,
"start": "2020-04-19 15:18:19.416903",
"stderr": "",
"stderr_lines": [],
"stdout": "root:x:0:0:root:/root:/bin/bash\noperator:x:11:0:operator:/root:/sbin/nologin",
"stdout_lines": [
"root:x:0:0:root:/root:/bin/bash",
"operator:x:11:0:operator:/root:/sbin/nologin"
]
},
{
"_ansible_ignore_errors": null,
"_ansible_item_label": "nginx",
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "grep nginx /etc/passwd|cat",
"delta": "0:00:00.004500",
"end": "2020-04-19 15:18:19.714496",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "grep nginx /etc/passwd|cat",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": "nginx",
"rc": 0,
"start": "2020-04-19 15:18:19.709996",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
]
}
TASK [define userss by set_fact] ************************************************************************************************************************************************************
ok: [vagrant1] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2020-04-19 15:18:19.129083', '_ansible_no_log': False, u'stdout': u'vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash', u'cmd': u'grep vagrant /etc/passwd|cat', u'rc': 0, 'item': u'vagrant', u'delta': u'0:00:00.004695', '_ansible_item_label': u'vagrant', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': True, u'_raw_params': u'grep vagrant /etc/passwd|cat', u'removes': None, u'argv': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash'], u'start': u'2020-04-19 15:18:19.124388', '_ansible_ignore_errors': None, 'failed': False})
ok: [vagrant1] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2020-04-19 15:18:19.421598', '_ansible_no_log': False, u'stdout': u'root:x:0:0:root:/root:/bin/bash\noperator:x:11:0:operator:/root:/sbin/nologin', u'cmd': u'grep root /etc/passwd|cat', u'rc': 0, 'item': u'root', u'delta': u'0:00:00.004695', '_ansible_item_label': u'root', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': True, u'_raw_params': u'grep root /etc/passwd|cat', u'removes': None, u'argv': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'root:x:0:0:root:/root:/bin/bash', u'operator:x:11:0:operator:/root:/sbin/nologin'], u'start': u'2020-04-19 15:18:19.416903', '_ansible_ignore_errors': None, 'failed': False})
ok: [vagrant1] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2020-04-19 15:18:19.714496', '_ansible_no_log': False, u'stdout': u'', u'cmd': u'grep nginx /etc/passwd|cat', u'rc': 0, 'item': u'nginx', u'delta': u'0:00:00.004500', '_ansible_item_label': u'nginx', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': True, u'_raw_params': u'grep nginx /etc/passwd|cat', u'removes': None, u'argv': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [], u'start': u'2020-04-19 15:18:19.709996', '_ansible_ignore_errors': None, 'failed': False})
TASK [print userss] *************************************************************************************************************************************************************************
ok: [vagrant1] => {
"msg": [
"vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash",
"root:x:0:0:root:/root:/bin/bash",
"operator:x:11:0:operator:/root:/sbin/nologin"
]
}
TASK [print userss one by one] **************************************************************************************************************************************************************
ok: [vagrant1] => (item=vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash) => {
"msg": "vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash"
}
ok: [vagrant1] => (item=root:x:0:0:root:/root:/bin/bash) => {
"msg": "root:x:0:0:root:/root:/bin/bash"
}
ok: [vagrant1] => (item=operator:x:11:0:operator:/root:/sbin/nologin) => {
"msg": "operator:x:11:0:operator:/root:/sbin/nologin"
}
TASK [print part of userss one by one] ******************************************************************************************************************************************************
ok: [vagrant1] => (item=vagrant:x:1000:1000:vagrant:/home/vagrant:/bin/bash) => {
"msg": "/bin/bash"
}
ok: [vagrant1] => (item=root:x:0:0:root:/root:/bin/bash) => {
"msg": "/bin/bash"
}
ok: [vagrant1] => (item=operator:x:11:0:operator:/root:/sbin/nologin) => {
"msg": "/sbin/nologin"
}
其实上个示例,已经提到了set_fact,因为set_fact配合register可以实现一些重要和灵活的功能。
tasks:
- name: define a var1
shell: "whoami"
register: whoami
- debug:
msg: "whoami: {{ whoami }}"
- debug:
msg: "whoami.stdout: {{whoami.stdout}}"
- name: define a var by set_fact
set_fact:
whoami: "{{ whoami.stdout }}"
- name: show a var after defined by set_fact
debug:
msg: "{{ whoami }}"
使用这种方式,会简化变量的调用。
这个功能只有通过set_fact可以显示,在好多场景都会用到,尤其是你不知道自己注册的变量有多少个元素,而且配合register可以大大简化变量的后续调用和重新格式化。其实示例1.2的示例代码已经用了这种方式:
vars:
userss: []
- name: define userss by set_fact
set_fact:
userss: "{{userss +item.stdout_lines}}"
with_list: "{{ users.results }}"
- name: print userss
debug:
msg: "{{ userss }}"
- name: print userss one by one
debug:
msg: "{{ item }}"
with_list: "{{ userss}}"
- name: print part of userss one by one
debug:
msg: "{{ item.split(':')[6] }}"
with_list: "{{ userss}}"
尤其要注意,循环给list变量添加元素的时候,这个变量要已经定义过了,才可以循环添加元素。最后print part的时候,在ansible中调用了python的字符串拆分函数,对遍历到的每行元素进行拆分,获取我们最需要的字段。 先组合字符串,再拆分字符串,会简化整体playbook,避免使用难以理解容易出错的嵌套循环。
完整的示例,可以看这里: https://github.com/byygyy/ansible-best-practice/blob/master/test-vars-define.yml