- 运维
- 配置管理
- 后端
【免费下载链接】salt
Software to automate the management and configuration of infrastructure and applications at scale.
导读
本文围绕 Salt 的 schedule 状态模块(salt.states.schedule)展开,讲解如何在状态文件中以声明式方式创建、修改、删除、启用和禁用 minion 端的定时调度任务(Scheduled Jobs)。读完本文后,你将掌握schedule.present、schedule.absent、schedule.enabled、schedule.disabled四个状态函数的完整用法、全部参数语义,并了解它们与底层schedule执行模块、minion 事件系统之间的调用关系,能够直接把定时任务纳入 Salt 的自动化管理体系。
schedule 状态模块是什么
在 Salt 中,minion 内置了一个"调度器(scheduler)",可以让指定函数按固定间隔、特定时间点或 cron 表达式周期性地在 minion 本机执行。这些任务通常定义在 minion 配置或 pillar 中,而 schedule 状态模块 提供了一套状态层的接口,使你能在普通的 SLS 状态文件中管理调度任务,将其与其他状态统一纳入 Salt 的声明式编排体系。
模块提供四个状态函数:
| 状态函数 | 作用 |
|---|---|
schedule.present | 确保某个调度任务存在于 minion 的调度表中(不存在则新增,已存在但配置不一致则修改) |
schedule.absent | 确保某个调度任务从调度表中删除 |
schedule.enabled | 确保某个调度任务处于启用状态 |
schedule.disabled | 确保某个调度任务处于禁用状态 |
从实现上看,这四个函数都依赖执行模块 salt/modules/schedule.py 提供的schedule.list、schedule.add、schedule.modify、schedule.delete、schedule.enable_job、schedule.disable_job等底层函数,并通过 minion 的事件总线(manage_schedule事件)完成实际调度表变更。
schedule.present:定义与确保调度任务
schedule.present(name, **kwargs)是核心状态函数,保证名为name的调度任务处于期望状态。其工作流程如下(对应 schedule.py 中的 present 实现):
- 调用
schedule.list(show_all=True, return_yaml=False, offline=...)获取当前调度表快照; - 若任务尚不存在,则调用
schedule.add新增; - 若任务已存在,则先调用
schedule.build_schedule_item根据本次参数构建期望项,与当前项逐字段比较:完全一致则返回"Job {name} in correct state"(幂等,无变更);不一致则调用schedule.modify更新; - 在
test=True试运行模式下,所有变更仅做预演,不实际生效。
基础示例:按固定间隔执行
job3: schedule.present: - function: test.ping - seconds: 3600 - splay: 10以上配置将test.ping命令每隔 3600 秒(1 小时)执行一次,并把执行时间在 0~10 秒之间随机抖动(splay)。
splay 区间抖动示例
job2: schedule.present: - function: test.ping - seconds: 15 - splay: start: 10 end: 20此例中test.ping每 15 秒执行一次,执行时刻在 10~20 秒之间随机偏移。splay既可以是单个秒数值,也可以是含start/end的字典区间(源码中 build_schedule_item 对此做了专门处理,保证区间内的start/end顺序)。
按具体时刻执行(when)
job1: schedule.present: - function: state.sls - job_args: - httpd - job_kwargs: test: True - when: - Monday 5:00pm - Tuesday 3:00pm - Wednesday 5:00pm - Thursday 3:00pm - Friday 5:00pm该示例在每周一、周三、周五下午 5 点和周二、周四下午 3 点执行state.sls httpd test=True。when使用 dateutil 格式的时间字符串,要求 minion 上安装 python-dateutil;模块在构建任务时会逐个调用dateutil_parser.parse校验时间字符串合法性,解析失败会直接报错(见 build_schedule_item 中的 when 校验)。
使用 cron 表达式
job1: schedule.present: - function: state.sls - job_args: - httpd - job_kwargs: test: True - cron: '*/5 * * * *'调度任务也可以直接使用标准 crontab 格式。本例表示每 5 分钟运行一次state.sls httpd test=True,要求 minion 上安装 python-croniter。
组合 returner 回传执行结果
job1: schedule.present: - function: state.sls - job_args: - httpd - job_kwargs: test: True - when: - Monday 5:00pm - Tuesday 3:00pm - Wednesday 5:00pm - Thursday 3:00pm - Friday 5:00pm - returner: xmpp - return_config: xmpp_state_run - return_kwargs: recipient: user@domain.com该示例在同样的时间点执行state.sls httpd test=True,并使用 xmpp returner 将任务执行结果回传,回传时使用xmpp_state_run配置节中的替代配置项,并通过return_kwargs覆盖单个配置(收件人)。
skip_during_range:避开特定时间段
job1: schedule.present: - function: state.sls - job_args: - httpd - job_kwargs: test: True - hours: 1 - skip_during_range: start: 2pm end: 3pm - run_after_skip_range: True该示例让任务每小时运行一次,但避开下午 2 点至 3 点的时间段;run_after_skip_range: True表示跳过区间结束后立即补跑一次。skip_during_range同样要求 python-dateutil。
present 完整参数详解
schedule.present支持的参数如下(均为**kwargs透传给执行模块),完整声明见 schedule.py 的 present 文档字符串:
| 参数 | 类型/默认值 | 说明 |
|---|---|---|
name | string(必填) | 调度任务的唯一名称,即调度表中的键名 |
seconds/minutes/hours/days | int | 固定时间间隔,任务经过指定时长后执行一次 |
when | string 或 list | 在指定时刻执行,使用 dateutil 格式,需 python-dateutil |
cron | string | 使用 crontab 格式指定执行时刻,需 python-croniter |
run_on_start | bool | minion 启动时是否立即执行;否则首次会跳过,等下一个调度周期 |
function | string | 调度任务要执行的函数名(必填) |
job_args | list | 传给函数的定位参数 |
job_kwargs | dict | 传给函数的关键字参数 |
maxrunning | int | 同一任务最多允许同时运行 N 个副本,防止任务重叠 |
jid_include | bool(默认 True) | 是否将任务纳入 job cache(任务缓存) |
splay | int 或 dict | 执行时刻的随机抖动;可为秒数或{start, end}区间 |
range | dict | 仅在该时间范围内执行,需 python-dateutil |
once | string | 在指定日期只执行一次 |
once_fmt | string | once的日期格式,默认 ISO 8601,可覆盖 |
enabled | bool(默认 True) | 任务是否启用 |
return_job | bool | 任务完成后是否向 master 回传执行信息 |
metadata | dict | 关联到任务的元数据,不参与执行,可用于与return_job组合检索任务 |
returner | string | 用于回传任务结果的 returner 名称 |
return_config | string | returner 使用的替代配置节 |
return_kwargs | dict | 覆盖单个 returner 配置项 |
persist | bool(默认 True) | 变更是否持久化保存到 minion 配置文件 |
skip_during_range | dict | 在指定时间区间内不执行({start, end}),需 python-dateutil |
run_after_skip_range | bool | 跳过区间结束后是否立即补跑 |
offline | bool | minion 未运行时也把任务写入调度(versionadded 3006.3 引入) |
几个值得注意的实现细节
- 时间参数互斥校验:
seconds/minutes/hours/days不能与when或cron混用,when与cron也不能同时使用。schedule.add、schedule.modify、schedule.build_schedule_item三处均有此校验,冲突时会直接返回result: False并给出明确报错(见 build_schedule_item 的冲突检查)。 job_args/job_kwargs类型校验:job_args必须是 list、job_kwargs必须是 dict,否则构建任务会失败(见 build_schedule_item)。- 默认值注入:
maxrunning默认 1、enabled默认 True、jid_include默认 True。state 层比较新旧配置时,也会为期望项补上缺失的enabled字段后再比较,避免误判(见 present 的实现)。 offline模式:当 minion 进程未运行时,schedule.add/schedule.modify不再通过事件总线触发,而是直接把合并后的调度表写入_schedule.conf文件(由_get_schedule_config_file生成,位于 minion 配置目录下,见 list_ 与 add 的 offline 分支 与 add 的 offline 写文件逻辑)。
schedule.absent:移除调度任务
schedule.absent(name, **kwargs)用于确保某任务不在调度表中:
cleanup-job: schedule.absent: - name: job1- 若任务存在,调用
schedule.delete删除,返回Removed job {name} from schedule,changes中记录移除结果; - 若任务本就不存在,返回
Job {name} not present in schedule,视为成功(幂等); test=True模式下仅预演删除;persist参数(默认 True)决定删除操作是否持久化——为 False 时任务只从运行中的调度表移除,minion 重启后仍会从保存的配置中恢复;- 同样支持
offline=True,在 minion 未运行时直接改写_schedule.conf(见 absent 实现)。
schedule.enabled 与 schedule.disabled:启停任务
这两个状态函数分别调用schedule.enable_job和schedule.disable_job,用于在不删除任务的前提下启停任务,适合临时维护场景:
pause-backup: schedule.disabled: - name: nightly-backup resume-backup: schedule.enabled: - name: nightly-backup- 任务存在时正常启停并返回对应 comment;任务不存在则返回
Job {name} not present in schedule; test=True时仅预演;persist决定变更是否保存(见 enabled 实现 与 disabled 实现)。
与执行模块及事件系统的联动原理
状态函数本身不做调度,而是把参数透传给 salt/modules/schedule.py 的执行函数。在线模式下,执行函数通过event.fire(data, "manage_schedule")向 minion 事件总线发送manage_schedule事件,minion 调度器进程收到后执行真实变更,再通过minion_schedule_add_complete、minion_schedule_modify_complete、minion_schedule_enabled_job_complete等标签回发完成事件,执行函数等待事件返回后确认结果(例如 enable_job 的事件往返)。
在test=True试运行模式下,状态层会把test参数注入kwargs透传下去,使执行模块返回"would be added / would be modified / would be deleted"等预演信息而不做真实变更。
测试验证
仓库中针对本状态模块的单元测试位于 tests/pytests/unit/states/test_schedule.py,覆盖了以下关键行为:
- 新增任务:调度表为空时调用
schedule.add,返回Adding new job job1 to schedule; - 无变化幂等:任务已存在且期望配置一致时返回
Job job1 in correct state; - 修改任务:任务已存在但
when等字段变化时调用schedule.modify,changes中给出 old/new 完整对比; - test 模式:
test=True时只预演,comment 变为would be added / would be modified / would be deleted; - 删除任务:存在时调用
schedule.delete,不存在时返回Job job1 not present in schedule; - offline 模式:
offline=True时直接写入_schedule.conf,且不触发事件总线调用(测试中断言event.call_count == 0)。
这些测试同时佐证了状态层对test、offline、persist等分支的处理逻辑与上述说明一致。
使用建议
- 将调度任务定义放进状态文件后,可通过
salt 'minion*' state.apply schedule批量下发,任务会同时持久化到 minion 配置目录下的_schedule.conf; - 需要快速查看 minion 当前调度表时,可结合执行模块命令
salt '*' schedule.list show_all=True对比状态管理结果; - 涉及
when、range、skip_during_range时务必确认 minion 已安装 python-dateutil,涉及cron时确认已安装 python-croniter,否则任务构建会直接报错; - 需要"立刻执行一次"某调度任务时,可使用执行模块的
salt '*' schedule.run_job job1(force=True可强制执行被禁用的任务,见 run_job 实现)。
综上,salt.states.schedule把 minion 端定时任务的"增删改查启停"全部收敛为声明式状态,配合事件系统与配置文件持久化机制,让定时任务的管理和审计与 Salt 的其他基础设施管理保持同一套自动化流程。
- 运维
- 配置管理
- 后端
【免费下载链接】salt
Software to automate the management and configuration of infrastructure and applications at scale.
相关推荐
Salt 状态模块 at:用 at.present / at.absent / at.watch 管理一次性定时任务
Salt 状态模块 at:用 at.present / at.absent / at.watch 管理一次性定时任务 导读 本文围绕 Salt 状态模块 sal
运维配置管理后端Salt Proxy Minion 状态管理实战:用 salt_proxy.configure_proxy 在 minion 上部署与运行 salt-proxy
Salt Proxy Minion 状态管理实战:用 salt_proxy.configure_proxy 在 minion 上部署与运行 salt proxy
运维配置管理后端Salt 状态模块指南:使用 salt.states.environ 管理 Minion 进程环境变量
Salt 状态模块指南:使用 salt.states.environ 管理 Minion 进程环境变量 导读 environ 是 Salt 中专门用于管理「当前
运维配置管理后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考