目录
[1 when条件语句概述](#1 when条件语句概述)
[1.1 基本语法](#1.1 基本语法)
[1.2 简单示例](#1.2 简单示例)
[2 when条件判断的工作原理](#2 when条件判断的工作原理)
[2.1 执行流程](#2.1 执行流程)
[.2.3 变量评估机制](#.2.3 变量评估机制)
[3 when条件判断的常见用法](#3 when条件判断的常见用法)
[3.1 基于变量判断](#3.1 基于变量判断)
[3.2 基于事实判断](#3.2 基于事实判断)
[3.3 基于多个条件判断](#3.3 基于多个条件判断)
[3.4 使用列表和字典](#3.4 使用列表和字典)
[3.5 使用正则表达式](#3.5 使用正则表达式)
[4 when条件判断的实践建议](#4 when条件判断的实践建议)
[4.1 保持条件简单明了](#4.1 保持条件简单明了)
[4.2 使用Jinja2过滤器](#4.2 使用Jinja2过滤器)
[4.3 避免在when中使用复杂计算](#4.3 避免在when中使用复杂计算)
[4.4 使用标签优化执行](#4.4 使用标签优化执行)
[5 when条件判断的高级用法](#5 when条件判断的高级用法)
[5.1 使用注册变量和when](#5.1 使用注册变量和when)
[5.2 使用block和when](#5.2 使用block和when)
[5.3 使用failed_when和when结合](#5.3 使用failed_when和when结合)
[6 when条件判断的应用场景](#6 when条件判断的应用场景)
[6.1 环境差异化配置](#6.1 环境差异化配置)
[6.2 条件性软件安装](#6.2 条件性软件安装)
[6.3 基于主机角色的配置](#6.3 基于主机角色的配置)
[6.4 条件性服务重启](#6.4 条件性服务重启)
[7 总结](#7 总结)
引言
在自动化运维领域,Ansible凭借其简洁的YAML语法和强大的模块化功能,成为了众多运维工程师的首选工具。在Ansible Playbook中,when条件语句是实现精细化任务控制的关键机制。
1 when条件语句概述
when是Ansible Playbook中的一个关键字,用于根据特定条件判断是否执行某个任务。它类似于编程语言中的if语句,允许我们基于变量、事实(facts)或其他条件来控制任务的执行流程。
1.1 基本语法
- name: 示例任务
hosts: target_hosts
tasks:
- name: 仅在特定条件下执行
ansible.builtin.command: /path/command
when: condition_expression
- when 后面的表达式可以是任何返回布尔值的表达式,当表达式为 true 时,任务才会执行;否则,任务将被跳过
1.2 简单示例
- name: 系统更新任务
hosts: all
vars:
is_development: true
tasks:
- name: 仅在生产环境更新系统
ansible.builtin.apt:
update_cache: yes
upgrade: dist
when: not is_development
- 在这个示例中,只有当is_development为false时,系统更新任务才会执行
2 when条件判断的工作原理
2.1 执行流程

- 变量和事实加载:Ansible首先加载所有变量(包括inventory变量、playbook变量、角色变量等)和系统事实(facts)
- 条件检查:对于每个任务,Ansible检查是否定义了when条件
- 表达式评估:如果定义了when条件,Ansible会评估该表达式的值
- 执行决策 :
- 如果表达式结果为true,则执行任务
- 如果表达式结果为false,则跳过任务
- 结果记录:无论任务是否执行,都会记录相应的结果(changed、skipped等)
- 继续执行:继续处理下一个任务
.2.3 变量评估机制
Ansible在评估 when 表达式时,会遵循以下规则:
- 所有变量都被视为字符串,除非它们被明确转换为其他类型
- 布尔值true和false是特殊的,它们会被正确识别为布尔值
- 数字可以与字符串进行比较,但可能会产生意外结果
- 空值(如空字符串、空列表、空字典)在布尔上下文中被视为false
3 when条件判断的常见用法
3.1 基于变量判断
- name: 配置Web服务器
hosts: webservers
vars:
enable_ssl: true
ssl_cert_path: /etc/ssl/certs/mycert.pem
tasks:
- name: 安装Nginx
ansible.builtin.apt:
name: nginx
state: present
- name: 配置SSL证书
ansible.builtin.copy:
src: files/cert.pem
dest: "{{ ssl_cert_path }}"
when: enable_ssl
3.2 基于事实判断
-
Ansible会自动收集目标主机的系统信息,称为"事实"(facts)。我们可以使用这些事实来编写条件判断
- name: 根据操作系统执行不同任务
hosts: all
tasks:-
name: 更新APT缓存
ansible.builtin.apt:
update_cache: yes
when: ansible_os_family == "Debian" -
name: 更新YUM缓存
ansible.builtin.yum:
list: updates
when: ansible_os_family == "RedHat"
-
- name: 根据操作系统执行不同任务
3.3 基于多个条件判断
-
我们可以使用逻辑运算符组合多个条件
- name: 复杂条件示例
hosts: all
vars:
env: production
maintenance: false
tasks:- name: 执行关键任务
ansible.builtin.command: /path/to/critical_command
when: env == "production" and not maintenance
- name: 执行关键任务
- name: 复杂条件示例
3.4 使用列表和字典
- name: 列表条件判断
hosts: all
vars:
required_packages:
- nginx
- apache2
- mysql-server
tasks:
- name: 安装必需软件包
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop: "{{ required_packages }}"
when: item in ansible_facts.packages
- name: 字典条件判断
ansible.builtin.debug:
msg: "服务已安装"
when: ansible_facts.services["nginx"] is defined
3.5 使用正则表达式
- name: 使用正则表达式
hosts: all
tasks:
- name: 处理特定主机
ansible.builtin.debug:
msg: "处理Web服务器"
when: inventory_hostname | match("web.*")
4 when条件判断的实践建议
4.1 保持条件简单明了
-
复杂的条件表达式难以理解和维护。如果条件过于复杂,考虑将其分解为多个变量或使用过滤器
不推荐
- name: 复杂条件
ansible.builtin.command: /path/to/command
when: (ansible_os_family == "Debian" and ansible_distribution_release in ["buster", "bullseye"]) or (ansible_os_family == "RedHat" and ansible_distribution_major_version >= "8")
推荐
-
name: 定义变量
set_fact:
is_supported_debian: "{{ ansible_os_family == 'Debian' and ansible_distribution_release in ['buster', 'bullseye'] }}"
is_supported_redhat: "{{ ansible_os_family == 'RedHat' and ansible_distribution_major_version >= '8' }}" -
name: 执行命令
ansible.builtin.command: /path/to/command
when: is_supported_debian or is_supported_redhat
- name: 复杂条件
4.2 使用Jinja2过滤器
-
Jinja2提供了丰富的过滤器,可以帮助我们更灵活地处理条件
- name: 使用Jinja2过滤器
hosts: all
tasks:- name: 检查版本是否大于等于1.0
ansible.builtin.debug:
msg: "版本符合要求"
when: version is version('1.0', '>=')
- name: 检查版本是否大于等于1.0
- name: 使用Jinja2过滤器
4.3 避免在when中使用复杂计算
-
复杂的计算应该在任务外部完成,以提高Playbook的可读性
不推荐
- name: 复杂计算
ansible.builtin.command: /path/to/command
when: (ansible_facts['memory_mb']['real']['total'] / 1024 / 1024) > 4
推荐
-
name: 计算内存大小
set_fact:
memory_gb: "{{ ansible_facts['memory_mb']['real']['total'] / 1024 / 1024 }}" -
name: 检查内存大小
ansible.builtin.command: /path/to/command
when: memory_gb > 4
- name: 复杂计算
4.4 使用标签优化执行
-
结合when和tags可以更灵活地控制Playbook的执行
- name: 带标签的任务
hosts: all
tasks:-
name: 仅在生产环境执行
ansible.builtin.command: /path/to/production_command
tags: production
when: env == "production" -
name: 仅在开发环境执行
ansible.builtin.command: /path/to/development_command
tags: development
when: env == "development"
-
- name: 带标签的任务
5 when条件判断的高级用法
5.1 使用注册变量和when
-
我们可以使用register关键字捕获任务的结果,然后在后续任务中使用when基于这些结果进行判断
- name: 检查服务状态
hosts: all
tasks:-
name: 检查nginx是否运行
ansible.builtin.systemd:
name: nginx
state: started
register: nginx_status -
name: 重启nginx
ansible.builtin.systemd:
name: nginx
state: restarted
when: nginx_status.status.changed
-
- name: 检查服务状态
5.2 使用block和when
-
block允许我们将相关任务组织在一起,并可以对整个块应用条件
- name: 使用block和when
hosts: all
vars:
enable_maintenance: false
tasks:- name: 维护模式任务块
block:- name: 停止应用服务
ansible.builtin.systemd:
name: myapp
state: stopped - name: 执行维护任务
ansible.builtin.command: /path/to/maintenance_script - name: 启动应用服务
ansible.builtin.systemd:
name: myapp
state: started
when: enable_maintenance
- name: 停止应用服务
- name: 维护模式任务块
- name: 使用block和when
5.3 使用failed_when和when结合
-
failed_when允许我们自定义任务失败的条件,可以与when结合使用实现更复杂的错误处理
- name: 错误处理示例
hosts: all
tasks:-
name: 执行可能失败的任务
ansible.builtin.command: /path/to/risky_command
register: result
failed_when: result.rc != 0 and not allow_failure
changed_when: result.rc == 0 -
name: 处理失败的任务
ansible.builtin.debug:
msg: "任务失败,但允许继续执行"
when: result.rc != 0 and allow_failure
-
- name: 错误处理示例
6 when条件判断的应用场景
6.1 环境差异化配置
-
在不同环境中(开发、测试、生产)执行不同的配置任务
- name: 环境差异化配置
hosts: all
vars:
env: "{{ lookup('env', 'ANSIBLE_ENV') | default('development') }}"
tasks:-
name: 开发环境配置
ansible.builtin.copy:
src: configs/dev.conf
dest: /etc/app/config.conf
when: env == "development" -
name: 测试环境配置
ansible.builtin.copy:
src: configs/test.conf
dest: /etc/app/config.conf
when: env == "testing" -
name: 生产环境配置
ansible.builtin.copy:
src: configs/prod.conf
dest: /etc/app/config.conf
when: env == "production"
-
- name: 环境差异化配置
6.2 条件性软件安装
-
根据系统需求或用户选择安装不同的软件包
- name: 条件性软件安装
hosts: all
vars:
install_database: true
install_webserver: false
tasks:-
name: 安装数据库
ansible.builtin.apt:
name: postgresql
state: present
when: install_database -
name: 安装Web服务器
ansible.builtin.apt:
name: nginx
state: present
when: install_webserver
-
- name: 条件性软件安装
6.3 基于主机角色的配置
-
根据主机在架构中的角色执行不同的配置
- name: 基于角色的配置
hosts: all
tasks:-
name: 配置Web服务器
ansible.builtin.copy:
src: configs/nginx.conf
dest: /etc/nginx/nginx.conf
when: "'web_server' in group_names" -
name: 配置数据库服务器
ansible.builtin.copy:
src: configs/postgresql.conf
dest: /etc/postgresql/12/main/postgresql.conf
when: "'db_server' in group_names" -
name: 配置负载均衡器
ansible.builtin.copy:
src: configs/haproxy.cfg
dest: /etc/haproxy/haproxy.cfg
when: "'load_balancer' in group_names"
-
- name: 基于角色的配置
6.4 条件性服务重启
-
仅在配置文件更改时重启服务
- name: 条件性服务重启
hosts: all
tasks:-
name: 更新配置文件
ansible.builtin.copy:
src: files/app.conf
dest: /etc/app/app.conf
register: config_updated -
name: 重启应用服务
ansible.builtin.systemd:
name: app
state: restarted
when: config_updated.changed
-
- name: 条件性服务重启
7 总结
本文探讨了Ansible Playbook中when条件判断的使用方法。通过合理使用when条件,我们可以实现更加灵活和精确的任务控制,使Playbook能够适应不同的环境和需求。
掌握when条件判断是编写高效、可维护Ansible Playbook的关键技能。通过合理运用这一特性,我们可以构建出更加智能和灵活的自动化运维解决方案,提高运维效率,减少人为错误。