咨询SaltStack处理公共依赖的标准模式:单独执行状态时依赖缺失问题
这个问题其实是SaltStack声明式状态系统的特性导致的——当你单独执行state.apply telegraf时,Salt只会加载telegraf相关的state文件,构建依赖图时找不到/var/log/mycompany对应的state定义,哪怕这个目录实际已经存在,它也会判定依赖不满足而失败。下面是几种标准的解决方案,按推荐程度排序:
方案1:使用file.exists检查系统实际状态(最灵活)
把原来直接依赖另一个state的写法,改成检查目录是否实际存在的测试型state。这样不管公共state有没有被执行过,只要目录真实存在,依赖就会通过:
/var/log/jellybooks/telegraf: file.directory: - user: telegraf - group: telegraf - mode: 755 - require: - file: log_dir_exists # 定义一个检查公共目录是否存在的测试state log_dir_exists: file.exists: - name: /var/log/mycompany
file.exists是Salt的执行模块函数,它直接检查系统的实际状态,而不是依赖另一个state的定义。这样即使你单独运行telegraf的state,只要目录已经存在,这个require就会通过;如果目录不存在,它会报错,这也符合你希望确保目录就绪再启动服务的需求。
方案2:在子State中包含公共依赖State
在telegraf的state文件顶部,用include语句引入公共的salt.system.init state,这样执行state.apply telegraf时会自动加载公共state的内容,确保依赖的目录定义被包含在依赖图中:
# 引入公共初始化state include: - salt.system.init /var/log/jellybooks/telegraf: file.directory: - user: telegraf - group: telegraf - mode: 755 - require: - file: /var/log/mycompany
这种方法的好处是完全复用原有的公共state定义,不需要额外修改逻辑,但要注意:如果公共init.sls里还有其他操作(比如系统参数配置、其他目录创建),这些操作也会在执行telegraf state时被运行,可能带来不必要的副作用。如果公共state内容比较单纯,这种方法很简洁。
方案3:使用反向依赖require_in(全局统一管理)
如果你希望在公共state中统一管理所有依赖它的子state,可以用require_in反向声明依赖。修改salt/system/init.sls中的公共目录定义:
/var/log/mycompany: file.directory: - user: root - group: root - mode: 755 # 声明所有依赖这个目录的state - require_in: - file: /var/log/jellybooks/telegraf # 可以继续添加其他依赖的state,比如 - file: /var/log/jellybooks/nginx 等
这样当你执行任何依赖这个目录的子state(比如telegraf)时,Salt会自动检测到反向依赖,先执行公共目录的state,再执行子state。这种方法适合统一管理公共资源的依赖关系,避免在每个子state里重复处理依赖。
为什么原来的写法在state.highstate中正常?
因为state.highstate会加载所有匹配的state文件,包括公共的salt/system/init.sls,所以依赖图中存在/var/log/mycompany的state定义,Salt可以正确解析依赖关系,自然能正常执行。
内容的提问来源于stack exchange,提问作者jma

