- 运维
- 配置管理
- 后端
【免费下载链接】salt
Software to automate the management and configuration of infrastructure and applications at scale.
导读
system是 Salt 内置的执行模块(Execution Module),为 POSIX 类系统提供关机(shutdown)、重启(reboot)、停机(halt)、断电(poweroff)、运行级别切换(init)、系统日期/时间设置与读取、以及主机描述与主机名的管理能力。本文以 salt/modules/system.py 的实现为主线,结合 官方模块文档 与 单元测试、功能测试 中的验证逻辑,完整讲解每个函数的参数、返回值和 CLI 用法,并深入剖析其底层命令调用、平台差异处理与硬件时钟同步原理,帮助你安全、精准地在生产集群上批量执行电源管理与时间同步操作。
模块概览:定位、平台限制与加载机制
模块定位
salt.modules.system是 Salt 的“电源与系统时间控制”入口,直接对应salt '*' system.<function>形式的远程命令。它把 POSIX 系统的常用管理动作(halt、reboot、shutdown、poweroff、init、时间日期设置、主机名设置等)封装成统一的 Salt 接口,避免在各台机器上手工敲击底层命令。
模块源码开头的模块说明明确指出(salt/modules/system.py):
该模块提供对 POSIX 类系统上 reboot、shutdown 等操作的支持。
平台可用性(virtual)
system模块并不是在所有平台上都可用。__virtual__()函数(salt/modules/system.py)在加载阶段即做平台判定:
- Windows:不可用,返回
(False, "This module is not available on Windows"); - macOS(Darwin):不可用,返回
(False, "This module is not available on Mac OS"); - SunOS/Solaris:不可用,返回
(False, "This module is not available on SunOS"); - 其他 POSIX 平台(Linux、FreeBSD、NetBSD、OpenBSD 等)返回虚拟名
"system"正常加载。
也就是说,system只服务于 POSIX 类系统。Windows、macOS 与 Solaris 各有自己的专用模块:Windows 使用 salt/modules/win_system.py(其文档入口为 salt.modules.win_system),macOS 使用 salt/modules/mac_system.py(文档入口 salt.modules.mac_system),Solaris 使用salt/modules/solaris_system.py。这与官方模块索引 doc/ref/modules/all/index.rst 中列出的多平台 system 模块体系一致。
一个重要的使用提醒:molly-guard 等交互包装器
模块文档开头特别提醒(salt/modules/system.py):如果系统配置了诸如molly-guard这类用于拦截交互式关机命令的包装脚本,那么通过salt-call调用system.halt、system.poweroff、system.reboot、system.shutdown时会因为包装脚本在等待用户输入而无限期挂起;而通过salt(master 下发)调用则行为正常。这在批量管理带有交互防护的生产机时是需要警惕的坑。
电源管理四件套:halt、poweroff、reboot、shutdown
这四个函数是本模块最常用的能力,全部基于__salt__["cmd.run"]调用底层系统命令,并且统一使用python_shell=False以避免 shell 注入风险(salt/modules/system.py)。
halt:停机但不一定断电
def halt(): cmd = ["halt"] ret = __salt__"cmd.run" return ret- CLI:
salt '*' system.halt - 底层命令:直接执行
halt。 - 注意:
halt在多数现代 Linux 上只是停机关机流程的一环,具体是否断电取决于发行版与配置。
poweroff:直接断电
def poweroff(): cmd = ["poweroff"] ...- CLI:
salt '*' system.poweroff - 底层命令:直接执行
poweroff。
reboot:重启,支持延迟时间
def reboot(at_time=None): cmd = ["shutdown", "-r", (f"{at_time}" if at_time else "now")] ...- CLI:
salt '*' system.reboot或salt '*' system.reboot 5(5 分钟后重启)。 - 参数
at_time:以分钟为单位的延迟时间;不传则立即重启(底层命令为shutdown -r now)。 - 底层命令:
shutdown -r [minutes|now]。这里的语义是:传数字表示延迟 N 分钟,传字符串now表示立即。
单元测试对这两条命令路径做了精确断言(tests/pytests/unit/modules/test_system.py):
cmd_mock.assert_called_with(["shutdown", "-r", "now"], python_shell=False) cmd_mock.assert_called_with(["shutdown", "-r", "5"], python_shell=False)shutdown:关机,BSD 系自动断电
def shutdown(at_time=None): if (salt.utils.platform.is_freebsd() or salt.utils.platform.is_netbsd() or salt.utils.platform.is_openbsd()): # these platforms don't power off by default when halted flag = "-p" else: flag = "-h" cmd = ["shutdown", flag, (f"{at_time}" if at_time else "now")] ...- CLI:
salt '*' system.shutdown或salt '*' system.shutdown 5(5 分钟后关机)。 - 参数
at_time:延迟分钟数;不传则立即关机。 - 平台差异(关键点):在 FreeBSD / NetBSD / OpenBSD 上,halt 默认不会断电,所以底层使用
shutdown -p(power off);其他平台使用shutdown -h(halt)。
单元测试覆盖了这四种平台分支(tests/pytests/unit/modules/test_system.py):Linux/通用平台断言["shutdown", "-h", "now"],FreeBSD、NetBSD、OpenBSD 分别断言["shutdown", "-p", "now"]。
init:sysV 运行级别切换
def init(runlevel): cmd = ["init", f"{runlevel}"] ...- CLI:
salt '*' system.init 3 - 底层命令:
init <runlevel>,仅适用于 sysV 兼容系统。注意参数是按字符串拼接的(init "3"),传入的 runlevel 会原样传给init命令。
时间管理:读取系统时间与日期
时间管理函数围绕_get_offset_time与_FixedOffset构建,支持通过utc_offset参数在任意时区视角下读取时间(salt/modules/system.py)。
时间偏移解析机制
_offset_to_min(utc_offset)(salt/modules/system.py)用正则^([+-])?(\d\d)(\d\d)$把+0600、-0300、0800之类的偏移字符串解析为分钟数(如+0500→-300、-0300→180、0800→480)。注意其返回值符号与直觉相反(东八区+0800返回-480),因为该函数计算的是“从 UTC 到该时区的修正量”。_get_offset_time(utc_offset)以salt.utils.timeutil.utcnow()为基准加上偏移分钟数,构造带_FixedOffset时区信息的 datetime;未传偏移时使用datetime.now()(本地时区)。_FixedOffset类(salt/modules/system.py)是固定偏移 tzinfo 的轻量实现,源自 Python 官方 datetime 文档的经典模式。
读取函数族
| 函数 | CLI 示例 | 输出格式 |
|---|---|---|
get_system_time | salt '*' system.get_system_time | HH:MM:SS AM/PM(如02:37:54 PM) |
get_system_date_time | salt '*' system.get_system_date_time "'-0500'" | YYYY-MM-DD hh:mm:ss |
get_system_date | salt '*' system.get_system_date | %a %m/%d/%Y(如Tue 05/12/2015) |
utc_offset参数为四位数偏移格式(如+0600),带可选+/-符号;不传则使用本地时区。功能测试验证了本地时间与 UTC(+0000)两种读取路径,误差要求 3 秒以内(tests/pytests/functional/modules/test_system.py)。
命令行引号提示:在 salt 命令行上传递负偏移时,由于 Salt 参数解析器会先处理参数,需要使用双重引号,例如
"'−0000'"(文档原文为"'+0000'"示例,负偏移同理,如"'-0500'")。
时间管理:设置系统时间与日期
set_system_time:只改时分秒
- CLI:
salt '*' system.set_system_time "'11:20'" - 支持的输入格式(解析器
_try_parse_datetime依次尝试,salt/modules/system.py):HH:MM:SS AM/PMHH:MM AM/PMHH:MM:SS(24 小时制)HH:MM(24 小时制)
- 解析失败返回
False。成功后将时分秒委托给set_system_date_time,日期保持不变。
由于命令行的日期/时间参数在到达模块前可能已被 Salt 命令行解析器处理,所以时间参数必须以字符串形式传递,命令行上通常需要双重引号(如示例中的"'11:20'")。
set_system_date:只改年月日
- CLI:
salt '*' system.set_system_date '03-28-13' - 支持的输入格式:
YYYY-MM-DDMM-DD-YYYYMM-DD-YYMM/DD/YYYYMM/DD/YYYYYY/MM/DD
- 格式非法时抛出
SaltInvocationError("Invalid date format")(salt/modules/system.py);合法则调用set_system_date_time只更新年/月/日,时间保持不变。
set_system_date_time:核心设置函数
这是时间设置的真正实现(salt/modules/system.py),set_system_time与set_system_date最终都委托给它:
- CLI:
salt '*' system.set_system_date_time 2015 5 12 11 37 53 "'-0500'" - 参数:
years、months、days、hours、minutes、seconds、utc_offset。每个参数都可选:未传的字段沿用当前系统值,从而实现“只改年份”“只改时间”等局部修改。 - 取值范围:months
1-12,days1-31,hours0-23,minutes/seconds0-59;非法组合会抛出SaltInvocationError(如datetime构造ValueError被捕获后重新抛出,salt/modules/system.py)。
底层实现流程:
- 以
_get_offset_time(utc_offset)取得当前时间作为基准; - 缺失字段用当前值填充,构造新的
datetime; - 调用
_date_bin_set_datetime通过date命令设置软件时钟(内核时钟); - 若系统存在可设置的硬件时钟(
has_settable_hwclock()为真),再调用_swclock_to_hwclock()执行hwclock --systohc,把软件时钟同步到硬件时钟,保证重启后时间不丢(salt/modules/system.py)。
_date_bin_set_datetime:date 命令的两级降级策略
_date_bin_set_datetime(salt/modules/system.py)体现了对 POSIX 兼容性的细致处理:
- 若 datetime 带时区信息(
utcoffset() is not None),先换算为 UTC 等价时刻,加-u参数以 UTC 设置; - 第一优先级使用非 POSIX 扩展格式
date MMDDhhmm[[CC]YY[.ss]](可精确到秒),执行cmd.run_all并检查返回码; - 若失败(返回码非 0),降级为纯 POSIX 格式
date MMDDhhmm[[CC]YY](只能精确到分钟)重试; - 两次都失败则抛出
CommandExecutionError,并透出第一次尝试的stderr便于排障。
也就是说,严格 POSIX 的 date 只能把时间设置到分钟级,秒级设置是尽力而为的扩展特性。功能测试对此有专门的描述:“我们只能把时间设置到秒的精度,所以测试可能看起来在负时间运行”(tests/pytests/functional/modules/test_system.py)。
has_settable_hwclock / _swclock_to_hwclock:硬件时钟探测与同步
has_settable_hwclock()(salt/modules/system.py):先用salt.utils.path.which_bin(["hwclock"])探测hwclock是否存在;存在则执行hwclock --test --systohc(--test为演练模式,不真正写入),返回码为 0 即认为硬件时钟可被软件设置。_swclock_to_hwclock()(salt/modules/system.py):真正执行hwclock --systohc把软件时钟写入硬件时钟;失败仅记录 warning,不中断流程。
功能测试_test_hwclock_sync通过hwclock --compare对比硬件/软件时钟,要求差值 ≤ 2 秒(tests/pytests/functional/modules/test_system.py),从侧面印证了set_system_date_time同步硬件时钟的正确性。
主机名与主机描述管理
get_computer_desc / set_computer_desc:PRETTY_HOSTNAME
这两个函数管理/etc/machine-info中的PRETTY_HOSTNAME变量(人类可读的机器描述,如“Michael's laptop”)。
get_computer_desc(salt/modules/system.py):
- 优先使用
hostnamectl status --pretty(systemd 系统); - 无
hostnamectl时回退为解析/etc/machine-info中的PRETTY_HOSTNAME=行,自动剥离引号,并反转义\\、\"、\n、\t; - 文件或变量不存在时返回
False。
set_computer_desc(salt/modules/system.py):
- 入参先做转义:
"→\"、换行 →\n、制表符 →\t; - 优先使用
hostnamectl set-hostname --pretty <desc>(systemd); - 回退路径:
/etc/machine-info不存在则先创建,然后用正则定位既有PRETTY_HOSTNAME=行并替换,找不到则追加到文件末尾;文件操作失败返回False,成功返回True。
功能测试验证了普通描述、包含引号/制表符/Unicode 的多行描述都能正确往返(tests/pytests/functional/modules/test_system.py),并且当测试环境中的hostnamectl因缺少 system bus 而退化时会被自动跳过(check_hostnamectl探测逻辑,tests/pytests/functional/modules/test_system.py)。
get_computer_name / set_computer_name:主机名
def set_computer_name(hostname): return __salt__"network.mod_hostname" def get_computer_name(): return __salt__["network.get_hostname"]()- CLI:
salt '*' system.set_computer_name master.saltstack.com、salt '*' system.get_computer_name - 这两个函数委托给 network 模块:
network.mod_hostname与network.get_hostname(实现在salt/modules/network.py中)。因此system模块并未直接操作/etc/hostname,而是复用了 network 模块的跨平台主机名管理逻辑。
特殊功能:NI Linux RT 的重启见证标记
模块还包含一对仅适用于NI Linux RT(os_family == "NILinuxRT",由_is_nilrt_family()判定)的特殊函数,通过@depends("_is_nilrt_family")装饰器(salt/utils/decorators.py)仅在 NI Linux RT 上暴露:
set_reboot_required_witnessed()(salt/modules/system.py):在临时文件系统(tmpfs)路径/var/volatile/tmp/salt/reboot_witnessed写入见证文件,用于记录“已观察到需要重启的事件”;由于写在 tmpfs 上,重启后自动消失。目录创建失败会抛出SaltInvocationError。get_reboot_required_witnessed()(salt/modules/system.py):返回该文件是否存在,用于判断当前启动会话中是否见证过重启请求。
这是为 NI 实时 Linux 的嵌入式/工控场景设计的机制,普通 Linux 上不可用。
实战场景:如何组合使用
场景一:批量延迟重启并等待回归
借助salt.function状态模块与salt.wait_for_event,可以实现“全量重启、等待 minion 全部回归”的编排(该示例来自 salt/states/saltmod.py 的文档):
reboot_all_minions: salt.function: - name: system.reboot - tgt: '*' wait_for_reboots: salt.wait_for_event: - name: salt/minion/*/start - id_list: - jerry - stuart - dave - phil - kevin - mike - require: - salt: reboot_all_minions这展示了system.reboot作为状态编排中的一环:先用它重启目标,再用事件监听保证所有 minion 重新上线后才继续后续操作。
场景二:集群时间校正
对需要强时间一致性的集群(如依赖时间戳的分布式服务),可在窗口期统一校正:
salt 'web*' system.set_system_date_time 2025 5 12 11 37 53 "'+0800'" salt 'web*' system.get_system_date_time "'+0800'"第一行按东八区 2025-05-12 11:37:53 设置系统时间(内部换算为 UTC 执行date -u,随后同步硬件时钟);第二行验证结果。注意:修改系统时间属于高风险操作,应先在小范围 minion 上验证,且确认systemd-timesyncd等 NTP 服务不会立即回拨时钟(功能测试的 setup/teardown 正是先停用再恢复systemd-timesyncd,tests/pytests/functional/modules/test_system.py)。
场景三:批量标注机器用途
salt '*' system.set_computer_desc "Web frontend - production" salt '*' system.get_computer_desc借助get_computer_desc/set_computer_desc在/etc/machine-info中维护可读的主机描述,便于审计与资产盘点。
结论与扩展阅读
salt.modules.system用极薄的封装把 POSIX 电源管理、运行级别、系统时间与主机标识统一到了 Salt 的远程执行框架中,底层命令与平台差异被函数级隔离:shutdown的 BSD 断电分支、date命令的 POSIX 降级、hostnamectl//etc/machine-info的双路径,处处体现对多发行版兼容性的设计。
进一步阅读:
- 模块完整源码:salt/modules/system.py
- 官方 API 文档入口:doc/ref/modules/all/salt.modules.system.rst
- 单元测试(命令级断言):tests/pytests/unit/modules/test_system.py
- 功能测试(真实时间设置与硬件时钟同步):tests/pytests/functional/modules/test_system.py
- 平台专属替代模块:salt.modules.win_system、salt.modules.mac_system
- 状态编排示例(
salt.wait_for_event):salt/states/saltmod.py
- 运维
- 配置管理
- 后端
【免费下载链接】salt
Software to automate the management and configuration of infrastructure and applications at scale.
相关推荐
Salt hosts 执行模块全指南:用 `salt '*' hosts.*` 管理 hosts 文件中的 IP 与主机名映射
Salt hosts 执行模块全指南:用 salt ' ' hosts. 管理 hosts 文件中的 IP 与主机名映射 本篇技术指南围绕 Salt 内置的 h
运维配置管理后端Salt 的 Windows 系统管理模块 win_system:重启关机、域加入、改名与待重启检测实战指南
Salt 的 Windows 系统管理模块 win_system:重启关机、域加入、改名与待重启检测实战指南 本指南系统讲解 Salt 中用于 Windows
运维配置管理后端Salt vSphere 执行模块实战指南:统一管理 vCenter 与 ESXi 主机
Salt vSphere 执行模块实战指南:统一管理 vCenter 与 ESXi 主机 导读 本文面向使用 Salt 管理 VMware 基础设施的运维与研发
运维配置管理后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考