用条件与循环把分支压扁
目标
把因复制粘贴而不断增加的 task 收拢为数据和循环,并能通过条件筛选条目。
为什么重要
多个几乎相同的 task 中,迟早会有一个被误改得与其他项不同,而且仅靠阅读代码很难发现。把 task 合并成一个,出错的位置也只剩一个;数据像表格一样排列,缺项会一目了然。实际使用循环时,经常遇到三个问题:日志泄露——直接遍历字典会把其中所有值写入日志,因此需要 loop_control.label;幂等性——循环十次,非幂等造成的影响也会扩大十倍;组合爆炸——两个列表的笛卡尔积会迅速膨胀。使用 until 等待某个条件时,还应让重试次数体现“在这段时间内仍未成功,就说明确实有问题”的判断。
步骤
- 在
/root/ans/loops/site.yml中使用loop,在/root/ans/loops/simple/下创建alpha、beta、gamma三个目录。只能使用一个 task。 - 读取
/opt/lab/fixtures/ansible/users.yml中的app_users,根据每个条目的dir创建目录,并设置为mode权限:/root/ans/loops/deploy(0750)、/root/ans/loops/metrics(0755)、/root/ans/loops/backup(0700)。 - 在同一循环中添加
when,仅在权限比0755更严格的条目目录中留下PRIVILEGED文件:必须创建/root/ans/loops/deploy/PRIVILEGED和/root/ans/loops/backup/PRIVILEGED,不得创建/root/ans/loops/metrics/PRIVILEGED。 - 使用
loop_control的label整理日志,并将执行输出保存到/root/ans/loops/out/run.txt。日志中应出现item=deploy形式的简短标签,不得显示整个字典。 - 创建使用
until/retries/delay的等待 task,并将成功结果写入/root/ans/loops/out/ready.txt,内容为ready。 - 根据环境(
dev,stage,prod)×组件(app,worker)的组合,在/root/ans/loops/matrix/<환경>-<컴포넌트>.conf下创建 6 个文件(例如/root/ans/loops/matrix/dev-app.conf、/root/ans/loops/matrix/prod-worker.conf)。每个文件包含env=<환경>和component=<컴포넌트>两行。 - 使用模式匹配,将文件收集并复制到
/root/ans/loops/collected/,目标是 matrix 中的 6 个.conf文件。不得逐个列出文件名。 - 创建
/root/ans/loops/out/loops.json,其中包含users(3 项,每项都有布尔值privileged)和matrix_files(6)。再把第二次执行结果保存到/root/ans/loops/out/run2.txt,且必须为changed=0。
参考
- 每个实验都会启动全新的实验 Pod。如果
/root/ans/inventory/hosts.ini不存在,请先重新创建与第一个实验相同的 inventory(web1·web2·db1,ansible_host=127.0.0.1、ansible_port=2222、ansible_user=root,并在[prod:children]中加入 web·db)。结构可以参考/opt/lab/fixtures/ansible/inventory.sample.ini。 - 可以像
loop: "{{ app_users }}"这样直接传入变量。 - 组合可写成
"{{ envs | product(components) | list }}"。 - 常见错误 1:
loop中的 task 不具备幂等性,导致第二次执行时按循环次数产生 changed。 - 常见错误 2:依赖模式查询结果的顺序。该顺序没有保证。
用列表循环创建三个目录
在 /root/ans/loops/site.yml 中使用 loop,在 /root/ans/loops/simple/ 下创建 alpha、beta、gamma 三个目录。只能使用一个 task。
给 loop: 提供列表,并通过 item 引用当前项。不要复制 task。
遍历字典列表
读取 /opt/lab/fixtures/ansible/users.yml 中的 app_users,根据每个条目的 dir 创建目录,并设置为 mode 权限:/root/ans/loops/deploy(0750)、/root/ans/loops/metrics(0755)、/root/ans/loops/backup(0700)。
通过 vars_files 读取 fixture 中的 app_users。使用 item.name、item.mode 这样的字段访问方式。
只处理符合条件的条目
在同一循环中添加 when,仅在权限比 0755 更严格的条目目录中留下 PRIVILEGED 文件:必须创建 /root/ans/loops/deploy/PRIVILEGED 和 /root/ans/loops/backup/PRIVILEGED,不得创建 /root/ans/loops/metrics/PRIVILEGED。
loop 与 when 一起使用时,会对每个条目分别判断条件。mode 为 0755 的条目必须被排除。
整理日志中的循环标签
使用 loop_control 的 label 整理日志,并将执行输出保存到 /root/ans/loops/out/run.txt。日志中应出现 item=deploy 形式的简短标签,不得显示整个字典。
使用 loop_control 的 label 缩短显示内容。日志中不能出现完整字典。
重试直到条件成立
创建使用 until/retries/delay 的等待 task,并将成功结果写入 /root/ans/loops/out/ready.txt,内容为 ready。
until/retries/delay 三项缺一不可。请将成功结果保存到文件。
生成两个列表的全部组合
根据环境(dev,stage,prod)×组件(app,worker)的组合,在 /root/ans/loops/matrix/<환경>-<컴포넌트>.conf 下创建 6 个文件(例如 /root/ans/loops/matrix/dev-app.conf、/root/ans/loops/matrix/prod-worker.conf)。每个文件包含 env=<환경> 和 component=<컴포넌트> 两行。
使用 product 过滤器生成组合。3 个环境 × 2 个组件 = 6 个文件。
通过模式收集文件
使用模式匹配,将文件收集并复制到 /root/ans/loops/collected/,目标是 matrix 中的 6 个 .conf 文件。不得逐个列出文件名。
不要逐个写出文件名,而要通过模式获取文件列表。复制后的内容必须与原文件一致。
生成循环结果报告并验证重跑
创建 /root/ans/loops/out/loops.json,其中包含 users(3 项,每项都有布尔值 privileged)和 matrix_files(6)。再把第二次执行结果保存到 /root/ans/loops/out/run2.txt,且必须为 changed=0。
将每个用户的 privileged 状态和组合文件数量整理为 JSON,并确认第二次执行为 changed=0。