Sysadmin

Bash

Backup of subversion repository

This script does an svn hotcopy of a subversion repository and then rsyncs it to an external location. Easy to script, nice trouble-free way of maintaining subversion backups.

#!/bin/bash
export RSYNC_RSH=/usr/bin/ssh

# some variables in case they change later
server=destination.com # where we are sending the backup to
user=miguel
tempcopy=/home/${user}/svnbackup
dest=/media/disk/svnserver/svnbackup

# example svn repository
# make the backup with svnadmin hotcopy
svnadmin hotcopy /data1/svn/repo/ ${tempcopy}/repo/

# rsync it to the external hard drive on my desk
rsync -aHPvz ${tempcopy}/repo/ "${user}@${server}:${dest}/repo/"

# finally, remove the backup on svnserver to free up some space
rm -rf ${tempcopy}/repo

Getting a cron to execute on the last day of month

Tags:

It had never occured to me before, but suddenly I had the need to run a script on the last day of every month, in order to get the right results per month.

Given that a month's last date can be 28, 29 30 or 31, it wasn't as simple as usual!

After a bit of googling I found the easy solution. Simply get the crontab to run every day, but add into the crontab a check to see if tomorrow's date of the month is '01'. If it isn't, do nothing. If it is, then continue with the rest of the script.

36 14 * * * [ `date -d tomorrow +%d` -eq '01'] && /execute/the/real/script.sh

Edit: Hmm, got a syntax error there:

/bin/sh: -c: line 0: unexpected EOF while looking for matching ``' /bin/sh: -c: line 1: syntax error: unexpected end of file

Ah well, since I'm only executing a shell script, I just added this to my script:

#!/bin/bash
TODAY=`/bin/date +%d`
TOMORROW=`/bin/date +%d -d "1 day"`
# See if tomorrow's day is less than today's
if [ $TOMORROW -lt $TODAY ]; then
(real script executes here)
exit 0
fi
exit 1

Sharing bash sessions

Both articles from Sébastien Wains's blog

Named pipe

You may know “screen”, tool that can help you put your session on hold and and get back to it whenever you want.
Described below is a way to share your session with someone… this can come in handy while doing support or if you just want to share your session for some reason

You should follow the following steps carefully

User 1 will work in the terminal
User 2 will watch what user 1 is doing

1. User 1 :

mkfifo /tmp/file

2. User 2 :

cat /tmp/file

3. User 1 :

script -f /tmp/file

User 1 can start working, user 2 will be able to follow his work, user 1 should type ctrl + D if wanting to stop sharing the session…

If user 2 tries to input something, the connection to the pipe will be lost and you should get back to step 2.

Screen method

This is a great way if you can’t install anything on the machine. If you are able to get “screen” installed, screen provides a much easier way, which allows all connected users to interact on the shared session. The named pipe method only allowed one user to watch what the other user was doing.

So here it goes…

1. user 1 connects to the machine and type the command “screen”
2. inside the screen terminal, user 1 hits ctrl + a and then type “:multiuser on”
3. user 2 joins in by typing “screen -x”
4. other users can join as described at point 3

Both users are now sharing the session.

Ctrl + a then d will close the screen session

Links :

Source : http://linuxhelp.blogspot.com/2005/01/screen-window-manager-for-console....

rsync backup script

VERY simple rsync script. It rsyncs a remote directory across to a local one. There's no special reason why I did this, other than I wanted to run the script on my local machine. It could just as easily rsync a local directory to a remote one.

#!/bin/sh
export RSYNC_RSH=/usr/bin/ssh
origin=remote.machine.com # the remote machine to rsync from
user=miguel # the remote user
rsync -aHPvz "${user}@${origin}:/remote/files/" "/local/files/"

I run ssh-keygen -t rsa and create a password-less key on the remote machine, and copy the .pub file into my authorized_keys. This way I can run this script on a cron, say in the middle of the night, and not have to be around to enter a password at the prompt.

Bash shortcuts

Ctrl-a -> go to the start of command line
Ctrl-e -> go to the end of command line
Ctrl-p -> previous command in history
Ctrl-n -> next command in history
Ctrl-f -> next character in command line
Ctrl-b -> previous character in command line
Ctrl-r -> reverse search in history file
Ctrl-d -> delete current character
Ctrl-k -> delete from the prompt to the end of command line
Ctrl-_ -> undo (yes, but limited)
Meta-< -> go to beginning of history file
Meta-> -> go to end of history file
Meta-f -> go to next word in command line
Meta-b -> go to previous word in command line
Meta-d -> delete next word in command line (from the actual position of the prompt)

Better rsync backup script


#!/bin/bash
# Basic backup script
# Written in February 2010

# Set to q to disable verbosity
VERBOSITY="v"

# The program we're using to backup
PROGRAM="rsync"

# The arguments to the program
OPTIONS="-aHP$VERBOSITY"

# The remote machine we're backing up
SERVER="max"

# The local disk to back up to
DISK="/mnt/disk"

# An array of shares on $SERVER to back up
SHARES=(
hr
finance
clients
operations
newsvn
svn
backup/jira
backup/svn/noah
backup/dbbackups/kontrol_live
backup/dbbackups/god
)

# The magic
for share in ${SHARES[*]}; do
echo "Backup of $share beginning at" `date`
$PROGRAM $OPTIONS $PROGRAM://$SERVER/$share/ $DISK/$share/
echo "Backup of $share completed at" `date`
done

Bash: Monitor file addition/deletion in a directory

Silly little script to monitor changes in a directory (new or removed files)

Takes the destination dir to monitor from stdin

One day I'll learn how to use inotify.


#!/bin/bash

# Monitor a directory for file changes
# (add or remove) as requested

touch /tmp/testdirb.$$
while true
do
find $1 -print > /tmp/testdira.$$
diff /tmp/testdira.$$ /tmp/testdirb.$$ > /tmp/dirdiff
if [ -s /tmp/dirdiff ]
then
sed -i s/" sed -i s/">"/"Removed files"/ /tmp/dirdiff
/usr/bin/mail -s "Files changed in $1" "you@example.com" There have been file changes in $1 since the last hour.
`cat /tmp/dirdiff`
EOF
fi

cp /tmp/testdira.$$ /tmp/testdirb.$$
sleep 3600
done

How to deny caching of specific hosts in Squid

Tags:

acl confickerworkinggroup dstdomain .confickerworkinggroup.org
 
cache deny confickerworkinggroup

How to update cygwin /etc/passwd to get all latest windoze users

mkpasswd -cl > /etc/passwd

mkgroup --local > /etc/group

Install HP Color Laserjet 2600n driver on Linux

http://wiki.markoschulz.de/index.php/Install_and_setup_HP_Color_LaserJet


apt-get install cupsys cupsys-bsd a2ps psutils gs-esp build-essential


wget -O foo2zjs.tar.gz http://foo2zjs.rkkda.com/foo2zjs.tar.gz


cp foo2zjs.tar.gz /usr/local/src/


cd /usr/local/src/


tar zxf foo2zjs.tar.gz


cd foo2zjs


make


make install


make cups

http://localhost:631/admin

Add the printer

socket address is the IP of the printer

choose the 2600n driver

So easy!

Learning Git

Bunch of good resources

Networking

Using tcpdump to analyse arp who-has requests on internal network

Couldn't really tell you how useful this is, but it's interesting anyway.

Specifically, the article over at everythingsysadmin.com shows how you can use tcpdump to analyse what's happening over a network and potentially suss out any infected machines making too many arp who-has requests..

tcpdump -l -n arp | egrep 'arp who-has' | head -100 | awk '{ print $NF }' |sort | uniq -c | sort -n

Suspect ddos attack? Check the current connections

This command displays current IP connections to the tcp/udp service.

netstat -an | grep 'tcp\|udp' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n

PAM authentication against an LDAP server

Rather brief notes on getting LDAP auth running on a Debian server

Install dependencies

apt-get install libpam-ldap libnss-ldap

Debconf

LDAP server Uniform Resource Identifier: ldaps://10.179.43.21/
Distinguished name of the search base: dc=badwolf,dc=greenbeedigital,dc=com,dc=au
LDAP version to use: 3
Does the LDAP database require login? No
Special LDAP privileges for root? No
Make the configuration file readable/writeable by its owner only? No
Make local root Database admin. No
Does the LDAP database require login? No
Local crypt to use when changing passwords. crypt

/etc/libnss-ldap.conf modifications

# OpenLDAP SSL mechanism
# start_tls mechanism uses the normal LDAP port, LDAPS typically 636
ssl start_tls
ssl on

/etc/ldap/ldap.conf modifications

BASE dc=badwolf,dc=greenbeedigital,dc=com,dc=au
URI ldaps://10.179.43.21/
TLS_REQCERT never

/etc/nsswitch.conf modifications

passwd: files ldap
group: files ldap

/etc/pam.d/common-auth modifications

auth [success=1 default=ignore] pam_unix.so nullok_secure
auth required pam_ldap.so use_first_pass
auth required pam_permit.so

/etc/pam.d/common-account modifications

account sufficient pam_unix.so
account required pam_ldap.so

/etc/pam.d/common-session modifications

session required pam_unix.so
session required pam_mkhomedir.so skel=/etc/skel/ umask=0022

PHP

php: Strip characters out of a string to just leave numbers

Tags:

$string = "Test test total count 500000 bytes";
$string = preg_replace('#[^0-9]#','',strip_tags($string));
echo $string;

Perl

Convert timestamps in Nagios log

/var/log/nagios2/nagios.log prints computer timestamps that aren't that easy to read.

Run this instead:

perl -pe 's/(\d+)/localtime($1)/e' /var/log/nagios2/nagios.log
Or better yet put it in a script and just run it as 'nagioslog' or something...

Parsing HTML table into Excel spreadsheet

This script fetches a HTML page from the internet and parses the tables it finds in it, into an Excel spreadsheet.
This has been used for grabbing an AWstats index.html summary of sites and their bandwidth, and then parsing to Excel so one can tally up totals.

It's not perfect - I haven't used it in a while but from memory, it overwrites some rows due to being poorly coded :)

When the time comes that I need to use this again, I'll have another look at it.

#!/usr/bin/perl -w
use Spreadsheet::WriteExcel;
use HTML::TableExtract;
use LWP::Simple;
# Create a Table extraction
my $te = new HTML::TableExtract(gridmap=>1);
# Get the table out of my stats page
my $content = get("http://localhost/stats/index.html");
# Pass the data out of the table
$te->parse($content);
# Create a new Excel workbook
my $workbook = Spreadsheet::WriteExcel->new("totals.xls");
# Add a worksheet
my $worksheet = $workbook->add_worksheet();
# For each table, dump its parsed table rows into the worksheet
for my $ts ($te->table(1,0))
{
foreach my $row ($ts->rows)
{
$worksheet->write(0,0, $row, @{$row});
}
}

for my $ts ($te->table(1,1))
{
foreach my $row ($ts->rows)
{
$worksheet->write(1,0, $row, @{$row});
}
}

# Now add up the Total bandwidth
$worksheet->write_formula(2, 3, '=SUM(D1:D2)/1000000' );
#worksheet->write_formula(2, 3, '=SUM(D3/1000000)');

Perl script to check website with regex, alert if failure

Wrote this script today using the WWW::Curl::Easy example.

Background: Recently eaccelerator screwed up a dev server so that while Apache didn't die, php scripts weren't parsing, and I got no alerts.

This script parses a php script using curl, which contains a basic 'hello()' function that prints hello out.

The perl script checks the output for 'hello' and if it doesn't find it, it sends me an e-mail (it also sends me an SMS using our Clickatell account, but I'm not giving you the credentials, silly.)

#!/usr/bin/perl
#
# Checks a php script using curl and if there is a
# problem, e-mail me
#
use strict;
use WWW::Curl::Easy;
my $url = "http://localhost/test.php";
# Init the curl session
my $curl= WWW::Curl::Easy->new() or die "curl init failed!\n";
# Give curl the URL to use
$curl->setopt(CURLOPT_URL, $url);
# a subroutine which is called for each 'chunk' as the
# file is received.
sub body_callback {
my ($chunk,$context)=@_;
# add the chunk we received to the end of the array we've been given
push @{$context}, $chunk;
return length($chunk); # OK
}
# configure which subroutine to call when some data comes in
$curl->setopt(CURLOPT_WRITEFUNCTION, \&body_callback);
my @body;
# tell the subroutine which array to put the data into
$curl->setopt(CURLOPT_FILE, \@body);
if ($curl->perform() != 0) {
print "Failed ::".$curl->errbuf."\n";
};
my $output = join("",@body);
# Check if we got 'hello' out of the php script. If we did, ignore it
if ($output=~ m/hello/i) {
}
else {
#sms me, incidentally this is done with curl too, so I create another instance of WWW::Curl::Easy
my $alert_url = "http://the-clickatell-api-command-to-sms-me";
my $curl_alert= WWW::Curl::Easy->new() or die "curl init failed!\n";
$curl_alert->setopt(CURLOPT_URL, $alert_url);
$curl_alert->setopt(CURLOPT_WRITEFUNCTION, \&body_callback);
$curl_alert->setopt(CURLOPT_FILE, \@body);
if ($curl_alert->perform() != 0) {
print "Failed ::".$curl_alert->errbuf."\n";
};
# send me an e-mail now, using Sendmail
unless(open (MAIL, "|/usr/sbin/sendmail -t")) {
print "error.\n";
warn "Error starting sendmail: $!";
}
else {
print MAIL "From: web\@the-server.com\n";
print MAIL "To: miguel\@example.com\n";
print MAIL "Subject: PHP problem on the server\n\n";
print MAIL "The server has stopped parsing php! Panic! Panic!";
close(MAIL) || warn "Error closing mail: $!";
}
}

Perl script to send e-mail

#!/bin/perl

# Build an array of e-mail addresses to be Bcc'd to
my @bcc_addresses = (
'foo@bar.com',
'foo@bar2.com');

# The main recipient
my $to='foofoo@bar.com';

# Join the bcc addresses from the array, separate with comma
my $bcc = join(", ", @bcc_addresses);

# Where it's coming from
my $from='miguel@foobar.com';

# e-mail Subject
my $subject="Perl mail example";

# The e-mail content follows
my $out = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Nullam vestibulum dictum lectus.
Etiam at sapien. Donec fermentum dictum nisi. In ornare adipiscing massa.";

# Now let's fire up sendmail and push the data into it, then send
open(MAIL, "|/usr/sbin/sendmail -t");
print MAIL "To: $to\n";
print MAIL "Bcc: $bcc\n";
print MAIL "From: $from\n";
print MAIL "Subject: $subject\n";
print MAIL $out;

close(MAIL);

Pro Git

Nice guide to Git

progit.org

Quick and dirty guide to CVS

Tags:

proftpd log time and date mixed up

On my Etch servers, proftpd's logs in /var/log/proftpd/ are all mixed up. Just logging in, transferring a file, logging out, each action or series of actions were often being logged with mixed dates and times, never in order, and always wrong.

Turns out by default proftp is logging times in GMT or somesuch, I guess based on the client's system? To force proftpd to log by the server's local time, add these two lines to /etc/proftpd/proftpd.conf

TimesGMT off
SetEnv TZ :/etc/localtime

/etc/init.d/proftpd restart

Should be all good now.