The post Monitor IPSec VPN Tunnel appeared first on Justin Silver.
]]>I have an IPSec Tunnel built from one of my servers to an integration partner which is used to secure our web service calls. It uses a IPSec, OpenSwan, and Pluto to maintain a private network. Unfortunately I was seeing that this tunnel would for some reason collapse, requiring me to manually restart IPSec to rebuild the tunnel and re-enable our web services. This usually seemed to happen around 1am so despite many, many (MANY), emails, I wouldn’t actually fix it for several hours.
To aid in the process of stopping and then restarting the services, I wrote a bash script to handle all the comments. I only have one IPSec interface of ipsec0
which is used in my script. Make sure to chmod +x /usr/local/bin/ipsec-restart.sh
.
#!/bin/bash # get the -i or --interface argument value while [[ $# > 1 ]] do key="$1" case $key in -i|--interface) INTERFACE="$2" shift # past argument ;; esac shift # past argument or value done # show an error if the interface isn't specified if [ -z "$INTERFACE" ] then echo "You must provide an interface argument with -i or --interface" exit fi # restart ipsec, then bring up the IPSec tunnel /sbin/service ipsec restart /usr/sbin/ipsec whack --shutdown /usr/sbin/ipsec setup --restart /usr/sbin/ipsec auto --add $INTERFACE sleep 5 /usr/sbin/ipsec auto --up $INTERFACE
Next step is to have the system automatically run the script when the tunnel goes down. Using NetCat (nc
) is a good option for this – it can actually do a crazy number of things I won’t go into here. Basically we want to test the hostname of our service to see if we can open port 80, and if not, run the restart script. Passing in -w 10
tells it to wait 10 seconds to time out. By redirecting the output we can have this show nothing if it connects successfully, but email the address specified in the MAILTO
with the ipsec-restart.sh
output. Run this script every 5 minutes (and as root) by adding it to crontab while logged in as root, or using sudo crontab -e
to edit.
# Monitor VPN MAILTO="[email protected]" */5 * * * * ( nc -w 10 -z hostname.webservice.com 80 ) >& /dev/null || /usr/local/bin/ipsec-restart.sh -i ipsec0
The post Monitor IPSec VPN Tunnel appeared first on Justin Silver.
]]>The post Disable WP-Cron in WordPress appeared first on Justin Silver.
]]>WP-Cron is the way that WordPress executes scheduled jobs that are added via wp_schedule_event()
or one of its associated functions. First it’s a bit of a hack given the single threaded-ness of PHP. It’s simply not possible to spin up a Thread
like you would in Java to do the work asynchronously, and we don’t want the users to have to wait while we run a large job. To get around this WordPress checks to see if there are any scheduled jobs with an execution time in the past (more on this in a bit), and will then make a request to itself calling wp-cron.php
with a querystring of doing_wp_cron
. The job can now run in this new request (which is a different PHP process) and the page HTML is returned to the users without ever trying to fetch the results.
WP-Cron lets you do things like check for plugin updates or other arbitrary tasks at set intervals – once or twice a day, longer, or more frequently if you desire. In many ways this mimics the functionality of cron
on your Linux box.
There are lots of useful things you can do with a scheduled task – send emails, update derived database values, really anything that you want to happen regularly, but not on every request. If you’re ok with some user’s seeing slightly stale data in exchange for better performance, you can use a WP-Cron job to indicate that the cache needs to be primed.
While WP-Cron can be a very useful tool, there are some downsides to it as well. As mentioned earlier it can only check for jobs that should have already run, meaning that the scheduled $execution_time < time()
, but this can be an issue on sites with low traffic, especially if you actually care what time the task will be run. Even if your site does decent traffic during the day, maybe it drops way off at night and you want to run something as close to 1:00AM as possible… which might or might not happen.
There is also the performance hit you take making an HTTP request, even though it’s to yourself. Why check the database and WP-Cron locks to see if the HTTP request is even necessary? Speaking of locks – while much better about locking WP-Cron, sites with heavy traffic can occasionally end up with multiple WP-Cron requests (if user requests come in at the exact same time).
The way that I handle WP-Cron on my sites is to disable it entirely by setting the DISABLE_WP_CRON
constant to true
in wp-config.php
. This will prevent WordPress from checking for WP-Cron tasks at all when a user makes a request.
The next step is to set cron on the system to make the request to wp-cron.php based on whatever schedule works best for you. You can have it run as frequently as once per minute, or up to… forever. Probably whatever the smallest resolution of your recurring tasks are is best, unless you are using wp_schedule_single_event()
to run something asynchronously – then a minute might be best.
define( 'DISABLE_WP_CRON', true );
# Run WP-Cron every 5 minutes */5 * * * * /usr/bin/curl --silent http://example.com/wp-cron.php?doing_wp_cron >/dev/null
The post Disable WP-Cron in WordPress appeared first on Justin Silver.
]]>The post Production Cron Tasks appeared first on Justin Silver.
]]>Useful if you run scheduled tasks in production and want to leverage cron, via Orchestrate.io. The Gist shell script for cron_helper.sh
is below.
#!/bin/bash usage() { cat << EOF Usage: $0 [OPTION]... COMMAND Execute the given command in a way that works safely with cron. This should typically be used inside of a cron job definition like so: * * * * * $(which "$0") [OPTION]... COMMAND Arguments: -c Ensure that the job never exits non zero. -e EXITFILE The exit file that will have a time stamp written to it if the job succeeds. -h This help message. -i Nice the job so that it doesn't over consume resources. -k LOCKFILE The lock file to hold while the job is running. -l LOGFILE The log file to write stdout and stderr too. -n NAME The name of this cron job. Giving the cron job a name causes log lines to include it in the output, and automatically sets EXITFILE, LOCKFILE, and LOGFILE to some simple default values. EXITFILE will be set to /var/run/\$USER/NAME.exit if /var/run/\$USER exists, otherwise it will write to /var/tmp/\$USER/NAME.exit LOCKFILE will be set to /var/run/\$USER/NAME.lock if /var/run\$USER exists, otherwise it will write to /var/tmp/\$USER/NAME.lock LOGFILE will be set to /var/log/\$USER/NAME.log if /var/log/\$USER exists, otherwise it will write to /var/tmp/$USER/NAME.log -s If set the script will sleep a random time between 0 and 60 seconds before starting the command. -t If set then the output from the script will be automatically timestamped when being written to the log file. COMMAND is the command that should be executed. EOF } SAFE_EXIT=0 EXIT_FILE="" NICE=0 LOCK_FILE="" LOG_FILE="" NAME="" SLEEP=0 TIMESTAMP=0 # This is a cach of all the groups the user is a member of. We use it with # canwrite() later. GROUPS="" # Checks to see if the shell array ($2) contains $1. contains() { local i for i in "${@:2}"; do [[ "$i" == "$1" ]] && return 0 done return 1 } # Checks to see if the current user can write to the given file. This will check the # file permissions first, and if the file does not exist then it will check the # directory permissions. canwrite() { local perm local owner local group if [ -f "$1" ] ; then read perm owner group < <(stat -Lc "%a %G %U" "$1" 2> /dev/null) else read perm owner group < <(stat -Lc "%a %G %U" "$(dirname $1)" 2> /dev/null) fi if [ $? -ne 0 ] ; then return 1 fi if [ "$owner" == "$USER" ] ; then if [ $((perm&0200)) -ne 0 ] ; then return 1 fi return 0 elif contains "$group" "${GROUPS[@]}" ; then if [ $((perm&0020)) -ne 0 ] ; then return 1 fi return 0 else if [ $((perm&0002)) -ne 0 ] ; then return 1 fi return 0 fi } name() { NAME="$1" # Exit file if [ -z "$EXIT_FILE" ] ; then if canwrite "/var/run/${USER}/${NAME}.exit" ; then EXIT_FILE="/var/run/${USER}/${NAME}.exit" else mkdir -p "/var/tmp/${USER}" EXIT_FILE="/var/tmp/${USER}/${NAME}.exit" fi fi # Lock File if [ -z "$LOCK_FILE" ] ; then if canwrite "/var/run/${USER}/${NAME}.lock" ; then LOCK_FILE="/var/run/${USER}/${NAME}.lock" else mkdir -p "/var/tmp/${USER}" LOCK_FILE="/var/tmp/${USER}/${NAME}.lock" fi fi # Log File if [ -z "$LOG_FILE" ] ; then if canwrite "/var/run/${USER}/${NAME}.lock" ; then LOG_FILE="/var/log/${USER}/${NAME}.log" else mkdir -p "/var/tmp/${USER}" LOG_FILE="/var/tmp/${USER}/${NAME}.log" fi fi } while getopts "ce:hik:l:n:st" arg; do case $arg in c) SAFE_EXIT=1 ;; e) EXIT_FILE="$OPTARG" ;; h) usage ; exit ;; i) NICE=1 ;; k) LOCK_FILE="$OPTARG" ;; l) LOG_FILE="$OPTARG" ;; n) name "$OPTARG" ;; s) SLEEP=1 ;; t) TIMESTAMP=1 ;; esac done shift $((OPTIND-1)) # This function will write a log line to the output. This can either be called by the # timestamper, or internally. log() { if [ $TIMESTAMP -eq 1 ] ; then echo "$(date) $*" else echo "$*" fi } # Setup logging first so we can report to the user what is happening. if [ -n "$LOG_FILE" ] ; then exec > "$LOG_FILE" 2>&1 fi # Attempt to lock the lock file if it is set. if [ -n "$LOCK_FILE" ] ; then exec 200>> "$LOCK_FILE" flock -n -x 200 if [ $? -ne 0 ] ; then log "Unable to obtain a lock, is a job already running?" if [ $SAFE_EXIT -eq 1 ] ; then exit 0 else exit 1 fi fi fi # Sleep a random amount between 0 and 60 seconds. if [ $SLEEP -eq 1 ] ; then sleep $((RANDOM%60)) fi # Get the pre-command in case we need to nice the job. PRECOMMAND="" if [ $NICE -eq 1 ] ; then PRECOMMAND="nice" fi # Run the command. if [ $TIMESTAMP -eq 1 ] ; then $PRECOMMAND "$@" 2>&1 | while read line ; do log "$line" ; done else $PRECOMMAND "$@" 2>&1 fi EXIT_STATUS=$? # Process the exit file. if [ -n "$EXIT_FILE" -a $EXIT_STATUS -eq 0 ] ; then date > "$EXIT_FILE" fi # Exit status if [ $SAFE_EXIT -eq 1 ] ; then exit 0 else exit $EXIT_STATUS fi
The post Production Cron Tasks appeared first on Justin Silver.
]]>