Gheek.net

July 22, 2011

How to use curl to access a HTTPS URL using a Client Certificate

Filed under: Apache, linux, nix, shell scripts, tomcat — lancevermilion @ 11:14 am

I needed to check a HTTPS URL that required authentication of a client Certificate from the command line.

Using curl was a perfect fit.

curl --insecure --cert-type pem --cert /home/dummyuser/client-cert-stacked.pem --interface eth0:1 "https://192.168.1.2/GetKeepAlive"

Note: I use double quotes " " around the url because if there are any special characters or spaces it will not be read correctly.

Options Option Description
--insecure or -k Disable Certificate Verification against a Root/Intermediate
--cert or -E (HTTPS) Tells curl to use the specified certificate file. The certificate must be in PEM format.

If the optional password isn’t specified, it will be queried for on the terminal. Note that this certificate is the
private key and the private certificate concatenated!

If this option is used several times, the last one will be used.

--cert-type (SSL) Private key file type (DER, PEM, and ENG are supported).
--interface Query the URL using a specified interface.
Advertisement

April 26, 2011

Writing System V init scripts for Red Hat Linux

Filed under: linux, shell scripts — lancevermilion @ 6:06 pm

I was digging around for the different tags chkconfig/sysv init scripts accepts and what they mean. This was the most complete page I found.

From: https://fedorahosted.org/initscripts/browser/sysvinitfiles

Writing System V init scripts for Red Hat Linux

All System V init scripts are named /etc/rc.d/init.d/<servicename> where <servicename> is the name of the service. There must be no “.init” suffix.

This path will very likely be moved to /etc/init.d in the future. Once Red Hat Linux 7.0 is installed, you can access scripts as /etc/init.d/<servicename>, via symlinks

Sample Script:

#!/bin/bash
#
#	/etc/rc.d/init.d/<servicename>
#
#	<description of the *service*>
#	<any general comments about this init script>
#
# <tags -- see below for tag definitions.  *Every line* from the top
#  of the file to the end of the tags section must begin with a #
#  character.  After the tags section, there should be a blank line.
#  This keeps normal comments in the rest of the file from being
#  mistaken for tags, should they happen to fit the pattern.>

# Source function library.
. /etc/init.d/functions

<define any local shell functions used by the code that follows>

start() {
	echo -n "Starting <servicename>: "
	<start daemons, perhaps with the daemon function>
	touch /var/lock/subsys/<servicename>
	return <return code of starting daemon>
}

stop() {
	echo -n "Shutting down <servicename>: "
	<stop daemons, perhaps with the killproc function>
	rm -f /var/lock/subsys/<servicename>
	return <return code of stopping daemon>
}

case "$1" in
    start)
	start
	;;
    stop)
	stop
	;;
    status)
	<report the status of the daemons in free-form format,
	perhaps with the status function>
	;;
    restart)
    	stop
	start
	;;
    reload)
	<cause the service configuration to be reread, either with
	kill -HUP or by restarting the daemons, in a manner similar
	to restart above>
	;;
    condrestart)
    	<Restarts the servce if it is already running. For example:>
	[ -f /var/lock/subsys/<service> ] && restart || :
    probe)
	<optional.  If it exists, then it should determine whether
	or not the service needs to be restarted or reloaded (or
	whatever) in order to activate any changes in the configuration
	scripts.  It should print out a list of commands to give to
	$0; see the description under the probe tag below.>
	;;
    *)
	echo "Usage: <servicename> {start|stop|status|reload|restart[|probe]"
	exit 1
	;;
esac
exit $?

Notes:

  • The restart and reload functions may be (and commonly are) combined into one test, vis:
    restart | reload)
  • You are not prohibited from adding other commands; list all commands which you intend to be used interactively to the usage message.
  • Notice the change in that stop() and start() are now shell functions.

This means that restart can be implemented as

stop
start

instead of

$0 stop
$0 start

This saves a few shell invocations.

Functions in /etc/init.d/functions

daemon [ –check <name> ] [ –user <username>] [+/-nicelevel] program [arguments] [&]

Starts a daemon, if it is not already running. Does other useful things like keeping the daemon from dumping core if it terminates unexpectedly.

–check <name>:

Check that <name> is running, as opposed to simply the first argument passed to daemon().

–user <username>:

Run command as user <username>

killproc program [signal]

Sends a signal to the program; by default it sends a SIGTERM, and if the process doesn’t die, it sends a SIGKILL a few seconds later.

It also tries to remove the pidfile, if it finds one.

pidofproc program

Tries to find the pid of a program; checking likely pidfiles, and using the pidof program. Used mainly from within other functions in this file, but also available to scripts.

status program

Prints status information. Assumes that the program name is the same as the servicename.

Tags

# chkconfig: <startlevellist> <startpriority> <endpriority>

Required. <startlevellist> is a list of levels in which the service should be started by default. <startpriority> and <endpriority> are priority numbers.
For example:
# chkconfig: 2345 20 80

Read ‘man chkconfig’ for more information.

Unless there is a VERY GOOD, EXPLICIT reason to the contrary, the <endpriority> should be equal to 100 – <startpriority>

# description: <multi-line description of service>

Required. Several lines of description, continued with ‘\’ characters. The initial comment and following whitespace on the following lines is ignored.

# description[ln]: <multi-line description of service in the language \
#                                         ln, whatever that is>

Optional. Should be the description translated into the specified language.

# processname:

Optional, multiple entries allowed. For each process name started by the script, there should be a processname entry.
For example, the samba service starts two daemons:
# processname: smdb
# processname: nmdb

# config:

Optional, multiple entries allowed. For each static config file used by the daemon, use a single entry.
For example:

# config: /etc/httpd/conf/httpd.conf
# config: /etc/httpd/conf/srm.conf

Optionally, if the server will automatically reload the config file if it is changed, you can append the word “autoreload” to the line:

# config: /etc/foobar.conf autoreload

# pidfile:

Optional, multiple entries allowed. Use just like the config entry, except that it points at pidfiles. It is assumed that the pidfiles are only updated at process creation time, and not later. The first line of this file should be the ASCII representation of the PID; a terminating newline is optional. Any lines other than the first line are not examined.

# probe: true

Optional, used IN PLACE of processname, config, and pidfile. If it exists, then a proper reload-if-necessary cycle may be acheived by running these commands:

command=$(/etc/rc.d/init.d/SCRIPT probe)
[ -n “$command” ] && /etc/rc.d/init.d/SCRIPT $command

where SCRIPT is the name of the service’s sysv init script.

Scripts that need to do complex processing could, as an example, return “run /var/tmp/<servicename.probe.$$” and implement a “run” command which would execute the named script and then remove it.

Note that the probe command should simply “exit 0” if nothing needs to be done to bring the service into sync with its configuration files.

Copyright (c) 2000 Red Hat Software, Inc.

March 24, 2011

How to find the rpm file used to install the original RPM.

Filed under: linux, perl, shell scripts — lancevermilion @ 5:22 pm

I have run into a problem over the years where my linux system(s) is not on a network accessible segment but rather in a completely firewalled (i.e. POC) DMZ and only available via sneaker net.

This poses issues when I need to upgrade the OS (i.e. CentOS 5.2 to CentOS 5.4) and make sure the same versions of 3rd party software gets reinstalled on the newer version of OS. To try and solve the 3rd party software issue I have kept pretty detailed logs (software versions on which systems) of what is installed but every now and again I forget to update my list of installed 3rd party software. So I use the following steps to figure out what software must be reinstalled.

The first step I have done is check to see what RPMs are installed and in the RPM database. This is nice to have but it doesn’t tell me the complete rpm that was used for the install.

rpm -qa --queryformat '%{NAME}-%{VERSION}-%{RELEASE}

The second step I compare the output from the RPM database against the log (/var/log/rpmpkgs*) that gets written to when each RPM gets installed. This can be a very long process especially if you have done upgrades to your system recently. I normally do this with a quick shell script. I decided it would be best to attack it with a Perl script since I am more fond of Perl scripting then shell scripting.

At some point in time the RPM Packages log gets updated. I haven’t managed to track down the timing for exactly when it gets updated. If anyone knows this please let me know.

#!/usr/bin/perl

use strict;

print "#" x 80 . "\n";
print "Starting RPM Checking Script.\n";
print "-" x 80 . "\n";
print "Please wait while the RPM database is read.\n";
my @rpmdb=`rpm -qa --queryformat '%{NAME},%{VERSION},%{RELEASE}\n'`;
print "Please wait while the RPM package log is read.\n";
my @rpmpkgs=`cat /var/log/rpmpkgs*`;
print "Done reading the RPM database and package logs.\n";
print "RPMDB entries: " . scalar(@rpmdb) ."\n";
print "RPMPKGS log entries: " . scalar(@rpmpkgs) ."\n";
print "#" x 80 . "\n";
foreach(@rpmdb)
{
  chomp;
  my $attempts = 1;
  my $match=0;
  my $tmprpmpkg="";
  my ($name, $ver, $rel) = split(/,/, $_);
  $_ =~ s/,/-/g;
  my $mod = "$name-$ver-$rel";
  my $mod1 = "$name-$ver";
  my $mod2 = "$name";
  for my $rpmpkg (@rpmpkgs)
  {
    chomp($rpmpkg);
     # use the octal value of + instead of + since it has meaning in regex
    $mod =~ s/\53/plus/g;
    $rpmpkg =~ s/\53/plus/g;
    if ($rpmpkg =~ /$mod.*/)
    {
      $match=1;
      $tmprpmpkg=$rpmpkg;
    }
  }
# Uncomment if you want to see the broader search attempts
#  print "\"$mod\" was not found, attempting to find \"$mod1\".\n" if $match < 1 ;
  if ( $match < 1 )
  {
    $attempts++;
    for my $rpmpkg (@rpmpkgs)
    {
      chomp($rpmpkg);
     # use the octal value of + instead of + since it has meaning in regex
      $mod1 =~ s/\53/plus/g;
      $rpmpkg =~ s/\53/plus/g;
      if ($rpmpkg =~ /$mod1.*/)
      {
        $match=1;
        $tmprpmpkg=$rpmpkg;
      }
    }
  }
# Uncomment if you want to see the broader search attempts
#  print "\"$mod1\" was not found, attempting to find \"$mod2\".\n" if $match < 1 ;
  if ( $match < 1 )
  {
    $attempts++;
    for my $rpmpkg (@rpmpkgs)
    {
      chomp($rpmpkg);
     # use the octal value of + instead of + since it has meaning in regex
      $mod2 =~ s/\53/plus/g;
      $rpmpkg =~ s/\53/plus/g;
      if ($rpmpkg =~ /$mod2.*/)
      {
        $match=1;
        $tmprpmpkg=$rpmpkg;
      }
    }
  }
  # Uncomment the line below if you ALSO want to see RPMs that are installed.
  # I have commented this line out initially because I first want to know what
  # RPMs do I need to chase down.
  #print "MATCH: $tmprpmpkg\n" if $match >= 1 && $attempts == 1;
  print "SIMILAR: $_ ~ $tmprpmpkg\n" if $match >= 1 && $attempts > 1;
  print "NOT_FOUND: \"$_\" is not found in \"/var/log/rpmpkgs\".\n" if $match < 1 ;
}
print "#" x 80 . "\n";

Example output. I just added gtkspell and updated tcpdump so there would be some good output. I also snipped almost every match from the list, but left a few so you get the idea of the output.

################################################################################
Starting RPM Checking Script.
--------------------------------------------------------------------------------
Please wait while the RPM database is read.
Please wait while the RPM package log is read.
Done reading the RPM database and package logs.
RPMDB entries: 780
RPMPKGS log entries: 779
################################################################################
MATCH: tzdata-2009k-1.el5.noarch.rpm
MATCH: desktop-backgrounds-basic-2.0-41.el5.centos.noarch.rpm
MATCH: rootfiles-8.1-1.1.1.noarch.rpm
MATCH: atk-1.12.2-1.fc6.i386.rpm
MATCH: audit-libs-1.7.13-2.el5.i386.rpm
<snip>
NOT_FOUND: "gtkspell-2.0.11-2.1" is not found in "/var/log/rpmpkgs".
SIMILAR: tcpdump-3.9.4-15.el5 ~ tcpdump-3.9.4-14.el5.i386.rpm
################################################################################

If you want to get almost the same output (but only for exact matches) you can use this output.

for i in `rpm -qa --queryformat '%{NAME}-%{VERSION}-%{RELEASE}\n'`;
do
  t=`grep "$i" /var/log/rpmpkgs*`;
  [[ "$?" != "0" ]] && echo "$i not found";
done

Output:

gtkspell-2.0.11-2.1 not found
tcpdump-3.9.4-15.el5 not found

March 11, 2011

Bash Scripting I18N/L10N aka Internationalization/Locale

Filed under: linux, shell scripts — lancevermilion @ 11:06 am

It was driving me crazy for the last two days why so many service wrappers (init.d) scripts would use $”..” instead of “…”. Well that is because they are allowing for I18N/L10N.

Example using I18N/L10N with a locale of Spanish

echo $"Hello Sir" # Hola señor

Instead of

echo "Hello Sir" # Hello Sir

Explanation I found that was good was here.
http://wiki.bash-hackers.org/syntax/quoting

I18N/L10N

A dollar-sign followed by a double-quoted string, for example

echo $"generating database..."

means I18N. If there is a translation available for that string, it is used instead of the given text. If not, or if the locale is C/POSIX, the dollar sign simply is ignored, which results in a normal double-quoted string. 

If the string was replaced (translated), the result is double-quoted.

In case you’re a C-programmer: The purpose of $"..." is the same as for gettext() or _().

For useful examples to localize your scripts, please see Appendix I of the Advanced Bash Scripting Guide.

February 28, 2011

Howto Make Script More Portable With #!/usr/bin/env As a Shebang

Filed under: expect, linux, nix, perl, php, shell scripts — lancevermilion @ 9:33 am

The following article is taken directly from http://www.cyberciti.biz/tips/finding-bash-perl-python-portably-using-env.html by VIVEK GITE.

You may have noticed that most shell and perl script starts with the following line:
#!/bin/bash
OR
#!/usr/bin/perl

It is called a shebang. It consists of a number sign and an exclamation point character (#!), followed by the full path to the interpreter such as /bin/bash. All scripts under UNIX and Linux execute using the interpreter specified on a first line.

However there is a small problem. BASH or Perl is not always in the same location (read as PATH) such as /bin/bash or /usr/bin/perl. If you want to make sure that script is portable across different UNIX like operating system you need to use /usr/bin/env command.

env command allows to run a program in a modified environment.

Find line
#!/bin/bash

Replace with
#!/usr/bin/env bash

For example here is a small script:

#!/usr/bin/env bash
x=5
y=10
echo "$x and $y"

OR

#!/usr/bin/env perl
use warnings;
print "Hello " x 5;
print "\\n";

Now you don’t have to search for a program via the PATH environment variable. This makes the script more portable. Also note that it is not foolproof method. Always make sure you have /usr/bin/env exists or use a softlink/symbolic link to point it to correct path. And yes your work (script) looks more professional with this hack 🙂

December 16, 2010

Locally import RPMs to Spacewalk channel from CLI

Filed under: linux, shell scripts, spacewalk — lancevermilion @ 7:43 pm

Sometimes you don’t have a full version of oracle and thus it is not possible to hold a complete set of distro DVDs (updates, extras, base, epel, etc). So the solution I use is get a copy of the repo on my local disk and then push them into a channel. I wrote a script to do this in a prettier fashion since I normally don’t download directly to the distro tree.

Spacewalk is configured according to this website. The only exception is I have local repos for everything and I used spacewalk-client 1.2 instead of 1.0.
http://wiki.centos.org/HowTos/PackageManagement/Spacewalk

input file would look something like this.
osad-5.9.44-1.el5.noarch.rpm
python-ethtool-0.3-5.el5.i386.rpm
python-hwdata-1.2-1.el5.noarch.rpm
rhncfg-5.9.33-1.el5.noarch.rpm
rhncfg-actions-5.9.33-1.el5.noarch.rpm
rhncfg-client-5.9.33-1.el5.noarch.rpm
rhncfg-management-5.9.33-1.el5.noarch.rpm
rhn-check-1.2.15-1.el5.noarch.rpm
rhn-client-tools-1.2.15-1.el5.noarch.rpm
rhn-custom-info-5.4.3-1.el5.noarch.rpm
rhn-kickstart-5.4.5-1.el5.noarch.rpm
rhn-kickstart-common-5.4.5-1.el5.noarch.rpm
rhn-kickstart-virtualization-5.4.5-1.el5.noarch.rpm
rhnlib-2.5.28-1.el5.noarch.rpm
rhnmd-5.3.7-1.el5.noarch.rpm
rhnsd-4.9.7-1.el5.i386.rpm
rhn-setup-1.2.15-1.el5.noarch.rpm
rhn-setup-gnome-1.2.15-1.el5.noarch.rpm
rhn-virtualization-common-5.4.15-1.el5.noarch.rpm
rhn-virtualization-host-5.4.15-1.el5.noarch.rpm
spacewalk-backend-libs-1.2.74-1.el5.noarch.rpm
spacewalk-certs-tools-1.2.2-1.el5.noarch.rpm
spacewalk-koan-0.2.15-1.el5.noarch.rpm
yum-rhn-plugin-1.2.7-1.el5.noarch.rpm

#!/bin/bash

# variables
INPUTFILE="$1"
CHANNEL="$2"
DISTROTREE="$3"
CHOICE="$4"
SWUSER='spaceuser'
SWPASS='spacepass'
SWHOST='localhost'
SWPROTO='http'

if [ "$4" == '' ]; then
CHOICE='r'
fi

function VARIABLES ()
{
echo "#
# VARIABLES
#"
echo "Input file: \"${INPUTFILE}\""
echo "Spacewalk Channel: \"${CHANNEL}\""
if [ -d "${DISTROTREE}" ]; then
echo "Distro-tree directory: \"${DISTROTREE}\""
else
echo "FAIL: Distro-tree directory DOES NOT exist (${DISTROTREE})."
exit 1;
fi
}

function RPMCOPY ()
{
echo "#
# START RPM COPY
#"
echo "FOUND COPIED RPM"
for i in `cat ${INPUTFILE}`
do
FILE=`locate ${i} | grep "/${i}" | grep -v '${DISTROTREE}'`
if [ -f "${FILE}" ]; then
if [ -f "${DISTROTREE}/${i}" ]; then
#echo "File \"${i}\" is already in \"${DISTROTREE}\"."
echo "YES EXISTS ${i}"
else
cp $FILE ${DISTROTREE}/${i}
if [ -f "${DISTROTREE}/${i}" ]; then
echo "YES YES ${i}"
else
cp $FILE ${DISTROTREE}/${i}
echo "YES NO ${i}"
fi
fi
else
echo "NO NO ${i}"
fi
done

echo "#
# STOP RPM COPY
#"
}

function CHANNELCHECK ()
{
# Let the user know if the package is already in the channel
echo "
#
# START CHANNEL CHECK
#"
echo "IN_CHANNEL RPM"
for r in `rhnpush -l --channel=${CHANNEL} -u ${SWUSER} -p ${SWPASS} | awk '{print $1"-"$2"-"$3"."$5".rpm"}' | sed "s/\['//g" | sed "s/',//g" | sed "s/'//g"`
do
FIND=`find ${DISTROTREE} -name ${r}`
if [ "${FIND}" == '' ]; then
echo "NO ${r}"
else
echo "YES ${r}"
fi
done
echo "#
# STOP CHANNEL CHECK
#"
}

function PUSH2CHANNEL ()
{
echo -n "Are you sure? [y/N]: "
read ANS
case ${ANS} in
*y*) echo "Running: rhnpush --channel=${CHANNEL} --server=${SWPROTO}://${SWHOST}/APP --nosig --dir=${DISTROTREE} -v -u ${SWUSER} -p ${SWPASS}"
rhnpush --channel=${CHANNEL} --server=${SWPROTO}://${SWHOST}/APP --nosig --dir=${DISTROTREE} -v -u ${SWUSER} -p ${SWPASS}
cd ${DISTROTREE}
echo "Creating repo"
createrepo ${DISTROTREE}
;;
*) echo "Skipping push to Spacewalk."
echo "Exiting!!"
exit;
;;
esac
}

function CASE ()
{
case ${CHOICE} in
*[rR]*) RPMCOPY
echo -n "Do you wish to check if these RPM are in the Spacewalk Channel? [c/N]: "
read CHOICE
CASE;;
*[cC]*) CHANNELCHECK
echo -n "Do you wish to push these into a Spacewalk Channel? [p/N]: "
read CHOICE
CASE;;

*[pP]*) PUSH2CHANNEL;;
*[nN]*) echo "Exiting!!"
exit;;
esac
}

VARIABLES
CASE

October 20, 2010

Count (Series of) Character Occurrences in a file

Filed under: linux, shell scripts — lancevermilion @ 1:38 pm

There are times especially in bash/shell scripting when a “bash -n” doesn’t get the job done just right.

To help make sure you have matching characters like below you can use the following. The caveat is that if you have >> in your code it will count those under >> (1 occurrence) and > (2 occurrences).

for i in ' ' '>>' '<<' '(' ')' ']' '[' '{' '}' "'" "\""; do echo "$i occurs: `tr -dc "$i" < /var/local/yum/Build/KS_Build.sh | wc -c` times"; done

<> occurs: 2 times
occurs: 2 times
( occurs: 1 times
) occurs: 1 times
] occurs: 0 times
[ occurs: 0 times
{ occurs: 5 times
} occurs: 5 times
' occurs: 0 times
" occurs: 8 times

#!/bin/bash
#Author: Lance Vermilion
#Description: Script to Build KickStart configs for Different Server Types
#Date: 10/20/10

KSTYPE="$1"
KSCFG_LOCATION="/var/local/yum/Build/5.4/disc1/${KSTYPE}"
SCRIPTLET_DIR="/var/local/yum/Build/5.4/disc1/${KSTYPE}/SCRIPTLET"

INCLUDE()
{
SCRIPTLET="$1"
cat ${SCRIPTLET} >> ${KSCFG_LOCATION}
}

# These must be listed in the order you want them to be run
INCLUDE "SOME SCRIPLET TO INCLUDE"
INCLUDE "SOME OTHER SCRIPLET TO INCLUDE"

September 7, 2010

RSYNC CentOS

Filed under: linux, RSYNC, shell scripts — lancevermilion @ 10:21 am

Here is a script to help RSYNC/MIRROR a CentOS distro. I use this to get a distro (CentOS 5.4 in this case) that I need. This script is made from a variety of scripts that found online. Some parts I have added to make it more complete for my purposes.

#!/bin/bash
#
#--------------[ To Do List ]--------------
#-- Fix logging to be complete.
#--
#--
#--
#--
Version='1.0'

# Default values for CLI and HELP
# 0 Disabled
# 1 Enabled
CLI=0
HELP=0

Usage () {
echo "
+------------------------------------------------------------------------------------+
| Script: `basename $0`
| Description: This script is used to rsync CentOS distribution from a known mirror.
| from a known mirror. This script can only have one instance running
| at a time. The default log location if \"/var/log/rsync.log\".
| Version: $VERSION
| Possible Arguments:
| --cli or -c Run from command line and DO NOT output progress.
| --type or -t ALL = to rsync everything. updates = rsync only updates
| --help or -h Help menu (this output).
|
| Syntax Examples:
| For a cron script
| `basename $0` -c -t updates
|
| To watch progress of the rsync
| `basename $0` -t updates
| or
| `basename $0` -t ALL
+------------------------------------------------------------------------------------+
"
}

if [ "$#" -eq 0 ]; then
Usage
RETVAL=1
exit $RETVAL
fi

args=$(getopt -o ct:h -- "$@")
eval set -- "$args"
while [ ! -z "$1" ]
do
case "$1" in

-c) CLI=1;;

-t) # Check for optional argument.
case "$2" in #+ Double colon is optional argument.
"") # Not there.
HELP=1
RETVAL=1
;;

ALL) # Got it
TYPE='ALL'
;;

updates) # Got it
TYPE='updates'
;;

*) # Help since we don't support anything else
HELP=1
RETVAL=1
;;

esac
;;

-h) HELP=1
RETVAL=0
;;

*) HELP=0
RETVAL=1;;
esac
shift
done

if [ "$HELP" -eq 1 ]; then
if [ "$CLI" -eq 0 ]; then
Usage
fi
RETVAL=35
exit $RETVAL
fi

if [ "$TYPE" != 'ALL' ]; then
if [ "$TYPE" != 'updates' ]; then
if [ "$CLI" -eq 0 ]; then
Usage
fi
RETVAL=45
exit $RETVAL
fi
fi

# User/Group ID to chown files to afterwards
CUID=root
CGID=root

# Define where the rsync binary is based on distro
# Linux
RSYNC_PATH=/usr/bin/rsync
# FreeBSD
#RSYNC_PATH=/usr/local/bin/rsync

# name the file we are going to log our output to.
LOGFILE="/var/log/rsync.log"

# Specify where the temporary lock file will be created
TMPLOCKFILE='/var/lock/subsys/rsync'

# Used to tell cleanup not to remove lock file.
# 1 = DELETE TEMPORARY LOCK FILE
# 0 = DO NOT DELETE TEMPORARY LOCK FILE
DELLOCK=1

# if the logfile writable by the user running the script
# 1 = Yes
# 0 = No
if [ -w $LOGFILE ]; then
WRITABLE='1'
else
WRITABLE='0'
fi

if [ "$WRITEABLE" = '0' ]; then
FILEPERMS=`ls -l $LOGFILE | awk '{print $1,$3,$4,$9}'`
printf "Writable Log File: Log file ($LOGFILE) is not writeable ($FILEPERMS)\n" >> $LOGFILE
RETVAL=1
exit $RETVAL
fi

#----------------------------------------------------------
# Function to perform some housekeeping before exiting.
#----------------------------------------------------------
function cleanup {
#
# Did we create a temporary lock file?
if [[ -f "$TMPLOCKFILE" && "$DELLOCK" -eq 1 ]]; then
# YES, then delete it before we exit.
rm $TMPLOCKFILE
if [ -f "$TMPLOCKFILE" ]; then
printf "Remove Temporary Lock File: FAILED to remove $TMPLOCKFILE. See administrator.\n" >> $LOGFILE
else
printf "Remove Temporary Lock File: Successfully removed $TMPLOCKFILE\n" >> $LOGFILE
fi
fi

# Did we create a temporary file?
if [ -f "$TMPFILE" ]; then
# YES, then delete it before we exit.
rm $TMPFILE
if [ -f "$TMPLOCKFILE" ]; then
printf "Remove Temporary File: FAILED to remove $TMPFILE. See administrator.\n" >> $LOGFILE
else
printf "Remove Temporary File: Successfully removed $TMPFILE\n" >> $LOGFILE
fi
fi
# Terminate the script with a return code of 0 (normal termination) or any other number (abnormal termination).
printf "********** STOP: `date +'[%A %b %d %Y] - [%r]'` **********\n" >> $LOGFILE
exit $RETVAL
}

#----------------------------------------------------------
# Function to check if rsync terminated without errors?
#----------------------------------------------------------
function rsync_return_state {
if [[ "$RETVAL" -ne 0 ]]; then
# NO, there was a problem with rsync. Write a FAILED notice to our log file, then exit.
case $RETVAL in
1) REASON="Syntax or usage error";;
2) REASON="Protocol incompatibility";;
3) REASON="Errors selecting input/output files, dirs";;
4) REASON="Requested action not supported";;
5) REASON="Error starting client-server protocol";;
6) REASON="Daemon unable to append to log-file";;
10) REASON="Error in socket I/O";;
11) REASON="Error in file I/O";;
12) REASON="Error in rsync protocol data stream";;
13) REASON="Errors with program diagnostics";;
14) REASON="Error in IPC code";;
20) REASON="Received SIGUSR1 or SIGINT";;
21) REASON="Some error returned by waitpid()";;
22) REASON="Error allocating core memory buffers";;
23) REASON="Partial transfer due to error";;
24) REASON="Partial transfer due to vanished source files";;
25) REASON="The --max-delete limit stopped deletions";;
30) REASON="Timeout in data send/receive";;
35) REASON="Timeout waiting for daemon connection";;
*) REASON="Undefined error";;
esac
printf "Repository update status FAILED with error code $RETVAL: $REASON\n" >> $LOGFILE
fi
}

# Trap CTRL-C and execute cleanup before exiting
trap cleanup INT

if [ -f "$TMPLOCKFILE" ]; then
DELLOCK=0
printf "\n\n********** START: `date +'[%A %b %d %Y] - [%r]'` **********\n" >> $LOGFILE
printf "Repository update status FAILED: A RSYNC temporary lock file ($TMPLOCKFILE) already exist.\n" >> $LOGFILE
RETVAL=1
cleanup
fi

# Create the temporary lock file.
touch $TMPLOCKFILE

# Was the temporary lock file created without errors?
if [ "$?" -ne 0 ]; then
# NO, print a message to our log file then terminate.
printf "\n\n********** START: `date +'[%A %b %d %Y] - [%r]'` **********\n" >> $LOGFILE
printf "Repository update status FAILED: Unable to create temporary file ($TMPLOCKFILE)\n" >> $LOGFILE
RETVAL=1
cleanup
else
printf "\n\n********** START: `date +'[%A %b %d %Y] - [%r]'` **********\n" >> $LOGFILE
printf "Created Temporary Lock File: $TMPLOCKFILE\n" >> $LOGFILE
fi

# Create a temporary file. Creates file in /tmp
TMPFILE=`mktemp -t rsync.XXXXXXXXXX`

# Was the temporary file created without errors?
if [ $? -ne 0 ]; then
# NO, print a message to our log file then terminate.
printf "Repository update FAILED: Unable to create temporary file ($TMPFILE)\n" >> $LOGFILE
RETVAL=1
cleanup
else
printf "Created Temporary File: $TMPFILE\n" >> $LOGFILE
fi

#if [ "$CLI" -eq 1 ]; then
echo ""
echo "Only download progress for RSYNC will display to STDOUT. You should view the log files \"$LOGFILE\""
echo "and \"$TMPFILE\"."
echo "Example: tail -f $LOGFILE"
echo "Example: tail -f $TMPFILE"
echo ""
#fi

# Variables for RSYNC
DL_PATH='/var/local/yum'
OS='linux'
DISTRIBUTION='centos'
VERSION='5.4'
# Only usable if you are getting the current stable version
#MIRROR_SOURCE="msync.centos.org::CentOS/$VERSION/";
# Great for older stable versions
MIRROR_SOURCE="rsync://mirrors.usc.edu/centos/$VERSION/";

# Variablize paramaters for RSYNC
# All flags used below are explained in detail at the very bottom of this file.
# -a, --archive archive mode; same as -rlptgoD (no -H)
# -q, --quiet suppress non-error messages
# -t, --times preserve times
# -z, --compress compress file data during the transfer
# -H, --hard-links preserve hard links
# --exclude=PATTERN exclude files matching PATTERN
# --progress show progress during transfer
# --delete delete files that don’t exist on sender
# --delay-updates put all updated files into place at end
# --stats Give us some extra file transfer stats. Good during an interactive session.

if [ "$TYPE" = "ALL" ]; then
RSYNC="$RSYNC_PATH --progress --stats -aqtzH --delete --delay-updates --exclude=x86_64 --exclude=SRPM*";
else
RSYNC="$RSYNC_PATH --progress --stats -aqtzH --delete --delay-updates --exclude=SRPM* --exclude=isos --exclude=x86_64";
BASELIST="updates"
fi

printf "Repository update status: Started\n" >> $LOGFILE
printf "Repository update status: Type = $TYPE\n" >> $LOGFILE
if [ "$TYPE" = "updates" ]; then
for BASE in $BASELIST
do
# RSYNC the stuff and change ownership accordingly.

if [ $CLI -eq 1 ]; then
printf "Repository update status Syntax: $RSYNC $MIRROR_SOURCE $DL_PATH/$OS/$DISTRIBUTION/$VERSION/$BASE >> $TMPFILE 2>&1\n" >> $LOGFILE
$RSYNC $MIRROR_SOURCE $DL_PATH/$OS/$DISTRIBUTION/$VERSION/$BASE >> $TMPFILE 2>&1
else
printf "Repository update status Syntax: $RSYNC $MIRROR_SOURCE $DL_PATH/$OS/$DISTRIBUTION/$VERSION/$BASE\n" >> $LOGFILE
$RSYNC $MIRROR_SOURCE $DL_PATH/$OS/$DISTRIBUTION/$VERSION/$BASE
fi

# get the return value from rsync and assign it to RETVAL.
RETVAL=$?
rsync_return_state

printf "Repository update status: Finished\n" >> $LOGFILE
printf "Chowning Repository Syntax: chown -R $CUID:$CGID $DL_PATH/$OS/$DISTRIBUTION/$VERSION/$BASE\n" >> $LOGFILE
chown -R $CUID:$CGID $DL_PATH/$OS/$DISTRIBUTION/$VERSION/$BASE
done

else
# RSYNC the stuff and change ownership accordingly.

if [ $CLI -eq 1 ]; then
printf "Repository update status Syntax: $RSYNC $MIRROR_SOURCE $DL_PATH/$OS/$DISTRIBUTION/$VERSION/ >> $TMPFILE 2>&1\n" >> $LOGFILE
$RSYNC $MIRROR_SOURCE $DL_PATH/$OS/$DISTRIBUTION/$VERSION/ >> $TMPFILE 2>&1
else
printf "Repository update status Syntax: $RSYNC $MIRROR_SOURCE $DL_PATH/$OS/$DISTRIBUTION/$VERSION/\n" >> $LOGFILE
$RSYNC $MIRROR_SOURCE $DL_PATH/$OS/$DISTRIBUTION/$VERSION/
fi

# get the return value from rsync and assign it to RETVAL.
RETVAL=$?
rsync_return_state

printf "Repository update status: Finished\n" >> $LOGFILE
printf "Chowning Repository Syntax: chown -R $CUID:$CGID $DL_PATH/$OS/$DISTRIBUTION/$VERSION\n" >> $LOGFILE
chown -R $CUID:$CGID $DL_PATH/$OS/$DISTRIBUTION/$VERSION
fi

if [[ "$RETVAL" -ne 0 ]]; then
RETVAL=2
cleanup
else

RETVAL=0
cleanup

fi

#
# Excert from the man page for all flags that are used.
#
# -a, --archive
# This is equivalent to -rlptgoD. It is a quick way of saying you want recursion and want to preserve
# almost everything (with -H being a notable omission). The only exception to the above equivalence is
# when --files-from is specified, in which case -r is not implied.
#
# Note that -a does not preserve hardlinks, because finding multiply-linked files is expensive. You must
# separately specify -H.
#
# -q, --quiet
# This option decreases the amount of information you are given during the transfer, notably suppressing
# information messages from the remote server. This flag is useful when invoking rsync from cron.
#
#
# -t, --times
# This tells rsync to transfer modification times along with the files and update them on the remote sys-
# tem. Note that if this option is not used, the optimization that excludes files that have not been mod-
# ified cannot be effective; in other words, a missing -t or -a will cause the next transfer to behave as
# if it used -I, causing all files to be updated (though the rsync algorithm will make the update fairly
# efficient if the files haven’t actually changed, you’re much better off using -t).
#
# -z, --compress
# With this option, rsync compresses the file data as it is sent to the destination machine, which reduces
# the amount of data being transmitted -- something that is useful over a slow connection.
#
# Note that this option typically achieves better compression ratios than can be achieved by using a com-
# pressing remote shell or a compressing transport because it takes advantage of the implicit information
# in the matching data blocks that are not explicitly sent over the connection.
#
# -H, --hard-links
# This tells rsync to look for hard-linked files in the transfer and link together the corresponding files
# on the receiving side. Without this option, hard-linked files in the transfer are treated as though
# they were separate files.
#
# Note that rsync can only detect hard links if both parts of the link are in the list of files being
# sent.
#
# --delete
# This tells rsync to delete extraneous files from the receiving side (ones that aren’t on the sending
# side), but only for the directories that are being synchronized. You must have asked rsync to send the
# whole directory (e.g. "dir" or "dir/") without using a wildcard for the directory’s contents (e.g.
# "dir/*") since the wildcard is expanded by the shell and rsync thus gets a request to transfer individ-
# ual files, not the files’ parent directory. Files that are excluded from transfer are also excluded
# from being deleted unless you use the --delete-excluded option or mark the rules as only matching on the
# sending side (see the include/exclude modifiers in the FILTER RULES section).
#
# Prior to rsync 2.6.7, this option would have no effect unless --recursive was in effect. Beginning with
# 2.6.7, deletions will also occur when --dirs (-d) is in effect, but only for directories whose contents
# are being copied.
#
# This option can be dangerous if used incorrectly! It is a very good idea to run first using the --dry-
# run option (-n) to see what files would be deleted to make sure important files aren’t listed.
#
# If the sending side detects any I/O errors, then the deletion of any files at the destination will be
# automatically disabled. This is to prevent temporary filesystem failures (such as NFS errors) on the
# sending side causing a massive deletion of files on the destination. You can override this with the
# --ignore-errors option.
#
# The --delete option may be combined with one of the --delete-WHEN options without conflict, as well as
# --delete-excluded. However, if none of the --delete-WHEN options are specified, rsync will currently
# choose the --delete-before algorithm. A future version may change this to choose the --delete-during
# algorithm. See also --delete-after.
#
# --delay-updates
# This option puts the temporary file from each updated file into a holding directory until the end of the
# transfer, at which time all the files are renamed into place in rapid succession. This attempts to make
# the updating of the files a little more atomic. By default the files are placed into a directory named
# ".~tmp~" in each file’s destination directory, but if you’ve specified the --partial-dir option, that
# directory will be used instead. See the comments in the --partial-dir section for a discussion of how
# this ".~tmp~" dir will be excluded from the transfer, and what you can do if you wnat rsync to cleanup
# old ".~tmp~" dirs that might be lying around. Conflicts with --inplace and --append.
#
# This option uses more memory on the receiving side (one bit per file transferred) and also requires
# enough free disk space on the receiving side to hold an additional copy of all the updated files. Note
# also that you should not use an absolute path to --partial-dir unless (1) there is no chance of any of
# the files in the transfer having the same name (since all the updated files will be put into a single
# directory if the path is absolute) and (2) there are no mount points in the hierarchy (since the delayed
# updates will fail if they can’t be renamed into place).
#
# See also the "atomic-rsync" perl script in the "support" subdir for an update algorithm that is even
# more atomic (it uses --link-dest and a parallel hierarchy of files).
#
# --progress
# This option tells rsync to print information showing the progress of the transfer. This gives a bored
# user something to watch. Implies --verbose if it wasn’t already specified.
#
# When the file is transferring, the data looks like this:
#
# 782448 63% 110.64kB/s 0:00:04
#
# This tells you the current file size, the percentage of the transfer that is complete, the current cal-
# culated file-completion rate (including both data over the wire and data being matched locally), and the
# estimated time remaining in this transfer.
#
# After a file is complete, the data looks like this:
#
# 1238099 100% 146.38kB/s 0:00:08 (5, 57.1% of 396)
#
# This tells you the final file size, that it’s 100% complete, the final transfer rate for the file, the
# amount of elapsed time it took to transfer the file, and the addition of a total-transfer summary in
# parentheses. These additional numbers tell you how many files have been updated, and what percent of
# the total number of files has been scanned.
#
# --exclude=PATTERN
# This option is a simplified form of the --filter option that defaults to an exclude rule and does not
# allow the full rule-parsing syntax of normal filter rules.
#
# See the FILTER RULES section for detailed information on this option.

November 7, 2008

iSCSI init script supporting MySQL checking

Filed under: centos, iscsi, linux, mysql, shell scripts — Tags: , , , — lancevermilion @ 10:17 am

Here is a iSCSI init script for CentOS 5.x. I presume it will work on all flavors of Linux, but haven’t tested. This init script is the original init script but modified to support checking for MySQL databases that might be using the iSCSI mounted disk. So we do not want to umount the iSCSI disk while MySQL is running. I also added checks to see if iscsid is actually running, if it is then make sure you are not already logged in. If you are then don’t try to login again. Also once iSCSI is successfully started we want to mount the iSCSI disk so it is available.

*NOTE: Make sure to adjust your boot init setup. Normally mysql will start before iscsi and iscsid EXCEPT for init 5. Which by default init 5 is the only level which will start mysqld. If you have changed this or yours if not the same make sure you account for this.


chkconfig --list | egrep "iscsi|mysql"
iscsi 0:off 1:off 2:off 3:on 4:on 5:on 6:off
iscsid 0:off 1:off 2:off 3:on 4:on 5:on 6:off
mysqld 0:off 1:off 2:off 3:off 4:off 5:on 6:off

init level 3

ls -l /etc/rc.d/rc3.d/ | egrep -i "mysql|iscsi" | awk '{print $9, $10, $11, $12;}'
K36mysqld -> ../init.d/mysqld
S07iscsid -> ../init.d/iscsid
S13iscsi -> ../init.d/iscsi

init level 5

ls -l /etc/rc.d/rc5.d/ | egrep -i "mysql|iscsi" | awk '{print $9, $10, $11, $12;}'
S07iscsid -> ../init.d/iscsid
S13iscsi -> ../init.d/iscsi
S64mysqld -> ../init.d/mysqld

/etc/init.d/iscsi

#!/bin/sh
#
# chkconfig: 345 13 89
# description: Logs into iSCSI targets needed at system startup
#
# Source function library.
. /etc/init.d/functions

PATH=/sbin:/bin:/usr/sbin:/usr/bin

RETVAL=0

start()
{

        status iscsid > /dev/null 2>&1
        RETVAL=$?

        if [ $RETVAL -ne 0 ]; then
                /etc/init.d/iscsid start
        fi


        status iscsid > /dev/null 2>&1
        RETVAL=$?

        #
        # Verify iscsi is logged in to the iscsi disk
        # and iscsid is actually running.
        #
        iscsiadm -m session -R > /dev/null 2>&1
        iscsiadmcheck=$?
        if [ $RETVAL -eq  0 ]; then
           if [ $iscsiadmcheck -ne "0" ]; then
             echo -n $"Setting up iSCSI targets: "
             # this script is normally called from startup so log into
             # nodes marked node.startup=automatic
             iscsiadm -m node --loginall=automatic
             touch /var/lock/subsys/iscsi
             success
             echo
             sleep 5
             mount -a -O _netdev
           else
             action $"iscsid: " /bin/true
             echo "iscsi:   [ is running ]"
           fi
        else
           action $"Starting iscsid: " /bin/false
           RETVAL=1
        fi
}

stop()
{
        rm -f /var/lock/subsys/iscsi

        # If this is a final shutdown/halt, do nothing since
        # lvm/dm, md, power path, etc do not always handle this
        if [ "$RUNLEVEL" = "6" -o "$RUNLEVEL" = "0" -o "$RUNLEVEL" = "1" ]; then
                success
                return
        fi

        # Do NOT turn off iscsi if root is possibly on a iscsi disk
        rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' /etc/mtab)
        if [[ "$rootopts" =~ "_netdev" ]] ; then
                action $"Stopping iscsid: " /bin/false
                echo $"Can not shutdown iSCSI. Root is on a iSCSI disk."
                exit 1
        fi

        #
        # MySQL checking. If MySQL loads a DB from an iscsi disk we need to make sure
        # MySQL is NOT running before we shutdown iscsi and umount the iscsi disk.
        #
        mysqlopts=$(awk '{  if ( $1 ~ /^datadir/ ) { gsub("datadir=", "", $1); print $1; } }' /etc/my.cnf)
        iscsiopts=$(awk -v mysqlopts=$mysqlopts '{ if ($1 !~ /^[ \t]*#/ && $2 != "/" && mysqlopts ~ $2 ) { print $4; }}' /etc/mtab)
        /etc/init.d/mysqld status > /dev/null 2>&1
        mysqlcheck=$?
        if [[ "$iscsiopts" =~ "_netdev" ]] ; then
                if [ "$mysqlcheck" -eq 0 ]; then
                  action $"Stopping iscsid: " /bin/false
                  echo "Can not shutdown iSCSI. MySQL is mounted on a iSCSI disk."
                  exit 1
                fi
        fi
        iscsiadm -m node --logoutall=all
        /etc/init.d/iscsid stop
        success

        status iscsid > /dev/null 2>&1
        RETVAL=$?
        iscsiadm -m session -R > /dev/null 2>&1
        iscsiadmcheck=$?
        if [[ "$iscsiadmcheck" -ne 0 && $RETVAL -ne 0 ]]; then
          umount -a -O _netdev
        else
           action $"Stopping iscsid: " /bin/false
           echo "iSCSI did NOT logout successfully"
           RETVAL=1
        fi
}

case "$1" in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart)
                stop
                start
                ;;
        status)
                status iscsid
                RETVAL=$?
                ;;
        condrestart)
                [ -f /var/lock/subsys/iscsi ] && restart
                ;;
        *)
                echo $"Usage: $0 {start|stop|restart|status|condrestart}"
                exit 1
esac
exit $RETVAL

/etc/init.d/iscsid

#!/bin/sh
#
# chkconfig: 345 7 89
# description: Starts and stops the iSCSI daemon.
#
# processname: iscsid
# pidfile: /var/run/iscsid.pid
# config:  /etc/iscsi/iscsid.conf

# Source function library.
. /etc/init.d/functions

PATH=/sbin:/bin:/usr/sbin:/usr/bin

RETVAL=0

start()
{
        echo -n $"Turning off network shutdown. "
        # we do not want iscsi or network to run during system shutdown
        # incase there are RAID or multipath devices using
        # iscsi disks
        chkconfig --level 06 network off
        rm /etc/rc0.d/*network
        rm /etc/rc6.d/*network

        echo -n $"Starting iSCSI daemon: "
        modprobe -q iscsi_tcp
        modprobe -q ib_iser
        daemon iscsid
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] || return

        touch /var/lock/subsys/iscsid

        success
        echo
        sleep 5
}

stop()
{
        rm -f /var/lock/subsys/iscsid

        # If this is a final shutdown/halt, do nothing since
        # we may need iscsid for as long as possible (halt script kills
        # us at the last second)
        if [ "$RUNLEVEL" = "6" -o "$RUNLEVEL" = "0" -o "$RUNLEVEL" = "1" ]; then
                success
                return
        fi

        # don't turn off iscsi if root is possibly on a iscsi disk
        rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' /etc/mtab)
        if [[ "$rootopts" =~ "_netdev" ]] ; then
                echo $"Can not shutdown iSCSI. Root is on a iSCSI disk."
                exit 1
        fi

        mysqlopts=$(awk '{  if ( $1 ~ /^datadir/ ) { gsub("datadir=", "", $1); print $1; } }' /etc/my.cnf)
        iscsiopts=$(awk -v mysqlopts=$mysqlopts '{ if ($1 !~ /^[ \t]*#/ && $2 != "/" && mysqlopts ~ $2 ) { print $4; }}' /etc/mtab)
        /etc/init.d/mysqld status > /dev/null 2>&1
        mysqlcheck=$?
        if [[ "$iscsiopts" = "rw,_netdev" ]] ; then
                if [ "$mysqlcheck" -eq 0 ]; then
                  echo "Can not shutdown iSCSI. MySQL is on a iSCSI disk."
                  exit 1
                fi
        fi


        echo -n $"Stopping iSCSI daemon: "

        # iscsid does not have a nice shutdown process.
        # It really should never be stopped
        #pkill -KILL iscsid
        killproc iscsid
        echo

        modprobe -r ib_iser 2>/dev/null
        modprobe -r iscsi_tcp 2>/dev/null
}

restart()
{
        stop
        start
}

case "$1" in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart)
                stop
                start
                ;;
        status)
                status iscsid
                RETVAL=$?
                ;;
        condrestart)
                [ -f /var/lock/subsys/iscsid ] && restart
                ;;
        *)
                echo $"Usage: $0 {start|stop|restart|status|condrestart}"
                exit 1
esac

exit $RETVAL

MySQL init script supporting iSCSI disk mount checking

Filed under: centos, iscsi, linux, mysql, shell scripts — Tags: , , — lancevermilion @ 9:45 am

Here is a MySQLd init script for CentOS 5.x. I presume it will work on all flavors of Linux, but haven’t tested. The init script is the original init script but modified to support checking for iSCSI disk support. Basically if the my.cnf specifies a directory that is on an iSCSI mounted disk it will make sure iscsi/iscsid are running and the mount is present in /etc/mtab. I also added a check to see if MySQL is already running and if so do NOT try to restart mysql when a user issues “/etc/init.d/mysqld start”. Basically The user must first issue “/etc/init.d/mysqld restart” or “/etc/init.d/mysqld stop” then “/etc/init.d/mysqld start”. I also added a chkconfig bit. MySQLd needs to start after iSCSI has started just in case it needs to the iSCSI disk. Multipath should be enabled with “/sbin/chkconfig multipathd on” which by default sets init levels 2, 3, 4, and 5 to on. So you would have the services start up as so: multipathd, iscsid, iscsi, mysqld. They will shut down in reverse order: mysqld, iscsi, iscsid, multipathd.


#!/bin/bash
#
# mysqld This shell script takes care of starting and stopping
# the MySQL subsystem (mysqld).
#
# chkconfig: 345 64 36
# description: MySQL database server.
# processname: mysqld
# config: /etc/my.cnf
# pidfile: /var/run/mysqld/mysqld.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

prog="MySQL"

# extract value of a MySQL option from config files
# Usage: get_mysql_option SECTION VARNAME DEFAULT
# result is returned in $result
# We use my_print_defaults which prints all options from multiple files,
# with the more specific ones later; hence take the last match.
get_mysql_option(){
result=`/usr/bin/my_print_defaults "$1" | sed -n "s/^--$2=//p" | tail -n 1`
if [ -z "$result" ]; then
# not found, use default
result="$3"
fi
}

get_mysql_option mysqld datadir "/var/lib/mysql"
datadir="$result"
get_mysql_option mysqld socket "$datadir/mysql.sock"
socketfile="$result"
get_mysql_option mysqld_safe log-error "/var/log/mysqld.log"
errlogfile="$result"
get_mysql_option mysqld_safe pid-file "/var/run/mysqld/mysqld.pid"
mypidfile="$result"

start(){
#
# iscsi checking. If we need mysql to create/load a DB that is one an iscsi
# disk we ned to make sure iscsi is running, we can successfully login,
# and verify the iscsi disk is moutned before starting mysql.
#
status mysqld > /dev/null 2>&1
mysqlcheck=$?
mysqlopts=$(awk '{ if ( $1 ~ /^datadir/ ) { gsub("datadir=", "", $1); print $1; } }' /etc/my.cnf)
iscsiopts=$(awk -v mysqlopts=$mysqlopts '{ if ($1 !~ /^[ \t]*#/ && $2 != "/" && mysqlopts ~ $2 ) { print $4; }}' /etc/mtab)
status iscsid > /dev/null 2>&1
iscsicheck=$?
if [ "$mysqlcheck" -eq 0 ]; then
echo "MySQL [ already running ]"
exit 1
else
if [ "$iscsicheck" -ne 0 ] ; then
if [[ "$iscsiopts" =~ "_netdev" ]]; then
action $"Checking iscsid: " /bin/true
action $"Starting $prog: " /bin/false
echo "Can not start MySQL, iSCSI disk is not mounted. MySQL is on a iSCSI disk."
exit 1
fi
elif [ "$iscsicheck" -eq 0 ]; then
if [[ "$iscsiopts" =~ "_netdev" ]]; then
iscsiadm -m session -R > /dev/null 2>&1
iscsiadmcheck=$?
if [ "$iscsiadmcheck" -ne 0 ]; then
action $"Checking iscsid: " /bin/true
action $"Starting $prog: " /bin/false
echo "iSCSI login check failed. QUITING!!!"
exit 1
fi
fi
else
action $"Checking iscsid: " /bin/false
action $"Starting $prog: " /bin/false
echo "Can not start MySQL, iSCSI is not running. MySQL is on a iSCSI disk."
exit 1
fi
fi
touch "$errlogfile"
chown mysql:mysql "$errlogfile"
chmod 0640 "$errlogfile"
[ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile"
if [ ! -d "$datadir/mysql" ] ; then
action $"Initializing MySQL database: " /usr/bin/mysql_install_db
ret=$?
chown -R mysql:mysql "$datadir"
if [ $ret -ne 0 ] ; then
return $ret
fi
fi
chown mysql:mysql "$datadir"
chmod 0755 "$datadir"
# Pass all the options determined above, to ensure consistent behavior.
# In many cases mysqld_safe would arrive at the same conclusions anyway
# but we need to be sure.
/usr/bin/mysqld_safe --datadir="$datadir" --socket="$socketfile" \
--log-error="$errlogfile" --pid-file="$mypidfile" \
>/dev/null 2>&1 &
ret=$?
# Spin for a maximum of N seconds waiting for the server to come up.
# Rather than assuming we know a valid username, accept an "access
# denied" response as meaning the server is functioning.
if [ $ret -eq 0 ]; then
STARTTIMEOUT=30
while [ $STARTTIMEOUT -gt 0 ]; do
RESPONSE=`/usr/bin/mysqladmin -uUNKNOWN_MYSQL_USER ping 2>&1` && break
echo "$RESPONSE" | grep -q "Access denied for user" && break
sleep 1
let STARTTIMEOUT=${STARTTIMEOUT}-1
done
if [ $STARTTIMEOUT -eq 0 ]; then
echo "Timeout error occurred trying to start MySQL Daemon."
action $"Starting $prog: " /bin/false
ret=1
else
action $"Starting $prog: " /bin/true
fi
else
action $"Starting $prog: " /bin/false
fi
[ $ret -eq 0 ] && touch /var/lock/subsys/mysqld
return $ret
}

stop(){
MYSQLPID=`cat "$mypidfile" 2>/dev/null `
if [ -n "$MYSQLPID" ]; then
/bin/kill "$MYSQLPID" >/dev/null 2>&1
ret=$?
if [ $ret -eq 0 ]; then
STOPTIMEOUT=60
while [ $STOPTIMEOUT -gt 0 ]; do
/bin/kill -0 "$MYSQLPID" >/dev/null 2>&1 || break
sleep 1
let STOPTIMEOUT=${STOPTIMEOUT}-1
done
if [ $STOPTIMEOUT -eq 0 ]; then
echo "Timeout error occurred trying to stop MySQL Daemon."
ret=1
action $"Stopping $prog: " /bin/false
else
rm -f /var/lock/subsys/mysqld
rm -f "$socketfile"
action $"Stopping $prog: " /bin/true
fi
else
action $"Stopping $prog: " /bin/false
fi
else
ret=1
action $"Stopping $prog: " /bin/false
fi
return $ret
}

restart(){
stop
start
}

condrestart(){
[ -e /var/lock/subsys/mysqld ] && restart || :
}

# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status mysqld
;;
restart)
restart
;;
condrestart)
condrestart
;;
*)
echo $"Usage: $0 {start|stop|status|condrestart|restart}"
exit 1
esac

exit $?

Older Posts »

Blog at WordPress.com.