fix(controller-manager): renumber CronJob day-of-week for the cron crate - #111
Open
vyncint wants to merge 1 commit into
Open
fix(controller-manager): renumber CronJob day-of-week for the cron crate#111vyncint wants to merge 1 commit into
vyncint wants to merge 1 commit into
Conversation
`should_run_now` padded a Kubernetes schedule out to the seven fields the `cron`
crate wants, but the two number days of the week differently: Kubernetes follows
standard cron with 0-6 and Sunday as 0, while `cron` 0.17 uses 1-7 with Sunday as
1. Nothing renumbered the field, so every numeric day was read as the day before
the one requested, and 0 was out of range entirely.
Feeding the expressions the controller built straight to `cron::Schedule`,
searching forward from Saturday 2026-08-01:
schedule expression built first fire intended
0 0 * * 0 0 0 0 * * 0 * parse error Sunday
@Weekly 0 0 0 * * 0 * parse error Sunday
0 0 * * 1 0 0 0 * * 1 * Sun 2026-08-02 Monday
0 0 * * 6 0 0 0 * * 6 * Fri 2026-08-07 Saturday
0 0 * * SUN 0 0 0 * * SUN * Sun 2026-08-02 Sunday
`@weekly` is caught by this because it expands to `0 0 * * 0`, which is the one
value the crate rejects. The failure is silent: a parse error is swallowed into a
warning and `Ok(false)`, and `status.lastScheduleTime` is only written on the
job-creation path, so an affected CronJob reports nothing and keeps an empty
`lastScheduleTime` forever.
Renumber the day-of-week field before handing the expression over. Only value
positions shift: a step (`*/2`) counts intervals rather than days, and day names
already mean the same thing to both, so both pass through. A number outside 0-6
also passes through, which leaves it for the parser to reject rather than
silently turning it into a different day.
The conversion moves out of `should_run_now` into `to_cron_expression`, a free
function, so the mapping can be tested without a controller or storage. Seven-field
input is left alone — it is already in the crate's own format, and renumbering it
would shift a day that was never in Kubernetes numbering.
The existing `test_cron_schedule_parsing` asserted string literals
(`assert_eq!("@hourly", "@hourly")`) and exercised neither the conversion nor the
parse, which is why none of this was visible. It is replaced by five tests that assert
the weekday a schedule actually fires on, covering all seven day numbers,
day names, `@weekly`, lists, ranges, steps, and the untouched fields.
Reverting only the renumbering with the tests in place fails exactly three of
them — the day numbers, `@weekly`, and the list/range/step cases — and leaves the
name and non-weekday tests passing.
Fixes calfonso#110
Signed-off-by: Vyncint Ng <vyncint@icloud.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #110.
should_run_nowpadded a Kubernetes schedule out to the seven fieldsthe
croncrate wants, but the two number days of the week differently:cron0.17: 1-7, Sunday = 1Nothing renumbered the field, so every numeric day was read as the day before the
one requested, and
0was out of range entirely. Feeding the expressions thecontroller built straight to
cron::Schedule, searching forward from Saturday2026-08-01:
0 0 * * 00 0 0 * * 0 *@weekly0 0 0 * * 0 *0 0 * * 10 0 0 * * 1 *0 0 * * 60 0 0 * * 6 *0 0 * * SUN0 0 0 * * SUN *@weeklyis caught by this because it expands to0 0 * * 0atcronjob.rs:354,which is the one value the crate rejects. Day names are unaffected — both
numberings agree on those.
The failure is silent. A parse error is swallowed at
cronjob.rs:379-382into awarning and
Ok(false), andstatus.lastScheduleTimeis only written on thejob-creation path (
:396), so an affected CronJob reports nothing and keeps anempty
lastScheduleTimeforever.Change
Renumber the day-of-week field before handing the expression to the crate. Only
value positions shift:
010,31,41-52-61-5/22-6/2*/2*/2MON-FRIMON-FRI99The conversion moves out of
should_run_nowintoto_cron_expression, a freefunction, so the mapping is testable without a controller or storage. Seven-field
input is left alone: it is already in the crate's own format, and renumbering it
would shift a day that was never in Kubernetes numbering.
Validation
No cluster and no container runtime — plain
cargo test.test_cron_schedule_parsingasserted string literals(
assert_eq!("@hourly", "@hourly")) and exercised neither the conversion nor theparse, which is why none of this was visible. It is replaced by five tests that
assert the weekday a schedule actually fires on:
test_day_of_week_numbers_follow_kubernetes(all seven days)test_weekly_shortcut_runs_on_sundaytest_day_of_week_lists_ranges_and_stepstest_day_of_week_names_are_unchangedtest_non_weekday_fields_are_untouchedReverting only the renumbering with the tests in place fails exactly those three
and leaves the name and non-weekday tests passing, which is what shows the change
is confined to numeric day-of-week values:
cargo test --workspace --locked: 140 suites, 4250 tests, 0 failedcargo fmt(workspace members, as the fmt workflow runs it): cleancargo clippy --workspace --all-targets --locked: no warnings incrates/controller-manager/src/controllers/cronjob.rs