Salt 的 system 执行模块:POSIX 系统的关机、重启、时钟与主机名管理全指南
2026/9/23 14:39:43 网站建设 项目流程
  • 运维
  • 配置管理
  • 后端

【免费下载链接】salt

Software to automate the management and configuration of infrastructure and applications at scale.

项目地址:https://gitcode.com/gh_mirrors/sa/salt
点击查看免费下载

导读

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.haltsystem.poweroffsystem.rebootsystem.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.rebootsalt '*' 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.shutdownsalt '*' 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-03000800之类的偏移字符串解析为分钟数(如+0500-300-03001800800480)。注意其返回值符号与直觉相反(东八区+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_timesalt '*' system.get_system_timeHH:MM:SS AM/PM(如02:37:54 PM
get_system_date_timesalt '*' system.get_system_date_time "'-0500'"YYYY-MM-DD hh:mm:ss
get_system_datesalt '*' 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/PM
    • HH:MM AM/PM
    • HH: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-DD
    • MM-DD-YYYY
    • MM-DD-YY
    • MM/DD/YYYY
    • MM/DD/YY
    • YYYY/MM/DD
  • 格式非法时抛出SaltInvocationError("Invalid date format")(salt/modules/system.py);合法则调用set_system_date_time只更新年/月/日,时间保持不变。

set_system_date_time:核心设置函数

这是时间设置的真正实现(salt/modules/system.py),set_system_timeset_system_date最终都委托给它:

  • CLI:salt '*' system.set_system_date_time 2015 5 12 11 37 53 "'-0500'"
  • 参数:yearsmonthsdayshoursminutessecondsutc_offset每个参数都可选:未传的字段沿用当前系统值,从而实现“只改年份”“只改时间”等局部修改。
  • 取值范围:months1-12,days1-31,hours0-23,minutes/seconds0-59;非法组合会抛出SaltInvocationError(如datetime构造ValueError被捕获后重新抛出,salt/modules/system.py)。

底层实现流程

  1. _get_offset_time(utc_offset)取得当前时间作为基准;
  2. 缺失字段用当前值填充,构造新的datetime
  3. 调用_date_bin_set_datetime通过date命令设置软件时钟(内核时钟)
  4. 若系统存在可设置的硬件时钟(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.comsalt '*' system.get_computer_name
  • 这两个函数委托给 network 模块network.mod_hostnamenetwork.get_hostname(实现在salt/modules/network.py中)。因此system模块并未直接操作/etc/hostname,而是复用了 network 模块的跨平台主机名管理逻辑。

特殊功能:NI Linux RT 的重启见证标记

模块还包含一对仅适用于NI Linux RTos_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.

项目地址:https://gitcode.com/gh_mirrors/sa/salt
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询