Scheduler

Scheduling jobs

Salt’s scheduling system allows incremental executions on minions or the master. The schedule system exposes the execution of any execution function on minions, or any runner on the master.

Scheduling can be enabled by multiple methods:

  • schedule option in either the master or minion configuration files. These require the master or minion application to be restarted for the schedule to be implemented.

  • Minion pillar data. Schedule is implemented by refreshing the minion’s pillar data, for example by using saltutil.refresh_pillar.

  • The schedule state or schedule module. A scheduled run has no output on the minion unless the configuration is set to info level or higher. Refer to minion-logging-settings.

States are executed on the minion. You can pass positional arguments and provide a YAML dictionary of named arguments.

Note

The scheduler executes different functions on the master and minions. When running on the master, the functions reference runner functions. When running on the minion, the functions specify execution functions.

Declaring scheduled jobs

A skeleton structure of a schedule declaration is:

# master or minion configuration
schedule:
  <job1>:
    function: <module.function>
    <kwarg>: <value>
    job_args:
      - <arg1>
      - <arg2>
    kwargs:
      <kwarg1>: <value1>
...

Defining time in schedules

Time for jobs can be specified with valid elements or modifiers:

Time elements:

  • seconds

  • minutes

  • hours

  • days

Scheduling elements:

  • when

  • cron

  • once

Scheduling modifiers:

  • until

  • after

  • range

  • splay

The following keyword arguments can also be used if the python-dateutil Python module is installed.

# python-dateutil options
# date formats can be:
- 2017-04-21 23:46:00
- Thu Sep 25 10:30:00 EDT 2017

# repeat job until a specified time
until: 'Thu Sep 25 23:30:00 EDT 2017'

# do not run job until a specified time
after: '2017-09-25 23:30:00'

# run at a specific time
when: Thu May 02 03:45:30 UTC 2017

This schedules the command state.sls to bind every 3600 seconds (one hour).

schedule:
  Job1:
    function: state.sls
    seconds: 3600
    args:
      - bind

Specifying a random time

The splay kwarg can be used to set a random time within a defined window.

This schedules the command state.sls bind pillar='{"site": "example.com"}' every 300 seconds (five minutes), splaying the time between 0 and 15 seconds:

schedule:
  Job1:
    function: state.sls
    seconds: 300
    args:
      - bind
    kwargs:
      pillar:
        site: example.com
    splay: 15

This schedules the command state.sls bind pillar='{"site": "example.com"}' every 300 seconds (five minutes), splaying the time between 10 and 15 seconds:

schedule:
  job1:
    function: state.sls
    seconds: 300
    args:
      - bind
    kwargs:
      pillar:
        site: example.com
    splay:
      start: 10
      end: 15

Schedule by date and time

The frequency of jobs can also be specified using date strings supported by the Python dateutil library.

This schedules the command state.sls bind at 5:00 PM minion localtime:

schedule:
  job1:
    function: state.sls
    args:
      - bind
    when: 5:00pm

This schedules the command state.sls bind at 5:00 PM on Monday, Wednesday and Friday, and at 3:00 PM on Tuesday and Thursday.

schedule:
  job1:
    function: state.sls
    args:
      - bind
    when:
      - Monday 5:00pm
      - Tuesday 3:00pm
      - Wednesday 5:00pm
      - Thursday 3:00pm
      - Friday 5:00pm

This schedules the command state.sls bind every 3600 seconds (one hour) between the hours of 8:00 AM and 5:00 PM. The range parameter must be a dictionary with date strings using the dateutil format.

schedule:
  Job1:
    function: state.sls
    seconds: 3600
    args:
      - bind
    range:
      start: 8:00am
      end: 5:00pm

Using the invert option for range, this schedules the command state.sls bind every 3600 seconds (one hour) until the current time is between the hours of 8:00 AM and 5:00 PM. The range parameter must be a dictionary with date strings using the dateutil format.

schedule:
  Job1:
    function: state.sls
    seconds: 3600
    args:
      - bind
    range:
      invert: True
      start: 8:00am
      end: 5:00pm

This schedules the function pkg.install to be executed once at the specified time. The range parameter must be a dictionary with date strings using the dateutil format.

schedule:
  job1:
    function: pkg.install
    kwargs:
      pkgs: [{'bar': '>1.2.3'}]
      refresh: true
    once: '2016-01-07T14:30:00'

The schedule entry job1 will not be removed after the job completes, so use schedule.delete to manually remove it afterwards.

The default date format is ISO 8601 but can be overridden by also specifying the once_fmt option, like this:

schedule:
  job1:
    function: test.ping
    once: 2015-04-22T20:21:00
    once_fmt: '%Y-%m-%dT%H:%M:%S'

Maximum parallel jobs running

For jobs that are long-running and could possibly step on each other, or for jobs that could pile up in case of infrastructure outage, the scheduler supports the option maxrunning, the maximum number of copies of the routine that can run. The default for maxrunning is 1.

schedule:
  Long_running_job:
    function: big_file_transfer
    jid_include: True
    maxrunning: 1

Cron-like schedule

The scheduler also supports scheduling jobs using a cron-like format:

# cron format
cron:  '* * * * *'
        | | | | |
        | | | | +--- day of week (0 - 6) (Sunday = 0)
        | | | +----- month (1 - 12)
        | | +------- day of month (1 - 31)
        | +--------- hour (0 - 23)
        +----------- minute (0 - 59)

Note

The cron format requires the python-coniter module.

schedule:
  Job1:
    function: state.sls
    cron: '*/15 * * * *'
    args:
      - bind

Job data return

By default, data about jobs runs from the Salt scheduler is returned to the master.

Setting the return_job parameter to False will prevent the data from being sent back to the Salt master.

schedule:
  job1:
    function: scheduled_job_function
    return_job: False

Job metadata

It can be useful to include specific data to differentiate a job from other jobs. Using the metadata parameter, special values can be associated with a scheduled job.

These values are not used in the execution of the job, but can be used to search for specific jobs later if combined with the return_job parameter.

The metadata parameter must be specified as a dictionary, otherwise it will be ignored.

schedule:
  job1:
    function: scheduled_job_function
    metadata:
      foo: bar

Run on start

By default, any job scheduled based on the startup time of the minion will run the scheduled job when the minion starts up.

Sometimes this is not the desired situation. Setting the run_on_start parameter to False will cause the scheduler to skip this first run and wait until the next scheduled run:

schedule:
  job1:
    function: state.sls
    seconds: 3600
    run_on_start: False
    args:
      - bind

Until and after

Using the until argument, the Salt scheduler allows you to specify an end time for a scheduled job. If this argument is specified, jobs will not run once the specified time has passed. Time should be specified in a format supported by the Python dateutil library.

schedule:
  job1:
    function: state.sls
    seconds: 15
    until: '12/31/2015 11:59pm'
    args:
      - bind

Using the after argument, the Salt scheduler allows you to specify a start time for a scheduled job. If after is specified, jobs will not run until the specified time has passed. Time should be specified in a format supported by the Python dateutil library.

schedule:
  job1:
    function: state.sls
    seconds: 15
    after: '12/31/2015 11:59pm'
    args:
      - bind

Managing jobs and schedules

Managing jobs

Scheduled jobs can be managed with the following functions.

A new job can be added with the following command. This job will run every 15 minutes:

salt \* schedule.add job2 function='state.sls' job_args='["setup.cloud"]' job_ ,!kwargs='{"site": "example.com"}' cron='*/15 * * * *'

The new job will be defined as:

schedule:
  job2:
    args:
      - setup.cloud
    cron: '*/15 * * * *'
    enabled: true
    function: state.sls
    jid_include: true
    kwargs:
      site: example.com
    maxrunning: 1
    name: job1
    return_job: true

Note

Jobs are loaded into the Salt daemon memory space and not saved persistently to disk. The schedule.save function will save the file to /etc/salt/minion.d/_schedule.conf.

The job can then be modified by running:

salt \* schedule.modify job2 function='state.sls' job_args='["setup.cloud"]' job_ ,!kwargs='{"site": "example2.com"}' minutes=60

The new job will be defined as:

schedule:
  job2:
    args:
      - setup.cloud
    enabled: true
    function: state.sls
    jid_include: true
    kwargs:
      site: example2.com
    maxrunning: 1
    minutes: 60
    name: job2

Scheduled jobs can be listed:

salt \* schedule.list

Scheduler operations

The scheduler can be enabled on minions:

salt \* schedule.enable

The scheduler can be disabled on minions:

salt \* schedule.disable

A specific job can be disabled in the scheduler:

salt \* schedule.disable_job job1

A specific job can be enabled in the scheduler:

salt \* schedule.enable_job job1

Jobs can be reloaded from disk by running:

salt \* schedule.reload

Scheduling jobs from pillar

A minion schedule can be set and managed centrally on the Salt master in pillar. A pillar file defining the schedule for a minion would be defined as:

/srv/pillar/schedule.sls
schedule:
  job10:
    args: [rollout.app1_cicd]
    enabled: true
    function: state.sls
    jid_include: true
    kwargs: {site: example.com}
    maxrunning: 1
    name: job10
    return_job: true
    seconds: 3600

This schedule would then be added to the pillar top file to target specific minions. After a refresh of pillar data, a minion would now have the new scheduled jobs combined with locally defined scheduled jobs.

Managing schedules in states

Scheduled jobs can be managed in Salt states with the schedule state module.

This example schedules the command state.sls bind at 5:00 PM on Monday, Wednesday, and Friday, and at 3:00 PM on Tuesday and Thursday.

Note

This requires that python-dateutil is installed on the minion.

job1:
  schedule.present:
    - function: state.sls
    - job_args:
    - bind
    - when:
      - Monday 5:00pm
      - Tuesday 3:00pm
      - Wednesday 5:00pm
      - Thursday 3:00pm
      - Friday 5:00pm

Scheduled jobs can also be specified using the format used by cron. This example schedules the command state.sls bind test=True to run every 5 minutes.

Note

This requires that python-dateutil is installed on the minion.

job1:
  schedule.present:
    - function: state.sls
    - job_args:
      - bind
    - job_kwargs:
        test: True
    - cron: '*/5 * * * *'

This will remove job1 from the schedule:

job1:
  schedule.absent: []

This will disable job1 from the schedule:

disable_job1:
  schedule.disable:
    - name: job1