OSX bash script does not run from cron - macos

I have a bash script, that runs just fine from the command line. After adding it to the root users crontab (sudo crontab -e), I find it does not run. Here is the cron task:
0,15,30,45 * * * * /Users/lorenzot/Documents/scripts/restart-net.sh
Here is the script:
#!/bin/bash
echo "Net script" | logger -s >> /Library/Logs/netlog.log
# Ping twice just to be sure
/sbin/ping -c 2 8.8.8.8
/sbin/ping -c 2 8.8.8.8
if [ $? -ge 1 ]; then
echo "Network down :("
ifconfig en1 down
ifconfig en1 up
exit 1
else
echo "Network up! :)"
exit 0
fi
The script is owned by root and of course, it is executable (766) and it does exist at the correct path.
I'm not seeing an entry in the log file, but I'm not sure if this is the correct way of writing to a log file. I've tried a few different variations including:
syslog -s -k Facility com.apple.console \
Level Error \
Sender restartscript \
Message "Restart network script run"
But nothing is written to any log. Nevertheless, I would expect to see a log entry for the cron task having executed.
Any ideas?
Thanks

'logger -s` sends a copy of the message to stderr, not stdout. Also, you can pass the message as an argument, rather than via stdin. Try this:
logger -s "Net script" 2>> /Library/Logs/netlog.log

Related

How to grep the output of a command inside a shell script when scheduling using cron

I have a simple shell script where I need to check if my EMR job is running or not and I am just printing a log but it does not seem to work properly when scheduling the script using cron as it always prints the if block statement because the value of "status_live" var is always empty so if anyone can suggest what is wrong here otherwise on manually running the script it works properly.
#!/bin/sh
status_live=$(yarn application -list | grep -i "Streaming App")
if [ -z $status_live ]
then
echo "Running spark streaming job again at: "$(date) &
else
echo "Spark Streaming job is running, at: "$(date)
fi
Your script cannot run in cron because cron script has no environment context at all.
For example try to run your script as another use nobody that has no shell.
sudo -u nobody <script-full-path>
It will fail because it has no environment context.
The solution is to add your user environment context to your script. Just add source to your .bash_profile
sed -i "2a source $HOME/.bash_profile" <script-full-path>
Your script should look like:
#!/bin/sh
source /home/<your user name>/.bash_profile
status_live=$(yarn application -list | grep -i "Streaming App")
if [ -z $status_live ]
then
echo "Running spark streaming job again at: "$(date) &
else
echo "Spark Streaming job is running, at: "$(date)
fi
Now try to run it again with user nobody, if it works than cron will work as well.
sudo -u nobody <script-full-path>
Note that cron has no standard output. and you will need to redirect standard output from your script to a log file.
<script-full-path> >> <logfile-full-path>
# $? will have the last command status in bash shell scripting
# your complete command here below and status_live is 0 if it finds in grep (i.e. true in shell if condition.)
yarn application -list | grep -i "Streaming App"
status_live=$?
echo status_live: ${status_live}
if [ "$status_live" -eq 0 ]; then
echo "success
else
echo "fail"
fi

Automatize the cert creation OpenVPN

I do not know why I am getting an error when I run my script with SSH, but when I run the bash from my CA server everything works fine.
I installed my VPN server based on this article https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-18-04
I wrote a bash for the VPN creation but when I try to run it I need to SSH to the other server at some point. If I start the script with SSH in it I got an error message:
>./easyrsa: 341: set: Illegal option -o echo
My bash contain this and run from my VPN server:
sshpass -p $PASSWORD ssh username#"CA server IP" "/home/username/makevpn.sh $NAME $PASSWORD"
And makevpn.sh contain this:
>./easyrsa sign-req client $NAME
After this run it seems okay but give that error above.
I tried to read after this error and found nothing. :( Hope someone can help because I am hopeless after 4 days of troubleshooting.
Code of VPN script
#!/bin/sh
clear
read -p "Please enter the name of the new certificate : " NAME
read -p "Please enter the Password : " PASSWORD
cd /home/username/EasyRSA-3.0.7/
./easyrsa gen-req $NAME nopass
echo "gen-req done"
cp /home/username/EasyRSA-3.0.7/pki/private/$NAME.key /home/username/client-configs/keys/
echo "cp done"
sshpass -p $PASSWORD scp /home/username/EasyRSA-3.0.7/pki/reqs/$NAME.req username#192.168.1.105:/tmp
echo "scp done"
sshpass -p $PASSWORD ssh username#192.168.1.105 "/home/username/makevpn.sh $NAME $PASSWORD"
echo "ssh done"
cp /tmp/$NAME.crt /home/username/client-configs/keys/
echo "last CP done"
sudo /home/username/client-configs/make_config.sh $NAME
echo "All Done"
Code on CA server
#!/bin/sh
NAME=$1
PASSWORD=$2
cd /home/username/EasyRSA-3.0.7/
echo "CD Done"
./easyrsa import-req /tmp/$NAME.req $NAME
echo "Import-req done"
./easyrsa sign-req client $NAME
echo "Sign-req done"
sshpass -p $PASSWORD scp /home/username/EasyRSA-3.0.7/pki/issued/$NAME.crt username#192.168.1.103:/tmp
echo "Scp done"
I was just browsing the code of that easyrsa script here. This one is likely different from yours given the line for the error is 341. On the Github page, it is line 352 and it is part of a function called cleanup. It appears that this function is only attached as a trap (line 2744). Traps are used to catch signals like sigint (interrupt) which is normally sent on the terminal with ctrl+c (and may display a character like ^C). The reason the error only displays in your script is it likely causes a signal to be emitted that you would not normally receive if you ran it manually over ssh.
The error itself is really not an issue.
Code from Github:
Line 352:
(stty echo 2>/dev/null) || { (set -o echo 2>/dev/null) && set -o echo; }
Line 2744:
trap "cleanup" EXIT
It appears that line is just trying to turn terminal output of your typed characters back on (via stty echo). Sometimes programs will disable terminal output somewhere, and then re-enable it when the program finishes. However, if you were to kill the program mid way through (e.g. with ctrl+c), your program would terminate with the terminal output still disabled. This would make the terminal appear to be frozen. It would still work, but would not display the characters you type with your keyboard. The point of the trap is to ensure that terminal output is re-enabled no matter how the program exits.
More info...
At line 567 there is a function that disables echo. Looks like the point is to not show a password to the screen. If you were to kill the program during password reading, echo would remain disabled on the terminal. Likely the reason for the error has more to do with the way you are running the script. For whatever reason it causes stty echo to fail. Line 352 is assuming that the failure is due to stty echo not being a valid command. So on failure ( || ), it tries a different method (set -o echo) of enabling echo. If I try to run that on my terminal, I also get an error (bash 4.2):
-bash: set: echo: invalid option name

Script stuck during read line when script is executed remotely

I want to have one script which starts a services in another server.
I have tested that the script works as expected in the server where the server is going to run.
This is the code which starts the service and monitors the log until it is in the startup process:
pkill -f "$1"
nohup java -jar -Dspring.profiles.active=$PROFILE $1 &
tail -n 0 -f nohup.out | while read LOGLINE
do
echo $LOGLINE
[[ "${LOGLINE}" == *"$L_LOG_STRING"* ]] && pkill -P $$ tail
done
This works fine as long as I execute that from that machine.
Now I want to call that script from another server:
#!/usr/bin/env bash
DESTINATION_SERVER=$1
ssh root#$DESTINATION_SERVER /bin/bash << EOF
echo "Restarting first service..."
/usr/local/starter.sh -s parameter
echo "Restarting second service..."
/usr/local/starter.sh -s parameter2
EOF
Well, everytime I try that the script of the remote server gets stuck in the "while READ" loop. But as I said, when I execute it locally from the server works fine, and in my "not simplified script" I´m not using any system variable or similar.
Update: I just tried to simplify the code even more with the following lines in the first scenario:
pkill -f "$1"
nohup java -jar -Dspring.profiles.active=$PROFILE $1 &
tail -n 0 -f nohup.out | sed "/$L_LOG_STRING/ q"
I'd say the problem is some how in the "|" through ssh, but I still can find why.
it seems that the problem comes from not having an interactive console when you execute the ssh command, therefore the nohup command behaves strangly.
I could solve it in two ways, outputing the code to the file explicitly:
"nohup java -jar -Dspring.profiles.active=test &1 >> nohup.out &"
instead of:
"nohup java -jar -Dspring.profiles.active=test &1&"
Or changing the way I access via ssh adding the tt option (just one did not work):
ssh -tt root#$DESTINATION_SERVER /bin/bash << EOF
But this last solution could lead to other problems with some character, so unless someone suggests another solution that is my patch which makes it work.

process not starting completely, when called inside crontab

I have a script( let us call it watcher) which checks for a particular process if it's not running the watcher will start the process through a script.
I run this watcher in crontab at every minute. Now the problem is that it's not working in crontab but working if I run the watcher directly from the command line.
suppose the watcher start a script file called serverA.
ServerA code
echo -n "Starting $NAME: "
# start network server
start-stop-daemon --start --background --make-pidfile \
--pidfile $net_server_pidfile --startas /bin/bash -- -c "exec $angel $net_server \
-c $conf_file --lora-eui $lora_eui --lora-hw-1 $lora_hw --lora-prod-1 $lora_id \
--lora-path $run_dir --db $conf_db \
--noconsole >> $net_server_log 2>&1"
sleep 2
# start packet forwarder
/usr/sbin/start-stop-daemon --chdir $run_dir/1 --start --background --make-pidfile \
--pidfile $pkt_fwd_pidfile --exec $angel -- $pkt_fwd
renice -n -20 -p $(pgrep lora-network-se)
renice -n -20 -p $(pgrep $(basename $pkt_fwd))
echo "OK"
Now if i run watcher from directly the serverA will echo output Starting something then after sometime it continues with OK at the end.
But in crontab logs i dont see the OK, because of which the service never completes and serverA never starts.
watcher.sh
else
echo "$(date) do something, no packet forwader runnig"
exec /etc/init.d/lora-network-server start
fi
I think that you need to check difference of run time environments based terminal or not.
Firstly Check the lora-network-server whether depend on shell environments, such as JAVA_HOME or PATH (e.g. can execute the binary without absolute path of binary).
If it has different setting, it make same shell environments.
For exmaple, how to diff between cron env and runtime env.
runtime
$ env | tee ./runtime.output
cron
$ crontab <<EOF
* * * * * /bin/env > /path/to/cron.output 2>&1
EOF
Above cron output will create after 1 minute, and remove the cront after test.
you can check the variables onto cron.output and runtime.output
I hope this will help you.
Cron runs with a mostly empty environment. Are you setting all necessary environment variables in your scripts?

Crontab apparently not calling sudo

tl;dr A bash script which requires SUDO works fine when called manually, but does not work when called by crontab, even though it was add to crontab using sudo crontab -e
I am trying to automate my connection to my vpn proxy such that the vpn connection is turned on at midnight and off at 7:15AM.
In order to automate it, I wrote the following bash script, located at /usr/local/bin/cloak.sh.
#!/bin/bash
LOG_FILE=/home/declan/log/cloak.log
LogEntry()
{
while read data
do
echo "$(date "+%Y %m %d %T") ; $data" >>$LOG_FILE 2>&1;
done
}
echo "---------------------" | LogEntry
if [ $1 -eq 1 ]
then
echo "Turning Cloak On" | LogEntry
/etc/init.d/openvpn start proxpn.miami | LogEntry
else
echo "Turning Cloak Off" | LogEntry
/etc/init.d/openvpn stop | LogEntry
fi
echo "---------------------" | LogEntry
echo " " | LogEntry
My vpn is working and I have confirmed that the script is executable and that it works by checking my IP address before and after calls to the script, turning the VPN on (1 as parameter) or off (0 as parameter).
declan#mx:~/log$ wget http://ipecho.net/plain -O - -q ; echo
74.196.220.81 <<-- This is my real IP address
declan#mx:~/log$ sudo /usr/local/bin/cloak.sh 1 <<-- Turn the VPN on
declan#mx:~/log$ wget http://ipecho.net/plain -O - -q ; echo
173.0.8.33 <<-- This is my VPN IP address
declan#mx:~/log$ sudo /usr/local/bin/cloak.sh 0 <<-- Turn the VPN off
declan#mx:~/log$ wget http://ipecho.net/plain -O - -q ; echo
74.196.220.81 <<-- Back to my real IP address
declan#mx:~/log$
I add this script to cron, using sudo crontab -e to ensure that sudo is running the script, with the following lines in the crontab
# Cloak on at midnight, off at 7:15AM
0 0 * * * /usr/local/bin/cloak.sh 1
15 7 * * * /usr/local/bin/cloak.sh 0
If I look at the contents of the log, /home/declan/log/cloak.log, it shows that the cron job is being executed at the correct time.
The problem is that when I check my IP address after the cron job tries to start the VPN, my real IP address is still being used. My only guess is that somehow the cron job is not being called with sudo rights, but I can't understand why.
Any help would be appreciated. I am also open to any suggestions on alternative approaches, different scripts, etc...
Thanks
Declan
Added the following to my crontab and now everything is working as intended.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
The question is... "why use sudo?" you need a service restart which is a root operation. Edit the /etc/crontab and add the line like this:
0 0 * * * root /usr/local/bin/cloak.sh 1
15 7 * * * root /usr/local/bin/cloak.sh 0
and it should it work.

Resources