Scheduling Tasks in ESXi Using Cron

The utility “cron” is a job scheduler in Linux/Unix based operating systems. It is very useful for scheduling scripts or specific commands to run on a defined schedule – daily, weekly, monthly and everything in between. Thankfully, ESXi includes an implementation of the cron utility that can be accessed from the root shell. Normally, you wouldn’t need to use cron, but there are some situations where scheduling CLI commands can be useful.

A few use cases where I’ve personally done this over the years include:

  • To collect switchport statistics at certain times overnight to troubleshoot packet loss or performance issues.
  • Restarting a specific service every 24 hours to prevent a memory leak from getting out of hand.
  • Executing a python or shell script to collect various data from the CLI.

ESXi’s implementation of cron is similar to that of most linux distributions, but it is not exactly the same. The popular ‘crontab’ command isn’t included and can’t be used to easily add jobs. In addition, any cron changes you make won’t take effect until the crond service is restarted.

Preparation

Before changing the cron configuration, you’ll want to test the command or script you plan to schedule. In my case, I’m going to simply run an esxcli command every two minutes that will add a mark entry into the system log files:

 [root@esx1:~] esxcli system syslog mark --message="My cron job just ran!"

 [root@esx1:~] cat /var/log/vmkernel.log |grep "mark:"
 2021-02-17T17:39:00Z esxcfg-syslog[2102126]: mark: My cron job just ran! 

As you can see above, this is a great way to test out cron because every time it runs you’ll get proof in the logging along with a date/time stamp.

Tip: If you are adding a script to your host, avoid the /tmp location as it is not persistent across reboots. I like to use /opt in older releases, or the OSData partition in ESXi 7.0.

Also, if you are not familiar with crontab formatting, I’d recommend reading up on the subject to make sure your jobs run as expected. There are a number of good resources online that will show you the various scheduling options. I have included a few examples at the end of this post as well.

Adding a Cron Job

You’ll first need to SSH into your ESXi host. Once there, you can see the current crontab file at /var/spool/cron/crontabs/root. In ESXi 7.0, the file contains:

 [root@esx1:~] cat /var/spool/cron/crontabs/root
 #min hour day mon dow command
 1    1    *   *   *   /sbin/tmpwatch.py
 1    *    *   *   *   /sbin/auto-backup.sh
 0    *    *   *   *   /usr/lib/vmware/vmksummary/log-heartbeat.py
 */5  *    *   *   *   /bin/hostd-probe.sh ++group=host/vim/vmvisor/hostd-probe/stats/sh
 00   1    *   *   *   localcli storage core device purge
 */10 *    *   *   *   /bin/crx-cli gc
 */2 * * * * esxcli system syslog mark --message="My cron job just ran!" 

As you can see, ESXi already uses cron to schedule several internal housekeeping routines. Before changing the file, be sure to back it up just in case:

cp /var/spool/cron/crontabs/root /var/spool/cron/crontabs/root.old

You can modify the file using ‘vi’. For those not familiar with Linux, there is a bit of a learning curve to vi so I’d recommend reading up on how to navigate around in it. There are quite a few good turorials available online.

[root@esx1:~] vi /var/spool/cron/crontabs/root

Note: When using :wq to save your changes, you’ll likely get a warning that the file is read only. You don’t need to fiddle with the permissions. Simply use :wq! and the file will be written successfully.  

I have added a single line at the bottom of the file. Here is the updated root crontab file:

#min hour day mon dow command
 1    1    *   *   *   /sbin/tmpwatch.py
 1    *    *   *   *   /sbin/auto-backup.sh
 0    *    *   *   *   /usr/lib/vmware/vmksummary/log-heartbeat.py
 */5  *    *   *   *   /bin/hostd-probe.sh ++group=host/vim/vmvisor/hostd-probe/stats/sh
 00   1    *   *   *   localcli storage core device purge
 */10 *    *   *   *   /bin/crx-cli gc
 */2  *    *   *   *   esxcli system syslog mark --message="My cron job just ran!" 

Note: As mentioned previously, if you are not familiar with the min/hour/day/mon/dow formatting that cron uses, there are a number of good resources online that can help.

Despite updating the file, your changes will not take effect until the crond service is restarted on the host. First, get the crond PID (process identifier) by running the following command:

[root@esx1:~] cat /var/run/crond.pid
2098663

Next, kill the crond PID. Be sure to change the PID number to what you obtained in the previous step.

[root@esx1:~] kill 2098663

Once the process is stopped, you can use BusyBox to launch it again:

[root@esx1:~] /usr/lib/vmware/busybox/bin/busybox crond

You’ll know it was restarted successfully if you have a new PID now:

[root@esx1:~] cat /var/run/crond.pid
2103414

After leaving the host idle for a few minutes, you can see the command has been running every two minutes as desired:

[root@esx1:~] cat /var/log/vmkernel.log |grep -i mark:
2021-02-17T17:39:00Z esxcfg-syslog[2102126]: mark: My cron job just ran!
2021-02-17T20:16:00Z esxcfg-syslog[2103370]: mark: My cron job just ran!
2021-02-17T20:18:00Z esxcfg-syslog[2103382]: mark: My cron job just ran!
2021-02-17T20:20:00Z esxcfg-syslog[2103396]: mark: My cron job just ran!

As you can imagine, the possibilities are endless here. I will share some of the scripts I have used to collect some performance metrics via cron in a future post.

Crontab Examples

Run a command every two minutes:

#min hour day mon dow command
*/2    *    *   *   *   esxcli system syslog mark --message="My cron job just ran!"

Run a command every hour:

#min hour day mon dow command
*    */1    *   *   *   esxcli system syslog mark --message="My cron job just ran!"

Run a command at midnight every night:

#min hour day mon dow command
00    0    *   *   *   esxcli system syslog mark --message="My cron job just ran!"

Run a command at 3:30PM every Thursday:

#min hour day mon dow command
30    15    *   *   5   esxcli system syslog mark --message="My cron job just ran!"

Run a command at midnight and at noon every day:

#min hour day mon dow command
00    0,12    *   *   *   esxcli system syslog mark --message="My cron job just ran!"

9 thoughts on “Scheduling Tasks in ESXi Using Cron”

  1. Hi Mike, remember to say that is necessary to make a copy in /etc/rc.local.d/local.sh to active it on the next reboot:
    /bin/echo “*/2 * * * * esxcli system syslog mark” >> /var/spool/cron/crontabs/root

  2. Hi Mike,
    I am setting up a task to run using cron, however when my ESXi host restarts the crontab is reverted to its original state without my added command.

    Everything works fine until the host is restarted.

    Do you have any suggestions on how this could be fixed?

    1. Hi Matt,

      Check this one https://virtuallyvtrue.com/2019/03/29/shell-script-to-automatically-power-on-a-specific-vm-which-is-powered-off-vm/

      Add commands to /etc/rc.local.d/local.sh to re-generate the cron job when ESXi host reboots

      Edit /etc/rc.local.d/local.sh using a command such as “vi /etc/rc.local.d/local.sh“.
      At the end of the file just above ‘exit 0’, add following 3 lines. The first kills crond, the second adds the new cron job to the root crontab file, and the third restarts crond:
      /bin/kill $(cat /var/run/crond.pid)
      /bin/echo ‘0 */5 * * * /vmfs/volumes/lun1/power-on.sh’ >> /var/spool/cron/crontabs/root
      crond

      Save and exit the file
      Run the command “auto-backup.sh” so that the change to /etc/rc.local.d/local.sh survives a reboot.

    1. `touch /var/spool/cron/crontabs/cron.update` (not crontabs not crontab) — thanks this works well

  3. Hi George,
    I modified /etc/rc.local.d/local.sh and added
    /bin/kill $(cat /var/run/crond.pid)
    /bin/echo ‘0 */5 * * * /vmfs/volumes/datastore1/myscript.sh’ >> /var/spool/cron/crontabs/root
    crond

    It worked only once after rebooting I saw that the root crontab had the changes I made.
    After that I wrote a script to add these 3 lines to /etc/rc.local.d/local.sh as part of my installation process.
    Now I guess /etc/rc.local.d/local.sh does not run at the restart because I don’t see the myscript.sh added to /var/spool/cron/crontabs/root. It always reverts back.

    What could have gone wrong. I copied another file /etc/rc.local.d/local.sh.mod to /etc/rc.local.d/local.sh
    Could that be a problem?

    Thanks
    Deepali

    1. Possibly you have UEFI secure boot enabled? If that is the case the script will not be executed during boot.

Leave a comment