Creative Commons License Sysadmin Cookbook by Dobrica Pavlinusic is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Croatia License.
Source code repository

acct

install

root@opl:/srv/sysadmin-cookbook/recepies/acct# apt-get -f install acct

lastcomm duration

acct/lastcomm-duration.pl
#!/usr/bin/perl

use warnings;
use strict;

use YAML;

my $too_long = shift @ARGV || 0.5; # s
my $stats;

open(my $lastcomm, '-|', 'lastcomm');
while(<$lastcomm>) {
	chomp;
	if ( m{^(\S+).+?(\S+)\s+(\S+)\s+(\d+\.\d+) secs} ) {
		my ( $command, $user, $tty, $duration ) = ( $1, $2, $3, $4 );
		$stats->{command}->{$command} += $duration;
		$stats->{user}->{$user} += $duration;
		$stats->{tty}->{$tty} += $duration;
		print "$_\n" if $duration > $too_long;
	} else {
		warn "# $_";
	}
}

foreach my $stat ( keys %$stats ) {
	print "\n$stat:\n";
	my $counter = $stats->{$stat};
	foreach my $name ( sort { $counter->{$b} <=> $counter->{$a} } keys %$counter ) {
		my $d = $counter->{$name};
		printf "%8.2f %s\n", $d, $name if $d > $too_long;
	}
}

amt

install

root@klin:/srv/sysadmin-cookbook/recepies/amt# apt-get install amtterm

amt openamt

heci

amt/openamt/1.heci.sh
#!/bin/sh

test -d heci || svn co https://openamt.svn.sourceforge.net/svnroot/openamt/heci/trunk heci
cd heci && make && modinfo ./src/heci.ko && insmod ./src/heci.ko heci_debug=1

lms

Index: src/LMEConnection.cpp
===================================================================
--- src/LMEConnection.cpp	(revision 213)
+++ src/LMEConnection.cpp	(working copy)
@@ -41,6 +41,8 @@
 #include <arpa/inet.h>
 #endif
 
+#include <pthread.h>
+
 #define HECI_BUFF_SIZE 0x1000
 #define HECI_IO_TIMEOUT 5000

lms

amt/openamt/2.lms.sh
#!/bin/sh

test -d lms || svn co https://openamt.svn.sourceforge.net/svnroot/openamt/lms/trunk lms

cd lms && patch -N -p0 < ../2.lms.diff
cd -

test -x lms/src/lms || ( cd lms && ./bootstrap.sh && ./configure --enable-debug && make )

serial console

amt/serial-console.sh
#!/bin/sh -x

# add AMT serial console to inittab

ttyS=`dmesg | grep ttyS | grep 0x | tail -1 | sed 's/^.*\(ttyS[0-9]\).*$/\1/'`

test -z "$ttyS" && echo "Can't find serial port in dmesg output" && exit

if ! grep $ttyS /etc/inittab | grep -v ^# ; then
	echo "Am:2345:respawn:/sbin/getty $ttyS 115200 vt100-nav" >> /etc/inittab
	init q
fi

ps ax | grep $ttyS | grep -v grep

grub=/boot/grub/menu.lst
tmp=/tmp/menu.lst

test -f $grub || exit

if ! grep '^# kopt=' $grub | grep console= ; then
	cat $grub | sed "s/^\(# kopt=.*\)$/\1 console=$ttyS,115200 console=tty0/" > $tmp
else
	cat $grub > $tmp
fi


if ! grep 'terminal *serial' $grub ; then
	port=`dmesg | grep ttyS | grep 0xe | sed 's/^.*\(0xe[0-9a-f]*\).*$/\1/'`
	cat $tmp | sed "s/\(### BEGIN AUTOMAGIC KERNELS LIST\)/serial --port=$port --speed=115200\nterminal serial\n\n\1/" >> $tmp.serial && mv $tmp.serial $tmp || exit
fi

if ! diff -urw $grub $tmp ; then
	mv $tmp $grub && update-grub
fi

apache2

deflate test

apache2/deflate-test.sh
#!/bin/sh

if [ -z "$1" ] ; then
	echo "Usage: $0 http://www.example.com/"
	exit 1
else
	url=$1
fi

time wget $url -O /tmp/foo
echo
time wget --header="Accept-Encoding: gzip" $url -O /tmp/foo.gz
echo

orig_size=`ls -al /tmp/foo    | awk '{ print $5 }'`
comp_size=`ls -al /tmp/foo.gz | awk '{ print $5 }'`

if [ $comp_size -lt $orig_size ] ; then
	echo "OK $comp_size < $orig_size";
else
	echo "ERROR: no visible compression benefits"
fi

#ls -al /tmp/foo /tmp/foo.gz

deflate

apache2/deflate.conf
# /etc/apache2/conf.d/deflate.conf

<IfModule mod_deflate.c>
	AddOutputFilterByType DEFLATE text/html text/plain text/xml

	SetOutputFilter DEFLATE
	SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ 			no-gzip dont-vary
	SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$	no-gzip dont-vary
	SetEnvIfNoCase Request_URI \.pdf$							no-gzip dont-vary

	BrowserMatch ^Mozilla/4 gzip-only-text/html
	BrowserMatch ^Mozilla/4\.0[678] no-gzip
	BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

	DeflateFilterNote Input input_info
	DeflateFilterNote Output output_info
	DeflateFilterNote Ratio ratio_info
	LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
	CustomLog /var/log/apache2/deflate.log deflate
</IfModule>

server status

apache2/server-status.conf
<IfModule mod_status.c>

# munin needs ExtededStatus
ExtendedStatus On

<Location /server-status>
	SetHandler server-status
	Order deny,allow
	Deny from all
#	Allow from all
	Allow from 127.0.0.1
	Allow from .ffzg.hr
</Location>

</IfModule>

bookreader

README

Internet Archive BookReader

http://openlibrary.org/dev/docs/bookreader

http://raj.blog.archive.org/2011/03/17/how-to-serve-ia-style-books-from-your-own-cluster/

http://projects.biodiversitylibrary.org/projects/clusteredfilesystem/wiki/Installing_bookreader

btrfs

install

root@t42:~# apt-get install btrfs-tools

create snapshot

root@klin:/srv/sysadmin-cookbook/recepies/btrfs# btrfsctl -S snapshot /btrfs
operation complete
Btrfs Btrfs v0.18

root@klin:/btrfs# btrfsctl -s /btrfs/snapshot/test /btrfs/212226/
operation complete
Btrfs Btrfs v0.18

README

http://blog.rot13.org/2009/05/btrfs_kernel_warning_about_alpha_state_is_there_for_a_reason.html

btrfs progs unstable checkinstall

btrfs/btrfs-progs-unstable-checkinstall.sh
#!/bin/sh -x

sudo apt-get install git-core uuid-dev checkinstall

test -e btrfs-progs-unstable || git clone git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-progs-unstable.git

cd btrfs-progs-unstable && git pull && make && \
	checkinstall --pkgname=btrfs-progs-unstable \
	--pkgversion=`grep BTRFS_BUILD_VERSION version.h | cut -d\" -f2 | sed 's/.* v//'`

btrfs snap expire

btrfs/btrfs-snap-expire.pl
#!/usr/bin/perl

use warnings;
use strict;

use DateTime;

my $to = DateTime->now->subtract( days => 3 )->truncate( to => 'day' );

foreach my $snap ( glob '/mnt/*/.snap/*' ) {
	if ( $snap =~ m{^(.+)/((\d\d\d\d)-(\d\d)-(\d\d)T(\d\d))$} ) {
		my $path = $1;
		my $name = $2;
		next if $6 == 0; # keep daily snapshot
		my $dt = DateTime->new( year => $3, month => $4, day => $5, hour => $6 );
		next if $dt > $to;
		warn "remove $snap\n";
		system "btrfsctl -D $name $path";
	} else {
		warn "SKIP $snap\n";
	}
}

mksnap

btrfs/mksnap
#!/bin/sh -x

mnt=$1
rootfs=$mnt/rootfs
snap=$mnt/.snap/
date=`date +%Y-%m-%dT%H`
btrfsctl=/usr/local/bin/btrfsctl

test -d $rootfs || exit 1
test -d $snap || mkdir $snap

test -d $snap/$date && $btrfsctl -D $date $snap

$btrfsctl -s $snap/$date $rootfs

pull snapshot backup

btrfs/pull-snapshot-backup.sh
#!/bin/sh -x

from=koha-hw.ffzg.hr
date=`date +%Y-%m-%d`
pool=btrfs
log=/var/log/

function rsync_veid() {
	rsync -ravHC --numeric-ids --delete $from:/mnt/vz-backup/private/$1/ /$pool/$1/ && btrfsctl -s /$pool/backup/$1@$date /btrfs/$1/
}

(
df -h /$pool
ssh $from 'sync && sync && lvcreate -s -L 10G -n vz-backup /dev/vg/vz && mount /dev/vg/vz-backup /mnt/vz-backup/' || exit
rsync_veid 212226
rsync_veid 212052
ssh $from 'umount /mnt/vz-backup/ && lvremove -f /dev/vg/vz-backup'
df -h /$pool
) | tee -a $log/$0.$date.log

compcache

download

compcache/0-download.sh
wget -nc http://compcache.googlecode.com/files/compcache-0.6.2.tar.gz

compile

compcache/1-compile.sh
apt-get install linux-headers-`uname -r`

tar xvf compcache-*.tar.gz
cd compcache-* && make
cd -

load modules

compcache/2-load-modules.sh
modprobe lzo_compress
modprobe lzo_decompress

insmod compcache-*/ramzswap.ko backing_swap=/dev/sdb2 memlimit_kb=512000

crm114

download

crm114/1-download.sh
sudo apt-get install crm114

cryo

checkout and compile

dpavlin@klin:/srv/sysadmin-cookbook/recepies/cryo$ sudo apt-get install git-core

dpavlin@klin:/srv/sysadmin-cookbook/recepies/cryo$ git clone git://git.sr71.net/~hallyn/cryodev.git

dpavlin@klin:/srv/sysadmin-cookbook/recepies/cryo$ cd cryodev/ && make

debian

apt sources

debian/apt-sources.sh
#!/bin/sh -x

path=/etc/apt/sources.list
tmp=/tmp/sources.list

cp $path $tmp

function append() {
	if ! grep "$1" $path ; then
		echo "$1" >> $tmp
	fi
}

append "deb http://debian.rot13.org binary/"
append "deb http://debian.pkgs.cpan.org/debian unstable main"
#append "deb http://debian.rot13.org/debian unstable main"

if ! diff -uw $path $tmp ; then
	cp $path $path.old && mv $tmp $path
	apt-get update
fi

debian cpan

README

http://debian.pkgs.cpan.org/

dell

install

apt-get install libsmbios-bin iselect

README

based on instructions from http://www.ducea.com/2007/08/27/dell-bios-firmware-updates-on-debian/

flash bios

dell/flash-bios.sh
#!/bin/sh -x

system_id=`getSystemId | grep 'System ID:' | cut -d: -f2 | sed 's/ //g'`
version=`getSystemId | grep 'BIOS' | cut -d: -f2 | sed 's/ //g'`

dir=linux.dell.com/repo/firmware/bios-hdrs

bios=`ls -d $dir/*$system_id*/bios.hdr | cut -d/ -f 5 | iselect -a -t "System $system_id BIOS $version"`

test -z "$bios" && exit

bios="$dir/$bios/bios.hdr"

dellBiosUpdate -i -f $bios || exit
dellBiosUpdate -t -f $bios || exit

echo -n "ENTER to program bios and reboot or CTRL+C to abort ";
read

modprobe dell_rbu
dellBiosUpdate -u -f $bios
reboot

make mirror

dell/make-mirror.sh
#!/bin/sh -x

system_id=`getSystemId | grep 'System ID:' | cut -d: -f2 | sed 's/ //g'`

test -z "$system_id" && exit

url=http://linux.dell.com/repo/firmware/bios-hdrs/

wget -q -O - $url | grep system_bios_ven_0x1028_dev_$system_id | sed -e 's/^.*href="//' -e 's/".*$//' -e "s|^|$url|" -e "s|$|bios.hdr|" | xargs wget -m

deploy cookbook

install subversion

root@opl:~# apt-get install -y subversion

append /root/.ssh/config

Host llin
	Hostname 10.60.0.81
	User dpavlin
	Port 22013

perms

root@koha-hw:~# chmod 600 /root/.ssh/config

checkout ../ssh/login without password/2.copy root identity

root@opl:~# cd /srv/ && svn co svn+ssh://llin/home/dpavlin/private/svn/sysadmin-cookbook/

setup PATH

# . setup-PATH
export PATH=/srv/sysadmin-cookbook/bin:$PATH

etherpuppet

install

apt-get install etherpuppet

README

EtherPuppet: http://www.secdev.org/projects/etherpuppet/
Firmware Linux: http://impactlinux.com/firmware-linux/

build arch

etherpuppet/build-arch.sh
#!/bin/sh -x

arch=$1
fwl=/virtual/fwl/

wget -m -nd -nH http://hg.secdev.org/etherpuppet/raw-file/tip/etherpuppet.c || exit

path="$fwl/cross-compiler-$arch"

if [ ! -e $path ] ; then
	cd $fwl || exit
	wget -m -nd -nH http://impactlinux.com/fwl/downloads/binaries/cross-compiler/host-i686/cross-compiler-$arch.tar.bz2 || exit
	tar xvfj cross-compiler-$arch.tar.bz2
	cd -
fi

PATH=$path/bin:$PATH
$arch-gcc -static -o etherpuppet-$arch etherpuppet.c

ls -al etherpuppet-$arch
file   etherpuppet-$arch

firefox

install

firefox/install.sh
#!/bin/sh -x

ls -d $HOME/.mozilla/firefox/*.*/ | xargs -i cp -v userChrome.css {}/chrome/

userChrome

window {
  font-size: 12px !important;
}

menubar, menubutton, menulist, menu, menuitem, textbox, toolbar, tab,
tree, tooltip
{
    font-size: 11px !important;
}

ganeti

gnt ill

ganeti/gnt-ill
#!/bin/sh -x

gnt-instance list -o name,status,oper_vcpus,oper_ram,disk_usage,pnode,snodes$*

ganeti migrate lxc

ganeti

ganeti/migrate-lxc/0-ganeti.sh
#master=`ssh root@10.60.0.112 gnt-cluster getmaster`
#if [ -z "$master" ] ; then
#	echo "Ganeti master not found"
#	exit 1
#fi

master=10.60.0.112

test -d ganeti || mkdir ganeti

ssh_master() {
	log=`basename $1`
	if [ "$1" == "gnt-instance" ] ; then
		ssh root@$master $*
	else
		ssh root@$master $* | tee ganeti/$log
	fi
}

host

ganeti/migrate-lxc/0-host.sh
export host_fqdn=narada.vbz.ffzg.hr
test -z "$host" && host=`echo $host_fqdn | cut -d. -f1`
export host
test -d $host || mkdir $host

ssh_host() {
	log=`basename $1`
	ssh root@$host $* | tee $host/$log
}

lxc

ganeti/migrate-lxc/0-lxc.sh
export lxc=stage
export lxc_vg=stage5

test -d lxc || mkdir lxc

ssh_lxc() {
	log=`basename $1`
	ssh root@$lxc $* | tee lxc/$log
}

inspect container ip

ganeti/migrate-lxc/1-inspect-container-ip.sh
#!/bin/sh -x

. ./0-host.sh

ssh $host /sbin/ifconfig | tee $host/ifconfig

lxc mount point

ganeti/migrate-lxc/2-lxc-mount-point.sh
#!/bin/sh -x

. ./0-host.sh
. ./0-lxc.sh

ssh_lxc() {
	log=`basename $1`
	ssh root@$lxc $* | tee $host/$log
}

ssh_lxc /etc/init.d/lxc-watchdog status
mnt=`cat $host/lxc-watchdog | grep ^$host | awk '{ print $4 }' | tee $host/mnt`
ssh_lxc df -h $mnt
size=`cat $host/df | grep /mnt/$host | awk '{ print $2 }' | tee $host/size`

ganeti root lvm

ganeti/migrate-lxc/3-ganeti-root-lvm.sh
#!/bin/sh -x

. ./0-host.sh
. ./0-ganeti.sh


ssh_master lvcreate --size `cat $host/size` --name $host ffzgvg
ssh_master lvextend --size 4G /dev/mapper/ffzgvg-$host

ssh_master parted -s /dev/mapper/ffzgvg-$host 'mklabel msdos mkpart primary 0% 100% set 1 boot on'

ssh_master mkfs.ext4 -L root /dev/mapper/ffzgvg-${host}p1

ssh_master mkdir /tmp/$host
ssh_master mount /dev/mapper/ffzgvg-${host}p1 /tmp/$host
ssh_master df -h /tmp/$host

lxc snapshot create

ganeti/migrate-lxc/4-lxc-snapshot-create.sh
#!/bin/sh -x

. ./0-host.sh
. ./0-lxc.sh

ssh_lxc lvcreate -s -L 1G -n ganeti-$host /dev/$lxc_vg/$host
ssh_lxc mkdir /tmp/ganeti-$host
ssh_lxc mount /dev/$lxc_vg/ganeti-$host /tmp/ganeti-$host
ssh_lxc df -h /tmp/ganeti-$host

lxc rsync snapshot

ganeti/migrate-lxc/5-lxc-rsync-snapshot.sh
#!/bin/sh -x

. ./0-host.sh
. ./0-lxc.sh
. ./0-ganeti.sh

ssh_lxc rsync -ravH --numeric-ids --sparse --delete --exclude /tmp --exclude /var/tmp /tmp/ganeti-$host/ $master:/tmp/$host/

lxc snapshot remove

ganeti/migrate-lxc/6-lxc-snapshot-remove.sh
#!/bin/sh -x

. ./0-host.sh
. ./0-lxc.sh

ssh_lxc umount /tmp/ganeti-$host
ssh_lxc dmsetup remove $lxc_vg-ganeti--$host-cow
ssh_lxc dmsetup remove $lxc_vg-ganeti--$host
ssh_lxc lvremove /dev/$lxc_vg/ganeti-$host

lxc stop container

ganeti/migrate-lxc/7-lxc-stop-container.sh
#!/bin/sh -x

. ./0-host.sh
. ./0-lxc.sh
. ./0-ganeti.sh

ssh_lxc /etc/init.d/lxc-watchdog stop $host

ssh_lxc rm -v /var/lib/lxc/$host/on_boot

ssh_lxc rsync -ravH --numeric-ids --sparse --delete --exclude /tmp --exclude /var/tmp /mnt/$host/ $master:/tmp/$host/

A ganeti fix root

ganeti/migrate-lxc/A-ganeti-fix-root.sh
#!/bin/sh -x

. ./0-host.sh
. ./0-ganeti.sh

ssh_master ls -d /tmp/$host/rootfs/boot > $host/rootfs_boot
if [ -s $host/rootfs_boot ] ; then
	ssh_master mv /tmp/$host/rootfs/* /tmp/$host/
	ssh_master mv /tmp/$host/rootfs/.?* /tmp/$host/
	ssh_master rmdir /tmp/$host/rootfs
fi

ssh_master mkdir -p /tmp/$host/lib/modules
ssh_master cp -ra /lib/modules/3.2.0-4-amd64 /tmp/$host/lib/modules

ssh_master chroot /tmp/$host apt-get install --reinstall -y initscripts acpid

B ganeti network interfaces

ganeti/migrate-lxc/B-ganeti-network-interfaces.sh
#!/bin/sh -xe

. ./0-host.sh
. ./0-lxc.sh
. ./0-ganeti.sh

ssh_lxc cat /var/lib/lxc/$host/config | grep ipv4 | tee $host/ipv4
public_ip=`grep 193.198 $host/ipv4 | cut -d= -f2 | cut -d/ -f1 | sed 's/ *//'`
local_ip=` grep 10.60   $host/ipv4 | cut -d= -f2 | cut -d/ -f1 | sed 's/ *//'`

tee /tmp/network-interfaces-$host << __INTERFACES__
auto eth0 eth1 lo

iface lo inet loopback

iface eth0 inet static
	address $public_ip
	netmask 255.255.254.0
	gateway 193.198.212.1

iface eth1 inet static
	address $local_ip
	netmask 255.255.254.0
__INTERFACES__

# this will backup file on original machine which is still running!
ping -c 1 $host && ssh_master chroot /tmp/$host bak add,commit /etc/network/interfaces

scp /tmp/network-interfaces-$host root@$master:/tmp/

ssh_master mv -v /tmp/network-interfaces-$host /tmp/$host/etc/network/interfaces

C ganeti swap

ganeti/migrate-lxc/C-ganeti-swap.sh
#!/bin/sh -xe

. ./0-host.sh
. ./0-ganeti.sh

ssh_master lvcreate -L 1G -n $host-swap ffzgvg

ssh_master parted -s /dev/mapper/ffzgvg-$host--swap 'mklabel msdos mkpartfs primary linux-swap 0% 100%'

ssh_master dmsetup remove ffzgvg-${host}--swapp1

D ganeti create instance

ganeti/migrate-lxc/D-ganeti-create-instance.sh
#!/bin/sh -xe

. ./0-host.sh
. ./0-lxc.sh
. ./0-ganeti.sh

ssh_master umount /tmp/$host

ssh_master dmsetup remove ffzgvg-${host}p1

ssh_master gnt-instance add -H kvm:kernel_path=/boot/vmlinuz-3.2-kvmU,initrd_path=/boot/initrd.img-3.2-kvmU -B maxmem=1G,minmem=1G,vcpus=2 -t plain -n vmh12 -o debootstrap+default --disk 0:adopt=$host --disk 1:adopt=$host-swap --no-start --no-ip-check --no-name-check $host_fqdn

E ganeti network local

ganeti/migrate-lxc/E-ganeti-network-local.sh
#!/bin/sh -xe

. ./0-host.sh
. ./0-ganeti.sh

ssh_master gnt-instance modify --net add:link=br0060 $host_fqdn

F ganeti drdb

ganeti/migrate-lxc/F-ganeti-drdb.sh
#!/bin/sh -xe

. ./0-host.sh
. ./0-ganeti.sh

ssh_master gnt-instance modify -t drbd -n box01 $host_fqdn

G ganeti start

ganeti/migrate-lxc/G-ganeti-start.sh
#!/bin/sh -xe

. ./0-host.sh
. ./0-ganeti.sh

ssh_master gnt-instance start $host_fqdn

H host console

ganeti/migrate-lxc/H-host-console.sh
#!/bin/sh -xe

. ./0-host.sh
. ./0-ganeti.sh

ssh_host ps ax | grep getty | tee $host/getty
ssh_host cat /proc/cmdline  | tee $host/cmdline

cat $host/getty | grep ttyS0   > $host/serial_console
cat $host/getty | grep console > $host/console

tail $host/*console

#pid=`awk '{ print $1 }' $host/console`
#ssh_host kill $pid

ssh_host cat /etc/inittab > $host/inittab
grep -v ^# $host/inittab | grep console || (
	echo "1:2345:respawn:/sbin/getty 38400 console" | tee -a $host/inittab
	rsync $host/inittab root@$host:/etc/
	ssh_host bak diff /etc/inittab
	ssh_host init q
	ssh_host tail -1 /var/log/daemon.log
)

I acpi restart

ganeti/migrate-lxc/I-acpi-restart.sh
#!/bin/sh -x

. ./0-host.sh

#ssh_host apt-get install --reinstall -y initscripts acpid
ssh_host /etc/init.d/acpid restart
ssh_host lsmod | grep button
ssh_host tail -2 /var/log/messages

gearman

install

gearman/0.install.sh
apt-get install libgearman-client-perl

gearman

gearman/gearman.pl
#!/usr/bin/perl

use warnings;
use strict;

use Data::Dump qw(dump);
use Getopt::Long;
use Gearman::Worker;

my $host = '10.60.0.244:4730';
my $function = 'test';

GetOptions(
	'host' => \$host,
	'function' => \$function,
) || die $!;


my $worker = Gearman::Worker->new;
$worker->job_servers( $host );
$worker->register_function( $function => sub {
	my $job = $_[0];
	my $arg = $_[0]->arg;
	warn "# job ",dump($job);
});
warn "# worker ",dump($worker);
$worker->work while 1;

=for client

my $client = Gearman::Client->new;
$client->job_servers($host);

# running a single task
my $result_ref = $client->do_task("add", "1+2");
print "1 + 2 = $$result_ref\n";

# waiting on a set of tasks in parallel
my $taskset = $client->new_task_set;
$taskset->add_task( "add" => "1+2", {
	on_complete => sub { ... }
});

$taskset->add_task( "divide" => "5/0", {
	on_fail => sub { print "divide by zero error!\n"; },
});
$taskset->wait;

=cut

grep_logs

gearman/grep_logs.sh
#!/bin/sh -x

# echo 'error' | gearman -f grep_logs

if [ -z "$1" ] ; then
	hostname=`hostname`
	exec /srv/gearmand/bin/gearman -h 10.60.0.244 -w -f grep_$hostname $0 $hostname
fi

read pattern
grep $pattern /var/log/*.log

git

install

sudo apt-get install git-core git-svn

authors file

dpavlin = Dobrica Pavlinusic <dpavlin@rot13.org>

git checkout svn

git/git-checkout-svn.sh
#!/bin/sh -x

repository=svn+ssh://llin/home/dpavlin/private/svn/Frey

git svn clone $repository -T trunk -b branches \
	--authors-file /srv/sysadmin-cookbook/recepies/git/authors-file
cd Frey/
git branch -r

git revert trunk

git/git-revert-trunk.sh
git reset --hard remotes/trunk

git gitweb

install

sudo apt-get install gitweb

gps

install

gps/0.install.sh
apt-get install gpsd gpsd-clients

append /etc/bluetooth/rfcomm

rfcomm0 {
	bind yes;
	device 11:22:33:44:55:66;
	channel	1;
	comment "GPS";
}

modify /etc/default/gpsd

# Default settings for gpsd.
# Please do not edit this file directly - use `dpkg-reconfigure gpsd' to
# change the options.
START_DAEMON="true"
GPSD_OPTIONS=""
DEVICES="/dev/rfcomm0"
USBAUTO="true"
GPSD_SOCKET="/var/run/gpsd.sock"

gstreamer

record screencast

gstreamer/record-screencast.sh
gst-launch-0.10 -v ximagesrc ! video/x-raw-rgb,framerate=5/1 ! videorate ! ffmpegcolorspace ! videoscale method=1 ! timeoverlay ! theoraenc ! oggmux ! filesink location=screencast.ogg

test card

gstreamer/test-card.sh
gst-launch-0.10 -v videotestsrc ! video/x-raw-rgb ! ffmpegcolorspace ! timeoverlay ! theoraenc ! oggmux ! filesink location=testcard.ogg

ipmi

install

ipmi/0.install.sh
sudo apt-get install ipmitool

append /etc/modules

ipmi_devintf
ipmi_si

IPMIView sol

ipmi/IPMIView-sol.sh
#!/bin/sh -x

ip=`cat IPMIView.properties | cut -d= -f2 | cut -d: -f1`
ipmitool -I lanplus -H $ip -U ADMIN sol activate

iptables

iptables tcp proxy

iptables/iptables-tcp-proxy.sh
#!/bin/sh

# http://www.debian-administration.org/articles/595

test -z "$1" -o -z "$2" -o -z "$3" -o -z "$4" && echo "$0 LOCAL_IP LOCAL_PORT REMOTE_IP REMOTE_PORT" && exit 1

IPTABLES=/sbin/iptables

echo 'echo 1 > /proc/sys/net/ipv4/ip_forward'

echo $IPTABLES -t nat -A PREROUTING --dst $1 -p tcp --dport $2 -j DNAT --to-destination $3:$4
echo $IPTABLES -t nat -A POSTROUTING --dst $3 -p tcp --dport $4 -j SNAT --to-source $1
echo $IPTABLES -t nat -A OUTPUT --dst $1 -p tcp --dport $2 -j DNAT --to-destination $3:$4

kvm

create image

root@klin:/btrfs# kvm-img create -f qcow2 212052.cqow2 50G
Formatting '212052.cqow2', fmt=qcow2, size=52428800 kB

mount image

root@klin:/btrfs# kvm-nbd --port 10000 212052.qcow2 &

root@klin:/btrfs# nbd-client localhost 10000 /dev/nbd0
Negotiation: ..size = 52428800KB
bs=1024, sz=52428800

root@klin:/btrfs# mount /dev/nbd0p1 /mnt/tmp
root@klin:/btrfs# df /mnt/tmp
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/nbd0p1           51605436     53064  48930968   1% /mnt/tmp

image device

kvm/image-device.sh
#!/bin/sh -x

test -e $1 || ( echo echo "Usage: $0 image.qcow2" ; exit 1 )

image=$1

test -e $image.pid && kill `cat $image.pid` 

running=`ps ax | grep kvm-nbd | grep -v grep | wc -l`
port=`expr 10000 + $running`

kvm-nbd --port $port $image &
echo $! > $image.pid

sleep 1

nbd-client localhost $port /dev/nbd$running || exit

fdisk -l /dev/nbd$running

fdisk -l /dev/nbd1 | grep ^/dev/nbd | cut -d" " -f1 | sed 's!/dev/!!' | xargs -i sh -x -c "mkdir -p /mnt/$image/{} ; mount -v /dev/{} /mnt/$image/{}"

df -h /mnt/$image/*

image stop

kvm/image-stop.sh
#!/bin/sh

kill -9 `cat $1.pid || cat $1`

kvm windows drivers

build iso

kvm/windows-drivers/build-iso.sh
#!/bin/sh

sudo apt-get install mkisofs

wget -m -nd -nH http://sourceforge.net/projects/kvm/files/kvm-guest-drivers-windows/2/kvm-guest-drivers-windows-2.zip/download
unzip kvm-guest-drivers-windows-2.zip -d iso
mkisofs -J -R -o kvm-guest-drivers-windows-2.iso iso/

libvirt

install

libvirt/0.install.sh
#!/bin/sh -x

apt-get install libvirt-bin qemu-kvm virtinst virt-top

linux kernel

panic reboot

linux-kernel/panic-reboot.sh
#!/bin/sh -x

cat /proc/sys/kernel/panic
echo 10 > /proc/sys/kernel/panic

lvm

create lvm snapshot

root@koha-hw:~# lvcreate -s -L 10G -n vz-backup /dev/vg/vz
  Logical volume "vz-backup" created

root@koha-hw:~# test -d /mnt/vz-backup || mkdir /mnt/vz-backup

root@koha-hw:~# mount /dev/vg/vz-backup /mnt/vz-backup/

root@koha-hw:~# df /mnt/vz-backup/
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/mapper/vg-vz--backup
                     103212320  76571060  26641260  75% /mnt/vz-backup

lvcreate

# LV_NAME=zfs-200
# SIZE=200G

root@opl:/srv/sysadmin-cookbook/recepies/lvm# lvcreate -n zfs-200 -L 200G /dev/raid0
  Logical volume "zfs-200" created
root@opl:/srv/sysadmin-cookbook/recepies/lvm# lvdisplay /dev/raid0/zfs-200
  --- Logical volume ---
  LV Name                /dev/raid0/zfs-200
  VG Name                raid0
  LV UUID                Ms1SXp-mHKC-6wBt-KjcR-JS18-GoTZ-n0APy0
  LV Write Access        read/write
  LV Status              available
  # open                 0
  LV Size                200.00 GB
  Current LE             51200
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:2

lvdisplay kb

lvdisplay --units k $*

remove lvm snapshot

root@koha-hw:~# umount /dev/vg/vz-backup

root@koha-hw:~# lvremove /dev/vg/vz-backup 
Do you really want to remove active logical volume "vz-backup"? [y/n]: y
  Logical volume "vz-backup" successfully removed

lxc

install

lxc/0.install
sudo apt-get install lxc bridge-utils

cp lxc-debian /usr/local/sbin/lxc-debian && chmod 700 /usr/local/sbin/lxc-debian

append /etc/fstab

cgroup		/cgroup				cgroup	rw		0	0

append /etc/network/interfaces

#allow-hotplug eth0

# man bridge-utils-interfaces
auto br0
iface br0 inet static
	bridge_ports eth0
	bridge_fd 0
	address 10.60.0.92
	netmask 255.255.254.0
	gateway 10.60.0.1

append /etc/inittab

# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin
1:2345:respawn:/sbin/getty 38400 console
c1:12345:respawn:/sbin/getty 38400 tty1 linux
c2:12345:respawn:/sbin/getty 38400 tty2 linux
c3:12345:respawn:/sbin/getty 38400 tty3 linux
c4:12345:respawn:/sbin/getty 38400 tty4 linux

README

* http://lxc.sourceforge.net/
* http://www.ibm.com/developerworks/linux/library/l-lxc-containers/

create bridge

lxc/create-bridge.sh
#!/bin/sh -x

brctl addbr br0
brctl setfd br0 0

ifconfig br0 172.20.0.1 netmask 255.255.255.0

brctl addif br0 eth0

brctl show br0
ifconfig br0

lxc kvm

install

lxc/kvm/00-install.sh
#!/bin/sh -x

sudo apt-get install genext2fs e2fsprogs libc6-amd64

lxc kvm 01 setup

create kvm root

lxc/kvm/01-setup/01-create-kvm-root.sh
#!/bin/sh

if [ -z "$SUDO_UID" ] ; then
	echo "Run this script with: sudo $0"
	exit 1
fi

MIRROR=ftp.debian.org/debian
dpkg -l apt-cacher-ng >/dev/null && MIRROR="127.0.0.1:3142/$MIRROR"

echo "Using $MIRROR"

debootstrap --include=psmisc,less,strace,bzip2,make,gcc,libc6-dev,dropbear,lxc,libc6-amd64,file squeeze squeeze http://$MIRROR

echo -e "root\nroot" | chroot squeeze passwd
echo -e "auto lo\niface lo inet loopback\nauto eth0\niface eth0 inet dhcp" \
  > squeeze/etc/network/interfaces
ln -sf vimrc squeeze/etc/vimrc.tiny
rm -f squeeze/etc/udev/rules.d/70-persistent-net.rules
echo kvm > squeeze/etc/hostname
echo cgroup /mnt/cgroup cgroup defaults >> squeeze/etc/fstab
mkdir -p squeeze/mnt/cgroup

BLOCKS=$(((1024*$(du -m -s squeeze | awk '{print $1}')*12)/10))
genext2fs -z -d squeeze -b $BLOCKS -i 1024 squeeze.ext3
resize2fs squeeze.ext3 1G
tune2fs -j -c 0 -i 0 squeeze.ext3

chown $SUDO_UID:$SUDO_GID squeeze.ext3

build kvm kernel

lxc/kvm/01-setup/02-build-kvm-kernel.sh
#!/bin/sh -xe

wget -nc http://lxc.sourceforge.net/patches/linux/2.6.38/2.6.38.2-lxc1/patches.tar.gz
tar xvf patches.tar.gz

wget -nc ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.38.2.tar.gz
tar xvf linux-2.6.38.2.tar.gz


cd linux-2.6.38.2

ls ../patches/*.patch | xargs -i sh -cx "patch -p1 < {}"


# Start with the default configuration
make defconfig

cat >> .config << EOF
# Add /dev/hda for qemu/kvm
CONFIG_IDE=y
CONFIG_IDE_GD=y
CONFIG_IDE_GD_ATA=y
CONFIG_BLK_DEV_PIIX=y

# Switch on all container functionality
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_MEM_RES_CTLR=y
CONFIG_CGROUP_PERF=y

CONFIG_BLK_CGROUP=y
CONFIG_DEBUG_BLK_CGROUP=y
CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_BLK_DEV_THROTTLING=y

CONFIG_NET_CLS_CGROUP=y

# Virtual network devices
CONFIG_VETH=y
CONFIG_MACVLAN=y
CONFIG_VLAN_8021Q=y
EOF
yes '' | make oldconfig

# Build kernel (counting CPUS to supply appropriate -j to make)

CPUS=$(grep "^processor" /proc/cpuinfo | wc -l)
make -j $CPUS

boot kvm

lxc/kvm/01-setup/03-boot-kvm.sh
#!/bin/sh -x

kernel=$( ls -d linux-2.6.* | grep -v gz | tail -1 )

kvm -m 1024 -kernel $kernel/arch/x86/boot/bzImage -no-reboot -hda squeeze.ext3 \
  -append "root=/dev/hda rw panic=1" -net nic,model=e1000 -net user \
  -redir tcp:9876::22

lxc kvm 02 network

add tap

lxc/kvm/02-network/01-add-tap.sh
#!/bin/sh -x

# FIXME change username
tunctl -u dpavlin -t kvm0
ifconfig kvm0 192.168.254.1 netmask 255.255.255.0
echo 1 > /proc/sys/net/ipv4/ip_forward

# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

kvm two ethernets

lxc/kvm/02-network/02-kvm-two-ethernets.sh
#!/bin/sh -x

kvm -m 1024 -kernel ../01-setup/linux-2.6.*/arch/x86/boot/bzImage -no-reboot \
	-hda ../01-setup/squeeze.ext3 -append "root=/dev/hda rw panic=1" \
	-net nic,model=e1000 -net user -redir tcp:9876::22 \
	-net nic,model=e1000 -net tap,ifname=kvm0,script=no

lxc kvm 10 cgroup blkio

disk speed

lxc/kvm/10-cgroup-blkio/disk-speed.sh
#!/bin/sh -xe

lxc-ls | xargs -i sh -c "lxc-stop -n {} ; lxc-destroy -n {}"

echo "lxc.network.type = empty" > blkio.conf

PATH=$(pwd):$PATH lxc-create -f blkio.conf -t busybox -n disk1
PATH=$(pwd):$PATH lxc-create -f blkio.conf -t busybox -n disk2
PATH=$(pwd):$PATH lxc-create -f blkio.conf -t busybox -n disk3

lxc-ls | xargs -i dd if=/dev/zero of=/var/lib/lxc/{}/rootfs/tmp/zero bs=1M count=100

cat > /tmp/speed.sh <<EOF
#!/bin/sh
while true ; do
	sync ; echo 3 > /proc/sys/vm/drop_caches
	dd if=/tmp/zero of=/dev/null 2>&1
done | grep MB
EOF

chmod +x /tmp/speed.sh

lxc-ls | xargs -i cp /tmp/speed.sh /var/lib/lxc/{}/rootfs/tmp/speed.sh

lxc-ls | xargs -i lxc-start -d -n {}

README

this is set of scripts which follow instructions at

http://www.landley.net/lxc/

lxc debian

lxc/lxc-debian
#!/bin/bash

#
# lxc: linux Container library

apt-get install debootstrap

# Authors:
# Daniel Lezcano <daniel.lezcano@free.fr>

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

configure_debian()
{
    rootfs=$1
    hostname=$2

    # configure the inittab
    cat <<EOF > $rootfs/etc/inittab
id:3:initdefault:
si::sysinit:/etc/init.d/rcS
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin
1:2345:respawn:/sbin/getty 38400 console
c1:12345:respawn:/sbin/getty 38400 tty1 linux
c2:12345:respawn:/sbin/getty 38400 tty2 linux
c3:12345:respawn:/sbin/getty 38400 tty3 linux
c4:12345:respawn:/sbin/getty 38400 tty4 linux
EOF

    # disable selinux in debian
    mkdir -p $rootfs/selinux
    echo 0 > $rootfs/selinux/enforce

    # by default setup root password with no password
    cat <<EOF > $rootfs/etc/ssh/sshd_config
Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
UsePrivilegeSeparation yes
KeyRegenerationInterval 3600
ServerKeyBits 768
SyslogFacility AUTH
LogLevel INFO
LoginGraceTime 120
PermitRootLogin yes
StrictModes yes
RSAAuthentication yes
PubkeyAuthentication yes
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PermitEmptyPasswords yes
ChallengeResponseAuthentication no
EOF

    # configure the network using the dhcp
    cat <<EOF > $rootfs/etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
EOF

    # set the hostname
    cat <<EOF > $rootfs/etc/hostname
$hostname
EOF

    # reconfigure some services
    chroot $rootfs /usr/sbin/dpkg-reconfigure locales

    # remove pointless services in a container
    chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove
    chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove
    chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove
}

arch=$(arch)

download_debian()
{
    packages=\
ifupdown,\
locales,\
libui-dialog-perl,\
dialog,\
netbase,\
net-tools,\
iproute,\
openssh-server

    cache=$1

    # check the mini debian was not already downloaded
    mkdir -p "$cache/partial-$arch"
    if [ $? -ne 0 ]; then
	echo "Failed to create '$cache/partial-$arch' directory"
	return 1
    fi

    # download a mini debian into a cache
    echo "Downloading debian minimal ..."
    debootstrap --verbose --variant=minbase --arch=$arch \
	--include $packages \
	wheezy $cache/partial-$arch http://ftp.debian.org/debian
    if [ $? -ne 0 ]; then
	echo "Failed to download the rootfs, aborting."
	return 1
    fi

    mv "$1/partial-$arch" "$1/rootfs-$arch"
    echo "Download complete."

    return 0
}

copy_debian()
{
    cache=$1
    rootfs=$3

    # make a local copy of the minidebian
    echo -n "Copying rootfs to $rootfs..."
    cp -a $cache/rootfs-$arch $rootfs || return 1
    return 0
}

install_debian()
{
    cache="/var/cache/lxc/debian"
    rootfs=$1
    mkdir -p /var/lock/subsys/
    (
	flock -n -x 200
	if [ $? -ne 0 ]; then
	    echo "Cache repository is busy."
	    return 1
	fi

	if [ "$arch" == "x86_64" ]; then
	    arch=amd64
	fi

	if [ "$arch" == "i686" ]; then
	    arch=i386
	fi

	echo "Checking cache download in $cache/rootfs-$arch ... "
	if [ ! -e "$cache/rootfs-$arch" ]; then
	    download_debian $cache $arch
	    if [ $? -ne 0 ]; then
		echo "Failed to download 'debian base'"
		return 1
	    fi
	fi

	copy_debian $cache $arch $rootfs
	if [ $? -ne 0 ]; then
	    echo "Failed to copy rootfs"
	    return 1
	fi

	return 0

	) 200>/var/lock/subsys/lxc

    return $?
}

copy_configuration()
{
    path=$1
    rootfs=$2
    name=$3

    cat <<EOF >> $path/config
lxc.tty = 4
lxc.pts = 1024
lxc.rootfs = $rootfs
lxc.cgroup.devices.deny = a
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
EOF

    if [ $? -ne 0 ]; then
	echo "Failed to add configuration"
	return 1
    fi

    return 0
}

clean()
{
    cache="/var/cache/lxc/debian"

    if [ ! -e $cache ]; then
	exit 0
    fi

    # lock, so we won't purge while someone is creating a repository
    (
	flock -n -x 200 
	if [ $? != 0 ]; then
	    echo "Cache repository is busy."
	    exit 1
	fi

	echo -n "Purging the download cache..."
	rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
	exit 0

    ) 200>/var/lock/subsys/lxc
}

usage()
{
    cat <<EOF
$1 -h|--help -p|--path=<path> -a|--arch=stable --clean
EOF
    return 0
}

options=$(getopt -o hp:n:ca: -l help,path:,name:,clean,arch: -- "$@")
if [ $? -ne 0 ]; then
        usage $(basename $0)
	exit 1
fi
eval set -- "$options"

while true
do
    case "$1" in
        -h|--help)      usage $0 && exit 0;;
        -p|--path)      path=$2; shift 2;;
		-n|--name)      name=$2; shift 2;;
		-c|--clean)     clean=$2; shift 2;;
		-a|--arch)		arch=$2; shift 2;;
        --)             shift 1; break ;;
        *)              break ;;
    esac
done

if [ ! -z "$clean" -a -z "$path" ]; then
    clean || exit 1
    exit 0
fi

type debootstrap
if [ $? -ne 0 ]; then
    echo "'debootstrap' command is missing"
    exit 1
fi

if [ -z "$path" ]; then
    echo "'path' parameter is required"
    exit 1
fi

if [ "$(id -u)" != "0" ]; then
    echo "This script should be run as 'root'"
    exit 1
fi 

rootfs=$path/rootfs

install_debian $rootfs
if [ $? -ne 0 ]; then
    echo "failed to install debian"
    exit 1
fi

configure_debian $rootfs $name
if [ $? -ne 0 ]; then
    echo "failed to configure debian for a container"
    exit 1
fi

copy_configuration $path $rootfs
if [ $? -ne 0 ]; then
    echo "failed write configuration file"
    exit 1
fi

if [ ! -z $clean ]; then
    clean || exit 1
    exit 0
fi

lxc watchdog

lxc/lxc-watchdog.sh
#! /bin/sh
### BEGIN INIT INFO
# Provides:          lxc-watchdog
# Required-Start:    $remote_fs $named $network $time
# Required-Stop:     $remote_fs $named $network
# Required-Start:    
# Required-Stop:     
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Manage Linux Containers startup/shutdown
# Description:       Uses clever inotify hack to monitor container's
#                    halt/reboot events watching /var/run/utmp
### END INIT INFO

# Author: Dobrica Pavlinusic <dpavlin@rot13.org>
#
# based on Tony Risinger post to lxc-users mailing list
# http://www.mail-archive.com/lxc-users@lists.sourceforge.net/msg00074.html
#
# Install with:
# ln -sf /srv/sysadmin-cookbook/recepies/lxc/lxc-watchdog.sh /etc/init.d/lxc-watchdog
# update-rc.d lxc-watchdog defaults


which inotifywait >/dev/null || apt-get install inotify-tools


lxc_exists() {
	name=$1

	if [ ! -e /var/lib/lxc/$name/config ] ; then
		echo "Usage: $0 name"
		lxc_status
		exit 1
	fi
}


lxc_rootfs() {
	grep '^ *lxc\.rootfs *=' "/var/lib/lxc/$1/config" | cut -d= -f2 | sed 's/^ *//'
}

lxc_hostname() {
	inside=`cat $(lxc_rootfs $1)/etc/hostname`
	config=`grep lxc.utsname /var/lib/lxc/$name/config | cut -d= -f2`
	echo "$config [$inside]";
}

lxc_ip() {
	( grep lxc.network.ipv4 /var/lib/lxc/$name/config | grep -v '^#' | cut -d= -f2 || \
	grep address $(lxc_rootfs $name)/etc/network/interfaces | grep -v '^#' | sed 's/.*address //' ) | \
	head -1 | \
	sed -e 's/ *//g' -e 's/\/.*$//'
}

lxc_status() {
	( find /var/lib/lxc/ -name "config" | cut -d/ -f5 | sort -u | while read name ; do
		status=`lxc-info -n $name 2>/dev/null | grep state: | cut -d: -f2`     # 0.7.5
		test -z "$status" && status=`lxc-info -n $name | sed -e 's/^.* is //'` # 0.7.2
		boot="-"
		test -s /var/lib/lxc/$name/on_boot && boot="boot"
		echo "$name $status $boot $(lxc_rootfs $name) $(lxc_ip $name) $(lxc_hostname $name)"
	done ) | column -t
}


cleanup_init_scripts() {
	rootfs=$(lxc_rootfs $1)

	ls \
		$rootfs/etc/rc?.d/*checkroot* \
		$rootfs/etc/rc?.d/*umountfs \
		$rootfs/etc/rc?.d/*umountroot \
		$rootfs/etc/rc?.d/*hwclock* \
		$rootfs/etc/rc?.d/*udev* \
		$rootfs/etc/rc?.d/*checkfs* \
	2>/dev/null | xargs -i rm -v {}

	echo $1 > $rootfs/etc/hostname
	grep $1 $rootfs/etc/hosts || echo "$(lxc_ip $1) $1" >> $rootfs/etc/hosts
}


setup_inittab() {
	rootfs=$(lxc_rootfs $1)
	remove=$2
	add=$3

	# let container respond to kill -SIGPWR
	inittab=$rootfs/etc/inittab
	if test -e $inittab && ! grep "$add" ${inittab} >/dev/null ; then
		grep -v "$remove" ${inittab} > ${inittab}.new
		echo $add >> ${inittab}.new
		mv ${inittab}.new ${inittab}
		echo "$inittab modified with $add"
	fi
}


lxc_log() {
	echo `date +%Y-%m-%dT%H:%M:%S` $*
}


lxc_kill() {
	name=$1
	sig=$2

	ver=`lxc-version | cut -d: -f2 | sed 's/\.//g'`
	opts=''
	test $ver -ge 075 && opts='--'

	init_pid=`lxc-ps $opts -C init -o pid | grep "^$name" | cut -d" " -f2-`
	if [ -z "$init_pid" ] ; then
		lxc-info -n $name
		exit 1
	fi
	lxc_log "$name kill $sig $init_pid"
	/bin/kill $sig $init_pid
}

lxc_stop() {
	lxc_log "$name stop"
	lxc_kill $name -SIGPWR
	lxc-wait -n $name -s STOPPED
	lxc_log "$name stoped"
#	rm -f /var/lib/lxc/${name}/on_boot
}


lxc_start() {
	name=$1
	rootfs=$(lxc_rootfs $1)

	if [ ! -e $rootfs ] ; then
		echo "ERROR $name rootfs $rootfs not found"
		return
	fi

	if ! lxc-info -n $name | grep RUNNING ; then
		lxc_log "$name start"
		dev=`df -P $rootfs | tail -1 | cut -d" " -f1`
		mount $dev -o remount,rw # fix debian upgrade which remounts dir ro
		lxc-start -n $name -o /tmp/${name}.log -d
		lxc-wait  -n $name -s RUNNING
		lxc-info  -n $name
		test -f /var/lib/lxc/${name}/on_boot || echo $name > /var/lib/lxc/${name}/on_boot
	fi
}

lxc_watchdog() {
name=$1
cgroup=$(mount -t cgroup | awk '{ print $3 }')
test -d "$cgroup/lxc/$1" && cgroup="$cgroup/lxc"
rootfs=$(lxc_rootfs $1)
run=$rootfs/var/run
test -L $run && run=$rootfs/`readlink $run` # recent Debian have symlink to /run
cd $run || echo "can't cd watchdog into $run"

while true; do
	tasks=`wc -l < $cgroup/${name}/tasks`
	stop_on=1 # init
	sulogins=`lxc-ps --name $name | grep sulogin | wc -l`
	if [ "$sulogins" -gt 0 ] ; then
		stop_on=`expr $stop_on + $sulogins`
	fi

	test -z "$tasks" && exit 1
	if [ "$tasks" -eq $stop_on ]; then

		runlevel="$(runlevel utmp)"
		lxc_log "$name runlevel $runlevel"

		case $runlevel in
		N*)
			# nothing for new boot state
		;;
		??0|unknown)
			lxc_log "$name halt"
			lxc-stop -n "${name}"
			lxc-wait -n ${name} -s STOPPED
			break
		;;
		??6)
			lxc_log "$name reboot";
			lxc-stop -n ${name}
			lxc-wait -n ${name} -s STOPPED
			lxc-start -d -n ${name} -o /tmp/${name}.log
		;;
		*)
			# make sure vps is still running
			state="$(lxc-info -n "${name}" | sed -e 's/.* is //')"
			[ "$state" = "RUNNING" ] || break
		;;
		esac
	else
		lxc_log "$name $tasks tasks $sulogins console"
	fi

	# time of 5 minutes on it JUST IN CASE...
	inotifywait -qqt 300 utmp
done

lxc_log "$name watchdog exited"

}


usage() {
	echo "Usage: $0 {start|stop|restart|status|boot|disable} [name name ... ]" >&2
	exit 3
}

command_on_lxc() {
command=$1
shift

echo "# $command $1"

case "$command" in

start)
	lxc_exists $1
	cleanup_init_scripts $1
	setup_inittab $1 ":respawn:/sbin/getty.*tty1"	"c1:12345:respawn:/sbin/getty 38400 tty1 linux"
	setup_inittab $1 "::power"			"p0::powerfail:/sbin/init 0"
	setup_inittab $1 "::ctrlaltdel"			"p6::ctrlaltdel:/sbin/init 6"
	lxc_start $1
	# give container 5 seconds to start more than one process
	( sleep 5 ; nohup $0 watchdog $1 >> /tmp/$1.log 2>/dev/null ) &
	;;
stop|halt)
	lxc_exists $1
	lxc_stop $1
	;;
reload|force-reload|restart|reboot)
	lxc_kill $1 -SIGINT
	;;
watchdog)
	lxc_watchdog $1
	;;
boot)
	echo $1 > /var/lib/lxc/$1/on_boot
	;;
disable)
	echo -n > /var/lib/lxc/$1/on_boot
	;;
*)
	usage
	;;

esac

}

command=$1
test -z "$command" && usage
test "$command" = "status" && lxc_status && exit
shift

if [ -z "$1" ] ; then
	ls /var/lib/lxc/*/on_boot | while read path ; do
		name=`echo $path | cut -d/ -f5`
		if [ "$command" != "start" -o "$command" = "start" -a -s $path ] ; then
			command_on_lxc $command $name
		else
			echo "# skip $command $name"
		fi
	done
else
	while [ ! -z "$1" ] ; do
		command_on_lxc $command $1
		shift
	done
fi

ve2lxc

lxc/ve2lxc.sh
#!/bin/sh -x

test -z "$1" && echo "usage: $0 /path/to/ve/private [10.60.0.253 [hostname]]" && exit

dir=$1
ip=$2
hostname=$3
netmask=`grep netmask /etc/network/interfaces | head -1 | sed 's/^.*netmask *//'`
gateway=`grep gateway /etc/network/interfaces | head -1 | sed 's/^.*gateway *//'`

test -z "$ip" && ip=10.60.0.252
test -z "$hostname" && hostname=ve2lxc

path=/$dir/etc/inittab
tmp=/tmp/inittab

cp $path $tmp || exit

append() {
	if ! grep "$1" $path ; then
		echo "$1" >> $tmp
	fi
}

append "z6:6:respawn:/sbin/sulogin"
append "1:2345:respawn:/sbin/getty 38400 console"
append "c1:12345:respawn:/sbin/getty 38400 tty1 linux"
append "c2:12345:respawn:/sbin/getty 38400 tty2 linux"
append "c3:12345:respawn:/sbin/getty 38400 tty3 linux"
append "c4:12345:respawn:/sbin/getty 38400 tty4 linux"

if ! diff -uw $path $tmp ; then
	cp $path $path.old && mv $tmp $path
fi

lxc-stop -n $hostname
lxc-destroy -n $hostname

test -d /cgroup || mkdir /cgroup
grep /cgroup /etc/fstab || echo "cgroup /cgroup cgroup rw 0 0" >> /etc/fstab

grep eth0 $dir/etc/network/interfaces || cat << __interfaces__ > $dir/etc/network/interfaces
auto eth0 lo

iface lo inet loopback

iface eth0 inet static
	address $ip
	netmask $netmask
	gateway $gateway

__interfaces__

echo $hostname > $dir/etc/hostname

echo "$ip $hostname" >> $dir/etc/hosts

conf=/tmp/$hostname.conf

cat << __lxc__ > $conf
lxc.utsname = $hostname
lxc.tty = 4
lxc.pts = 1024

lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.name = eth0
lxc.network.mtu = 1500
#lxc.network.hwaddr = AC:DE:48:00:00:01
# interface visible on host, part of bridge
#lxc.network.veth.pair = veth0

#lxc.mount = $MNTFILE
lxc.rootfs = $dir
# lxc.mount.entry=/opt /virtual/lxc/rootfs/opt none ro,bind 0 0

lxc.cgroup.devices.deny = a
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
__lxc__

cp -v /etc/resolv.conf /$dir/etc/resolv.conf

mount | grep /cgroup || mount /cgroup || exit

lxc-create -n $hostname -f $conf && lxc-start -n $hostname

md

bitmap

md/bitmap.sh
#!/bin/sh -x

# https://raid.wiki.kernel.org/index.php/Bitmap

mdadm --grow --bitmap=internal $1

scrub

md/scrub.sh
#!/bin/sh -x

echo check > /sys/block/$1/md/sync_action

watch cat /proc/mdstat

munin

munin plugins

gearman

#!/usr/bin/perl
use warnings;
use strict;

# 2012-05-27 Dobrica Pavlinusic <dpavlin@rot13.org>

use IO::Socket::INET;
use Data::Dump qw(dump);

my $arg = shift @ARGV;
$arg ||= '';

my $sock = IO::Socket::INET->new(
	PeerAddr => '127.0.0.1',
	PeerPort => 4730,
	Proto    => 'tcp'
) || die $1;

if ( $arg eq 'autoconf' ) {
	print $sock ? "yes\n" : "no\n";
	exit 0;
}

print $sock "STATUS\n";

my $stats;

while ( my $line = <$sock> ) {
	chomp $line;
#	warn "# [$line]\n";
	last if $line eq '.';
	next if $line =~ m/\t0$/; # ignore functions which don't have active workers
	my ( $name, $queued, $running, $workers ) = split(/\t/,$line,4);
	$stats->{queued}->{$name} = $queued;
	$stats->{running}->{$name} = $running;
	$stats->{workers}->{$name} = $workers;
}

if ( $arg eq 'config' ) {
	foreach my $multigraph ( keys %$stats ) {
		print "multigraph $multigraph\n";
		print "graph_category gearman\n";
		print "graph_title Gearman $multigraph\n";

		foreach my $name ( keys %{ $stats->{$multigraph} } ) {
			my $label = $name;
			$name =~ s/\W+/_/g;
			print "$name.label $label\n";
		}
	}
} else {
	foreach my $multigraph ( keys %$stats ) {
		print "multigraph $multigraph\n";
		while ( my ($name,$value) = each %{ $stats->{$multigraph} } ) {
			$name =~ s/\W+/_/g;
			print "$name.value $value\n";
		}
	}
}

log

munin/plugins/log
#!/usr/bin/perl
use warnings;
use strict;
use lib $ENV{'MUNIN_LIBDIR'};
use Munin::Plugin;

# -*- perl -*-

=head1 NAME

log - Plugin to monitor log files

=head1 CONFIGURATION

add munin user to adm group if needed to read C</var/log/*.log>

  [log]
  group adm

=head1 MAGIC MARKERS

 #%# family=auto
 #%# capabilities=autoconf

=cut

my $log = '/var/log/daemon.log';

if ( $ARGV[0] ) {

    if ( $ARGV[0] eq 'autoconf' ) {
	print -r $log ? "yes\n" : "no\n";
    } elsif ( $ARGV[0] eq 'config' ) {
	print <<EOM;
multigraph stunnel
graph_category log
graph_title stunnel clients
clients.label clients

multigraph stunnel_transfer
graph_category log
graph_title stunnel transfer
graph_vlabel bytes/\${graph_period}
ssl.label SSL
ssl.draw AREA
socket.label Socket
socket.draw LINE2

multigraph n2n
graph_category log
graph_title n2n peers
pending.label Pending peers
operational.label Operational peers

multigraph lines
graph_category log
graph_title log lines
stunnel.label stunnel
n2n.label n2n
ignored.label ignored
EOM
    }
    exit 0;
}

my ( $pos ) = restore_state();
$pos = -s $log unless defined $pos;
my ($fh,$reset) = tail_open($log,$pos);

my $ip;
my $stat;


while(<$fh>) {
	if ( m/stunnel/ ) {
		$stat->{lines}->{stunnel}++;
		if ( m/accepted connection from (.+):\d+/ ) {
			$ip->{$1}++;
		} elsif ( m/Connection closed: (\d+) bytes sent to SSL, (\d+) bytes sent to socket/i ) {
			$stat->{stunnel_transfer}->{ssl}    += $1;
			$stat->{stunnel_transfer}->{socket} += $2;
		}
	} elsif ( m/n2n/ ) {
		$stat->{lines}->{n2n}++;
		if ( m/Pending peers list size=(\d+)/ ) {
			$stat->{n2n}->{pending} = $1; # latest
		} elsif ( m/Operational peers list size=(\d+)/ ) {
			$stat->{n2n}->{operational} = $1; # latest
		} elsif ( m/pending=(\d+), operational=(\d+)/ ) {
			$stat->{n2n} = { pending => 1, operational => 2 };
		}
	} else {
		$stat->{lines}->{ignored}++;
	}
}

$stat->{stunnel}->{clients} = scalar keys %$ip if $ip;

foreach my $graph ( keys %$stat ) {
	print "multigraph $graph\n";
	print "$_.value $stat->{$graph}->{$_}\n" foreach keys %{ $stat->{$graph} };
}

$pos = tail_close($fh);
save_state($pos);

nbd

install server

root@opr:~# apt-get install -y nbd-server

create /etc/nbd server/config

[generic]
	user = nbd
	group = disk
[export]
	exportname = /dev/sda
	port = 1234

start nbd server

root@opr:~# /etc/init.d/nbd-server start
 nbd-server.

install client

root@opl:~# apt-get install -y nbd-client

start client

root@opl:/srv/sysadmin-cookbook/recepies/nbd# nbd-client 10.60.0.91 1234 /dev/nbd0
Negotiation: ..size = 244140625KB
bs=1024, sz=244140625

root@opl:/srv/sysadmin-cookbook/recepies/nbd# fdisk -l /dev/nbd0

Disk /dev/nbd0: 250.0 GB, 250000000000 bytes
255 heads, 63 sectors/track, 30394 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00000000

     Device Boot      Start         End      Blocks   Id  System
/dev/nbd0p1               1       12159    97667136   83  Linux

netpipe tcp

install

root@opl:~# apt-get install netpipe-tcp

Makefile

netpipe-tcp/Makefile
graph:
	find . -name "*.np" -size 0 -exec rm {} \;
	./np2graphviz.pl | dot -Tpng -o graph.png && qiv graph.png

gnuplot:
	ls */*.np | xargs -i ./gnuplot.sh {}

xlax:
	mkxlax `cat hosts`

install:
	cat hosts | xargs -i ssh {} apt-get install -y netpipe-tcp

collect

netpipe-tcp/collect.sh
#!/bin/sh

cat hosts | xargs -i sh -c "test -d {} || mkdir {} ; rsync -v {}:/tmp/*.np {}/"
ls -al */*.np

gnuplot

netpipe-tcp/gnuplot.sh
#!/bin/sh

echo "creating $1.png"

cat << __gnuplot__ | gnuplot
set term png
set output "$1.png"

set grid

set ylabel "Throughput In Mbps"
set xlabel "Message Size"

set size 1,0.8 

plot "$1" using 1:2 title "$1" with lines linewidth 3 
__gnuplot__

hosts

mjesec.ffzg.hr
koha-hw.ffzg.hr
10.60.0.9
10.60.0.10
10.60.0.90
10.60.0.91
10.60.0.92
10.60.0.93
10.60.0.200

np2graphviz

netpipe-tcp/np2graphviz.pl
#!/usr/bin/perl

use warnings;
use strict;

my $graph;

my ($max,$min);

foreach my $file ( glob '*/*.np' ) {

	my $direction = $file;
	$direction =~ s/\.np$//;
	my ( $from, $to ) = split(m{/},$direction,2);

	my $line = `tail -1 $file`;
	$line =~ s{^\s+}{};
	$line =~ s{\s+$}{};
	my ( $size, $speed, $rtt ) = split(/\s+/, $line);

	warn "$from -> $to | $size | $speed | $rtt\n";

	my $len = int($speed / 100);

	my $rev = qq|"$to" -> "$from"|;

	# make edge bi-directional if speed difference is less then 10%
	if ( $graph->{$rev} && abs($graph->{$rev}->{speed}->[0] - $speed) < ($speed/10) ) {
		$graph->{$rev}->{speed}->[1] = int($speed);
		$graph->{$rev}->{dir} = 'both';
	} else {
		$graph->{ qq|"$from" -> "$to"| } = {
			size => $size,
			speed => [ int($speed) ],
			rtt => $rtt,
			dir => 'forward',
		};
	}

	$min ||= $speed;
	$min = $speed if $speed < $min;

	$max ||= $speed;
	$max = $speed if $speed > $max;

}

warn "# speed $min ... $max\n";

print qq|
digraph "netpipe" {
|,
join("\n", map {
	my $node = $_;
	my @speed = @{ $graph->{$node}->{speed} };
	my $speed = 0;
	$speed += $_ foreach @speed;
	$speed /= $#speed + 1;
	my $c = 'ff0000';
	$c = '00ff00' if ( $speed /  100 ) > 5;
	$c = '0000ff' if ( $speed / 1000 ) > 1;
	$c = '8888ff' if ( $speed / 1000 ) > 2;
	my $label = qq|labelfontsize=10,weight=$speed,|;
	$label .= qq|headlabel=$speed[0],| if $speed[0];
	$label .= qq|taillabel=$speed[1],| if $speed[1];
	$label .= qq|style=dashed,| if $graph->{$node}->{dir} eq 'both';
	qq|$node [ $label color="#$c",dir=$graph->{$node}->{dir} ]|;
} keys %$graph),
qq|
}
|;

ssh

netpipe-tcp/ssh.sh
#!/bin/sh -x
cat hosts | xargs -i ssh {} $*

test all

netpipe-tcp/test-all.pl
#!/usr/bin/perl

# usage: test-all.pl hosts

use warnings;
use strict;
use autodie;
use File::Slurp;
use Data::Dump qw(dump);

chdir '/srv/sysadmin-cookbook/recepies/netpipe-tcp/';

my @hosts = read_file 'hosts';
@hosts = map { chomp; $_ } @hosts;
warn "hosts = ",dump(@hosts);

foreach my $host ( @hosts ) {
	chomp($host);

	my @test;

	foreach my $to ( @hosts ) {
		next if -s "$host/$to.np";
		warn "start NPtcp on $to\n";
		system "ssh $to NPtcp &";
		push @test, $to;
	}

	warn "# missing ", dump(@test);

	open(my $ssh, '|-', "ssh $host xargs -i NPtcp -h {} -u 1048576 -o /tmp/{}.np");
	foreach my $to ( @test ) {
		warn "TEST from $host to $to\n";
		print $ssh "$to\n";
	}
	close($ssh);

	system "rsync -v $host:/tmp/*.np $host/";
}

test

netpipe-tcp/test.sh
#!/bin/sh

cd /srv/sysadmin-cookbook/recepies/netpipe-tcp/
while read host ; do
	echo "TEST `hostname` $host"
	NPtcp -h $host -u 1048576 -o /tmp/$host.np
done < hosts

ntpdate

install

# install on hardware

root@koha-hw:~# apt-get -y install ntpdate

nvidia

README

http://tutanhamon.com.ua/technovodstvo/NVIDIA-UNIX-driver/

info

nvidia/info.sh
#!/bin/sh

get() {
	echo -n $* " "
	sudo nvidia-settings -q $* -t
}

get GPUCurrentPerfLevel
get GPUCurrentClockFreqs
get GPUPowerSource

openvpn

install

openvpn/0.install.sh
apt-get install openvpn

on server.generate static key

openvpn/1.on-server.generate-static-key.sh
#!/bin/sh -x
KEY=/etc/openvpn/`hostname`.key
test -f $KEY && ls -al $KEY || openvpn --genkey --secret $KEY
echo "transfer $KEY to client"

on client.create /etc/openvpn/tap_home

remote 123.123.123.123
secret prod.key
comp-lzo
dev tap_home
up "/etc/openvpn/tap_home.sh"

on server

dev tap_home
secret prod.key
comp-lzo
up /etc/openvpn/tap_home.sh

on client.create /etc/openvpn/tap_home

openvpn/3.on-client.create
#!/bin/sh -x

ifconfig $1 10.60.0.81 netmask 255.255.254.0 up
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o $1 -j MASQUERADE

on server

openvpn/3.on-server.create
#!/bin/sh -x

ifconfig $1 up
brctl addif br0 $1

append /etc/network/interfaces

auto tap_home
iface tap_home inet manual
	openvpn tap_home

openvz

create ve 1 config

root@opl:/etc/vz/conf# vzsplit -n 1 -f 1 -s 2048
Config /etc/vz/conf/ve-1.conf-sample was created

set ve on clone

root@opl:/etc/vz/conf# vzctl set 60017 --private /zfs/vz-60017-clone/private/212226/ --root /zfs/vz-60017-clone/root/212226/ --ipadd 10.60.0.17 --hostname koha-clone --applyconfig 1 --diskspace 60G:70G --save

pppoe server

install

apt-get install pppoe

create /etc/ppp/pppoe server options

# PPPoE server
#nologin
mru 1492
noreplacedefaultroute
proxyarp
ms-dns 192.168.1.2

append /etc/ppp/pap secrets

# PPPoE server
#client	hostname	<password>	IP
test	*			"test"		*

append /etc/ppp/chap secrets

# PPPoE server
# client	server	secret	IP addresses
test		*	test	*

configure private net

ifconfig eth0:10 10.0.0.1 up

PADI

pppoe-relay -B eth0:1 -C eth0 -n 1 -F

pppoe server

pppoe-server -I eth0:1 -T 60 -C fake -S fake -L 10.0.0.2 -R 10.0.0.10 -N 1 -F

NAT

iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -j SNAT --to-source 192.168.1.90

tshark dump

pppoe-server/tshark-dump.sh
tshark -i eth0 -f '!port 80'

ps3

ps3 xserver xorg video spu

install

apt-get source xserver-xorg-video-spu
apt-get build-dep xserver-xorg-video-spu
apt-get install build-essential fakeroot dpkg-dev

build

cd xserver-xorg-video-spu* && dpkg-buildpackage -rfakeroot -b

pxe

install

root@klin:/srv/sysadmin-cookbook/recepies/pxe# apt-get install dnsmasq

create /etc/dnsmasq.d/pxe

dhcp-boot=pxelinux.0

dhcp-range=192.168.2.50,192.168.2.150,12h

enable-tftp
tftp-root=/srv/sysadmin-cookbook/recepies/pxe/tftpboot/
dhcp-boot=pxelinux.0

enable conf dir

pxe/2.enable-conf-dir.sh
#!/bin/sh -x

grep '^conf-dif=/etc/dnsmasq.d' /etc/dnsmasq.conf || ( echo 'conf-dir=/etc/dnsmasq.d' >> /etc/dnsmasq.conf && /etc/init.d/dnsmasq restart )

create tftpboot

pxe/3.create-tftpboot.sh
#!/bin/sh

url=ftp.hr.debian.org/debian/dists/lenny/main/installer-i386/current/images/netboot/netboot.tar.gz
url=http://people.debian.org/~joeyh/d-i/images/daily/netboot/netboot.tar.gz

test -d tftpboot || wget -nc $url && mkdir tftpboot && cd tftpboot && tar xvfz ../netboot.tar.gz

nat 192.168.2.0 wlan0

pxe/nat-192.168.2.0-wlan0.sh
sudo iptables -t nat -F
sudo iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o wlan0 -j MASQUERADE
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"

qr

qr wifi

qr/qr-wifi.sh
#/bin/sh -xe
# Generate QR code for WIFI network
test -z "$1" && echo -n "ssid:     " && read ssid || ssid=$1
test -z "$2" && echo -n "password: " && read pass || pass=$2
qrencode -o /tmp/qr-${ssid}.png "WIFI:S:$ssid;T:WPA;P:$pass;" ; qiv -m /tmp/qr-${ssid}.png

rsync

clone directory

rsync -ravHAX /var/lib/vz/ /zfs/vz/

rsync pull backup over ssh

pull backup from snapshot ../../lvm/create lvm snapshot

root@opl:~# rsync -ravHC --progress koha-hw:/mnt/vz-backup/ /zfs/vz/

pull backup ../../lvm/remove lvm snapshot

rsync -ravH koha-hw:/var/lib/vz/private/ /zfs/vz/private/

rsync clone

rsync/rsync-clone.sh
#!/bin/sh -x

rsync -ravH --numeric-ids --sparse --delete $*

screen

install

apt-get install screen

screen sharing

create student

useradd -d `pwd`/student -s `pwd`/student/screen.sh student

screen sharing perms

chmod u+s /usr/bin/screen
chmod 755 /var/run/screen

screen restore perms

chmod 755 /var/run/screen
chmod 2755 /usr/bin/screen

Makefile

screen/sharing/Makefile
screen:
	sudo sh -x 2.screen-sharing-perms
	sudo -u dpavlin xterm +rv -n perl -e screen -S perl -c screenrc &

test:
	xterm -fg grey -e ssh student@localhost &

screenrc

multiuser on
acladd student
#aclchg student -w "#"
aclumask student-w

screen sharing student

screen

screen/sharing/student/screen.sh
#!/bin/sh

exec screen -x dpavlin/perl

smart

debian install

smart/0-debian-install.sh
sudo apt-get install sudo smartmontools git-core

README

Controller status dump:

3ware Inc 9750 SAS2/SATA-II RAID

	http://www.lsi.com/channel/support/products/Pages/3wareSAS9750-8i.aspx

	http://kb.lsi.com/Download15800.aspx

Symbios Logic SAS2008

	http://www.supermicro.com/support/faqs/data_lib/FAQ_9633_SAS2IRCU_Phase_5.0-5.00.00.00.zip

count drives

smart/count-drives.sh
ls */smart.* | cut -d. -f2 | cut -d_ -f-3 | cut -d\- -f1 | sort | uniq -c

dump smart

smart/dump-smart.sh
#!/bin/sh -x

tw_cli=/srv/3ware/x86_64/tw_cli
sas2ircu=/srv/sas2ircu_linux_x86_rel/sas2ircu

cd /srv/smart
dir=`hostname -s`
test -d $dir || mkdir $dir
cd $dir
#ls -d /sys/block/sd* | cut -d/ -f4 | xargs -i sh -cx "/usr/sbin/smartctl -a /dev/{} > smart.{}"

if [ -z "$DEBUG" ] ; then

ls /dev/disk/by-id/scsi-* | grep -v part[0-9]* | while read dev ; do
	echo $dev
	name=`echo $dev | sed 's/^.*scsi-//'`
	sudo smartctl -a $dev > smart.$name
done

fi

test -x $sas2ircu && $sas2ircu LIST | grep 1000h | awk '{ print $1 }' | xargs -i $sas2ircu {} DISPLAY > controller.lsi_sysbios

if [ -x $tw_cli ] ; then
	controller=`$tw_cli show | grep ^c[0-9] | cut -d" " -f1`
	if [ ! -z "$controller" ] ; then
		$tw_cli /$controller show all > controller.3ware
		$tw_cli /$controller/bbu show all >> controller.3ware
	fi
fi

test ! -z "$DEBUG" && exit 1

git add smart.* controller.*
git commit -m `date +%Y-%m-%d.%H:%M:%S` -a

dump

smart/dump.sh
#!/bin/sh

if [ ! -e /etc/cron.d/smart ] ; then
	echo '*/30 *  * * *   /srv/sysadmin-cookbook/recepies/smart/dump.sh' > /etc/cron.d/smart
fi

cd /srv/sysadmin-cookbook/recepies/smart
# awk '{ if ( $3 >= 2930266584 ) print $4 }'

driver="-d megaraid,0"

cat /proc/partitions | grep ' sd.$' | awk '{ print $4 }' | xargs -i sudo sh -cx "smartctl $* $driver -a /dev/{} > smart.{}"
git commit -m `date +%Y-%m-%d.%H:%M:%S` -a

failure

smart/failure.sh
sed='s!/smart.! !'
egrep '(Raw_Read_Error_Rate|Reallocated_Sector_Ct|Seek_Error_Rate|Spin_Retry_Count|Reallocated_Event_Count|Current_Pending_Sector|Offline_Uncorrectable|UDMA_CRC_Error_Count)' */smart.* | awk '{ if ( $10 > 0 ) print $1 " " $2 " " $10 }' | sed -e "$sed" -e 's/:[0-9][0-9]* / /' | sort | while read host serial status count ; do
	echo $host $serial $status $count
	egrep -A 1 '(failure|progress)' $host/smart.*$serial | sed -e "$sed"
done

smart test all

smart/smart-test-all.sh
ls -d /sys/block/sd* | cut -d/ -f4 | xargs -i sh -cx "/usr/sbin/smartctl -t long /dev/{}"

smart test relocate

smart/smart-test-relocate.pl
#!/usr/bin/perl

use warnings;
use strict;

my $drive = $ARGV[0] || die "usage: $0 /dev/sda\n";
my $delay = 15;
my $rewrite_sectors = 16;

my $test_started = 0;

sub write_sector {
	my $s = shift;
	system "hdparm --write-sector $s --yes-i-know-what-i-am-doing $drive";
}

sub smart_test {
	my $sector = shift;
	my $cmd = "smartctl -t select,$sector-max $drive";
	warn "$cmd\n";
	system $cmd;
	$test_started = 1;
}

sub smart {
	my $cmd = "smartctl -l selective $drive";
	warn "$cmd\n";
	open(my $fh, '-|', $cmd);
	while(<$fh>) {
		chomp;
		print "# $_\n";
		if ( m/Completed_read_failure.*\((\d+)-\d+\)/ ) {
			my $sector = $1;
			print "rewrite sector: $sector\n";
			foreach my $s ( $sector .. $sector + $rewrite_sectors ) {
				write_sector $s;
			}
			smart_test $sector;
			return 1;
		} elsif ( m/Self_test_in_progress/ ) {
			$test_started = 1;
			return 1;
		} elsif ( m/Not_testing/ ) {
			if ( $test_started ) {
				smart_last_error();
				return 1 if $test_started;
			}
			smart_test 0; # first-time invocation
		}
	}
	return 0;
}

sub smart_last_error {
	my $cmd = "smartctl -l selftest $drive";
	warn "$cmd\n";
	open(my $fh, '-|', $cmd);
	while(<$fh>) {
		chomp;
		print "# $_\n";
		if (/^#\s+1.+Completed: read failure\s+\S+\s+\S+\s+(\d+)/) {
			write_sector $1;
			smart_test $1;
			return 1;
		}
	}
}

smart_last_error || smart_test 0;

while ( smart ) {
	warn "sleep $delay s", ( $test_started ? " smart test running..." : "idle" ), "\n";
	sleep $delay;
}

smtp

install

apt-get install swaks

ssd

trim test

ssd/trim-test.sh
#!/bin/sh -xe

# mount /dev/sda2 /mnt -o rw,noatime,discard

seq 1 1000 > testfile
hdparm --fibmap testfile | tee out.hdparm

sector=`cat out.hdparm | tail -1 | awk '{ print $2 }'`
hdparm --read-sector $sector /dev/sda > out.$sector.1

rm testfile
sync

hdparm --read-sector $sector /dev/sda > out.$sector.2
md5sum out.$sector.[12]

ssh

ssh login without password

generate root ssh key

root@opl:~# test -f /root/.ssh/id_rsa || ssh-keygen -f /root/.ssh/id_rsa -N ''

copy root identity

root@opl:~# ssh-copy-id -i /root/.ssh/id_rsa llin

strace

strace count

strace/strace-count.sh
#!/bin/sh -x

trace=/tmp/strace
strace -c -o $trace $* && ls -al $trace && cat $trace

systemtap

kernel source

apt-get install linux-source-`uname -r | cut -d\- -f1` kernel-package fakeroot

kernel build

r=`uname -r | cut -d\- -f1`
cd /usr/src
test -d linux-source-$r || tar xjf linux-source-$r.tar.bz2
cd linux-source-$r
cat /boot/config-`uname -r` | sed \
	-e  's/^# CONFIG_DEBUG_INFO.*/CONFIG_DEBUG_INFO=y/' \
	-e  's/^# CONFIG_KPROBES.*/CONFIG_KPROBES=y/' \
	> .config
make oldconfig
fakeroot make-kpkg --initrd --append-to-version=-systemtap kernel_image kernel_headers kernel_debug

usb sniff

usbmon

usb-sniff/0-usbmon.sh
#!/bin/sh -x

modprobe usbmon
mount -t debugfs / /sys/kernel/debug

vblade

client install

apt-get install aoetools

server install

apt-get install vblade

aoe module

rmmod aoe
modprobe aoe aoe_iflist="eth0 virtual"
dmesg | tail -1

client info

aoe-discover
aoe-stat

server lvblade

aoe-interfaces eth0
vblade 0 1 eth0 /dev/vg/lvblade

vde2

install

apt-get install vde2

append /etc/network/interfaces

iface tap0 inet static
  address 172.25.25.1
  netmask 255.255.255.0
  vde2-switch -

add to group vde2 net

vde2/2.add-to-group-vde2-net.sh
#!/bin/sh -x

USER=$1
usermod -a -G vde2-net $USER

eth0 nat

vde2/eth0-nat.sh
#!/bin/sh -x

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

kvm

vde2/kvm.sh
#!/bin/sh

#kvm-img create -f qcow2 faitest.img 5G
vdeq kvm -m 256 -net nic,vlan=1 -net vde,vlan=1,sock=/var/run/vde2/tap0.ctl/ctl -boot n # -hda faitest.img

vde2 virtualnetmanager

build deb

vde2/virtualnetmanager/build-deb.sh
#!/bin/sh -x

test -d trunk && cd trunk && svn update || svn co https://virtualnetmgr.svn.sourceforge.net/svnroot/virtualnetmgr/trunk && cd trunk
sudo checkinstall --requires graphviz --requires python --pkgname virtualnetmanager ./install.sh

vim

install

root@opl:~# apt-get -y install vim

create /home/dpavlin/

syntax on

web

stress test http

web/stress-test-http.sh
url='http://10.60.0.17:81/cgi-bin/koha/opac-search.pl?idx=&q='
cat /usr/share/dict/words | grep '^[a-z]*$' | xargs -i time wget -O /dev/null $url{}

yukon

install

sudo apt-get install libx11-dev libxv-dev x11proto-xext-dev mesa-common-dev libgl1-mesa-dev

checkout

svn co https://devel.neopsis.com/svn/seom/branches/packetized-stream seom
svn co https://devel.neopsis.com/svn/yukon/branches/rewrite yukon

README

Yukon is a set of libraries and applications that are designed to capture
realtime videos of OpenGL applications (games).

https://devel.neopsis.com/projects/yukon/

zfs

install

root@opl:~# apt-get install libfuse2 fuse-utils libaio1

root@opl:~# dpkg -i zfs-fuse_20090430-1_i386.deb 
Selecting previously deselected package zfs-fuse.
(Reading database ... 21076 files and directories currently installed.)
Unpacking zfs-fuse (from zfs-fuse_20090430-1_i386.deb) ...
Setting up zfs-fuse (20090430-1) ...

create pool

# http://docs.sun.com/app/docs/doc/819-5461/gaynr?a=view

root@opl:~# lvcreate -n zfs -L 100G raid0
  Logical volume "zfs" created

root@opl:~# zpool create zfs /dev/raid0/zfs

root@opl:~# zpool list
NAME   SIZE   USED  AVAIL    CAP  HEALTH  ALTROOT
zfs   99.5G  6.92G  92.6G     6%  ONLINE  -

create file system

root@opl:~# zfs create zfs/vz

root@opl:~# zfs list /zfs/vz
NAME     USED  AVAIL  REFER  MOUNTPOINT
zfs/vz  72.2G  18.8G  72.2G  /zfs/vz

create compressed file system

# http://docs.sun.com/app/docs/doc/819-5461/gayns?a=view

root@opl:~# zfs create zfs/install

root@opl:~# zfs set compression=on zfs/install

root@opl:~# zfs list zfs/install
NAME          USED  AVAIL  REFER  MOUNTPOINT
zfs/install    18K  18.8G    18K  /zfs/install

attach device

root@opl:/srv/sysadmin-cookbook/recepies/zfs# fdisk -l /dev/nbd0

Disk /dev/nbd0: 250.0 GB, 250000000000 bytes
255 heads, 63 sectors/track, 30394 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00000000

     Device Boot      Start         End      Blocks   Id  System
/dev/nbd0p1               1       13374   107426623+  83  Linux


root@opl:~# zpool status
  pool: zfs
 state: ONLINE
 scrub: scrub completed after 0h19m with 0 errors on Thu Apr 30 22:46:09 2009
config:

        NAME         STATE     READ WRITE CKSUM
        zfs          ONLINE       0     0     0
          raid0/zfs  ONLINE       0     0     0

errors: No known data errors


root@opl:~# zpool attach zfs /dev/raid0/zfs /dev/nbd0p1

root@opl:~# zpool status
  pool: zfs
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
	continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scrub: resilver in progress for 0h2m, 3.47% done, 1h5m to go
config:

	NAME           STATE     READ WRITE CKSUM
	zfs            ONLINE       0     0     0
	  mirror       ONLINE       0     0     0
	    raid0/zfs  ONLINE       0     0     0
	    nbd0p1     ONLINE       0     0     0

errors: No known data errors

create snapshot

# http://docs.sun.com/app/docs/doc/819-5461/gbcya?a=view

root@opl:~# zfs snapshot zfs/vz@`date +%Y-%m-%d_%H:%M:%S`

root@opl:~# zfs list
NAME                         USED  AVAIL  REFER  MOUNTPOINT
zfs                         85.5G  12.4G  6.92G  /zfs
zfs/install                 6.40G  12.4G  6.40G  /zfs/install
zfs/vz                      72.2G  12.4G  72.2G  /zfs/vz
zfs/vz@2009-05-01_14:41:50      0      -  72.2G  -

create writable clone

root@opl:/zfs/vz# zfs clone zfs/vz@60017 zfs/vz-60017-clone

root@opl:/zfs/vz# zfs list /zfs/vz-60017-clone
NAME                 USED  AVAIL  REFER  MOUNTPOINT
zfs/vz-60017-clone      0  88.2G  73.1G  /zfs/vz-60017-clone

nc zfs receive

root@opl:~# nc -l -p 8888 | dd_rescue - - | zfs receive opl/backup/212052

nc zfs send

root@opr:/etc/vz/conf# zfs send opr/vz/private/212052@2009-05-01 | dd_rescue - - | nc -w 1 10.60.0.90 8888

create /etc/cron.d/zfs cron backup

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user	command
15 21	* * *	root	/srv/sysadmin-cookbook/recepies/zfs/pull-snapshot-backup.sh

append /etc/rc

echo -n "Starting ZFS-fuse: "
pidof zfs-fuse || (
	/usr/local/sbin/zfs-fuse && sleep 1 && /usr/local/sbin/zfs mount -a && /usr/local/sbin/zpool status -x
)

Makefile

zfs/Makefile
# use newer zfs-fuse branch

#upstream=http://www.wizy.org/mercurial/zfs-fuse/trunk
#upstream=http://git.rudd-o.com/zfs/
upstream=http://git.zfs-fuse.net/official/

all:
	echo "make [checkout deb clean]"

checkout:
	git clone $(upstream) zfs-fuse

install: uninstall
	cd zfs-fuse/src && scons install #install_dir=/usr/sbin/

uninstall:
	rm -vf /usr/local/sbin/zdb /usr/local/sbin/ztest /usr/local/sbin/zpool /usr/local/sbin/zfs /usr/local/sbin/zfs-fuse

deb: uninstall
	echo "ZFS on FUSE/Linux" > zfs-fuse/description-pak
	echo "install:" > zfs-fuse/Makefile
	echo "	cd src && scons install" >> zfs-fuse/Makefile
	cd zfs-fuse && sudo checkinstall \
		--pkgname zfs-fuse --pkgversion `hg log --limit 1 | cut -d: -f2 | head -1` \
		--pkglicense CDDL --pkggroup contrib/non-free \
		--pkgsource $(upstream) --maintainer dpavlin@rot13.org \
		--provides zfs --requires libfuse2,fuse-utils,libaio1 \
		--exclude /rest/cvs/zfs-fuse/src/.sconsign.dblite \

depends:
	sudo apt-get install checkinstall libfuse-dev fuse-utils libaio-dev

clean:
	rm -Rf zfs-fuse/

README

Upstream source with fixes: http://git.rudd-o.com/zfs/

disks

zfs/disks.pl
#!/usr/bin/perl
use warnings;
use strict;
use autodie;
use Data::Dump qw(dump);

my ($before, $delimiter, $after) = ( ''=>' | '=> "\n" ); # double space for display
   ($before, $delimiter, $after) = ( '"'=>'","'=> '"'."\n" ) if @ARGV;

my $zfs;
open(my $zpool, '-|', 'zpool status');
my $name = 'zfs';
my $vdev = '';
while(<$zpool>) {
	chomp;
	$name = $1 if /^\s+pool:\s(\S+)/;
	$vdev = $1 if /^\s+(raid\S+|spare|log|cache)/;
	$zfs->{$1} = join(' ', $name, $vdev) if /^\s+(sd\S+)/;
}
warn "# zfs ",dump($zfs);

my $md;
open(my $mdstat, '<', '/proc/mdstat');
while(<$mdstat>) {
	chomp;
	if ( m/(md\d+)\s+:\s+active\s+(\S+)\s+(.+)/ ) {
		my ( $nr, $raid ) = ( $1, $2 );
		foreach my $dev ( split(/\s+/, $3) ) {
			my $d = $1 if $dev =~ m{(sd\w+)\d+};
			$md->{$d} = "$nr $raid $dev";
		}
	}
}
warn "# md ",dump($md);

open(my $lsscsi, '-|', 'lsscsi --size -v');

print $before, join($delimiter, qw(id type name dev size pert_of path) ), $after;

while(my $line = <$lsscsi>) {
	chomp($line);
#	warn "## $line\n";

	my @l = $line =~ m{(^\S+)\s+(\S+)\s+(.+)\s+(\S+)\s+(\S+)};

	my $dev = $l[3];
	$dev =~ s{/dev/}{};
	warn "# dev $dev\n";

	push @l,
		exists $zfs->{$dev} ? $zfs->{$dev} :
		exists $md->{$dev} ? $md->{$dev} :
		'-';

	my $v = <$lsscsi>;
	chomp($v);
	push @l, $1 if $v =~ m/\[(.+)\]/;
	print $before,join($delimiter,@l),$after;
};

zfs enlarge pool

attach block device to pool ../../lvm/lvcreate

root@opl:/srv/sysadmin-cookbook/recepies/lvm# zpool status
  pool: zfs
 state: ONLINE
 scrub: resilver completed after 0h45m with 0 errors on Fri May  1 01:56:58 2009
config:

        NAME           STATE     READ WRITE CKSUM
        zfs            ONLINE       0     0     0
          mirror       ONLINE       0     0     0
            raid0/zfs  ONLINE       0     0     0
            nbd0p1     ONLINE       0     0     0

root@opl:/srv/sysadmin-cookbook/recepies/lvm# zpool attach zfs /dev/raid0/zfs /dev/raid0/zfs-200

root@opl:/srv/sysadmin-cookbook/recepies/zfs/enlarge-pool# zpool status zfs
  pool: zfs
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scrub: resilver in progress for 0h6m, 10.14% done, 1h0m to go
config:

        NAME               STATE     READ WRITE CKSUM
        zfs                ONLINE       0     0     0
          mirror           ONLINE       0     0     0
            raid0/zfs      ONLINE       0     0     0
            nbd0p1         ONLINE       0     0     0
            raid0/zfs-200  ONLINE       0     0     0

errors: No known data errors

detach old block device

# this step is optional but will move read load from local block device to network mirror device

root@opl:/srv/sysadmin-cookbook/recepies/zfs/enlarge-pool# zpool detach zfs /dev/raid0/zfs

root@opl:/srv/sysadmin-cookbook/recepies/zfs/enlarge-pool# zpool status
  pool: zfs
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scrub: resilver in progress for 0h0m, 0.00% done, 265h17m to go
config:

        NAME               STATE     READ WRITE CKSUM
        zfs                ONLINE       0     0     0
          mirror           ONLINE       0     0     0
            nbd0p1         ONLINE       0     0     0
            raid0/zfs-200  ONLINE       0     0     0

errors: No known data errors

remove small remote block device

root@opl:~# zfs list
NAME                         USED  AVAIL  REFER  MOUNTPOINT
zfs                         97.7G   288M    22K  /zfs
zfs/install                 6.40G   288M  6.40G  /zfs/install
zfs/vz                      91.3G   288M  72.8G  /zfs/vz
zfs/vz@2009-05-01_14:41:50  18.5G      -  72.2G  -


root@opl:~# zpool status
  pool: zfs
 state: ONLINE
 scrub: resilver completed after 0h28m with 0 errors on Fri May  1 18:13:31 2009
config:

        NAME               STATE     READ WRITE CKSUM
        zfs                ONLINE       0     0     0
          mirror           ONLINE       0     0     0
            nbd0p1         ONLINE       0     0     0
            raid0/zfs-200  ONLINE       0     0     0

errors: No known data errors


root@opl:~# zpool detach zfs nbd0p1


root@opl:~# zpool status
  pool: zfs
 state: ONLINE
 scrub: resilver completed after 0h28m with 0 errors on Fri May  1 18:13:31 2009
config:

        NAME             STATE     READ WRITE CKSUM
        zfs              ONLINE       0     0     0
          raid0/zfs-200  ONLINE       0     0     0

errors: No known data errors


root@opl:~# zfs list
NAME                         USED  AVAIL  REFER  MOUNTPOINT
zfs                         97.7G  98.7G    22K  /zfs
zfs/install                 6.40G  98.7G  6.40G  /zfs/install
zfs/vz                      91.3G  98.7G  72.8G  /zfs/vz
zfs/vz@2009-05-01_14:41:50  18.5G      -  72.2G  -
r

pull rsync snap

zfs/pull-rsync-snap.sh
#!/bin/sh -x

from=10.60.0.200

pool=`zpool list -o name -H`
log=/$pool/log/

exclude='--exclude var/cache --exclude var/lib/koha/zebradb/biblios --exclude data/webpac2/var/'

function rsync_veid() {

veid=$1
host=$2

date_time=`rsync $from::mnt/$host/.snap/ | tail -1 | awk '{ print $5 }'`
date=`echo $date_time | cut -dT -f1`

(
rsync $exclude -ravHz --numeric-ids --delete --force --modify-window=2 \
	$from::mnt/$host/.snap/$date_time/	\
	/$pool/backup/$veid/			\
&& zfs snapshot $pool/backup/$veid@$date
2>&1 ) | tee -a $log/$date.log

}

rsync_veid 212052 koha-dev
rsync_veid 212056 webpac2
rsync_veid 212226 koha

#zfs list -r $pool/backup | tee -a $log/$date.log

pull snapshot backup

zfs/pull-snapshot-backup.sh
#!/bin/sh -x

# prod.vbz.ffzg.hr
from=10.60.0.200
vg=/dev/raid5

date=`date +%Y-%m-%d`
pool=`zpool list -o name -H`
log=/$pool/log/
exclude='--exclude var/cache --exclude var/lib/koha/zebradb/biblios --exclude data/webpac2/var/ --exclude tmp/'

test -d $log || mkdir $log || exit

rsync_veid() {
	ssh $from "umount /mnt/backup/$2 ; lvremove -f $vg/$2-backup"
	ssh $from "sync && sync && lvcreate -s -L 10G -n $2-backup $vg/$2 && mount $vg/$2-backup /mnt/backup/$2" || exit
	test -d /$pool/backup/$1 || zfs create $pool/backup/$1 || exit
	echo "## rsync $1"
	rsync $exclude -ravHz --numeric-ids --delete --force --modify-window=2 $from::mnt/backup/$2/rootfs/ /$pool/backup/$1/ && zfs snapshot $pool/backup/$1@$date
#	ssh $from "umount /mnt/backup/$2 && lvremove -f $vg/$2-backup"
}

(
zfs list -r $pool/backup
rsync_veid 212226 koha
rsync_veid 212052 koha-dev
rsync_veid 212056 webpac2
zfs list -r $pool/backup
2>&1 ) | tee -a $log/$date.log

replace failing drive

zfs/replace-failing-drive.sh
#!/bin/sh -x

pool=t1

# destroy existing pool
zpool status $pool && zpool destroy $pool

mkdisk() {
	dd if=/dev/zero of=disk/$1 bs=1M count=64
}

test -d disk || mkdir disk
mkdisk 1
mkdisk 2
mkdisk 3
mkdisk 4
mkdisk 5
mkdisk 6
mkdisk 7
mkdisk 8
mkdisk 9
mkdisk 10
mkdisk 11
mkdisk spare

d=`pwd`/disk

zpool create $pool raidz1 $d/1 $d/2 $d/3 $d/4 $d/5 $d/6 $d/7 $d/8 $d/9 $d/10 $d/11 spare $d/spare

zpool status $pool

dd if=/dev/zero of=/$pool/foo bs=1M count=500

zfs list $pool

dd if=/dev/urandom of=$d/11 bs=1M count=20

zpool status $pool

zpool scrub $pool

zpool status $pool

zpool replace $pool $d/11 $d/spare

zpool status $pool

zpool detach $pool $d/11

zpool status $pool

mkdisk 11.replaced

zpool replace $pool $d/spare $d/11.replaced

zpool status $pool

zfs expire snapshot

zfs/zfs-expire-snapshot.pl
#!/usr/bin/perl

use warnings;
use strict;

use DateTime;
use Data::Dump qw/dump/;

my $debug = $ENV{DEBUG} || 0;

my $config = {
	'default' => {
		21 => 5,
		30 => 10,
		90 => 30,
	},
	'212052' => {	# koha-dev
		7 => 10,
		14 => 30,
	},
	'212056' => {	# webpac2
		7 => 5,
		14 => 30,
	}
};

my $now = DateTime->now();

my $last_backup;

open(my $fs, '-|', 'zfs list -t snapshot -H');
while(<$fs>) {
	chomp;
	my ( $name, $used, $avail, $refer, $mountpoint ) = split(/\t/,$_,6);

	next unless $name =~ m{(.+)@(\d\d\d\d)-(\d\d)-(\d\d)};

	my $host = $1;

	my $date = DateTime->new( year => $2, month => $3, day => $4 );

	my $age = $now->delta_days( $date )->delta_days;

	my $op = ' ';
	my $last = 0;

	my $c = (grep { $host =~ m{\Q$_\E} } keys %$config)[0];
	$c = 'default' unless defined $c;

	warn "# config: $c\n" if $debug;

	my $h = $host;
	$h =~ s{,+/([^/]+)$}{}; # just hostname without path

	$c = $config->{$c} || die "can't find config for $c";

	warn "# c = ",dump($c) if $debug;

	my $keep_every_days;
	my $older_than_days;
	foreach ( sort { $b <=> $a } keys %$c ) {
		$older_than_days = $_;
		$keep_every_days = $c->{$_};
		warn "## $host $age > $older_than_days" if $debug;
		last if $age > $older_than_days;
	}

	my $config_applied = '';

	if ( $age > $older_than_days ) {

		$config_applied = "> $older_than_days keep $keep_every_days";

		$last_backup->{$host} ||= $date;
		$last = $last_backup->{$host}->delta_days( $date )->delta_days;

		if ( $last && $last < $keep_every_days ) {
			$op = 'D';
		} else {
			$op = ' ';
			$last_backup->{$host} = $date;
		}
	} else {
		$config_applied = 'none';
	}

	print "$op $name\t$used\t$refer\t$age\t$last\t$config_applied\n";

	system "zfs destroy $name" if $op eq 'D' && @ARGV;
}

zfs receive snaphost

zfs/zfs-receive-snaphost.sh
#!/bin/sh -x

from=10.60.0.90

fs=`ssh $from zfs list -t snapshot | grep @ | iselect -t "select snapshot to pull" -a | sed 's/ .*$//'`

if [ -z "$fs" ] ; then
	exit;
fi

veid=`echo $fs | cut -d/ -f3 | cut -d@ -f1`
date=`echo $fs | cut -d/ -f3 | cut -d@ -f2`
pool=`echo $fs | cut -d/ -f1`

echo "pull $pool / $veid @ $date"

local=`zfs list | grep $veid | cut -d" " -f1`

if [ -z "$local" ] ; then
	local_pool=`zfs list | grep /backup/ | head -1 | cut -d/ -f1`
	local="$local_pool/backup/$veid"
	zfs create $local || exit
fi

echo "clone $fs -- $veid to $local";

ssh $from "zfs send $fs | nc -w 5 -l -p 8888" &
sleep 1

nc $from 8888 | dd_rescue -w -y 0 -l /tmp/$veid@$data.log - - | zfs receive -F $local && zfs snapshot $local@$date

zfs list -t snapshot | grep $veid

zfs replicate pool

zfs/zfs-replicate-pool.pl
#!/usr/bin/perl
use warnings;
use strict;

use Net::OpenSSH;
use Data::Dump qw(dump);
use List::Util qw(first);
use Time::HiRes;

my $compress = '| lzop -c';
my $decompress = 'lzop -d |';

my $arh = Net::OpenSSH->new('root@10.60.0.204');
my $dev = Net::OpenSSH->new('root@10.60.0.202');

sub on {
	my ($ssh,$command) = @_;
	warn "## ", $ssh->get_host, "> $command\n" if $ENV{DEBUG};
	if ( $command =~ m/zfs list/ ) {
		map {
			chomp; $_;
		} $ssh->capture($command);
	} else {
		$ssh->capture($command);
	}
}

print on $arh => 'zpool status';
print on $dev => 'zpool status';

my @arh = on $arh => 'zfs list -H -o name';
my @dev = on $dev => 'zfs list -H -o name';

warn "# ",dump( \@arh, \@dev );

my $from_pool = $arh[0];
my $to_pool   = $dev[0];

sub snapshots_from {
	my ($ssh) = @_;
	my $host = $ssh->get_host;

	my $snapshot;

	my @snapshots = on $ssh => 'zfs list -H -t snapshot -o name';
	die $ssh->error if $ssh->error;
	foreach my $s (@snapshots) {
		my ($fs,$name) = split(/\@/,$s);
		push @{ $snapshot->{$fs} }, $name;
	}

#	warn "snapshots_from $host ",dump($snapshot),$/;

	return $snapshot;
}

foreach my $fs ( @arh ) {

	my $name = $fs;
	$name =~ s{^$from_pool/}{} || next; # FIXME skip top-level fs
	warn "? $name";

	my $arh_snapshot = snapshots_from $arh;
	if ( ! exists( $arh_snapshot->{$fs} ) ) {

		my $snapshot = $fs . '@send';
		print on $arh => "zfs snapshot $snapshot";
		die $arh->error if $arh->error;
		$arh_snapshot = snapshots_from $arh;
	}

	my $max_snapshot = $#{ $arh_snapshot->{$fs} };
	warn "$fs has ",$max_snapshot+1," snapshots\n";

	my $to_dev = "$to_pool/$name";

	foreach my $i ( 0 .. $max_snapshot ) {
		my $snap = $arh_snapshot->{$fs}->[$i] || die "no snap";

		my $dev_snapshot = snapshots_from $dev;
		if ( exists $dev_snapshot->{$to_dev} ) {
			if ( first { /^\Q$snap\E$/ } @{ $dev_snapshot->{$to_dev} } ) {
				warn "+ $name @ $snap exists\n";
				next;
			} else {
				warn "- $name @ $snap missing\n";
			}
		} else {
			warn "$name not found on target yet";
		}

		my $snapshot;
		if ( $i == 0 ) {
			$snapshot = "$from_pool/$name\@$snap";
		} else {
			my $prev = $arh_snapshot->{$fs}->[$i-1] || die "no prev";
			$snapshot = "-i $from_pool/$name\@$prev $from_pool/$name\@$snap";
		}

		warn "zfs transfer $snapshot -> $to_dev\n";

		my $t = time();

		my $recv = "nc -w 3 -l -p 8888 | $decompress zfs receive $to_dev";
		warn ">> $recv\n";
		my ($rin1,$pid1) = $dev->pipe_in($recv);
		warn ">> pid: $pid1";

		sleep 1; # FIXME wait for netcat to start

		my $send = "zfs send $snapshot $compress | nc -q 0 -w 2 10.60.0.202 8888";
		warn "<< $send\n";
		$arh->system($send);
		die $arh->error if $arh->error;

		$t = time() - $t;
		warn "took $t seconds to complete\n";

		$dev->system("zfs set readonly=on $to_pool/$name") if $i == 0;
		warn "ERROR: ",$dev->error if $dev->error;

		sleep 1;
		$dev_snapshot = snapshots_from $dev;
		die "can't find new snapshot $snap" unless $dev_snapshot->{$to_dev};

	}

}

zfs send snapshot

zfs/zfs-send-snapshot.sh
#!/bin/sh -x

fs=`zfs list | grep @ | iselect -t "select snapshot to send over netcat $veid" -a | sed 's/ .*$//'`

if [ -z "$fs" ] ; then
	exit;
fi

nopool=`echo $fs | cut -d/ -f2-`

ip=`ifconfig | awk '/inet addr/ {split ($2,A,":"); print A[2]}' | grep -v 127.0.0.1 | head -1`

echo -e "\n\nStart receiving side with:\n\nnc -w 5 $ip 8888 | dd_rescue -y 0 - - | zfs receive \`hostname\`/$nopool\n\n"

zfs send $fs | dd_rescue -y 0 - - | nc -l -p 8888

zfs snapshot to ve

zfs/zfs-snapshot-to-ve.sh
#!/bin/sh -x

veid=60018

fs=`zfs list | grep @ | iselect -t "select snapshot to clone into $veid" -a | sed 's/ .*$//'`

if [ -z "$fs" ] ; then
	exit;
fi

orig=`echo $fs | cut -d/ -f3 | cut -d@ -f1`
pool=`echo $fs | cut -d/ -f1`

echo "clone $fs -- $orig to $veid";

clone=$pool/clone/$orig-$veid

vzctl stop $veid && (
	umount /$clone
	zfs list | grep ^$clone
	zfs destroy $clone
)

zfs clone $fs $pool/clone/$orig-$veid

vzctl start $veid

vzlist -a