Schedule Management
OSAPI manages scheduled entries on target hosts. It supports two placement modes:
- Custom schedule — writes to
/etc/cron.d/{name}with a 5-field cron expression - Periodic interval — writes to
/etc/cron.{hourly,daily,weekly,monthly}/as executable scripts
Scheduled entries reference scripts stored in the NATS Object Store by name. Upload a script first with the file management commands, then create an entry pointing at it. This separates script content from scheduling configuration and enables versioned updates.
How It Works
Object-Based Workflow
The cron provider is a meta provider: it does not embed script content
directly. Instead, each entry holds an object name that references a file in
the NATS Object Store. When the agent deploys or updates an entry, it:
- Fetches the named object from the Object Store.
- Writes the script content to the appropriate path under
/etc/cron.d/or/etc/cron.{interval}/. - Records the deploy state in the file-state KV bucket (SHA-256, path, timestamps).
Both create and update are idempotent on content: the agent compares the
content it was asked to deploy with the file on disk and rewrites it only when
they differ, so an entry edited by hand is restored. create is the one
exception worth knowing: when an entry of the same name already exists under a
different schedule, it reports changed: false rather than writing a second
copy in another directory. Use update to move it.
Custom Schedule (/etc/cron.d/)
For entries with a schedule field, the provider writes a drop-in file. The
file content comes from the referenced object in the Object Store:
0 2 * * * root /usr/local/bin/backup.sh --full
The file is owned by root with mode 0644. No header comment is written;
ownership is tracked via the file-state KV instead.
Periodic Interval (/etc/cron.{interval}/)
For entries with an interval field, the provider writes an executable script
to the matching interval directory. The file content comes from the referenced
object — it should include a #!/bin/sh shebang:
#!/bin/sh
/usr/sbin/logrotate /etc/logrotate.conf
The file is written with mode 0755 so run-parts can execute it.
schedule and interval are mutually exclusive — provide exactly one. The API
validates this and returns 400 if both or neither are provided.
File-State KV Tracking
Deploy state is recorded in the file-state KV bucket rather than embedded in the deployed file as a header comment. This means:
- Deployed cron files contain only the script content — no
# Managed by osapimarker. - The list and get operations query the file-state KV to discover managed entries; manually created files are left untouched.
- State persists in the KV until explicitly removed — deleting an entry undeploys the file from disk but preserves the file-state record.
Template Support
If the referenced object was uploaded with content_type: template, the agent
renders it as a Go text/template before writing to disk. Pass variables at
deploy time with --vars:
# Upload a template script
osapi client node file upload --name backup-script.tmpl \
--content-type template --file ./backup.sh.tmpl
# Create a scheduled entry that renders the template on deploy
osapi client node schedule create --target web-01 \
--name backup --schedule "0 2 * * *" \
--object backup-script.tmpl \
--vars "retention_days=30,s3_bucket=my-bucket"
Template variables are merged with the agent's system facts and hostname. See File Management for the full template context reference.
Operations
| Operation | Description |
|---|---|
| List | List all osapi-managed entries |
| Get | Get a specific entry by name |
| Create | Upload script, then create the entry |
| Update | Upload new script version, then update |
| Delete | Undeploy cron file from disk |
CLI Usage
# Upload a script to the Object Store first
osapi client node file upload --name backup-script \
--file ./backup.sh
# Create with a custom schedule (/etc/cron.d/)
osapi client node schedule create --target web-01 \
--name backup --schedule "0 2 * * *" \
--object backup-script --user root
# Create with an interval (/etc/cron.daily/)
osapi client node schedule create --target web-01 \
--name logrotate --interval daily \
--object logrotate-script
# List all managed entries
osapi client node schedule list --target web-01
# Get a specific entry
osapi client node schedule get --target web-01 --name backup
# Update: upload a new script version and redeploy
osapi client node file upload --name backup-script \
--file ./backup-v2.sh --force
osapi client node schedule update --target web-01 \
--name backup --schedule "0 3 * * *" \
--object backup-script
# Delete an entry (undeploys file from disk; state preserved in KV)
osapi client node schedule delete --target web-01 --name backup
All commands support --json for raw JSON output.
File Permissions
The provider sets file ownership and modes to match cron requirements:
| Type | Path | Mode | Notes |
|---|---|---|---|
| Schedule | /etc/cron.d/{name} | 0644 | Not executable, root-owned |
| Interval | /etc/cron.{interval}/{name} | 0755 | Executable, #!/bin/sh shebang |
Files are created as root (the agent runs as root). Names must not contain dots
— run-parts skips dotfiles.
Undeploy Behavior
Deleting an entry undeploys the file: it is removed from the filesystem, but the file-state KV record is preserved. This means:
- Re-creating the entry with the same name and object will detect the prior state and only write the file if the content differs.
- The KV record serves as an audit trail of what was last deployed.
To remove the file-state record entirely, delete the corresponding file-state entry via the file management API after removing the scheduled entry.
Supported Platforms
| OS Family | Support |
|---|---|
| Debian | Full |
| Darwin | Skipped |
On unsupported platforms, cron operations return status: skipped instead of
failing. See Platform Detection for details on
OS family detection.
Permissions
| Operation | Permission |
|---|---|
| List, Get | schedule:read |
| Create, Update, Delete | schedule:write |
All built-in roles (admin, write, read) include schedule:read. The
admin and write roles also include schedule:write.
Naming Rules
Entry names must be alphanumeric with hyphens and underscores only (pattern:
^[a-zA-Z0-9_-]+$). Names like backup-daily, log_rotate, and health_check
are valid. Names containing /, .., or spaces are rejected.
Idempotent Updates
The update operation compares the new content against the existing file using
the SHA-256 stored in the file-state KV. If the script content and scheduling
parameters are unchanged, the response returns changed: false. This makes it
safe to run updates repeatedly without generating unnecessary filesystem writes.
Future: Crontab and Systemd Timers
Cron drop-in management is the first provider under the schedule domain.
Future providers will add:
- Crontab — user-level crontab management (
crontab -u <user>) - Systemd Timers — systemd timer unit management
These will be separate API endpoints under /node/{hostname}/schedule/crontab
and /node/{hostname}/schedule/timer.
Related
- File Management — uploading scripts and template rendering
- CLI Reference — schedule commands
- Platform Detection — OS family detection
- Configuration — full configuration reference