<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule">
  <channel>
      <title>In Valid Logic</title>
    <link>http://invalidlogic.com</link>
    <language>en</language>
    <webMaster>ken@invalidlogic.com (Ken Robertson)</webMaster>
    <pubDate>2013-02-26T09:59:12-08:00</pubDate>
    <copyright>Copyright 2009</copyright>
    <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    <ttl>60</ttl>
    <description>Endlessly expanding technology</description>
    
    <item>
      <title>Managing APT repositories on S3 with ease</title>
      <link>http://invalidlogic.com/2013/02/26/managing-apt-repos-on-s3/</link>
      <pubDate>2013-02-26 00:00:00 -0800</pubDate>
      <guid>http://invalidlogic.com/archives/2013/02/26/managing-apt-repos-on-s3/</guid>
      <description>&lt;p&gt;S3 is a great place to host an APT repository... cheap storage, easily available,
no server to run or anything. The annoying thing is that most ways to set it up
involve using something like &lt;a href=&quot;http://mirrorer.alioth.debian.org/&quot;&gt;reprepro&lt;/a&gt; on a local box and using
&lt;a href=&quot;http://s3tools.org/s3cmd&quot;&gt;s3cmd&lt;/a&gt; to then sync the local files up to S3. For me, the annoyance is that
I use throw away VMs. I don't want to store them, or I'll remove the VM without
thinking, and then need to redownload everything to just add one one package.&lt;/p&gt;

&lt;p&gt;I wanted just a simple tool that would upload the new package, generate the
Package file adding in the new file, and update relevant hashes in the Release
file.  It seems simple, but could find something for the lazy people like me.&lt;/p&gt;

&lt;p&gt;Finally decided to scratch my own itch.  Over the weekend I wrote
&lt;a href=&quot;https://github.com/krobertson/deb-s3&quot;&gt;deb-s3&lt;/a&gt;. Have to upload a package?
No problem.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;$ deb-s3 upload my-deb-package-1.0.0_amd64.deb --bucket my-bucket
&amp;gt;&amp;gt; Examining package file my-deb-package-1.0.0_amd64.deb
&amp;gt;&amp;gt; Retrieving existing package manifest
&amp;gt;&amp;gt; Uploading package and new manifests to S3
   -- Transferring pool/m/my/my-deb-package-1.0.0_amd64.deb
   -- Transferring dists/stable/main/binary-amd64/Packages
   -- Transferring dists/stable/main/binary-amd64/Packages.gz
   -- Transferring dists/stable/Release
&amp;gt;&amp;gt; Update complete.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;If it is your first package, it creates all the necessary files
from scratch.  On your server, you can then plug it in your
&lt;code&gt;/etc/apt/sources.list&lt;/code&gt; as:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;deb https://my-bucket.s3.amazonaws.com stable main
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;It features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Specify different components or codenames as you wish. It'll maintain other
components and architectures in the Release file.&lt;/li&gt;
&lt;li&gt;Options to specify the visibility of the file.  Can set to private or
authenticated, and then use &lt;a href=&quot;https://github.com/sigil66/apt-s3&quot;&gt;apt-s3&lt;/a&gt; to
supported authenticated requests against S3.&lt;/li&gt;
&lt;li&gt;Ability to sign the Release file (GPG will prompt for the passphrase)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a href=&quot;https://github.com/krobertson/deb-s3&quot;&gt;Check it out&lt;/a&gt;. Use it, love it, fork it,
extend it, send a pull request.&lt;/p&gt;

&lt;p&gt;If you simply want to use it, its
&lt;a href=&quot;https://rubygems.org/gems/deb-s3&quot;&gt;available as a gem as well&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;$ gem install deb-s3
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And you're set.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
    <item>
      <title>Golang Oddity &#35;1</title>
      <link>http://invalidlogic.com/2012/10/16/golang-oddity-1/</link>
      <pubDate>2012-10-16 00:00:00 -0700</pubDate>
      <guid>http://invalidlogic.com/archives/2012/10/16/golang-oddity-1/</guid>
      <description>&lt;p&gt;Every language in existance has its own set of oddities. Since I've been working
in Go full time for a couple of months now, I have run into some of its nuances
and wanted to chronicle some of them.&lt;/p&gt;

&lt;p&gt;While I am being critical in these kind of posts, the intent isn't to bash Go,
more it is about educating others. Go isn't breaking existing convention (too
much), however it is an emerging language and there isn't as much out there to
familiarize a newbie with things to be aware of.&lt;/p&gt;

&lt;p&gt;So to start off with, give you something simple but very annoying:&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Strings cannot be null, only empty&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;In Go, null (or &lt;code&gt;nil&lt;/code&gt;) isn't covered as heavily as I wish it was. Not every type
is nilable, and this can lead to some annoyances.&lt;/p&gt;

&lt;p&gt;All strings upon creation are simply an empty string (&lt;code&gt;&quot;&quot;&lt;/code&gt;). On the surface this
doesn't sound bad, but it can cause a lot of other busy work when dealing with
other things that allow string to be null, or where the difference between null
and empty are very important.&lt;/p&gt;

&lt;p&gt;Most databases have understood for a long time that a null string and an empty
string are completely different. Another is with user supplied input. Go is
excellent for writing servers and APIs, and a common case with an API is CRUD
functionality. You might want to support a partial update, where omitted values
(essentially null) or not altered while supplied values (which may be a blank
string) are updated.&lt;/p&gt;

&lt;p&gt;Take the case of user supplied input, such as over a JSON API:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// try at http://play.golang.org/p/1A7XZva4C1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;encoding/json&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&amp;quot;name&amp;quot;`&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&amp;quot;location&amp;quot;`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`{&amp;quot;name&amp;quot;:&amp;quot;John&amp;quot;}`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Name: %q\nLocation: %q\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;




&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Name: &amp;quot;John&amp;quot;
Location: &amp;quot;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;In this case I define a struct and unmarshal some JSON that only specified the
name. But then you can see &lt;code&gt;Location&lt;/code&gt; is set to &lt;code&gt;&quot;&quot;&lt;/code&gt;. If they
already have Name and Location set, and are doing an update with only Name, I don't
want to blank out Location.  Now you got to do hoops.&lt;/p&gt;

&lt;h4&gt;Pick up that hula hoop... welcome casting&lt;/h4&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// try at http://play.golang.org/p/VlAJ4N9uGY&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;encoding/json&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&amp;quot;name&amp;quot;`&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&amp;quot;location&amp;quot;`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`{&amp;quot;name&amp;quot;:&amp;quot;John&amp;quot;,&amp;quot;location&amp;quot;:&amp;quot;Gotham&amp;quot;}`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Your zipcode is %d\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lookupZipcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lookupZipcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Gotham&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Metropolis&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;In this mock example, passing the location to another function to look up the
zip code, but it expects the location as a &lt;code&gt;string&lt;/code&gt;, so now you need to cast it.&lt;/p&gt;

&lt;h4&gt;Uhh ohh, with interace{}, type enforcement isn't inherent&lt;/h4&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;  &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`{&amp;quot;name&amp;quot;:&amp;quot;John&amp;quot;,&amp;quot;location&amp;quot;:1234}`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Your zipcode is %d\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lookupZipcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;




&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;panic: interface conversion: interface is float64, not string

goroutine 1 [running]:
main.main()
  /tmpfs/gosandbox-9aac7f9a_0c33fe58_a998effb_2a4a973a_458fb2a3/prog.go:17 +0xcd
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;However, when using &lt;code&gt;interface{}&lt;/code&gt; as our type we lose the inherit type handling
within &lt;code&gt;json.Unmarshal&lt;/code&gt; and this will result in a panic rather than returning an
error. In this case, the panic is on the print line rather than when unmarshaling.
So now we need to do our own type validation, which has annoyances of its own.&lt;/p&gt;

&lt;h4&gt;Type checking #1&lt;/h4&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Your zipcode is %d\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lookupZipcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;OMG you didn&amp;#39;t enter the right value&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h4&gt;Type checking #2&lt;/h4&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Your zipcode is %d\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lookupZipcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;OMG you didn&amp;#39;t enter the right value&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;For type checking you can either go the &lt;code&gt;switch&lt;/code&gt; route or check the second
parameter in the cast call. If you're morbid you could write your own &lt;code&gt;typeof()&lt;/code&gt;
using reflection perhaps.&lt;/p&gt;

&lt;p&gt;For me, it is annoying because I need to actually do it and care. Perhaps I'm
simply too spoiled by Ruby, however plenty of other languages support null strings
as well.  And so what if I am spoiled by Ruby... it focuses on developer
happiness rather than hoops for performance. There are trade offs to all things,
and I've accepted Go's empty strings. I just miss my null strings.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
    <item>
      <title>Talking on the Food Fight Show</title>
      <link>http://invalidlogic.com/2012/10/03/talking-on-the-food-fight-show/</link>
      <pubDate>2012-10-03 00:00:00 -0700</pubDate>
      <guid>http://invalidlogic.com/archives/2012/10/03/talking-on-the-food-fight-show/</guid>
      <description>&lt;div style=&quot;float:right; margin-left: 10px; margin-bottom: 5px&quot;&gt;&lt;img src=&quot;http://s3.amazonaws.com/invalidlogic-blog/food-fight-show.png&quot; width=&quot;233&quot; height=&quot;75&quot;/&gt;&lt;/div&gt;


&lt;p&gt;Earlier this week I had the pleasure of talking with Bryan and Nathan on the
&lt;a href=&quot;http://foodfightshow.org/&quot;&gt;Food Fight Show&lt;/a&gt;, a devops focused podcast, talking
about PaaS, Cloud Foundry, where PaaS is heading, and also talking about Go and
the influence it will have on operations.&lt;/p&gt;

&lt;p&gt;Be sure to &lt;a href=&quot;http://foodfightshow.org/2012/10/ken-robertson-on-go.html&quot;&gt;check it out&lt;/a&gt;
or look it up on iTunes.&lt;/p&gt;

&lt;p&gt;It isn't really a secret that &lt;a href=&quot;http://apcera.com&quot;&gt;Apcera&lt;/a&gt; has been really looking
at Go... just look follow &lt;a href=&quot;http://twitter.com/krobertson&quot;&gt;me&lt;/a&gt;
or &lt;a href=&quot;http://twitter.com/derekcollison&quot;&gt;Derek&lt;/a&gt; on Twitter. We think Go will be
growing wildly in cloud services and high scale environments in the future. It is
a very elegant language for server/systems development, has a solid base, growing
ecosystem, and it will continue to grow and mature in the space. In some ways, I
see it as solving the problems people were saying Node solved, but in a better way.&lt;/p&gt;

&lt;p&gt;I'm starting to put together a few little mini posts about some of my adventures
(or misadventures) with Go. I've been really starting to like it a lot, and there
are some powerful things you can do with it that are encapsulated in a simple way.
But it also has some idiosyncrasies, some of which are just ironing out as the
language/ecosystem matures, and others are design decisions.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
    <item>
      <title>Joining Apcera - Building Something From Scratch</title>
      <link>http://invalidlogic.com/2012/08/28/joining-apcera/</link>
      <pubDate>2012-08-28 00:00:00 -0700</pubDate>
      <guid>http://invalidlogic.com/archives/2012/08/28/joining-apcera/</guid>
      <description>&lt;p&gt;This morning I realized I never really updated my blog after changing jobs a few
months ago. Back in June, I posted to the &lt;a href=&quot;http://blog.paas.io/2012/06/08/paasio-joining-forces-with-apcera/&quot;&gt;PaaS.io blog&lt;/a&gt;
about joining &lt;a href=&quot;http://apcera.com&quot;&gt;Apcera&lt;/a&gt;, though never actually made a personal
post about the change.&lt;/p&gt;

&lt;p&gt;Earlier in the year, I had the opportunity to meet &lt;a href=&quot;http://twitter.com/derekcollison&quot;&gt;Derek Collison&lt;/a&gt;. Can read
the PaaS.io blog post about why it made sense to merge the two. On a personal
point of view, I was also drawn to the opportunity to get back to an early stage,
highly motivated, build something fresh kind of startup.&lt;/p&gt;

&lt;p&gt;My first profession gig right after college was at &lt;a href=&quot;http://telligent.com&quot;&gt;Telligent&lt;/a&gt;
and I started when the company was just a month old. The early years at Telligent
are amung the most memoriable of my career and a lot of that stemed from the
energy at the company. A combination of the team transending to feeling like a
family, building a great product out of nothing, and truly being energetic and
dedicated to the goal. All of us ate, slept, and drank the product in those early
years.&lt;/p&gt;

&lt;p&gt;Since then, I've grown and learned a lot, however most of my work since has been on
already established products and later-stage startups. Typically when you start
needing Operations people, or people to do scaling/performance work, you already
have something that is generating that need.&lt;/p&gt;

&lt;p&gt;Working with Derek presented itself as a really unqiue chance. The team of people
he was gathering together was truly awesome with strong backgrounds. It would be
a tremendous chance ot learn from my peers. On top of that, he had the financial
backing to be able to carry it through. He had plenty of experience from building
Cloud Foundry and talking with clients, and his goals for Apcera's products were
pushing the status quo and appealing as a challenge.&lt;/p&gt;

&lt;p&gt;It was almost one of those &quot;if I could do that again knowing what I know now&quot;
type chances. Do an early stage startup again, build something incredible from
scratch. Two of the biggest motivators for me are fulfillment from building
something with my own hands and tackling the kind of challenging problem that your
first reaction is &quot;yeah, I think I could do that&quot; followed by you staring into
space while starting to think about how.&lt;/p&gt;

&lt;p&gt;It has been a littl over two and a half months at Apcera and it as been amazing
so far. We're deep in code building what we've been envisioning. I am definitely
eager to spill the beans, but until then I can only offer a &lt;a href=&quot;http://www.youtube.com/watch?v=dQw4w9WgXcQ&quot;&gt;slight preview&lt;/a&gt;.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
    <item>
      <title>Deploying Ubuntu 12.04 on XenServer Made Easy</title>
      <link>http://invalidlogic.com/2012/05/01/deploying-ubuntu-12-04-on-xenserver-made-easy/</link>
      <pubDate>2012-05-01 00:00:00 -0700</pubDate>
      <guid>http://invalidlogic.com/archives/2012/05/01/deploying-ubuntu-12-04-on-xenserver-made-easy/</guid>
      <description>&lt;p&gt;To follow up on my &lt;a href=&quot;/2012/04/28/ubuntu-precise-on-xenserver-disk-errors&quot;&gt;previous post&lt;/a&gt;
about disk errors with Ubuntu 12.04 on XenServer, I wanted to cover the process
I've put in place for provisioning Ubuntu VMs.&lt;/p&gt;

&lt;p&gt;With &lt;a href=&quot;http://paas.io&quot;&gt;PaaS.io&lt;/a&gt;, I have a mixture between systems deployed on bare
metal and virtualized.  With the virtualized systems, I set out to make the
provisioning as easy as if I was using an IaaS provider, while still giving me
fine control over sizing and placement. Some of the decisions there are enough
for another post.&lt;/p&gt;

&lt;p&gt;Ubuntu 12.04 is the new hotness and I'd been anxiously awaiting it, with plans
to progressively roll it out throughout PaaS.io.&lt;/p&gt;

&lt;p&gt;With XenServer, it provides an easy template for provisioning Ubuntu Lucid 10.04
VMs and even for some newer releases.  However, the way XenSever provisions
Ubuntu is to essentially netboot it and install it from a remote source. Because
of that, we can't simply use one of those templates buts install a newer release.&lt;/p&gt;

&lt;p&gt;Fortunately, the template itself is very simple, and which release it installs is
just a configuration parameter.&lt;/p&gt;

&lt;p&gt;To create a new Ubuntu 12.04 template, simply log into the XenServer console and
runt he following commands.  It will clone the Lucid template and then change
the parameter for the release to install from &lt;code&gt;lucid&lt;/code&gt; to &lt;code&gt;precise&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;TEMPLATE_UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;xe template-list &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        name-label=&amp;quot;Ubuntu Lucid Lynx 10.04 (64-bit)&amp;quot; params=uuid --minimal`&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;NEW_TEMPLATE_UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;xe vm-clone &lt;span class=&quot;nv&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$TEMPLATE_UUID&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        new-name-label=&amp;quot;Ubuntu Precise (64-bit)&amp;quot;`&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; xe template-param-set other-config:default_template&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        other-config:debian-release=precise uuid=$NEW_TEMPLATE_UUID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now you will find a &quot;Ubuntu Precise (64-bit)&quot; option in the template list of
XenCenter.&lt;/p&gt;

&lt;div style=&quot;text-align: center&quot; markdown=&quot;1&quot;&gt;
&lt;img src=&quot;http://invalidlogic-blog.s3.amazonaws.com/2012-04-30-xencenter1.jpg&quot; alt=&quot;XenCenter template list&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;Now, we can actually provision a new box.  Next, one interesting discovery was
that you can pass in a kickstart script in the boot parameters options for the new
VM.&lt;/p&gt;

&lt;p&gt;Kickstart allows you to do a scripted installation, automated pretty much
every aspect of the system.  Instead of picking a bunch of options, it allows
for an easy, repeatable process that basically leaves the machine completely
ready to go.&lt;/p&gt;

&lt;p&gt;To use a kickstart script, make a script available over HTTP somewhere on your
LAN or on the public internet.  By the time it is grabbed, the machine will have
an IP, DNS, and all.  Then, simply add &lt;code&gt;ks=http://url/to/your/kickstart&lt;/code&gt; to the
beginning part of &quot;advanced OS boot parameters&quot; option when selecting the
installation media.&lt;/p&gt;

&lt;div style=&quot;text-align: center&quot; markdown=&quot;1&quot;&gt;
&lt;img src=&quot;http://invalidlogic-blog.s3.amazonaws.com/2012-04-30-xencenter2.jpg&quot; alt=&quot;XenCenter media selection&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;Below is a cleaned version of the kickstart script I used on my Ubuntu VMs. The
main things of note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sets up my partition table&lt;/li&gt;
&lt;li&gt;Configures base system with ubuntu-minimal as well as some common packages
like openssh-server, curl, wget, and screen.&lt;/li&gt;
&lt;li&gt;Disables the creation of the &lt;code&gt;ubuntu&lt;/code&gt; user (I create a normal every day user through chef)&lt;/li&gt;
&lt;li&gt;Configures the fstab with &lt;code&gt;barrier=0&lt;/code&gt; as mentioned before&lt;/li&gt;
&lt;li&gt;Disables &lt;code&gt;/bin/sh&lt;/code&gt; from pointing to &lt;code&gt;/bin/dash&lt;/code&gt; (personal preference)&lt;/li&gt;
&lt;li&gt;Updates apt sources&lt;/li&gt;
&lt;li&gt;Installs xenstore-utils&lt;/li&gt;
&lt;li&gt;Downloads some auto-configuration scripts&lt;/li&gt;
&lt;li&gt;Installs XenTools&lt;/li&gt;
&lt;li&gt;Installs the Ubuntu virtual kernel and removes the generic one&lt;/li&gt;
&lt;li&gt;Cleans up apt caches&lt;/li&gt;
&lt;li&gt;Shuts down the VM.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;lang en_US
langsupport en_US
keyboard us
timezone America/Los_Angeles
text
install
skipx
halt
url --url http://us.archive.ubuntu.com/ubuntu

rootpw pa$$word   # you should replace, and use --iscrypted
auth --useshadow --enablemd5
user --disabled

bootloader --location=mbr
zerombr yes
clearpart --all --initlabel
part /boot --fstype=ext2 --size=64
part swap --size=1024
part / --fstype=ext4 --size=1 --grow

network --device=eth0 --bootproto=static --ip=10.0.0.50 --netmask=255.255.255.0 \
        --nameserver=10.0.0.1 --gateway=10.0.0.1
firewall --disabled

%packages
ubuntu-minimal
openssh-server
screen
curl
wget

%post

# update fstab for the root partition
perl -pi -e &amp;#39;s/(errors=remount-ro)/noatime,nodiratime,$1,barrier=0/&amp;#39; /etc/fstab

# point sh to bash instead of dash
rm /bin/sh
ln -s /bin/bash /bin/sh

# add normal apt source list
(
cat &amp;lt;&amp;lt;&amp;#39;EOP&amp;#39;
deb http://us.archive.ubuntu.com/ubuntu/ precise main restricted universe
deb http://us.archive.ubuntu.com/ubuntu/ precise-security main restricted universe
deb http://us.archive.ubuntu.com/ubuntu/ precise-updates main restricted universe
EOP
) &amp;gt; /etc/apt/sources.list
apt-get update
apt-get upgrade -y

# install some additional packages
apt-get install -y xenstore-utils

# set up xenserver automation scripts
AUTOMATER_REPO=https://raw.github.com/krobertson/xenserver-automater
curl $AUTOMATER_REPO/master/usr/sbin/xe-set-hostname &amp;gt; /usr/sbin/xe-set-hostname
curl $AUTOMATER_REPO/master/usr/sbin/xe-set-network &amp;gt; /usr/sbin/xe-set-network
curl $AUTOMATER_REPO/master/usr/sbin/generate-sshd-keys &amp;gt; /usr/sbin/generate-sshd-keys
curl $AUTOMATER_REPO/master/etc/init/xe-automator.conf &amp;gt; /etc/init/xe-automator.conf
chmod a+x /usr/sbin/xe-set-hostname
chmod a+x /usr/sbin/xe-set-network
chmod a+x /usr/sbin/generate-sshd-keys

# setup locales
locale-gen en_US.UTF-8
update-locale LANG=&amp;quot;en_US.UTF-8&amp;quot;
echo &amp;#39;LANG=en_US.UTF-8&amp;#39; &amp;gt;&amp;gt; /etc/environment
echo &amp;#39;LC_ALL=en_US.UTF-8&amp;#39; &amp;gt;&amp;gt; /etc/environment

# install xe tools
cd /tmp
wget http://some/url/to/xe-guest-utilities_6.0.0-743_amd64.deb
dpkg -i xe-guest-utilities_6.0.0-743_amd64.deb

# install paravirt kernel image
apt-get install -f -y linux-virtual
dpkg -l | grep generic | grep linux | awk &amp;#39;{print $2}&amp;#39; | xargs apt-get remove -y

# clean up some stuff
rm -f /etc/ssh/ssh_host_*
rm -f /var/cache/apt/archives/*.deb
rm -f /var/cache/apt/*cache.bin
rm -f /var/lib/apt/lists/*_Packages
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;It is important that it shuts down at the end.  My goal was to have it be all
inclusive, and that means setting up the virtual kernel.  However, it can't successfully
reboot, because we need to update some PV boot options before it is ready to go.&lt;/p&gt;

&lt;p&gt;Also, some packages must be installed in the post steps. The default install sources
for Ubuntu don't always have all packages available, and I found it best to do
the kernel last.&lt;/p&gt;

&lt;p&gt;When you first bring up the new VM in XenServer, you may need to enter in a few
details if you don't have DHCP running.  It will self configure by default,
but I normally opt to manually configure it to ensure the template gets a certain
IP just to avoid any future possible collision.&lt;/p&gt;

&lt;p&gt;After the bootstrapping is done and the VM is then off, log into console on
the XenServer host itself and run the following snippet:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;VMNAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;precise-20120501
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;xe vm-list name-label&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$VMNAME&amp;quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;uuid --minimal&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;EDITOR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;cat xe-edit-bootloader -n &lt;span class=&quot;s2&quot;&gt;&amp;quot;$VMNAME&amp;quot;&lt;/span&gt; -p 1 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        -f /grub/grub.cfg &amp;gt; /tmp/$VMNAME-grub&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;KERNEL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;grep vmlinuz /tmp/&lt;span class=&quot;nv&quot;&gt;$VMNAME&lt;/span&gt;-grub | grep virtual |
&lt;span class=&quot;go&quot;&gt;        grep -v recovery | awk &amp;#39;{print $2}&amp;#39;`&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ROOT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;grep vmlinuz /tmp/&lt;span class=&quot;nv&quot;&gt;$VMNAME&lt;/span&gt;-grub | grep virtual |
&lt;span class=&quot;go&quot;&gt;        grep -v recovery | awk &amp;#39;{print $3}&amp;#39;`&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RAMDISK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;grep initrd /tmp/&lt;span class=&quot;nv&quot;&gt;$VMNAME&lt;/span&gt;-grub | head -1 | awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; xe vm-param-set &lt;span class=&quot;nv&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$UUID&lt;/span&gt; PV-bootloader-args&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;--kernel=$KERNEL --ramdisk=$RAMDISK&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; xe vm-param-set &lt;span class=&quot;nv&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$UUID&lt;/span&gt; PV-args&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$ROOT ro quiet console=hvc0&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Before you run it, of course set the VMNAME to the name of your VM.  You might
also want to check some of the values as you go (&lt;code&gt;echo $UUID&lt;/code&gt;). You can use the
&lt;code&gt;xe-edit-bootloader&lt;/code&gt; command to view the grub configuration within the VM, but
need to set the PV settings outside the guest.  By faking the &lt;code&gt;EDITOR&lt;/code&gt; to cat,
you can export the grub file to a local file, then use some grep+awk to get
the necessary pieces and finally set the PV settings correctly.&lt;/p&gt;

&lt;p&gt;At this point, the machine is ready to be booted, converted into a template, or
simply cloned.  I personally like to leave my templates as never-been-used.&lt;/p&gt;

&lt;p&gt;One of the main benefits of an IaaS setup like OpenStack or CloudStack is the
self orientating of the VMs.  Normally with a template, it keeps the template's
setting for its hostname and network configuration.  However, I found some example
scripts on Github for passing network information into a VM through the VM's
&quot;xenstore&quot; options.  That way on boot, the VM can read in the settings it needs
and update itself. I &lt;a href=&quot;https://github.com/krobertson/xenserver-automater&quot;&gt;did some work&lt;/a&gt;
to update the scripts to work with Precise, to more thoroughly update the hostname
and DNS, as well as to regenerate the ssh host keys (since the kickstart did
delete them).&lt;/p&gt;

&lt;p&gt;As an example, this would be how to clone the template to a VM, set the params,
and boot it:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;xe vm-install &lt;span class=&quot;nv&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;precise-20120501 new-name-label&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;builder&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; xe vm-param-set &lt;span class=&quot;nv&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$UUID&lt;/span&gt; xenstore-data:vm-data/ip&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10.0.0.11
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; xe vm-param-set &lt;span class=&quot;nv&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$UUID&lt;/span&gt; xenstore-data:vm-data/gw&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10.0.0.1
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; xe vm-param-set &lt;span class=&quot;nv&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$UUID&lt;/span&gt; xenstore-data:vm-data/nm&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;255.255.255.0
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; xe vm-param-set &lt;span class=&quot;nv&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$UUID&lt;/span&gt; xenstore-data:vm-data/ns&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;10.0.0.1 10.0.0.2&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; xe vm-start &lt;span class=&quot;nv&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$UUID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That is cool and all, but I don't want to log into the XenServer console each
time I want to setup a VM.  Luckily, found a plugin for Chef's &lt;code&gt;knife&lt;/code&gt; utility
that &lt;a href=&quot;https://github.com/bvox/knife-xenserver&quot;&gt;adds XenServer provisioning&lt;/a&gt;. I
forked it and added &lt;a href=&quot;https://github.com/krobertson/knife-xenserver&quot;&gt;setting xenstore network parameters&lt;/a&gt;
to it.&lt;/p&gt;

&lt;p&gt;Now, provisioning a new VM, configuring it, and bootstrapping chef on it is just
a matter of one call:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; knife xenserver vm create --vm-template precise-20120501 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                            -x root --keep-template-networks \&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                            -r &amp;quot;role[foo]&amp;quot; -E production \&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;                            --vm-ip 10.0.0.12 --vm-name foobar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The command may be a little long, but it is all encapsulated in a single command.
I simply have an internal README of sorts with the command pre-prepared for various
roles.&lt;/p&gt;

&lt;p&gt;If you have any questions, please leave a comment and ask.  I'd be glad to help
and always looking to improve my process as well.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
    <item>
      <title>Fixing random disk errors with Ubuntu 12.04 Precise on XenServer</title>
      <link>http://invalidlogic.com/2012/04/28/ubuntu-precise-on-xenserver-disk-errors/</link>
      <pubDate>2012-04-28 00:00:00 -0700</pubDate>
      <guid>http://invalidlogic.com/archives/2012/04/28/ubuntu-precise-on-xenserver-disk-errors/</guid>
      <description>&lt;p&gt;Ubuntu 12.04 LTS Precise is hot off the press right now.  Over the past few days,
have been working on building new base images for &lt;a href=&quot;http://paas.io&quot;&gt;PaaS.io&lt;/a&gt;, but
was running into random issues where the root parition would encounter an error
and freeze up.  It normally happened just after it would finish booting and about
50% of the time.&lt;/p&gt;

&lt;p&gt;A few times it happened after I already logged in, so was able to do basic read
only operations.  In &lt;code&gt;dmesg&lt;/code&gt;, was able to see the following:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;[    6.748868] blkfront: barrier: empty write xvda op failed
[    6.748876] blkfront: xvda: barrier or flush: disabled
[    6.748890] end_request: I/O error, dev xvda, sector 6584768
[    6.748908] end_request: I/O error, dev xvda, sector 6584768
[    6.748943] Aborting journal on device xvda6-8.
[    6.767022] EXT4-fs error (device xvda6): ext4_journal_start_sb:327: Detected aborted journal
[    6.767046] EXT4-fs (xvda6): Remounting filesystem read-only
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Or if you weren't able to log in first, you might see this in the XenCenter
console:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://img.skitch.com/20120427-qxcyrn473jdw37qi67ay1wguqf.medium.jpg&quot; alt=&quot;XenCenter show&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After some Googling, was able to track a similar error down by someone else. The
fix was to update the mount options for the root partition.  Mine are now:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;noatime,nodiratime,errors=remount-ro,barrier=0
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The key is the &lt;code&gt;barrier=0&lt;/code&gt;.  From some &lt;a href=&quot;http://kernelnewbies.org/Ext4#head-25c0a1275a571f7332fa196d4437c38e79f39f63&quot;&gt;documentation&lt;/a&gt;, it is an option to help increase the
integrity of writes by ensuring everything is flushed to disk be committing to the
journal.  However sometimes in a virtualized environment that is difficult to
guarantee.  In my case, have disk-&gt;RAID-&gt;dom0-&gt;LVM-&gt;domU.&lt;/p&gt;

&lt;p&gt;Figure many other people will be diving into Precise this weekend, potentially
running into this issue like me.&lt;/p&gt;

&lt;p&gt;Soon, will post some additional details about how to easily get a nice Precise
template in XenServer 6. I've been getting my setup nicely tuned using a kickstart
script for the base system and leveraging xenstore data to dynamically setup the
IP and hostname on boot.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
    <item>
      <title>Configuring MongoDB Replica Sets With Keepalived</title>
      <link>http://invalidlogic.com/2012/02/23/configuring-mongodb-replica-sets-with-keepalived/</link>
      <pubDate>2012-02-23 00:00:00 -0800</pubDate>
      <guid>http://invalidlogic.com/archives/2012/02/23/configuring-mongodb-replica-sets-with-keepalived/</guid>
      <description>&lt;p&gt;While working on developing &lt;a href=&quot;http://paas.io&quot;&gt;PaaS.io&lt;/a&gt;, one of my primary objectives is to
ensure that everything is configured to be truly Highly Available (HA).
This means everything has a secondary, replicated, and has automated
failover. This way it is nicely resilent and fault tolerant. Core
infrastructure changes can be made without any affect to running
applications, servers go down without issues. Sweet, huh?&lt;/p&gt;

&lt;p&gt;When it came to setting up MongoDB, the obvious option was to go to
using Replica Sets. They're like master-slave replication in RDBMSes but
the master node is essentially floating.  Client applications connect to
the whole cluster, identify the master, and then start to speak to it.&lt;/p&gt;

&lt;p&gt;By default, Cloud Foundry provisions a dedicated MongoDB instance for
you and provides you the IP, port, and other credentials. This doesn't
include replication, and focuses on single IP connections rather than
replica sets.&lt;/p&gt;

&lt;p&gt;However when using Replica Sets, the connection pattern in your code is
slightly different.  You use a &lt;code&gt;ReplSetConnection&lt;/code&gt; instead of a
normal &lt;code&gt;Connection&lt;/code&gt;, in ruby driver speak. So you need to &lt;em&gt;know&lt;/em&gt; you're
connecting to a Replica Set if the host you're connecting to isn't the
master. If you only connect to the master though, you can use a
traditional connection.&lt;/p&gt;

&lt;p&gt;I was interested in maintainin full compatibility with Cloud Foundry's
out-of-the-box experience, so first looked at using &lt;code&gt;mongos&lt;/code&gt; in front of
replicas. It is normally used to front a sharded setup, but using it
without sharding is still a &lt;a href=&quot;https://jira.mongodb.org/browse/SERVER-1594&quot;&gt;feature request&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So I set out looking at how to use a virtual IP
have it track which node is the master. In this case, if one switches over, it will
pick it up and move the virtual IP to follow. This would be mostly
transparent to the application. The only handling in the app is the next
query will fail, but quickly reconnect and its fine.&lt;/p&gt;

&lt;p&gt;I'd already been using &lt;a href=&quot;http://www.keepalived.org/&quot;&gt;keepalived&lt;/a&gt; for HA within HAProxy, and one of the
nice things it provides is the ability to define a script to run as a
part of its local health checks. Using this, can have a script that just
asks the local system &lt;em&gt;&quot;you the master?&quot;&lt;/em&gt; and returns appropriately.&lt;/p&gt;

&lt;p&gt;Below is the script:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;optparse&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:hostname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;:port&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;27017&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;:password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;optparser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OptionParser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;banner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Usage: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vg&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; [options]&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-H&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;--hostname HOST&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Hostname&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hostname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-P&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;--port PORT&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Hostname&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-u&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;--username USER&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Username&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-p&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;--password PASSWORD&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Password&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;optparser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse!&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
  &lt;span class=&quot;vg&quot;&gt;$stderr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
  &lt;span class=&quot;vg&quot;&gt;$stderr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;optparser&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;mongo&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Mongo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hostname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;authenticate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;master_status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;isMaster&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;master_status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ismaster&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This won't return any output, but will exit with 0 if it is the master
or 1 if it isn't.&lt;/p&gt;

&lt;p&gt;Its requirements are simple... Ruby, RubyGems, &lt;code&gt;mongo&lt;/code&gt; gem, and
recommend the &lt;code&gt;bson_ext&lt;/code&gt; gem too.&lt;/p&gt;

&lt;p&gt;Then within our &lt;code&gt;keepalived.conf&lt;/code&gt; file, it looks like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;global_defs {
   notification_email {
     me@example.com
   }
   notification_email_from system@example.com
   smtp_server 192.168.1.1
   smtp_connect_timeout 30
}

# Define the script used to check if mongod is running
vrrp_script chk_mongod {
    script &amp;quot;killall -0 mongod&amp;quot;
    interval 2 # every two seconds
    weight 2
}

# Define the script to see if the local node is the primary
vrrp_script chk_mongo_primary {
    script &amp;quot;/usr/local/mongodb/bin/mongo_check_primary -u admin -p password&amp;quot;
    interval 2 # every two seconds
    weight 2
}

# Configuation for the virtual interface
vrrp_instance VI_1 {
    interface bond0
    state node MASTER        # SLAVE on the other nodes
    priority 101             # 100 on other nodes
    virtual_router_id 55

    authentication {
        auth_type AH
        auth_pass secret     # Set this to some secret phrase
    }

    # The virtual ip address shared between the two nodes
    virtual_ipaddress {
        192.168.1.222
    }

    # Use the script above to check if we should fail over
    track_script {
        chk_mongod
        chk_mongo_primary
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;With this in place, if a server goes down, it'll switch. If &lt;code&gt;mongod&lt;/code&gt;
dies, it will switch over (since Mongo itself will recognize that), and
if the current primary is switched, the &lt;code&gt;mongo_check_primary&lt;/code&gt; will
return an exit code of 1, causing it to switch over.&lt;/p&gt;

&lt;p&gt;Another reason this might be useful in some cases is because some clients &lt;a href=&quot;https://github.com/bcg/em-mongo/issues/12&quot;&gt;still don't
support replica sets&lt;/a&gt;. With
this method, they don't need to.&lt;/p&gt;

&lt;p&gt;In addition to these steps, you will need to perform the normal steps to
setup keepalived.  These would include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure &lt;code&gt;mongod&lt;/code&gt; is bound to &lt;code&gt;0.0.0.0&lt;/code&gt; so it'll accept any incoming
connection.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;net.ipv4.ip_nonlocal_bind=1&lt;/code&gt; in sysctl so you can use virtual
IPs.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Try this out and let me know your experiences. If you're interested in
this kind of seamless infrastructure automation, check out
&lt;a href=&quot;http://paas.io&quot;&gt;PaaS.io&lt;/a&gt; or drop me a line.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
    <item>
      <title>Jekyll on PaaS.io with Cloud Foundry</title>
      <link>http://invalidlogic.com/2012/01/06/jekyll-on-paasio-with-cloud-foundry/</link>
      <pubDate>2012-01-06 00:00:00 -0800</pubDate>
      <guid>http://invalidlogic.com/archives/2012/01/06/jekyll-on-paasio-with-cloud-foundry/</guid>
      <description>&lt;p&gt;Recently I moved my blog over to the service I am currently working on building, &lt;a href=&quot;http://paas.io&quot;&gt;PaaS.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Running Jekyll on PaaS.io isn't all that different from running it on other services, though I had a few other goals in mind.  The way I wanted it set up was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stop using &lt;code&gt;rack-jekyll&lt;/code&gt;.  Its a nice gem, however it is locked to an older version of Jekyll.  And the current gem is on an even more outdated one.  Currently, Cloud Foundry doesn't support pulling bundler sources from git too.&lt;/li&gt;
&lt;li&gt;Have a &lt;code&gt;public&lt;/code&gt; folder for static content like CSS and images.&lt;/li&gt;
&lt;li&gt;Have the &lt;code&gt;_site&lt;/code&gt; folder for generated content&lt;/li&gt;
&lt;li&gt;Don't have it copy the &lt;code&gt;Gemfile&lt;/code&gt; and the &lt;code&gt;config.ru&lt;/code&gt; into the &lt;code&gt;_site&lt;/code&gt; folder (annoys me)&lt;/li&gt;
&lt;li&gt;Redirect &lt;code&gt;www.invalidlogic.com&lt;/code&gt; to &lt;code&gt;invalidlogic.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Low foot print&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;First, the &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rubygems&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rack-contrib&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:require&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rack/contrib/try_static&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rack-redirect&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;thin&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:development&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;jekyll&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;RedCloth&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rdiscount&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The main gems being used are &lt;code&gt;thin&lt;/code&gt;, &lt;code&gt;rack-contrib&lt;/code&gt; (for TryStatic, note on that later), and &lt;code&gt;rack-redirect&lt;/code&gt; (for www redirection).  I also include some of the gems I use for Jekyll in the development group.  That way they are available locally but not loaded when I deploy (lower footprint... and yes, it is minor).&lt;/p&gt;

&lt;p&gt;Now, the &lt;code&gt;config.ru&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bundler&amp;#39;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Bundler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;require&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Solo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;DomainRedirect&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TryStatic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;_site&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:urls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%w[/]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;index.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/index.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Static&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;public&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:urls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%w[/]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;text/html&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Not Found&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;There are 4 rack components here.  First, &lt;code&gt;Rack::EY::Solo::DomainRedirect&lt;/code&gt; is the &lt;code&gt;rack-redirect&lt;/code&gt; gem and handles the www redirection.  Next, is &lt;code&gt;Rack::TryStatic&lt;/code&gt;.  It is used to access files from the &lt;code&gt;_site&lt;/code&gt; generated content directory.  It gives a couple different &lt;code&gt;:try&lt;/code&gt; values for different ways to find the intended file.  Then is the &lt;code&gt;Rack::Static&lt;/code&gt; which gets static content from the &lt;code&gt;public&lt;/code&gt; directory.  No need to try different combinations.  And last is a generic lambda that will return 404.&lt;/p&gt;

&lt;p&gt;Next, want to avoid duplication.  With things as they are, when I run &lt;code&gt;jekyll&lt;/code&gt; it will copy the &lt;code&gt;public&lt;/code&gt; and other items into the &lt;code&gt;_site&lt;/code&gt; folder duplicating it.  To resolve that, in our &lt;code&gt;_config.yml&lt;/code&gt;, can add an exclude line:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;public&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Gemfile&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Gemfile.lock&amp;#39;&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;config.ru&amp;#39;&lt;/span&gt; &lt;span class=&quot;p-Indicator&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And with that, we are set!  All of our goals are met.  Commit and push to deploy!  Currently I have &lt;a href=&quot;http://cloudfoundry.org&quot;&gt;Cloud Foundry&lt;/a&gt; set up with a Rack framework defined (will be sending a pull request with it soon) and also have my blog set to use Ruby 1.9.3 as well.&lt;/p&gt;

&lt;p&gt;Soon I'll be providing some more details on &lt;a href=&quot;http://paas.io&quot;&gt;PaaS.io&lt;/a&gt;, so stay tuned and click over to it and sign up to get access to the beta.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
    <item>
      <title>iPhone vs Android is the new Mac vs PC</title>
      <link>http://invalidlogic.com/2011/10/18/iphone-vs-android-is-the-new-mac-vs-pc/</link>
      <pubDate>2011-10-18 00:00:00 -0700</pubDate>
      <guid>http://invalidlogic.com/archives/2011/10/18/iphone-vs-android-is-the-new-mac-vs-pc/</guid>
      <description>&lt;p&gt;After spending &lt;a href=&quot;/2010/04/06/one-week-with-a-droid-and-a-few-hours-with-an-ipad/&quot;&gt;18 months with Android&lt;/a&gt;, I am now back to an iPhone and
likely here to stay.  While Android isn't necessarily bad, it more boils
down to iPhone simply being better.  After a while, I started looking at
iPhone vs Android as largely a repeat of the Mac vs PC comparisons.&lt;/p&gt;

&lt;h3&gt;Mac vs PC&lt;/h3&gt;

&lt;p&gt;Just look at it.  Apple is doing what they've always done.  They control
the hardware and the software.  They have a solid, unified experience.
You can pick up any iPhone, old or new, and still be at home.&lt;/p&gt;

&lt;p&gt;Android is repeating the history of PCs.  Google makes the OS, as
Microsoft did with Windows.  Then OEMs offer a wide variety of different
hardware, with their own shitty customizations layered on top of the OS.
Even worse, you have the carriers layering on their customizations and
restrictions.&lt;/p&gt;

&lt;p&gt;You can go from one Android phone to another and have it
be completely foreign.  Even baseline apps can have different names and
a completely different look and feel, such between the &quot;Email&quot; vs &quot;Mail&quot; of vanilla
Android and HTC Android.&lt;/p&gt;

&lt;h3&gt;Shelf Life&lt;/h3&gt;

&lt;p&gt;With Android, the phones have a very short shelf life.  I bought a
Thunderbolt from Verizon back in April, just 6 months ago.  About a
month after I bought it, it was no longer the hot model they were
pimping.  In fact, there have been 2-3 phones to come out since then
that became &quot;king of the mountain.&quot;&lt;/p&gt;

&lt;p&gt;With iPhone, they release a new phone about once a year, and that one
stays the current phone.  Older phones are still pretty well supported.
The iPhone 3GS is over 2 years old, still got updated to iOS 5, and
likely will until iOS 6.  My original Motorola Droid that is
nearing 2 years old is pretty much forgotten already.&lt;/p&gt;

&lt;p&gt;Updates with iPhone?  Available right away to everyone.  AT&amp;amp;T or
Verizon, you get the update when Apple makes it generally available.&lt;/p&gt;

&lt;p&gt;Updates with Android?  Have fun.  Google has to release it, your OEM has
to customize it, then the carrier gets to tweak it, and decide when to
finally roll it out.  Google released Gingerbread back in December 2010,
nearly 10 months ago.  Verizon just started rolling out the update last
month, &lt;a href=&quot;http://www.gottabemobile.com/2011/10/17/htc-thunderbolt-gingerbread-update-said-to-be-returning-soon/&quot;&gt;then pulled it&lt;/a&gt;.  Even then, they decide when you can upgrade with a phased roll out.  And since it was pulled, looks like they seem to skip over adequate testing.&lt;/p&gt;

&lt;p&gt;Most Android users who want recent releases end up rooting their phones
and use unofficial ROMs put together by an informal group of people.
Have an issue with your phone?  Limited options.&lt;/p&gt;

&lt;h3&gt;Marketing&lt;/h3&gt;

&lt;p&gt;I definitely agreed with &lt;a href=&quot;http://www.slowcookedbacon.com/&quot;&gt;my friend Joe&lt;/a&gt; in his &lt;a href=&quot;http://www.slowcookedbacon.com/the-droid-bionic-shows-why-android-isnt-domin&quot;&gt;post about the Droid Bionic&lt;/a&gt;.  Android phones are being pitched like PCs.  They give a bunch of technical specs that are meaningless to consumers.  It echos the &lt;a href=&quot;http://www.ted.com/talks/simon_sinek_how_great_leaders_inspire_action.html&quot;&gt;&quot;Golden Circle&quot;&lt;/a&gt; idea by Simon Sinek.  Apple is still doing what they do best.  Verizon sells like PC manufacturers.  Lacking inspiration.&lt;/p&gt;

&lt;h3&gt;False Sense of Market Share&lt;/h3&gt;

&lt;p&gt;You've probably seen the headlines of &lt;a href=&quot;http://www.dailytech.com/Android+Outsells+iPhone+5to2+Has+Nearly+50+Percent+of+the+Market/article22326.htm&quot;&gt;&quot;Android sales outpacing
iPhone&quot;&lt;/a&gt;
or &lt;a href=&quot;http://www.dailytech.com/Android+Market+Share+Reaches+56+Percent+RIMs+Microsofts+Cut+in+Half/article22852.htm&quot;&gt;&quot;Android market share to surpass iPhone&quot;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Overall the numbers are comparing apples to oranges.  They are comparing
the sales figure of a &lt;em&gt;single phone&lt;/em&gt; to a whole &lt;em&gt;group of phones&lt;/em&gt;.
There are many different Android phones, and individually, iPhone is
spanking them in sales figures.  No single Android phone has a chance of
elipsing the iPhone or gaining any meaningful market share, especially
with their overall short shelf life.  I'd be very interested to see
sales figured of individual phones and see how long they really last.
All the manufacturers are still struggling to get a sliver of what the iPhone is capable of.&lt;/p&gt;

&lt;p&gt;The numbers may hold some weight for developers because it represents
the size of your audience.  But at the same time, Android is many phones
vs iPhones entire existence is now just 5 phones.  Less &quot;your app
doesn't work on my Verizon Droid Mumbojumbo&quot; and you don't have a Droid
Mumbojumbo to test on.&lt;/p&gt;

&lt;h3&gt;Falseness of Open&lt;/h3&gt;

&lt;p&gt;Many people tout Android as being open, however the actions of Google
with &lt;a href=&quot;http://www.businessweek.com/technology/content/mar2011/tc20110324_269784_page_2.htm&quot;&gt;Honeycomb's source code&lt;/a&gt; seem to be heading in the direction of more closed.&lt;/p&gt;

&lt;p&gt;While Google said part of their goal was to try and unify the platform
more, as Honeycomb was intended for tablets and not handsets, the
ability to control a platform is difficult while also keeping it &quot;open.&quot;
I think Google is right in closing it, since in order to further the
platform, they will need to have some control in order to maintain a
consistent direction.&lt;/p&gt;

&lt;p&gt;However, the &quot;openness&quot; usually just comes from developers.  What do most of then
define the &quot;openness&quot; as?  Being able to write apps and put them on
their phone without paying $99.  They tout the source being open, but
the truth is that isn't what they really care about.  Very few Android
developers likely dive into the OS code, they just want to install their
own apps for free.&lt;/p&gt;

&lt;p&gt;Personally, if I prefer one platform over the other, a $99 fee to build
apps isn't going to a stopper for me.  But I also
don't mind paying for the tools I use in my craft if they are worth it.&lt;/p&gt;

&lt;h3&gt;Working&lt;/h3&gt;

&lt;p&gt;Most average people care more about how well the phone works.  iPhone
simply works better.  Since software and hardware are more married, the
experience is more consistent.  In my own experience, apps crash less on
iPhone.  The phone lags less.  Scrolling and browsing is more graceful.
My wife is still on her original Droid for another month, and every day
I see her struggle with the phone.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.changewaveresearch.com/articles/2011/smart_phones_20110718.html&quot;&gt;iPhone has better customer satisfaction ratings than Android.&lt;/a&gt;  While the reasons aren't mentioned, I wouldn't be surprised that part of it stems from &quot;it just works&quot;.&lt;/p&gt;

&lt;p&gt;Apple has a strong emphasis on usability.  Google and the OEMs aren't as
much so.  This particularly stuck me with a &lt;a href=&quot;http://dinnerwithandroid.tumblr.com/post/8838035574/dual-wielding&quot;&gt;post I read&lt;/a&gt; about a guy talking to a girl who had an Android phone and an iPod Touch.  In particuar, &quot;nothing happened when I plugged it into my computer.&quot;  To the average user, the simple integration is important.  They don't know why the phone shows up as a &quot;Mass Storage Device&quot; when they plug it in.&lt;/p&gt;

&lt;h3&gt;Future&lt;/h3&gt;

&lt;p&gt;The future for Android will probable improve.  The OS is maturing and
hardware getting better, however the ecosystem of manufacturers and
carriers will likely stay the same.  The reality is that Apple is doing
what Apple has always done and they've gotten really good at it.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
    <item>
      <title>Cooking with Chef slides</title>
      <link>http://invalidlogic.com/2011/07/25/cooking-with-chef-slides/</link>
      <pubDate>2011-07-25 00:00:00 -0700</pubDate>
      <guid>http://invalidlogic.com/archives/2011/07/25/cooking-with-chef-slides/</guid>
      <description>&lt;p&gt;A little late, but I have posted my slides from my talk at the &lt;a href=&quot;http://www.meetup.com/EBRuby/&quot;&gt;East Bay
Ruby Meetup&lt;/a&gt; in &lt;a href=&quot;http://www.meetup.com/EBRuby/events/16505489/&quot;&gt;June&lt;/a&gt;.&lt;/p&gt;

&lt;center&gt;&lt;div style=&quot;width:425px;margin: 10px&quot; id=&quot;__ss_8668127&quot;&gt;&lt;strong style=&quot;display:block;margin:12px 0 4px&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/krobertson2/cooking-with-chef-8668127&quot; title=&quot;Cooking with Chef&quot;&gt;Cooking with Chef&lt;/a&gt;&lt;/strong&gt;&lt;object id=&quot;__sse8668127&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cheftalk-110722221912-phpapp02&amp;stripped_title=cooking-with-chef-8668127&amp;userName=krobertson2&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;&lt;embed name=&quot;__sse8668127&quot; src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cheftalk-110722221912-phpapp02&amp;stripped_title=cooking-with-chef-8668127&amp;userName=krobertson2&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;/center&gt;


&lt;p&gt;Check them out and feel free to ping me if there are any questions.  At
the meetup, was also talking about doing a bit of a blog series on
getting started with Chef and posting some of the scripts and baseline
setup I have used before.  Hope to start forming some simple getting started resources.&lt;/p&gt;
</description>
      <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/</creativeCommons:license>
    </item>
    
  </channel>
</rss>