- 运维
- 配置管理
- 后端
【免费下载链接】salt
Software to automate the management and configuration of infrastructure and applications at scale.
test.ping是 Salt 生态中使用频率最高的连通性探针之一。本文围绕 salt/resources/ssh/modules/test.py 这一针对ssh资源类型(Resource Type)的执行模块覆盖(execution module override),讲解它如何通过__resource_funcs__["ssh.ping"]()委托机制,让test.ping返回的是目标 SSH 主机的真实连通性而非管理 minion 的存活状态,并顺带说明 Salt Resources 框架下 per-type 执行模块的加载、优先级与扩展方式。读者读完后,既能理解salt -C 'T@ssh:web-01' test.ping的完整执行链路,也能掌握为自定义资源类型编写执行模块覆盖的通用模式。
一、背景:Salt Resources 框架中的执行模块覆盖
Salt Resources(资源类型框架)允许把一个 minion 同时"管理"多个外部资源——例如通过 SSH 管理的远程 Linux/Unix 主机。框架为每种资源类型维护独立的执行模块加载器(per-type loader),并通过目录约定实现"插槽覆盖":
- 资源类型
ssh的覆盖模块存放在salt/resources/ssh/modules/目录下; - 文件名(去掉
.py)即对应执行模块的虚拟名(slot),例如 modules/cmd.py 覆盖cmd、modules/pkg.py 覆盖pkg、modules/state.py 覆盖state、modules/test.py 覆盖test。
这一机制在 doc/topics/resources/authoring/execution_modules.rst 中有完整说明:当一条 job 被派发到某资源类型时,__salt__会先在<rtype>/modules/中查找,找不到的函数才回落到标准的 salt/modules/ 目录。这正是框架设计的核心——为资源类型定制cmd.run、pkg.installed等行为时,无需 fork 标准模块,也无需触碰__virtual__。
二、modules/test.py:一行委托,直通真实 SSH 连通性
salt/resources/ssh/modules/test.py 的源码非常简短,但语义关键。它只定义了一个ping()函数:
def ping(): """ Return ``True`` if the targeted SSH resource is reachable. Delegates to :func:`salt.resources.ssh.ping` via ``__resource_funcs__`` so the result reflects actual SSH connectivity to the remote host rather than the liveness of the managing minion. CLI Example: salt -C 'T@ssh:web-01' test.ping salt -C 'T@ssh' test.ping """ return __resource_funcs__["ssh.ping"]()三个要点值得展开:
1. 位置即加载门控。该文件位于salt/resources/ssh/modules/这一 per-type 覆盖目录,只会被 ssh 资源的加载器发现(通过salt.loader._module_dirs中 per-type 的目录前缀注入),因此不需要__virtual__或__virtualname__门控。这与salt/modules/test.py中标准test模块的加载方式形成鲜明对比。
2. 目录优先级实现"影子遮蔽"。对派发到 ssh 资源的 job 而言,目录顺序优先级使salt.resources.ssh.modules.test遮蔽了标准salt.modules.test模块;而管理 minion 自身(managing minion)的 job 仍使用标准模块。也就是说:同一个test.ping调用,因目标不同而得到不同的语义。
3. 委托而非复制逻辑。ping()通过__resource_funcs__["ssh.ping"]()调用连接模块(connection module,即 salt/resources/ssh/init.py)中定义的ping()。真正的连接逻辑只维护在连接模块一处,覆盖文件纯粹负责"插槽绑定"。
三、__resource_funcs__dunder:连接模块的命名空间入口
__resource_funcs__是资源类型执行模块专用的 loader dunder,它暴露的是连接模块的函数命名空间,按下标<rtype>.<fname>索引。在 doc/topics/resources/authoring/execution_modules.rst 中明确说明:如果连接模块定义了def ping(),覆盖模块内即可用__resource_funcs__["ssh.ping"]()调用——这是覆盖模块触达连接模块助手的规范方式。
类似的 dunder 还包括:
__resource__:{"type": ..., "id": ...},始终在执行模块代码中可用;__grains__:当前资源的 grains(由grains()采集),而非管理 minion 的 grains;__minion__:管理 minion 的标准执行模块 loader,用于覆盖模块确需访问本机资源的情形;__salt__:per-resource 合并 loader(覆盖槽位 + 标准模块兜底)。
modules/test.py顶部的注释还特意强调:这些 dunder 由 per-type loader 在运行时注入(# pylint: disable=undefined-variable),因此不能在模块导入期捕获,只能在函数体内使用。
四、底层实现:ssh.ping()如何判定连通性
连接模块 salt/resources/ssh/init.py 中的ping()(ssh_resource ping())定义如下逻辑:
def ping(): resource_id = _resource_id() try: shell = _make_shell(resource_id, cfg_override={"timeout": 10}) stdout, _stderr, retcode = shell.exec_cmd("echo ping") return retcode == 0 and "ping" in stdout except Exception as exc: log.warning("ssh resource ping() failed for %s: %s", resource_id, exc) return False要点:
- 通过
_make_shell()构造salt.client.ssh.shell.Shell实例,并在本次调用中把连接超时强制设为 10 秒(cfg_override={"timeout": 10}),避免 ping 探测长时间挂起; - 在远端执行
echo ping,以退出码为 0 且输出包含 "ping"作为连通性判据——这是对 SSH 会话可用的最小、最可靠验证; - 任何异常(连接失败、认证失败、超时)都会捕获并返回
False。
也就是说,ssh 资源上的test.ping反映的是"SSH 传输层是否健康",而不是管理 minion 的进程存活状态。这正是modules/test.py模块 docstring 中强调的语义差异。
五、实战:用复合定位符-C对 SSH 资源发起 ping
根据modules/test.py的 CLI 示例,对 ssh 资源执行 ping 的完整命令为:
salt -C 'T@ssh:web-01' test.ping # 单个 ssh 资源 salt -C 'T@ssh' test.ping # 该 minion 管理的全部 ssh 资源其中:
-C使用复合定位符(compound matcher);T@ssh:web-01是资源定位表达式:T@前缀表示按资源类型(type)匹配,ssh为资源类型,web-01为资源 ID(即 Pillar 中hosts下的键);T@ssh则匹配该 minion 下所有 ssh 资源。
资源 ID 由连接模块的discover()返回——即 Pillar 中ssh.hosts的键集合(详见 salt/resources/ssh/init.py 的discover())。向该 Pillar 键增删主机后执行saltutil.refresh_resources,即可热更新 Master 的 Resource Registry,无需重启进程。
六、连接配置:Pillar 中的 ssh 资源声明
ssh 资源的连接参数全部来自 Pillar(顶层键默认为resources,可通过 minion 选项resource_pillar_key覆盖)。在 salt/resources/ssh/init.py 的模块 docstring 中给出了完整示例:
resources: ssh: hosts: web-01: host: 192.168.1.10 user: root priv: /etc/salt/ssh_keys/web-01 web-02: host: 192.168.1.11 user: admin passwd: secretpassword no_host_keys: true每个主机可配置的参数及默认值如下(与_make_shell()/_make_single()的 kwargs 一一对应):
| 参数 | 说明 | 默认值 |
|---|---|---|
host | 远端主机名或 IP(必填) | — |
user | SSH 登录用户 | root |
port | SSH 端口 | 22 |
priv | SSH 私钥文件路径;与passwd互斥语义,但两者可同时给出,设priv时走密钥认证选项串 | 无 |
passwd | SSH 密码;生产环境建议优先使用密钥认证 | 无 |
priv_passwd | 私钥保护口令 | 无 |
sudo | 是否通过 sudo 以 root 执行命令 | False |
timeout | SSH 连接超时(秒) | 30 |
identities_only | 传-o IdentitiesOnly=yes,防止 SSH agent 提供无关密钥 | False |
no_host_keys | 完全关闭主机密钥校验(同时置StrictHostKeyChecking=no与UserKnownHostsFile=/dev/null) | False |
ignore_host_keys | 传-o StrictHostKeyChecking=no,但不丢弃 known_hosts 数据库 | False |
known_hosts_file | 该主机的自定义 known_hosts 文件路径 | 无 |
ssh_options | 原样传给 ssh 二进制的附加-o Key=Value选项列表 | 无 |
keepalive | 启用 TCP keepalive | True |
keepalive_interval | ServerAliveInterval(秒) | Salt opts 或60 |
keepalive_count_max | ServerAliveCountMax | Salt opts 或3 |
底层实现细节:_shell_opts()会把ignore_host_keys、no_host_keys、known_hosts_file逐主机覆盖到__opts__副本之上(Shell是从 opts 字典而非构造 kwargs 读取这些项的),并保证_ssh_version始终存在(_passwd_opts()以[]下标访问该键,缺失会抛KeyError)。ssh 版本在资源类型init()时预解析并缓存到__context__["ssh_resource"],确保 job 执行期间不跑子进程。
七、同类覆盖模块与整体扩展模式
modules/test.py不是孤例,同一目录下的兄弟模块展示了完整的覆盖谱系:
- modules/cmd.py:提供
cmd.run、cmd.run_all、cmd.retcode,全部委托__resource_funcs__["ssh.cmd_run"]。cmd.run返回 stdout 字符串;cmd.run_all返回{stdout, stderr, retcode}字典;cmd.retcode只返回退出码。这是 SSH 资源执行模块的基础构建块(相当于 proxy 模型中__proxy__["ssh_sample.cmd"]()的角色)。对应 CLI:salt -C 'T@ssh:web-01' cmd.run 'uptime'、salt -C 'T@ssh' cmd.run 'df -h' timeout=60。 - modules/pkg.py:实现
pkg.install、pkg.remove、pkg.version、pkg.list_pkgs,根据远端os_familygrain 自动选择apt-get(Debian/Ubuntu)或yum(RedHat/CentOS/Fedora/SUSE),并透传timeout。 - modules/state.py:实现
state.highstate、state.sls、state.apply,在管理 minion 进程内复刻 salt-ssh 的状态执行管线(编译 →prep_trans_tar打包 → SCP 传输 tar → 经 salt-thin 执行state.pkg),通过__func_alias__将apply_映射为apply。
从框架层面看(doc/topics/resources/authoring/execution_modules.rst),为资源类型新增覆盖模块有三种典型模式:
- 只覆盖标准模块中的个别函数——在
modules/pkg.py里只写需要的函数,其余pkg.*槽位继续由标准模块(如salt.modules.aptpkg)填充;优先级是逐函数的; - 重导出标准模块——用
salt.utils.functools.namespaced_function把state.sls等函数复制进覆盖模块 globals,使__salt__等 dunder 在调用期解析到 per-resource loader(modules/state.py即官方示例); - 纯委托连接模块——如
modules/test.py这样的一行转发,连接逻辑集中在__init__.py,覆盖文件只做槽位绑定。
同时要避免三类常见错误:在模块导入期抓取 dunder(NamedLoaderContext 代理仅在函数体内有效);在覆盖模块中重定义__virtualname__(槽位由文件位置决定);绕过 loader 直接import salt.modules.cmdmod调用(会跳过 dunder 注入与 per-resource 上下文)。
八、实现证据与测试佐证
modules/test.py的存在与语义均有明确源码依据:
- 加载门控:模块 docstring 明言"其位于 per-type 覆盖目录,只会被 ssh 资源加载器发现(经由
_module_dirs的 per-type 前缀),因此无需__virtual__门控;派发到 ssh 资源的 job 中,标准salt.modules.test被目录顺序优先级隐藏,管理 minion 的 job 继续使用标准模块"; - 委托语义:
ping()一行代码直接转发__resource_funcs__["ssh.ping"](); - 底层连通性判定:
ssh.ping()在 salt/resources/ssh/init.py 中通过Shell.exec_cmd("echo ping")与 10 秒调用级超时实现; - 文档注册:该模块被登记在 doc/ref/resources/all/index.rst 的资源类型子模块目录树中(与
salt.resources.ssh.modules.cmd、pkg、state并列),对应的 API 参考页为 doc/ref/resources/all/salt.resources.ssh.modules.test.rst。
仓库内针对 SSH 资源的集成测试(tests/pytests/integration/resources_ssh/ 与 tests/pytests/unit/resources/test_ssh_resource.py)覆盖了资源注册、连接参数解析等链路,可作为进一步阅读与验证的入口。需要说明的是,ssh 资源类型的完整运行依赖 minion 上存在ssh二进制(连接模块通过salt.utils.path.which("ssh")做加载门控),本文所述机制均以当前仓库源码为基准。
小结
salt.resources.ssh.modules.test是理解 Salt Resources 执行模块覆盖机制的最小、最完整的标本:一个文件、一个函数、一行委托,背后却是"目录位置 = 加载门控"、"目录优先级 = 槽位遮蔽"、"__resource_funcs__= 连接模块命名空间"三大框架设计。掌握了它,你就能以此为模板,为自己的资源类型快速定制test、cmd、pkg、state乃至任意执行模块的远端语义。
- 运维
- 配置管理
- 后端
【免费下载链接】salt
Software to automate the management and configuration of infrastructure and applications at scale.
相关推荐
Salt 资源框架中的 `dummy` 类型执行模块覆盖:深入解析 `salt.resources.dummy.modules.test`
Salt 资源框架中的 dummy 类型执行模块覆盖:深入解析 salt.resources.dummy.modules.test salt.resources
运维配置管理后端Salt SSH 资源执行模块 cmd:无代理远程命令执行的源码级解析
Salt SSH 资源执行模块 cmd:无代理远程命令执行的源码级解析 导读 本文聚焦 salt.resources.ssh.modules.cmd 执行模块
运维配置管理后端Salt 代理 Minion 的 SSH 服务执行模块(salt.modules.ssh_service)深度解析
Salt 代理 Minion 的 SSH 服务执行模块(salt.modules.ssh_service)深度解析 导读 salt.modules.ssh_se
运维配置管理后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考