<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
  	<atom:link href="http://unflyingobject.com/blog/rss.php" rel="self" type="application/rss+xml" />
    <title>unflyingobject.com - for the thrill of understanding</title>
  	<link>http://unflyingobject.com/blog/</link>
		<description>mac geekery</description>
		<language>en-us</language>
		<ttl>500</ttl>


	  <item>
	    <title>
  	    <![CDATA[10.7: System Information]]>
    	</title>
   		<pubDate>Mon, 01 Aug 2011 21:21:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1081</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1081</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>One cool addition to Lion, at least from a techie's perspective is System Information (previously known as System Profiler).  On the outside it looks pretty much like System Profiler, with all it's categories:</p>

<p style="text-align:center">
  <img src="/images/system_information_1.png" alt=""/>
</p>

<p>... <strong>but</strong>, hit Cmd-I and voila:</p>

<p style="text-align:center">
  <img src="/images/system_information_2.jpg" alt=""/>
</p>

<p>Notice the title of the window. I'm guessing this will one day replace the venerable "About This Mac" under the Apple menu. This thing could be pretty useful since it tells you how you're hard drive space is distributed:</p>

<p style="text-align:center">
  <img src="/images/system_information_3.jpg" alt=""/>
</p>

<p>... <strong>and</strong> about the current and possible configurations of RAM:</p>

<p style="text-align:center">
  <img src="/images/system_information_4.jpg" alt=""/>
</p>

<p>The "Support" and "Service" tabs hold some useful links but unfortunately they all seem to go to blank pages at the moment.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[Auditron]]>
    	</title>
   		<pubDate>Mon, 18 Jul 2011 02:27:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1080</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1080</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>I've started a pretty useful little <a href="https://github.com/filipp/Auditron">project</a> over at Github, called Auditron. It's essentially a wrapper for System Profiler that you can easily preconfigure and then distribute, say via email.</p>

<p>Very often you have to audit a  bunch of totally unmanaged Macs and I know from personal experience that touching every machine yourself either doesn't work very well ("Umm, does anyone know the password to Joe's workstation?") or is simply impossible ("Umm, does anyone know where Joe's workstation is?"). The idea for this actually came from this very need back in 2006 - I was still working at Humac <a href="http://business.timesonline.co.uk/tol/business/industry_sectors/retailing/article3708563.ece">back then</a> and some B2B salespeople really wanted to sell stuff but couldn't since they didn' know what the customer was running and therefore needed. Back then I threw together an AppleScript Studio app that did pretty much the same thing as Auditron but then you had to use a few command-line script to put the results back together.</p>

<p>This one is much simpler to use - first you run it on your own machine and set your name and email address (assuming you're the one collecting this information) then you just ZIP up the app and send to everyone at the office. When lauched, auditron runs System Profiler in the background, saves the results in a safe place and then tells (either Mail.app or Entourage) to create a new mail with the compressed system profile as an attachment).</p>

<p>The second part is comparing the results. Once you get all them back, you just save them into one folder, open Auditron and run the File > Compare Results command (Cmd-K) on that folder which should pop open a table with the basic info of every Mac in the folder. You can then export that as a CSV file for further processing in Excel.</p>

<p>I think this thing might also be pretty useful for AASP's for doing "remote" diagnostics (as in "Does that Early 2011 MBP really have the correct 10.6.7 update installed?"). <a href="http://www.mcare.fi/fi/index.php">We</a> might even put it up on our website somewhere...</p>

<p><a href="https://github.com/downloads/filipp/Auditron/Auditron.zip">Download here</a>. Bug reports preferably to Github, but you can also just <a href="mailto:f@0x00.co">drop me a line</a> directly.</p>

<p>As an aside - I started writing this in <a href="http://developer.apple.com/library/mac/#releasenotes/ScriptingAutomation/RN-AppleScriptObjC/_index.html">AppleScriptObjC</a> and can honestly say that that "language" or "platform" or whatever you want to call it is number 2 in my list of horrendous development environments (Symbian C++ is still king!). Luckily I hadn't gotten too far and was able to switch over to Cocoa pretty quickly. I suspect AppleScriptObjC (just look at the name of it!) is just Apple's way of trying to get all those poor AppleScript devs over to Cocoa/Objective-C (which I heartly recommend, considering the alternative). I just wish they'd make a statement about <a href="http://www.macruby.org/">this thing</a> already.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[Mediator]]>
    	</title>
   		<pubDate>Sun, 10 Jul 2011 22:31:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1079</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1079</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>Back from <a href="http://medlab.me/filipp/nyc">our trip to NYC</a> with my sister, we had a whole bunch of AVCHD material in MTS format that I just couldn't get into iMovie. So the idea was to first convert them to QuickTime. Turns out there's no shortage of "mts2mov" utilities out there but they're all crapware. Horrible Windows-look-alike contraptions with ridiculous pricetags and big honking "try now for free"-signs... yuck.</p>

<p>But then I turned to my old friend <a href="http://www.ffmpeg.org/">ffmpeg</a>, downloaded, compiled and, as usual, had a fresh batch of QuickTime files ready for editing in no time at all.</p>

<p>But this got me thinking - why not have a general-purpose <em>ffmpeg</em> wrapper for these kinds of occasions. At first I wrote a simple Cocoa app but then came up with a better idea - a collection of Automator actions. It goes by the name of <a href="https://github.com/filipp/Mediator">Mediator</a> and right now there's only one action - "Convert into QuickTime" which simply uses <em>ffmpeg</em> (bundled into the action) to repackage an input file to MOV.</p>

<p style="text-align:center">
  <img src="/tmp/mediator.png" alt=""/>
</p>

<p>The compiled <em>ffmpeg</em> is for x86_64 so it'll only run on Core 2 Duo and beyond. <a href="https://github.com/filipp/Mediator">Source</a> and <a href="https://github.com/downloads/filipp/Mediator/Convert%20into%20QuickTime.action.zip">binary</a> in Github.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[cpu2asr]]>
    	</title>
   		<pubDate>Fri, 10 Jun 2011 20:32:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1072</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1072</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>There's one more new tool in MTK that I thought was worth a quick shout-out, namely <a href="https://github.com/filipp/mtk/blob/master/cpu2asr">cpu2asr</a>.  While <a href="https://github.com/filipp/mtk/blob/master/netbless.sh">netbless</a> has turned out to be pretty useful, restoring entire CPUs with it has two drawbacks:</p>

<ul>
<li>You have to create a user account to install the bundled applications (the second disc)</li>
<li>It's slow. While an installer-based workflow is great for doing "archive &amp; install" — type installations, restoring a brand new drive with this method is much slower than a simple ASR restore.</li>
</ul>

<p>So we need a method to create ASR-ready images from the bundled media. The obvious problem is the media will only install on the machine the it was designed for (i.e., you need to have an actual "MacBook Pro (Mid 2010)" to create the corresponding ASR image. With so many Mac models out there, this isn't always possible, especially if you're a service-only shop like us. And even if we manage to do this, doing "gold master" restores has some potential problems, with machine-specific settings and code being redistributed to several different units.</p>

<p>This is where <a href="https://github.com/filipp/mtk/blob/master/cpu2asr">cpu2asr</a> comes in. It takes 3 arguments - disc 1, disc 2 and the name of the output image. The result is an ASR-ready image you can restore on a machine in minutes, via Deploy Studio or whatever. You can also run the tool on any Mac (there's an [incredibly crude <a href="https://github.com/filipp/mtk/blob/master/cpu2asr#L45">hack</a> to basically bypass <strong>all</strong> requirement checks).</p>

<p>So far I've managed to create both 10.5 and 10.6-based ASR images with it (the 10.6-based ones needed an additional step to extract the XAR archive for the patching to work). Since the "volumes" are installed "offline" never booted, you also avoid distributing and machine-specific settings.</p>

<p>So, in summary, the whole process becomes a simple matter of:</p>

<pre><code># cpu2asr Mac\ OS\ X\ Install\ DVD.dmg Application\ Install\ Disc.dmg imac_21.5_m10.dmg
</code></pre>

<p>The code could still use some cleanup (and a few more features, like the option to install additional packages) but I've now "imaged" half a dozen machines with this so it seemed safe to put it out there. Also, while digging through the OS X distribution files, I've found that one bundled OS build can support several Mac models, so it would make sense to figure out an efficient workflow for storing and distributing these (kinda like <a href="http://unflyingobject.com/blog/posts/1074">asd2nb</a>, but storing it with the OS's build number, for example).</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[asd2nb]]>
    	</title>
   		<pubDate>Tue, 07 Jun 2011 19:38:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1074</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1074</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>There's a new tool in <a href="https://github.com/filipp/mtk/">MTK</a>, creatively named <a href="https://github.com/filipp/mtk/tree/master/asd2nb">asd2nb</a> which helps put Apple System Diagnostic images on your NetBoot server. The idea and motivation is very similar to netbless — there are dozens of ASD discs, with more coming out with every new Mac model and managing them becomes more and more complicated in any AASP environment.</p>

<p>A word of warning - ASD OS tests are not currently designed to be run over NetBoot. In our testing we've seen several false positives and some tests (like NIC tests) even seem to hang. But considering the benefits, this is definitely something to try out and maybe even implement, once you know how to work around a few known issues.</p>

<p>Also, the EFI tests seem to work just fine.</p>

<h2>The Workflow</h2>

<p>We start by creating a NetBoot set from each ASD image using System Image Utility:</p>

<ul>
<li>Mount the ASD OS image, launch SIU and add the devices supported by the test to the "Filter Computer Models" action.</li>
<li>Name the NBI by the test version (for example 3S145.nbi)</li>
<li><p>Mount the EFI ASD image and <em>rsync</em> the contents under the new NBI, i.e.:</p>

<pre><code># rsync -au ./Volumes/3S144\ ASD\ EFI/ ./3S145.nbi/efi
</code></pre></li>
<li><p>Copy the NBI to your deployment server</p></li>
</ul>

<p>The annoying part about this is of course having to do this on the same major OS version that's in the ASD image (which go back as far as 10.4 for 108 and 116). We have a machine with 3 partitions (10.4-10.6) set aside for this.</p>

<h2>116 and 108</h2>

<p>For some reason, the NBI created by 10.4 SIU will result in a kernel panic during boot. Even if you create the set on an Intel machine. Luckily the workaround is quite simple:</p>

<ul>
<li>Create the NBI using SIU as usual (saved into /Volumes/nb/asd/3S116.nbi in my case)</li>
<li><p>Mount the original ASD 116/108 image (/Volumes/ASD\ Dual\ Boot\ 3S116) and then:</p>

<pre><code># cd /Volumes/ASD\ Dual\ Boot\ 3S116
# ditto mach_kernel /Volumes/nb/asd/3S116.nbi/i386/mach.macosx
# ditto System/Library/Extensions.mkext /Volumes/nb/asd/3S116.nbi/i386/mach.macosx.mkext
# ditto usr/standalone/i386/boot.efi /Volumes/nb/asd/3S116.nbi/i386/booter
</code></pre></li>
</ul>

<h2>Client &amp; Server</h2>

<p>A single ASD may support more than one Mac model which makes matching a machine with it's corresponding ASD a bit more involved. I chose to have a <a href="https://github.com/filipp/mtk/blob/master/asd2nb/server.php">server-side script</a> do the heavy lifting - it takes the machine's model ID as an argument and then scans the whole ASD NBI repository for each NBI's <em>NBImageInfo.plist</em> file for a matching string in it's <em>EnabledSystemIdentifiers</em> array, returning the NBI name, if successful. With this method, you don't have to make any changes to the client script — just keep adding new ASD images as Apple releases them using the workflow outlined above.</p>

<h2>And what about EFI?</h2>

<p>The <a href="https://github.com/filipp/mtk/blob/master/asd2nb/asdbless.sh">client-side script</a> accepts one optional parameter — "efi". If set, this will change the <em>bless</em> behavior to set the boot file to the EFI test's boot.efi binary. The EFI tests seem to work just fine over NetBoot without any weird false positives so far.</p>

<p>Some older tests (namely 3S108 and 3S116) came as one big DMG, with the EFI and OS tests on the same partition. You have to do a bit more preparation with these. For example, to make 3S116 fit our workflow, I mount the image and then:</p>

<pre><code># rsync -au /Volumes/ASD\ 3S116/System/Library/CoreServices/.diagnostics ./3S116.nbi/efi
# cd ./3S116.nbi/efi
# ln -s diags.efi boot.efi
</code></pre>

<p>If you use DeployStudio, you can create 2 workflows — "Boot ASD OS" which runs <em>asdbless.sh</em> as is, and "Boot ASD EFI" which runs <em>asdbless.sh</em> with the <em>efi</em> parameter.</p>

<p>In closing, I have a feeling this will all be integrated into AST some day (it would just seem logical), but until that day comes, this method gives pretty good results.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[AST & DeployStudio]]>
    	</title>
   		<pubDate>Fri, 03 Jun 2011 12:23:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1073</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1073</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>In AST version 1.0.6 (?) Apple added the "Other NetBoot" option to boot other NBI:s hosted on the same server. This is great, except I think there's a bug that makes it incompatible with DeployStudio. </p>

<p>DeployStudio creates root images with the name "DeployStudioRuntime.sparseimage". It also says so in the NBImageInfo.plist's RootPath key. For some strange reason, using the "Other NetBoot" command sets the root path to "NetInstall.dmg". You can see it clearly by starting up in verbose mode or reading setenv. I suspect it's just a bug and that AST doesn't actually check the plist and reported it, but didn't get a clear answer.</p>

<p>The result is you get a "stop" sign when you try to boot the NBI (machine gets the booter file via TFTP, but not the root image).</p>

<p>In any case, the workaround is simple - just rename DeployStudioRuntime.sparseimage to NetInstall.dmg every time you create your DeployStudio NBI with the DeployStudio Assistant and all will be fine. I just got bit by this the other day <em>again</em> and thought I'd write it down.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[gsxcl]]>
    	</title>
   		<pubDate>Sun, 29 May 2011 21:15:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1071</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1071</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>Just wanted to give a quick shoutout to <a href="https://github.com/filipp/gsxlib/blob/master/gsxcl">gsxcl</a>. It started out as a simple test tool for <a href="https://github.com/filipp/gsxlib/">gsxlib</a>, but has now evolved into a pretty useful replacement for GSX's web UI. Currently it supports the following operations:</p>

<ul>
<li>Warranty status</li>
<li>Part lookups</li>
<li>Checking repair details and status</li>
<li>Downloading part return labels</li>
</ul>

<p>That's right - you can even use this to quickly download the return label of a part as a PDF:</p>

<pre><code>./gsxcl -u username -p password -s sold-to -m label -q return-order:part-number &gt; test.pdf
file ./test.pdf
test.pdf: PDF document, version 1.4
</code></pre>

<p>The operating principle is that -m defines the "mode" of operation and then everything after -q should supply the necessary arguments. Multiple arguments are separated with a colon, as for example in the label download command - we must supply both the return order number (starting with 7...) and the part number being returned.</p>

<pre><code>usage: gsxcl -s sold-to -u username -p password [-r region] [-e environment] [-f format] [-m mode] [-q query]
-s  sold-to           your GSX Sold-To account
-u  username    the Apple ID with GSX WS API access
-p  password    the password for the Apple ID
-r  region           either "am" (America), "emea" (default, Europe, Middle-East, Africa) "apac" (Asia-Pacific) or "la" (Latin America)
-e  environment the GSX environment. Either empty (production), "it" or "ut" Defaults to production
-f  format          the output format. Either print_r (default), json, xml or csv
-m  mode          what to search for. Currently one of: warranty, parts, pending, repair, lookup, status, label.
              Defaults to "warranty"
-q  query           a query string (serial number, order confirmation, repair number, EEE code, etc
              Defaults to this machine's serial number
</code></pre>

<p>One of the most recent changes I added was the format option, allowing you to get data out of it in CSV, XML or just a PHP print_r(). The CSV option is probably the most useful one, the header row is constructed from all the property names of the GSX WS response.</p>

<p>Running it with just the required arguments will perform a warranty status check for the current machine. </p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[NetBless & DeployStudio]]>
    	</title>
   		<pubDate>Tue, 10 May 2011 21:46:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1070</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1070</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>It turns out that <a href="/blog/story/1063">NetBless</a> works really well together with DeployStudio. All that was needed was a <a href="https://github.com/filipp/mtk/commit/b74a04eedaeba86926953e346754814e1f956a62">simple change</a> while checking for $USER.</p>

<p>This is actually pretty cool - it gives you access to all your installation media, right within DeployStudio, your users don't have to "learn Terminal" and you no longer have to worry about individual diagnostics OS being up to date - it's all in NetBoot.</p>

<p>For our environment, I created 3 workflows:</p>

<ul>
<li>"Boot Bundled Installer" which calls NetBless without arguments, allowing it to choose the appropriate OS. Since NetBless returns 1 when the original installer is not found, you get a failed result when running the Workflow, which is perfect.</li>
<li>"Boot 10.6 Installer" calls NetBless with retail_10.6.3.nbi which is a NetInstall set of a retail 10.6.3 disc</li>
<li>"Boot 10.5 Installer" calls NetBless with retail_10.5.8.nbi which is a NetInstall set of a retail 10.5.8 disc</li>
</ul>

<p>You can copy netbless.sh to the Scripts directory and call it from a "Generic task" or just copy/paste it into a "Generic task"  as is.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[gsxlib]]>
    	</title>
   		<pubDate>Fri, 29 Apr 2011 16:05:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1068</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1068</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>I've started a new project on github called <a href="https://github.com/filipp/gsxlib">gsxlib</a>. It's a helper library for dealing with Apple's GSX web service API. I just noticed I have several web apps all using their own GSX code, so the idea is to refactor them all under this one library.</p>

<p>Very simple to use, you don't even have to know the WSDL URL:</p>

<pre><code>&lt;?php

  include 'gsxlib/gsxlib.php';
  $gsx = new GsxLib('your sold-to account', 'gsx user', 'password');
  $info = $gsx-&gt;warrantyStatus('serialnumber');
  echo $info-&gt;productDescription;

?&gt;

MacBook Pro (15-inch 2.4/2.2GHz)
</code></pre>

<p>Currently it only has a shortcut for warranty status checks, more to come soon. Check <a href="https://github.com/filipp/gsxlib/blob/master/README.md">the readme</a> for more details.</p>

<p>On a totally unrelated note - <a href="http://freshmeat.net/projects/imapsync/">imapsync</a> is awesome.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[IT Tip Of the Month - Change Your Managed Switch's Default IP]]>
    	</title>
   		<pubDate>Tue, 19 Apr 2011 12:50:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1067</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1067</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>Let's say your LAN is 172.17.64.0/24 and it has 3 ProCurve 1800-24G switches, all with default IP's. You connect your Mac to the switch you want to manage, set your IP to 192.168.2.20 and aim Safari at 192.168.2.10, the web GUI comes up. Great!</p>

<p>But which switch are you actually connecting to?</p>

<p>I assumed it was the one on the other end of the Ethernet cable. Checking the VLAN configuration revealed there were none so I assumed this switch was only part of the network I was deleting (I was combining two networks) and then just connected this switch to the other network.</p>

<p>And then nothing worked. And I spent the next 3 hours fixing things and got home around 2 AM...</p>

<p>I know now I had created an Ethernet loop. The switch I was configuring wasn't actually the switch I was physically connected to, but some random one of the three identical 1800's we have in our office (the 1800 actually supports <a href="http://en.wikipedia.org/wiki/Spanning_Tree_Protocol">STP</a>, which I've never used, until now). After disconnecting all other cables from the switch I saw that this one did indeed have 3 VLAN's and that the one I connected to the "other network" was actually the same one.</p>

<p>OK, so no default IP's for managed switches. Ever. But which one do you give them then? My experience with switch IP's is that no-one ever remembers them since they're usually used very rarely (along with their admin passwords, but that's a different "IT tip of the month"). Well, you use the 2 databases that occur naturally in any network - DNS and/or your firewall's configuration (DHCP static map). In this case, I chose the latter.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[Some Things]]>
    	</title>
   		<pubDate>Tue, 12 Apr 2011 03:36:00 +0300</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1066</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1066</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>Some random updates:</p>

<ul>
<li><p>PHP's gettext support made me want to smoke crack so I ported the entire <a href="https://github.com/filipp/servo">servo</a> localisation to <a href="http://www.mind-it.info/2010/02/22/a-simple-approach-to-localization-in-php/">one based on JSON</a>. Also, <a href="http://www.poedit.net/">POEdit</a> is rubbish so I feel much better now. Also wrote <a href="https://gist.github.com/914410">a simple tool</a> to convert existing PO files to JSON.</p></li>
<li><p>The only thing I was missing from POEdit was the ability to quickly scan the sources for updated strings. So I wrote <a href="https://gist.github.com/914416">this thing</a> which actually works pretty well. By the way, my gettext function is called __().</p></li>
<li><p>MTK now includes <a href="https://github.com/filipp/mtk/blob/master/whatbuild.sh">a tool</a> to report the build number of any OS X volume. In case you ever have to match <a href="http://support.apple.com/kb/ht1159">any of these</a>.</p></li>
<li><p><a href="http://unflyingobject.com/blog/story/1055">iTunesScrubber</a> now has a "GUI". It's <a href="/tmp/itsscrub.zip">a simple droplet</a> that contains the AtomicParsley binary and my script. Just drop your iTunes Store M4A(s) on it and it'll ask for a destination folder for the cleaned files.</p></li>
<li><p>Apache 2.2 (at least on FreeBSD) comes with a weird WebDAV default configuration which causes every <strong>/uploads</strong> URL to trigger an Access Denied error, such as this:</p>

<pre><code>client denied by server configuration: /usr/local/uploads
</code></pre></li>
</ul>

<p>The solution (if you need DAV support in the first place), is to edit <strong>/usr/local/etc/apache22/extra/httpd-dav.conf</strong> and set</p>

<pre><code>Alias /uploads "/usr/local/uploads"
</code></pre>

<p>to something else. Sounds obvious now, but was driving me nuts...</p>

<ul>
<li>Indiegogo.com seems nice. It's exactly the kind of thing I was thinking of a while ago. I found it because a friend of mine is working ona movie project and they're trying to raise some of the funding through that. <a href="http://www.indiegogo.com/What-Would-Be-If-1">Go check it out</a>!</li>
</ul>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[Virtualmin RC Script for FreeBSD]]>
    	</title>
   		<pubDate>Fri, 04 Feb 2011 13:02:00 +0200</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1065</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1065</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p><a href="http://www.virtualmin.com/about.html">Virtualmin's</a> in ports, but I liked it so much that we decided to buy the pro version, which of course, isn't. Unfortunately, the latest FreeBSD version the installer script officially supports is 7.x, so I guess that's why some of the system setup didn't go quite as planned.</p>

<p>I'm happy to report that the system seems to be running fine (for a few months now), the only thing that didn't work at all was the startup script, so I had to create one from scratch:</p>

<pre><code>#!/bin/sh
#
# PROVIDE: virtualmin
# REQUIRE: LOGIN
# KEYWORD: shutdown
#

. /etc/rc.subr

name="virtualmin"
rcvar=${name}_enable

load_rc_config $name

: ${virtualmin_enable="NO"}

start_cmd=${name}_start
stop_cmd=${name}_stop
extra_commands="restart"

virtualmin_start() {
  /usr/local/etc/webmin/start
}

virtualmin_stop() {
  /usr/local/etc/webmin/stop
}

virtualmin_restart() {
  /usr/local/etc/webmin/restart
}

run_rc_command "$1"
</code></pre>

<p>Save that into /usr/local/etc/rc.d/virtualmin, chmod +x and set virtualmin_enable="YES" in /etc/rc.conf.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[NetBoot Over OpenVPN]]>
    	</title>
   		<pubDate>Tue, 01 Feb 2011 12:59:00 +0200</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1064</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1064</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>NetBooting over VPN isn't anything new or that complicated - just set up a tunnel and use <em>bless</em> with the slightly more elaborate arguments to set the boot parameters, as in Mr. Bombich's <a href="http://www.afp548.com/netboot/mactips/nbas.html">example</a>:</p>

<pre><code>sudo bless --netboot --booter tftp://server.apple.edu/NetBoot/NetBootSP0/NetInstall.nbi/i386/booter \\
--kernel tftp://server.apple.edu/NetBoot/NetBootSP0/NetInstall.nbi/i386/mach.macosx \\
--options "rp=nfs:server.apple.edu:/private/tftpboot/NetBoot/NetBootSP0:NetInstall.nbi/NetInstall-Restore.dmg"
</code></pre>

<p>Where the IP of <em>server.apple.edu</em> would be at the other end of the tunnel. The problem is, this requires a working system and isn't particularly "user firendly".</p>

<p><a href="http://www.mcare.fi/index_en.html">Our</a> goal was to give our reseller partners the opportunity to run Apple Service Toolkit. AST is a completely EFI-based system so the amount of data transfered is relatively tiny. An entire MRI session is perhaps a few dozen megabytes, so I knew it should not only be possible, but might actually work quite well.</p>

<p>The only question was how do we make the whole experience seamless - to have customer simply start up the Mac with the N-key and have it work as if on the same subnet as the AST server. The whole solution would consist of:</p>

<ul>
<li>A pfSense (1.2.3) system at both ends. We happened to have a few spare PC Engines Alix.2 boxes so we used those.</li>
<li>OpenVPN (2.0.6) as the VPN software (included in pfSense)</li>
<li>A Mac mini running 10.6.5 server and AST 1.0.5.</li>
</ul>

<h2>OpenVPN bridging</h2>

<p>For DHCP broadcasts to work, we need to <strong>bridge</strong> the local and remote networks. There's quite a lot of <a href="http://www.google.com/search?client=safari&amp;rls=en&amp;q=openvpn+bridge&amp;ie=UTF-8&amp;oe=UTF-8">information</a> on this out there, but I found that most instructions dealt with bridging a specific <em>client</em> to the remote network. What we needed, was a <strong>bridged site-to-site</strong> connection. Setting it up turned out to be quite a bit easier than I thought, here's how I did it:</p>

<p style="text-align:center">
  <img src="/blog/images/inetboot.png" alt="" />
</p>

<h2>1.</h2>

<p>I set up a static IP on the WAN</p>

<h2>2.</h2>

<p>Configure a new OpenVPN server (VPN > OpenVPN > Server > Add).</p>

<ul>
<li>Protocol: TCP</li>
<li>Address pool: to my understanding, this is meaningless in this case, but it made sense to set it to something within the NetBoot server's subnet, but outside the internal DHCP range.</li>
<li>Enable "Use static IPs". Presumably because we want the <em>internal</em> DHCP server to assign IPs.</li>
<li>Authentication method: PKI. This is a prerequisite to "Use static IPs".</li>
<li>Under "Custom options" add "dev tap0"</li>
</ul>

<p>The other fields should be set according to your own requirements.</p>

<p>When you save all that, pfSense will try to start up the newly configured OpenVPN server. Assuming everything was kosher, this will create a new network interface on the box, called <strong>tap0</strong>. This is the interface that your VPN clients will connect to and works just like a physical interface. </p>

<p>All that remains is to bridge this new interface with the LAN, where your DHCP and NetBoot live. You could do this through the WebGUI (Interfaces > Assign, etc) and it would work, but only until you reboot the VPN box. This is because pfSense's start up sequence tries to assign bridges <strong>before</strong> starting the OpenVPN server. Fortunately, we can circumvent this quite easily.</p>

<p>In WebGUI, open <strong>Diagnostics > Edit File</strong> and load up <strong>/conf/config.xml</strong>. Append the following to the <system> element:</p>

<pre><code>&lt;earlyshellcmd&gt;ifconfig bridge0 create&lt;/earlyshellcmd&gt;
&lt;earlyshellcmd&gt;ifconfig bridge0 addm vr0 up&lt;/earlyshellcmd&gt;
&lt;shellcmd&gt;ifconfig bridge0 addm tap0&lt;/shellcmd&gt;
</code></pre>

<p>That looks a bit weird at first, but it makes sense, knowing that OpenVPN is initialised between <earlyshellcmd> and <shellcmd>. Save the file and reboot the box to make sure <em>tap0</em> and <em>bridge0</em> are still there. vr0 is the LAN port on the Alix.2 board. This concludes our server part of the program.</p>

<h2>3.</h2>

<p>Over on the client side, it's almost a mirror image of the server, only a bit more simplified. VPN > OpenVPN > Client > Add:</p>

<ul>
<li>Protocol: TCP</li>
<li>Server address: WAN IP of server</li>
<li>Server address: empty</li>
<li>Interface IP: empty</li>
<li>Authentication method: PKI</li>
</ul>

<p>Once you save that, the tunnel should be up, but broadcasts shouldn't work yet since we haven't defined the LAN/TAP bridge. Load up <strong>conf/config.xml</strong> and do the exact same change as on the server side. Reboot to verify it's working. The last thing I had to do, was to make sure the <strong>IP of the VPN client's LAN port</strong> was within the server-side network. Without this, broadcasts would work, but I couldn't actually connect to anything on the remote network.</p>

<p>Oh, and make sure you've disabled the DHCP server on the LAN port.</p>

<h2>4.</h2>

<p>After the reboot, connect a machine to the LAN port. You should get an IP on the (now) remote network. Startup Disk should see the NetBoot server on the remote network (the AST NBI in our case). Booting up the machine with the Alt-key should also list the NetBoot server (with recent enough firmware). Booting with the N-key should boot the machine over the VPN connection.</p>

<h2>Finishing touches</h2>

<p>For extra style points, you can have OpenVPN flash the LED's on your client (the Alix.2 board in my case), by using the "up" and "down" parameters to OpenVPN (Custom Options field in pfSense), for instance:</p>

<pre><code>up "echo 1 &gt; /dev/led/led2"; down "echo 0 &gt; /dev/led/led2"; up-restart"
</code></pre>

<p>The "up-restart" option will run the commands for VPN restarts as well.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[netbless]]>
    	</title>
   		<pubDate>Fri, 07 Jan 2011 12:31:00 +0200</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1063</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1063</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>In my <a href="http://unflyingobject.com/blog/posts/1061">previous post</a>, I alluded to a tool that we use to make NetBooting different machines with their correct OS quite a bit simpler. Here's what it is and how to use it. But first a few words about my workflow:</p>

<h2>The Setup</h2>

<ul>
<li>We collect CPU installation media from customers and resellers and then rip them to the file server. I rip both disks into a folder named after the "mnemonic" name of that machine. For instance, "MacBook Pro (15-inch, Late 2008)" becomes "mbp_15_l08" etc.</li>
<li><p>I then use System Image Utility to create NetInstall sets of all ripped images and name the .nbi's according to the machine's hardware "model", for instance "mbp_15_l08" then becomes "MacBookPro5,1". You can read the model of a machine either from Mactracker, System Profiler or simply:</p>

<pre><code>$ sysctl -n hw.model
MacBookPro3,1
</code></pre></li>
<li><p>The reason I use two different naming schemes is because the first makes the images easy to browse for technicians and the second makes them easy to match to a specific machine (the first is easy to remember for humans, the second for machines, if you will)</p></li>
<li>The NetInstall sets are then transfered to a folder where they are accessible to NetBoot (see my previous post for specifics).</li>
</ul>

<h2>Making it Run</h2>

<p>With things organized this way, it's now very simple to match any machine to it's corresponding installation media. To automate this, I created a tool that consists of two parts:</p>

<ul>
<li>A web service (which runs on the NetBoot server) that lists all the available NetInstall sets</li>
<li>A command-line tool (essentially just a wrapper for bless) that can query the web service and set the appropriate boot args for a given NetInstall set</li>
</ul>

<p>The web service couldn't be any simpler, it just lists the available NBIs:</p>

<pre><code>&lt;?php
$datadir="/data/nb";
header("Content-type: text/plain");
foreach (glob("${datadir}/*.nbi") as $nb)
{
    $images[] = basename($nb);
}
echo implode(" ", $images)
?&gt;
</code></pre>

<p>By default, the <a href="https://github.com/filipp/mtk/blob/master/netbless.sh">client-side</a> tool tries to match the current machine to a set on the server:</p>

<pre><code>$ sudo ./netbless.sh 
Error: model MacBookPro3,1 not found on the NetBoot server
</code></pre>

<p>... meaning I haven't ripped the media for this machine yet. In these cases I can force the tool to use a specific NBI. To do that, I'll probably need to know what is available:</p>

<pre><code>sudo ./netbless.sh list
Available images: 10.5.6_retail.nbi MacBook3,1.nbi MacBook7,1.nbi MacBookAir2,1.nbi MacBookPro5,2.nbi MacBookPro6,2.nbi MacBookPro7,1.nbi Macmini3,1.nbi Macmini4,1.nbi boot.nbi iMac11,3.nbi retail_10.6.3.nbi retail_10.6.3_2.nbi
</code></pre>

<p>So, to boot to the 10.5.6 installer, I would say:</p>

<pre><code>sudo ./netbless.sh 10.5.6_retail
</code></pre>

<p>The script makes some assuptions (for instance of the NetBoot and web services being on the same server) but is general enough to customise it to any environment. If you're image library is comprehensive enough, using netbless is usually just a matter of:</p>

<pre><code>$ sudo ./netbless &amp;&amp; reboot
</code></pre>

<p>And yes, using this requires a bootable system to start with (say your known-good diagnostics partition). Ideally, netbless would be an EFI-binary that you could run off a memstick, without an OS, but my <a href="http://www.osxbook.com/book/bonus/chapter4/efiprogramming/">EFI-programming</a> skills aren't quite up to snuff yet...</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[NetBoot on FreeBSD]]>
    	</title>
   		<pubDate>Thu, 23 Dec 2010 17:45:00 +0200</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1061</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1061</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>Continuing our series of <a href="http://unflyingobject.com/blog/posts/1056">"alternate lifestyle"</a> articles, here's a short howto on how to provide NetBoot services to your Macs from a FreeBSD server. None of this would be possible without Jeff McCune's excellent <a href="https://www.math.ohio-state.edu/oldwiki/administration/macosx/netboot/bsdp_with_isc_dhcp">notes on the subject</a>. The following is basically a rehash of his research, with some FreeBSD-specifics thrown in, as well as some more general AASP-related workflow tips.</p>

<h2>The Specs</h2>

<ul>
<li>I built this system for <a href="http://www.mcare.fi/index_en.html">our Authorized Apple Service Provider</a> where we use it primarily for NetInstalling machines after a hard drive replacement. Getting the right system on the right machine is crucial and NetBoot provides the best platform to do so, in my opinion (as opposed to, say having dozens of drives and/or partitions of installers for every possible Intel Mac, for each of your technicians).</li>
<li>We don't need diskless support (something I'll probably have to address sooner or later).</li>
<li>We don't support PPC machines (haven't had the need to do so thus far).</li>
</ul>

<p>The server is running FreeBSD 8.1. I create the NetBoot images using System Image utility (I have a machine with both 10.5. and 10.6 installed so I can create images of both systems). The images are stored on a RAID-Z pool under /data/nb.</p>

<h2>Installation</h2>

<p>NetBoot essentially consists of 3 pieces  (in order of appearance):</p>

<ul>
<li>A DHCP server to provide addressing and initial server discovery</li>
<li>A TFTP server for transferring the kernel and extension cache</li>
<li>An HTTP or NFS server to provide the actual disk image data</li>
</ul>

<p>NFS and TFTP are essentially "built in" to FreeBSD, so we only need to install ISC's DHCP server:</p>

<pre><code># cd /usr/ports/net/isc-dhcp41-server
# make install clean
</code></pre>

<p>On to configuring the DHCP server. I'm assuming you already have the basic functionality sorted and will only focus on the NetBoot-relevant bits:</p>

<pre><code># nano /usr/local/etc/dhcpd.conf
</code></pre>

<p>To which we append the following:</p>

<pre><code>class "AppleNBI-i386" {
  match if substring (option vendor-class-identifier, 0, 14) = "AAPLBSDPC/i386";
  option dhcp-parameter-request-list 1,3,17,43,60;

  if (option dhcp-message-type = 1) { option vendor-class-identifier "AAPLBSDPC/i386"; }
  if (option dhcp-message-type = 1) { option vendor-encapsulated-options 08:04:81:00:00:67; }

  filename "boot.nbi/i386/booter";
  option root-path "nfs:172.17.65.1:/data/nb:/boot.nbi/NetBoot.dmg";
}
</code></pre>

<p>The first four lines inside the class section - I have no idea what they do, but I haven't tried this without them, so there they are. The last two however make perfect sense - the first defines the path of the booter file (the low-level EFI binary). This is always relative to the root of your tftp server, which by default is <em>/tftpboot</em>. Since my only application for <em>tftpd</em> is NetBoot, I simply symlink <em>/tftpboot</em> to my NetBoot image set repository:</p>

<pre><code># ln -s /tftpboot /data/nb
# ls /tftpboot
MacBookPro5,2.nbi   Macmini4,1.nbi      boot.nbi        retail_10.6.3_2.nbi
MacBook3,1.nbi      MacBookPro6,2.nbi   MacBook7,1.nbi      MacBookPro7,1.nbi   iMac11,3.nbi
10.5.6_retail.nbi   MacBookAir2,1.nbi   Macmini3,1.nbi      asd_efi_3s123       retail_10.6.3.nbi
</code></pre>

<p>I like to name all my CPU-specific install images based on their "Model Identifier" (sysctl hw.model, more on "why" in a later article...). As mentioned previously, the sets are all created using SUI. <em>boot.nbi</em> is a NetBoot set, preferably of a really fresh retail package (or the latest CPU bundle) which is used as the default set. As you can see, I also have an Apple Service Diagnostic image in there, more on that some other time...</p>

<p>The last line sets the network path of the actual NetBoot "payload" - the OS and/or installer that will be booted and mounted. The colons are significant - "nfs" means the file sharing protocol (which will set up in just a bit), "/data/nb" is the path of the NFS share and is separated from the IP of the server so that the client (in our case the OS X kernel) knows what to mount and finally "/netboot.nbi/NetBoot.dmg" is the path of the actual disk image to be mounted.</p>

<p>All that remains is to let dhcpd know we mean business:</p>

<pre><code># /usr/local/etc/rc.d/isc-dhcpd restart
</code></pre>

<h2>TFTP and NFS</h2>

<p>With DHCP set up, let's configure and test the two other components of this system, starting with TFTP:</p>

<pre><code># nano +28 /etc/inetd.conf
</code></pre>

<p>Uncomment the current and following line and kick inetd:</p>

<pre><code># /etc/rc.d/inetd restart
</code></pre>

<p>Test it by downloading one of the booter files from any Mac. In my environment this would mean:</p>

<pre><code>$ tftp 172.17.65.1
tftp&gt; get boot.nbi/i386/booter
Received 322301 bytes in 14.1 seconds
tftp&gt; quit
$ file booter
booter: Universal EFI binary with 2 architectures, x86_64, i386
</code></pre>

<p>Ignore the insane slowness, I'm testing this over VPN. Notice the path that we "get" is exactly the same as the <em>filename</em> parameter in dhcpd.conf. If you didn't get the "Received..." line, try the same thing locally on the server and go from there...</p>

<p>NFS can be a bit more involved and I'm tempted to simply point you to <a href="http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/network-nfs.html">the handbook</a>, but in a nutshell:</p>

<pre><code># nano /etc/rc.conf
rpcbind_enable="YES"
nfs_server_enable="YES"
mountd_flags="-r"
# echo /data/nb &gt;&gt; /etc/exports
# rpcbind
# nfsd -u -t -n 4
# mountd -r
</code></pre>

<p>You can test the NFS connection from the Finder, with Command-K > nfs://172.17.65.1/data/nb. A number of things can go wrong here, I strongly suggest you check the handbook as well as the server and client logs (may the Lords of Cobol be with you).</p>

<h2>Taking it for a spin</h2>

<p>Everything should now be set up and ready to go. Grab an Intel Mac and boot it with the N-key. You should see the big globe icon (looking for the server), followed by the Apple logo and spinning globe (downloading kernel) and then the normal progress indicator (mounting the DMG and booting). If you get a kernel panic, then booting with N and then Command-V will usually give you a hint as to what's wrong.</p>

<p>Any number of things could have gone wrong here and I can't recommend Mike Bombich's excellent <a href="http://www.afp548.com/netboot/mactips/netboot.html">Troubleshooting the NetBoot Process</a> article enough (thank the gods it's now hosted in a safe place on AFP548).</p>

<h2>Does this mean that...</h2>

<p>... you can use any PC server to NetBoot Macs? Yes. But in all honesty, this is all little more than a clunky workaround for sysadmins desperately strapped for cash (not to mention too much time on their hands). And even though it also serves as a nice "training program" for understanding the inner workings of NetBoot, Apple's solution is much nicer and waaay easier to use.</p>

<p>For example, as it stands, this system will not support diskless NetBoot, and only the default NetBoot set will be available from the firmware. As I understand, this is because Apple actually uses a proprietary DHCP server (not the stock ISC one that we installed) that has a "special relationship" with the Mac firmware. Oh, and you can forget about limiting certain Mac models to certain NetInstall sets (which would be nice).</p>

<p>But this system works surprisingly well for us and so I decided to write it down. There's actually one more piece of the puzzle (a "secret sauce", if you will) that makes this whole thing a bit more useful (which I call "netbless"), but more on that some other time... :-P</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[Me Thinks So Too]]>
    	</title>
   		<pubDate>Fri, 26 Nov 2010 01:02:00 +0200</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1060</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1060</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>but still, the most heartfelt spam email ever:</p>

<p style="text-align:center">
<img src="/tmp/metoo.png" alt=""/>
</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[BatchDMG Updated]]>
    	</title>
   		<pubDate>Sun, 14 Nov 2010 22:33:00 +0200</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1059</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1059</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p><a href="http://unflyingobject.com/blog/story/1016">A while back</a> I wrote a little utility to ease imaging large collections of discs. I had to use it recently only to discover that it didn't work anymore. Don't know why - the mount notifications just weren't firing. Tired of fussing around with PyObjc, I rewrote the whole thing in clean Objective C and everything seems to work fine again.</p>

<p>There are also some improvements - you can now specify the output path (defaults to the current directory) as the first argument as well as run it with any number of optical drives (I tested it with 2). The discs are also ejected automatically after a successful rip. And most importantly, the tool is now licensed under the <a href="http://sam.zoy.org/wtfpl/">WTFPL</a>. ;-)</p>

<p>Grab the source or universal binary from <a href="https://github.com/filipp/BatchDMG/downloads">Github</a>.</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[Still Different?]]>
    	</title>
   		<pubDate>Sat, 13 Nov 2010 18:36:00 +0200</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1058</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1058</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>"Here's to the crazy ones. The misfits. The rebels. The troublemakers..."</p>

<p>...timeless words from possibly one of the  most memorable <a href="http://www.youtube.com/watch?v=zyF1k2UZrog">ad</a> campaigns ever conceived. Apple.com even had a <a href="http://web.archive.org/web/20030602031811/www.apple.com/thinkdifferent/">hidden page</a> set aside for "Think Different" long after the actual campaign had ended.</p>

<p>Why this sudden trip down memory lane? Because I was sifting through some OS X application icons and this is what TextEdit looks like at 512x512:</p>

<p style="text-align:center">
   <img src="/images/te.jpeg" alt="TextEdit"/>
</p>

<p>Oh, and many thanks to all of you who've sent feedback about my site. I've made some improvements (you can now browse all the tags if you click on the "Blog" link and am working on getting the archive and search to work properly as well).</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[aptest]]>
    	</title>
   		<pubDate>Wed, 10 Nov 2010 22:34:00 +0200</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1057</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1057</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<p>Intermittent AirPort connectivity issues are among the toughest to troubleshoot at a service depot. I would say that in 90% of cases, the problem is with the actual network(s), but how can you spot the remaining 10%? Typically the machine will connect just fine to your local network. What you need is to generate some traffic and then monitor that over a period of time.</p>

<p>This is where <a href="http://iperf.sourceforge.net/">iperf</a> comes in:</p>

<blockquote>
  <p>Iperf was developed by NLANR/DAST as a modern alternative for measuring maximum TCP and UDP bandwidth performance. Iperf allows the tuning of various parameters and UDP characteristics. Iperf reports bandwidth, delay jitter, datagram loss.</p>
</blockquote>

<p>In other words it can do a hell of a lot more than just generate traffic, but that's what we'll use it for this time. iperf consists of two parts - a client and a server. I run our server on our FreeBSD box:</p>

<pre><code>$ cd /usr/ports/net/iperf
$ sudo make install clean
$ iperf -sD
</code></pre>

<p>That installed iperf and launched it as a server in the background. Now we need to run the client on the machine we want to test. For this, I created a dead-simple AppleScript wrapper for iperf (which also includes the iperf binary itself), just double-click and enter the address of the iperf server. This launches iperf with some options apropriate for long term testing, in a new Terminal window.</p>

<p style="text-align:center">
<img src="/images/aptest.png" alt=""/>
</p>

<p>The script (called "aptest", also part of <a href="https://github.com/filipp/mtk">MTK</a>) tries to bind the iperf instance to the AirPort interface. This will wreak havoc on your wireless network - I would advise to set up a separate base station for this kind of testing. :-)</p>

<p>It would be fun to one day create a proper GUI that would plot the CSV output of iperf, but this will have to do for now...</p>
]]>
			</description>
		</item>


	  <item>
	    <title>
  	    <![CDATA[Building a Software Update Server Replica with FreeBSD]]>
    	</title>
   		<pubDate>Fri, 05 Nov 2010 01:39:00 +0200</pubDate>
	   	<link>http://unflyingobject.com/blog/posts/1056</link>
  	 	<guid>http://unflyingobject.com/blog/posts/1056</guid>
			<author>filipp@lepalaan.org (Filipp Lepalaan)</author>
			<description>
				<![CDATA[<h2>A short intro</h2>

<p>One of the interesting facets of starting a business is that you don't have any money. This forces you to find creative, and most importantly, cost-effective (i.e. free) solutions to problems. For example, our <a href="http://www.mcare.fi/index_en.html">service center</a> is divided into two networks - the "office" network (employee's machines, printers, servers) and the "service" network (customer machines).</p>

<p>The only server license we could afford is being used by the Mac mini server in the office network, providing mail, wiki, calendar and chat services. But we also needed a robust system to host netboot, AFP, NFS and local Software Update services as well as to act as a secure gateway between the service and office networks. So I built a PC, set it up with 3 drives and <a href="http://blogs.sun.com/bonwick/entry/raid_z">RAID-Z</a> and two gigabit NICs and FreeBSD - all for roughly half the price of a Mac mini server.</p>

<p>Now the question was how do I get this PC to act as a Software Update server to all the service machines. There's actually a million ways, here's just one:</p>

<h2>The pieces</h2>

<p>First, let's find out where all the software update data is:</p>

<pre><code>$ defaults read /etc/swupd/swupd updatesDocRoot
/Volumes/Drobo/SoftwareUpdate/
</code></pre>

<p>I wanted to avoid using any messy authentication (since software updates aren't exactly trade secrets), so I set up a read-only rsync repository on the Mac mini to share the software update document root with a very simple rsyncd.conf file:</p>

<pre><code>[sus]
comment = software update server
path = /Volumes/Drobo/SoftwareUpdate/html
readonly = true
</code></pre>

<p>That's all the changes we have to do to the Mac server. On the FreeBSD side, we need to install lighttpd and dnsmasq:</p>

<pre><code>$ cd /usr/ports/www/lighttpd
$ sudo make install clean
$ cd /usr/ports/dns/dnsmasq
$ sudo make install clean
</code></pre>

<p>The FreeBSD server also functions as a DHCP server for the service network and sets itself as the primary DNS server for all the DHCP clients. The idea was that we wouldn't have to make any changes to the customer's machines to have them use our local SUS, ie to use <a href="http://hints.macworld.com/article.php?story=20071009082248452">a transparent software update solution</a>. So I added these lines to /usr/local/etc/dnsmasq.conf (172.17.65.1 is the IP of the FreeBSD server):</p>

<pre><code>address=/swscan.apple.com/172.17.65.1
address=/swcdn.apple.com/172.17.65.1
address=/swquery.apple.com/172.17.65.1
</code></pre>

<p>I then create a directory for the SUS data on my RAID-Z, ZFS pool:</p>

<pre><code>sudo mkdir /data/sus
</code></pre>

<p>and edit /usr/local/etc/lighttpd/lighttpd.conf to use the SUS docroot as the default docroot:</p>

<pre><code>server.document-root = "/data/sus/"
</code></pre>

<p>Then just fire up dnsmasq and lighttpd.</p>

<h2>Making it run</h2>

<p>The final step is to put it all together. At first I thought it would be a trivial matter of just dumping the data, but there are some additional steps that need to be taken, so I threw together this little script:</p>

<pre><code>#! /usr/bin/env bash

if [[ $# -lt 4 ]]
then
  echo "usage: $(basename $0) server repo port destination" 2&gt;&amp;1
  exit 1
fi

MAC_SERVER=$1
REMOTE_REPO=$2
REMOTE_PORT=$3
LOCAL_DOCROOT=$4
HOSTNAME=$(hostname)

# download latest update packages, removing deprecated
rsync -av --delete rsync://${MAC_SERVER}:${REMOTE_PORT}/${REMOTE_REPO} ${LOCAL_DOCROOT}

if [[ ! $? ]]
then
  echo "Failed to fetch software update content" 2&gt;&amp;1
  exit 1
fi

# update hostnames in catalog files
find ${LOCAL_DOCROOT} -name *.sucatalog -type f -exec sed -i '' "s/${MAC_SERVER}:8088/${HOSTNAME}/g" {} \;

# rebuild symlinks
cd ${LOCAL_DOCROOT}
rm ./index*
ln -s ./content/catalogs/others/index-leopard-snowleopard.merged-1.sucatalog ./index-leopard-snowleopard.merged-1.sucata$
ln -s ./content/catalogs/others/index-leopard.merged-1.sucatalog ./index-leopard.merged-1.sucatalog
ln -s ./content/catalogs/index.sucatalog ./index.sucatalog
# 10.4 seems to need this
ln -s ./content/catalogs/index.sucatalog ./content/catalogs/index-1.sucatalog
curl -o ${LOCAL_DOCROOT}/scanningpoints/scanningpointX.xml http://swscan.apple.com/scanningpoints/scanningpointX.xml
</code></pre>

<p>Save that into a file and run it:</p>

<pre><code>$ ./supdate.sh macserver.example.com sus 874 /data/sus/
</code></pre>

<p>If all worked as expected, save it so that it's run periodically (say, once a week). Notice that the script is assuming the Mac server was hosting the updates on port 8088! I had a version of the script that actually read the repo path and port from the Mac server using SSH, but I like this solution much more - no authentication required.</p>
]]>
			</description>
		</item>


  </channel>
</rss>

