How do I evaluate a class not on every puppet run?

I would like to have a method that only evaluates a particular class once a day at a specific time. Right now I am running my puppet agent from the cron, but I would like to change it to either run as a daemon, or run more frequently. The barrier with increasing the frequency is that there is one class that takes about 4 minutes to process, and doesn't need to happen very often. I am trying to find some method to only evaluate that particular class once a day from cron.

Is there a simple method for me to set an environment variable (FOO=bar;puppet agent ..), or add a command line option (puppet agent .. --foo bar) to the crontab that will become a fact I can use in my manifests to include or not include the class?

class foobar {
  if 'bar' == $::foo {
    # do the slow stuff
  }
}

A schedule sounds like it'll provide what you're looking for. First you create a schedule resource that specifies when things can run and how many times in a given period.

schedule { "slow":
  range  => "1 - 5",
  period => daily,
  repeat => 1,
}

The example above will only be evaluated or run during the hours of 1am and 5am and a maximum of once. You can remove the range parameter and it'll run any time of the day, but again, only once.

On resources, you then specify the schedule meta-parameter to link them to the above schedule:

exec { "example":
  command  => "/usr/bin/foo",
  unless   => "/usr/bin/bar",
  schedule => "slow",
}

When you run Puppet with --debug, you'll now see the following if it's already been evaluated the given number of times, or the range isn't applicable:

debug: /Stage[main]//Exec[example]: Not scheduled

If you've got a few resources, you could use resource defaults inside the class you're restricting to affect all resources of the same type:

Exec {
  schedule => "slow",
}

You'd need to do this for each resource type - Exec, File, Augeas etc.

Couple of notes on improving this:

  • I don't know a way to apply it to all types of resources in the class
  • Applying the schedule meta-parameter to a class doesn't appear to work, might be worth raising a bug

I believe you can accomplish this via an Environment declaration. You invoke it on the command-line:

puppet agent --environment latetbus

You can use it to specify a different manifest in the puppet.conf file:

[latebus]
  manifest = $confdir/latetbus/site.pp

And even can do different modules that way.

There is also a method for adding custom facts to facter. This leverages plugins to make work. You create a custom ruby file to check for something:

# run_latebus.rb

facter.add("latebus_exec") do
    setcode do
        %x{if [ -e /tmp/run_latebus ] ; then echo "true" ; else echo "false" ; fi}.chomp
    end
end

Where the puppet agent invocation script would touch /etc/run_latebus before starting puppet agent, which is evaluated by Facter during the puppet run.

The .rb file is placed in a custom module, specifically in the lib/facter directory of the module itself.