Ansible如何使用lookup插件模板化外部数据
Posted 山河已无恙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible如何使用lookup插件模板化外部数据相关的知识,希望对你有一定的参考价值。
写在前面
- 今天和小伙伴分享使用lookup插件模板化外部数据
- 博文内容比较简单
- 主要介绍的常用lookup插件和对应的Demo
- 外部数据如何代替cat等通过lookup插件读取
- 理解不足小伙伴帮忙指正
- 食用方式:了解Ansible基础语法
运维箴言:重启试试
lookup插件
lookup 插件是 Jinja2 模板化语言的 Ansible 扩展。这些插件使 Ansible 能够使用外部来源的数据,如文件和Shell 环境
。
默认的Ansible安装中有几十个可用的插件。ansible-doc-t lookup -l
,获取可用查找插件的完整列表。
[root@vms81.liruilongs.github.io]$ ansible-doc -t lookup -l
aws_account_attribute Look up AWS account attributes
aws_secret Look up secrets stored in AWS Secrets Manager
aws_service_ip_ranges Look up the IP ranges for services provided in AWS such as EC2 and S3
aws_ssm Get the value for a SSM parameter or all parameters under a path
cartesian returns the cartesian product of lists
可以运行 ansible-doc -t lookup PLUGIN_NAME
命令。我们随便看一个模块
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ansible-doc -t lookup vars
> VARS (/usr/lib/python2.7/site-packages/ansible/plugins/lookup/vars.py)
Retrieves the value of an Ansible variable.
* This module is maintained by The Ansible Community
OPTIONS (= is mandatory):
= _terms
The variable names to look up.
......
嗯,获取一个Ansible变量的值,顺便研究下代码怎么写
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$cat /usr/lib/python2.7/site-packages/ansible/plugins/lookup/vars.py
# (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
## 一些模块的说明
DOCUMENTATION = """
lookup: vars
author: Ansible Core
version_added: "2.5"
short_description: Lookup templated value of variables
description:
- Retrieves the value of an Ansible variable.
options:
_terms:
description: The variable names to look up.
required: True
default:
description:
- What to return if a variable is undefined.
- If no default is set, it will result in an error if any of the variables is undefined.
"""
## 模块使用方法
。。。。
RETURN = """
_value:
description:
- value of the variables requested.
"""
from ansible.errors import AnsibleError, AnsibleUndefinedVariable
from ansible.module_utils.six import string_types
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
##只有一个方法,接收所有参数
def run(self, terms, variables=None, **kwargs):
# variables不为none的话
if variables is not None:
self._templar.available_variables = variables
myvars = getattr(self._templar, '_available_variables', )
self.set_options(direct=kwargs)
default = self.get_option('default')
ret = []
for term in terms:
if not isinstance(term, string_types):
raise AnsibleError('Invalid setting identifier, "%s" is not a string, its a %s' % (term, type(term)))
try:
try:
value = myvars[term]
except KeyError:
try:
value = myvars['hostvars'][myvars['inventory_hostname']][term]
except KeyError:
raise AnsibleUndefinedVariable('No variable found with this name: %s' % term)
ret.append(self._templar.template(value, fail_on_undefined=True))
except AnsibleUndefinedVariable:
if default is not None:
ret.append(default)
else:
raise
return ret
可以看到,和回调插件的编写方式类似,继承基类,重写方法。主要用于根据变量名获取当前剧本中的变量,变量名可以是经过运行的变量,我编写一个Demo来测试下
---
- name: vars Demo
hosts: master
tasks:
- name: Show value of 'variablename'
debug:
msg: " lookup('vars', 'variabl' + myvar)"
vars:
variablename: hello
myvar: ename
- name: Show default empty since i dont have 'variablnotename'
debug:
msg: " lookup('vars', 'variabl' + myvar, default='变量不存在')"
vars:
variablename: hello
myvar: notename
- name: Produce an error since i dont have 'variablnotename'
debug:
msg: " lookup('vars', 'variabl' + myvar)"
ignore_errors: True
vars:
variablename: hello
myvar: notename
- name: find several related variables
debug:
msg: " lookup('vars', 'ansible_play_hosts', 'ansible_play_batch', 'ansible_play_hosts_all') "
- name: alternate way to find some 'prefixed vars' in loop
debug:
msg: " lookup('vars', 'ansible_play_' + item) "
loop:
- hosts
- batch
- hosts_all
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ansible-playbook vars.yaml
PLAY [vars Demo] ****************************************************************
TASK [Gathering Facts] **********************************************************
ok: [192.168.26.81]
TASK [Show value of 'variablename'] *********************************************
ok: [192.168.26.81] =>
"msg": "hello"
TASK [Show default empty since i dont have 'variablnotename'] *******************
ok: [192.168.26.81] =>
"msg": "变量不存在"
TASK [Produce an error since i dont have 'variablnotename'] *********************
fatal: [192.168.26.81]: FAILED! => "msg": "The task includes an option with an undefined variable. The error was: No variable found with this name: variablnotename\\n\\nThe error appears to be in '/root/ansible/vars.yaml': line 19, column 5, but may\\nbe elsewhere in the file depending on the exact syntax problem.\\n\\nThe offending line appears to be:\\n\\n\\n - name: Produce an error since i dont have 'variablnotename'\\n ^ here\\n"
...ignoring
TASK [find several related variables] *******************************************
ok: [192.168.26.81] =>
"msg": [
[
"192.168.26.81"
],
[
"192.168.26.81"
],
[
"192.168.26.81"
]
]
TASK [alternate way to find some 'prefixed vars' in loop] ***********************
ok: [192.168.26.81] => (item=hosts) =>
"msg": [
"192.168.26.81"
]
ok: [192.168.26.81] => (item=batch) =>
"msg": [
"192.168.26.81"
]
ok: [192.168.26.81] => (item=hosts_all) =>
"msg": [
"192.168.26.81"
]
PLAY RECAP **********************************************************************
192.168.26.81 : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$
可以使用lookup和query来调用查找插件。使用方法与过滤器相似;指定函数的名称,并在括号中添加要调用的查找插件的名称以及该插件所需的所有参数。
调用lookup插件
可以使用两个 Jinja2 模板函数
(lookup 或 query
)中的一个来调用插件。
这两种方法都具有和过滤器非常相似的语法。指定函数的名称,并在圆括号中指定要调用的lookup
插件的名称和插件需要的任何参数。
通过lookup的file插件获取指定文件的内容,编写剧本
- name: lookup Demo
hosts: master
vars:
hosts: " lookup('file', '/etc/hosts')"
tasks:
- debug:
var: hosts
模拟执行剧本
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ansible-playbook jinja2.yaml -C
PLAY [lookup Demo] **********************************************************************************
TASK [Gathering Facts] ******************************************************************************ok: [192.168.26.81]
TASK [debug] ****************************************************************************************ok: [192.168.26.81] =>
"hosts": "127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4\\n::1 localhost localhost.localdomain localhost6 localhost6.localdomain6\\n192.168.26.81 vms81.liruilongs.github.io vms81\\n192.168.26.82 vms82.liruilongs.github.io vms82\\n192.168.26.83 vms83.liruilongs.github.io vms83"
PLAY RECAP ******************************************************************************************192.168.26.81 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
使用逗号分隔,可以在 file 插件中包含多个文件名:
- name: lookup Demo
hosts: master
vars:
issue: " lookup( 'file','/etc/hosts','/etc/issue')"
tasks:
- debug:
var: issue
在Ansible 2.5
和更高版本中,可以使用query
函数,而不是 lookup
来调用查找插件
。两者之间的区别在于,query
始终会返回⼀个更容易解析和使用的列表
,而不是返回逗号分隔的值
。
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ansible-playbook query.yaml
PLAY [query] **********************************************************************************
TASK [Gathering Facts] ************************************************************************
ok: [192.168.26.81]
TASK [debug] **********************************************************************************
ok: [192.168.26.81] =>
"param": [
"\\\\S\\nKernel \\\\r on an \\\\m\\n\\n192.168.26.81",
"127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4\\n::1 localhost localhost.localdomain localhost6 localhost6.localdomain6\\n192.168.26.81 vms81.liruilongs.github.io vms81\\n192.168.26.82 vms82.liruilongs.github.io vms82\\n192.168.26.83 vms83.liruilongs.github.io vms83"
]
PLAY RECAP ************************************************************************************
192.168.26.81 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$
- name: query
hosts: master
vars:
param: " query('file','/etc/issue','/etc/hosts')"
tasks:
- debug:
var: param
那这里有一个问题,lookup获取文件的内容适控制节点,还是被控节点,实际上是控制节点
读取文件的内容
file 插件
允许 Ansible
将本地文件的内容加载到变量。来看一个传递SSH密钥的Demo
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ssh root@vms82.liruilongs.github.io useradd fred
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ssh root@vms82.liruilongs.github.io useradd naoko
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ssh-keygen -N '' -f fred.key
Generating public/private rsa key pair.
Your identification has been saved in fred.key.
Your public key has been saved in fred.key.pub.
The key fingerprint is:
SHA256:AABygrfjKr2zllYikm0DCbxHaEvt/5fLwN6jY/OaXN8 root@vms81.liruilongs.github.io
The key's randomart image is:
+---[RSA 2048]----+
|*.=.. |
|+B.o . |
|+o=. . |
|oooo . |
| =... S |
|+ * ... |
|.= = .o .. |
|o * o=*+. . |
|.oo+ .*B=o. E |
+----[SHA256]-----+
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ssh-keygen -N '' -f naoko.key
Generating public/private rsa key pair.
Your identification has been saved in naoko.key.
Your public key has been saved in naoko.key.pub.
The key fingerprint is:
SHA256:UDtUESSooboZtIungph4VJoLa3mwVqekwp6wdoExwaI root@vms81.liruilongs.github.io
The key's randomart image is:
+---[RSA 2048]----+
|. .+o=o |
|.o . .o o |
|o .. o. o |
|E+. o . . |
|..=+ S |
|++++ . |
|BOO.+ |
|&@=+ |
|X*o |
+----[SHA256]-----+
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ls | grep key
fred.key
fred.key.pub
naoko.key
naoko.key.pub
- name: Add authorized keys
hosts: 192.168.26.82
vars:
users:
- fred
- naoko
tasks:
- name: Add keys
authorized_key:
user: " item "
key: " lookup('file',item + '.key.pub')"
loop: " users "
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ansible-playbook file_vars.yaml
PLAY [Add authorized keys] **************************************************************************
TASK [Gathering Facts] ******************************************************************************
ok: [192.168.26.82]
TASK [Add keys] *************************************************************************************
changed: [192.168.26.82] => (item=fred)
changed: [192.168.26.82] => (item=naoko)
PLAY RECAP ******************************************************************************************
192.168.26.82 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ssh -i fred.key fred@vms82.liruilongs.github.io id
uid=1001(fred) gid=1001(fred) 组=1001(fred)
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ssh -i naoko.key naoko@vms82.liruilongs.github.io id
uid=1002(naoko) gid=1002(naoko) 组=1002(naoko)
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$
对于公钥的获取,也可以直接通过变量拼接,不使用运算符。
key: " lookup('file', ' item .key.pub')"
如果文件是JSON 或 YAML
格式,可以使用from_yaml 或 from_json
过滤器将其解析为正确结构化的数据:
我们读取一个pod资源文件试试
---
- name: yaml to vars
hosts: 192.168.26.82
tasks:
- name: show yaml
debug:
var: " lookup('file', 'static-pod.yaml') | from_yaml"
---
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod-static
name: pod-static
namespeace: default
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: pod-demo
resources:
dnsPolicy: ClusterFirst
restartPolicy: Always
status:
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ansible-playbook file_yaml.yaml
PLAY [yaml to vars] *********************************************************************************
TASK [Gathering Facts] ******************************************************************************
ok: [192.168.26.82]
TASK [show yaml] ************************************************************************************
ok: [192.168.26.82] =>
" lookup('file', 'static-pod.yaml') | from_yaml":
"apiVersion": "v1",
"kind": "Pod",
"metadata":
"creationTimestamp": null,
"labels":
"run": "pod-static"
,
"name": "pod-static",
"namespeace": "default"
,
"spec":
"containers": [
"image": "nginx",
"imagePullPolicy": "IfNotPresent",
"name": "pod-demo",
"resources":
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always"
,
"status":
PLAY RECAP ******************************************************************************************
192.168.26.82 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
json也是一样的,我们来看一下,这是传递一个docker加速器设置
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$cat daemon.json
"registry-mirrors": ["https://2tefyfv7.mirror.aliyuncs.com"]
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$cat file_json.yaml
---
- name: json to vars
hosts: 192.168.26.82
tasks:
- debug:
var: lookup('file', 'daemon.json') | from_json
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ansible-playbook file_json.yaml
PLAY [json to vars] *********************************************************************************
TASK [Gathering Facts] ******************************************************************************
ok: [192.168.26.82]
TASK [debug] ****************************************************************************************
ok: [192.168.26.82] =>
"lookup('file', 'daemon.json') | from_json":
"registry-mirrors": [
"https://2tefyfv7.mirror.aliyuncs.com"
]
PLAY RECAP ******************************************************************************************
192.168.26.82 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ini插件查询控制节点ini格式文件特定参数值。
---
- name: lookup or query Play
hosts: 192.168.26.82
gather_facts: false
tasks:
- debug:
msg: >
first name in file /etc/foo. ini section liruilong is lookup('ini', 'first_name lest_name section=liruilong file=/etc/foo.ini')
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ansible-playbook file_ini.yaml
PLAY [lookup or query Play] ********************************************************************************************
TASK [debug] ***********************************************************************************************************
ok: [192.168.26.82] =>
"msg": "first name in file /etc/foo. ini section liruilong is []\\n"
PLAY RECAP *************************************************************************************************************
192.168.26.82 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
使用模板应用数据
与file
插件一样,template
插件也会返回文件的内容,不同之处在于,template
插件预期文件内容为 Jinja2 模
板,并在应用之前评估该模板。
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$echo "hello name " > hello.j2
---
- name: template Demo
hosts: 192.168.26.82
vars:
name: liruilong
tasks:
- name: mes deml
debug:
var: lookup('template', 'hello.j2')
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$ansible-playbook template_demo.yaml
[WARNING]: Found variable using reserved name: name
PLAY [template Demo] ***********************以上是关于Ansible如何使用lookup插件模板化外部数据的主要内容,如果未能解决你的问题,请参考以下文章
Ansible自动化运维Ansible变量之lookup生成变量方法
如何从 Ansible 中的 lookup() 模块的结果中删除换行符 '\n'?