SaltStack Oxygen版本top.sls中file.find获取目录列表异常排查
你的问题核心在于**salt['file.find']搭配print='name'返回的是多行字符串,而非你预期的Python列表**,这导致for循环遍历的是字符串的每个字符,而非每个目录名,最终生成的pillar匹配规则完全不符合预期。
为什么会这样?
当你使用print='name'参数时,file.find模块会将结果格式化为人类可读的多行字符串(每个目录名占一行),而不是返回结构化的列表数据。比如如果/srv/salt/projects下有一个expected目录,它返回的是字符串u'expected'(Python 2中的Unicode字符串),而非列表['expected']。
你看到注释行#[u'expected']就是最好的证明:这是把字符串转成字符串表示时的输出,而硬编码的列表会显示为#['expected']。当你对这个字符串做for prj in prjlist循环时,其实是在逐个遍历字符,自然无法生成正确的role:{{ prj }}_server规则。
修正方案
这里有两种可靠的方法获取目录列表:
方案1:利用file.find的结构化输出生成列表
去掉print='name'参数,file.find会返回包含目录详细信息的字典列表,我们可以通过列表推导式提取每个目录的name字段:
{%- set prjlist = [item['name'] for item in salt['file.find']('/srv/salt/projects', type='d', mindepth=1, maxdepth=1)] %} # {{ prjlist }} {%- for prj in prjlist %} 'role:{{ prj }}_server': - match: pillar - projects.{{ prj }}.server {%- endfor %}
这种方法直接利用file.find的结构化数据,无需额外处理,是最推荐的方式。
方案2:用file.listdir结合目录判断
如果你觉得file.find的写法不够直观,也可以用file.listdir获取目录下的所有条目,再过滤出子目录:
{%- set prj_dir = '/srv/salt/projects' %} {%- set prjlist = [name for name in salt['file.listdir'](prj_dir) if salt['file.isdir'](salt['path.join'](prj_dir, name))] %} # {{ prjlist }} {%- for prj in prjlist %} 'role:{{ prj }}_server': - match: pillar - projects.{{ prj }}.server {%- endfor %}
这里用salt['path.join']拼接路径,避免手动拼接字符串可能出现的错误,再通过file.isdir判断是否为目录。
验证方法
修改后,你可以再次执行salt-call -l debug state.show_highstate,查看渲染后的注释行是否显示为#['expected'](和硬编码列表一致),同时检查生成的pillar匹配规则是否正确。
内容的提问来源于stack exchange,提问作者pwan

