Salt 源码级解析rpm_lowpkg 执行模块——RPM 包管理的底层查询引擎【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址: https://gitcode.com/gh_mirrors/sa/salt导读salt.modules.rpm_lowpkg是 Salt 在 RPM 系发行版RHEL/CentOS、Fedora、openSUSE/SLES 等上执行包管理任务的底层执行模块虚名为lowpkg。它封装了rpm命令的查询、校验、文件归属与版本比较能力是yumpkg、pkg等高层状态模块在 RPM 平台上的数据来源。读完本文你将掌握该模块的加载条件、全部 11 个核心函数的参数语义与 CLI 用法并理解其与salt.utils.pkg.rpm工具层的协作原理可直接在 minion 上通过salt * lowpkg.*完成包信息审计与完整性校验。一、模块定位RPM 系发行版的 lowpkg 虚名在 Salt 的执行模块体系中lowpkg是低级包管理low-level package manager的抽象命名yumpkg、dnf等高级模块负责软件源解析与依赖求解而具体的 RPM 数据库查询、文件归属判定等脏活则统一委托给lowpkg。本模块源码位于 salt/modules/rpm_lowpkg.py对应的 API 文档入口为 doc/ref/modules/all/salt.modules.rpm_lowpkg.rst该文档通过automodule指令自动从模块 docstring 生成全部成员文档。1.1 虚名注册与平台约束模块顶部将虚名定义为__virtualname__ lowpkg__virtual__()函数负责在加载时判定当前平台是否支持该模块salt/modules/rpm_lowpkg.py#L31-L67判定逻辑如下系统中必须存在rpm二进制通过salt.utils.path.which(rpm)检测否则返回(False, rpm binary is not in the path.)必须能从 grains 中读取os与os_familyos_family属于redhat或suse或osgrain 命中以下白名单之一amazon、xcp、xenserver、virtuozzolinux、virtuozzo、issabel pbx、openeuler、vmware photon os也就是说除了经典的 RedHat/SUSE 两大系外openEuler、Photon OS、XenServer、Virtuozzo 等以 RPM 为基础的发行版同样会加载本模块。测试 tests/pytests/unit/modules/test_rpm_lowpkg.py#L34-L62 专门验证了 openEuler、Issabel Pbx、Virtuozzo 以及无 rpm 二进制时返回 False 元组四种加载场景。使用前提本模块仅在 RPM 系系统上可用在 Debian/Ubuntu 上对应的是dpkg_lowpkg。跨平台通用能力请走pkg.*状态与执行模块。二、包信息查询bin_pkg_info 与 list_pkgs2.1 bin_pkg_info解析未安装的 RPM 文件元数据bin_pkg_info(path, saltenvbase)用于直接解析一个 RPM 包文件无需安装并返回其元数据字典salt/modules/rpm_lowpkg.py#L70-L125自 Salt 2015.8.0 起可用。path 参数支持两种形式形式说明本地绝对路径如/root/salt-2015.5.1-2.el7.noarch.rpm要求文件真实存在于 minion 上Salt fileserver URL如salt://salt-2015.5.1-2.el7.noarch.rpm会先通过cp.cache_file缓存到 minion 再解析当传入salt://协议路径时模块先调用__salt__config.valid_fileproto判断协议有效性再调用cp.cache_file拉取文件若缓存失败抛出CommandExecutionError。本地路径则校验os.path.exists与绝对路径os.path.isabs否则分别抛出CommandExecutionError或SaltInvocationError。底层实现模块使用rpm -qp --queryformat读取包头信息查询格式复用工具层的QUERYFORMAT# salt/utils/pkg/rpm.py#L59 QUERYFORMAT %{NAME}_|-%{EPOCH}_|-%{VERSION}_|-%{RELEASE}_|-%{ARCH}_|-%{REPOID}_|-%{INSTALLTIME}由于%{REPOID}对未安装的 rpm 文件不是合法标签调用前会将其替换为字符串none。输出随后交给salt.utils.pkg.rpm.parse_pkginfosalt/utils/pkg/rpm.py#L118-L148解析按_|-分隔符拆分出 name/epoch/version/release/arch/repoid/install_time再组合为PkgInfonamedtuple其字段为name, version, arch, repoid, install_date, install_date_time_t。返回值中的version会按规则拼接有 release 时追加-releaseepoch 非(none)/0时以epoch:version形式前缀。CLI 示例salt * lowpkg.bin_pkg_info /root/salt-2015.5.1-2.el7.noarch.rpm salt * lowpkg.bin_pkg_info salt://salt-2015.5.1-2.el7.noarch.rpm2.2 list_pkgs枚举已安装包list_pkgs(*packages, **kwargs)返回已安装包字典{package_name: version}salt/modules/rpm_lowpkg.py#L128-L156不传包名时执行rpm -qa传包名时执行rpm -q pkg...查询格式固定为%{NAME} %{VERSION}\n支持root关键字参数用于指定 RPM 数据库的顶层目录默认/常用于 chroot 环境输出中形如package is not installed的行会被跳过不纳入结果。salt * lowpkg.list_pkgs salt * lowpkg.list_pkgs root/mnt/chroot单元测试 tests/pytests/unit/modules/test_rpm_lowpkg.py#L68-L86 验证了默认调用与带root/调用时命令确实以rpm --root /开头。三、包完整性校验verify 与 modified3.1 verify逐文件校验属性verify(*packages, **kwargs)封装rpm -Va/rpm -V pkg返回每个文件与其 RPM 数据库记录的差异salt/modules/rpm_lowpkg.py#L159-L253。关键参数ignore_types忽略特定文件属性类型的差异可取config、doc、ghost、license、readme对应 rpm 输出中的c d g l r标记支持列表或逗号分隔字符串verify_options透传给 rpm 的--选项列表同样支持列表或逗号分隔字符串rootRPM 数据库顶层目录。返回结构字典以文件路径为键值为{mismatch: [...]}若文件缺失则改为{missing: True}。mismatch列表中的元素来自 rpm 校验位S M 5 D L U G T P分别映射为校验位含义Ssize大小变化Mmode权限变化5md5sum内容校验和变化Ddevice major/minor numberLreadlink path符号链接目标变化Uuser属主变化Ggroup属组变化Tmtime修改时间变化Pcapabilities能力位变化当ignore_types命中某文件类型如config时该文件会被整体跳过校验命令失败且无 stdout 时会抛出CommandExecutionError。salt * lowpkg.verify salt * lowpkg.verify httpd salt * lowpkg.verify httpd postfix salt * lowpkg.verify httpd postfix ignore_types[config,doc]3.2 modified仅列出被修改的文件modified(*packages, **flags)自 Salt 2015.5.0 起执行rpm -Va后返回被修改文件 → 修改点列表的字典salt/modules/rpm_lowpkg.py#L256-L339每个文件的修改点取自size/mode/checksum/device/symlink/owner/group/time/capabilities九个维度旧版 RPM 不支持 capabilities 时自动补齐保证位置对齐配置文件rpm 输出三列格式会额外追加config标记返回码大于 1 视为命令执行失败直接返回错误字典返回码 0 表示无修改返回空字典支持按维度过滤传入flags如checksumTrue、modeFalse时只返回满足指定为 True 的维度确实被修改、指定为 False 的维度未被修改条件的文件_开头的参数被忽略。salt * lowpkg.modified httpd salt * lowpkg.modified httpd postfix salt * lowpkg.modified # 全系统被修改文件四、文件归属与包文件清单owner、file_list、file_dict4.1 owner查询文件属于哪个包owner(*paths, **kwargs)封装rpm -qf --queryformat %{name} pathsalt/modules/rpm_lowpkg.py#L419-L454传单个路径时返回包名字符串传多个路径时返回{path: pkgname}字典文件未被任何包拥有、或文件在 minion 上不存在时对应路径返回空字符串支持root参数。salt * lowpkg.owner /usr/bin/apachectl salt * lowpkg.owner /usr/bin/apachectl /etc/httpd/conf/httpd.conf4.2 file_list / file_dict列出包内文件file_list(*packages)执行rpm -ql pkg不带包名时为rpm -qla返回{errors: [], files: [...]}salt/modules/rpm_lowpkg.py#L342-L371file_dict(*packages)先查询各包版本再逐个执行rpm -ql返回{errors: [...], packages: {pkg: {version: v, files: [...]}}}结构salt/modules/rpm_lowpkg.py#L374-L416按包分组更便于状态判断。两函数都支持root参数不带包名时会枚举 RPM 数据库中的全部文件官方 docstring 明确标注not generally recommended一般不建议这么做数据量巨大。salt * lowpkg.file_list httpd salt * lowpkg.file_dict httpd postfix五、包文件与已安装版本对比diffdiff(package_path, path)返回 RPM 包内原始文件与当前已安装文件的格式化 diffsalt/modules/rpm_lowpkg.py#L457-L486自 Salt 2015.8.0 起可用package_pathRPM 包文件的完整路径path已安装文件的完整路径函数被which(rpm2cpio)、which(cpio)、which(diff)三个装饰器保护任一工具缺失则函数不可用底层管道为rpm2cpio rpm | cpio -i --quiet --to-stdout .path | diff -u ...即从包内提取原始文件并与磁盘上当前文件做 unified diff覆盖配置文件与非配置文件二进制内容无法 diff此时返回提示File path is binary and its content has been modified.。salt * lowpkg.diff /path/to/apache2.rpm /etc/apache2/httpd.conf该函数在 salt/modules/yumpkg.py#L3637 中被yumpkg的 verify 相关逻辑调用用于在包验证时展示本地文件与包内原始内容的差异。六、包元数据审计infoinfo(*packages, **kwargs)返回包的详细元数据salt/modules/rpm_lowpkg.py#L489-L678不传包名时返回所有已安装包的信息。attr 参数逗号分隔的属性白名单合法取值包括version, vendor, release, build_date, build_date_time_t, install_date, install_date_time_t, build_host, group, source_rpm, arch, epoch, size, license, signature, packager, url, summary, description未指定attr时返回全部可用属性name与edition总是被自动附加edition的格式为epoch:version-release无 epoch 时省略用于内部排序指定了无效属性集合时会抛出CommandExecutionError(No valid attributes found.)。其他参数all_versions默认False只保留每个包的最高版本设为True时返回{pkg: [版本信息列表]}适用于内核多版本并存的场景rootRPM 数据库顶层目录日期类属性build_date、install_date由 Unix 时间戳转换为 ISO 8601 格式如2024-01-01T00:00:0000:00Z*_time_t版本保留整数时间戳size属性优先使用%{LONGSIZE}老版本 rpm 不支持时回退%{SIZE}这是为规避 Issue #31366 的兼容处理排序后会自动过滤gpg-pubkey类型的 GPG 公钥包避免污染审计结果。salt * lowpkg.info apache2 bash salt * lowpkg.info apache2 bash attrversion salt * lowpkg.info apache2 bash attrversion,build_date,size salt * lowpkg.info apache2 bash attrversion,build_date,size all_versionsTrue七、版本比较与签名校验version_cmp、checksum7.1 version_cmpRPM 语义的版本比较version_cmp(ver1, ver2, ignore_epochFalse)执行 cmp 风格的版本比较salt/modules/rpm_lowpkg.py#L681-L749自 2015.8.9 起可用返回-1ver1 ver2、0相等、1ver1 ver2出错返回Noneignore_epoch默认False设为True时剥离epoch:前缀再比较2015.8.10 / 2016.3.2 起支持先通过salt.utils.pkg.rpm.version_to_evr将版本拆分为(epoch, version, release)三元组若一侧缺 release 而另一侧有且其余部分相等则忽略 release 差异例如用3.2判断3.2-1是否满足实现细节若 Python 环境装有rpm模块import rpm成功优先调用rpm.labelCompare获得与 RPM 完全一致的比较语义若labelCompare缺失例如 Python path 中混入了同名模块则回退到salt.utils.pkg.rpm.evr_compare的纯 Python 实现。比较结果不在{-1, 0, 1}内会抛出CommandExecutionError。salt * pkg.version_cmp 0.2-001 0.2.0.1-002该函数被 salt/modules/yumpkg.py#L668 的version_cmp透传调用构成pkg.version_cmp在 RPM 平台上的最终实现。7.2 checksum验证 RPM 包签名checksum(*paths, **kwargs)验证一个或多个 RPM 文件的签名是否有效salt/modules/rpm_lowpkg.py#L752-L783底层执行rpm -K --quiet file-K即 checksig返回码为 0 视为签名有效返回{path: True/False}文件在 minion 上不存在时直接判定为False未指定任何包文件时抛出CommandExecutionError(No package files has been specified.)支持root参数。salt * lowpkg.checksum /path/to/package1.rpm salt * lowpkg.checksum /path/to/package1.rpm /path/to/package2.rpm八、在高层模块中的协作关系lowpkg并非孤立存在它是yumpkg/pkg在 RPM 平台的基石。从 salt/modules/yumpkg.py 可以看到典型委托链pkg.version_cmp→lowpkg.version_cmpyumpkg.py#L668本地包文件安装前的元数据探测 →lowpkg.bin_pkg_infoyumpkg.py#L1079pkg.info→lowpkg.infoyumpkg.py#L1111pkg.verify→lowpkg.verifyyumpkg.py#L2595pkg.file_list/pkg.file_dict→lowpkg.file_list/lowpkg.file_dictyumpkg.py#L3425、yumpkg.py#L3444pkg.modified→lowpkg.modifiedyumpkg.py#L3529包内文件差异审计 →lowpkg.owner与lowpkg.diffyumpkg.py#L3624-L3637。因此当你在 minion 上执行salt * pkg.list_pkgs、salt * pkg.verify或编写pkg.installed状态时最终的数据都源自本模块对rpm命令的封装。九、测试保障与扩展阅读本模块的行为由 tests/pytests/unit/modules/test_rpm_lowpkg.py共 791 行系统覆盖测试要点包括__virtual__在 openEuler / Issabel Pbx / Virtuozzo 上的加载判定test_rpm_lowpkg.py#L34-L56list_pkgs、verify、file_list、file_dict、owner、info、modified等函数的默认调用与root参数调用断言底层命令以rpm --root /开头对cmd.run/cmd.run_all/cmd.run_stdout的 mock 注入方式可作为编写同类执行模块测试的模板。进一步深入可阅读查询格式与解析工具salt/utils/pkg/rpm.pyQUERYFORMAT、parse_pkginfo、version_to_evr、evr_compare、resolve_name多架构包名归一化高层包装模块salt/modules/yumpkg.py跨平台状态入口salt/states/pkg.py中的pkg.installed/pkg.verify状态。结语rpm_lowpkg用一套简洁的函数封装了 RPM 生态中最常用的底层操作查询list_pkgs、bin_pkg_info、info、校验verify、modified、checksum、文件归属owner、file_list、file_dict、diff与版本语义比较version_cmp。理解它就等于理解了 Salt 在 RHEL/SUSE/openEuler 等平台上所有包管理能力的底层数据通道——无论是排查包被篡改、定位文件归属还是审计已安装包元数据lowpkg都是第一手的调试入口。【免费下载链接】saltSoftware to automate the management and configuration of infrastructure and applications at scale.项目地址: https://gitcode.com/gh_mirrors/sa/salt创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
