微信公众号:运维开发故事,作者:姜总

前言

很多时候,某些场景下playbook的结果依赖于变量、fact或者是前一个任务的执行结果,或者有的时候,我们会基于上一个task执行返回的结果而决定如何执行后续的task。这个时候就需要用到条件判断。

条件语句在Ansible中的使用场景:

  • 在目标主机上定义了一个硬限制,比如:目标主机的发行版本必须是RedHat,才能执行该task;

  • 捕获一个命令的输出,根据命令输出结果的不同以触发不同的task;

  • 根据不同目标主机的facts,以定义不同的task;

  • 根据目标机的cpu或者memory的大小,对相关应用性能进行调优;

  • 用于判断某个服务的配置文件是否发生变更,以确定是否需要重启服务等。

下面就介绍一些常用的条件判断

when 关键字

1. when 关键字使用

在ansible中,when是条件判断的最常用关键字。如在安装包的时候,需要指定主机的操作系统类型,可以使用when语句来做判断。when关键字后面跟着的是python的表达式,在表达式中你能够使用任何的变量或者fact,当表达式的结果返回的是false,便会跳过本次的任务。

示例:

---
- name: install wget packagehosts: alltasks:- name: Install wgetyum:name: wgetstate: installedwhen: ansible_os_family == "RedHat"

2. when 配合比较运算符

以上示例,我们使用了"=="的比较运算符,在ansible中,还支持如下比较运算符:

  • ==:比较两个对象是否相等,相等则返回真。可用于比较字符串和数字

  • !=:比较两个对象是否不等,不等则为真。

  • :比较两个对象的大小,左边的值大于右边的值,则为真

  • <:比较两个对象的大小,左边的值小于右边的值,则为真

  • =:比较两个对象的大小,左边的值大于等于右边的值,则为真

  • <=:比较两个对象的大小,左边的值小于等于右边的值,则为真

如:

when: ansible_disibution == "CentOS"when: ansible_machine == "x86_64" when: max_memory <= 512

3. 逻辑运算符

  • and:逻辑与,当左边和右边两个表达式同时为真,则返回真

  • or:逻辑或,当左右和右边两个表达式任意一个为真,则返回真

  • not:逻辑否,对表达式取反

  • ():当一组表达式组合在一起,形成一个更大的表达式,组合内的所有表达式都是逻辑与的关系

# 逻辑与
when: ansible_disibution == "CentOS" and ansible_disibution_major_vsion == "7"# 逻辑或
when: ansible_disibution == "RedHat" or ansible_disibution == "Fedora"when:- ansible_disibution_vsion == "7.9"- ansible_kernel == "3.10.0-327.el7.x86_64"# 组合使用
when: => ( ansible_disibution == "RedHat" and ansible_disibution_major_vsion == "7" )or( ansible_disibution == "Fedora" and ansible_disibution_major_vsion == "28")

示例:

- name: uninstall and stop forewalldhosts: dbsrvstasks:- name: uninstall firewalldyum: pkg=firwalld state=absentwhen: ansible_disibution == "CentOS" and ansible_disibution_major_vsion == "7"tags: uninstall_firewalld- name: stop and disabled iptablesshell: systemctl stop firewalld.service && systemctl disable firewalld && systemctl stop iptables && systemctl disable iptableswhen: ansible_disibution == "CentOS" and ansible_disibution_major_vsion == "7"tags: stop_firewalld###
- name: restart httpd if postfix is runninghosts: dbsrvstasks:- name: get postfix serv statuscommand: /usr/bin/systemctl is-active postfixignore_errors: yesregister: result- name: restart apache httpd based on postfix statusservice:name: httpdstate: restartedwhen: result.rc == 0

tests 配合条件判断

通过条件语句判断tpath的路径是否存在

- hosts: dbsrvsvars:tpath: /ayunwSkytasks:- debug:msg: "file exist"when: tpath is exists

参数解释:

  • is exists: 用于路径存在时返回真

  • is not exists: 用于路径不存在时返回真

  • 也可以在整个条件表达式的前面使用not来取反
- hosts: dbsrvsvars:tpath: /ayunwSkytasks:- debug:msg: "file not exist"when: not tpath is exists

除了 exists 方式以外,还有其他的判断方式,如下:

判断变量
  • defined:判断变量是否已定义,已定义则返回真

  • undefined:判断变量是否未定义,未定义则返回真

  • none:判断变量的值是否为空,如果变量已定义且值为空,则返回真

- hosts: dbsrvsgather_facts: novars:tvar: "test"tvar1:tasks:- debug:msg: "tvar is defined"when: tvar is defined- debug:msg: "tvar2 is undefined"when: tvar2 is undefined- debug:msg: "tvar1 is none"when: tvar1 is none

判断执行结果

  • sucess或succeeded:通过任务执行结果返回的信息判断任务的执行状态,任务执行成功则返回true

  • failure或failed:任务执行失败则返回true

  • change或changed:任务执行状态为changed则返回true

  • skip或skipped:任务被跳过则返回true

- hosts: dbsrvsgather_facts: novars:doshell: truetasks:- shell: 'cat /ayunwSky/allenjol'when: doshellregister: resultignore_errors: true- debug:msg: "success"when: result is success- debug:msg: "failed"when: result is failure- debug:msg: "changed"when: result is change- debug:msg: "skip"when: result is skip

判断路径

  • file:判断指定路径是否为一个文件,是则为真

  • directory:判断指定路径是否为一个目录,是则为真

  • link:判断指定路径是否为一个软链接,是则为真

  • mount:判断指定路径是否为一个挂载点,是则为真

  • exists:判断指定路径是否存在,存在则为真

关于路径的所有判断均是判断主控端上的路径,而非被控端上的路径

- hosts: dbsrvsgather_facts: novars:tpath1: "/ayunwSky/allenjol"tpath2: "/ayunwSky"tasks:- debug:msg: "file"when: tpath1 is file- debug:msg: "directory"when: tpath2 is directory

判断字符串

  • lower:判断字符串中的所有字母是否都是小写,是则为真

  • upper:判断字符串中的所有字母是否都是大写,是则为真

- hosts: dbsrvsgather_facts: novars: s1: "ayunw"s2: "AYUNW"tasks:- debug:msg: "s1 is all lowercase"when: s1 is lower- debug:msg: "s2 is all uppercase"when: s2 is upper

判断整除

  • even:判断数值是否为偶数,是则为真

  • odd:判断数值是否为奇数,是则为真

  • divisibleby(n):判断是否可以整除指定的数值,是则为真

- hosts: dbsrvsgather_facts: novars: n1: 5n2: 10 n3: 20tasks:- debug: msg: "n1 is an even nber"when: n1 is even- debug:msg: "n2 is an odd nber"when: n2 is odd- debug:msg: "n3 can be divided exactly by"when: n3 is divisibleby(3)

其他 tests 方法

  1. version:对比两个版本号的大小,或者与指定的版本号进行对比,使用语法为vsion(“版本号”,“比较操作符”)

version中使用的比较运算符说明:

  • 大于:>, gt

  • 大于等于:>=, ge

  • 小于:<, lt

  • 小于等于:<=, le

  • 等于:=, ==, eq

  • 不等于:!=, <>, ne

- hosts: dbsrvsvars:v1: 1.2v2: 1.3tasks:- debug:msg: "v1 is greater than v2"when: v1 is vsion(v2,">")- debug:msg: "system vsion {{ ansible_distribution_vsion }} greater than 7.3"when: ansible_distribution_vsion is vsion("7.3","gt")
  1. superset: 判断一个list是不是另一个list的父集
- hosts: dbsrvsgather_facts: novars:a:- 3- 7b: [1,3,4,5,7,9]tasks:- debug:msg: "A is a subset of B"when: a is subset(b)- debug:msg: "B is the parent set of A"when: b is superset(a)
  1. in: 判断一个字符串是否存在于另一个字符串中,也可用于判断某个特定的值是否存在于列表中
- hosts: dbsrvsvars:supported_distros:- RedHat- CentOStasks:- debug:msg: "{{ ansible_distribution }} in supported_distros"when: ansible_distribution in supported_distros
  1. number: 判断对象是否为一个数字,是则为真
- hosts: dbsrvsgather_facts: novars:var1: 1var2: "1"var3: atasks:- debug:msg: "var1 is a number"when: var1 is number- debug:msg: "var2 is a string"when: var2 is string- debug:msg: "var3 is a string"when: var3 is string

条件判断与block

block

when做条件判断时,如果条件成立则执行对应的任务。但这就存在一个问题:当我们要使用同一个条件判断执行多个任务的时候,就意味着我们要在某一个任务下面都写一下when语句,而且判断条件完全一样。这种方式非常麻烦。Ansible提供了一种更好的方式来解决这个问题,即block。

在ansible中,使用block将多个任务进行组合,当作一个整体。我们可以对这一个整体做条件判断,当条件成立时,则执行块中的所有任务:

使用block注意事项:

  • 可以为block定义name

  • 可以直接对block使用when,但不能直接对block使用loop

- hosts: dbsrvstasks:- name: set /etc/resolv.conftemplate: src: resolv.conf.j2 dest: /etc/resolv.conf owner: root group: root mode: 0644- block:- name: ensure /etc/resolvconf/resolv.conf.d/base file for ubuntu 16.04template: src: resolv.conf.j2dest: /etc/resolvconf/resolv.conf.d/base- name: config dns for ubuntu 16.04template: src: resolv.conf.j2dest: /etc/resolv.confwhen: ansible_distribution == "Ubuntu" and ansible_distribution_major_version == "16" 

rescue

block除了能和when一起使用之外,还能作错误处理。这个时候就需要用到rescue关键字:

- hosts: dbsrvstasks:- block:- shell: 'ls /ayunwSky'rescue:- debug:msg: '/ayunwSky is not exists'

当block中的任务执行失败时,则运行rescue中的任务。如果block中的任务正常执行,则rescue的任务就不会被执行。如果block中有多个任务,则任何一个任务执行失败,都会执行rescue。block中可以定义多个任务,同样rescue当中也可以定义多个任务。

always

当block执行失败时,rescue中的任务才会被执行;而无论block执行成功还是失败,always中的任务都会被执行:

- hosts: dbsrvstasks:- block:- shell: 'ls /ayunwSky'rescue:- debug:msg: '/ayunwSky is not exists'always:- debug:msg: 'This task always executes'

条件判断与错误处理

fail模块

在shell中,可能会有这样的需求:当脚本执行至某个阶段时,需要对某个条件进行判断,如果条件成立,则立即终止脚本的运行。在shell中,可以直接调用"exit"即可执行退出。事实上,在playbook中也有类似的模块可以做这件事。即fail模块。

fail模块用于终止当前playbook的执行,通常与条件语句组合使用,当满足条件时,终止当前play的运行。

fail模块只有一个参数,即 msg:终止前打印出信息

# 使用fail模块中断playbook输出
- hosts: dbsrvstasks:- shell: echo "Just a test--error" register: result- fail:msg: "Conditions established,Interrupt running playbook"when: "'error' in result.stdout"- debug:msg: "Inever execute,Because the playbook has stopped"

failed_when

当fail和when组合使用的时候,还有一个更简单的写法,即failed_when,当满足某个条件时,ansible主动触发失败。

如果在command_result存在错误输出,且错误输出中,包含了FAILED字串,即返回失败状态:

- name: this command prints FAILED when it failscommand: /usr/bin/example-command -x -y -zregister: command_resultfailed_when: "'FAILED' in command_result.stderr"

直接通过fail模块和when条件语句:

- name: this command prints FAILED when it failscommand: /usr/bin/example-command -x -y -zregister: command_resultignore_errors: True- name: fail the play if the previous command did not succeedfail: msg="the command failed"when: " command_result.stderr and 'FAILED' in command_result.stderr"
  • ansible一旦执行返回失败,后续操作就会中止,所以failed_when通常可以用于满足某种条件时主动中止playbook运行的一种方式。

  • ansible默认处理错误的机制是遇到错误就停止执行。但有些时候,有些错误是计划之中的。我们希望忽略这些错误,以让playbook继续往下执行。此时可以使用ignore_errors忽略错误,从而让playbook继续往下执行。

changed_when

当我们控制一些远程主机执行某些任务时,当任务在远程主机上成功执行,状态发生更改时,会返回changed状态响应,状态未发生更改时,会返回OK状态响应,当任务被跳过时,会返回skipped状态响应。我们可以通过changed_when来手动更改changed响应状态

- shell: /usr/bin/billybass --mode="take me to the river"
register: bass_result
# 该条task执行以后,bass_result.rc的值不为2时,才会返回changed状态
changed_when: "bass_result.rc != 2"# this will never report 'changed' status
- shell: wall 'beep'# 当changed_when为false时,该条task在执行以后,永远不会返回changed状态changed_when: False

循环语句中使用条件语句

  1. 只打印大于 10 的值
tasks:- command: echo {{ item }}loop: [ 0, 2, 4, 6, 8, 10, 100, 130, 150 ]when: item > 10
  1. 确保将mariadb-server安装到根分区且根分区的可用空间要大于200M
- name: install nginx if enough space on rootyum: name: nginxstate;latestloop: "{{ ansible_mounts }}"when: item.mount == "/" and item.size_available > 200000000

以上就是大部分的判断方法,欢迎各位志同道合的朋友一起交流。

温馨提示

一名常年穿梭于Google、阿里、百度、腾讯的一线运维从业者。是<<运维开发故事>>公众号的成员之一。不定期分享技术干货和对技术的理解与感悟。

[Ansible专栏]Ansible条件判断的介绍和使用相关推荐

  1. Ansible中的条件判断、handlers

    1.有条件地运行任务 Ansible可使用conditionals在符合特定条件时执行任务或play. 所以我们可以利用条件来区分不同的受管主机,并根据它们所符合的条件来分配功能角色.Playbook ...

  2. linux系统中shell脚本最全详解二shell条件判断语法介绍函数分析

    目录 一.shell判断句 1.if条件判断语句 2.test判断 二.语法介绍 1.shell运算符 2.shell循环语句 三.shell函数 一.shell判断句 1.if条件判断语句 if语法 ...

  3. ansible的条件判断、迭代执行、tags

    在ansible中支持条件判断,这使我们操作更加灵活 使用when进行条件测试 示例1: 将 testservers 组中的其中一台主机上的 httpd 服务卸载掉,另外主机不卸载 1 2 3 4 5 ...

  4. ansible介绍、安装、远程执行命令、拷贝文件或目录、远程执行脚本、管理任务计划、安装包和管理服务、playbook、变量、循环、条件判断、handlers、安装nginx、管理配置文件

    24.15 ansible介绍 ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系 ...

  5. Ansible系列(六):循环和条件判断

    Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html 1. 循环 ansible中的循环都是借助迭代来实现的.基本都是以" ...

  6. Ansible 条件判断 循环 handlers 任务失败 文件管理的使用

    文章目录 Ansible 条件判断 循环 handlers 任务失败 文件管理的使用 1.条件判断 1.1测试多个条件 1.2循环和有条件任务 2. handlers 3. 任务失败 3.1忽略任务失 ...

  7. 自动化运维-Ansible (第三部:Playbook 介绍)

    前言 之前有两篇文章分别讲了 Ansible 的部署.Ansible 的 模块使用,对 Ansible 有了最初的了解,这篇文章最主要是要介绍 Playbook. 需要了解 Ansible 的部署请点 ...

  8. 自动化运维工具ansible的安装管理以及模块介绍

    自动化运维工具ansible的安装管理以及模块介绍 目录 自动化运维工具ansible的安装管理以及模块介绍 一.ansible概述 1.几种常用运维工具比较 2.Ansible简介 3.Ansibl ...

  9. python多个判断条件_Python基础介绍 | 条件判断Conditionals

    先前我们已经学了如何使用Strings和Numbers两个数据类型,还有其他的数据类型,例如列表啊.字典啊,我们先放着不学,但以下的内容多多少少少会涉及. 今天学啥呢?我们来看看条件判断,即Condi ...

  10. [Ansible系列]ansible tag介绍

    目录 简介 task      tag 1.  执行指定tag的task 2.  排除指定tag的task 3.   查看playbook中的所有tag 4.  打tag的方式 4.1   一个tas ...

最新文章

  1. oracle删除大表的数据的方法
  2. Kraken采用CashAddr地址,BCH地址统一向前一步
  3. 第十一届青少年蓝桥杯国赛真题精选 - 编程题
  4. Linux Shell 简介
  5. 【注意力机制】SENet(Squeeze-and-Excitation Networks)详解
  6. 认知NumPy数学运算库
  7. PHP的OB缓存(输出缓存)
  8. 随机数是骗人的,.Net、Java、C为我作证 - 杨中科 - 博客园
  9. VB 串口编程 开发心得
  10. 系统集成项目管理工程师(软考中级)—— 第七章 知识产权 笔记分享
  11. VMI的两种库存管理模式
  12. CAD教程:CAD软件打开图纸后钢筋符号无法读取的解决办法
  13. 我的无线路由器是红色的——N倍速的快感,初探Openwrt系统无线路由器
  14. 交换友情链接时要谨防以下12种情况
  15. eNB、gNB、en-gNB和ng-eNB的区别
  16. MFC文本编程--退格键的操作
  17. matlab实验思考,MATLAB实验.doc
  18. Android 13 Camera ITS 环境搭建(从Python安装到环境配置详解)
  19. matlab读取excel数据
  20. php下载pdf文件不全,关于php:Zip PDF文件下载无效

热门文章

  1. aop:aspectj-autoproxy 标签解析
  2. 小语种语音情感语料库的建立——论文阅读1
  3. 计算机主机重装主机过程,电脑更换硬盘重装系统全过程详解
  4. kafka2.2源码分析之KafkaChannel
  5. 《安全评估报告》7条回答范例
  6. PAT乙级 打印沙漏(20)
  7. ATM(异步传输模式)是什么?
  8. 【NLP】句法分析一
  9. uni-app 页面中的背景图片高度和宽度自适应
  10. 数值微分的python实现