运维箴言:重启试试
写在前面
今天和小伙伴分享使用lookup插件模板化外部数据
博文内容比较简单
主要介绍的常用lookup插件和对应的Demo
外部数据如何代替cat等通过lookup插件读取
理解不足小伙伴帮忙指正
食用方式:了解Ansible基础语法
运维箴言:重启试试
lookup插件 lookup 插件是 Jinja2 模板化语言的 Ansible 扩展。这些插件使 Ansible 能够使用外部来源的数据,如文件和Shell 环境
。
默认的Ansible安装中有几十个可用的插件。ansible-doc-t lookup -l
,获取可用查找插件的完整列表。
1 2 3 4 5 6 [student@workstation data-filters]$ 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
命令。我们随便看一个模块
1 2 3 4 5 6 7 8 9 10 11 12 ┌──[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变量的值,顺便研究下代码怎么写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$cat /usr/lib/python2.7/site-packages/ansible/plugins/lookup/vars.py 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): 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来测试下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 --- - 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 ┌──[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插件获取指定文件的内容,编写剧本
1 2 3 4 5 6 7 - name: lookup Demo hosts: master vars: hosts: "{{ lookup('file', '/etc/hosts')}} " tasks: - debug: var: hosts
模拟执行剧本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ┌──[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 插件中包含多个文件名: ```yaml - name: lookup Demo hosts: master vars: issue: "{{ lookup( 'file','/etc/hosts','/etc/issue')}}" tasks: - debug: var: issue
在Ansible 2.5
和更高版本中,可以使用query
函数,而不是 lookup
来调用查找插件
。两者之间的区别在于,query
始终会返回⼀个更容易解析和使用的列表
,而不是返回逗号分隔的值
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ┌──[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] └─$
1 2 3 4 5 6 7 - name: query hosts: master vars: param: "{{ query('file','/etc/issue','/etc/hosts')}} " tasks: - debug: var: param
那这里有一个问题,lookup获取文件的内容适控制节点,还是被控节点,实际上是控制节点
读取文件的内容 file 插件
允许 Ansible
将本地文件的内容加载到变量。来看一个传递SSH密钥的Demo
1 2 3 4 5 6 ┌──[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] └─$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ┌──[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]-----+
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ┌──[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] └─$
1 2 3 4 5 6 ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$ls | grep key fred.key fred.key.pub naoko.key naoko.key.pub
1 2 3 4 5 6 7 8 9 10 11 12 13 - 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 }} "
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ┌──[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
1 2 3 4 5 6 7 8 ┌──[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] └─$
对于公钥的获取,也可以直接通过变量拼接,不使用运算符。
1 key: "{{ lookup('file', '{{ item }}.key.pub')}}"
如果文件是JSON 或 YAML
格式,可以使用from_yaml 或 from_json
过滤器将其解析为正确结构化的数据:
我们读取一个pod资源文件试试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 --- - 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: {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 ┌──[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加速器设置
1 2 3 4 5 6 7 8 9 10 11 12 13 ┌──[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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ┌──[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格式文件特定参数值。
1 2 3 4 5 6 7 8 --- - 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' ) }}
1 2 3 4 5 6 7 8 9 10 11 12 13 ┌──[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 模 板,并在应用之前评估该模板。
1 2 ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$echo "hello {{ name }}" > hello.j2
1 2 3 4 5 6 7 8 9 --- - name: template Demo hosts: 192.168 .26 .82 vars: name: liruilong tasks: - name: mes deml debug: var: lookup('template', 'hello.j2' )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ┌──[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到主机中时,此功能很有用。
1 2 3 4 5 6 7 8 9 10 --- - 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 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 插件
将该命令的输出拆分为行。
1 2 3 4 5 6 7 8 9 10 11 --- - 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/')
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ┌──[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
看一个简单的
1 2 3 4 5 6 7 8 9 10 11 ┌──[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
插件,返回逗号分隔的文件名清单。
1 2 3 4 5 ┌──[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
插件,强制返回文件列表值。
1 2 3 4 5 6 7 8 9 ┌──[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 获取内容:
1 2 3 4 5 6 ┌──[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 选项来提供对象类型:
1 2 3 4 5 6 - 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 集群。
1 2 3 4 5 6 7 8 9 10 11 12 - 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还可以从数据库中获取信息。
1 2 ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$ansible -doc -t lookup etcd
1 2 3 4 5 ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$ansible master -m debug -a "msg={{ lookup('etcd', 'foo')}} " 192.168.26.81 | SUCCESS => { "msg" : "" }
1 2 3 4 5 6 7 8 9 - 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插件可用于创建用户密码,并保存在文件中。、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$ansible 192.168.26.82 -m user -a "name=liruilong password={{ lookup('password','password-liruilong chars=digits lengt h=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-liruilong 747437 salt=Uy3I0UCN ┌──[root@vms81.liruilongs.github.io]-[~/ansible] └─$ssh liruilong@192.168.26.82 liruilong@192.168.26.82's password: [liruilong@vms82 ~]$
处理liikup错误 大多数 Ansible 插件可在失败时中止 Ansible Playbook
,但是,lookup 功能将执行委托给其它插件,这些插件可能不需要在失败时中止 Ansible Playbook。
1 2 3 4 5 6 - 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 插件会以静默方式忽略错误,并返回空字符串(或空列表)
实战 本地生成密码远程批量创建用户
读取文件创建用户
1 2 3 4 5 $ cat users.txt jonfoo janebar philbaz $
编写剧本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ 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') }} " $
1 2 3 4 5 6 7 8 9 10 11 12 $ 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
1 2 3 4 $ ls credentials/* | xargs cat 4qj2fAR6_ FrQRx7XR4 DgJoh1e7:
博文参考
《Red Hat Ansible Engine 2.8 DO447》