写点什么

Ansible 如何使用 lookup 插件模板化外部数据

作者:山河已无恙
  • 2022 年 9 月 10 日
    内蒙古
  • 本文字数:15629 字

    阅读完需:约 51 分钟

写在前面



  • 今天和小伙伴分享使用 lookup 插件模板化外部数据

  • 博文内容比较简单

  • 主要介绍的常用 lookup 插件和对应的 Demo

  • 外部数据如何代替 cat 等通过 lookup 插件读取

  • 理解不足小伙伴帮忙指正

  • 食用方式:了解 Ansible 基础语法


运维箴言:重启试试



lookup 插件

lookup 插件是 Jinja2 模板化语言的 Ansible 扩展。这些插件使 Ansible 能够使用外部来源的数据,如文件和Shell 环境


默认的 Ansible 安装中有几十个可用的插件。ansible-doc-t lookup -l,获取可用查找插件的完整列表。


[student@workstation data-filters]$ ansible-doc -t lookup -laws_account_attribute Look up AWS account attributesaws_secret            Look up secrets stored in AWS Secrets Manageraws_service_ip_ranges Look up the IP ranges for services provided in AWS such as EC2 and S3aws_ssm               Get the value for a SSM parameter or all parameters under a pathcartesian             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 CommunityOPTIONS (= 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, AnsibleUndefinedVariablefrom ansible.module_utils.six import string_typesfrom 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  -CPLAY [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.yamlPLAY [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.keyGenerating 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.ioThe 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.keyGenerating 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.ioThe 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 keyfred.keyfred.key.pubnaoko.keynaoko.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 iduid=1001(fred) gid=1001(fred) 组=1001(fred)┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ssh -i naoko.key  naoko@vms82.liruilongs.github.io iduid=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: v1kind: Podmetadata: creationTimestamp: null labels: run: pod-static name: pod-static namespeace: defaultspec: containers: - image: nginx imagePullPolicy: IfNotPresent name: pod-demo resources: {} dnsPolicy: ClusterFirst restartPolicy: Alwaysstatus: {}
复制代码


┌──[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] ********************************************************************************
TASK [Gathering Facts] ******************************************************************************ok: [192.168.26.82]
TASK [mes deml] *************************************************************************************ok: [192.168.26.82] => { "lookup('template', 'hello.j2')": "hello liruilong\n"}
PLAY RECAP ******************************************************************************************192.168.26.82 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
复制代码

读取控制节点上的环境变量

env 插件查询控制节点环境变量。当控制主机是容器化的应用程序,并且将环境变量注入 configmap 和 secret 到主机中时,此功能很有用。


---- name: lookup or query play  hosts: 192.168.26.82  tasks:    - name: show env LANG      debug:        var: lookup('env', 'LANG')    - name: show env      debug:        var: ansible_env
复制代码



PLAY [lookup or query play] ********************************************************************************************
TASK [Gathering Facts] *************************************************************************************************ok: [192.168.26.82]
TASK [show env LANG] ***************************************************************************************************ok: [192.168.26.82] => { "lookup('env', 'LANG')": "zh_CN.UTF-8"}
TASK [show env] ********************************************************************************************************ok: [192.168.26.82] => { "ansible_env": { "HOME": "/root", "LANG": "zh_CN.UTF-8", "LESSOPEN": "||/usr/bin/lesspipe.sh %s", "LOGNAME": "root", "LS_COLORS": "rs=0:di=38;5;27:ln=38;5;51:mh=44;38;5;15:pi=40;38;5;11:so=38;5;13:do=38;5;5:bd=48;5;232;38;5;11:cd=48;5;232;38;5;3:or=48;5;232;38;5;9:mi=05;48;5;232;38;5;15:su=48;5;196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;10;38;5;21:st=48;5;21;38;5;15:ex=38;5;34:*.tar=38;5;9:*.tgz=38;5;9:*.arc=38;5;9:*.arj=38;5;9:*.taz=38;5;9:*.lha=38;5;9:*.lz4=38;5;9:*.lzh=38;5;9:*.lzma=38;5;9:*.tlz=38;5;9:*.txz=38;5;9:*.tzo=38;5;9:*.t7z=38;5;9:*.zip=38;5;9:*.z=38;5;9:*.Z=38;5;9:*.dz=38;5;9:*.gz=38;5;9:*.lrz=38;5;9:*.lz=38;5;9:*.lzo=38;5;9:*.xz=38;5;9:*.bz2=38;5;9:*.bz=38;5;9:*.tbz=38;5;9:*.tbz2=38;5;9:*.tz=38;5;9:*.deb=38;5;9:*.rpm=38;5;9:*.jar=38;5;9:*.war=38;5;9:*.ear=38;5;9:*.sar=38;5;9:*.rar=38;5;9:*.alz=38;5;9:*.ace=38;5;9:*.zoo=38;5;9:*.cpio=38;5;9:*.7z=38;5;9:*.rz=38;5;9:*.cab=38;5;9:*.jpg=38;5;13:*.jpeg=38;5;13:*.gif=38;5;13:*.bmp=38;5;13:*.pbm=38;5;13:*.pgm=38;5;13:*.ppm=38;5;13:*.tga=38;5;13:*.xbm=38;5;13:*.xpm=38;5;13:*.tif=38;5;13:*.tiff=38;5;13:*.png=38;5;13:*.svg=38;5;13:*.svgz=38;5;13:*.mng=38;5;13:*.pcx=38;5;13:*.mov=38;5;13:*.mpg=38;5;13:*.mpeg=38;5;13:*.m2v=38;5;13:*.mkv=38;5;13:*.webm=38;5;13:*.ogm=38;5;13:*.mp4=38;5;13:*.m4v=38;5;13:*.mp4v=38;5;13:*.vob=38;5;13:*.qt=38;5;13:*.nuv=38;5;13:*.wmv=38;5;13:*.asf=38;5;13:*.rm=38;5;13:*.rmvb=38;5;13:*.flc=38;5;13:*.avi=38;5;13:*.fli=38;5;13:*.flv=38;5;13:*.gl=38;5;13:*.dl=38;5;13:*.xcf=38;5;13:*.xwd=38;5;13:*.yuv=38;5;13:*.cgm=38;5;13:*.emf=38;5;13:*.axv=38;5;13:*.anx=38;5;13:*.ogv=38;5;13:*.ogx=38;5;13:*.aac=38;5;45:*.au=38;5;45:*.flac=38;5;45:*.mid=38;5;45:*.midi=38;5;45:*.mka=38;5;45:*.mp3=38;5;45:*.mpc=38;5;45:*.ogg=38;5;45:*.ra=38;5;45:*.wav=38;5;45:*.axa=38;5;45:*.oga=38;5;45:*.spx=38;5;45:*.xspf=38;5;45:", "MAIL": "/var/mail/root", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin", "PWD": "/root", "SHELL": "/bin/bash", "SHLVL": "2", "SSH_CLIENT": "192.168.26.81 43056 22", "SSH_CONNECTION": "192.168.26.81 43056 192.168.26.82 22", "SSH_TTY": "/dev/pts/0", "TERM": "xterm-256color", "USER": "root", "XDG_RUNTIME_DIR": "/run/user/0", "XDG_SESSION_ID": "2", "_": "/usr/bin/python" }}
PLAY RECAP *************************************************************************************************************192.168.26.82 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
复制代码

读取控制节点执行命令输出

pipe lines插件都在Ansible控制节点上运行命令,并返回输出pipe 插件返回命令生成的原始输出,lines 插件将该命令的输出拆分为行。


---- name: pipe & lines demo  hosts: 192.168.26.82  tasks:    - name: pipe demo      debug:        var: lookup('pipe' , 'pwd','uname -a','ls -l k8s-volume-create/')    - name: lines demo      debug:        var: lookup('lines', 'pwd','uname -a','ls -l k8s-volume-create/')
复制代码


┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ansible-playbook pipe_demo.yaml
PLAY [pipe & lines demo] ****************************************************************************
TASK [Gathering Facts] ******************************************************************************ok: [192.168.26.82]
TASK [pipe demo] ************************************************************************************ok: [192.168.26.82] => { "lookup('pipe' , 'pwd','uname -a','ls -l k8s-volume-create/')": "/root/ansible,Linux vms81.liruilongs.github.io 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux,总用量 40\ndrwxr-xr-x 2 root root 135 12月 1 19:54 nfsdy\n-rw-r--r-- 1 root root 442 12月 1 23:04 pod_storageclass.yaml\n-rw-r--r-- 1 root root 438 11月 27 17:14 PodVolumeHostPath.yaml\n-rw-r--r-- 1 root root 478 11月 28 11:10 podvolumenfs.yaml\n-rw-r--r-- 1 root root 695 11月 27 16:15 pod_volume_r.yaml\n-rw-r--r-- 1 root root 206 11月 28 17:17 pod_volumes-pvc.yaml\n-rw-r--r-- 1 root root 442 11 月 28 17:43 pod_volumespvc.yaml\n-rw-r--r-- 1 root root 615 11月 27 15:51 pod_volumes.yaml\n-rw-r--r-- 1 root root 646 11月 27 15:28 pod_volume.yaml\n-rw-r--r-- 1 root root 330 11月 28 17:18 pod_volunms-pv.yaml\n-rw-r--r-- 1 root root 199 12月 1 20:15 pvc_nfs.yaml"}
TASK [lines demo] ***********************************************************************************ok: [192.168.26.82] => { "lookup('lines', 'pwd','uname -a','ls -l k8s-volume-create/')": "/root/ansible,Linux vms81.liruilongs.github.io 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux,总用量 40,drwxr-xr-x 2 root root 135 12月 1 19:54 nfsdy,-rw-r--r-- 1 root root 442 12月 1 23:04 pod_storageclass.yaml,-rw-r--r-- 1 root root 438 11月 27 17:14 PodVolumeHostPath.yaml,-rw-r--r-- 1 root root 478 11月 28 11:10 podvolumenfs.yaml,-rw-r--r-- 1 root root 695 11月 27 16:15 pod_volume_r.yaml,-rw-r--r-- 1 root root 206 11月 28 17:17 pod_volumes-pvc.yaml,-rw-r--r-- 1 root root 442 11月 28 17:43 pod_volumespvc.yaml,-rw-r--r-- 1 root root 615 11月 27 15:51 pod_volumes.yaml,-rw-r--r-- 1 root root 646 11月 27 15:28 pod_volume.yaml,-rw-r--r-- 1 root root 330 11月 28 17:18 pod_volunms-pv.yaml,-rw-r--r-- 1 root root 199 12月 1 20:15 pvc_nfs.yaml"}
PLAY RECAP ******************************************************************************************192.168.26.82 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
复制代码


看一个简单的


┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ansible master -m debug -a "msg={{ query('lines', 'ls /etc/host*')}}"192.168.26.81 | SUCCESS => {    "msg": [        "/etc/host.conf",        "/etc/hostname",        "/etc/hosts",        "/etc/hosts.allow",        "/etc/hosts.deny"    ]}
复制代码


lookup使用fileglob插件,返回逗号分隔的文件名清单。


┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ansible master -m debug -a "msg={{ lookup('fileglob', '/etc/hosts*') }}"192.168.26.81 | SUCCESS => {    "msg": "/etc/hosts,/etc/hosts.allow,/etc/hosts.deny"}
复制代码


query使用fileglob插件,强制返回文件列表值。


┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ansible master -m debug -a "msg={{ query('fileglob', '/etc/hosts*') }}"192.168.26.81 | SUCCESS => {    "msg": [        "/etc/hosts",        "/etc/hosts.allow",        "/etc/hosts.deny"    ]}
复制代码

从 URL 获取内容

url 插件从 URL 获取内容:


┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ansible master -m debug -a "msg={{ query('url', 'https://liruilongs.github.io/') }}"192.168.26.81 | SUCCESS => {    "msg": [        "<!doctype html>",        "<html lang=\"zh\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\"><meta><title>山河已无恙</title><link rel=\"manifest\" href=\"/manifest.json\"><meta name=\"application-name\" content=\"山河已无恙\"><meta name=\"msapplication-TileImage\" content=\"https://cdn.jsdelivr.net/gh/removeif/removeif-demo@latest/img/favicon.png\"><meta name=\"apple-mobile-web-app-capable\" content=\"yes\"><meta name=\"apple-mobile-web-app-title\" content=\"山河已无恙\"><meta name=\"apple-mobile-web-app-status-bar-style\" content=\"default\"><meta property=\"og:type\" content=\"blog\"><meta property=\"og:title\" content=\"山河已无恙\"><meta property=\"og:url\" ....
复制代码


同时具有许多选项用于控制身份验证、web 代理或将结果拆分为行等。

从 Kubernetes API 获取信息

k8s 插件通过 openshift Python 模块提供对 Kubernetes API 的完全访问权限。必须使用 kind 选项来提供对象类型:


- name: k8s demo  hosts: 192.168.26.81  tasks:    - name: debug demo k8s      debug:        var: lookup('k8s',kind='pod',namespect='kube-system',resource_name='kube-proxy')
复制代码


注意:k8s 插件是一个 lookup 插件,主要用途是从 Kubernetes 集群提取信息,而不是对其进行更新。使用 k8s 模块来管理 Kubernetes 集群。


- name: Fetch all deployments   set_fact:     deployments: "{{ lookup(k8s',kind='Deployment)}"- name: Fetch all deployments in a namespace   set_fact:     deployments: "{{ lookup(k8s',kind='Deployment',namespace='testing)}}"- name: Fetch a specific deployment by name   set_fact:     deployments: {{ lookup(k8s',kind='Deployment',namespace='testing, resource_name='elastic)}}- name: Fetch with label selector   set_fact:     service: "{{ lookup('k8s',kind='Service',label_ selector='app=galaxy') }}"
复制代码


这个 Demo 有问题,之后需要在看下


查询插件 etcd,redis,mongodb 还可以从数据库中获取信息。


┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ansible-doc -t lookup etcd
复制代码


┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ansible master  -m debug -a "msg={{ lookup('etcd', 'foo')}} "192.168.26.81 | SUCCESS => {    "msg": ""}
复制代码


- name: a value from a locally running etcd  debug:     msg: "{{ lookup('etcd', 'foo/bar')}"- name: "values from multiple folders on a locally running etcd"  debug:     msg: "{{ lookup('etcd', 'foo','bar','baz')}}"- name: "since Ansible 2.5 you can set server options inline"  debug:     msg: "{{ lookup('etcd','foo', version='v2', url='http://192.168.0.27') }}"
复制代码

password 插件生成密码

password 插件可用于创建用户密码,并保存在文件中。、


┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ansible 192.168.26.82 -m user -a "name=liruilong password={{ lookup('password','password-liruilong chars=digits length=6 encrypt=sha512_crypt') }}"192.168.26.82 | CHANGED => {    "ansible_facts": {        "discovered_interpreter_python": "/usr/bin/python"    },    "changed": true,    "comment": "",    "create_home": true,    "group": 1003,    "home": "/home/liruilong",    "name": "liruilong",    "password": "NOT_LOGGING_PASSWORD",    "shell": "/bin/bash",    "state": "present",    "system": false,    "uid": 1003}┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$cat password-liruilong747437 salt=Uy3I0UCN┌──[root@vms81.liruilongs.github.io]-[~/ansible]└─$ssh liruilong@192.168.26.82liruilong@192.168.26.82's password:[liruilong@vms82 ~]$
复制代码

处理 liikup 错误

大多数 Ansible 插件可在失败时中止 Ansible Playbook,但是,lookup 功能将执行委托给其它插件,这些插件可能不需要在失败时中止 Ansible Playbook。


- name: error demo  hosts: 192.168.26.81  tasks:    - name: debug demo error      debug:        var: lookup('file', '/etc/passwd',error='warn') | default("Default file conten")
复制代码


lookup 插件接受 error 参数:


  • error 选项的默认值为 strict,如果基础脚本失败,lookup 插件会导致严重错误。

  • error 选项可以设置为 warn,则 lookup 插件在基础脚本失败时记录警告并返回空字符串(或空列表)

  • error 选项可以设置为 ignore,则 lookup 插件会以静默方式忽略错误,并返回空字符串(或空列表)

实战

本地生成密码远程批量创建用户


读取文件创建用户


$ cat users.txtjonfoojanebarphilbaz$
复制代码


编写剧本


$ cat site.yml- name: Populate users from file  hosts: all  gather_facts: no  tasks:    - name: Create remote user      vars:        password: "{{ lookup('password', 'credentials/' + item + ' length=9') }}"      user:        name: "{{ item }}"        password: "{{ password | password_hash('sha512') }}"        update_password: on_create        state: present      loop: "{{ query('lines','cat users.txt') }}"$
复制代码


$ ansible-playbook  site.yml
PLAY [Populate users from file] ******************************************************************************
TASK [Create remote user] ************************************************************************************changed: [serverf.lab.example.com] => (item=jonfoo)changed: [serverf.lab.example.com] => (item=janebar)changed: [serverf.lab.example.com] => (item=philbaz)
PLAY RECAP ***************************************************************************************************serverf.lab.example.com : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
复制代码


$ ls credentials/* | xargs cat4qj2fAR6_FrQRx7XR4DgJoh1e7:
复制代码

博文参考



《Red Hat Ansible Engine 2.8 DO447》


发布于: 2022 年 09 月 10 日阅读数: 3
用户头像

InfoQ写作平台签约作者,RHCE、CKA认证 2022.01.04 加入

Java 后端一枚,技术不高,前端、Shell、Python 也可以写一点.纯种屌丝,不热爱生活,热爱学习,热爱工作,喜欢一直忙,不闲着。喜欢篆刻,喜欢吃好吃的,喜欢吃饱了晒太阳。

评论

发布
暂无评论
Ansible如何使用lookup插件模板化外部数据_ansible_山河已无恙_InfoQ写作社区