I want to automate editing crontabs. I often create or edit identical cron entries on different projects or machines, so automating this will save me time.
01 00 * * * echo "" > /www/apache/logs/error_logA common gotcha with cron is that it doesn’t share the same environment as you do when running your shell – in particular the PATH may be different and commands available to you in your shell may be missing on cron’s default PATH. To help with this, cron allows you to add lines to set environment variables. eg.
PATH=/usr/bin:/usr/local/bin
crontab -l outputs the current users cron entries
crontab -e opens the current users crontab for edit (configure editor with EDITOR environment variable)
Add -u user to your crontab commands to avoid accidentally installing as root for example. (eg crontab -u app_user -e)
crontab - allows us to pipe content into the current users crontab, which is allows us to run commands like this, to manipulate crontab using sed.crontab -l | sed s/PATH=.*/PATH=\\/new\\/vvvpath/ | crontab -
cronedit is a small ruby library that allows us to manipulate crontab using ruby.
gem install croneditHere’s a quick taste of what you can do.
cm = CronEdit::Crontab.new 'app_user'
cm.add 'job1', "5,35 0-23/2 * * * echo 'hello world'"
cm.add 'job2', {:minute=>5, :command=>'echo 42'}
cm.remove 'job3'
cm.commit
Add jobs, either using familiar standard crontab syntax, or using a ruby hash, perhaps easier to read. An interesting thing to note is how it adds labels to your tasks, using comments in crontab. This is used to identify jobs for removal/replacement.
##__job1__ 5,35 0-23/2 * * * echo 'hello world'One shortcoming of cronedit is that it doesn’t provide a mechanism for adding environment variables (eg. PATH). So either take the hit, and add PATH manually, or take another approach, perhaps something like:
current = %x(crontab -l -u app_user)
%x(echo "PATH=/usr/bin:/usr/local/bin\n#{cron}" | crontab -)
or more robustly – check first whether it is there already.
def update_cron_environment(user, key,value)
cron = %x(crontab -l -u #{user})
pattern = Regexp.new("^#{key}.*")
if cron =~ pattern
cron.gsub!(pattern, "#{key}=#{value}"
else
cron = "#{key}=#{value}\n#{cron}"
%x(echo "#{cron}" | crontab -)
end
This gives a toolbox to automate editing my crontabs. But what about….
I’m deploying a rails application, it’s running as a user, used for no other purposes. This works for me.
Keep a file in source control with the app, and on deploy overwrite the current crontab, with the latest version, included with the app. With a crontab file in RAILS_ROOT/config/crontab.txt we can add a simple capistrano task to update the crontab on every deploy.
namespace :cron do
task :update do
%x(cat #{release_path}/config/crontab.txt | crontab -u #{user} -)
end
end
after "deploy:symlink", "cron:update"
If you really can’t stand the crontab syntax, you could combine use this approach, in combination with crondle, a dsl for cron.