Ansible 循环、过滤器与判断逻辑

发布于:2025-09-03 ⋅ 阅读:(18) ⋅ 点赞:(0)

Ansible 循环、过滤器与判断逻辑

一、Ansible 循环

循环用于批量执行重复任务,减少代码冗余,Ansible 提供多种迭代方式适配不同场景,核心类型及用法如下:

循环类型 功能说明 关键特点
with_items / loop 列表循环 loop 可完全替代 with_items,适用于简单列表(如用户、软件包)
with_dict 迭代字典 需同时使用键(key)和值(value),如 “路径 + 权限” 组合场景
with_fileglob 迭代本地文件 支持通配符(如 *.conf),用于批量处理本地配置文件
with_lines 迭代命令输出的每一行 处理命令行执行结果,如清理旧文件、读取日志内容
with_nested 嵌套迭代(多重循环) 多列表组合迭代,如 “用户名 + 用户组” 关联配置
with_sequence 生成有序序列 支持数字 / 字母序列,如创建 test1-test5 系列测试文件
with_random_choice 随机选择列表中的元素执行 从列表中随机挑选一个元素执行,如抽样测试节点连通性

二、Ansible 过滤器

过滤器用于对变量值进行加工处理(格式转换、加密等),核心语法为 {{ 变量名 | 过滤功能 }},支持链式调用(如 {{ 变量 | lower | trim }})。

2.1 基础过滤器

过滤器名称 功能说明 示例
upper 将字符串转换为纯大写 {{ “Ansible” | upper}}
lower 将字符串转换为纯小写 {{ “ANSIBLE” | lower}}
trim 去除字符串首尾空格(含换行符) {{ " hello ansible " | trim}}
length 计算字符串长度或列表元素个数 {{ “ansible” | length}}

2.2 安全过滤器(字符串哈希加密)

主要用于用户密码加密,避免明文存储,支持 sha512、md5 等哈希算法。

示例:创建用户并设置 SHA512 加密密码

---
- name: 创建用户 sl 并设置加密密码  
  hosts: node1  
  tasks:    
  	- name: 新建用户 sl,密码为 123456(SHA512 加密)      
  	  user:        
  	    name: sl        
  	    password: "{{ '123456' | password_hash('sha512') }}"  # 核心加密逻辑        
  	    state: present

三、Ansible 判断逻辑

通过 when 关键字实现条件控制,根据 “变量状态、任务结果、路径属性” 等决定是否执行任务,支持多种内置测试器。

3.1 核心判断场景及测试器

3.1.1 变量状态判断

用于检查变量是否定义、是否为空值:

测试器 功能说明 示例(when 条件)
defined 变量已定义则执行任务 when: test_var is defined
undefined 变量未定义则执行任务 when: test_var is undefined
none 变量已定义但为空值则执行任务 when: test_var is none
3.1.2 任务执行结果判断

先通过 register 注册任务结果,再根据结果状态执行后续操作:

测试器 功能说明 示例(when 条件)
success 任务执行成功则执行 when: task_result is success
failed 任务执行失败则执行 when: task_result is failed
changed 任务导致主机状态变化则执行 when: task_result is changed
skipped 任务被跳过则执行 when: task_result is skipped
3.1.3 路径属性判断

判断文件 / 目录 / 链接等路径的属性:

测试器 功能说明 示例(when 条件)
file 路径是普通文件则执行 when: “/tmp/test.txt” is file
directory 路径是目录则执行 when: “/tmp/logs” is directory
link 路径是软链接则执行 when: “/tmp/current” is link
mount 路径是挂载点则执行 when: “/mnt/data” is mount
exists 路径存在(无论类型)则执行 when: “/tmp/test.txt” is exists
3.1.4 字符串与数据类型判断
测试器 功能说明 示例(when 条件)
lower 字符串是纯小写则执行 when: “ansible” is lower
upper 字符串是纯大写则执行 when: “ANSIBLE” is upper
string 对象是字符串类型则执行 when: test_var is string
number 对象是数字类型(int/float)则执行 when: test_var is number

3.2 高级判断:block-rescue-always(异常捕获)

类似 try-except-finally,用于捕获任务执行异常,实现 “正常执行→异常处理→收尾操作” 的逻辑:

  • block:正常尝试执行的任务块;

  • rescue:block 执行失败时触发的异常处理块;

  • always:无论 block 成功与否,都会执行的收尾块。

示例:逻辑卷创建与异常处理

---
- name: 逻辑卷创建(含异常处理)  
  hosts: all  
  tasks:
    - name: 逻辑卷操作主逻辑
      block:        # 正常尝试创建 1500MiB 逻辑卷
        - name: 在 research 卷组创建 1500MiB 逻辑卷 data
          lvol:
            vg: research
            lv: data
            size: 1500MiB
            state: present
      rescue:        # block 失败(如空间不足)时执行
        - name: 输出错误消息
          debug:
            msg: "Could not create logical volume of that size"
            # 降级创建 800MiB 逻辑卷
        - name: 改为创建 800MiB 逻辑卷 data
          lvol:
            vg: research
            lv: data
            size: 800MiB
            state: present
      always:        # 无论成败,都格式化逻辑卷为 ext4
        - name: 格式化逻辑卷为 ext4 文件系统
          filesystem:
            dev: /dev/research/data
            fstype: ext4
      when: "'research' in ansible_lvm.vgs"  # 仅卷组存在时执行    
# 卷组不存在时输出提示    
    - name: 卷组不存在提示      
      debug:        
        msg: "Volume group does not exist"
      when: "'research' not in ansible_lvm.vgs"

3.3 任务状态控制(手动干预结果)

通过关键字手动控制任务执行结果,适配特殊场景:

关键字 / 模块 功能说明 示例
ignore_errors: yes 忽略任务错误,继续执行后续任务 执行 “读取不存在文件” 命令时,忽略错误不中断剧本
changed_when: 条件 自定义任务 “是否变化” 的判断 changed_when: false → 强制标记任务 “无变化”
failed_when: 条件 自定义任务 “是否失败” 的判断 failed_when: “‘error’ in result.stdout” → 输出含 error 则标记失败
fail 模块 手动中断剧本,输出自定义错误 关键变量为空时,中断剧本并提示

四、前提准备:LVM 卷组部署(lvm2.yml)

在 node1、node2 上添加硬盘后,通过剧本安装 LVM 工具并创建卷组:

---
# 所有节点安装 lvm2 软件
- name: 安装 lvm2 工具  
  hosts: all   
  tasks:      
    - name: 安装 lvm2 包      
      yum:         
        name: lvm2        
        state: present
# node1 创建 2G 卷组 research
- name: 为 node1 创建卷组  
  hosts: node1  
  tasks:    
    - name: 分区 /dev/vdb(10MiB-2010MiB 为主分区)      
      parted:         
        device: /dev/vdb        
        number: 1        
        part_type: primary        
        part_start: 10MiB        
        part_end: 2010MiB        
        state: present    
    - name: 创建物理卷(PV)      
      pvcreate:         
        devices: /dev/vdb1        
        state: present    
    - name: 创建卷组(VG)research       
      lvg:          
        vg: research        
        pvs: /dev/vdb1        
        state: present
# node2 创建 1G 卷组 research
- name: 为 node2 创建卷组  
  hosts: node2  
  tasks:     
    - name: 分区 /dev/vdb(10MiB-1010MiB 为主分区)      
      parted:         
        device: /dev/vdb        
        number: 1        
        part_type: primary       
        part_start: 10MiB        
        part_end: 1010MiB        
        state: present    
    - name: 创建物理卷(PV)      
      pvcreate:         
        devices: /dev/vdb1        
        state: present    
    - name: 创建卷组(VG)research      
      lvg:        
        vg: research        
        pvs: /dev/vdb1        
        state: present

五、实战练习

主机清单说明

[test01]
node1

[test02]
node2

[web]
node3
node4

[test05]
node5

[webtest:children]
web  # webtest 组包含 web 组的所有节点

5.1 练习 1:动态生成主机清单(newhosts.yml)

需求从 http://ansible.example.com/materials/newhosts.j2 下载模板文件
完成该模板文件,用来生成新主机清单(主机的显示顺序没有要求),结构如下:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.122.10 node1.example.com node1
192.168.122.20 node2.example.com node2
192.168.122.30 node3.example.com node3
192.168.122.40 node4.example.com node4
192.168.122.50 node5.example.com node5
创建剧本/home/student/ansible/newhosts.yml,它将使用上述模板在 test01 主机组的主机上
生成文件/etc/newhosts。

5.1.1 步骤 1:下载并编写模板(newhosts.j2)
  1. 下载模板:curl -o http://ansible.example.com/materials/newhosts.j2
  2. 编辑模板内容:
#cat newhosts.j2

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

{% for sl in groups.all %}
{{ hostvars[sl].ansible_default_ipv4.address }} {{ hostvars[sl].ansible_fqdn }} {{ hostvars[sl].ansible_hostname }}
{% endfor %}

5.2.2 步骤 2:编写剧本(newhosts.yml)
---# 先收集所有主机信息(需访问 all 主机组)
- name: 收集所有主机变量  
  hosts: all  
# 在 test01 组生成主机清单
- name: 生成 /etc/newhosts 文件  
  hosts: test01  
  tasks:     
    - name: 部署模板文件      
      template:         
        src: /home/student/ansible/newhosts.j2        
        dest: /etc/newhosts        
5.2.3 验证命令
ansible test01 -m shell -a 'cat /etc/newhosts'

在这里插入图片描述

5.3 练习 3:差异化修改 /etc/issue(newissue.yml)

需求:创建剧本 /home/student/ansible/newissue.yml,满足下列要求:
1)在所有清单主机上运行,替换/etc/issue 的内容
2)对于 test01 主机组中的主机,/etc/issue 文件内容为 test01
3)对于 test02 主机组中的主机,/etc/issue 文件内容为 test02
4)对于 web 主机组中的主机,/etc/issue 文件内容为 Webserver

---
- name: 差异化修改 /etc/issue  
  hosts: all  
  tasks:     
    - name: 设置 /etc/issue 内容      
      copy:         
        content: |          
          {% if "test01" in group_names %}          
          test01          
          {% elif "test02" in group_names %}          
          test02          
          {% elif "web" in group_names %}          
          Webserver          
          {% endif %}        
        dest: /etc/issue
验证命令
ansible all -m shell -a 'cat /etc/issue'

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到