Skip to main content

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:

  1. Fetches the named object from the Object Store.
  2. Writes the script content to the appropriate path under /etc/cron.d/ or /etc/cron.{interval}/.
  3. 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 osapi marker.
  • 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​

OperationDescription
ListList all osapi-managed entries
GetGet a specific entry by name
CreateUpload script, then create the entry
UpdateUpload new script version, then update
DeleteUndeploy 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:

TypePathModeNotes
Schedule/etc/cron.d/{name}0644Not executable, root-owned
Interval/etc/cron.{interval}/{name}0755Executable, #!/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 FamilySupport
DebianFull
DarwinSkipped

On unsupported platforms, cron operations return status: skipped instead of failing. See Platform Detection for details on OS family detection.

Permissions​

OperationPermission
List, Getschedule:read
Create, Update, Deleteschedule: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.