<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>zomo tech</title>
	<atom:link href="http://www.zomo.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zomo.co.uk</link>
	<description>Is it done yet?</description>
	<lastBuildDate>Mon, 23 Apr 2012 02:27:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>URL handlers on OS X</title>
		<link>http://www.zomo.co.uk/2012/04/url-handlers-on-os-x/</link>
		<comments>http://www.zomo.co.uk/2012/04/url-handlers-on-os-x/#comments</comments>
		<pubDate>Fri, 20 Apr 2012 02:41:05 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=500</guid>
		<description><![CDATA[Update 2012-04-25 Corrected the plist key to CFBundleIdentifier. I&#8217;ve often wondered about how to do this without monkeying in Objective C. It&#8217;s doable in (ugh) Applescript with some property list editing. Whimsical XKCD handler such that xkcd://627 behaves like http://xckd.com/627: on open location uri &#160;&#160;set delimiter to AppleScript's text item delimiters &#160;&#160;set AppleScript's text item [...]]]></description>
			<content:encoded><![CDATA[<p><em>Update 2012-04-25</em> Corrected the <code>plist</code> key to <code>CFBundleIdentifier</code>.</p>
<p>I&#8217;ve often wondered about how to do this without monkeying in Objective C. It&#8217;s doable in (ugh) Applescript with some property list editing. Whimsical XKCD handler such that <a href="xkcd://627"><code>xkcd://627</code></a> behaves like <a href="http://xkcd.com/627"><code>http://xckd.com/627</code></a>:</p>
<p><code><br />
on open location uri<br />
&nbsp;&nbsp;set delimiter to AppleScript's text item delimiters<br />
&nbsp;&nbsp;set AppleScript's text item delimiters to "//"<br />
&nbsp;&nbsp;set comic to text item 2 of uri<br />
&nbsp;&nbsp;set page to "http://xkcd.com/" &#038; comic<br />
&nbsp;&nbsp;tell application "Safari"<br />
&nbsp;&nbsp;&nbsp;&nbsp;activate<br />
&nbsp;&nbsp;&nbsp;&nbsp;open location page<br />
&nbsp;&nbsp;end tell<br />
&nbsp;&nbsp;set AppleScript's text item delimiters to delimiter<br />
end open location<br />
</code></p>
<p>Save as an Application rather than a Script. Open its <code>info.plist</code> and add<br />
<code><br />
&nbsp;&lt;key&gt;CFBundleIdentifier&lt;/key&gt;<br />
&nbsp;&lt;string&gt;uk.co.zomo.xkcd-handler&lt;/string&gt;<br />
&nbsp;&lt;key&gt;CFBundleURLTypes&lt;/key&gt;<br />
&nbsp;&lt;array&gt;<br />
&nbsp;&nbsp;&lt;dict&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;key&gt;CFBundleURLName&lt;/key&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;string&gt;XKCD helper&lt;/string&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;key&gt;CFBundleURLSchemes&lt;/key&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;array&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;string&gt;xkcd&lt;/string&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/array&gt;<br />
&nbsp;&nbsp;&lt;/dict&gt;<br />
&nbsp;&lt;/array&gt;<br />
</code></p>
<p>To nudge OS X to notice changed a plist:<br />
<code><br />
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -v -f ~/Library/Scripts/xkcd-handler.app<br />
</code></p>
<p>Links:</p>
<ul>
<li><a href="http://applescript123.com/linktrigger/">http://applescript123.com/linktrigger/</a></li>
<li><a href="http://stackoverflow.com/questions/8981749/how-do-i-refresh-application-metadata-url-handlers-web-browsers-after-insta">http://stackoverflow.com/questions/8981749/how-do-i-refresh-application-metadata-url-handlers-web-browsers-after-insta</a></li>
<li><a href="http://www.rubicode.com/Software/RCDefaultApp/">http://www.rubicode.com/Software/RCDefaultApp/</a>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2012/04/url-handlers-on-os-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>httperf on Linux</title>
		<link>http://www.zomo.co.uk/2012/04/httperf-on-linux/</link>
		<comments>http://www.zomo.co.uk/2012/04/httperf-on-linux/#comments</comments>
		<pubDate>Mon, 16 Apr 2012 07:34:29 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[stash]]></category>
		<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=491</guid>
		<description><![CDATA[&#8220;httperf is a tool for measuring web server performance. It provides a flexible facility for generating various HTTP workloads and for measuring server performance.&#8221; Set open files to 65535 via ulimit -n Recompile httperf with /usr/include/bits/typesizes.h&#8216;s __FD_SETSIZE dialled up to 655351 Twiddle the TCP stack for faster socket recycling23 : echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle echo [...]]]></description>
			<content:encoded><![CDATA[<p>&#8220;<a href="http://code.google.com/p/httperf/" title="httperf">httperf</a> is a tool for measuring web server performance. It provides a flexible facility for generating various HTTP workloads and for measuring server performance.&#8221;</p>
<ul>
<li>Set open files to 65535 via <code>ulimit -n</code></li>
<li>Recompile <code>httperf</code> with <code>/usr/include/bits/typesizes.h</code>&#8216;s <code>__FD_SETSIZE</code> dialled up to 65535<sup><a href="http://www.zomo.co.uk/2012/04/httperf-on-linux/#footnote_0_491" id="identifier_0_491" class="footnote-link footnote-identifier-link" title=" http://gom-jabbar.org/articles/2009/02/04/httperf-and-file-descriptors ">1</a></sup> </li>
<li>Twiddle the TCP stack for faster socket recycling<sup><a href="http://www.zomo.co.uk/2012/04/httperf-on-linux/#footnote_1_491" id="identifier_1_491" class="footnote-link footnote-identifier-link" title=" http://www.speedguide.net/articles/linux-tweaking-121 ">2</a></sup><sup><a href="http://www.zomo.co.uk/2012/04/httperf-on-linux/#footnote_2_491" id="identifier_2_491" class="footnote-link footnote-identifier-link" title="http://serverfault.com/questions/331513/httperf-hangs-when-using-hog">3</a></sup> :<br />
<code><br />
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle<br />
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse<br />
</code><code></code></li>
</ul>
<ol class="footnotes"><li id="footnote_0_491" class="footnote"> http://gom-jabbar.org/articles/2009/02/04/httperf-and-file-descriptors </li><li id="footnote_1_491" class="footnote"> http://www.speedguide.net/articles/linux-tweaking-121 </li><li id="footnote_2_491" class="footnote">http://serverfault.com/questions/331513/httperf-hangs-when-using-hog</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2012/04/httperf-on-linux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Moving disks from Xen to KVM</title>
		<link>http://www.zomo.co.uk/2012/04/moving-disks-from-xen-to-kvm/</link>
		<comments>http://www.zomo.co.uk/2012/04/moving-disks-from-xen-to-kvm/#comments</comments>
		<pubDate>Sun, 08 Apr 2012 07:17:35 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[stash]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=477</guid>
		<description><![CDATA[Overview Moving virtual machines from Xen to KVM The storage for both is under LVM Under Xen the storage for each VM isn&#8217;t partitioned as a disk, it&#8217;s just a filesystem. GRUB under KVM will need to see a boot sector and a partition table. Under Xen the storage for each VM doesn&#8217;t contain a [...]]]></description>
			<content:encoded><![CDATA[<h3>Overview</h3>
<ul>
<li>Moving virtual machines from Xen to KVM</li>
<li>The storage for both is under LVM</li>
<li>Under Xen the storage for each VM isn&#8217;t partitioned as a disk, it&#8217;s just a filesystem. GRUB under KVM will need to see a boot sector and a partition table.</li>
<li>Under Xen the storage for each VM doesn&#8217;t contain a kernel. GRUB under KVM will need one to boot the VM.</li>
</ul>
<h3>Sequence</h3>
<ul>
<li>Measure disks on Xen server, create on KVM server. Create the new root disk 10MB larger than its counterpart.<sup><a href="http://www.zomo.co.uk/2012/04/moving-disks-from-xen-to-kvm/#footnote_0_477" id="identifier_0_477" class="footnote-link footnote-identifier-link" title=" Later we align the original root filesystem at cylinder 1 on this new disk. A LVM cylinder is roughly 8MB ">1</a></sup><br />
<code><br />
kyero@xen03 ~ $ sudo lvscan<br />
  ACTIVE            '/dev/vg4/mail-root' [20.00 GB] inherit<br />
  ACTIVE            '/dev/vg4/mail-swap' [1.00 GB] inherit<br />
</code><br />
<code><br />
[kyero@vm02 ~]$ sudo lvcreate -L20490M -n mail-root vg4<br />
[kyero@vm02 ~]$ sudo lvcreate -L2G -n mail-swap vg4<br />
</code>
</li>
<li>Create a boot disk on the KVM server. We make it 4 cylinders long, roughly 32MB.<sup><a href="http://www.zomo.co.uk/2012/04/moving-disks-from-xen-to-kvm/#footnote_1_477" id="identifier_1_477" class="footnote-link footnote-identifier-link" title=" File backed disk is used rather than LVM owing to grief with GRUB and LVM (Error 22: No such partition) ">2</a></sup><br />
<code><br />
[kyero@vm02 ~]$ sudo dd if=/dev/zero of=/var/boot-images/mail-boot bs=32901120 count=1<br />
</code>
</li>
<li>Partition the boot disk with one partition starting at cylinder zero<br />
<code><br />
[kyero@vm02 ~]$ sudo sfdisk /var/boot-images/mail-boot<br />
last_lba(): I don't know how to handle files with mode 81a4<br />
Warning: /var/boot-images/mail-boot is not a block device<br />
Disk /var/boot-images/mail-boot: cannot get geometry</p>
<p>Disk /var/boot-images/mail-boot: 4 cylinders, 255 heads, 63 sectors/track</p>
<p>sfdisk: ERROR: sector 0 does not have an msdos signature<br />
 /var/boot-images/mail-boot: unrecognized partition table type<br />
Old situation:<br />
No partitions found<br />
Input in the following format; absent fields get a default value.<br />
&lt;start&gt; &lt;size&gt; &lt;type [E,S,L,X,hex]&gt; &lt;bootable [-,*]&gt; &lt;c,h,s&gt; &lt;c,h,s&gt;\nUsually you only need to specify &lt;start&gt; and &lt;size&gt; (and perhaps &lt;type&gt;).</p>
<p>/var/boot-images/mail-boot1 :0<br />
/var/boot-images/mail-boot1          0+      3       4-     32129+  83  Linux<br />
/var/boot-images/mail-boot2 :<br />
/var/boot-images/mail-boot2          0       -       0          0    0  Empty<br />
/var/boot-images/mail-boot3 :<br />
/var/boot-images/mail-boot3          0       -       0          0    0  Empty<br />
/var/boot-images/mail-boot4 :<br />
/var/boot-images/mail-boot4          0       -       0          0    0  Empty<br />
New situation:<br />
Units = cylinders of 8225280 bytes, blocks of 1024 bytes, counting from 0</p>
<p>   Device Boot Start     End   #cyls    #blocks   Id  System<br />
/var/boot-images/mail-boot1          0+      3       4-     32129+  83  Linux<br />
/var/boot-images/mail-boot2          0       -       0          0    0  Empty<br />
/var/boot-images/mail-boot3          0       -       0          0    0  Empty<br />
/var/boot-images/mail-boot4          0       -       0          0    0  Empty<br />
Warning: no primary partition is marked bootable (active)<br />
This does not matter for LILO, but the DOS MBR will not boot this disk.<br />
Do you want to write this to disk? [ynq] y<br />
Successfully wrote the new partition table</p>
<p>Re-reading the partition table ...<br />
BLKRRPART: Inappropriate ioctl for device</p>
<p>If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)<br />
to zero the first 512 bytes:  dd if=/dev/zero of=/dev/foo7 bs=512 count=1<br />
(See fdisk(8).)</p>
<p></code>
</li>
<li>Format and mount the partition<br />
<code><br />
[kyero@vm02 ~]$ sudo kpartx -av /var/boot-images/mail-boot<br />
add map loop1p1 : 0 64259 linear /dev/loop1 1</p>
<p>[kyero@vm02 ~]$ sudo mke2fs /dev/mapper/loop1p1<br />
mke2fs 1.39 (29-May-2006)<br />
Filesystem label=<br />
OS type: Linux<br />
Block size=1024 (log=0)<br />
Fragment size=1024 (log=0)<br />
8032 inodes, 32128 blocks<br />
1606 blocks (5.00%) reserved for the super user<br />
First data block=1<br />
Maximum filesystem blocks=33030144<br />
4 block groups<br />
8192 blocks per group, 8192 fragments per group<br />
2008 inodes per group<br />
Superblock backups stored on blocks:<br />
        8193, 24577</p>
<p>Writing inode tables: done<br />
Writing superblocks and filesystem accounting information: done</p>
<p>This filesystem will be automatically checked every 34 mounts or<br />
180 days, whichever comes first.  Use tune2fs -c or -i to override.</p>
<p>[kyero@vm02 ~]$ sudo mount /dev/mapper/loop1p1 /mnt/boot/</p>
<p>[kyero@vm02 ~]$ df -h /mnt/boot<br />
Filesystem            Size  Used Avail Use% Mounted on<br />
/dev/mapper/loop1p1    31M  389K   29M   2% /mnt/boot<br />
</code>
</li>
<li>Copy a kernel to it, configure GRUB&#8217;s notion of the root device and install the boot sector.<br />
<code><br />
[kyero@vm02 ~]$ sudo rsync -a /boot/ /mnt/boot/<br />
[kyero@vm02 ~]$ sudo vi /mnt/boot/grub/menu.lst<br />
[kyero@vm02 ~]$ sudo touch /mnt/boot/kvm-boot-image<br />
[kyero@vm02 ~]$ sudo grub --device-map=/dev/null</p>
<p>    GNU GRUB  version 0.97  (640K lower / 3072K upper memory)</p>
<p> [ Minimal BASH-like line editing is supported.  For the first word, TAB<br />
   lists possible command completions.  Anywhere else TAB lists the possible<br />
   completions of a device/filename.]<br />
grub> device (hd0) /var/boot-images/mail-boot<br />
device (hd0) /var/boot-images/mail-boot<br />
grub> find /kvm-boot-image<br />
find /kvm-boot-image<br />
 (hd0,0)<br />
grub> root (hd0,0)<br />
root (hd0,0)<br />
 Filesystem type is ext2fs, partition type 0x83<br />
grub> setup (hd0)<br />
setup (hd0)<br />
 Checking if "/boot/grub/stage1" exists... no<br />
 Checking if "/grub/stage1" exists... yes<br />
 Checking if "/grub/stage2" exists... yes<br />
 Checking if "/grub/e2fs_stage1_5" exists... yes<br />
 Running "embed /grub/e2fs_stage1_5 (hd0)"... failed (this is not fatal)<br />
 Running "embed /grub/e2fs_stage1_5 (hd0,0)"... failed (this is not fatal)<br />
Done.<br />
grub> quit</p>
<p>[kyero@vm02 ~]$ sudo umount /mnt/boot<br />
[kyero@vm02 ~]$ sudo kpartx -d /var/boot-images/mail-boot<br />
loop deleted : /dev/loop1</p>
<p></code></li>
<li>Populate the new root disk with one cylinder of zeros and a copy of the old root disk.<br />
The first cylinder will contain the MBR and not much else. The padding means it&#8217;s easy to align the old root disk at cylinder one.<br />
Use <code>pv</code> so we can see the copy progress.<br />
The <code>dd-lvm-out</code> script is mostly just a <code>sudo</code>-blessed wrapper.<br />
<code>[kyero@vm02 ~]$ ( dd if=/dev/zero bs=8225280 count=1 ; ssh xen03.local -l kyero sudo /data/system/bin/dd-lvm-out.sh mail-root ) | pv -e -r -s 21474836480 | sudo dd bs=1048577 of=/dev/vg4/mail-root<br />
1+0 records in<br />
1+0 records out<br />
8225280 bytes (8.2 MB) copied, 0.03395 seconds, 242 MB/s<br />
20480+0 records in<br />
20480+0 records out<br />
21474836480 bytes (21 GB) copied, 611.215 s, 35.1 MB/s<br />
0+662630 records in<br />
0+662630 records out<br />
21483061795 bytes (21 GB) copied, 615.249 seconds, 34.9 MB/s<br />
</code>
</li>
<li>Partition the new root disk with a single partition starting at cylinder one.<br />
<code>[kyero@vm02 ~]$ sudo sfdisk /dev/vg4/mail-root<br />
Checking that no-one is using this disk right now ...<br />
BLKRRPART: Invalid argument<br />
OK</p>
<p>Disk /dev/vg4/mail-root: 2614 cylinders, 255 heads, 63 sectors/track</p>
<p>sfdisk: ERROR: sector 0 does not have an msdos signature<br />
 /dev/vg4/mail-root: unrecognized partition table type<br />
Old situation:<br />
No partitions found<br />
Input in the following format; absent fields get a default value.<br />
&lt;start&gt; &lt;size&gt; &lt;type [E,S,L,X,hex]&gt; &lt;bootable [-,*]&gt; &lt;c,h,s&gt; &lt;c,h,s&gt;\nUsually you only need to specify &lt;start&gt; and &lt;size&gt; (and perhaps &lt;type&gt;).</p>
<p>/dev/vg4/mail-root1 :1<br />
/dev/vg4/mail-root1          1    2613    2613   20988922+  83  Linux<br />
/dev/vg4/mail-root2 :<br />
/dev/vg4/mail-root2          0+      0       1-      8032   83  Linux<br />
/dev/vg4/mail-root3 :<br />
/dev/vg4/mail-root3          0       -       0          0    0  Empty<br />
/dev/vg4/mail-root4 :<br />
/dev/vg4/mail-root4          0       -       0          0    0  Empty<br />
New situation:<br />
Units = cylinders of 8225280 bytes, blocks of 1024 bytes, counting from 0</p>
<p>   Device Boot Start     End   #cyls    #blocks   Id  System<br />
/dev/vg4/mail-root1          1    2613    2613   20988922+  83  Linux<br />
/dev/vg4/mail-root2          0+      0       1-      8032   83  Linux<br />
/dev/vg4/mail-root3          0       -       0          0    0  Empty<br />
/dev/vg4/mail-root4          0       -       0          0    0  Empty<br />
Warning: no primary partition is marked bootable (active)<br />
This does not matter for LILO, but the DOS MBR will not boot this disk.<br />
Do you want to write this to disk? [ynq] y<br />
Successfully wrote the new partition table</p>
<p>Re-reading the partition table ...<br />
BLKRRPART: Invalid argument</p>
<p>If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)<br />
to zero the first 512 bytes:  dd if=/dev/zero of=/dev/foo7 bs=512 count=1<br />
(See fdisk(8).)</p>
<p></code></li>
<li>Mount the new root filesystem<br />
<code>[kyero@vm02 ~]$ sudo kpartx -av /dev/vg4/mail-root<br />
add map mail-root1 : 0 41977845 linear /dev/vg4/mail-root 16065<br />
add map mail-root2 : 0 16064 linear /dev/vg4/mail-root 1<br />
[kyero@vm02 ~]$ sudo e2fsck /dev/mapper/mail-root1<br />
e2fsck 1.39 (29-May-2006)<br />
/dev/mapper/mail-root1: clean, 435213/1310720 files, 4086961/5242880 blocks</p>
<p>[kyero@vm02 ~]$ sudo mount /dev/mapper/mail-root1 /mnt/tmp<br />
</code></li>
<li>Add the new kernel&#8217;s modules, tweak filesystem mounts, disable swap, check console.<br />
<code><br />
[kyero@vm02 ~]$ sudo rsync -a /lib/modules/ /mnt/tmp/lib/modules/</p>
<p>[kyero@vm02 ~]$ sudo vi /mnt/tmp/etc/fstab</p>
<p>[kyero@vm02 ~]$ sudo vi /mnt/tmp/etc/inittab<br />
</code>
</li>
<li>Create the KVM guest, assigning the boot, root and swap storage<br />
<code>[kyero@vm02 ~]$ sudo virt-install -n mail -r 1024 --vcpus 1 --os-type linux --os-variant generic26 --accelerate --disk path=/var/boot-images/mail-boot --disk path=/dev/mapper/vg4-mail--root,bus=ide,format=raw --disk path=/dev/mapper/vg4-mail--swap,bus=ide,format=raw --network bridge:br0 --network bridge:br1 --import --noreboot<br />
Starting install...<br />
Guest installation complete... you can restart your domain<br />
by running 'virsh start mail'</p>
<p>[kyero@vm02 ~]$ sudo virsh dumpxml mail<br />
...<br />
    &lt;disk type='file' device='disk'&gt;<br />
      &lt;driver name='qemu' type='raw' cache='none'/&gt;<br />
      &lt;source file='/var/boot-images/mail-boot'/&gt;<br />
      &lt;target dev='hda' bus='ide'/&gt;<br />
      &lt;address type='drive' controller='0' bus='0' unit='0'/&gt;<br />
    &lt;/disk&gt;<br />
    &lt;disk type='block' device='disk'&gt;<br />
      &lt;driver name='qemu' type='raw' cache='none'/&gt;<br />
      &lt;source dev='/dev/mapper/vg4-mail--root'/&gt;<br />
      &lt;target dev='hdb' bus='ide'/&gt;<br />
      &lt;address type='drive' controller='0' bus='0' unit='1'/&gt;<br />
    &lt;/disk&gt;<br />
    &lt;disk type='block' device='disk'&gt;<br />
      &lt;driver name='qemu' type='raw' cache='none'/&gt;<br />
      &lt;source dev='/dev/mapper/vg4-mail--swap'/&gt;<br />
      &lt;target dev='hdd' bus='ide'/&gt;<br />
      &lt;address type='drive' controller='0' bus='1' unit='1'/&gt;<br />
    &lt;/disk&gt;<br />
...<br />
</code>
</li>
<li>Boot the KVM guest<br />
<code><br />
[kyero@vm02 ~]$ sudo virsh start mail<br />
[kyero@vm02 ~]$ sudo virsh autostart mail<br />
[kyero@vm02 ~]$ sudo virsh console mail<br />
</code>
</li>
<li>Log into KVM guest, partition <code>/dev/hdd</code> and configure it as swap, update <code>/etc/fstab</code>.
</li>
</ul>
<ol class="footnotes"><li id="footnote_0_477" class="footnote"> Later we align the original root filesystem at cylinder 1 on this new disk. A LVM cylinder is roughly 8MB </li><li id="footnote_1_477" class="footnote"> File backed disk is used rather than LVM owing to grief with GRUB and LVM (<code>Error 22: No such partition</code>) </li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2012/04/moving-disks-from-xen-to-kvm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Directory sizes and filesystems</title>
		<link>http://www.zomo.co.uk/2012/03/directory-sizes-and-filesystems/</link>
		<comments>http://www.zomo.co.uk/2012/03/directory-sizes-and-filesystems/#comments</comments>
		<pubDate>Mon, 19 Mar 2012 04:23:37 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=445</guid>
		<description><![CDATA[kyero@fs02 ~/log $ du -hs . 1.7M kyero@fs02 ~/log $ ls &#124; wc -l 24 kyero@fs02 ~/log $ ls -ild . 909313 drwxr-xr-x 2 kyero kyero 1630208 Mar 19 05:25 . This log directory was allowed to grow indefinitely (ahem) until I trimmed it this morning. Now it is mostly empty (1.7MB), but the directory [...]]]></description>
			<content:encoded><![CDATA[<p><code><br />
kyero@fs02 ~/log $ du -hs .<br />
1.7M<br />
kyero@fs02 ~/log $ ls | wc -l<br />
24<br />
kyero@fs02 ~/log $ ls -ild .<br />
909313 drwxr-xr-x 2 kyero kyero 1630208 Mar 19 05:25 .<br />
</code></p>
<p>This log directory was allowed to grow indefinitely (ahem) until I trimmed it this morning. Now it is mostly empty (1.7MB), but the directory <em>entry</em> is still huge (at 1.6MB, compared to the default 4kB). I had a vague idea of why this happens but realised I was unclear on the specifics so it was time for The Learning.</p>
<p>On traditional filesystems (here, FFS on FreeBSD and ext2 on GNU/Linux) directories look much like files, just with special content. They have an inode that points to either blocks on disk or to indirection blocks that themselves point to blocks (or to other indirection blocks, up to three levels of indirection). The contents of these directory blocks are reasonably straightforward: they&#8217;re a sequence of <a href="http://en.wikipedia.org/wiki/Dirent.h"><code>dirent</code></a> structures that generally contain a filename and that file&#8217;s inode number along with some small housekeeping data.</p>
<p>As a directory fills this sequence of <code>dirent</code>s grows to fill all the direct blocks, then starts on the indirect blocks and so on. Each time the sequence crosses a block boundary the directory&#8217;s own size, rather than the total of the files it contains, grows by another block. Since filenames have variable length a single block will contain a variable number of <code>dirent</code>s.</p>
<p>So far so good. What happens you delete a file from a directory? Other than freeing the actual file&#8217;s inode and respective blocks something must happen to its <code>dirent</code> entry in the directory&#8217;s data. What doesn&#8217;t happen is that the <code>dirent</code> is removed and all the ones after it get bumped towards the front of the list, which would lead to fewer overall directory blocks given enough deletions and ultimately smaller directories.</p>
<p>Why this doesn&#8217;t happen partly relates to the guarantees that <code>telldir</code> and friends make to programs with the directory open: a file&#8217;s relative position in the sequence of <code>dirent</code> will not change for any process that has the directory open. The deletion process can&#8217;t compact the directory itself without breaking that guarantee. Both FFS and ext2 blank out the file&#8217;s inode in the <code>dirent</code> record (<a href="http://fxr.watson.org/fxr/source/fs/ext2fs/ext2_lookup.c#L923">ext2 with zero,</a> <a href="http://fxr.watson.org/fxr/source/ufs/ufs/ufs_lookup.c?im=excerpts#L1182">FFS with a special value</a>). Subsequent directory operations will ignore this blanked <code>dirent</code>, and processes which knew its sequence number via <code>telldir</code> will error if they attempt operations on it.</p>
<p>To recover the disk space used by a directory that has ballooned and then contracted its simplest to simply delete it entirely and recreate it. ext2 has an option (<code>-D</code>) in its filesystem check to compact the directory offline.</p>
<p>Interestingly this behaviour isn&#8217;t present on all filesystems, particularly those that use indexes instead of special files for directories: for example ZFS and HFS+. They can remove a file&#8217;s entry in the directory index yet still keep the remaining files appearing at their same positions by informed updates to the index.</p>
<p>Here is these four filesystem&#8217;s compared by</p>
<ul>
<li>Creating an empty directory</li>
<li>Filling it with a million files</li>
<li>Removing all but one of those files</li>
</ul>
<p>The comparison shows how on ext2 and FFS the directory itself remains at its peak size after the test files are removed, whereas ZFS and HFS+ contract.</p>
<h3>ext2</h3>
<p><code>[build@centos-x86-64-build tmp]$ df -ih .<br />
Filesystem            Inodes   IUsed   IFree IUse% Mounted on<br />
/dev/sdb                1.3M      11    1.3M    1% /mnt/tmp<br />
[build@centos-x86-64-build tmp]$ ls -ild .<br />
2 drwxr-xr-x. 3 build build 4096 Mar 19 08:58 .</p>
<p>[build@centos-x86-64-build tmp]$ seq --format 'f%06g' 0 999999 | xargs touch<br />
[build@centos-x86-64-build tmp]$ df -ih .<br />
Filesystem            Inodes   IUsed   IFree IUse% Mounted on<br />
/dev/sdb                1.3M    977K    304K   77% /mnt/tmp<br />
[build@centos-x86-64-build tmp]$ ls -ild .<br />
2 drwxr-xr-x. 3 build build 23224320 Mar 19 08:59 .</p>
<p>[build@centos-x86-64-build tmp]$ seq --format 'f%06g' 0 999998 | xargs rm<br />
[build@centos-x86-64-build tmp]$ df -ih .<br />
Filesystem            Inodes   IUsed   IFree IUse% Mounted on<br />
/dev/sdb                1.3M      12    1.3M    1% /mnt/tmp<br />
[build@centos-x86-64-build tmp]$ ls -ild .<br />
2 drwxr-xr-x. 3 build build 23224320 Mar 19 09:02 .<br />
</code></p>
<h3>FFS</h3>
<p><code>[lemon@zest ~/tmp]$ df -ih .<br />
Filesystem            Size    Used   Avail Capacity iused ifree %iused  Mounted on<br />
/dev/mirror/gm0s1a     19G     10G    7.5G    58%    587k  2.1M   22%   /<br />
[lemon@zest ~/tmp]$ ls -ild .<br />
521826 drwxr-xr-x  2 lemon  lemon  512 Mar 19 14:50 .</p>
<p>[lemon@zest ~/tmp]$ jot -w "f%06d" 1000000 0 | xargs touch<br />
[lemon@zest ~/tmp]$ df -ih .<br />
Filesystem            Size    Used   Avail Capacity iused ifree %iused  Mounted on<br />
/dev/mirror/gm0s1a     19G     10G    7.5G    58%    1.6M  1.1M   60%   /<br />
[lemon@zest ~/tmp]$ ls -ild .<br />
521826 drwxr-xr-x  2 lemon  lemon  16000512 Mar 20 01:10 .</p>
<p>[lemon@zest ~/tmp]$ jot -w "f%06d" 999999 0 | xargs rm<br />
[lemon@zest ~/tmp]$ df -ih .<br />
Filesystem            Size    Used   Avail Capacity iused ifree %iused  Mounted on<br />
/dev/mirror/gm0s1a     19G     10G    7.5G    58%    587k  2.1M   22%   /<br />
[lemon@zest ~/tmp]$ ls -ild .<br />
521826 drwxr-xr-x  2 lemon  lemon  16000512 Mar 20 01:44 .<br />
</code></p>
<h3>ZFS</h3>
<p><code>[lemon@zest /mnt/ark/tmp]$ df -ih .<br />
Filesystem    Size    Used   Avail Capacity iused ifree %iused  Mounted on<br />
ark           207G    686M    206G     0%     58k  432M    0%   /mnt/ark<br />
[lemon@zest /mnt/ark/tmp]$ ls -ild<br />
5 drwxrwsr-x  2 root  wheel  2 Mar 20 06:18 .</p>
<p>[lemon@zest /mnt/ark/tmp]$ jot -w "f%06d" 1000000 0 | xargs touch<br />
[lemon@zest /mnt/ark/tmp]$ df -ih .<br />
Filesystem    Size    Used   Avail Capacity iused ifree %iused  Mounted on<br />
ark           207G    859M    206G     0%    1.1M  432M    0%   /mnt/ark<br />
[lemon@zest /mnt/ark/tmp]$ ls -ild .<br />
5 drwxrwsr-x  2 root  wheel  1000002 Mar 20 07:53 .</p>
<p>[lemon@zest /mnt/ark/tmp]$ jot -w "f%06d" 999999 0 | xargs rm<br />
[lemon@zest /mnt/ark/tmp]$ df -ih .<br />
Filesystem    Size    Used   Avail Capacity iused ifree %iused  Mounted on<br />
ark           207G    727M    206G     0%     58k  432M    0%   /mnt/ark<br />
[lemon@zest /mnt/ark/tmp]$ ls -ild<br />
5 drwxrwsr-x  2 root  wheel  3 Mar 20 09:27 .<br />
</code></p>
<h3>HFS+</h3>
<p><code><br />
[lemon@further tmp] 0 $ df -ih .<br />
Filesystem   Size   Used  Avail Capacity  iused    ifree %iused  Mounted on<br />
/dev/disk1  233Gi  185Gi   48Gi    80% 48506927 12484688   80%   /<br />
[lemon@further tmp] 0 $ ls -ild .<br />
12149971 drwxr-xr-x  2 lemon  staff  68 19 Mar 16:06 .</p>
<p>[lemon@further tmp] 0 $ jot -w "f%06d" 1000000 0 | xargs touch<br />
[lemon@further tmp] 0 $ df -ih .<br />
Filesystem   Size   Used  Avail Capacity  iused    ifree %iused  Mounted on<br />
/dev/disk1  233Gi  185Gi   48Gi    80% 48492686 12498929   80%   /<br />
[lemon@further tmp] 0 $ ls -ild .<br />
12149971 drwxr-xr-x  2 lemon  staff  34000068 19 Mar 17:32 .</p>
<p>[lemon@further tmp] 0 $ jot -w "f%06d" 999999 0 | xargs rm<br />
[lemon@further tmp] 0 $ df -ih .<br />
Filesystem   Size   Used  Avail Capacity  iused    ifree %iused  Mounted on<br />
/dev/disk1  233Gi  185Gi   48Gi    80% 48524492 12467123   80%   /<br />
[lemon@further tmp] 0 $ ls -ild .<br />
12149971 drwxr-xr-x  2 lemon  staff  102 19 Mar 19:08 .<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2012/03/directory-sizes-and-filesystems/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>pf on OS X 10.7</title>
		<link>http://www.zomo.co.uk/2011/09/pf-on-os-x-10-7/</link>
		<comments>http://www.zomo.co.uk/2011/09/pf-on-os-x-10-7/#comments</comments>
		<pubDate>Wed, 14 Sep 2011 07:54:18 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>
		<category><![CDATA[10.6]]></category>
		<category><![CDATA[10.7]]></category>
		<category><![CDATA[ipfw]]></category>
		<category><![CDATA[lion]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[pf]]></category>
		<category><![CDATA[snow leopard]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=423</guid>
		<description><![CDATA[Today&#8217;s the first day that my new laptop, which runs OS X 10.7 (Lion), will sit on an untrusted network so I figured it was time to port my firewall rules across from the old one, that ran OS X 10.6 (Snow Leopard). I cut my UNIX teeth at a cryptoanarchist shop whose culture of [...]]]></description>
			<content:encoded><![CDATA[<p>Today&#8217;s the first day that my new laptop, which runs OS X 10.7 (Lion), will sit on an untrusted network so I figured it was time to port my firewall rules across from the old one, that ran OS X 10.6 (Snow Leopard).</p>
<p>I cut my UNIX teeth at a cryptoanarchist shop whose culture of paranoia makes me wary of Apple&#8217;s own firewall with its emphasis on letting all the hot shinyness Just Work rather than being overly fussy about inbound connections. Furthermore, with IPv6 tunnels like <a href="http://www.sixxs.net/tools/aiccu/">aiccu</a>, you aren&#8217;t behind the warm fuzzy comfort of NAT, you&#8217;re just there on the net with all the fun that entails. So, worth having some extra protection I reckon.</p>
<p>10.6 (and earlier) came with <a href="http://www.freebsd.org/cgi/man.cgi?ipfw"><code>ipfw</code></a>, a packet filter that&#8217;s knocked around the BSD world for some time. It works but isn&#8217;t overly featuresome (for example, it doesn&#8217;t support NAT in-kernel, so you monkey about passing packets to <a href="http://www.freebsd.org/cgi/man.cgi?natd">an external daemon</a>). But it was Good Enough for an end system so I supplemented the system&#8217;s &#8220;Application Firewall&#8221; with an additional <code>ipfw</code> ruleset to give an approximation of safety when out and about, and way more permissive when on networks I trust.</p>
<p>On 10.6 I used <a href="http://www.hanynet.com/waterroof/">WaterRoof</a> to sort-of manage the <code>ipfw</code> rules: in that I only really used its <a href="http://en.wikipedia.org/wiki/Launchd">launchd</a> loader and would hack on the rules by hand. In the spirit of decrufting I figured I&#8217;d sort that myself and went to remind myself how to load <code>ipfw</code> rules enmasse. I noticed at the top of man page:<br />
<code><br />
NAME<br />
     ipfw -- IP firewall and traffic shaper control program (DEPRECATED)<br />
...<br />
DESCRIPTION<br />
     Note that use of this utility is DEPRECATED. Please use pfctl(8) instead<br />
</code></p>
<p>Deprecated? Use <code>pfctl</code> instead? <a href="http://www.zomo.co.uk/wp-content/uploads/2011/09/good-news.jpg">Good news everyone</a> &#8211; OS X 10.7 now comes with <code>pf</code>, another BSD packet filter that I&#8217;ve chosen of <code>ipfw</code> on BSD hosts for years off the back of its featureset (native NAT, state syncing between failover firewall pairs, traffic queing&#8230;).</p>
<p>Anyway, the point of this post is to point out a few things I noticed which are intriguing. Firstly, <code>pf</code> is not enabled by default. Further, Apple have added some moving parts around how it <em>is</em> enabled. From <code>/etc/pf.conf</code>:<br />
<code><br />
# This file contains the main ruleset, which gets automatically loaded<br />
# at startup.  PF will not be automatically enabled, however.  Instead,<br />
# each component which utilizes PF is responsible for enabling and disabling<br />
# PF via -E and -X as documented in pfctl(8).  That will ensure that PF<br />
# is disabled only when the last enable reference is released.<br />
</code><br />
These two flags, <code>-E</code> and <code>-X</code>, are absent from <code>pf</code> on BSD. Here&#8217;s how they&#8217;re documented on OS X:<br />
<code><br />
     -E      Enable the packet filter and increment the pf enable reference count.<br />
     -X token<br />
             Release the pf enable reference represented by the token passed.<br />
</code><br />
This suggests that different system components might choose to enable and disable <code>pf</code>, and this is the mechanism to coordinate that. There&#8217;s a clue about which components in <code>/etc/pf.anchors/com.apple</code>, which is loaded by the main <code>/etc/pf.conf</code>. It defines additional rule anchors:<br />
<code><br />
anchor "100.InternetSharing/*"<br />
anchor "200.AirDrop/*"<br />
anchor "250.ApplicationFirewall/*"<br />
</code></p>
<p>Interestingly, this host&#8217;s ApplicationFirewall has a bunch of entries in when viewed in the Preferences GUI, yet the <code>pf</code> anchor of the same name is empty (and <code>pf</code> was disabled when I started out):<br />
<code><br />
$ sudo pfctl -a com.apple/250.ApplicationFirewall -s rules<br />
Password:<br />
No ALTQ support in kernel<br />
ALTQ related functions disabled<br />
</code><br />
so I&#8217;m unsure what the status of this mechanism is. I&#8217;ve not had occasion to use AirDrop or connection sharing, but would be curious to see if either use these anchors and enable <code>pf</code> temporarily.</p>
<p>Finally, what&#8217;s the token that&#8217;s passed to <code>-X</code>? You can ask <code>pfctl</code> for the current tokens:<br />
<code><br />
$ sudo pfctl -s References<br />
No ALTQ support in kernel<br />
ALTQ related functions disabled<br />
TOKENS:<br />
PID      Process Name                 TOKEN                    TIMESTAMP<br />
17013    pfctl                        18446743524308110600     0 days 01:05:50<br />
</code><br />
I enabled <code>pf</code> with <code>pfctl</code>, so that makes sense. When I did so it didn&#8217;t inform me of the token, but I suppose an enabling process would spelunk the token shortly after enabling <code>pf</code> by merit of its name and <code>PID</code> and pass it back when it&#8217;s finished with <code>pf</code>.</p>
<p>Now, on with the actual job of ruleset writing and puzzling out the <code>launchd</code> voodoo required to enable it at boot.</p>
<p>Minor whinge: Apple could do with updating <code>/etc/protocols</code>:<br />
<code><br />
# $FreeBSD: src/etc/protocols,v 1.14 2000/09/24 11:20:27 asmodai Exp $<br />
</code><br />
Why whinge? It doesn&#8217;t know <code>icmp6</code> is a valid alias for <code>ipv6-icmp</code>. Yep, minor.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2011/09/pf-on-os-x-10-7/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Cyrus saslauthd and passwords containing quote marks</title>
		<link>http://www.zomo.co.uk/2011/06/cyrus-saslauthd-and-passwords-containing-quote-marks/</link>
		<comments>http://www.zomo.co.uk/2011/06/cyrus-saslauthd-and-passwords-containing-quote-marks/#comments</comments>
		<pubDate>Sat, 11 Jun 2011 15:33:06 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=404</guid>
		<description><![CDATA[n the back of reading how affordable and powerful GPUs make for insanely fast brute-force software (eg: whitepixel2) I recently did a round of password strengthening, even for accounts that aren&#8217;t immediately vulnerable to 30 billion MD5s a second (yes!) attacks. I then found then whenever I sent mail using authenticated SMTP my mail server [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://jhische.com/dailydropcap/O-10-cap.png" title="Daily Drop Cap by Jessica Hische" align="left" alt="O"/>n the back of reading how affordable and powerful GPUs make for insanely fast brute-force software (eg: <a href="http://blog.zorinaq.com/?e=43">whitepixel2</a>) I recently did a round of password strengthening, even for accounts that aren&#8217;t immediately vulnerable to 30 billion MD5s a second (yes!) attacks.</p>
<p>I then found then whenever I sent mail using authenticated SMTP my mail server would lock up with <code>saslauthd</code> chewing the CPU. This authentication daemon is the glue between the MTA (<a href="http://www.exim.org/">Exim</a>) and the IMAP server (<a href="http://www.courier-mta.org/imap/">Courier</a>) &#8211; it logs into the IMAP service to test the SMTP user&#8217;s credentials. This little kink of indirection comes about because the IMAP daemon is downstream from the Exim host, in a <a href="http://en.wikipedia.org/wiki/FreeBSD_jail">BSD jail</a> host, so its own authentication mechanisms aren&#8217;t visible to the MTA.</p>
<p>My new mail password contained a double-quote mark, which made me wonder if the password wasn&#8217;t being quoted properly. Testing a bit with <code>openssl</code>:<br />
<code><br />
$ openssl s_client -starttls smtp -connect localhost:25<br />
CONNECTED(00000003)<br />
---<br />
250 HELP<br />
EHLO localhost<br />
250-svc9.zomo.co.uk Hello localhost [127.0.0.1]<br />
250-SIZE 52428800<br />
250-PIPELINING<br />
250-AUTH PLAIN LOGIN<br />
250 HELP<br />
AUTH PLAIN AGZvbwAi < -- this is Base64 for username foo, password "</p>
<p>[ hang ]</p>
<p></code><br />
Compiling a </code><code>-g</code> debug variant of the daemon and aiming <code>gdb</code> at it:<br />
<code><br />
$ sudo gdb /usr/local/sbin/saslauthd-debug 97103<br />
GNU gdb 6.1.1 [FreeBSD]<br />
Copyright 2004 Free Software Foundation, Inc.<br />
...<br />
(gdb) bt<br />
#0  0x284250d1 in strchr () from /lib/libc.so.7<br />
#1  0x0804a823 in qstring ()<br />
#2  0x0804ac45 in auth_rimap ()<br />
#3  0x0804f8e3 in do_auth ()<br />
#4  0x0804e1f4 in do_request ()<br />
#5  0x0804e53b in ipc_loop ()<br />
#6  0x0805018d in main ()<br />
</code></p>
<p>What&#8217;s <code>qstring()</code>? It&#8217;s a function for escaping the quote marks in strings passed to the IMAP daemon. Turns out count-the-quotemark logic wasn&#8217;t properly advancing along the string, so it would sit there spinning forever.<br />
<script src="https://gist.github.com/1020643.js"> </script><br />
Trivial patch<sup><a href="http://www.zomo.co.uk/2011/06/cyrus-saslauthd-and-passwords-containing-quote-marks/#footnote_0_404" id="identifier_0_404" class="footnote-link footnote-identifier-link" title="Gist if it&amp;#8217;s not inlined above">1</a></sup> fixes:<br />
<code><br />
$ openssl s_client -starttls smtp -connect localhost:25<br />
CONNECTED(00000003)<br />
---<br />
250 HELP<br />
EHLO localhost<br />
250-svc9.zomo.co.uk Hello localhost [127.0.0.1]<br />
250-SIZE 52428800<br />
250-PIPELINING<br />
250-AUTH PLAIN LOGIN<br />
250 HELP<br />
AUTH PLAIN AGZvbwAi<br />
535 Incorrect authentication data<br />
</code></p>
<p>Better :)</p>
<ol class="footnotes"><li id="footnote_0_404" class="footnote"><a href="https://gist.github.com/1020643">Gist</a> if it&#8217;s not inlined above</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2011/06/cyrus-saslauthd-and-passwords-containing-quote-marks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Competing webserver workloads</title>
		<link>http://www.zomo.co.uk/2011/02/competing-webserver-workloads/</link>
		<comments>http://www.zomo.co.uk/2011/02/competing-webserver-workloads/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 21:57:30 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=363</guid>
		<description><![CDATA[Recently a client was receiving complaints that their busy server hosting both their WordPress sites and their OpenX1 banner delivery was underperforming. Specifically, sites including their banners were seeing page loads hang on them. If you&#8217;re in the business of selling banners this is bad news. There were reports of the WordPress sites being slow [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css"><!--
th,td { font-size: 10px; align: center;}
li { margin-top: 0.25em; margin-right: 2em;}
.hr {margin-top: 0.25em; border-color: black; border-bottom-style: solid;}
.titre	{background: #20D0D0;color: #000000; font-weight: bold;}
.total	{background: #20D0D0;color: #ffff80;}
.frontend	{background: #e8e8d0;}
.backend	{background: #e8e8d0;}
.active0	{background: #ff9090;}
.active1	{background: #ffd020;}
.active2	{background: #ffffa0;}
.active3	{background: #c0ffc0;}
.active4	{background: #ffffa0;}
.active5	{background: #a0e0a0;}
.active6	{background: #e0e0e0;}
.backup0	{background: #ff9090;}
.backup1	{background: #ff80ff;}
.backup2	{background: #c060ff;}
.backup3	{background: #b0d0ff;}
.backup4	{background: #c060ff;}
.backup5	{background: #90b0e0;}
.backup6	{background: #e0e0e0;}
.rls      {letter-spacing: 0.2em; margin-right: 1px;}
table.tbl { border-collapse: collapse; border-style: none;}
table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray;}
table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}
table.tbl th.pxname {background: #b00040; color: #ffff40; font-weight: bold; border-style: solid solid none solid; padding: 2px 3px; white-space: nowrap;}
table.tbl th.empty { border-style: none; empty-cells: hide; background: white;}
table.tbl th.desc { background: white; border-style: solid solid none solid; text-align: left; padding: 2px 3px;}
table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}
table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}
table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}
-->
</style>
<p>Recently a client was receiving complaints that their busy server hosting both their <a href="http://wordpress.org/">WordPress</a> sites and their <a href="http://www.openx.org/">OpenX</a><sup><a href="http://www.zomo.co.uk/2011/02/competing-webserver-workloads/#footnote_0_363" id="identifier_0_363" class="footnote-link footnote-identifier-link" title=" advertising is a necessary evil, right? ">1</a></sup>  banner delivery was underperforming. Specifically, sites including their banners were seeing page loads hang on them. If you&#8217;re in the business of selling banners this is bad news. There were reports of the WordPress sites being slow too, but mostly from administrators<sup><a href="http://www.zomo.co.uk/2011/02/competing-webserver-workloads/#footnote_1_363" id="identifier_1_363" class="footnote-link footnote-identifier-link" title=" and that turned out to be a pagination issue ">2</a></sup> rather than site visitors.</p>
<p>I sorted out a bunch of <a href="http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/">request amplification issues</a> but still things still weren&#8217;t right, so I added a second server to help out. Instead of just chucking the combined traffic at both servers I used <a href="http://haproxy.1wt.eu/">HAProxy</a> to separate out the traffic to each, with a view to adding more OpenX servers as necessary.</p>
<p>Here&#8217;s what HAProxy&#8217;s stats had to say after some time running the sites split:</p>
<table class="tbl" width="100%">
<tbody>
<tr class="titre" align="center">
<th class="pxname" width="10%">wordpress</th>
</tr>
<tr class="titre" align="center">
<th rowspan="2"></th>
<th colspan="3">Queue</th>
<th colspan="3">Session rate</th>
<th colspan="5">Sessions</th>
<th colspan="2">Bytes</th>
</tr>
<tr class="titre" align="center">
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Total</th>
<th>LbTot</th>
<th>In</th>
<th>Out</th>
</tr>
<tr class="active3" align="center">
<td>app01</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">-</td>
<td align="right">1</td>
<td align="right">367</td>
<td align="right"></td>
<td align="right">2</td>
<td align="right">454</td>
<td align="right">-</td>
<td align="right"><span class="rls">1</span>75<span class="rls">8</span>026</td>
<td align="right"><span class="rls">1</span>75<span class="rls">8</span>026</td>
<td align="right"><span class="rls">1</span>33<span class="rls">6</span>54<span class="rls">1</span>933</td>
<td align="right">3<span class="rls">0</span>06<span class="rls">2</span>77<span class="rls">7</span>594</td>
</tr>
</tbody>
</table>
<table class="tbl" width="100%">
<tbody>
<tr class="titre" align="center">
<th class="pxname" width="10%">openx</th>
</tr>
<tr class="titre" align="center">
<th rowspan="2"></th>
<th colspan="3">Queue</th>
<th colspan="3">Session rate</th>
<th colspan="5">Sessions</th>
<th colspan="2">Bytes</th>
</tr>
<tr class="titre" align="center">
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Total</th>
<th>LbTot</th>
<th>In</th>
<th>Out</th>
</tr>
<tr class="active3" align="center">
<td>app02</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">-</td>
<td align="right">19</td>
<td align="right">45</td>
<td align="right"></td>
<td align="right">3</td>
<td align="right">75</td>
<td align="right">-</td>
<td align="right"><span class="rls">5</span>58<span class="rls">8</span>327</td>
<td align="right"><span class="rls">5</span>58<span class="rls">8</span>293</td>
<td align="right"><span class="rls">4</span>21<span class="rls">6</span>68<span class="rls">7</span>748</td>
<td align="right">1<span class="rls">1</span>87<span class="rls">8</span>95<span class="rls">1</span>168</td>
</tr>
</tbody>
</table>
<p>Some of these I found unsurprising &#8211; WordPress serves a higher volume of data, it is content heavy compared to banner delivery and related click handling. Conversely the inbound data volume for OpenX is up because it&#8217;s loaded with click information.</p>
<p>What&#8217;s interesting is that the WordPress sites have a higher maximum concurrent session count, yet the total sessions is far higher for the OpenX banners. This illustrates the benefit of separating out different server loads: one server is churning away pushing out fat content and even when heavily cached this burns enough resource that requests get queued and gum up, whilst another is fielding quick-in quick-out requests. When it&#8217;s not contending with its laggard sibling it can get on with its business unhindered.</p>
<p>Ultimately the visibility HAProxy affords beats an Apache <a href="http://httpd.apache.org/docs/2.2/mod/mod_status.html">scoreboard</a> when that Apache is fielding two differently focused workloads.</p>
<ol class="footnotes"><li id="footnote_0_363" class="footnote"> advertising is a necessary evil, right? </li><li id="footnote_1_363" class="footnote"> and that turned out to be a <a href="http://twitter.com/zomoco/status/32487132966686720">pagination</a> issue </li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2011/02/competing-webserver-workloads/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Timeouts and failing fast</title>
		<link>http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/</link>
		<comments>http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/#comments</comments>
		<pubDate>Sun, 23 Jan 2011 20:57:24 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=301</guid>
		<description><![CDATA[&#8220;Integration points are the number-one killer of systems&#8221; &#8211; Release It!, Michael Nygard Last week I had two different web systems fail in a similar way. One was a single box running two busy WordPress sites, another was a largish multi-tier publishing cluster. Both dropped off air because they didn&#8217;t handle the failure of a [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>&#8220;Integration points are the number-one killer of systems&#8221; &#8211; <a href="http://pragprog.com/titles/mnee/release-it">Release It!</a>, Michael Nygard</p></blockquote>
<p>Last week I had two different web systems fail in a similar way. One was a single box running two busy <a href="http://wordpress.org/">WordPress</a> sites, another was a largish multi-tier publishing cluster. Both dropped off air because they didn&#8217;t handle the failure of a remote system very well. In particular, both had the webserver waiting on a HTTP request to a foreign site to complete before returning a page to the client.</p>
<p>The architecture issues with this kind of request amplification are reasonably clear, and can sometimes be avoided. Data ingest from other systems can often execute asynchronously in another process. The cluster mentioned has a set of machines dedicated to just this, distributing the data they retrieve from remote systems via database and shared filesystem ready for the webservers to use when building pages.</p>
<p>However, in the situations where it is necessary for a webserver to dial out to another system at request time then it&#8217;s worth being really paranoid about how that outbound request works and untrusting of the reply. The particular problem here was lack of timeouts.</p>
<p>Here, both systems were running <a href="http://httpd.apache.org/docs/2.2/mod/prefork.html">mpm_prefork</a> <a href="http://httpd.apache.org">Apache</a>. Both were serving a request that made a HTTP call somewhere else before returning the page to the client<sup><a href="http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/#footnote_0_301" id="identifier_0_301" class="footnote-link footnote-identifier-link" title="One of the WordPress sites was doing this in every page&amp;#8217;s footer. And not caching the result. Better still, it was contacting the other WordPress site on the same server. This almost guarantees the request won&amp;#8217;t return when the shared webserver gets busy since there may be no spare server slots to accept the second request. Ouch.">1</a></sup>. Last week the remote sites that both these systems contact had outages, leaving Apache waiting for the reply up until the request timed out.</p>
<p>However, with no timeout configured that wait is effectively infinite. Long enough for these hanging Apache processes to consume all the available slots of the webserver, resulting an interesting set of observations:</p>
<ul>
<li>New TCP connections to the server just hang.</li>
<li>Server load is low, because the load measures runnable processes (and, on Linux, uninterruptible sleeping processes), and these hanging processes are just sleeping, waiting on <code>poll(2)</code> or <code>select(2)</code>.</li>
<li>No errors are logged by Apache or the application code because they haven&#8217;t failed yet.<sup><a href="http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/#footnote_1_301" id="identifier_1_301" class="footnote-link footnote-identifier-link" title="If you don&amp;#8217;t run Apache hot, then you&amp;#8217;d see a &amp;#8220;I&amp;#8217;ve reached MaxClients&amp;#8221; message in the error log, but not much else.">2</a></sup> </li>
</ul>
<p>Here&#8217;s some <code>vmstat</code> during such a wedge:<br />
<code><br />
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----<br />
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa<br />
 0  0 140580  56528  58168 516184    0    0     0     0 1026   78  0  0 100  0  0<br />
 0  0 140580  56528  58168 516184    0    0     0     0 1032   80  0  0 100  0  0<br />
 0  0 140580  56528  58168 516184    0    0     0     0 1031   78  0  0 100  0  0<br />
</code><br />
&#8220;It was quiet. <strong>Too</strong> quiet&#8221;. Hook up <code>gdb</code> and you can see what&#8217;s going on:<br />
<code><br />
(gdb) bt<br />
#0  0x00002aafffb7d14f in poll () from /lib64/libc.so.6<br />
#1  0x00002ab0090b3930 in Curl_select () from /usr/lib64/libcurl.so.3<br />
#2  0x00002ab0090ac4bc in Curl_perform () from /usr/lib64/libcurl.so.3<br />
#3  0x00002ab00850591b in zif_curl_exec () from /etc/httpd/modules/libphp5.so<br />
#4  0x00002ab0086663b2 in ?? () from /etc/httpd/modules/libphp5.so<br />
#5  0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#6  0x00002ab00865dc09 in ?? () from /etc/httpd/modules/libphp5.so<br />
#7  0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#8  0x00002ab008688750 in ?? () from /etc/httpd/modules/libphp5.so<br />
#9  0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#10 0x00002ab00865dc09 in ?? () from /etc/httpd/modules/libphp5.so<br />
#11 0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#12 0x00002ab00865c11e in ?? () from /etc/httpd/modules/libphp5.so<br />
#13 0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#14 0x00002ab0086395de in zend_execute_scripts () from /etc/httpd/modules/libphp5.so<br />
#15 0x00002ab0085fe697 in php_execute_script () from /etc/httpd/modules/libphp5.so<br />
#16 0x00002ab0086b6ad6 in ?? () from /etc/httpd/modules/libphp5.so<br />
#17 0x00002aaffdbb7a4a in ap_run_handler ()<br />
#18 0x00002aaffdbbaed8 in ap_invoke_handler ()<br />
#19 0x00002aaffdbc578a in ap_internal_redirect ()<br />
#20 0x00002ab0069ffbc0 in ap_make_dirstr_parent () from /etc/httpd/modules/mod_rewrite.so<br />
#21 0x00002aaffdbb7a4a in ap_run_handler ()<br />
#22 0x00002aaffdbbaed8 in ap_invoke_handler ()<br />
#23 0x00002aaffdbc5938 in ap_process_request ()<br />
#24 0x00002aaffdbc2b70 in ?? ()<br />
#25 0x00002aaffdbbecd2 in ap_run_process_connection ()<br />
#26 0x00002aaffdbc9789 in ?? ()<br />
#27 0x00002aaffdbc9a1a in ?? ()<br />
#28 0x00002aaffdbc9ad0 in ?? ()<br />
#29 0x00002aaffdbca7bb in ap_mpm_run ()<br />
#30 0x00002aaffdba4e48 in main ()<br />
</code></p>
<p>Another kink is that a <a href="http://httpd.apache.org/docs/2.2/stopping.html#graceful">graceful</a> restart of Apache, via <code>SIGUSR1</code>, doesn&#8217;t work since a graceful restart waits for a request to finish &#8211; and these ones aren&#8217;t finishing. <code>apachectl</code> or <code>service(8)</code> scripts will exit but the hung processes remain. These long running wedged processes are also visible in <code>ps</code>:<br />
<code><br />
apache     580  0.0  0.3  30332  5492 ?        S    Jan02   0:00<br />
/usr/sbin/httpd<br />
</code><br />
and can be matched up with the hung connections via <code>netstat -anp</code><br />
<code><br />
tcp        0      0 172.18.74.113:50129         192.0.32.10:80<br />
    ESTABLISHED 580/httpd<br />
</code></p>
<p>This is a mostly a long winded way of pointing out the importance of timeouts on code that executes during a request, particularly when doing something non-local. Fail fast!</p>
<p>To keep the WordPress sites running I ran through the code adding <code>CURLOPT_CONNECTTIMEOUT</code>, <code>CURLOPT_TIMEOUT</code> settings to all the cURL calls I could find, and the development team took care of the code running on the cluster. Both have been stable since.</p>
<p>There are plenty of other pitfalls in these integration points between systems. Michael Nygard&#8217;s book, linked at top, makes a good survey of them alongside other stability antipatterns in complex systems. It&#8217;s a recommended read.</p>
<ol class="footnotes"><li id="footnote_0_301" class="footnote">One of the WordPress sites was doing this in every page&#8217;s footer. And not caching the result. Better still, it was contacting the other WordPress site on the same server. This almost guarantees the request won&#8217;t return when the shared webserver gets busy since there may be no spare server slots to accept the second request. Ouch.</li><li id="footnote_1_301" class="footnote">If you don&#8217;t run Apache hot, then you&#8217;d see a &#8220;I&#8217;ve reached <code>MaxClients</code>&#8221; message in the error log, but not much else.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FreeBSD, gettext, libintl and bash</title>
		<link>http://www.zomo.co.uk/2010/10/freebsd-gettext-libintl-and-bash/</link>
		<comments>http://www.zomo.co.uk/2010/10/freebsd-gettext-libintl-and-bash/#comments</comments>
		<pubDate>Mon, 25 Oct 2010 07:06:31 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=265</guid>
		<description><![CDATA[Login surprise! Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD 8.0-RELEASE-p4 (GENERIC) #0: Mon Jul 12 20:22:27 UTC 2010 /libexec/ld-elf.so.1: Shared object "libintl.so.8" not found, required by "bash" $ What&#8217;s happened here is that gettext (which provides libintl.so) has been upgraded without [...]]]></description>
			<content:encoded><![CDATA[<p>Login surprise!</p>
<pre>Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
        The Regents of the University of California.  All rights reserved.

FreeBSD 8.0-RELEASE-p4 (GENERIC) #0: Mon Jul 12 20:22:27 UTC 2010

/libexec/ld-elf.so.1: Shared object "libintl.so.8" not found, required by "bash"
$
</pre>
<p>What&#8217;s happened here is that <a href="http://www.gnu.org/software/gettext/"><code>gettext</code></a> (which provides <code>libintl.so</code>) has been upgraded without its dependencies noticing (read: I messed up some package maintenance). These dependencies are linked against a specific version of this library that&#8217;s now gone. One of these dependencies is <a href="http://www.gnu.org/software/bash/"><code>bash</code></a>, my preferred shell.</p>
<p>Having your shell asplode like that is ungood. If <code>bash</code> has been set as my default shell then I wouldn&#8217;t be able to log in at all! This is a risk of relying on software that isn&#8217;t part of FreeBSD&#8217;s core to absolutely always work across system maintenance. <code>bash</code> is a third-party <a href="http://www.freebsd.org/ports/index.html">port</a>, and it&#8217;s prudent to anticipate package management fail<sup><a href="http://www.zomo.co.uk/2010/10/freebsd-gettext-libintl-and-bash/#footnote_0_265" id="identifier_0_265" class="footnote-link footnote-identifier-link" title="because all package management sucks at some point, yes?">1</a></sup>. </p>
<p>To side-step this risk I tend to set my shell to something that <i>is</i> native to a FreeBSD release (plain ole&#8217; <code>/bin/sh</code>) and adding the following in my <code>.profile</code>, to test if <code>bash</code> is indeed working before running it:</p>
<p><code>/usr/local/bin/bash -c true &#038;&#038; exec /usr/local/bin/bash</code></p>
<p>And to fix all the other ports that are now broken:</p>
<p><code> $ sudo portmaster -r -R devel/gettext</code></p>
<ol class="footnotes"><li id="footnote_0_265" class="footnote">because all package management sucks at some point, yes?</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2010/10/freebsd-gettext-libintl-and-bash/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>devopsdays Hamburg 2010</title>
		<link>http://www.zomo.co.uk/2010/10/devopsdays-hamburg-2010/</link>
		<comments>http://www.zomo.co.uk/2010/10/devopsdays-hamburg-2010/#comments</comments>
		<pubDate>Mon, 18 Oct 2010 08:35:31 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[conference]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=246</guid>
		<description><![CDATA[Recently back from devopsdays in Hamburg. Here&#8217;s a quick braindump whilst it&#8217;s all still fresh. People I went with a bunch of colleagues from the BBC, hooked up with some people I&#8217;d not seen for ages, unexpectedly met in real life people I&#8217;d worked with online previously and met a whole load of talented and [...]]]></description>
			<content:encoded><![CDATA[<p>Recently back from <a href="http://www.devopsdays.org/2010/10/04/devopsdays-2010-hamburg/">devopsdays</a> in Hamburg. Here&#8217;s a quick braindump whilst it&#8217;s all still fresh.</p>
<h3>People</h3>
<p>I went with a bunch of colleagues from the BBC, hooked up with some people I&#8217;d not seen for ages, unexpectedly met in real life people I&#8217;d worked with online previously and met a whole load of talented and interested engineers.</p>
<h3>Talks</h3>
<p>The conference was split between set talks and <a href="http://www.devopsdays.org/open-space-format/">open space</a> sessions. The talk I got the most out of was <a href="http://agilesysadmin.net">Stephen Nelson Smith</a>&#8216;s <a href="http://www.devopsdays.org/2010-europe/programme/#business">talk</a> on his experience bringing devops-shaped thinking to a large government site refresh. His thoughts about what worked and what didn&#8217;t were interesting and well made.</p>
<p><a href="http://www.johnmwillis.com/">John Willis</a> gave an excellent presentation on <a href="http://wiki.opscode.com/display/chef/Home">Chef</a>. I&#8217;ve monkeyed a bit with Chef but am only using <a href="http://www.puppetlabs.com/">Puppet</a> in real world situations so far. John&#8217;s a powerful evangelist and definitely got me enthused about Chef. I deliberately didn&#8217;t ask about Chef&#8217;s <a href="http://tickets.opscode.com/browse/CHEF-13">lack of dry-run mode</a> since I&#8217;ve banged on about it on the chef-users list twice now<sup><a href="http://www.zomo.co.uk/2010/10/devopsdays-hamburg-2010/#footnote_0_246" id="identifier_0_246" class="footnote-link footnote-identifier-link" title="and, for the record, I understand why such a mode would be imperfect and not aligned with Chef&amp;#8217;s overall philosophy">1</a></sup>, and because I wanted to see if anyone else flagged it as a concern &#8211; they did. All that aside, I am certainly going to get it up in a lab soon.</p>
<h3>Link dump</h3>
<ul>
<li><a href="http://marionette-collective.org/">Marionette Collective</a> (mcollective) &#8211; message bus framework for mass host control. I&#8217;m really interested by this. Seems similar to <a href="http://www.engineyard.com/">Engine Yard</a>&#8216;s <a href="http://github.com/engineyard/vertebra">Vertebrae</a> thing, but perhaps more immediately useable for me.</li>
<li><a href="http://docs.fabfile.org/0.9.2/">Fabric</a> &#8211; a more traditional (ie: centralised) mass control mechanism. We&#8217;ve all rolled our own variant of this at some point, right?</li>
<li><a href="http://hadoop.apache.org/zookeeper/">Zookeeper</a> &#8211; mentioned in passing, need to check this out.</li>
<li><a href="http://github.com/nistude/cucumber-puppet">cucumber-puppet</a> &#8211; not currently doing anything like this, probably should!</li>
<li><a href="http://circonus.com/">Circonus</a> &#8211; flagged in passing, monitoring.</li>
<li><a href="http://oreilly.com/catalog/0636920000136">Web Operations</a> &#8211; seems to be a good compliment to <a href="http://www.pragprog.com/titles/mnee/release-it">Release It!</a>, will grab and read.</li>
</ul>
<h3>Après-ski</h3>
<p>The conference laid on a boat trip around Hamburg&#8217;s canals and harbour on the Friday night with beer and soup. Brilliant! Afterwards we maxed out the lounge area of the <a href="http://www.bartime.de/location.chilli-club.2.1451.html">Chilli Club</a>. After sufficient beers and cocktails we headed off to the <a href="http://www.bartime.de/location.bunker.2.13717.html">Bunker</a> club for an epic all nighter<sup><a href="http://www.zomo.co.uk/2010/10/devopsdays-hamburg-2010/#footnote_1_246" id="identifier_1_246" class="footnote-link footnote-identifier-link" title="but no, I didn&amp;#8217;t quite last the whole night!">2</a></sup>. Clearly we didn&#8217;t know about the school gym dress theme but hey that didn&#8217;t matter. The utterly bizarre story that unfolded on stage throughout the night was hilarious. House of Pain MCd by a large sweaty man in a baby costume? Oh yes! (more outrageous moments omitted&#8230;)</p>
<p>Saturday night included more <a href="http://en.wikipedia.org/wiki/Brownian_motion">Brownian motion</a> around the Reeperbahn, plus Mike and I hanging out in a bar 0wned by <a href="http://en.wikipedia.org/wiki/FC_St._Pauli">St Pauli</a> supporters. I don&#8217;t know much about football but these guys are clearly very dedicated to their cause! Edgy. More drinks into the dawn, then tactical sleep before flying home.</p>
<h3>Hamburgers</h3>
<p>I was consistently amazed how friendly everyone is. Wandering around Hamburg you could strike up conversation with pretty much anyone and find something of interest to jib about. At several points strangers would change the course of their evening just to steer our slightly cat-herdesque group of geeks towards fun.</p>
<h3>Thanks</h3>
<p>Huge thanks to everyone who helped make this an excellent weekend, especially <a href="http://www.wegermann.com/">Marcel</a> and <a href="http://www.jedi.be/">Patrick</a>.</p>
<ol class="footnotes"><li id="footnote_0_246" class="footnote">and, for the record, I understand why such a mode would be imperfect and not aligned with Chef&#8217;s overall philosophy</li><li id="footnote_1_246" class="footnote">but no, I didn&#8217;t quite last the whole night!</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2010/10/devopsdays-hamburg-2010/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

