Running df -k command for my application server,and it is having mount issue,so need to trigger a mail - shell

I an running df -k command for my application server, and it is having mount issue.
So I need to trigger a mail saying that the server is having mount issue.
My basic question, I will write a shell script which will run df -k command and identify if the command takes long time to complete the command, then I need to trigger a mail.
How can I do this ?

This question lists ways to detect stale NFS mounts: Is there a good way to detect a stale NFS mount
Select one solution and run it before the df -k.
Alternatively, you can redirect stderr to stdout and then grep for the error pattern:
df -k 2>&1 | grep ...error...
if [[ $? -ne 0 ]]; then
...send mail...
fi

It's not clear what exactly you're trying to archive; but timing how long a command takes is fairly easy, for example:
#!/bin/sh
start=$(date +%s)
out=$(sleep 6)
took=$(($(date +%s) - $start))
if [ $took -gt 5 ]; then
echo "$out" | mail -s "Command took too long" test#example.com
fi
Edit
This required the command to finish; if you want to have a timeout, I'd recommend using Python. It is possible with shell scripting, but IMHO this is much easier.
#!/usr/bin/env python
import subprocess, smtplib
from email.mime.text import MIMEText
proc = subprocess.Popen(['sleep', '100'])
try:
proc.wait(5) # 5 is the timeout in seconds
except subprocess.TimeoutExpired:
proc.kill()
# Send email
msg = MIMEText("Command took too long\r\n")
msg['Subject'] = 'Command took too long'
msg['From'] = 'test#example.com'
msg['To'] = 'test#example.com'
s = smtplib.SMTP('localhost')
s.sendmail('test#example.com', ['test#example.com'], msg.as_string())
s.quit()

Related

OSX bash script does not run from cron

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

bash script to accept log on stdin and email log if inputting process fails

I'm a sysadmin and I frequently have a situation where I have a script or command that generates a lot of output which I would only like to have emailed to me if the command fails. It's pretty easy to write a script that runs the command, collects the output and emails it if the command fails, but I was thinking I should be able to write a command that
1) accepts log info on stdin
2) waits for the inputting process to exit and see what it's exit status was
3a) if the inputting process exited cleanly, append the logging input to a normal log file
3b) if the inputting process failed, append the logging input to the normal log and also send me an email.
It would look something like this on the command line:
something_important | mailonfail.sh me#example.com /var/log/normal_log
That would make it really easy to use in crontabs.
I'm having trouble figuring out how to make my script wait for the writing process and evaluate how that process exits.
Just to be exatra clear, here's how I can do it with a wrapper:
#! /bin/bash
something_important > output
ERR=$!
if [ "$ERR" -ne "0" ] ; then
cat something_important | mail -s "something_important failed" me#example.com
fi
cat something_important >> /var/log/normal_log
Again, that's not what I want, I want to write a script and pipe commands into it.
Does that make sense? How would I do that? Am I missing something?
Thanks Everyone!
-Dylan
Yes it does make sense, and you are close.
Here are some advises:
#!/bin/sh
TEMPFILE=$(mktemp)
trap "rm -f $TEMPFILE" EXIT
if [ ! something_important > $TEMPFILE ]; then
mail -s 'something goes oops' -a $TEMPFILE you#example.net
fi
cat $TEMPFILE >> /var/log/normal.log
I won't use bashisms so /bin/sh is fine
create a temporary file to avoid conflicts using mktemp(1)
use trap to remove file when the script exit, normally or not
if the command fail
then attach the file, which would or would not be preferred over embedding it
if it's a big file you could even gzip it, but the attachment method will change:
# using mailx
gzip -c9 $TEMPFILE | uuencode fail.log.gz | mailx -s subject ...
# using mutt
gzip $TEMPFILE
mutt -a $TEMPFILE.gz -s ...
gzip -d $TEMPFILE.gz
etc.

Bash Script works locally but not from server

I have a script which runs fine when executed locally on a mac.
# Ask to make system changes
read -p "Would You Like to make system changes? (Finder, etc...) ? (y/n)?" CONT
if [ "$CONT" == "y" ]; then
# Keep-alive: update existing `sudo` time stamp until `mac.sh` has finished
echo "Keep this mac alive while ding this task..."
while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &
# Show Date on menubar
echo "Showing Date on menubar..."
defaults write com.apple.menuextra.clock.plist DateFormat "EEE dd MMM h:mm:ss a"
killall "SystemUIServer";
else
echo "Done makng system changes"
fi
But when I try remotely like this:
curl -s https://192.168.63.23/mac.sh --insecure | sh
I get this error:
sh: line 93: syntax error near unexpected token `else'
sh: line 93: `else'
You aren't executing anything remotely; you are just copying the script from a remote server to execute locally. One problem is that your script uses bash extensions like read -p, but you are executing it with sh (which, even if it is a link to bash, executes in POSIX mode). Use bash explicitly:
curl -s --insecure https:/192.168.63.23/mac.sh | bash
As for the syntax error, run your code through shellcheck.net. You haven't shown enough of the actual code to locate the problem.

Terminal Application to Keep Web Server Process Alive

Is there an app that can, given a command and options, execute for the lifetime of the process and ping a given URL indefinitely on a specific interval?
If not, could this be done on the terminal as a bash script? I'm almost positive it's doable through terminal, but am not fluent enough to whip it up within a few minutes.
Found this post that has a portion of the solution, minus the ping bits. ping runs on linux, indefinitely; until it's actively killed. How would I kill it from bash after say, two pings?
General Script
As others have suggested, use this in pseudo code:
execute command and save PID
while PID is active, ping and sleep
exit
This results in following script:
#!/bin/bash
# execute command, use '&' at the end to run in background
<command here> &
# store pid
pid=$!
while ps | awk '{ print $1 }' | grep $pid; do
ping <address here>
sleep <timeout here in seconds>
done
Note that the stuff inside <> should be replaces with actual stuff. Be it a command or an ip address.
Break from Loop
To answer your second question, that depends in the loop. In the loop above, simply track the loop count using a variable. To do that, add a ((count++)) inside the loop. And do this: [[ $count -eq 2 ]] && break. Now the loop will break when we're pinging for a second time.
Something like this:
...
while ...; do
...
((count++))
[[ $count -eq 2 ]] && break
done
ping twice
To ping only a few times, use the -c option:
ping -c <count here> <address here>
Example:
ping -c 2 www.google.com
Use man ping for more information.
Better practice
As hek2mgl noted in a comment below, the current solution may not suffice to solve the problem. While answering the question, the core problem will still persist. To aid to that problem, a cron job is suggested in which a simple wget or curl http request is sent periodically. This results in a fairly easy script containing but one line:
#!/bin/bash
curl <address here> > /dev/null 2>&1
This script can be added as a cron job. Leave a comment if you desire more information how to set such a scheduled job. Special thanks to hek2mgl for analyzing the problem and suggesting a sound solution.
Say you want to start a download with wget and while it is running, ping the url:
wget http://example.com/large_file.tgz & #put in background
pid=$!
while kill -s 0 $pid #test if process is running
do
ping -c 1 127.0.0.1 #ping your adress once
sleep 5 #and sleep for 5 seconds
done
A nice little generic utility for this is Daemonize. Its relevant options:
Usage: daemonize [OPTIONS] path [arg] ...
-c <dir> # Set daemon's working directory to <dir>.
-E var=value # Pass environment setting to daemon. May appear multiple times.
-p <pidfile> # Save PID to <pidfile>.
-u <user> # Run daemon as user <user>. Requires invocation as root.
-l <lockfile> # Single-instance checking using lockfile <lockfile>.
Here's an example of starting/killing in use: flickd
To get more sophisticated, you could turn your ping script into a systemd service, now standard on many recent Linuxes.

Restart a process when cpu gets high

I've got a cron job checking for webserver (seeing if its active), which is handy..
http://pastebin.com/raw.php?i=KW8crfzh
I'm wanting after something similar for cpu usage. I'm running java backend which occasionally gets 70%+ cpu. I'm after a cron script to automatically kill/restart java if cpu load gets too high, how is this possible?
You could use top in batch mode coupled with some code to parse its output. For example:
top -p 1234 -n 1 -b
Will output a snapshot of the state of process 1234.
I use this script and it is pretty cool
#!/bin/bash
# author = Jaysunn
# Log
LOGFILE=/var/log/load_kill_log
# log the process causing the load at the time.
PSFILE=/var/log/ps_log
# Obtain the server load
loadavg=`uptime |cut -d , -f 4|cut -d : -f 2`
thisloadavg=`echo $loadavg|awk -F \. '{print $1}'`
if [ "$thisloadavg" -ge "10" ]; then
ps auxfww >> $PSFILE
date >> $LOGFILE
# Issue the command of choice. This can be any shell command.
## Put the command which restarts ..
fi
give executable permissions and add this to crontab with proper path to this script.

Resources