ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Salt 状态系统执行模块 state 全解析:从 highstate 应用到源码级原理

Salt 状态系统执行模块 state 全解析:从 highstate 应用到源码级原理 运维配置管理后端【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址https://gitcode.com/gh_mirrors/sa/salt点击查看免费下载本篇技术指南以 Salt 仓库中 doc/ref/modules/all/salt.modules.state.rst 所对应的 salt/modules/state.py 为核心系统讲解 Salt 状态系统在 minion 端的所有执行入口state.apply、state.highstate、state.sls、state.single、state.top以及队列、暂停、禁用、请求等高级控制能力。读完本文你将掌握每一个状态执行函数的作用、参数含义与 CLI 用法并能结合源码理解 Salt 状态系统底层的工作机制。1. 模块概览state 模块在 Salt 中的定位salt.modules.state是 Salt 中在 minion 上控制系统状态State System的核心执行模块。它负责把 SLS 状态文件编译成可执行的数据并在目标机器上逐一落实。模块头部 docstring 说明了其关键设计——状态缓存State Caching当一次 highstate 被调用时minion 会自动缓存一份最近一次的高数据high data。如果之后以cacheTrue运行 highstate就会使用这份缓存的高数据除了状态自身内部的salt://链接之外不再访问 fileserver。从 salt/modules/state.py 的源码可见该模块通过__virtualname__ state第 70 行定义虚拟名并声明__proxyenabled__ [*]第 48 行意味着它可以在所有 proxy minion 环境下运行。同时它通过__outputter__第 50-64 行把几乎所有执行函数统一映射到highstate输出器保证返回数据的展示风格一致。模块还通过__func_alias__ {apply_: apply}第 66 行将内部函数apply_对外暴露为state.apply。与大多数执行模块不同这里的函数大多直接使用salt.state.HighState或salt.state.State类定义于 salt/state.py来完成从高数据编译到低数据执行的全过程。2. 最常用的入口state.apply 与 state.highstate2.1 state.apply统一、直观的入口state.apply源码实现为apply_第 773 行自 2015.5.0 引入是官方推荐的日常状态执行入口。它的行为取决于参数不传任何 SLS 目标等价于执行state.highstate应用top.sls中为该 minion 配置的所有状态。传入 SLS 文件列表等价于执行state.sls只应用指定的 SLS 文件。源码第 981-983 行清晰地展示了这一分发逻辑if mods: return sls(mods, **kwargs) return highstate(**kwargs)应用 top.sls 中配置的全部状态salt * state.apply应用单个 SLS 文件salt://stuff.sls或salt://stuff/init.slssalt * state.apply stuff应用多个 SLS 文件salt * state.apply stuff,pkgs应用深层嵌套目录中的 SLSsalt * state.apply my.organized.stuffstate.apply同时接受以下常用参数完整参数说明见 源码 docstring参数默认值作用test—以 dry-run测试模式运行状态只报告将要做的更改而不实际执行mockFalse完全不调用任何状态返回模拟结果用于校验 requisite 顺序与状态编排2015.8.4 起pillar—以字典形式传入自定义 Pillar 值会覆盖pillar_roots或外部 Pillar 源的同名值exclude—排除特定状态接受 SLS 名列表、逗号分隔字符串或含sls/id键的字典列表支持 glob 通配queueFalse当有另一个状态运行在进行时排队等待而非直接失败详见第 6 节concurrentFalse允许状态并发执行危险仅用于可安全并行的场景不可用于性能优化saltenvbase若未配置指定使用的 fileserver 环境pillarenv—指定 Pillar 环境minion 配置中的pillarenv也可设置localconfig—使用指定文件中的 minion 配置并与现有配置合并可让特定状态用独立的自定义配置运行sync_mods—运行 SLS 前同步指定类型的自定义模块如sync_modsstates,modules或sync_modsall2017.7.8 起state_events—状态运行中每个函数完成时发送进度事件3006.0 起2.2 state.highstate执行完整状态编排state.highstate第 1138 行从 master 检索该 minion 的状态数据并执行——即应用top.sls中匹配该 minion 的所有状态。# 应用 top.sls 中配置的全部状态 salt * state.highstate # 只运行白名单中的 SLS salt * state.highstate whitelistsls1_to_run,sls2_to_run # 排除指定 SLS salt * state.highstate excludesls_to_exclude # 传递自定义 Pillar salt * state.highstate pillar{foo: Foo!, bar: Bar!}执行流程源码第 1324-1358 行highstate会创建salt.state.HighState实例并进入上下文管理器随后依次完成检查 Pillar 渲染错误_get_pillar_errors出错返回EX_PILLAR_FAILUREst_.push_active()标记自身为活跃状态防止并发重复执行可选地创建 snapper pre 快照受snapper_states配置控制st_.call_highstate(...)编译并执行全部高数据若配置state_data: terse或传入terseTrue过滤掉结果成功且无更改的条目_filter_running第 88 行_set_retcode根据结果设置退出码最后创建 snapper post 快照。state.highstate支持exclude的三种写法与state.apply一致salt * state.highstate excludebar,baz salt * state.highstate excludefoo* salt * state.highstate exclude[{id: id_to_exclude}, {sls: sls_to_exclude}]从源码看exclude最终以high_[__exclude__]的形式注入高数据见 sls 函数第 1624-1629 行在编译阶段被剔除。2.3 防呆助手state.teststate.test第 986 行2017.7/3001 起是state.apply的别名但强制testTrue避免手误漏写testTrue造成意外变更salt * state.test源码实现非常简单——把kwargs[test] True后直接转调apply_。3. 精确执行state.sls、state.sls_id 与 state.single3.1 state.sls执行指定的 SLS 文件state.sls第 1361 行执行一个或多个指定的 SLS 文件# 执行 salt://core.sls或 salt://core/init.sls与 salt://edit/vim.sls salt * state.sls core,edit.vim # 执行深层嵌套的 SLS salt * state.sls my.nested.state # 指定 saltenv 与自定义 Pillar salt * state.sls myslsfile pillar{foo: Foo!, bar: Bar!} saltenvdevsls执行的关键流程源码第 1596-1667 行render_highstate({opts[saltenv]: mods})渲染指定 SLS 为高数据若有exclude追加到high_[__exclude__]st_.state.call_high(high_, orchestration_jid)编译低数据并执行结果写入cachedir/sls.p同时把高数据缓存到cachedir/cache_name.cache.p默认highstate.cache.p供后续cacheTrue运行复用。此外sls会在执行前处理sync_mods参数源码第 1555-1570 行把输入拆分为列表、去重为[all]后逐个调用saltutil.sync_type实现运行前同步自定义模块。3.2 state.sls_id只执行某个 IDstate.sls_id第 2036 行2014.7.0 起从指定的一个或多个 SLS 模块中调用单个状态 ID并处理其全部 requisite。注意命令行中ID 在模块名之前# 只执行 my_module 中 id 为 my_state 的状态含其 requisite salt * state.sls_id my_state my_module # 在多个模块中查找该 ID salt * state.sls_id my_state my_module,a_common_module若指定 ID 未在 SLS 中找到函数会抛出SaltInvocationError提示No matches for ID my_state found in SLS ... within saltenv ...源码第 2160-2165 行。3.3 state.single单条命令式状态执行state.single第 2506 行直接执行单个状态函数不需要任何 SLS 文件。kwargs 默认按 YAML 解析也支持 JSON 格式salt * state.single pkg.installed namevim源码内部会把fun按点号拆成state与fun两部分comps fun.split(.)组装出{state: pkg, fun: installed, __id__: vim, name: vim}这样的低数据块然后交给st_.verify_data(kwargs)校验、st_.call(kwargs)执行。若传入的函数名不含点号少于两段直接返回Invalid function passed。4. 预览与调试show_* 系列函数Salt 提供一组以show_开头的函数用于在不实际执行的情况下查看将要应用的状态数据是排查 SLS 编写问题的重要工具。函数作用示例state.show_highstate显示该 minion 在 highstate 下将应用的全部高数据salt * state.show_highstatestate.show_lowstate列出将应用到该 minion 的低数据low data列表salt * state.show_lowstatestate.show_sls显示指定 SLS 的状态数据不支持 top 文件salt * state.show_sls core,edit.vim saltenvdevstate.show_low_sls显示指定 SLS 编译后的低数据salt * state.show_low_sls foo saltenvdevstate.show_top返回 highstate 将使用的 top 数据即 top.sls 中匹配的条目salt * state.show_topstate.show_states返回 highstate 将应用的状态文件列表2019.2.0 起salt * state.show_statesstate.show_state_usage分析 highstate 数据中已使用/未使用的状态salt * state.show_state_usage其中show_highstate调用st_.compile_highstate()show_lowstate调用st_.compile_low_chunks()show_states则基于compile_low_chunks()的结果收集每个 chunk 的__sls__字段并去重源码第 2014-2033 行。它们都不会触发任何实际的状态变更适合在发布前做静态预览。与预览配套的还有两个存在性检测函数均 2019.2.0 起# 检查 SLS 文件是否存在 salt * state.sls_exists core,edit.vim saltenvdev # 检查指定 ID 是否存在于指定 SLS 中 salt * state.id_exists create_myfile,update_template filestate saltenvdev从源码看sls_exists实现为show_sls的返回值是否为 dict第 2434 行id_exists则把show_low_sls返回的所有__id__收集成集合判断目标 ID 集合是否是其子集第 2456-2461 行。5. 依赖图state.graph 与 state.graph_highstateSalt 可以把状态的依赖关系渲染为DOT 格式的依赖图便于直观检查 requisite 编排# 显示单个/多个 SLS 的依赖图DOT 格式 salt * state.graph core,edit.vim saltenvdev # 显示整个 highstate 的依赖图 salt * state.graph_highstate两者都可以用 Graphviz 渲染成图片salt * state.graph_highstate --outtxt | dot -Tpng -o highstate.png salt * state.graph core --outtxt | dot -Tpng -o state_graph.png源码层面graph先复用show_sls取得高数据再通过st_.compile_high_data(high)构建st_.dependency_dag并输出to_dot()第 2393-2412 行graph_highstate则先compile_highstate()再走相同路径第 1839-1908 行。注意非 dict 的返回如编译错误列表会原样返回不会尝试生成图。6. 并发控制queue、running 与并发防护6.1 冲突检测与 state.runningSalt 默认串行执行状态防止同一 minion 上多个状态任务互相干扰。state.running第 378 行返回当前正在运行的状态信息salt * state.running源码实现通过saltutil.is_running(state.*)获取活跃任务并跳过当前 JID__opts__.get(jid)以避免把自身误判为冲突——这个细节避免了state.apply(queueFalse)时因进程表中的占位符而产生误报源码第 395-398 行的注释专门说明了这一点。6.2 队列机制queue 参数与 state_queue 配置当有状态运行在进行时默认行为是直接失败。设置queueTrue则会把新任务排队等前一个完成后自动开始salt * state.apply stuff queueTrue从源码_check_queue第 474 行可以看到队列是基于磁盘的 FIFO 队列冲突时把任务信息fun、arg、tgt、jid、user、kwarg 等序列化写入state_queue_dir下的queued_微秒时间戳_jid.p文件文件名的时间戳保证 FIFO 顺序由后台线程取出执行排队中的任务执行时绕过process_count_max限制避免被其他负载饿死。自 3006.0 起该参数还能通过 minion 配置 conf/minion 中的state_queue统一设置且可传入整数表示允许排队的最大任务数超出则拒绝入队防止无限开启新线程拖垮系统相关说明见 conf/minion 第 610-618 行# conf/minion 中的默认配置默认关闭 # state_queue: False需要提醒的是concurrentTrue是另一条路径——它直接跳过冲突检查允许并发但官方在 docstring 中明确警告该标志potentially dangerous只应在多个状态运行可以安全并行的场景使用不要用它做性能优化。队列的配套函数还有_wait第 130 行当queue为整数即max_queue时保留阻塞式等待行为在队列锁保护下轮询_prior_running_states直至先前任务全部结束或达到最大队列深度。7. 运行中控制pause、resume、soft_killSalt 支持对正在运行的状态任务进行暂停、恢复和软终止。这些函数需要传入运行中的 JID# 暂停整个状态运行 salt * state.pause 20171130110407769519 # 暂停到指定 state_id 之前例如 vim salt * state.pause 20171130110407769519 vim # 带时长暂停20 秒 salt * state.pause 20171130110407769519 vim 20 # 恢复 salt * state.resume 20171130110407769519 salt * state.resume 20171130110407769519 vim # 软终止在执行到给定 state_id 前安全退出 salt * state.soft_kill 20171130110407769519 salt * state.soft_kill 20171130110407769519 vim # 查看当前所有暂停任务 salt * state.get_pauses注意 state_id 是指 SLS 中定义的 ID例如vim: pkg.installed: []这里传给pause/soft_kill的 state_id 就是vim。实现上这些控制基于cachedir/state_pause/jid目录下的 msgpack 数据文件_get_pause第 186 行。soft_kill写入kill: True标记pause写入可选的duration秒数resume则弹出对应 state_id 的条目。get_pauses第 208 行在列出暂停信息时会先检查任务是否仍在运行已结束任务的暂停文件会被自动清理。8. 请求执行state.request 与 run_requestSalt 支持先请求、后执行的异步管理模式2015.5.0 起# 在 minion 上请求执行以 test 模式预演并把请求写入缓存 salt * state.request salt * state.request stuff salt * state.request stuff,pkgs # 查看当前挂起的请求 salt * state.check_request # 执行挂起的请求执行后请求文件被清除 salt * state.run_request # 清除请求而不执行 salt * state.clear_request从源码看request第 1001 行先以testTrue调用apply_得到预演结果然后把{name: {test_run: ret, mods: mods, kwargs: kwargs}}序列化写入cachedir/req_state.p。run_request第 1107 行读取该文件、去掉test标记后真正执行成功后删除请求文件。这一机制适用于由本地管理员稍后通过salt-call state.run_request触发执行的场景。9. 状态缓存cache 参数与 clear_cache前文提到执行 highstate 或 sls 时 minion 会把高数据缓存到cachedir/*.cache.p文件。配合cacheTrue运行可以完全绕过 fileserversalt://链接除外# 使用缓存的 highstate 数据执行不访问 fileserver salt * state.highstate cacheTrue # 强制清理所有状态缓存文件 salt * state.clear_cacheclear_cache第 2582 行会遍历cachedir删除所有以.cache.p结尾的文件并返回被删除的文件名列表。需要注意的是默认状态下该缓存功能是完全禁用的只有在调用状态时显式传cacheTrue才会写入并复用缓存。从 sls 函数第 1603-1608 行的代码可以看到命中缓存时直接call_high返回不再渲染 SLS。10. 模板与底层测试接口template、low、high以下函数面向模板渲染与系统自测场景state.template第 693 行直接处理minion 本地路径上的模板文件不经过 master。注意路径无需也不应以salt://开头且函数内部会自动补.sls后缀salt * state.template Path to template on the minionstate.template_str第 746 行执行内嵌在字符串中的 SLS 模板salt * state.template_str Template Stringstate.low第 591 行与state.high第 640 行分别执行单条低数据调用和一组高数据调用docstring 明确说明它们主要用于测试状态系统日常使用中不太可能用到salt * state.low {state: pkg, fun: installed, name: vi} salt * state.high {vim: {pkg: [installed]}}从源码看low用salt.state.State实例的verify_data校验数据后调用callhigh则校验 pillar 类型后调用call_high。这两个函数与single一样是状态系统核心执行链路的底层测试入口。11. 特殊执行方式top、orchestrate 与 pkg11.1 state.top执行指定的 top 文件state.top第 1670 行执行一个指定的 top 文件而非默认的top.sls适合在不修改默认 top 的情况下切换 dev/prod 等不同环境salt * state.top reverse_top.sls salt * state.top prod_top.sls excludesls_to_exclude salt * state.top dev_top.sls exclude[{id: id_to_exclude}, {sls: sls_to_exclude}]实现上它把st_.opts[state_top]设置为传入的 top 文件 URL并支持通过saltenv指定 top 文件所在的 fileserver 环境st_.opts[state_top_saltenv]随后走与 highstate 相同的call_highstate路径。11.2 state.orchestratemasterless 编排state.orchestrate第 347 行2016.11.0 起允许在masterless minionsalt-call --local上执行原本属于 runner 的 orchestrate 编排salt-call --local state.orchestrate webserver salt-call --local state.orchestrate webserver saltenvdev testTrue salt-call --local state.orchestrate webserver saltenvdev pillarenvaws它本质上是对salt.runners.state.orchestrate的包装模块通过salt.utils.functools.namespaced_function把 runner 中的orchestrate函数引入当前命名空间见__virtual__第 73-85 行支持mods、saltenv、test、exclude、pillar、pillarenv等参数。11.3 state.pkg打包状态运行state.pkg第 2607 行执行一个本地 tarball 打包的状态运行该 tarball 可由 salt-ssh 生成salt * state.pkg /tmp/salt_state.tgz 760a9353810e36f6d81416366fc426dc md5调用需提供 tarball 路径、哈希值与哈希类型。源码做了多层安全与完整性校验文件不存在或哈希不匹配直接返回{}解包前检查每个成员路径若以/或../开头、或包含../片段则拒绝解包防止路径穿越解包后读取lowstate.json作为低数据、可选的pillar.json作为 Pillar 覆盖、可选的roster_grains.json作为 grains以fileclient local、临时目录为file_roots的方式构造salt.state.State执行。12. 状态禁用disable、enable 与 list_disabledSalt 支持动态禁用/启用状态运行包括整个 highstate 或某个 SLS# 禁用 highstate salt * state.disable highstate # 禁用多个状态 salt * state.disable highstate,test.succeed_without_changes # 按 SLS 名禁用与 state.sls 传参一致 salt * state.disable bind.config # 重新启用 salt * state.enable highstate salt * state.enable test.succeed_without_changes # 列出当前禁用的状态 salt * state.list_disabled实现要点禁用状态列表持久化在 grainstate_runs_disabled中grains.setval写入disable与enable修改后都会调用saltutil.refresh_modules()刷新模块。内部辅助函数_disabled第 2796 行支持xxx.*前缀通配匹配——例如禁用bind.*会拦截所有以bind.开头的 SLS。当 highstate 被禁用时state.highstate会直接返回一个result: False、comment: Disabled的结果并在日志中提示To re-enable, run state.enable highstate源码第 1256-1268 行。13. 事件监听state.eventstate.event第 2851 行2016.3.0 起阻塞监听 Salt 事件总线直到匹配指定 tagsalt-call --local state.event prettyTrue主要参数源码 docstring 与签名参数默认值作用tagmatch*事件 tag 的 glob 或正则2019.2.0 起支持正则count-1匹配次数计数-1表示持续监听quietFalse不打印到 stdout仅阻塞sock_dir—master 事件 socket 路径prettyFalseFalse时单行 JSON便于 shell 处理True时美化缩进nodeminion监听 minion 侧或 master 侧事件总线实现上通过salt.utils.event.get_event(..., listenTrue, auto_reconnectTrue)获取事件流用expr_match匹配 tag匹配到的事件以tagTABjson格式输出。值得注意的一个实现细节事件的 JSON 序列化使用了_json_safe第 2837 行作为default回调——当事件载荷中混有原始bytes例如x509.sign_remote_certificate返回的 DER 编码证书不是合法 UTF-8时会转成 base64 的 ASCII 字符串输出保证事件流始终是合法 JSON。tests/pytests/unit/modules/test_state.py中的test_event_handles_binary_payload第 346 行正是对这一行为的回归测试。14. 测试与质量保障模块的核心行为在单元测试 tests/pytests/unit/modules/test_state.py 中有系统覆盖可作为理解语义的补充证据test_get_initial_pillar第 30 行与test_check_test_value_is_boolean第 44 行验证 Pillar 快照与test标志的解析逻辑test_check_queue_*系列第 59、142、210、269、299 行覆盖队列冲突检测其中test_check_queue_preserves_master_jid_69386验证排队任务保留 master 分配的 JID对应源码中 issue #69386 的修复test_check_queue_mints_jid_for_saltcall_when_no_pub_jid验证本地调用场景下才生成新 JID——这保证了 master 端的任务追踪returners、jobs runner、syndic 转发始终以 master 发布的 JID 为键不会被 minion 端的新 JID 打断test_event_handles_binary_payload验证事件输出的二进制安全。15. 总结如何选择正确的执行入口综合以上分析可以从执行粒度维度做如下选择需求推荐入口应用 top.sls 中全部状态state.apply无参数/state.highstate应用指定 SLS 文件state.apply sls/state.sls只执行某个 ID含 requisitestate.sls_id不写 SLS直接执行单个状态函数state.single执行指定 top 文件state.top预览将应用的数据state.show_*系列查看依赖图state.graph/state.graph_highstate排队/暂停/恢复/终止运行中任务queue参数、state.pause、state.resume、state.soft_kill请求-延迟执行state.request/state.run_request禁用/启用状态state.disable/state.enable所有执行类函数最终都汇聚到salt.state.HighState与salt.state.State两个核心类见 salt/state.pyHighState负责从 master/fileserver 获取并渲染 SLS 为高数据State负责把高数据编译成低数据low chunks并逐条执行、处理 requisite 与监听器。理解这一分层后无论通过哪个入口调用都能清楚地预判状态系统在 minion 端的行为路径。赞分享运维配置管理后端【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址https://gitcode.com/gh_mirrors/sa/salt点击查看免费下载相关推荐使用 Salt State 调用 Ansibleansiblegate 状态模块深度解析使用 Salt State 调用 Ansibleansiblegate 状态模块深度解析 在 Salt 与 Ansible 并存的基础设施中通过 salt.运维配置管理后端Salt Windows 用户组管理实战win_groupadd 执行模块与 group 状态模块全解析Salt Windows 用户组管理实战win_groupadd 执行模块与 group 状态模块全解析 导读 本文围绕 Salt 官方文档 salt.mod运维配置管理后端Kilo VS Code 扩展后台 Agent 可见性任务卡滚动离屏后的会话级子代理监控方案Kilo VS Code 扩展后台 Agent 可见性任务卡滚动离屏后的会话级子代理监控方案 本文基于 Kilo 仓库中 packages/kilo vsco运维配置管理后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表