Repository navigation
issue#133: Automation Networks scheduler, Telnet skip-username, bulk device edit - #197
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Corrupted PHP source prevents plugin loading and test collection, while unresolved scheduling and Telnet authentication defects can trigger unwanted backups or failed logins.
4 open issues
What changed in this PR
Extends RouterConfigs with the remaining scheduling, Telnet login, and bulk-edit features from #133, building on the earlier TFTP and Cacti-device import work.
Changes:
- Adds schedule types and recurrence settings for 10-day and calendar-month backups, with legacy schedule migration.
- Adds password-only Telnet login handling when no username is configured.
- Adds bulk device editing with a “No Change” option for each setting.
| File | Description |
|---|---|
tests/Unit/RouterconfigsSchedulerTest.php |
Adds scheduler calculation and delegation test cases. |
tests/Unit/RouterconfigsScheduleMigrationTest.php |
Adds legacy schedule migration test cases. |
tests/bin/patch-coverage.php |
Excludes collection-time constant declarations from patch coverage. |
setup.php |
Invokes schedule migration after schema upgrades. |
router-devices.php |
Adds bulk editing and persists scheduler settings. |
phpunit.xml |
Adds scheduler coverage and removes constants coverage. |
locales/po/cacti.pot |
Updates translation strings for scheduling and bulk editing. |
INFO |
Bumps the plugin version to 1.10. |
includes/scheduler.php |
Adds plugin-local scheduling calculations and optional core delegation. |
includes/functions.php |
Initializes imported schedules and integrates next-backup calculation. |
includes/database.php |
Adds scheduler columns and legacy migration logic. |
includes/constants.php |
Defines the bulk-edit action identifier. |
includes/arrays.php |
Adds schedule controls, recurrence choices, and bulk-edit action. |
classes/PHPTelnet.php |
Adds a login path that skips the username prompt. |
CHANGELOG.md |
Documents the three feature additions. |
.gitignore |
Ignores PHPUnit cache files. |
Review effort: Balanced
da01aea to
8c574b6
Compare
8c574b6 to
1b92698
Compare
1b92698 to
ef91c61
Compare
somethingwithproof
left a comment
There was a problem hiding this comment.
Blocker: Monthly without a day of month skips February, then drifts. When day_of_month is empty, plugin_routerconfigs_schedule_normalize() falls back to date('j', $after), the day of the current run. A run on Jan 31 asks for "February 31 2026", which strtotime() turns into 2026-03-03. February gets no backup, and the device runs on the 3rd from then on. Any late retry moves the day again. Every migrated or newly set Monthly device starts with day_of_month empty, so all of them hit this. Store the day when the device is saved or migrated, or clamp to the last day of the month (day_of_month = 32).
Suggestion: bulk edit doesn't validate the values it writes. plugin_routerconfigs_bulk_edit_set() casts sched_type, account and devicetype to int without checking them against the offered options. An unknown sched_type makes plugin_routerconfigs_schedule_next_start() return 0, so the device is due on every daily scheduled run. Check sched_type against plugin_routerconfigs_sched_types(), and account and device type against existing rows. save_devices() should get the same sched_type check.
Suggestion: Weekly with specific weekdays ignores Rerun Every. With Monday selected and Rerun Every 2, the device runs every week. The field's description promises "every X weeks". Either honor recur_every in the weekday branch or hide the field once weekdays are picked.
Suggestion: changing the schedule doesn't recompute nextbackup. Neither the edit form nor bulk edit updates it, so a device moved from Daily to Monthly runs once more on the old Daily schedule. Recomputing it from plugin_routerconfigs_schedule_next_start() on save would fix both paths.
…le on change Monthly without a day of month used the day of the current run, so a Jan 31 run asked for "February 31", which strtotime() turned into March 3, and the device drifted from then on. A Monthly schedule saved, or bulk-set, without a day now stores the day it was set up on (Last, 32, after the 28th so short months still run), and the calculator falls back to the 1st rather than the run day. Days a month does not have (February 30, April 31) are skipped, as RFC 5545 section 3.3.10 requires, instead of rolling into the next month. The replica is now used on every Cacti version. Core's api_scheduler_calculate_next_start() rolls nonexistent dates over, so delegating to it on 1.3+ would give the same device different backup dates on 1.2 and 1.3. Bulk edit validated nothing: sched_type, account and devicetype were cast to int, so an unknown sched_type resolved to 0 and the device ran on every scheduled poll. plugin_routerconfigs_bulk_edit_validate() now accepts only the offered Schedule Types, Rerun Every 1-31, a known Connection Type, and existing accounts and device types; anything else raises an error and nothing is changed. save_devices() checks Schedule Type and Rerun Every the same way. Changing the schedule now recomputes nextbackup on the device form and in bulk edit, so a device moved from Daily to Monthly no longer runs once more on the old schedule. Manual stores 0, which the download query excludes. A device that has never been scheduled keeps NULL so its first backup still runs next. Bulk edit reads the selected rows once and groups devices with identical results into one UPDATE ... WHERE id IN (...). Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Now that nonexistent dates are skipped, a Monthly schedule on February 29 alone has no date in 2026 or 2027. The calculator tried only this year and next, so it returned 0 and the device became due on every scheduled run. It now searches 8 years, the longest gap between leap years (2096 to 2104), and still returns false for a day that never exists, such as February 30. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
somethingwithproof
left a comment
There was a problem hiding this comment.
Rechecked against the previous review. All four findings are resolved:
- Monthly with no day of month now stores a fixed day on save (32 once past the 28th), and the normalize fallback is the 1st, so a Jan 31 run no longer skips February or drifts.
save_devices()and bulk edit validatesched_type,recur_every, account, device type and connection type against what the form offers, and apply nothing if any value is bad.- Weekly + Rerun Every can't be reached in this PR, since there is no Days of Week field yet.
nextbackupis recomputed when a schedule field changes, on both the edit and bulk paths.
Nit: includes/scheduler.php:279 adds offset * 86400 to a local-midnight base. When the offset crosses a DST change, that one run lands an hour early or late (a Weekly 02:00 backup runs at 03:00 once). The next recompute corrects it. Building the candidate with strtotime('+N days', $base) would avoid it.
No blockers. CI is green.
|
Pushed fixes for the review points:
Tests: new Profiling (PHP 8.5, M3 Max, median of 11): To revisit:
|
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
d971476
|
|
Automated validity review of @somethingwithproof's commits (8677063, 8aa842a, d971476) Reviewed and validated: full Pest suite passes (208 tests, 100% patch coverage), all integration legs (PHP 8.2–8.6) and SonarCloud are green, and the new One design-decision note worth a maintainer confirmation (not a code blocker): commit 8677063 removes the core |





Description
This is the first PR in a stacked chain addressing the four open RouterConfigs feature requests (#133 → #117 → #130 → #109). It implements the three remaining parts of #133 (the per-device TFTP server and the add-from-Cacti-Devices import were merged earlier in #183/#185 and #184):
Automation Networks style scheduler — replaces the fixed
Daily / Weekly / Monthly (= every 10 days)device schedule with aSchedule Type+Rerun Everymodel mirroring Cacti core's Automation Networks scheduler (sched_type,recur_every, and theday_of_week/month/day_of_month/monthly_week/monthly_dayfields). This delivers both an explicit 10-day cadence (Daily, Rerun Every 10) and a true calendar Monthly backup. Because core'slib/api_scheduler.phpships only on Cacti 1.3+ (it is absent from1.2.x) and this plugin'scompatis1.2.29, the next-run calendar math is a plugin-local replica (includes/scheduler.php) that delegates to core'sapi_scheduler_calculate_next_start()when it exists (1.3+) and runs the ported logic otherwise. Existing devices are migrated automatically and idempotently: legacy weekly (7) becomes a true Weekly, every other interval becomesDaily / rerun-every-N, preserving the original cadence (so the old "Monthly" = every 10 days becomesDaily / rerun-every-10).Telnet skip-username — when a device/account has no username configured, the Telnet login skips the username prompt and waits directly for the password prompt, so password-only Telnet devices can be backed up.
Bulk device edit — a new
Edit (bulk change settings)action on the Devices list lets you change Enabled, Schedule Type, Rerun Every, Connection Type, Authentication Account, and Device Type across many devices at once; each field offers aNo Changeoption so untouched settings are left alone.The day-of-week / day-of-month selectors and date-nested backup directories build on this scheduler in the next PR of the chain (#117).
Related Issue
#133
Motivation and Context
The previous scheduler could only express Daily / Weekly / "Monthly", and "Monthly" was actually every 10 days, with no way to pick a real calendar month or a 10-day cadence. The schema and next-run logic now follow the established Cacti Automation Networks pattern, giving operators the schedule types requested in #133 while remaining compatible with Cacti 1.2.29+.
How Has This Been Tested?
Ran the plugin's Pest suite from a Cacti checkout with the plugin as a real
plugins/routerconfigsdirectory:pest --configuration phpunit.xml→ 168 passed (1084 assertions). Addedtests/Unit/RouterconfigsSchedulerTest.php(19 cases covering Manual, Daily, the 10-day cadence, Weekly with/without weekdays, true Monthly, Monthly-on-Day, year roll-over, last-day-of-month, the legacy fallback, Hourly, the unknown-type guard, and core delegation) andtests/Unit/RouterconfigsScheduleMigrationTest.php(migration mapping + idempotency).php tests/bin/patch-coverage.php coverage/clover.xml origin/develop 100→ 100.00% (136/136 lines).php tests/bin/check-i18n-pot.php origin/develop→ OK (locales/po/cacti.potregenerated; per-language.po/.moleft to Weblate).php -lclean on every changed file.php tests/bin/validate-manifest.php→ matches (includes/already covered).includes/constants.phpwas moved out of the instrumented<source>set and into the patch-coverage allowlist: it contains onlydefine()declarations, and is loaded at Pest collection time (before coverage starts) via a top-levelrequirein a Security test, so its lines can never register as covered.Types of changes
Checklist: