AWX Project Schedules API 详解:rrule 格式规范与项目定时任务实战
2026/9/21 14:01:46 网站建设 项目流程

AWX Project Schedules API 详解:rrule 格式规范与项目定时任务实战

【免费下载链接】awxAWX provides a web-based user interface, REST API, and task engine built on top of Ansible. It is one of the upstream projects for Red Hat Ansible Automation Platform.项目地址: https://gitcode.com/gh_mirrors/aw/awx

导读

Project Schedules(项目调度)是 AWX 中用于让 Project(项目)按指定时间规律自动触发 SCM 更新等操作的核心能力。本文以 AWX 仓库中的 API 文档模板awx/api/templates/api/project_schedules_list.md为主体骨架,系统讲解该端点支持的 GET 列表、POST 创建两种操作,并深入剖析其底层rrule(iCalendar 循环规则)的格式约束、校验逻辑与示例。读完本文,你将掌握如何通过 REST API 为 Project 创建定时更新调度,并能准确写出通过校验的rrule字符串。

端点概览:Project Schedules 能做什么

在 AWX 中,ProjectSchedulesList视图对应路由project_schedules_list,注册于 awx/api/urls/project.py#L35:

re_path(r'^(?P<pk>[0-9]+)/schedules/$', ProjectSchedulesList.as_view(), name='project_schedules_list'),

也就是说,对单个 Project 的调度端点形如GET/POST /api/v2/projects/{id}/schedules/。该视图定义于 awx/api/views/init.py#L1016:

class ProjectSchedulesList(SubListCreateAPIView): name = _("Project Schedules") model = models.Schedule serializer_class = serializers.ScheduleSerializer parent_model = models.Project relationship = 'schedules' parent_key = 'unified_job_template' resource_purpose = 'schedules of a project'

关键点在于parent_key = 'unified_job_template':Project 通过UnifiedJobTemplate统一作业模板基类与Schedule模型关联,而Schedule模型上的外键unified_job_template(见 awx/main/models/schedules.py#L131)正是这种关系的落点。因此,Project Schedules 本质上是"挂在统一作业模板上的定时触发规则",其触发的动作是 Project Update(项目更新)。

从模板继承关系看,project_schedules_list.md继承自 sub_list_create_api_view.md,后者又引入 sub_list_api_view.md,从而形成"列表 + 创建"两个操作的文档结构。

GET:列出某 Project 下的所有调度

GET /api/v2/projects/{id}/schedules/发起请求,即可检索与所选 Project 关联的全部调度。该列表是标准的分页列表,返回的是 ScheduleSerializer 序列化后的字段集合。

Schedule模型(awx/main/models/schedules.py#L123)的核心字段如下:

字段类型说明
unified_job_templateForeignKey关联的作业模板(此处为 Project),同一模板下调度名唯一(unique_together = ('unified_job_template', 'name')
nameCharField(max_length=512)调度名称
enabledBooleanField(default=True)是否启用该调度,关闭后不再处理
rruleTextFieldiCalendar 格式的循环规则字符串,即本文重点
dtstartDateTimeField计算字段,表示首次执行时间(大于等于该时间的第一次出现)
dtendDateTimeField计算字段,表示最后一次执行时间,之后调度过期
next_runDateTimeField计算字段,下一次执行时间
timezone/until只读属性rrule推导出的时区与结束时间

其中timezone属性(awx/main/models/schedules.py#L167)会解析rruleDTSTART的时区信息:若为 UTC 直接返回'UTC',否则通过 zoneinfo 数据库反查时区名。列表默认按next_run降序排列,null 值排最后。

POST:为 Project 创建新调度

对同一端点发起POST请求,可在指定 Project 下创建新的调度,需提交调度相关字段。POST 请求的rrule值必须遵循特定格式,且仅允许规则集的一个子集,详细约束见下文。

关于关联语义需要区分两点:由于本端点parent_key = 'unified_job_template',创建出的 Schedule 直接与 Project(经统一作业模板)绑定;若父模型字段不同,同一文档模板族中的其他子列表端点(如job_template_schedules_listinventory_source_schedules_list,参见 awx/api/templates/api/ 下的同名模板)会呈现"关联/取消关联已有对象"的语义,而 Project Schedules 走的是直接创建路径。

调度一旦创建并启用,AWX 的调度器(awx/main/scheduler目录)会依据next_run到期触发,Schedule.get_job_kwargs()(awx/main/models/schedules.py#L284)会基于调度的prompts_dict()配置拼接作业参数,并以launch_type: 'scheduled'schedule: self的方式标记作业来源。

rrule 格式规范:AWX 支持的规则子集

POST 请求中的rrule必须符合以下格式与约束(出自 awx/api/templates/api/_schedule_detail.md):

  • DTSTART必填,且必须采用DTSTART:YYYYMMDDTHHMMSSZ格式;
  • DTSTART必须为 UTC 时间;
  • INTERVAL必填;
  • 不支持SECONDLY(按秒);
  • RRULE关键字必须位于规则语句之前;
  • BYDAY受支持,但不支持带数字前缀的形式(如20MO);
  • BYYEARDAYBYWEEKNO不支持;
  • 每条调度只支持一条RRULE语句;
  • COUNT必须小于 1000。

这些约束在序列化器层有严格对等的实现。ScheduleSerializer.validate_rrule(awx/api/serializers.py#L5687)会逐条拒绝:

  • 缺少DTSTART(提示必须以DTSTART:YYYYMMDDTHHMMSSZ开头);
  • DTSTART为 naive datetime(缺少时区,提示DTSTART cannot be a naive datetime);
  • 出现多个DTSTART(提示Multiple DTSTART is not supported);
  • 未包含rrule:关键字(提示One or more rule required in rrule);
  • 包含exdate:EXDATE not allowed in rrule);
  • 包含rdate:RDATE not allowed in rrule);
  • 规则中缺少INTERVAL,或INTERVAL不是正整数;
  • 使用了secondly
  • BYDAY带数字前缀(正则.*?BYDAY[\:\=][0-9]+[a-zA-Z]{2}命中即拒绝);
  • COUNT > 999(提示COUNT > 999 is unsupported);
  • 最终通过Schedule.rrulestr(rrule_value)做整体解析,解析失败则报rrule parsing failed validation

校验通过后,调度写入数据库。Schedule.rrulestr(awx/main/models/schedules.py#L257)还封装了自定义解析逻辑:先将UNTIL中按 RFC5545 允许的纯日期形式(naive)强制转换为与DTSTART一致的时区感知形式(coerce_naive_until,见 awx/main/models/schedules.py#L197),再交给底层 rrule 库解析为rruleset,为next_rundtstartdtend等计算字段提供依据。

rrule 示例全集与解读

以下是文档中给出的 13 条合法rrule示例,覆盖了从"分钟级一次性"到"按年"的常见调度需求,可直接作为 POST 请求体中的rrule值使用:

"DTSTART:20500331T055000Z RRULE:FREQ=MINUTELY;INTERVAL=10;COUNT=5" "DTSTART:20240331T075000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1" "DTSTART:20140331T075000Z RRULE:FREQ=MINUTELY;INTERVAL=1;UNTIL=20230401T075000Z" "DTSTART:20140331T075000Z RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,FR" "DTSTART:20140331T075000Z RRULE:FREQ=WEEKLY;INTERVAL=5;BYDAY=MO" "DTSTART:20140331T075000Z RRULE:FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=6" "DTSTART:20140331T075000Z RRULE:FREQ=MONTHLY;INTERVAL=1;BYSETPOS=4;BYDAY=SU" "DTSTART:20140331T075000Z RRULE:FREQ=MONTHLY;INTERVAL=1;BYSETPOS=-1;BYDAY=MO,TU,WE,TH,FR" "DTSTART:20140331T075000Z RRULE:FREQ=MONTHLY;INTERVAL=1;BYSETPOS=-1;BYDAY=MO,TU,WE,TH,FR,SA,SU" "DTSTART:20140331T075000Z RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=4;BYMONTHDAY=1" "DTSTART:20140331T075000Z RRULE:FREQ=YEARLY;INTERVAL=1;BYSETPOS=-1;BYMONTH=8;BYDAY=SU" "DTSTART:20140331T075000Z RRULE:FREQ=WEEKLY;INTERVAL=1;UNTIL=20230401T075000Z;BYDAY=MO,WE,FR" "DTSTART:20140331T075000Z RRULE:FREQ=HOURLY;INTERVAL=1;UNTIL=20230610T075000Z"

逐条解读:

  • 第 1 条:从 2050-03-31 05:50:00(UTC)起,每 10 分钟触发一次,共 5 次(COUNT限次,适合一次性短周期任务)。
  • 第 2 条:每天一次、只触发 1 次,等价于"仅执行一次"的日调度写法。
  • 第 3 条:每分钟触发,直到UNTIL=20230401T075000Z为止(UNTIL定终止时间,与COUNT二选一)。
  • 第 4 条:每周一、三、五各触发一次(BYDAY多值并列)。
  • 第 5 条:每 5 周触发一次,仅限周一。
  • 第 6 条:每月 6 日触发一次(BYMONTHDAY指定月内日)。
  • 第 7 条:每月第 4 个星期日触发(BYSETPOS=4+BYDAY=SU组合出"第几个星期几")。
  • 第 8 条:每月最后一个工作日(周一至周五)触发(BYSETPOS=-1表示倒数第一个,BYDAY=MO,TU,WE,TH,FR限定工作日)。
  • 第 9 条:每月最后一天触发(BYSETPOS=-1+ 周一到周日全量)。
  • 第 10 条:每年 4 月 1 日触发。
  • 第 11 条:每年 8 月的最后一个星期日触发(BYMONTH=8+BYSETPOS=-1+BYDAY=SU,典型的"某月最后一个星期几"写法)。
  • 第 12 条:每周一、三、五触发,且受UNTIL截止时间约束(UNTILBYDAY可同时出现)。
  • 第 13 条:每小时触发一次,直到 2023-06-10 07:50:00(UTC)为止。

一个常见的 POST 请求体示例(为某 Project 创建"每天 07:50 UTC 更新一次"的调度)形如:

{ "name": "nightly-project-update", "rrule": "DTSTART:20240331T075000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1", "enabled": true }

注意DTSTART是调度的"生效起点"而非首次执行时间本身:首次执行发生在DTSTART之后按规则计算出的第一个时刻,即next_run字段所标示的时间。若希望调度长期有效,可用UNTIL或省略终止条件;若只需要有限次数,用COUNT(须小于 1000)。

校验与调试:用源码确认边界

如果你需要预演某条rrule能产生多少次执行,AWX 还提供了SchedulePreviewSerializer(awx/api/serializers.py#L5671),它接收rrule并复用同一套validate_rrule逻辑,返回按该规则计算出的未来执行时间序列,适合在创建调度前进行预览验证。

提交rrule时若违反上述任一约束,API 会返回 400 及具体的错误消息(如COUNT > 999 is unsupportedMultiple DTSTART is not supported)。因此实践中的要点可以归纳为:

  1. 永远以DTSTART:YYYYMMDDTHHMMSSZ(UTC)开头;
  2. 永远在RRULE:之后声明FREQINTERVAL
  3. 避免SECONDLYBYYEARDAYBYWEEKNO、带数字前缀的BYDAYEXDATERDATE
  4. COUNT控制在 999 以内,且不要与UNTIL同时使用;
  5. 一条调度只写一条RRULE语句。

文档模板体系:这份规范从哪里来

project_schedules_list.md本身是 AWX 自动生成 API 文档体系中的一个 Jinja2 模板:它继承sub_list_create_api_view.md获得 GET 列表与 POST 创建的结构骨架,再通过{% block post_create %}引入 _schedule_list_common.md,后者强调"POST 请求必须包含符合格式约束的rrule",并继续引入 _schedule_detail.md 展开 rrule 的完整格式细则。相同的调度模板块还被schedule_list.mdjob_template_schedules_list.mdinventory_source_schedules_list.md复用(见 awx/api/templates/api/),这意味着本文讲解的 rrule 约束不仅适用于 Project,也适用于 Job Template、Inventory Source 等所有挂载调度的资源,一通则百通。

小结

Project Schedules 端点把"定时更新项目"这一高频运维诉求收敛为一次简单的POST:只要提交合法的rrule,AWX 就会持久化调度、计算next_run并在到期时自动发起带launch_type='scheduled'标记的项目更新作业。理解rrule的格式子集(UTC 的DTSTART、必填的INTERVAL、受限制的BYDAY/BYSETPOS/COUNT)与序列化器层的逐项校验,是写出稳定可用的定时任务的第一步,也是排查 400 报错的关键依据。

【免费下载链接】awxAWX provides a web-based user interface, REST API, and task engine built on top of Ansible. It is one of the upstream projects for Red Hat Ansible Automation Platform.项目地址: https://gitcode.com/gh_mirrors/aw/awx

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

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

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

立即咨询