Syed Jahanzaib Personal Blog to Share Knowledge !

June 26, 2018

BASH Script with time & single execution per day checks

Filed under: freeradius, Linux Related — Tags: , , — Syed Jahanzaib / Pinochio~:) @ 2:00 PM

 

repeat

Scenario:

We have a bash script that performs various functions related to Freeradius, including expiration checkup & various groups updates functions.

Problem:

We have schedules this script to run daily at 1700 hours, What will happen if server was powered offย  at 1700 hours? Script will missed its schedule resulting in expired users account will not be disabled for that day and incorrect display of users status in front gui. Alternatively we can schedule it to run hourly but it will increase the server load because of repeated task , which is supposed to be executed only once per day

Requirements:

We need to make some checks and balances so that if script must have some intelligent IF ELSE criteria in order to check following steps …

  • Script is scheduled to run hourly, so that if it misses the 1700 hour it will be relaunched next hour,
  • If time is 1700 hours or above then execute the script,
  • If the script executes successfully , then save this result, and on next run (within current date) it should detect last run status and dont repeat the code to avid recurrence,
  • If the last run was not executed for any reason, & the time is 1700 or above then execute the script and save its run status in file,
  • Once the data changes, it should re-run the script only if the time is 1700 or above.

Solution:

the SCRIPT ! Sample Purpose only

#!/bin/bash
# Bash Script to make sure script runs at specific time, and should not run again for the same date
# record date in local file, to avoic repeating running the code in todays date, once the date is changed,
# then re-run the code and match time again and so on
# Syed Jahanzaib / 26-Jun-2018
# set -x

# Setting variables
DATE=$(date +%d-%m-%Y)
FULL_DATE=`date`
FILE=/temp/1.txt
touch $FILE
CURR_HOUR=$(date +%H)

# Set time for script execution
SCR_SCHEDULED_TIME="11"
H=$(date +'%-H')

CHK_GREP=`grep -c $DATE $FILE`
echo "Current Date time is $FULL_DATE"

# If script is executed successfully then dont re-run and exit now
if grep -q $DATE $FILE >/dev/null 2>&1
then
echo "It seems the script was executed successfully today $DATE, It will run on next date change.... Exiting now."
exit 1
fi

# Check if time is matched that is greater or equals to $SCR_SCHEDULED_TIME and also check if script hae ran successfully or not previously
echo "
Stage-1: Checking if current time is equals or greater then '$SCR_SCHEDULED_TIME hours' ..."
if [ "$CURR_HOUR" -ge "$SCR_SCHEDULED_TIME" ] && [ "$CHK_GREP" == "0" ]; then
echo "
Stage-2: Time matched that is equals or greater then $SCR_SCHEDULED_TIME"
# If all matches, then run the code ! and add time stamp in file to avoid repeatingo/re-running the following script code on next RUN
echo "Finally: All conditions time + this day first execution matched, Now running the script code ...."
date +%d-%m-%Y >> $FILE
exit 1
fi

# If time have not come like its before the $SCR_SCHEDULED_TIME, then give error and exit now
echo "
Warning !
Scheudled time is equals or greater then $SCR_SCHEDULED_TIME hours : Current hour is $CURR_HOUR
Time have not came yet ! wait for your turn ..."

This way I was able to achieve the task I was thiking of.


# Actual Script which performs various functions with time checkups etc

Just for personnel reference …

#!/usr/bin/env bash
####!/bin/sh
#set -x
#trap "set +x; set -x" DEBUG
# BASH base script to discopnnect users whose expiry is today & update there GROUPS as well and update log table.
# the simple logic can be applied for about any other task as well. I tried to make it as simple as it can be
# also check if the scrpit ran successfully then dont re-run today,
# By Syed Jahanzaib
# CREATED on : 16th July, 2015
# Modified on 25h June 2018

# Local Variables
# Mysql credentials
SQLID="root"
SQLPASS="ROOTPASS"
export MYSQL_PWD=$SQLPASS
CMD="mysql -u$SQLID --skip-column-names -s -e"
DB="radius"
#Table which contain main users information
TBL="users"
#Rad user group in which we will update user profile like from 1mb to expired or likewise
GROUP="radusergroup"
NEXTSRV="expired"
TBL_LOG="log"

# Date Time Variables
DATE=$(date +%d-%m-%Y)
FULL_DATE=`date`
CURR_HOUR=$(date +%H)
TODAY=$(date +"%Y-%m-%d")
WEEK=`date -d "-1000 days" '+%Y-%m-%d'`
BEGIN="1970-01-01"
H=$(date +'%-H')
################################
## Set time for script execution
## IMPORTANT, donot use 0 in it
SCR_SCHEDULED_TIME="12"
################################

#Network Related
hostname=`hostname`
IP=`ip route get 8.8.8.8 | awk '{print $NF; exit}'`

# Gmail Data
GMAILID="MYGMAIL@gmail.com"
GMAILPASS="MYGMAILPASS"
SMTP="64.233.184.108:587"
ADMINMAIL1="aacableAThotmail.com"
COMPANY="ZAIB"
MAILSUB="$COMPANY INFO -$HOSTNAME-$IP- List of account expired on $TODAY"

##################################################
##################################################
# Temp folder and files setup for various actions
##################################################
##################################################
TEMP="temp"
# Temp holders to store users list
ALLEXPLIST=/$TEMP/all_time_expired_users_list.txt
TODEXPLIST=/$TEMP/only_today_expired_users_list.txt
FILE=/$TEMP/check_user_expiration_exec.txt

# Checking if /temp folder is previously present or not , if not create one ...
{
if [ ! -d "/$TEMP" ]; then
echo
mkdir /$TEMP
fi
}

# remove and recreate users list to avoid any Duplication or issue
{
if [ -f $ALLEXPLIST ]; then
rm $ALLEXPLIST
touch $ALLEXPLIST
fi
}
{
if [ -f $TODEXPLIST ]; then
rm $TODEXPLIST
touch $TODEXPLIST
fi
}
# File Holder to store last execution date
{
if [ ! -f $FILE ]; then
touch $FILE
fi
}

############################
############################
###### START thE script cOdE
############################
############################

CHK_GREP=`grep -c $DATE $FILE`
echo "Current Date time is $FULL_DATE
"
# If script is executed successfully in current date, then dont re-run and exit now
echo "Stage-1:
Checking if the script have already ran successfully for today, by getting current date from the $FILE"
if grep -q $DATE $FILE >/dev/null 2>&1
then
echo "
Result:
It seems the script was executed successfully today $DATE, It will run on next date change. Exiting now ..."
exit 1
fi

# Check if time is matched that is greater or equals to $SCR_SCHEDULED_TIME and also check if script hae ran successfully or not previously by getting date from $FILE
echo "
Stage-2: Checking if current hour is equals or greater then '$SCR_SCHEDULED_TIME hours' & previous run is not done yet ..."
if [ "$CURR_HOUR" -ge "$SCR_SCHEDULED_TIME" ] && [ "$CHK_GREP" == "0" ]; then
echo "
Stage-2:
Time matched that is equals or greater then $SCR_SCHEDULED_TIME"
# If all matches, then run the code ! and add time stamp in file to avoid repeatingo/re-running the following script code on next RUN
echo "Finally:
All conditions time + this day first execution matched, Now running the script code ..."
date +%d-%m-%Y >> $FILE

# Pull users that are expiring from beginning till TODAY, to avoid missing any part
$CMD "use $DB; select username from $TBL where expiration between '$BEGIN' AND '$TODAY';" |sort > $ALLEXPLIST
# Pull user list that are expiring today only, for email purposes
$CMD "use $DB; select username from $TBL where expiration ='$TODAY';" |sort > $TODEXPLIST

# IF no user found , show error and exit - zaib
CHK=`wc -m $ALLEXPLIST | awk {'print $1}'`
if [ "$CHK" -eq 0 ]
then
echo "No user found expiring today, exiting ..."
exit 1
fi

# Apply formula
num=0
cat $ALLEXPLIST |while read data
do
num=$[$num+1]
USERNAME=`echo $data`

# Update user status in RADgroup & users table so that he will rejected on next login
IS_EXPIRED=`$CMD "use $DB; select is_expired from users where username ='$USERNAME';"`
if [ "$IS_EXPIRED" = "N" ]; then
echo "user_IS EXIPRED is NO *************************************************************************************************"
$CMD "use $DB; update $GROUP set groupname='$NEXTSRV' where username='$USERNAME';"
$CMD "use $DB; update $TBL set is_expired='Y' where username='$USERNAME';"
$CMD "use $DB; update $TBL set is_days_expired='Y' where username='$USERNAME';"
$CMD "use $DB; INSERT into $TBL_LOG (data, msg) VALUES ('$USERNAME', '$USERNAME - User reached Expiration, Group udpated.');"
fi

# CHECK ONLINE AND KICK
# Pull account session id from radacct table, which will be used to COA OR user disconnection
ACCTSESID=`$CMD "use $DB; select acctsessionid from radacct where username ='$USERNAME' AND acctstoptime is NULL;"`
# If user is not Online , just give info that he is not online
if [ -z "$ACCTSESID" ]; then
$CMD "use $DB; INSERT into $TBL_LOG (data, msg) VALUES ('$USERNAME', '$USERNAME - User reached Expiration, Group udpated but its already offline');"
echo "$USERNAME - User reached Expiration, Group udpated but its already offline."
else
# Kick user by getting his NAS ip, secret and other info and log
# Mikrotik NAS IP and Radport and Shared Secret
NAS_IP=`$CMD "use $DB; select nasipaddress from radacct where username ='$USERNAME' AND acctstoptime is NULL;"`
NAS_SECRET=`$CMD "use $DB; select secret from nas where nasname ='$NAS_IP';"`
NAS_COA_PORT=`$CMD "use $DB; select nas_coa_port from nas where nasname ='$NAS_IP';"`
# Disconnect users now using RADCLIENT with username adn Account session ID taken from radacct table
echo user-name=$USERNAME,Acct-Session-Id=$ACCTSESID | radclient -x $NAS_IP:$NAS_COA_PORT disconnect $NAS_SECRET
# LOG into LOG TABLE in radius DB
$CMD "use $DB; INSERT into $TBL_LOG (data, msg) VALUES ('$USERNAME', '$USERNAME - User reached Expiration, kicked & updated,.');"
echo "$USERNAME - User reached Expiration, kicked & updated."
fi
done

#TOT=`cat $TODEXPLIST | wc -l`
#echo "
#-----------
#-----------

#$COMAPNY _ List of TODAY $TODAY expired users, Total = $TOT"
#cat $TODEXPLIST

# Send Email to all admin - currently 4 users
sendemail -t $GMAILID -u "$MAILSUB" -o tls=yes -s $SMTP -t $ADMINMAIL1 -xu $GMAILID -xp $GMAILPASS -f $GMAILID -o message-file=$TODEXPLIST -o message-content-type=text
fi

Regard’s
Syed Jahanzaib

August 8, 2016

UPS Monitor BASH Script with SMS / Email Alerts

Filed under: Linux Related — Tags: , , — Syed Jahanzaib / Pinochio~:) @ 1:26 PM

Following script is just For my personal reference Purpose only!!!

 

script ups output

Emerson UPS Info via DUDE

kesc

 


Scenario:

In our datacenter , we have Emerson 10kva UPS x 2 in failover + load balancing mode. Yesterday we got some electric failure resulting in UPS shutdown after its batteries banks got drained. This UPS doesn’t have advance alerting system other than simple traditional alerts of light failure and restore via email. Therefore I made some customized scripts which are now monitoring the UPS status with more deeper digging.

Example: If the Electricity failure occurs (or low voltage under xxx value) then it should send email + sms alert to the admin. So basically we will match at least two conditions.

In this script we have use following software hardware

  • Ubuntu 12.4 Server Edition with this bash script
  • Network Support UPS with SNMP card
  • Kannel SMS gateway in same ubuntu box for sending SMS using locally attached GSMmodem
  • Sendemail application for sending emails alerts (Its not SENDMAIL server, its small app name sendemail which we can use to send email via Gmail as well, it comes handy ๐Ÿ™‚ )

Before proceeding, make sure that

  • You can ping the UP ip properly,
  • You can query the UPS via SNMP query like snmpwalk -v1 -c PUBLIC UPSIP
  • You can query UPS input OID and get result like 220 (or if you get result like 2200 use the formula in the script in later section)


#!/bin/bash
# Function: DATA CENTER UPS KE INPUT ONLY - SCRIPT [KE is the company name wihch provides electricity in Karcahi city - Karachi Electric
# Scheduled Script to check data center KE INPUt + UPS Bacnkup remain time via SNMP after every 1 mnt or as per scheudled cron job.
# If it found no input , it wll send sms or email Alerts, but donot repeat it untill next status change.
# Script Designed by Syed Jahanzaib
# aacable at hotmail dot com
# http://aacable . wordpress . com
# Cration Date: 2015
# Last revision DAte: 7-June-2018]
#set -x
# Colors Config . . . [[ JZ . . . ]]

ESC_SEQ="\x1b["
COL_RESET=$ESC_SEQ"39;49;00m"
COL_RED=$ESC_SEQ"31;01m"
COL_GREEN=$ESC_SEQ"32;01m"
DATE=`date`

# COMPANY NAME
COMPANY="ZAIB-LTD"
FOOTER="Powered by Syed Jahanzaib."

# Hostname
HOSTNAME=`hostname`

# KANNEL SMS Gateway Info
KURL="127.0.0.1:13013"
KANNELID="kannel"
KANNELPASS="KANNEL-PASSWORD"
CELL1="03333021909"
SENTSMSRESULT="/temp/kemonsentsmsresult.txt"
LOCATION="FSD"

# GMAIL DETAILS
GMAILID="GMAIL-ID@gmail.com"
GMAILPASS="GMAIL-PASS"
ADMINMAIL1="YOUREMAIL@hotmail.com"

# to install sendemail, use apt-get install sendemail
SENDMAILAPP="sendemail"
STATUS_HOLDER="/temp/upskemon.txt"
SNMPRESULT="/temp/kesnmpoutput.txt"
touch $SNMPRESULT

# UPS RELATED INFO
UPSIP="$1"
SNMPSTR="PUBLIC"

# For APC SMART 1500 UPS Model, You must change them as per your version
UPSINPUTOID="1.3.6.1.4.1.318.1.1.1.3.2.1.0"
UPSTIMEOID="1.3.6.1.4.1.318.1.1.1.2.2.1.0"
UPSTIMELIMIT="30"
KELIMIT="150"

# Check if UPS is accessibel or not, if not then EXIT immediately with error / zaib
if [[ $(ping -q -c 3 $UPSIP) == @(*100% packet loss*) ]]; then
echo "ALERT ..... UPS IP $UPSIP is DOWN ..."
exit 1
fi

snmpwalk -v1 -c $SNMPSTR $1 $UPSINPUTOID > $SNMPRESULT
if [ ! -s $SNMPRESULT ]; then
echo "ALERT ALERT: UPS IP $UPSIP - SNMP NOT Repsonding"
exit 1
fi

# If temporary status holder is not present , then create it,
# forumla is being applied to prevent repeated attempt of file creation / zaib
if [ ! -f $STATUS_HOLDER ]; then
echo -e "Creating Status Holder for first time usage"
touch $STATUS_HOLDER
fi

# Check for KE INPUT via SNMP query, make sure to chhange it accordingly
# currently i am using emerson UPS with snmp web card, as example
TIMEQ=`snmpwalk -v1 -Oqv -c $SNMPSTR $UPSIP $UPSTIMEOID`
KEINPUT=`snmpwalk -v1 -Oqv -c $SNMPSTR $UPSIP $UPSINPUTOID`
#KE=$(($KEINPUT / 100))
KE="$KEINPUT"

NORMSG="All Seems OK !
$FOOTER"
UPMSG="/temp/upmsg.sms"
DOWNMSG="/temp/downmsg.sms"

# MESSAGES
# SMS and email msg fromat for up n down
MSG_UP_SUB="$COMPANY - $LOCATION - UPS INPUT restored @ $DATE"
MSG_DOWN_SUB="$COMPANY - $LOCATION - UPS INPUT failed @ $DATE"
LOWMSG="$COMPANY - $LOCATION - UPS Info: UPS Voltage Input failed @ $DATE
Current Volate Input = $KE volts

$FOOTER"
OKMSG="$COMPANY - $LOCATION - UPS Info: Voltage Input restored @ $DATE
Current Voltage Input = $KE volts

$FOOTER"

# Print Values
echo -e "$COMPANY - $LOCATION - SCRIPT TO MONITOR ELECTRIC INPUT VOLTAGE in UPS ONLY *******
UPS IP / PING response = $UPSIP / Ping Responding OK
UPS SNMP Response = OK / SNMP query Accessible
Minimum Time Threshold = $UPSTIMELIMIT mnts
Minimum KE Input Threshold = $KELIMIT volts
Current Backup Time = $TIMEQ mnts
Current K.E Input = $KE volts

"

# Matching Formula starts here .. zaib
# IF KE INPUT result is greater the our defined limit, then give alert
if [ "$KE" -lt "$KELIMIT" ]; then
echo -e "$LOWMSG "
if [ $(grep -c "TEMP" "$STATUS_HOLDER") -eq 1 ]; then
echo -e "SMS/Email for DOWN have already been sent "
fi
fi

# IF KE INPUT result is less then our defined limit, then send sms and email, IF NOT ALREAY SENT
if [ "$KE" -lt "$KELIMIT" ]; then
if [ $(grep -c "TEMP" "$STATUS_HOLDER") -eq 0 ]; then
echo -e "ALERT: $LOWMS $(date) / SENDING SMS/Email .... "
echo "$LOWMSG" > $DOWNMSG
echo "TEMP" > $STATUS_HOLDER

# Sending DOWN SMS via KANNEL
echo $DATE > $SENTSMSRESULT
cat $DOWNMSG | curl "http://$KURL/cgi-bin/sendsms?username=$KANNELID&password=$KANNELPASS&to=$CELL1" -G --data-urlencode text@- >> $SENTSMSRESULT

# Sending Email via sendEmail tool app using GMAIL
$SENDMAILAPP -u "$MSG_DOWN_SUB" -o tls=yes -s smtp.gmail.com:587 -t $ADMINMAIL1 -xu $GMAILID -xp $GMAILPASS -f $GMAILID -o message-file=$DOWNMSG -o message-content-type=text
fi
else
echo -e "$NORMSG ... "
if [ $(grep -c "TEMP" "$STATUS_HOLDER") -eq 1 ]; then
echo -e "$COMPANY ALERT : $OKMSG $(date) / SENDING OK SMS/Email .... "
echo "$OKMSG" > $UPMSG
sed -i "/TEMP/d" "$STATUS_HOLDER"

# Sending UP SMS via KANNEL
echo $DATE > $SENTSMSRESULT
cat $UPMSG | curl "http://$KURL/cgi-bin/sendsms?username=$KANNELID&password=$KANNELPASS&to=$CELL1" -G --data-urlencode text@- >> $SENTSMSRESULT

# Sending Email via sendEmail tool app using GMAIL
$SENDMAILAPP -u "$MSG_UP_SUB" -o tls=yes -s smtp.gmail.com:587 -t $ADMINMAIL1 -xu $GMAILID -xp $GMAILPASS -f $GMAILID -o message-file=$UPMSG -o message-content-type=text
fi
fi

# Script Ends Here
# Syed Jahanzaib / aacable @ hotmail . com
# http:// aacable . wordpress . com


TEST RUN !

Now execute the script like

/temp/kemon.sh 192.168.0.1

x.JPG

 


Regard’s

Syed Jahanzaib

 

April 4, 2016

Multiple IF statement matching with Mikrotik Script

Filed under: Mikrotik Related — Tags: , , , — Syed Jahanzaib / Pinochio~:) @ 4:06 PM

mqtching

:if (($dsl1 = "DOWN") && ($dsl2 = "DOWN")) do={

Note: This is a draft version of a solution i made for an OP, donot copy paste, its just showing a different way of achieving the goal by customized scripting in Mikrotik. Surely there are other proper , more sophisticated methods out there, its just a way among them for a lamer like me ๐Ÿ˜‰


 

SCENARIO:

We have two WAN DSL links in our RB with PCC configured. Now 3rd wan link is being attached and it should be used as failover only. Means if both DSL fails, then the master script should disable routing to both dsl, and enable 3rd wan link and send sms as well. In this example we are using VARIABLES from existing scripts and take decision based on those variables.

I used KANNEL as SMS gateway to send sms alerts. [installed on a local linux system]

Script:

WAN1MON = it checks for DSL 1 status and update variable ‘wan1staus’

WAN2MON = it checks for DSL 2 status and update variable ‘wan1staus’

Now we will make 3rd script name MASTER [ described in this post ] which will check for variable values created by above scripts. if it found value DOWN for both wan links, it will simply disable the PCC rules, and will enable simple NAT rule.

I cannot explain the script in details dueto time shortage, but this script was created for some customized purpose and it fulfilled the requirements well , at least for particular OP.



# Mikrotik MASTER WAN Link monitoring SCRIPT with optional SMS Alert,
# We are using local KANNEL as SMS gateway
# by Syed Jahanzaib
# https://aacable.wordpress.com
# Email : aacable at hotmail dot com
# Script Last Modified : 4th-APR-2016 / 1300 hours
# Setting VARIABLES
:local date;
:local time;
:set date [/system clock get date];
:set time [/system clock get time];
:local cell1 "03333021909"

# Company Name, donot use spaces in it
:local COMPANY "JZ"

#If you dont have kannel sms gateway ignore this.
:local KURL "http://192.168.100.1:13013/cgi-bin/sendsms"
:local KID "kannel"
:local KPASS "kannelpass"


:global masterstatus
:local dsl1 [/system script environment get [/system script environment find name="wan1netstatus"] value];
:local dsl2 [/system script environment get [/system script environment find name="WAN2netstatus"] value];

# SMS Msg format for Kannel SMS gateway (donot use spaces in it)
:local MSGDOWNSMS "$COMPANY+WAN+ALERT:%0AWAN1-and-2+is+now+DOWN."

#Match condition
:if (($dsl1 = "DOWN") && ($dsl2 = "DOWN")) do={
:if (($masterstatus="UP")) do={
set masterstatus "DOWN";

# If both vdsl found dead, then enable backup link
:log error "BOTH VDSL SEEMS TO BE DOWN, ACTIVATING BACKUP LB - BACKUP LINK ... Powered by SYED JAHANZAIB"

# Send SMS via KANNEL FOR UP ALERT
/tool fetch url="$KURL\?username=$KID&password=$KPASS&to=$cell2&text=$MSGDOWNSMS"

#INSERT YOUR RULES HERE FOR DOWN ACTION
#/ip firewall mangle disable [find comment="PCC-1"]
#/ip firewall mangle disable [find comment="PCC-2"]
#/ip firewall mangle disable [find comment="PCC-3"]
#/ip firewall mangle disable [find comment="PCC-4"]
#/ip firewall mangle disable [find comment="PCC-5"]
#/ip firewall mangle disable [find comment="PCC-6"]
#/ip firewall nat enable [find comment="BACKUP_NAT_ENABLE_IT_WHEN_VDSL_DOWN"]

# If one or both vdsl seems to be alive, then do nothing, just skip
} else={:set masterstatus "DOWN";}
} else={
:if (($masterstatus="DOWN")) do={
:set masterstatus "UP";
:log warning "At least one or both vdsl seems to be UP... Skipping ... Powered by Syed JahanzaiB"</pre>
#INSERT YOUR RULES HERE FOR UP ACTION
#/ip firewall mangle enable [find comment="PCC-1"]
#/ip firewall mangle enable [find comment="PCC-2"]
#/ip firewall mangle enable [find comment="PCC-3"]
#/ip firewall mangle enable [find comment="PCC-4"]
#/ip firewall mangle enable [find comment="PCC-5"]
#/ip firewall mangle enable [find comment="PCC-6"]
#/ip firewall nat disable [find comment="BACKUP_NAT_ENABLE_IT_WHEN_VDSL_DOWN"]

:local MSGUPSMS "$COMPANY+WAN+INFO:%0AWAN-1-2+have+been+Restored.%0AFailover+Script+Powered+By+Syed+Jahanzaib."

# Send SMS via KANNEL FOR UP ALERT
/tool fetch url="$KURL\?username=$KID&password=$KPASS&to=$cell2&text=$MSGUPSMS"
}
}
} 

Regard’s
Syed Jahanzaib

%d bloggers like this: