ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Salt 状态 Altering States 全局参数实战:unless、onlyif、creates、check_cmd 与 retry 的条件执行与校验机制

Salt 状态 Altering States 全局参数实战:unless、onlyif、creates、check_cmd 与 retry 的条件执行与校验机制 运维配置管理后端【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址https://gitcode.com/gh_mirrors/sa/salt点击查看免费下载Salt当前仓库为gh_mirrors/sa/salt的 State 系统除了require、watch等关系型依赖外还提供了一套Altering States全局状态参数用于在单个状态执行前注入条件判断、在执行后复核结果甚至在失败时自动重试。本文将围绕doc/ref/states/requisites.rst中的 Altering States 章节展开系统讲解unless、onlyif、creates、runas、runas_password、check_cmd、reload_modules、fire_event、retry、umask等参数的用法与底层实现读完你就能写出精确到命令退出码、文件是否存在、甚至自定义复核逻辑的高可控状态文件。原doc/ref/states/altering_states.rst只是一个跳转入口其正文已被合并进 Requisites and Other Global State Arguments本文即以该章节为骨架展开。一、Altering States 是什么让状态按预期执行Salt 的 State 引擎在salt/state.py中会为每个状态 chunk 做执行前检查与执行后校验。官方文档对这一系统的定位是The state altering system is used to make sure that states are evaluated exactly as the user expects. It can be used to double check that a state preformed exactly how it was expected to, or to make 100% sure that a state only runs under certain conditions.即两个核心诉求确保状态只在特定条件下运行——通过unless、onlyif、creates实现确保状态执行结果符合预期——通过check_cmd复核reload_modules/reload_pillar/reload_grains刷新运行环境retry在未达到期望结果时自动重试。这些参数在源码中作为全局状态关键字被显式声明见 salt/state.py 第 91-108 行附近的全局关键字列表包含check_cmd、onlyif、unless、creates、retry、fire_event等。与 Requisites 的关系需要澄清altering_states.rst的正文之所以被并入requisites.rst是因为这些参数与require/watch/onchanges等关系型依赖同属全局状态参数Global State Arguments。区别在于Requisitesrequire、watch、listen、prereq、onfail、use等描述状态之间的依赖关系组成一张单向依赖图Altering States 参数描述单个状态自身的执行条件与结果校验。两者可以组合使用。例如下面的经典场景先确保 nginx 已安装require依赖再用onchanges在配置变化后触发动作nginx: pkg.installed: - name: nginx-light service.running: - enable: True - require: - pkg: nginx关于 Requisites 的匹配规则按 ID 声明与name参数匹配、通配符匹配、省略 state module 等可继续阅读 Requisites and Other Global State Arguments 前文本文聚焦 Altering States 参数本身。二、reload_modules状态执行后刷新运行环境reload_modules是一个布尔选项强制 Salt 在某个状态执行完毕后重新加载其模块同时可以设置reload_pillar与reload_grains。常见场景是某个状态修改了 grains 或 pillar 数据后续状态需要读取到最新值。官方示例展示了如何在module.run中刷新 grainsgrains_refresh: module.run: - name: saltutil.refresh_grains - reload_grains: true grains_read: module.run: - name: grains.items这里grains_refresh先执行saltutil.refresh_grains刷新 minion 上的 grains并带上reload_grains: true确保随后grains_read读取到的是最新数据。相关概念可参见 Reloading Modules 一节。三、unlessNAND 语义的条件跳过unless在 2014.7.0 版本加入。它指定当列表中任意一条命令返回False时状态才执行换言之它按 NANDnot-and逻辑工作适合做幂等判断——例如包已安装就不必再装。官方示例vim: pkg.installed: - unless: - rpm -q vim-enhanced - ls /usr/bin/vim逻辑拆解两条命令都返回Truevim-enhanced 已安装 且 /usr/bin/vim 存在→ 状态不执行任意一条返回False未安装 或 文件不存在→ 状态执行。底层实现文档明确提示unless底层调用cmd.retcode且python_shellTrue。在源码 salt/state.py 的_run_check_unless约 1250 行中字符串条目会被交给self.functionscmd.retcode执行以**退出码shell 语义的 True/False**而非 Python 布尔值判定。因此命令经 shell 解析执行shell 会以与 salt-minion 相同的权限运行需警惕副作用布尔结果由 shell 的0/ 非0决定与 Python 的 True/False 概念无关。unless 对多 name 的处理unless检查会针对每个关联的 name 分别解析。例如deploy_app: cmd.run: - names: - first_deploy_cmd - second_deploy_cmd - unless: some_checksome_check会在每个 name 执行前各运行一次——first_deploy_cmd前一次、second_deploy_cmd前再一次。3000 起支持模块字典形式从 3000 版本起unless可以接收一个字典通过fun指定要调用的执行模块其余键作为 kwargs 传给该函数也可以显式用args传递位置参数install apache on debian based distros: cmd.run: - name: make install - cwd: /path/to/dir/whatever-2.1.5/ - unless: - fun: file.file_exists path: /usr/local/bin/whateverset mysql root password: debconf.set: - name: mysql-server-5.7 - data: mysql-server/root_password: {type: password, value: {{pillar[mysql.pass]}} } - unless: - fun: pkg.version args: - mysql-server-5.7sodium 版本起对返回深层数据结构的模块可用get_return键提取结果test: test.nop: - name: foo - unless: - fun: consul.get consul_url: http://127.0.0.1:8500 key: not-existing get_return: res源码中_run_check_unless对字典条目调用_run_check_functionsalt/state.py 约 1165 行它会弹出fun与args剩余键作为 kwargs并经format_slots处理 slot 后执行模块函数若存在get_return则用salt.utils.data.traverse_dict_and_list从返回结构中取指定路径的值作为判定依据。3006.0 起支持 cmd_opts_exclude由于unless借助cmd.retcode状态中某些参数会被透传给cmd.retcode。这可能引发问题例如user.present的shell设为/sbin/nologin时该 shell 会被传给cmd.retcode导致命令无论结果如何都以该 shell 运行而失败。此时可用cmd_opts_exclude排除这些参数jim_nologin: user.present: - name: jim - shell: /sbin/nologin - unless: - echo hello world - cmd_opts_exclude: - shell源码 salt/state.py 的_run_check中定义了可透传的参数集合POSSIBLE_CMD_ARGS含cwd、root、runas、env、prepend_path、umask、timeout、success_retcodes并在此基础上结合cmd_opts_exclude过滤后再传给cmd.retcode。四、onlyifAND 语义的条件放行onlyif与unless互为镜像当列出的每条命令都返回True时状态才执行任意一条返回False则状态不执行。它同样在 2014.7.0 加入底层同样通过cmd.retcodepython_shellTrue执行。官方 gluster 示例——只有前置命令返回 0 才执行并配合watch串起步骤顺序stop-volume: module.run: - name: glusterfs.stop_volume - m_name: work - onlyif: - gluster volume status work - order: 1 remove-volume: module.run: - name: glusterfs.delete - m_name: work - onlyif: - gluster volume info work - watch: - cmd: stop-volume3000 起的模块字典形式与unless一样3000 起支持fun字典install apache on redhat based distros: pkg.latest: - name: httpd - onlyif: - fun: match.grain tgt: os_family:RedHat install apache on debian based distros: pkg.latest: - name: apache2 - onlyif: - fun: match.grain tgt: os_family:Debianarbitrary file example: file.touch: - name: /path/to/file - onlyif: - fun: file.search args: - /etc/crontab - entry1sodium 起同样支持get_returntest: test.nop: - name: foo - onlyif: - fun: consul.get consul_url: http://127.0.0.1:8500 key: does-exist get_return: res3006.0 起的cmd_opts_exclude行为与unless完全一致见上节jim_nologin示例。源码视角_run_check_onlyifsalt/state.py 约 1173 行的核心逻辑是任何一条为 False 就阻止执行。对字符串条目执行cmd.retcodecmd ! 0即判定为onlyif condition is false并设置skip_watch: True后续 watch 不会触发对字典条目则调用模块函数并以返回值或get_return提取后的值的真值作为判定。onlyif / unless / creates 的合并规则从源码_run_check约 1103 行可以看到三者的组合语义onlyif与unless、creates的检查结果通过or合并——只要任一检查放行结果为真状态就会执行。这与文档所述unless 按 NAND 工作是一致的unless命中命令返回 False即放行onlyif全部通过即放行creates中文件不存在即放行。五、creates基于文件存在性的条件跳过creates在 3001 版本加入语义与unless类似NAND当指定的文件都已存在时状态不执行只要有一个文件不存在状态就执行。它此前曾被cmd与docker_container状态内部使用3001 起提升为全局状态参数。contrived creates example: file.touch: - name: /path/to/file - creates: /path/to/file也支持文件列表此时任意文件不存在都会触发执行creates list: file.cmd: - name: /path/to/command - creates: - /path/file - /path/file2源码视角_run_check_createssalt/state.py 约 1364 行用os.path.exists做纯文件系统检查。字符串形式文件存在 →resultTrue且skip_watchTrue列表形式全部存在才跳过all([os.path.exists(path) for path in ...])否则判定Creates files not found而放行。六、runas 与 runas_password指定执行用户runas2017.7.0 加入用于设置执行cmd.run相关命令的用户django: pip.installed: - name: django 1.6, 1.7 - runas: daniel - require: - pkg: python-pip上例中pip.installed触发的 pip 命令将以daniel用户运行。runas_password2017.7.2 加入用于指定runas所需的密码——Windows 平台上cmd.run使用runas时必须提供run_script: cmd.run: - name: Powershell -NonInteractive -ExecutionPolicy Bypass -File C:\\Temp\\script.ps1 - runas: frank - runas_password: supersecret七、check_cmd自定义结果复核check_cmd2014.7.0 加入用于判定状态是否按预期执行状态函数执行完成后check_cmd中命令的退出码会覆写状态的最终结果。官方示例——修改 yum repo 文件后复核是否真的没有残留enabled0comment-repo: file.replace: - name: /etc/yum.repos.d/fedora.repo - pattern: ^enabled0 - repl: enabled1 - check_cmd: - ! grep enabled0 /etc/yum.repos.d/fedora.repo逻辑拆解bash 语义grep若还找到enabled0返回 0被前置!反转后check_cmd得到非 0 → 状态判为失败grep若没找到替换成功返回 1被!反转后得到 0 → 状态判为成功。注意此处的check_cmd与file.managed状态自带的check_cmd参数行为不同勿混淆。源码视角_run_check_cmdsalt/state.py 约 1330 行对每条命令执行cmd.retcode(entry, ignore_retcodeTrue, python_shellTrue)cmd 0时置resultTruecheck_cmd determined the state succeeded任一条非 0 则置resultFalse并立即返回check_cmd determined the state failed。该检查发生在状态主函数执行之后见 salt/state.py 约 2489 行if check_cmd in low:的分支。八、覆盖默认检查mod_run_check 与 mod_run_check_cmd对于状态模块作者而言可以通过定义两个特殊函数覆盖默认行为mod_run_check负责onlyif与unless的默认检查逻辑mod_run_check_cmd负责check_cmd的默认逻辑。在状态模块文件salt/states/下的实现中定义同名函数即可替换全局默认实现。源码中 salt/state.py 约 2432-2437 行正是这样判定的只有当unless/onlyif/creates出现且{state}.mod_run_check不存在时才调用内置的self._run_check(low)check_cmd同理通过{state}.mod_run_check_cmd是否存在来决定是否走默认_run_check_cmd。这为某些需要特殊判定逻辑的状态模块如网络设备类状态留出了扩展点。九、fire_event状态完成时向 Master 发送事件fire_event2015.8.0 加入使 minion 在单个状态执行完成后向 Salt Master 发送事件。设为True时事件 tag 为salt/state_result/jid/minion_id/state_id事件的 data 字段即该状态结果nano_stuff: pkg.installed: - name: nano - fire_event: True官方给出的实际 tag 形如salt/state_result/20150505121517276431/dasalt/nano——注意状态的name此处为nano会被追加到 tag 中。设为任意字符串时该字符串会成为自定义 tag 片段nano_stuff: pkg.installed: - name: nano - fire_event: custom/tag/nano/finished此时 tag 形如salt/state_result/20150505121725642845/dasalt/custom/tag/nano/finished。这类事件可被 reactor 系统订阅用于驱动后续自动化流程。十、retry让状态自动重试直到期望结果retry2017.7.0 加入允许一个状态执行多次直到达到期望结果或耗尽尝试次数。四个参数参数作用默认值attempts最大执行次数2未指定或非法值until满足该结果即停止重试True未指定或非法值interval两次尝试之间的等待秒数30splay在 interval 基础上额外随机扩展的秒数0不扩展官方示例——最多跑 5 次、间隔 60 秒、并额外 splay 最多 10 秒my_retried_state: pkg.installed: - name: nano - retry: attempts: 5 until: True interval: 60 splay: 10仅写retry: True时全部使用默认值最多 2 次、间隔 30 秒、直到返回 Trueinstall_nano: pkg.installed: - name: nano - retry: True轮询等待场景——每 30 秒检查一次文件最多 15 次wait_for_file: file.exists: - name: /path/to/file - retry: attempts: 15 interval: 30重试状态的返回数据重试时返回值的规则result最后一次运行的result例如第 1 次返回 False、第 2 次返回 True则整体result为 Truestarted第一次运行时的started时间duration所有尝试的总耗时加上间隔时间comment包含此前所有尝试的结果与注释。实际输出示例file.exists连跑 10 次均失败间隔 2 秒、splay 5ID: wait_for_file Function: file.exists Result: False Comment: Attempt 1: Returned a result of False, with the following comment: Specified path /path/to/file does not exist Attempt 2: Returned a result of False, with the following comment: Specified path /path/to/file does not exist ... Attempt 10: Returned a result of False, with the following comment: Specified path /path/to/file does not exist Started: 09:08:12.903000 Duration: 47000.0 ms Changes:源码视角重试循环在 salt/state.py 约 2241-2270 行实现进入循环前先verify_retry_data校验参数循环内当low[retry][until] ret[result]时停止否则按interval random.randint(0, splay)等待后再次调用self.states[cdata[full]]并累加duration、拼接comment。十一、umask以不同 umask 运行状态umask3002 加入Windows 不可用可以指定某个状态以特定 umask 运行。此前它只属于cmd状态3002 起成为可应用于任意状态的全局参数cleanup_script: cmd.script: - name: salt://myapp/files/my_script.sh - umask: 077 - onchanges: - file: /some/file源码中状态执行处使用了salt.utils.files.set_umask(low.get(__umask__))包裹状态调用salt/state.py 约 2484 行确保整个状态函数体在指定 umask 上下文中运行。十二、实战组合一个完整的条件化部署状态综合上述参数构造一个实际场景——仅当目标为 RedHat 系系统且源码包尚未编译时执行make install成功后复核二进制存在并轮询等待服务端口install apache on redhat based distros: cmd.run: - name: make install - cwd: /path/to/dir/whatever-2.1.5/ - onlyif: - fun: match.grain tgt: os_family:RedHat - unless: - fun: file.file_exists path: /usr/local/bin/whatever - creates: - /usr/local/bin/whatever - runas: buildbot - check_cmd: - test -x /usr/local/bin/whatever各参数分工清晰onlyifAND不是 RedHat 系就直接跳过unless/createsNAND二进制已存在就不再编译runas以buildbot用户执行编译命令check_cmd编译完成后复核二进制是否真实可执行结果不通过则整个状态判为失败。十三、常见陷阱速查shell 布尔语义unless/onlyif/check_cmd都经由cmd.retcode以 shell 执行判定依据是退出码而非 Python 真值命令会以 minion 同权限运行注意命令注入与副作用风险。cmd_opts_exclude3006.0 起若状态参数如user.present的shell/sbin/nologin被透传给检查命令导致误判记得用cmd_opts_exclude排除。check_cmd与file.managed的check_cmd不同前者是全局参数用于整状态结果复核后者是文件状态自身的校验选项。onchanges/watch对 SLS 级 requisite 无效监控某个被 include 的 SLS 的变化没有意义只能监控其中具体的 state ID。watch与mod_watch的触发条件仅当被观察状态resultTrue且changes非空时才调用mod_watch若观察状态的常规运行自身产生了changesmod_watch不会被调用避免非幂等动作执行两次可通过在常规运行中返回force_mod_watch: True强制触发。retry的until默认是True即默认重试直到成功若需要重试直到失败显式设置until: False。exclude与 requisite 冲突用exclude移除某个 state ID 后引用它的 requisite 会被当作引用不存在的状态在编译期报硬错误需要可选依赖时应采用条件 include SLS 的方式。参考与延伸阅读本文骨架Requisites and Other Global State Arguments含 Requisites 匹配规则、真值表与 Altering States 全部参数原入口页Altering States核心实现salt/state.py_run_check、_run_check_onlyif、_run_check_unless、_run_check_creates、_run_check_cmd、retry 循环状态模块实现参考cmd 状态模块含mod_watch与mod_run_check相关扩展点模块重载说明Reloading Modules赞分享运维配置管理后端【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址https://gitcode.com/gh_mirrors/sa/salt点击查看免费下载相关推荐Salt 状态并行执行Parallel States完全指南parallel: True 的用法、原理与避坑要点Salt 状态并行执行Parallel States完全指南parallel: True 的用法、原理与避坑要点 导读 parallel: True 是运维配置管理后端FluentValidation 条件验证指南使用 When / Unless 精确控制规则执行时机FluentValidation 条件验证指南使用 When / Unless 精确控制规则执行时机 在 FluentValidation 中 When 与后端一句话生成完整视频ViMax 多智能体视频创作框架从配置到成片实战一句话生成完整视频ViMax 多智能体视频创作框架从配置到成片实战 ViMax 是一个开源的多智能体Agentic视频生成框架它把编剧、角色设定、分镜设运维配置管理后端上一篇单目3D重建实战指南用MoGe从一张照片生成可测量的点云、深度与法线图下一篇Dependency-Check安全漏洞工具自身的安全加固终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表