Can upstart's "service start" be used inside a cron job?
Asked Answered
U

1

9

TLDR; Is it possible to create a cron job that runs service service_name start? How?

Content of my

sudo crontab -e

is:

45 23 * * * service bormarise_celery_daemon start

This runs normally on terminal as root or server:

service bormarise_celery_daemon start
start: Job is already running: bormarise_celery_daemon

But cron gave the following error instead:

bormarise_celery_daemon: unrecognized service
Unsparing answered 30/6, 2015 at 4:6 Comment(0)
U
18

tl;dr

You need to add /sbin to cron's PATH so the service script can find initctl. To do that, add a definition like this to the top of your crontab:

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

You may still run into issues with cron emailing you since initctl exits with status 1 (fail) if the job you try to start is already running. You could get around that with something like:

45 23 * * * service bormarise_celery_daemon status | grep -q running || service bormarise_celery_daemon start

Despite being a bit long, it should only try to run the start command if the bormarise_celery_daemon service isn't running.

service vs initctl

While the service command makes an attempt to manage Upstart jobs, it is not the actual Upstart control function -- that would be initctl and the related suite of short-hand commands (i.e., start, stop, etc.). All of the Upstart scripts reside in /sbin/.

The service command tries to facilitate people spreading services between both Upstart and classic SysV-style scripts. That way you can use one interface (the service script) to manage services from both systems.

Delving into the service Script

If you browse the actual source of the service script (it's just a Bash script) on Ubuntu 14.04, you'll see:

if [ -r "/etc/init/${SERVICE}.conf" ] && which initctl >/dev/null \
   && initctl version | grep -q upstart
then
   # Upstart configuration exists for this job and we're running on upstart
   case "${ACTION}" in
      start|stop|status|reload)
         # Action is a valid upstart action
         exec ${ACTION} ${SERVICE} ${OPTIONS}
      ;;
      restart)
         # Map restart to the usual sysvinit behavior.
         stop ${SERVICE} ${OPTIONS} || :
         exec start ${SERVICE} ${OPTIONS}
      ;;
      force-reload)
         # Upstart just uses reload for force-reload
         exec reload ${SERVICE} ${OPTIONS}
      ;;
   esac
fi

The opening conditional:

  1. Checks if the service you specified (in your case: bormarise_celery_daemon) is an Upstart job. Upstart jobs go into /etc/init/ with a .conf extension.
  2. If it is, the service script will check to see if it can run initctl.
  3. If it can, the service script will then make sure that initctl is a new-enough version.

If all of that is true, then the service script will try to use the appropriate initctl command to run the Upstart job. For example:

service bormarise_celery_daemon start

translates into:

start bormarise_celery_daemon

which is (basically) equivalent to:

initctl start bormarise_celery_daemon

However, if any of those conditions is not true, the service script assumes you're trying to run a SysV-style script. These are just Bash scripts located in /etc/init.d/. However, if no such script exists, it will exit with the unrecognized service error message.

Putting the Pieces Together

The default PATH for cron only contains /bin/ and /usr/bin/. This means it doesn't include /sbin/ which is where the initctl executable is. This means cron will not be able to run initctl.

When cron runs your crontab, the service script is able to find your Upstart job, but it is not able to run the initctl command, so it skips over trying to run your service via Upstart (i.e., initctl). Instead, it then tries to look for a SysV-style script in /etc/init.d/. Since that script doesn't exist, the service script gives up and prints your error message.

If you override cron's default PATH with one including /sbin/, then the service script will be able to find initctl and will attempt to launch your Upstart job.


Interestingly, on Ubuntu 12.04 the service script only checks to see if an Upstart job exists, omitting both initctl checks. That means if you were trying this on Ubuntu 12.04, it would attempt to use Upstart to start your service. However, if /sbin/ isn't on the path, it would fail with a (slightly) more intelligible error message:

/usr/bin/service: 123: exec: start: not found
Unfreeze answered 5/7, 2015 at 1:2 Comment(1)
grep -q with || is very clever. TIL. Thank you!Unsparing

© 2022 - 2024 — McMap. All rights reserved.