wget not executed through cronjob but directly in console - cron

I have an TP Link Archer C7 with 15.05 Chaos Calmer at home.
I am trying to get the cronjob to work. It looks like this:
* * * * * /usr/bin/wget --spider \"https://subdomain.domain.net/update.php\" >/dev/null 2>&1
Unfortunately this does not get executed. I also tried to do* * * * wget -O - https://subdomain.domain.net/update.php same result.
BOTH versions are executed correctly if entered through the console directly.
Last line of logread
Tue Sep 20 11:55:00 2016 cron.info crond[10317]: USER xxx pid 16697 cmd /usr/bin/wget --spider \"https://subdomain.domain.net/update.php\" >/dev/null 2>&1
Looks correct? Any idea why it is not executed through the cronjob?

Your cron job does run, but wget runs into an error.
Also to get a log, i.s.o. redirecting to /dev/null, you cannot use /out.txt, as cron will have no write access to /, /tmp/wget.txt will do fine.
Same goes for the wget command, where does the output get stored? you should use use -p <directory prefix> option.
Secondly you need to handle if data is already in that directory, which could be to use -N and only download newer files and override the old ones.
Thirdly use the -q option when all is working to quiet down wget output.
Fourthly you cannot run the script every minute * * * * *, as previous run might not have finished yet, see format:
# ┌───────────── min (0 - 59)
# │ ┌────────────── hour (0 - 23)
# │ │ ┌─────────────── day of month (1 - 31)
# │ │ │ ┌──────────────── month (1 - 12)
# │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to
# │ │ │ │ │ Saturday, or use names; 7 is also Sunday)
# │ │ │ │ │
# │ │ │ │ │
# * * * * * command to execute
For the sake of test let's run it every night at 1 past midnight.
Remark: To really make it correct, you should use a script file to execute and put wget command in there, where as the script file could make a lock in case you want to execute this frequently, see here for advice as this is beyond the scope of this question/answer.
And Number 5: don't need to escape the " with \", even so the " is not needed, so remove it.
In conclusion, make first a directory where data can be stored e.g. /wget_data
mkdir /wget_data
chmod 777 /wget_data
then adjust your cron line, add the -p <directory prefix> and -N and adjust the execute format:
1 0 * * * /usr/bin/wget -N -p /wget_data --spider https://subdomain.domain.net/update.php >/tmp/wget.txt 2>&1
and restart your cron, can't advice on that, don't known what is used yet.
also wise would be to to test your command from the command line first with:
/usr/bin/wget -N -p /wget_data --spider https://subdomain.domain.net/update.php >/tmp/wget.txt 2>&1
and then cat /tmp/wget.txt to see if the command worked, and ls /wget_data to see if wget did collect data.

Main things you need to check:
If crond is up and running ( top , ps -A )
If crond has enough permissions to execute wget ( ls -l /usr/bin )
If wget does not produce any errors (don't throw away output to /dev/null, store it in some file and then check firstly - if file created at all, if not - tripple check things 1 and 2, if file is created and there is some information - it could be helpful)
Related to items 1 and 2. Check what user running crond and try to execute command using this user.
Try execute not wget but some command that will write some string to some file and check if it will works.

Related

crontab not being executed into a container after setting up permissions

I'm running a docker container with an image:
ubi8/ubi-minimal
The cronjob has correct path and go packet is already installed:
crontab -l
*/2 * * * * go run /usr/local/src/script.go
The file has correct permissions:
-rw-r-xr-x 1 root root 6329 Jun 16 15:10 script.go
However the crontab -e is like this:
/bin/sh: /usr/bin/vi: No such file or directory
crontab: "/usr/bin/vi" exited with status 127
and
cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
The crontab was added in the dockerfile like this:
RUN crontab -l | { cat; echo "*/2 * * * * go run /usr/local/src/script.go"; } | crontab -
I think is correctly setup isn't it?
the crontab should execute the script every 2 minuts but it's not. Also the image is minimal and I cannot edit any file I just included some permissions to the files from the dockerfile.
If needed to change any Path from crontab I have to do this trough the dockerfile.
As it sounds like a lot of trouble, consider skipping the cron daemon entirely and just sleep in a loop
#!/bin/sh
while true; do
TIME_LOOP_START=$(date +%s) # integer time in seconds
script.go
# calculate offset for 2 minutes in seconds
sleep $(($TIME_LOOP_START + 120 - $(date +%s)))
done
adapted from
https://askubuntu.com/questions/852070/automatically-run-a-command-every-5-minutes
Get current time in seconds since the Epoch on Linux, Bash
You may find this is even better extended by making the time and target executable arguments $1 $2
You need to start the cron daemon. Here's a Dockerfile I made to illustrate
FROM registry.access.redhat.com/ubi8/ubi-minimal
RUN microdnf update && microdnf install cronie
RUN crontab -l | { cat; echo "*/2 * * * * /usr/local/src/script.sh"; } | crontab -
COPY script.sh /usr/local/src/
CMD crond -n
Note that the CMD runs crond with the -n option which keeps crond in the foreground. If we let it daemonize, docker would see that the process had ended and would terminate the container.
Instead of using go, I made a small shell script like this, called script.sh
#/bin/sh
echo Hello from script >> ~/log.txt
It writes to /root/log.txt every 2 minutes.

Why is my docker container not executing my cron job?

I have a node script that I want to run periodically so I created the following Dockerfile to run it from a cron task:
FROM node:8
RUN apt-get update && apt-get install -y cron
# ensure the node packages are installed in the image
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
# copy the node task to working directory
COPY db-update.js .
# copy the script which will start cron to the working directory
COPY startcron.sh .
# copy the cron task to the cond.d directory
COPY crontask /etc/cron.d/crontask
# give execution rights on the cron job and script
RUN chmod 0644 /etc/cron.d/crontask && chmod 777 ./startcron.sh
# apply the cron job
RUN crontab /etc/cron.d/crontask
# create the log file to be able to run tail
RUN touch /var/log/cron.log
# execute the command in the foreground
CMD /usr/src/app/startcron.sh
In startcron.sh bash script I have the following:
#!/bin/bash
set -e
printenv | sed 's/^\(.*\)$/export \1/g' > /tmp/env.sh
echo 'Starting cron' # <- ONLY THIS APPEARS IN MY CONTAINER LOGS
cron -f
I needed to create /tmp/env.sh to export the environmental variables my node script requires. This script should then start cron in the foreground. My crontask should "source" those environmental variables and run my node script. If I have set up everything correctly I expect to see the output from my node script in the logs of my Docker container.
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday;
# │ │ │ │ │ 7 is also Sunday on some systems)
# │ │ │ │ │
# │ │ │ │ │
# * * * * * command to execute
# DOES THIS COMMAND EXECUTE SUCCESSFULLY, IF NOT WHY NOT?
*/5 * * * * . /tmp/env.sh /usr/local/bin/node /usr/src/app/db-update.js > /proc/1/fd/1 2>/proc/1/fd/2
# need to leave an empty line
This is a snippet from my node script:
const sftpclient = require('ssh2-sftp-client');
const expressGraphQL = require('express-graphql');
const mongoose = require('mongoose');
const fs = require('fs');
console.log('now executing db-update');
const IN_PRODUCTION = (process.env.NODE_ENV === 'production' ? true : false);
console.log('what is node env: ', process.env.NODE_ENV);
console.log('what is env: ', process.env);
When I run this container, however, the only output I am seeing in my container logs is the echo command from my bash script "Starting Cron". I don't see any output from the node script but the container continues to run. How can I ensure that the node script runs or that the container fails if it doesn't?
To make your life much more easier I would recommend to change strategy to use simple infinite loop with sleep instead of cron
so in CMD just place
while true; sleep 300; execute-node-program || exit 1; done
In such strategy:
You have all output of your node program in docker logs
Container will fail if your program fail
It will be hard to achieve that by using cron as you will need probably to place systemd for 2 processes:
One process for cron
Second process to observe what is node program output and kill systemd if needed, print logs, etc. <--- that sounds really bad
Edit:
So to give you idea how to deal with killing your container when cron job fails:
Start your container with --init flag e.g. docker run --init... - that's really important and will allow you to kill main container's process from within container
Use similar crontab record: */5 * * * * bash -c "/tmp/env.sh && /usr/local/bin/node /usr/src/app/db-update.js || pkill -9 -f cron" > /proc/1/fd/1 2>/proc/1/fd/2

Crontab not launching script

I'm trying to run the following script through crontab every day at 12 :
#!/bin/sh
mount -t nfs 10.1.25.7:gadal /mnt/NAS_DFG
echo >> ~/Documents/Crontab_logs/logs.txt
date >> ~/Documents/Crontab_logs/logs.txt
rsync -ar /home /mnt/NAS_DFG/ >> ~/Documents/Crontab_logs/logs.txt 2>&1
unmout /mnt/NAS_DFG
As it needs to run in sudo, I added the following line to 'sudo crontab' such that I have :
someone#something:~$ sudo crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
0 12 * * * ~/Documents/Crontab_logs/Making_save.sh
But it does not run. I mention that just executing the script thourgh :
sudo ~/Documents/Crontab_logs/Making_save.sh
works well, except that no output of the rsync command is written in the log file.
Any ideas what's going wrong ? I think I checked the main source of mistakes, i.e. using shell, leaving an empty line at the end, etc ...
sudo crontab creates a job which runs out of the crontab of root (if you manage to configure it correctly; the syntax in root crontabs is different). When cron runs the job, $HOME (and ~ if you use a shell or scripting language with tilde expansion) will refer to the home of root etc.
You should probably simply add
0 12 * * * sudo ./Documents/Crontab_logs/Making_save.sh
to your own crontab instead.
Notice that crontab does not have tilde expansion at all (but we can rely on the fact that cron will always run out of your home directory).
... Though this will still have issues, because if the script runs under sudo and it creates new files, those files will be owned by root, and cannot be changed by your regular user account. A better solution still is to only run the actual mount and umount commands with sudo, and minimize the amount of code which runs on the privileged account, i.e. remove the sudo from your crontab and instead add it within the script to the individual commands which require it.

How do I set up a Vagrant box to always have a cron job?

How do I configure my Vagrant configuration so that when I provision a machine its crontab is automatically configured? (vagrant is provisioned according to Chef(?) files)
As an example, I wanted to have the following cron set up:
5 * * * * curl http://www.google.com
Basic provisioning for things like this can easily be done without Chef/Puppet/Ansible and instead using the shell.
The Vagrant docs cover this basic provisioning pretty well for their example of having the box download Apache from a boostrap.sh.
Similarly you could follow the same steps in editing your Vagrantfile to call a bootstrap.sh file when being provisioned:
Vagrant.configure("2") do |config|
...
config.vm.provision :shell, path: "bootstrap.sh"
...
end
You could then create a bootstrap.sh file in the same directory as your Vagrantfile which would contain something like:
#!/bin/bash
# Adds a crontab entry to curl google.com every hour on the 5th minute
# Cron expression
cron="5 * * * * curl http://www.google.com"
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ └───── day of week (0 - 6) (0 to 6 are Sunday to Saturday, or use names; 7 is Sunday, the same as 0)
# │ │ │ └────────── month (1 - 12)
# │ │ └─────────────── day of month (1 - 31)
# │ └──────────────────── hour (0 - 23)
# └───────────────────────── min (0 - 59)
# Escape all the asterisks so we can grep for it
cron_escaped=$(echo "$cron" | sed s/\*/\\\\*/g)
# Check if cron job already in crontab
crontab -l | grep "${cron_escaped}"
if [[ $? -eq 0 ]] ;
then
echo "Crontab already exists. Exiting..."
exit
else
# Write out current crontab into temp file
crontab -l > mycron
# Append new cron into cron file
echo "$cron" >> mycron
# Install new cron file
crontab mycron
# Remove temp file
rm mycron
fi
By default Vagrant provisioners run as root so this will append a cron job to the root user's crontab assuming it doesn't already exist. If you want to add it to the vagrant user's crontab then you will need to run the provisioner with the privileged flag set to false:
config.vm.provision :shell, path: "bootstrap.sh", privileged: false

Running Laravel Task at specific time

I've seen some similar questions at SO but none of then have answered me. I had never heard of CRON before and I'm new to Laravel. What I need is to run a Task once a week to perform some actions on my database (MySql), say every sunday at 12:00 am. How could I achieve this goal?
If you can use cron, you just have to execute
crontab -e
Or, if you need to run as root:
sudo crontab -e
This will open a text editor so you can modify your crontab and there you'll have one line for each scheduled command, as this one:
1 0 * * * php /var/www/myBlog/artisan task:run
The command in this like will be executed at the first minute of every day (0h01 or 12h01am).
Here is the explanation of it all:
* * * * * <command to execute>
┬ ┬ ┬ ┬ ┬
│ │ │ │ │
│ │ │ │ │
│ │ │ │ └───── day of week (0 - 6) (0 to 6 are Sunday to Saturday, or use names)
│ │ │ └────────── month (1 - 12)
│ │ └─────────────── day of month (1 - 31)
│ └──────────────────── hour (0 - 23)
└───────────────────────── min (0 - 59)
So, in your case, you'll create a line like this:
0 12 * * 0 <command to execute>
But how do you do that for a task in Laravel? There are many ways, one of them is in my first example: create an artisan command (task:run) and then just run artisan, or you can just create a route in your app to that will call your task every time it is hit:
Route::get('/task/run',array('uses'=>'TaskController#run'));
And then you just have to add it your crontab, but you'll need something to hit your url, like wget or curl:
0 12 * * 0 curl http://mysite.com/run/task
Since Laravel 5, the only entry you need to put into crontab after executing crontab -e is
* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1
Do remember to change /path/to/artisan part to your project specific path.
And then you can define your scheduled tasks and running frequency in Laravel's App\Console\Kernel class. See Laravel documentation for more information: Task Schedule
You can create and run your laravel tasks from the command line just like any other Artisan command. So if you are on windows you can just run the command manually to see if it works or not.
Then when you are on production server (better of course if it is Unix based) then you can follow Antonio's direction to create the cron job and add it to the cron tab. Keep in mind you will need to know the complete paths for the PHP execution.
My tutorial explains this all in detail : http://maxoffsky.com/code-blog/practical-laravel-using-cron-jobs-in-laravel/
Hope you find the answer that you are looking for.

Resources