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

<channel>
	<title>Ramblings &#187; Systems</title>
	<atom:link href="http://ramblings.gibberishcode.net/archives/category/systems/feed" rel="self" type="application/rss+xml" />
	<link>http://ramblings.gibberishcode.net</link>
	<description>about fetching, interpreting, and executing.</description>
	<lastBuildDate>Sat, 01 May 2010 19:19:27 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Apache 2.2 and Active Directory and Group restrictions</title>
		<link>http://ramblings.gibberishcode.net/archives/apache-22-and-active-directory-and-group-restrictions/36</link>
		<comments>http://ramblings.gibberishcode.net/archives/apache-22-and-active-directory-and-group-restrictions/36#comments</comments>
		<pubDate>Wed, 22 Jul 2009 16:44:44 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Configuration]]></category>
		<category><![CDATA[Servers]]></category>
		<category><![CDATA[Setups]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[active directory]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[authnz ldap module]]></category>
		<category><![CDATA[mod_authnz_ldap]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=36</guid>
		<description><![CDATA[I was really struggling with getting Apache and Active Directory talking and restricting access (authorizing) only a sub-set of users that belonged to a particular group.  Here, I show you how I solved the problem.

The Stage
I am setting up a Ubuntu server with Apache 2.2 and authenticating users against a Windows 2003 Server&#8217;s Active [...]]]></description>
			<content:encoded><![CDATA[<p>I was really struggling with getting Apache and Active Directory talking and restricting access (authorizing) only a sub-set of users that belonged to a particular group.  Here, I show you how I solved the problem.
</p>
<h2>The Stage</h2>
<p>I am setting up a Ubuntu server with Apache 2.2 and authenticating users against a Windows 2003 Server&#8217;s Active Directory.  This is standard fare when all you need is a require valid-user directive.  But when it came to getting require ldap-group directive going, I really stumbled.  And on multiple fronts, too.  I am not a Windows guru by any measure, nor am I an LDAP guru, so there was a huge cultural and vocabulary barrier for me to cross on both the LDAP vernacular and the somewhat different parlance surrounding Microsoft&#8217;s documentation on Active Directory.  Its like a Southern Redneck talking to a Scottish Highlander about home-brewing beer.
</p>
<p>So here&#8217;s what we&#8217;re going to do:</p>
<ul>
<li>Apache 2.2</li>
<li>Microsoft Active Directory (Windows 2003 Server)</li>
<li>authnz_ldap module</li>
</ul>
<p>For this effort, I am authenticating users that reside in the MyBusiness -> Users folders and I&#8217;m restricting access to the Auditors Security Group, also residing under MyBusiness.  The domain I use is &#8220;sample.local&#8221; herein.  See the screen shot of the Active Directory structure and details of the Auditors group below:
</p>
<p><img src="http://www.cybrains.net/images/ad_screenshot.png" alt='Active Directory Screenshot' /></p>
<p>There are <a href="http://httpd.apache.org/docs/trunk/mod/mod_authnz_ldap.html">plenty of resources out there</a> about getting the authnz_ldap module working with Apache, so I won&#8217;t be covering this part of the setup.  Instead, I will focus on the gestalt of the actual configuration.
</p>
<h2>Will the Real AuthLdapUrl Please Stand Up?</h2>
<p>There seems to be no real standard way to set the AuthLdapURL configuration string.  I think I visited ten or fifteen web sites on the topic and each one was a little bit different!  And none really explained fully the chosen syntax and LDAP selectors being used.  Fortunately, I came across a <a href="http://www.computerperformance.co.uk/Logon/Logon_CSVDE.htm">site dedicated to explaining CSVDE</a>, which turned out to be a bit of a rosetta stone for me.
</p>
<p>CSVDE is a tool I had never heard of, but yet is apparently installed on every Windows 2003 Server.  After about five minutes of reading and 20 minutes of perusing the CSV export I generated, I knew exactly how to construct the AuthLdapURL configuration string.  Well, with one caveat, that is.  I still am not sure what &#8220;(objectClass=*)&#8221; does for me, but several examples had it and I kept it.
</p>
<h2>Know your Users</h2>
<p>All of my users are maintained under group policies and they reside under the domain&#8217;s root node in &#8220;MyBusiness&#8221; and &#8220;Users&#8221; under that.  Standard Windows accounts, especially system administrator accounts reside in a &#8220;Users&#8221; folder directly off the domain&#8217;s root node.  This was one of the first points of contention that I had to understand when looking at the vast majority of other people&#8217;s solution.  Simply put, know which &#8220;Users&#8221; you wish to work with in Apache.
</p>
<p>Knowing I wanted to authenticate users under the MyBusiness node, my AuthLdapUrl becomes:
</p>
<pre class="twilight">
AuthLDAPURL ldap://ad.sample.local:389/OU=MyBusiness,DC=sample,DC=local?sAMAccountName?sub?(objectClass=*)
</pre>
<h2>Bind a User so Apache can Query</h2>
<p>You do have to bind to Active Directory so that Apache can actually query.  To do this, I created a User under the standard &#8220;Users&#8221; folder (where administrator, and other such accounts traditionally reside).  I don&#8217;t know if I applied correct rights or not, but the account is no more than a &#8220;Domain User&#8221; member.  I called the user &#8220;AD_VIEWER&#8221; with description &#8220;Account to bind Apache to Active Directory for authentication.&#8221;  This leads to the following Apache directives:
</p>
<pre class="twilight">
AuthLDAPBindDN "AD_VIEWER@sample.local"
AuthLDAPBindPassword bottom_secret_password
</pre>
<p>I tested the above getting the usual &#8220;require valid-user&#8221; directive working with Apache.  Once I was sure I could do this much, it was time to turn my attention to restricting access to users that are members of a specific group.
</p>
<h2>Where&#8217;s my Group?</h2>
<p>I struggled for quite a while with the groups before I finally got wise and set the debug level to get more details into the apache log files.  The debug logging level can be set with:
</p>
<pre class="twilight">
LogLevel debug
</pre>
<p>And this leads to quite detailed information about what&#8217;s going on with Apache and Authentication.  For example, before I got my ldap-group configuration correct, I was seeing this:
</p>
<pre class="twilight">
[debug] mod_authnz_ldap.c(721): [2934] auth_ldap authorise: require group: testing for uniquemember: CN=Code Connoisseur,OU=MyBusiness,OU=Users,DC=sample,DC=local (CN=Auditors,OU=MyBusiness,DC=sample,DC=local)
[debug] mod_authnz_ldap.c(737): [2934] auth_ldap authorise: require group "CN=Auditors,OU=MyBusiness,DC=sample,DC=local": authorisation failed [Comparison complete][No such object]
[debug] mod_authnz_ldap.c(852): [2934] auth_ldap authorise: authorisation denied
</pre>
<p>Note the &#8220;No such object&#8221; as this was telling me the group itself was not found.  I tried many permutations without success until I found the CSVDE program and was able to dump the Active Directory to Excel for further inspection.  I realized with the CSVDE output that I was doing both the<br />
AuthLDAPURL (the above AuthLDAPURL is correct as I have spared you from my mistakes).  The correct ldap-group config string for accessing a Security Group defined under MyBusiness is:</p>
<pre class="twilight">
require ldap-group CN=Auditors,OU=Security Groups,OU=MyBusiness,DC=sample,DC=local
</pre>
<p>In short, you have to exactly declare the selector for your Active Directory Group or Apache will fail to find it.  After getting the group setting right, I now see &#8220;attribute member&#8221; and &#8220;Comparison true&#8221; in the logs, which indicates that the group was found and that my user is a member of that group.
</p>
<pre class="twilight">
[debug] mod_authnz_ldap.c(377): [3134] auth_ldap authenticate: using URL ldap://10.0.1.5:389/OU=MyBusiness,DC=sample,DC=local?sAMAccountName?sub?(objectClass=*)
[debug] mod_authnz_ldap.c(474): [3134] auth_ldap authenticate: accepting mwlang
[debug] mod_authnz_ldap.c(715): [3134] auth_ldap authorise: require group: testing for group membership in "CN=Auditors,OU=Security Groups,OU=MyBusiness,DC=sample,DC=local"
[debug] mod_authnz_ldap.c(721): [3134] auth_ldap authorise: require group: testing for member: CN=Michael Lang,OU=Employees,OU=Users,OU=Users,OU=MyBusiness,DC=sample,DC=local (CN=Auditors,OU=Security Groups,OU=MyBusiness,DC=sample,DC=local)
[debug] mod_authnz_ldap.c(730): [3134] auth_ldap authorise: require group: authorisation successful (attribute member) [Comparison true (adding to cache)][Compare True]
</pre>
<h2>The complete Apache Config</h2>
<p>Bringing all of the items discussed above together, we arrive at this Apache configuration.  I am using Virtual Hosts to uniquely identify the service.  Also of note, I am using Ramaze to provide the functionality of the actual site, so please do take this into account if you&#8217;re copying and pasting.  This config is a complete virtual host entry:
</p>
<pre class="twilight"><span class="Keyword">&lt;</span>VirtualHost *:<span class="Keyword">80&gt;</span>
    ServerName audit.sample.local
    RackBaseURI /
    RackAutoDetect on
    DocumentRoot /var/www/balancer/public

    LogLevel debug
    <span class="Keyword">&lt;</span>Location <span class="String"><span class="String">&quot;</span>/data_entry<span class="String">&quot;</span></span><span class="Keyword">&gt;</span>
        AuthBasicProvider ldap
        AuthType Basic
        AuthName <span class="String"><span class="String">&quot;</span>Sample Realm<span class="String">&quot;</span></span>
        AuthLDAPURL ldap://10.0.1.5:389/OU=MyBusiness,DC=sample,DC=local?sAMAccountName?sub?(objectClass=*)
        AuthzLDAPAuthoritative on

        AuthLDAPBindDN <span class="String"><span class="String">&quot;</span>AD_VIEWER@sample.local<span class="String">&quot;</span></span>
        AuthLDAPBindPassword bottom_secret_password

        AuthLDAPGroupAttributeIsDN on
        require ldap-group CN=Auditors,OU=Security Groups,OU=MyBusiness,DC=sample,DC=local
    <span class="Keyword">&lt;</span>/Location<span class="Keyword">&gt;</span>
<span class="Keyword">&lt;</span>/VirtualHost<span class="Keyword">&gt;</span>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/apache-22-and-active-directory-and-group-restrictions/36/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>macports is not darwinports</title>
		<link>http://ramblings.gibberishcode.net/archives/macports-is-not-darwinports/35</link>
		<comments>http://ramblings.gibberishcode.net/archives/macports-is-not-darwinports/35#comments</comments>
		<pubDate>Tue, 23 Jun 2009 00:36:06 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Macs]]></category>
		<category><![CDATA[Setups]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[darwinports]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[macports]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=35</guid>
		<description><![CDATA[For those of you who don&#8217;t keep a close eye on the macports system that provides you with convenient builds of popular open source software, let me put you on guard:  macports supplanted darwinports a few years back to avoid continued confusion over the name.
I was having a good bit of trouble getting ports [...]]]></description>
			<content:encoded><![CDATA[<p>For those of you who don&#8217;t keep a close eye on the macports system that provides you with convenient builds of popular open source software, let me put you on guard:  macports supplanted darwinports a few years back to <a href="http://trac.macports.org/wiki/DarwinPorts">avoid continued confusion</a> over the name.</p>
<p>I was having a good bit of trouble getting ports to install ImageMagick and have had trouble many other times getting ports to install things.  As such, I often fell back on fink or compiling and installing from source rather than figuring out the root causes of my macports problems.  </p>
<p>Macports was surprisingly easy to fix up and get fully operational again, and this was on a fairly old machine that I am pretty certain I started with &#8220;Darwin Ports&#8221; roughly 3.5 years ago.  </p>
<h2>First Thing&#8217;s First</h2>
<p>First, know that the official macports website is: <a href="http://macports.org">trac.macports.org</a>.  Be wary of anything &#8220;darwinports&#8221; as name is officially retired in favor of &#8220;macports.&#8221;
</p>
<h2>Trouble a-brewing</h2>
<p>It all started innocently enough.  I wanted to install ImageMagick on my mac.  I&#8217;ve been through installing ImageMagick on Linux and knew it was not going to be a cakewalk to install from source.  ImageMagick simply has too many dependencies to relish the thought of an install from source route.  So I googled and found <a href="">instructions for ports</a> and began:
</p>
<pre class="twilight">sudo port install tiff -macosx imagemagick +q8 +gs +wmf
Warning: Group file could not be located.
---<span class="Keyword">&gt;</span>  Activating tiff 3.8.2_3
Error: Target org.macports.activate returned: Image error: Another version of this port (tiff @3.8.2_2+darwin_9+macosx) is already active.
</pre>
<p>Oh, ok, lets remove the old one&#8230;</p>
<pre class="twilight">
sudo port uninstall tiff -macosx imagemagick +q8 +gs +wmf
---<span class="Keyword">&gt;</span>  The following versions of tiff are currently installed:
---<span class="Keyword">&gt;</span>  	tiff @3.8.2_2+darwin_9+macosx (active)
---<span class="Keyword">&gt;</span>  	tiff @3.8.2_3
Error: port uninstall failed: Registry error: Please specify the full version as recorded <span class="Keyword">in</span> the port registry.
[mwlang@macdoze shared] sudo port uninstall tiff @3.8.2_2+darwin_9+macosx
---<span class="Keyword">&gt;</span>  Unable to uninstall tiff 3.8.2_2+darwin_9+macosx, the following ports depend on it:
---<span class="Keyword">&gt;</span>  	gtk2
---<span class="Keyword">&gt;</span>  	lcms
---<span class="Keyword">&gt;</span>  	sane-backends
---<span class="Keyword">&gt;</span>  	xsane
Error: port uninstall failed: Please uninstall the ports that depend on tiff first.
[mwlang@macdoze shared] sudo port uninstall tiff @3.8.2_2+darwin_9+macosx gtk2 lcms sane-backends xsane
---<span class="Keyword">&gt;</span>  Unable to uninstall tiff 3.8.2_2+darwin_9+macosx, the following ports depend on it:
---<span class="Keyword">&gt;</span>  	gtk2
---<span class="Keyword">&gt;</span>  	lcms
---<span class="Keyword">&gt;</span>  	sane-backends
---<span class="Keyword">&gt;</span>  	xsane
Error: port uninstall failed: Please uninstall the ports that depend on tiff first.
[mwlang@macdoze shared] sudo port uninstall gtk2 lcms sane-backends xsane
---<span class="Keyword">&gt;</span>  Unable to uninstall gtk2 2.12.9_0+x11, the following ports depend on it:
---<span class="Keyword">&gt;</span>  	gconf
---<span class="Keyword">&gt;</span>  	gnome-keyring
---<span class="Keyword">&gt;</span>  	libglade2
---<span class="Keyword">&gt;</span>  	gail
---<span class="Keyword">&gt;</span>  	libgnomecanvas
---<span class="Keyword">&gt;</span>  	libbonoboui
---<span class="Keyword">&gt;</span>  	poppler
---<span class="Keyword">&gt;</span>  	py25-gtk
---<span class="Keyword">&gt;</span>  	gtk-nodoka-engine
---<span class="Keyword">&gt;</span>  	xsane
Error: port uninstall failed: Please uninstall the ports that depend on gtk2 first.
</pre>
<p>Not a very auspicious start, is it?  Time to step back and think about this one and dig into the macports facility to learn how to properly manage things.  New strategy: Get an education.</p>
<h2>Discovering Deactivate/Activate</h2>
<p>So, looking at the above problem, I realized that there was almost certainly an easier route out of this dependency nightmare and I needed to learn how to upgrade those old, stale packages.  Going through the docs reveals activate and deactivate commands.  Sounds perfect, lets try:</p>
<pre class="twilight">sudo port activate tiff @3.8.2_3
---<span class="Keyword">&gt;</span>  Activating tiff @3.8.2_3
Error: port activate failed: Image error: Another version of this port (tiff @3.8.2_2+darwin_9+macosx) is already active.
[mwlang@macdoze shared] sudo port deactivate tiff @3.8.2_2+darwin_9+macosx
---<span class="Keyword">&gt;</span>  Deactivating tiff @3.8.2_2+darwin_9+macosx
[mwlang@macdoze shared] sudo port activate tiff @3.8.2_3
---<span class="Keyword">&gt;</span>  Activating tiff @3.8.2_3
</pre>
<p>So there&#8217;s the kicker.  First, deactivate the old version, <i>then</i> activate the new version.</p>
<h2>So Macports itself is out of date, you say?</h2>
<pre class="twilight">sudo port install tiff -macosx imagemagick +q8 +gs +wmf
Error: Unable to execute port: invalid command name <span class="String"><span class="String">&quot;</span>use_autoreconf<span class="String">&quot;</span></span>
</pre>
<p>I had no clue what this was.  Googling around was turning up precious little.  So I hopped over into the IRC #macports channel.  Right off the bat, Toby tells me to selfupdate.  I had made the mistake of thinking that &#8220;sudo port sync&#8221; was keeping macports packages all up to date in one fell swoop.  But the two are two distinct activities.  So remember to keep ports itself updated with this:</p>
<pre class="twilight">sudo port selfupdate
</pre>
<p>With that, port was upgraded from a very old version to a bright and shiny new version.  Time to try to install ImageMagick again.  And I&#8217;m happy to report that I got much further along this time.  But still hit a roadblock&#8230;</p>
<h2>Mysterious failure demystified</h2>
<p>A little down the chain of installing various xorg packages, I hit upon this one with the xorg-libx11 package:</p>
<pre class="twilight">checking <span class="Keyword">for</span> XPROTO... configure: error: Package requirements (xproto <span class="Keyword">&gt;</span>= 7.0.13) were not met.
Consider adjusting the PKG_CONFIG_PATH environment variable <span class="Keyword">if</span> you
installed software <span class="Keyword">in</span> a non-standard prefix.

Alternatively you may set the XPROTO_CFLAGS and XPROTO_LIBS environment variables
to avoid the need to call pkg-config.  See the pkg-config man page <span class="Keyword">for</span>
more details.

Error: The following dependencies failed to build: ghostscript xorg-libXext xorg-libX11 xorg-libXt xorg-libsm xorg-libice
Error: Status 1 encountered during processing.
[mwlang@macdoze shared] sudo port install ImageMagick
Error: Requested variants <span class="Keyword">do</span> not match original selection.
Please perform <span class="String"><span class="String">'</span>port clean ImageMagick<span class="String">'</span></span> or specify the force option.
Error: Status 1 encountered during processing.
</pre>
<p>Strange, what&#8217;s that <b>xproto >= 7.0.13</b>?  How odd that a dependency would fail!  I tried a <b>sudo port install xproto</b>, but that was a no-go (so don&#8217;t bother trying, it&#8217;ll fail for you, too).  but then I noticed the dependency list (which oddly is missing <b>xorg-xproto</b>) and most of the packages are prefixed with &#8220;xorg-&#8221;, and tried <b>sudo port install xorg-xproto</b> and thus, was on my way again.</p>
<p>I lie! <i>I lie!</i>  I had no clue.  I googled &#8220;xproto port install&#8221; and learned the truth for the real package name that way.  However, as it happens, I found the answer on darwinports dot com in a dependency list for xorg-libx11.  I casually mentioned this site in the IRC channel and the #macports tenants were very quick to point out was an imposter site, so be wary of anything you read and learn there.  Information is liable to be stale while the site owner attempts to lighten your wallet a bit for no good cause.  Little did I know!</p>
<h2>Final tidbit</h2>
<p>Once I got the ports system updated and the xproto package installed, it was a fair breeze to finish with the ImageMagick installation.  One last command I learned from the good folks in #macports is to run the following on a frequent basis to keep your macports installation in fair good shape:</p>
<pre class="twilight">sudo port selfupdate <span class="Keyword">&amp;&amp;</span> sudo port upgrade outdated
</pre>
<h2>Conclusion</h2>
<p>For years,  I struggled with ports, and for no good reason.  Once I took the time to learn the package management&#8217;s commands (along with the help of those in #macports, for which I&#8217;m very grateful to them for saving me a few hours of head-scratching), I am finding I&#8217;m able to install packages painlessly on the mac and have even tried a couple of others I had problems with in the past and they&#8217;re all installing without a hitch.  The lesson for me:  take the time to learn your tools.  It may be slow-going at first, but the rewards always seem to pay back big dividends down the road.</p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/macports-is-not-darwinports/35/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails vs. Ramaze Performance Comparison</title>
		<link>http://ramblings.gibberishcode.net/archives/rails-vs-ramaze-performance-comparison/31</link>
		<comments>http://ramblings.gibberishcode.net/archives/rails-vs-ramaze-performance-comparison/31#comments</comments>
		<pubDate>Thu, 19 Feb 2009 21:07:24 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Servers]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[mri ruby]]></category>
		<category><![CDATA[passenger]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ramaze]]></category>
		<category><![CDATA[ree ruby]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=31</guid>
		<description><![CDATA[One of my biggest concerns of late is that my &#8220;more than just a little trivial&#8221; Rails projects seem to find their way straight into the heavyweight category in no time at all.  While I am quite hopeful that Merb being the 3.0 version of Rails will resolve many of the issues I face [...]]]></description>
			<content:encoded><![CDATA[<p>One of my biggest concerns of late is that my &#8220;more than just a little trivial&#8221; Rails projects seem to find their way straight into the heavyweight category in no time at all.  While I am quite hopeful that Merb being the 3.0 version of Rails will resolve many of the issues I face today, I have no idea when I can truly count on Rails 3.0&#8217;s arrival at the party.  Thus, I have begun looking at other frameworks that are available today.</p>
<h2>Introducing Ramaze</h2>
<p>One I found is <a href="http://www.ramaze.net">Ramaze</a>.  I have to say that Ramaze is a very minimalist approach to a framework that is actually rather enlightening.  For one coming from a Rails&#8217; world, it can feel a bit sparse at first.  But lately, I&#8217;m attributing my lack of comfort to being put on my toes to do some actual real Ruby coding.  Its both a little scary and liberating at the same time.  I have found that I am enjoying Ruby a lot more as a result of my exposure to Ramaze and my thought process is actually radically changing, almost like a Visual Basic programmer going to Borland Delphi might feel.</p>
<p>So I decided to take a hard look at performance metrics between Rails and Ramaze&#8217;s.  At the same time, I wanted to see how MRI 1.8.7 stacked up against Ruby Enterprise Ed. 1.8.6, so I&#8217;m satisfying a dual curiosity herein.  Being quite happy with <a href="http://www.mod_rails.com">Phusion Passenger</a>, I decided to set things up with Apache 2.2.9 + Passenger + Rails/Ramaze.  Since I&#8217;m quite comfortable with ERB and ActiveRecord, I tweaked Ramaze to be a bit more like the familiar Rails world I am familiar with.</p>
<h2>Un-DRYing the Results</h2>
<p>There&#8217;s no point in generating a lot of data and reporting on it if others cannot repeat yourself (CRY!) in replicating the results, so with that in mind, I attempt to refrain from further bad turn of words by busying myself in pushing everything I utilized to <a href="http://github.com/mwlang/benchmarks/tree/master">github.com</a> and documenting the basic <a href="http://ramblings.gibberishcode.net/archives/bootstrap-ubuntu-server-810-intrepid-64-bit/29">bootstrapping of Ubuntu Intrepid</a>.  For these tests in particular, I used two scripts, <a href="http://github.com/mwlang/bootstrap-scripts/blob/af44b371a24a79820c98fcf9cfe014b7a523a24a/ubuntu/intrepid/bootstrap-passenger-std.sh">bootstrap-passenger-std.sh</a> and <a href="http://github.com/mwlang/bootstrap-scripts/blob/af44b371a24a79820c98fcf9cfe014b7a523a24a/ubuntu/intrepid/bootstrap-passenger-ent.sh">bootstrap-passenter-ent.sh</a> to set up four distinct configurations under the Ruby1.8 interpreter.  Ruby 1.9.1. was a bit difficult to set up and there is a <a href="http://github.com/mwlang/bootstrap-scripts/blob/af44b371a24a79820c98fcf9cfe014b7a523a24a/ubuntu/intrepid/bootstrap-passenger-191.sh">bootstrap-passenger-191.sh</a> script that I assembled as I installed things, but I haven&#8217;t run it to ensure it works end-to-end.   </p>
<table style="width: 70%;" border="1">
<thead>
<tr>
<td style="text-align: center;" colspan="5">Apache 2.2.2</td>
</tr>
<tr>
<td style="text-align: center;" colspan="4">Passenger 2.0.6<br/>(gem)</td>
<td style="text-align: center;">Passenger 2.1.0<br/>(source)</td>
</tr>
<tr>
<td style="text-align: center;" colspan="2">Rails 2.2.2</td>
<td style="text-align: center;" colspan="2">Ramaze 2009.01</td>
<td style="text-align: center;" colspan="1">Ramaze 2009.01</td>
</tr>
<tr>
<td style="text-align: center;">MRI Ruby 1.8.7<br/>package</td>
<td style="text-align: center;">Ent. Ruby 1.8.6<br/>source</td>
<td style="text-align: center;">MRI Ruby 1.8.7<br/>package</td>
<td style="text-align: center;">Ent. Ruby 1.8.6<br/>source</td>
<td style="text-align: center;">MRI Ruby 1.9.1<br/>source</td>
</tr>
</thead>
</table>
<p>I utilized this simple call to Apache Bench to run through the four test scenarios:<br />
All data collected was based on 10,000 requests at 100 concurrent users after an initial &#8220;warmup&#8221; of the passenger threads with start of 100 requests at 10 concurrent users.  The following command shows the basic set of parameters issued to Apache Bench:</p>
<pre class="twilight">
ab -n 10000 -c 100 http://demo.u64rails01.local/posts
</pre>
<p><br/></p>
<h2>What was tested?</h2>
<p>In order to compare, as close as possible, apples to apples, I opted to use Active Record and ERubis in Ramaze to set up the same MVC classes in both the Rails and Ramaze project.  ActiveRecord is probably the heaviest weighted ORM that can be utilized with Ramaze.  I tried briefly to get Erubis working with Rails so that the two frameworks&#8217; projects would be more closely aligned than the out-of-box ERB rendering Rails ships with would have afforded.  I did attempt Erubis with Rails, however, I was either doing something very wrong or Erubis under Rails takes a sizable performance hit and I stuck with out-of-box ERB for these tests given its better performance.  As such, Rails uses out of box ERB rendering in these tests.</p>
<p>The <a href="http://github.com/mwlang/benchmarks/tree/0baffeb9cf3eb514912c6de34b64dc2ce25c2e31/2009/02">application itself</a> is ridiculously simple, offering only one model and performing only a read against the database, but hopefully, an effective start towards building this benchmark framework towards more substantive benchmark tests to come.  For now, lets take a look at how Rails and Ramaze stack up to each other and what affect the underlying interpreter can have on performance.  Standard packaged Main Ruby Interpreter (MRI) 1.8.7 consisted of simple package install provided by the Ubuntu Intrepid repositories whle <a href="http://www.rubyenterpriseedition.com/">Ruby Enterprise Edition</a> (REE) 1.8.6, which hails from the same folks bringing you Phusion Passenger, is compiled from source.</p>
<p>As a bonus, I also compiled and clocked metrics for Ramaze on 1.9.1.  This was a tricky environment to get set up and working.  And my initial results made me think I did something horribly wrong with compiling and configuring Ruby 1.9.1.  However, I fully replicated Antonio Cangiano&#8217;s benchmarks in my test environment (see <a href="http://antoniocangiano.com/2008/12/09/the-great-ruby-shootout-december-2008/">The Great Ruby Shootout (December 2008)</a>) and MRI 1.9.1. did indeed crush the other Ruby interpreters in Fibonacci number crunching (amongst others).  The theory tossed around in the Ramaze IRC channel was that 1.9.1. change in implementation of the String class (and it being unicode native now) slows things down a good bit with string processing.</p>
<h2>The Results</h2>
<p>The following table tabulates the results gathered from Apache Bench as well as passenger-memory-stat.  I ran a short run to warm things up (100 requests, 10 concurrently).  And then ran the big bench at 10,000 requests, 100 concurrently, and then ran again and recorded the results.  At around 5,000 requests, I ran passenger-memory-stat to collect the data during mid-processing and then again at the end.  These tests were run on a Ubuntu 64-bit Intrepid 8.10 virtual server that was allocated 1 CPU core and 512MB of RAM.  Swap space was never triggered (0k utilization), and CPU utilization was roughly 85% within the Virtual Machine during the test runs.  The host machine, which is four core CPU, showed one core busy at near 100% with the other three cores pretty much idle.</p>
<table border="0" cellspacing="0" frame="void" rules="none">
<tbody>
<tr>
<td width="138" height="17" align="left"><strong></strong></td>
<td width="86" align="right"><strong>mri_rails</strong></td>
<td width="86" align="right"><strong>ree_rails</strong></td>
<td width="86" align="right"><strong>mri_ramaze</strong></td>
<td width="86" align="right"><strong>ree_ramaze</strong></td>
<td width="86" align="right"><strong>191_ramaze</strong></td>
<td width="86" align="left"><strong>units</strong></td>
</tr>
<tr>
<td height="16" align="right"><strong>Time taken for tests</strong></td>
<td align="right">489.24</td>
<td align="right">379.76</td>
<td align="right">397.43</td>
<td align="right">287.5</td>
<td align="right">351.95</td>
<td align="left"><em>seconds</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Complete requests</strong></td>
<td align="right">10000</td>
<td align="right">10000</td>
<td align="right">10000</td>
<td align="right">10000</td>
<td align="right">10000</td>
<td align="left"><em></em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Failed requests</strong></td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="left"><em></em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Write errors</strong></td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="left"><em></em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Total transferred</strong></td>
<td align="right">36670146</td>
<td align="right">36668229</td>
<td align="right">18130000</td>
<td align="right">18130000</td>
<td align="right">18460000</td>
<td align="left"><em>bytes</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>HTML transferred</strong></td>
<td align="right">30500000</td>
<td align="right">30500000</td>
<td align="right">14480000</td>
<td align="right">14480000</td>
<td align="right">14680000</td>
<td align="left"><em>bytes</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Requests per second</strong></td>
<td align="right">20.44</td>
<td align="right">26.33</td>
<td align="right">25.19</td>
<td align="right">34.78</td>
<td align="right">28.41</td>
<td align="left"><em>[#/sec] (mean)</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Time per request</strong></td>
<td align="right">4892.42</td>
<td align="right">3797.56</td>
<td align="right">3970.43</td>
<td align="right">2875.03</td>
<td align="right">3519.49</td>
<td align="left"><em>[ms] (mean)</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Time per request</strong></td>
<td align="right">48.92</td>
<td align="right">37.98</td>
<td align="right">39.7</td>
<td align="right">28.75</td>
<td align="right">35.2</td>
<td align="left"><em>[ms] (mean, across all concurrent requests)</em></td>
</tr>
<tr>
<td height="17" align="right"><strong>Transfer rate</strong></td>
<td align="right">73.19</td>
<td align="right">94.29</td>
<td align="right">44.59</td>
<td align="right">61.58</td>
<td align="right">51.22</td>
<td align="left"><em>[Kbytes/sec] received</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Total private dirty RSS</strong></td>
<td align="right">323.73</td>
<td align="right">180.89</td>
<td align="right">221.11</td>
<td align="right">221.51</td>
<td align="right">210.73</td>
<td align="left"><em>MB</em></td>
</tr>
</tbody>
</table>
<h2>Throughput</h2>
<p>Everybody likes to <a href="http://www.therailsway.com/2009/1/6/requests-per-second">talk about throughput</a>, so lets start there.  As you can see, MRI and Rails was the worst performer while REE and Ramaze clocked in with the highest throughput in terms of requests per second.  Be forewarned that throughput doesn&#8217;t necessarily equate to user response times.  This metric simply tells you the load at which your system is capable of delivering content at.</p>
<p><img src='http://github.com/mwlang/benchmarks/raw/0baffeb9cf3eb514912c6de34b64dc2ce25c2e31/2009/02/throughput.png' alt='throughput' class='alignnone' /></p>
<h2>Time per Request</h2>
<p>Time per request helps you see about how long an average user request takes for a given load.  As you can see here, with times in the milliseconds, we&#8217;re talking about numbers that will easily be swallowed in the noise of network latency.  Even so, its not hard to be impressed by what the REE folks managed to pull out of their hat with regards to performance on the main ruby interpreter.</p>
<p><img src='http://github.com/mwlang/benchmarks/raw/0baffeb9cf3eb514912c6de34b64dc2ce25c2e31/2009/02/time_per_request.png' alt='Time per Request' class='alignnone' /></p>
<h2>Memory Consumption</h2>
<p>This final graph shows the sizeable dent REE makes in memory consumption for running a Rails application.  Ramaze is already pretty efficient and lean and REE made practically no dent in memory consumption here.  However, REE&#8217;s use of the faster memory allocation routines does have a good effect on boosting Ramaze&#8217;s performance (as seen in above graphs), so there&#8217;s still lots to be gained by running Ramaze with REE.</p>
<p><img src='http://github.com/mwlang/benchmarks/raw/0baffeb9cf3eb514912c6de34b64dc2ce25c2e31/2009/02/memory_usage.png' alt='Memory Usage' class='alignnone' /></p>
<h2>Conclusion</h2>
<p>For me, I have two very, very viable solutions before me.  Rails on Enterprise Ruby or Ramaze on Ruby 1.8.7.  The final choice comes down to how much I can bet on my own Ruby prowess.   Ramaze is a very lean framework that gets you going, but doesn&#8217;t get you a nine inch pillowed mattress topping for your bed like Rails does.  Because Ramaze is so lean, I realize I will have to really take my Ruby skills to the next level and truly understand the ruby code that other developers produce.  Unlike Rails, where there&#8217;s gobs and gobs of plugins and blogs on the topic that make pretty much any need simple to satisfy and get working, I have to know my Ruby to get a solution implemented on Ramaze.  Not a bad thing, but certainly a more challenging and potentially rewarding path to take.</p>
<p>Aside from my personal concerns about making the jump, looking at these results, it is good to see that I have options and how easy it is to get a good deployment up and working compared to 3 or 4 years ago when I was banging my head against the wall for days on end to keep lighttpd + fcgi processes up and running around the clock.  In these tests, it was very, very satisfying that not one single crash or dropped request was recorded in all the benchmarking I performed.  Mongrel came along and made a big impact, but you still needed something like monit to watch Mongrel and restart it on ocvasion.  Now Passenger has come along and made yet another big impact in the ease of deploying Rails, Ramaze, or any of the other ruby-based frameworks.  We&#8217;ve come a long ways, indeed.  I, for one, certainly look forward to what the Ruby sphere will bring us over the next couple of years.</p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/rails-vs-ramaze-performance-comparison/31/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Ruby, Mysql, CentOS 5, and 64-bit</title>
		<link>http://ramblings.gibberishcode.net/archives/ruby-mysql-centos-5-and-64-bit/23</link>
		<comments>http://ramblings.gibberishcode.net/archives/ruby-mysql-centos-5-and-64-bit/23#comments</comments>
		<pubDate>Mon, 19 Jan 2009 20:36:35 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[64-bit]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[Ruby Language]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=23</guid>
		<description><![CDATA[I have lately switched away from Ubuntu as my desktop and started using CentOS 5.2 because I wanted better support for a lot of RAM and virtualization (where I can quickly commission Linux servers to build out my testbed of target environments).  With the change, I also make the leap into pure 64-bit libraries with [...]]]></description>
			<content:encoded><![CDATA[<p>I have lately switched away from Ubuntu as my desktop and started using CentOS 5.2 because I wanted better support for a lot of RAM and virtualization (where I can quickly commission Linux servers to build out my testbed of target environments).  With the change, I also make the leap into pure 64-bit libraries with little to no 32-bit libraries installed.  There&#8217;s been a few sticky points to push through and one of them is getting Mysql and the appropriate mysql gems installed.  This quick post shows the way.</p>
<p><H2>My System</H2><br />
I am running CentOS 5.2 64-bit.  Or more succinctly:</p>
<pre  name="code" class="c:nocontrols">
2.6.18-92.1.22.el5 #1 SMP Tue Dec 16 11:57:43 EST 2008 x86_64 x86_64 x86_64 GNU/Linux
</pre>
<h2>The Problem</h2>
<p>If you simply execute:</p>
<pre  name="code" class="c:nocontrols">
sudo gem install mysql
</pre>
<p>You&#8217;ll get the following errors on a 64-bit system:</p>
<pre  name="code" class="c:nocontrols">
$ sudo gem install mysql
Building native extensions.  This could take a while...
ERROR:  Error installing mysql:
        ERROR: Failed to build gem native extension.

/usr/local/bin/ruby extconf.rb install mysql
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lm... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lz... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lsocket... no
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lnsl... yes
checking for mysql_query() in -lmysqlclient... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/usr/local/bin/ruby
        --with-mysql-config
        --without-mysql-config
        --with-mysql-dir
        --without-mysql-dir
        --with-mysql-include
        --without-mysql-include=${mysql-dir}/include
        --with-mysql-lib
        --without-mysql-lib=${mysql-dir}/lib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-mlib
        --without-mlib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-zlib
        --without-zlib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-socketlib
        --without-socketlib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-nsllib
        --without-nsllib
        --with-mysqlclientlib
        --without-mysqlclientlib

Gem files will remain installed in /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7 for inspection.
Results logged to /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/gem_make.out
</pre>
<p>After digging into the gem options and logs a bit and looking at where mysql actually got installed, I discovered that it was hitting all the locations the 32-bit version would normally install to, but not the 64-bit version, which ends up in /usr/lib64/mysql. </p>
<p><H2>Installing the Ruby gems</h2>
<p>To properly install the Ruby gems for mysql, you&#8217;ll have to explicitly tell the gem where the mysql config is and it will then handle all the rest.  </p>
<pre  name="code" class="c:nocontrols">
gem install mysql -- --with-mysql-config=/usr/lib64/mysql/mysql_config
</pre>
<p>With that, you should see the following:</p>
<pre  name="code" class="c:nocontrols">
Building native extensions.  This could take a while...
Successfully installed mysql-2.7
1 gem installed
</pre>
<p>Check it out with:</p>
<pre  name="code" class="c:nocontrols">
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'mysql'
=> true
irb(main):003:0> quit
</pre>
<p>Life is good.  </p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/ruby-mysql-centos-5-and-64-bit/23/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Overview of Xen Virtualization</title>
		<link>http://ramblings.gibberishcode.net/archives/overview-of-xen-virtualization/21</link>
		<comments>http://ramblings.gibberishcode.net/archives/overview-of-xen-virtualization/21#comments</comments>
		<pubDate>Mon, 24 Nov 2008 15:55:49 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Servers]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[high availability]]></category>
		<category><![CDATA[hyper-v]]></category>
		<category><![CDATA[virtualization]]></category>
		<category><![CDATA[vmware]]></category>
		<category><![CDATA[xen]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=21</guid>
		<description><![CDATA[Many people start looking at Virtualization Technologies because of the promise of doing more with less and high-availability solutions that the technology offers.  However, there are many other benefits to virtualizing your data center, which are explored herein.  Here, we will mainly focus on the free, open-source offering of Xen.  This post [...]]]></description>
			<content:encoded><![CDATA[<p>Many people start looking at Virtualization Technologies because of the promise of doing more with less and high-availability solutions that the technology offers.  However, there are many other benefits to virtualizing your data center, which are explored herein.  Here, we will mainly focus on the free, open-source offering of Xen.  This post closely follows a presentation I gave at the local <a href="http://www.uga.edu/~chugalug/main.html">Classic Hackers UGA Linux Users Group</a> (CHUGALUG) in Athens, Georgia.</p>
<p><center></p>
<div style="width:425px;text-align:left" id="__ss_783075"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/mwlang88/xen-virtualization-2008-presentation?type=powerpoint" title="Xen Virtualization 2008">Xen Virtualization 2008</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=xenq42008-1227532937309184-8&#038;stripped_title=xen-virtualization-2008-presentation" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=xenq42008-1227532937309184-8&#038;stripped_title=xen-virtualization-2008-presentation" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View SlideShare <a style="text-decoration:underline;" href="http://www.slideshare.net/mwlang88/xen-virtualization-2008-presentation?type=powerpoint" title="View Xen Virtualization 2008 on SlideShare">presentation</a> or <a style="text-decoration:underline;" href="http://www.slideshare.net/upload?type=powerpoint">Upload</a> your own. (tags: <a style="text-decoration:underline;" href="http://slideshare.net/tag/xen">xen</a> <a style="text-decoration:underline;" href="http://slideshare.net/tag/vmware">vmware</a>)</div>
</div>
<p></center></p>
<h2>The Main Players</h2>
<p><a href="http://www.vmware.com">VMWare</a> is the most mature offering of the popular offerings.  It was (one of) the first to fully virtualize the Windows Operating system and has been steadily fine-tuning and optimizing its implementation while expanding further into the Enterprise setting than all others.  With it far more mature VMMotion for delivering high-availability features, VMWare currently (Q4 2008) has the leg up in terms of product offering.  VMWare has a product for nearly every niche, from virtualization products for the Windows, Mac, and Linux desktops to a complete Enterprise Infrastructure offering comprehensive business continuity solutions along with the tools to migrate and convert your physical and virtual images up the platform chain.</p>
<p><a href="http://www.xen.org/">Xen</a> is the leading Open Source virtualization solution available.  XenSource was the leading firm providing sponsorship and stewardship of Xen and was recently acquired by <a href="http://www.citrix.com">Citrix, Inc.</a>, long a player in Thin-Application (terminal server) delivery of the Windows platform.  Xen is variously offered and supported by Citrix, Oracle, IBM, SuSE, Sun, Red Hat, and numerous others.</p>
<p><a href="http://www.microsoft.com/windowsserver2008/en/us/hyperv.aspx">Microsoft Hyper-V</a> (formerly Viridian) is, of course, Microsoft&#8217;s entry into the virtualization platform and will become much more prevalent after Windows 2008 Server editions launch.  Hyper-V is still in beta at the time of this writing and expected to emerge from beta within six month of Windows 2008 General Availability (GA).</p>
<h2>Virtualization Technology</h2>
<p>There are two terms to get familiar with when you start assessing virtualization solutions.  Those terms are &#8220;fully-virtualized&#8221; and &#8220;para-virtualized&#8221; (which Microsoft uses &#8220;enlighted Windows&#8221; in their Hyper-V documentation).  </p>
<p>A fully-virtualized OS image is one in which all hardware access is fully protected and/or emulated to the guest Operating System.  This means an unmodified OS and kernel is running in the guest instance and the guest OS typically has no awareness that it is operating as a virtualized instance.</p>
<p>A para-virtualized OS image is one in which a special kernel is deployed for the guest OS and this typically gives the guest OS direct access to many of the hardware components and drivers that the Host OS itself utilizes.  These para-virtualized guests are &#8220;aware&#8221; of their virtualization state and can communicate and coordinate with the other running guest OS&#8217;s on the Host in order to safely share hardware resources.</p>
<h2>CPU Technology</h2>
<p>Both Intel and AMD have gotten into the virtualization game by offering new instruction sets on their respective CPUs that provide hardware assisted virtualization support.  These hardware optimized instruction sets allow for very efficient hypervisor implementations that allow virtualization technologies to offload the oft-complex resource scheduling and sharing logic to the processors themselves.  Those two technologies are called, respectively, Intel-VT (Virtualization Technology) and AMD-V (Virtualization).</p>
<p>Because of VMWare&#8217;s approach to its hypervisor technology, VMWare traditionally makes the least use of these new instruction sets as it already claims to have the most highly optimized &#8220;trap and translate&#8221; and mature hardware management, allowing it to run fully-virtualized (unmodified) versions of guest OS&#8217;s.</p>
<p>Xen and Hyper-V, on the other hand, are heavily reliant on these new instruction sets and consequentially have a much &#8220;thinner&#8221; hypervisor since neither has to get into the business of trapping those unsafe instructions and rewriting them (as VMWare does) to offer a safe and reliable side-by-side hosting of OS&#8217;s.</p>
<p>The bottom line:  VMWare does not require the special instruction sets while Xen and Hyper-V do.  The one caveat to the above is that, because of some design decisions Intel made on memory management on their 64-bit instruction set, VMWare <i>does</i> require Intel-VT to host 64-bit guests, but is using only a small subset of the VT instruction set as it concerns memory, not specifically for managing safe access to hardware resources (so yes, it does get confusing!).  Please see the table on slide #5 in the above presentation for a requirements matrix regarding these CPU instruction sets.</p>
<h2>The benefits of Virtualizing</h2>
<p>I believe most people tend to get interested in virtualization technology when they hear the pitches for the high-availability (HA) solutions that the technology makes almost trivially simple to implement.  High-availability is a catch-all for describing a class of services that allow a guest OS to remain up and running with no apparent downtime should a physical host server go down.  VMWare implements this with VMMotion while Citrix XenServer calls their solution &#8220;Live Migration.&#8221;</p>
<p>However, these HA solutions require a considerable investment in licensing to deploy and may not be fully justifiable for all IT shops.  There are a number of other benefits that a data center can gain from implementing a virtualization platform that can be considerably more valuable than High-availability:</p>
<h3>Increase Hardware Utilization</h3>
<p>Probably the chief advantage the most basic virtualization deployment can offer is simply increasing your CPU and RAM utilization.  Virtualization chiefly takes advantage of the fact that most services on a server are not running at full CPU and RAM capacity 100% of of the time so its very possible to get a perceived 100% of bare-metal performance even in the face of 3 or 4 (or more) guest OS&#8217;s running on one physical machine.  </p>
<p>One of the most astounding discoveries I found in utilizing virtualization technologies is in implementing EnterpriseDB SQLGrid in a virtual environment.  Grid SQL works pretty much as the name implies in that a SQL query is farmed out to all participating nodes in a grid and serviced in parallel with the results being compiled into final result by the master node on the grid.  I found that the DBMS simply wasn&#8217;t taking full advantage of all the CPU cores and RAM when running on bare metal and decided to try running two or three slave nodes within guest OS&#8217;s on the <strong>same</strong> physical server.  It turned out I could get nearly linear improvement in query result performance and much higher utilization of all CPU cores and available RAM.</p>
<h3>Separate Service from Hardware</h3>
<p>Another very beneficial avantage to virtualizing your operating systems, especially with Windows systems is that you can separate your OS install from the hardware.  Our typical approach these days is to install Linux to the bare-metal and then install Windows into a virtual guest instance on our older hardware.  By doing so, we&#8217;re getting near bare-metal performance out of our Windows systems on hardware beyond its reliable lifespan and when the hardware fails, we&#8217;re able to quickly bring up the entire OS instance on another server and continue along our merry way without having to get into re-installing, re-activating, and re-installing all the latest services patches (which, altogether now takes about 4 to 8 hours to get through all those mouse clicks and reboots).</p>
<p>This approach does take you down an entirely new way of thinking about backups and restores.  Instead of deploying expensive backup solutions such as Veritas and Backup-Exec and installing and maintaining agents and directory exception lists, we now use very simple tools such as rsync and gzip to backup full disk images with the server offline and then only backup essential files (such as the SQL Server database backups) on the live running.  </p>
<p>When we do service patches or change software settings, we again down the server and snapshot the disk image for backup (the live snapshots can probably do the same, but we haven&#8217;t truly explored this in our environment since its a relatively new feature to come along since establishing our standard operating procedures).  We&#8217;re not a 24&#215;7 critical shop and are able to establish service windows for maintenance, so this works very, very well for us in practice.</p>
<h3>Business Continuity</h3>
<p>The phenomenal thing we realized about server virtualization technologies and the simple backup and restore procedures discussed above is that we can carry our entire data center of over 60 servers around on one 500gb USB drive (or an offsite storage provider such as Amazon&#8217;s).  Albeit scary from a security standpoint (you will definitely need some good security policies and checkpoints (such as backups being encrypted at rest)), but very liberating from a business continuity standpoint.  </p>
<p>One no longer has to fully invest in a second, continuously running data center and keeping near identical hardware in sync in both locations, not to mention paying for being &#8220;online&#8221; and maintaining a broadband connection for continuously transferring the files to the second data center.  If you have a solid working relationship with your hardware vendor or even a fully-hosted ISP that offers very quick server provisioning in their distance data center, you can literally walk in with your Install CDs for the virtualization host servers, install the hosts on the server equipment, transfer the server images off the USB drives, fire up the guest OS&#8217;s, restore the database backups and other user files (such as the office&#8217;s common drive), change your public DNS entries and you&#8217;re back online for your <i>entire</i> data center in an entirely new data center location.</p>
<h3>Try New Things Cost Effectively</h3>
<p>The final big benefit gained from virtualization technologies is being able to quickly try out new things with new servers without actually having to have a bunch of spare machines sitting around.  New servers can be provisioned in under an hour.  New services can be tried, demoed and evaluated and then the provisioned servers disposed of (or further tuned, licensed, and promoted to &#8220;production&#8221;).</p>
<p>Additionally, you can clone your production servers and painlessly perform &#8220;dry-run&#8221; upgrades and service patches on the instances and run full regression tests on the services all before ever actually performing the work on your live, production systems.  In some cases, you can perform the upgrades on the cloned system in a sandbox environment, then move the new image over to production, down the live instance and up the new instance and be back online in a matter of minutes rather than having to take your services down for extending lengths of time.</p>
<h2>Hardware Consideration</h2>
<p>With the power in today&#8217;s CPUs and server hardware, its often difficult to determine where to invest to get the best bang for the buck.  The following sub-components are listed in order of best ROI to least ROI:</p>
<ol>
<li>Sufficient RAM &#8211; to run many OS guests</li>
<li>Fast Front-Side Bus (FSB) &#8211; to facilitate pushing the memory <--> CPU traffic around</li>
<li>Fast Hard Drives and Controllers &#8211; to boost disk I/O to optimal levels</li>
<li>Multi-core CPU&#8217;s &#8211; to boost number of guests on a single physical server</li>
<li>CPU speed &#8211; To get tasks done in a reasonable response time</li>
<li>Network bandwidth &#8211; To keep all guests responsive even when one is pushing a heavy network load</li>
</ol>
<p>In addition to the above basic hardware consideration, high-availability options require the following:</p>
<ul>
<li>Dedicated iSCSI VLAN w/dedicated NICs</li>
<li>Line-speed, non-blocking switches</li>
<li>Host Bus Adaptors with TCP/IP offload Engines (TOE)</li>
<li>Wide-striped LUN’s</li>
<li>Load-balancing Storage Processors on your SAN</li>
<li><a href="http://www.yolinux.com/TUTORIALS/LinuxClustersAndFileSystems.html">Clustered Filesystems</a> such as Oracle Cluster File System (OCFS2) or Global File System (GFS)</li>
</ul>
<h2>Getting Started</h2>
<p>Many have asked me how to best get started in exploring and deploying virtualized solutions.  My recommendation is to simply start small and take small steps all along the way.  You do not need to invest heavily and take a great leap of faith to begin reaping the benefits of virtualization.  Building a performant virtualization environment requires experience and knowledge of what you&#8217;re working with and an extension of your sleuthing skills for finding performance bottlenecks and resolving those issues.  Instead of simply solving one physical machine&#8217;s problem, you&#8217;re now faced with the task of resolving any one guest OS&#8217;s performance problems in light of any other guest OS that may be running on that box.  So you will have to become adept at looking at both the big picture for the host server and simultaneously looking at the individual guests to see where the issues are coming from.</p>
<p>Also, I would not recommend starting out virtualizing core infrastructure components (such as email, DNS, firewalls, etc.) or critical services, and <em>especially</em> I/O intensive services such as database servers until you have become adept at running a very stable and performant virtualization infrastructure.  </p>
<p>Instead, try to cut your virtual teeth on currently unstable services or servers that are verily on their last legs hardware-wise.  After all, if you migrate an old Pentium IV 500mhz server into very poorly performing virtual host environment that is running 2ghz multi-core processors, you are still hard-pressed to be taking a step backwards performance-wise.</p>
<h2>Conclusion</h2>
<p>Virtualization technologies are changing the landscape of server and data management in the data centers.  More services can be run on significantly less hardware and those services begin to become much more portable and deployable.  Virtualization addresses many issues from business continuity and high-availability management to quickly provisioning and simplifying server configurations while significantly boosting utilization levels of the hardware itself.</p>
<h2>Background</h2>
<p>In preparing this post, I ran across a very good resources that give an in-depth background look at Xen and virtualization technologies in general.  These are provided here:</p>
<ul>
<li><a href="http://en.opensuse.org/Virtualization_Terminology">Virtualization Terminology</a></li>
<li><a href="http://www.ibm.com/developerworks/library/l-xen/">A moment of Xen: Virtualize Linux to test your apps</a></li>
<li><a href="http://en.wikipedia.org/wiki/X86_virtualization">x86 virtualization</a></li>
<li><a href="http://www.kernelthread.com/publications/virtualization/">An Introduction to Virtualization</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/overview-of-xen-virtualization/21/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting mouse wheel to work with KVM and Ubuntu</title>
		<link>http://ramblings.gibberishcode.net/archives/getting-mouse-wheel-to-work-with-kvm-and-ubuntu/20</link>
		<comments>http://ramblings.gibberishcode.net/archives/getting-mouse-wheel-to-work-with-kvm-and-ubuntu/20#comments</comments>
		<pubDate>Mon, 03 Nov 2008 00:02:10 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Servers]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[kvm]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mouse]]></category>
		<category><![CDATA[mouse wheel]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=20</guid>
		<description><![CDATA[I have been busy getting a Ubuntu based Network Attached Storage server up and running as well as finally switching my trusty desktop to Ubuntu running my old Windows XP as a VMWare Server image.  All was fine and dandy until I decided to add a KVM to the mix so I could easily switch [...]]]></description>
			<content:encoded><![CDATA[<p>I have been busy getting a Ubuntu based Network Attached Storage server up and running as well as finally switching my trusty desktop to Ubuntu running my old Windows XP as a VMWare Server image.  All was fine and dandy until I decided to add a KVM to the mix so I could easily switch between the NAS and my workstation without having to have two monitors and keyboards.</p>
<p>Turns out the mouse wheel would stop working after a switcharoo.  It took me a little while to track down the solution on the Ubuntu forums.  There was a lot of back and forth in the comments, but this is the dead-simple solution:</p>
<h3>Ensure the psmouse module is loading</h3>
<p>Edit and add the following line to /etc/modules:</p>
<pre class="c:nocontrols">psmouse
</pre>
<p>You&#8217;ll need to use sudo (i.e. <strong>sudo vi /etc/modules</strong>).</p>
<h3>Set the imps option for the module</h3>
<p>As sudo user, edit /etc/modprobe.d/options and append the following:</p>
<pre class="c:nocontrols"> # Make my mouse work with KVM
 options psmouse proto=imps
</pre>
<h3>Reload the mouse module</h3>
<p>Once you have the above, issue the following commands:</p>
<pre class="c:nocontrols"> # sudo modprobe -r psmouse
 # sudo modprobe -a psmouse
</pre>
<p>Once you do this, you should have a functioning mouse wheel.  Test it out before and after switching machines with your KVM hot keys.</p>
<p>Thanks to the contributors of the <a href="http://ubuntuforums.org/archive/index.php/t-205640.html">Ubuntu Forums</a> for this.</p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/getting-mouse-wheel-to-work-with-kvm-and-ubuntu/20/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Jumpstarting your Virtual tour with Oracle VM</title>
		<link>http://ramblings.gibberishcode.net/archives/jumpstarting-your-virtual-tour-with-oracle-vm/19</link>
		<comments>http://ramblings.gibberishcode.net/archives/jumpstarting-your-virtual-tour-with-oracle-vm/19#comments</comments>
		<pubDate>Wed, 29 Oct 2008 23:02:38 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Servers]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[oracle vm]]></category>
		<category><![CDATA[virtualization]]></category>
		<category><![CDATA[vmware]]></category>
		<category><![CDATA[xen]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=19</guid>
		<description><![CDATA[Server virtualization technology has come a long ways in the last 18 months (today being a wonderful October 28, 2008 crisp, cold Fall Sunny day).  Here, I am going to take a look at Oracle VM, one of the relative newcomers to the game and show you how to quickly get up and running with [...]]]></description>
			<content:encoded><![CDATA[<p>Server virtualization technology has come a long ways in the last 18 months (today being a wonderful October 28, 2008 crisp, cold Fall Sunny day).  Here, I am going to take a look at Oracle VM, one of the relative newcomers to the game and show you how to quickly get up and running with a Xen host and virtual server.</p>
<h3>A little background&#8230;</h3>
<p>Our shop has been using virtual technologies for just over two years.  At the time we started taking it seriously, the open source offerings were just on the cusp of being production quality; Citrix had not yet bought into Xen; and VMWare had just rolled out their free VMWare Server option.  We had a mixture of Linux and Windows servers, all physical, and were really feeling some of the budget pince in our rapid growth.  We decided it was time to rethink how we were growing our data-center and that led us to try out VMWare and Xen side-by-side, eventually siding with Xen since the bulk of our servers turned out to be Linux hosts while our predominant application, SQL Server 2005 was not all that conducive to being virtualized without some heavy, heavy investment in hardware purchases.  </p>
<p>The gameplan, get some beefy servers, run Xen on them, with images residing on SAN and migrate all our physical Linux hosts to virtualized environment.  Once converted, we&#8217;d simply reclaim all the excess hardware to fuel the Windows SQL Server hunger.  </p>
<p>So, off we went. We purchased a three of Dell&#8217;s first dual quad-core servers at 1.66ghz and loaded them up with 16gb of RAM and a Dell AX150i iSCSI dual storage processor SAN to run our wonderfully envisioned HA cluster off of.  </p>
<p>Xen had just turned 3.0 at the time and we really went through a lot of permutations in our stress testing and daily use before we finally came up with a stable blending of several offerings from the open source community.  As wild as it may seem, we settled on Oracle VM&#8217;s first release as the Xen server, CentOS 5 repositories to manage packages on the host, Red Hat&#8217;s kickstart project to build the VM&#8217;s and ran a mixed guest environment of CentOS 4, CentOS 5, and Fedora Core 8.  The guest environment&#8217;s heterogeneity had a purpose for existing.  You see, our clients often dictated what version of Red Hat they wanted us to support when we deployed our systems in their data center, so we needed these three items (all relatively free of compulsory licensing fees) to give us the ability to effectively emulate any of our clients&#8217; data center in-house for Q/A, stress/load, and deployment &#8220;dry-run&#8221; testing purposes. </p>
<p>After trying for many moons to effect a HA clustering solution that was rock-solid and backed by the SAN, we sadly had to regress from that vision (for now).  VM images that were once all homed on the SAN and connected via iSCSI to the Xen hosts simply overwhelmed our SAN with I/O dropping low enough to force the filesystems of the guests into read-only state.  We gave up the HA vision (for now) and purchased a bunch of very fast SCSI drives and RAID 5&#8242;d them, filling up each of the Xen Host&#8217;s drive bays and relocated the VM images to each Xen host&#8217;s local volumes.  </p>
<p>This infrastructure has been our &#8220;norm&#8221; for the better part of the year now and we have a rock-solid deployment running about 80 virtualized Linux hosts on just four Dell servers.  The ease with which we can set up a new server or tear one down and dismiss it has had quite an effect on our ability to test widely varying deployment scenarios and automate the deployments themselves. </p>
<h3>Fast forward October 2008</h3>
<p>The newest version of Xen from Red Hat (and hence CentOS for us) is looking rather sharp.  Virtually all the issues we were encountering with just standalone Xen hosts appear to be addressed (in our limited testing).  One of the more critical one, where our Dom0 environment would become unstable and we&#8217;d lose ability to manage it has been fixed (our lone-remaining headache in the above setup).  We have not, however, ventured to test whether our HA woes have been resolved as well.  One other thing we did notice, though was that VM guests shutdown and launch a whole lot faster than they do on our production servers, so that could hint to some very good performance improvements lurking in the newest releases of Xen.,</p>
<p>The downside:  Six, yes count &#8216;em, six CDs must be downloaded to install the CentOS Xen version.  Oracle VM, by comparison clocks in at roughly ONE 500mb CD image plus two companion CDs that give you their VM Manager and some other handy tools that go hand in hand with managing a Virtual Server environment.  Oracle wisely dispenses with all the developer tools and Gnome desktop and office productivity tools that bloat up the RHEL/CentOS distros.  Good security practices recommend only running what you need to run on your server and nothing else!</p>
<p>What follows below is how to get your first Virtualized server up and running by downloading just the one Oracle VM Xen Server CD.  As far as I know, this is about as simple as it gets.  The graphical environment is not used and none of the iSCSI or LVM (logical volume management) tools are employed.  This is just a simple exercise that gets your hands dirty and playing with virtual technologies.</p>
<h3>Step 1 &#8211; Install the Xen Server</h3>
<p>Download the Oracle VM Server 32-bit Edition CD from <a href="http://www.oracle.com/virtualization">Oracle</a> and burn the ISO to CD.  Then plop it into your CD drive on the machine you want and boot up.  Follow the installation instructions on the screen (or the <a href="http://download.oracle.com/docs/cd/E11081_01/welcome.html">Online documentation</a>).  Once installed, boot up and log in as root.</p>
<p>Note:  At the time of this writing, we&#8217;re installing Oracle VM 2.1.2</p>
<p>You should now be able to issue:</p>
<pre  name="code" class="ruby:nocontrols">
# xm list
Name                                        ID   Mem VCPUs      State   Time(s)
Domain-0                                     0   543     1     r-----   3036.7
</pre>
<p>And see an output similar to the above.  Congratulations, you have a Xen Server up and running.</p>
<h3>Step 2 &#8211; Initial File Preparation for the Guest</h3>
<p>Initialize diskspace for your first Virtual Machine by performing the following commands (as root):</p>
<pre  name="code" class="ruby:nocontrols">
# cd /OVS
# mkdir -p local/numberone &#038;&#038; cd local/numberone
# mkdir numberone
# cd numberone
# dd if=/dev/zero of=numberone_hda1.img bs=1024k count=6000
# dd if=/dev/zero of=numberone_hda2.img bs=1024k count=1500
</pre>
<p>This will set up a &#8220;local/numberone&#8221; folder on the Oracle Clustered File System partition, &#8220;/OVS&#8221; with first file being 6gb and 2nd file being 1.5gb.  These will then become root partition and swap space of the guest VM, which we&#8217;re calling &#8220;numberone&#8221; here (you can name it any valid hostname you desire). Once these files are established, we create the filesystems for them with:</p>
<pre  name="code" class="ruby:nocontrols">
# mkfs.ext3 numberone_hda1.img
# mkswap numberone_hda2.img
</pre>
<h3>Step 3 &#8211; Establish the Root partition of the Guest</h3>
<p>Its time to push some files onto the root partition so that we have a valid system that can boot.  Begin by issuing the following statements:</p>
<pre  name="code" class="ruby:nocontrols">
# cd /OVS/local/numberone
# mkdir hda1
# mount -o loop numberone_hda1.img hda1
# rsync  -avH /boot hda1
# rsync  -avH /root hda1
# rsync  -avH /dev hda1
# rsync  -avH /var hda1
# rsync  -avH /etc hda1
# rsync  -avH /usr hda1
# rsync  -avH /bin hda1
# rsync  -avH /sbin hda1
# rsync  -avH /lib hda1
# rsync -avH /selinux hda1
# mkdir hda1/{proc,sys,home,tmp}
# chmod 777 hda1/tmp
# unmount hda1
# rmdir -rf hda1
</pre>
<h3>Step 4 &#8211; Configure the Guest</h3>
<p>You really don&#8217;t want the guest OS coming up with the same configuration as your Xen Host, so lets get into the guest&#8217;s /etc folder and do some tweaking:</p>
<p>Edit /OVS/local/numberone/hda1/etc/fstab and set the root and swap partitions</p>
<pre  name="code" class="ruby:nocontrols">
/dev/hda1               /                       ext3    defaults        1 1
/dev/hda2               swap                    swap    defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
tmpfs                   /dev/shm                tmpfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
sysfs                   /sys                    sysfs   defaults        0 0
</pre>
<p>Edit /OVS/local/numberone/hda1/etc/sysconfig/network and change the hostname</p>
<pre  name="code" class="ruby:nocontrols">
NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=numberone
GATEWAY=192.168.0.5
</pre>
<p>Note:  Gateway is the firewall on your network providing Internet connectivity.  Mine happens to be 192.168.0.5.</p>
<p>Edit /OVS/local/numberone/hda1/etc/hosts and change the hostname</p>
<pre  name="code" class="ruby:nocontrols">
127.0.0.1               numberone localhost.localdomain localhost
::1             localhost6.localdomain6 localhost6
</pre>
<p>Rename /OVS/local/numberone/hda1/etc/sysconfig/network-scripts/ifcfg-eth0 to /OVS/local/numberone/hda1/etc/sysconfig/network-scripts/ifcfg-eth0.bak so its not used when the guest first boots up.</p>
<p>Similarly, rename /OVS/local/numberone/hda1/lib/tls to /OVS/local/numberone/hda1/lib/tls.disabled</p>
<p>Then unmount the guest&#8217;s root partition:</p>
<pre  name="code" class="ruby:nocontrols">
# cd /OVS/local/numberone
# umount hda1
</pre>
<p>Create a domain configuration file for your new guest in /etc/xen/numberone on the Xen Server (not the guest&#8217;s root partition):</p>
<pre  name="code" class="ruby:nocontrols">
#  -*- mode: python; -*-
#============================================================================
# Python configuration setup for 'xm create'.
# This script sets the parameters used when a domain is created using 'xm create'.
# You use a separate script for each domain you want to create, or
# you can set the parameters for the domain on the xm command line.
#============================================================================

#----------------------------------------------------------------------------
kernel = "/boot/vmlinuz-2.6.18-8.1.15.1.16.el5xen"
ramdisk = "/boot/initrd-2.6.18-8.1.15.1.16.el5xen.img"
memory = 512
name = "numberone"

vif = [ 'bridge=xenbr0' ]

disk = ['file:/OVS/local/gox/gox_hda1.img,hda1,w',
        'file:/OVS/local/gox/gox_hda2.img,hda2,w' ]

root = "/dev/hda1 ro"

# Sets runlevel 4.
extra = "4"
</pre>
<p>The mac address was left out of the vif definition.  We&#8217;ll boot up the guest to console and see what &#8220;reasonable value&#8221; the Xen host establishes for the server then come back and hard code the value so its not changing all the time.  </p>
<h3>Step 5 &#8211; Booting for the first time</h3>
<p>To boot the guest, we&#8217;ll use the command-line tools, specifically &#8220;xm&#8221; to create (boot) the guest and shutdown rather than the Oracle VM Manager.  So lets have a look:</p>
<pre  name="code" class="ruby:nocontrols">
# xm create -c numberone
</pre>
<p>The &#8220;-c&#8221; flag boots you with console view of the guest.  If all went well, you&#8217;ll see a typical Linux boot up process that leads all the way to a login prompt similar to this:</p>
<pre  name="code" class="ruby:nocontrols">
Oracle VM server release 2.1.2
Hypervisor running in UNDETERMINED bit mode (WARNING: XEND IS PROBABLY NOT RUNNING).

Network :
Management Interface  :
If : eth1(Down)  Mac :  IP address : 

Configured Networks and Bridges :
If : eth0	 Mac : 00:16:3E:22:F3:4F

CPU :
cpu family	: 15
model		: 31
model name	: AMD Athlon(tm) 64 Processor 3200+

numberone login:
</pre>
<p>Copy that Mac address to clipboard (or write it down) because you&#8217;re going to need it for the next steps.  Log in as root, same password as the Xen Host (since we copied everything off the host to begin with!).</p>
<p>Edit /etc/sysconfig/network-scripts/ifcfg-eth0:</p>
<pre  name="code" class="ruby:nocontrols">
DEVICE=eth0
BOOTPROTO=static
HWADDR=00:16:3E:22:F3:4F
ONBOOT=yes
IPADDR=192.168.0.150
NETMASK=255.255.255.0
</pre>
<p>Once you&#8217;ve done this, you should be able to start your network and ping your gateway:</p>
<pre  name="code" class="ruby:nocontrols">
# ifup eth0
# ping 192.168.0.5
PING 192.168.0.5 (192.168.0.5) 56(84) bytes of data.
64 bytes from 192.168.0.5: icmp_seq=1 ttl=64 time=3.33 ms
64 bytes from 192.168.0.5: icmp_seq=2 ttl=64 time=1.04 ms
</pre>
<p>If not, check for typos.  Otherwise, you&#8217;re done with configuring the guest.  Continue by logging out of your guest then break from console with <strong>CTRL-]</strong> (control-key plus left-bracket key).  Edit /etc/xen/numberone and change the vif line to read:</p>
<pre  name="code" class="ruby:nocontrols">
vif = [ 'mac=00:16:3E:22:F3:4F, bridge=xenbr0' ]
</pre>
<p>This gels your mac address for the guest VM so the network will be reliably started on reboots for eth0 device.  Now issue the following:</p>
<pre  name="code" class="ruby:nocontrols">
# xm shutdown numberone
# xm top
</pre>
<p>And watch your guest disappear from the listing.  Once its gone, issue the following to bring it back up:</p>
<pre  name="code" class="ruby:nocontrols">
# xm create numberone
</pre>
<p>Finally, if everything&#8217;s gone well, you will be able to ssh to the guest VM with:</p>
<pre  name="code" class="ruby:nocontrols">
# ssh 192.168.0.150 -l root
</pre>
<p>(Hey, I didn&#8217;t say it was uber secure or that we&#8217;re following best practices regarding root accounts!)</p>
<p>If you can&#8217;t ssh into the guest from the xen server, you&#8217;ll have to get back into console and review logs and figure out what went wrong.  You may need to fix typos in your configs or try another xen bridge such as xenbr1.  If you are able to issue &#8220;ifup eth0&#8243; within the guest and can ping your firewall, its not network connectivity, but a typo in your /etc/sysconfig/* files somewhere.  Probably the best place to double-check things is the mac address.</p>
<pre  name="code" class="ruby:nocontrols">
# xm console numberone
</pre>
<p>One last tip.  If you want to install packages that didn&#8217;t come on the Oracle VM install CD, you can add the CentOS5 repository to the VM guest and install various packages using yum thereafter.  To do this, log into your Guest VM, and edit the following new file: /etc/yum.repos.d</p>
<pre  name="code" class="ruby:nocontrols">
[CentOS5 base]
name=CentOS-5-Base
mirrorlist=http://mirrorlist.centos.org/?release=5&#038;arch=$basearch&#038;repo=os
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=0
enabled=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5

[CentOS5 updates]
name=CentOS-5-Updates
mirrorlist=http://mirrorlist.centos.org/?release=5&#038;arch=$basearch&#038;repo=updates
gpgcheck=0
enabled=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5

[CentOS5plus]
name=CentOS-5-Plus
mirrorlist=http://mirrorlist.centos.org/?release=5&#038;arch=$basearch&#038;repo=centosplus
gpgcheck=0
enabled=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
</pre>
<p>So there you have it.  One of the simplest approaches to getting your first Xen guest Virtual Machine up and running and well on your way to experimenting with virtual technologies.  </p>
<p><em><strong>Special Note:</strong>  Much credit must go to my colleague, Manyuan Jin, who spent many, many tireless hours researching early instability issues and treading through the jungle of open source solutions to assemble a working solution for our shop.  </em></p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/jumpstarting-your-virtual-tour-with-oracle-vm/19/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Converting Oddmuse Wiki to Edgewall Trac</title>
		<link>http://ramblings.gibberishcode.net/archives/converting-oddmuse-wiki-to-edgewall-trac/13</link>
		<comments>http://ramblings.gibberishcode.net/archives/converting-oddmuse-wiki-to-edgewall-trac/13#comments</comments>
		<pubDate>Thu, 02 Oct 2008 16:30:38 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Macs]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python Language]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[oddmuse]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[trac]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=13</guid>
		<description><![CDATA[Our company began long ago with wiki&#8217;s, but we chose the Oddmuse wiki way back when.  These days, we&#8217;re heavy users of Trac wiki because of its integrated ticket support system.  So what to do with all those old wiki&#8217;s that folks have stopped using and reading.  The Oddmuse wikis still hold [...]]]></description>
			<content:encoded><![CDATA[<p>Our company began long ago with wiki&#8217;s, but we chose the Oddmuse wiki way back when.  These days, we&#8217;re heavy users of Trac wiki because of its integrated ticket support system.  So what to do with all those old wiki&#8217;s that folks have stopped using and reading.  The Oddmuse wikis still hold valuable data, but they have since become an administrative overhead to keep around, so I decided to convert them all to Edgewall&#8217;s Trac. </p>
<p>To get started, I needed to know how to get the data into Trac.  The following links gave me an API I could utilize to create trac pages and content:</p>
<p><a href="http://trac.edgewall.org/wiki/TracDev/DataModels">Trac Data Models</a><br />
<a href="http://trac.edgewall.org/browser/trunk/trac/wiki/model.py">The Data model Python code</a></p>
<p>Great!  Except there&#8217;s one small problem.  I don&#8217;t really know python all that well, even though I did do a bit of Zope development, oh, five years ago.  These days, my language of choice is Ruby, so I needed to figure out how to parse the Oddmuse syntax and turn it into Trac syntax.  The strategy:  Parse with Ruby, load cleaned page files with Python.  </p>
<p>This script will take a filename at command line and convert it and save back to file, but different extension (I chose *.om for &#8220;oddmuse&#8221;).  In the script below, I made the command-line optional as I discovered I didn&#8217;t handle every case as I worked on developing this script, so I simply changed the line that pulls the command-line argument to point to a specific file and output such to terminal and this allowed me to debug and fix as I went:</p>
<pre  name="code" class="ruby:nocontrols">
#!/opt/local/bin/ruby
# $FS  = "\xb3";      # The FS character is the RECORD SEPARATOR control char in ASCII
# $FS0 = "\xb3";      # The old FS character is a superscript "3" in Latin-1
# $FS1 = $FS . '1';   # The FS values are used to separate fields
# $FS2 = $FS . '2';   # in stored hashtables and other data structures.
# $FS3 = $FS . '3';   # The FS character is not allowed in user data.

FS = 179.chr

SITE_NAME = "corporate_wiki"
ATTACHMENT_URL_BASE = "https://intranet.example.com/#{SITE_NAME}/attachment/wiki/ConvertedAttachments/"

require 'find'
require 'ftools'

def safe_page_name(pagename)
  result = pagename.gsub("'","")
  result = result.slice(/(\w+)/).first
end

def get_section(page, section)
  page.each_with_index {|e,i| return page[i+1] if e == section}
  return ''
end

def asterick_prefixed(text)
  t = text.match(/(\*+)([^\b]*)/)
  return text if t.nil?

  tokens = t.to_a
  return ('  ' * tokens[1].size) + '* ' + tokens[2]
end

def colon_prefixed(text)
  return "  #{colon_prefixed(text.slice(1,text.size))}" if text[0] == ":"[0]
  return text
end

def pound_prefixed(text)
  return "  1. #{text.slice(1,text.size)}" if text[0] == "#"[0]
  return text
end

def fix_headers(text)
  t = text.match(/(=+)([^=]+)(=+)/)
  return text if t.nil?

  tokens = t.to_a
  return "#{tokens[1]} #{tokens[2].strip} #{tokens[1]}"
end

def replace_a_url(url, text)
  text.gsub!("http://#{url}", ATTACHMENT_URL_BASE)
  text.gsub!("https://#{url}", ATTACHMENT_URL_BASE)
  text.gsub!("http:/#{url}", ATTACHMENT_URL_BASE)
  text.gsub!("https:/#{url}", ATTACHMENT_URL_BASE)
  return text
end

def replace_wiki_urls(text)
  matches = text.match(/\[http(.)*\]/)
  result = text
  if matches
    result = replace_a_url("wiki.example.com/#{SITE_NAME}/wikifiles/", result)
    result = replace_a_url("pdfreviewfiles/", result)
    result = replace_a_url("cgi-bin/", result)
  end
  result
end

def convert_formats(text)
  result = text.gsub(/\[\[(\w+)\]\]/,"[wiki:" + '\1' + "]")
  result = asterick_prefixed(result)
  result = colon_prefixed(result)
  result = pound_prefixed(result)
  result = replace_wiki_urls(result)
  result = fix_headers(result)
  result
end

def oddmuse_to_trac(text)
  result = ''
  in_pre = false
  text.split("\n").each do |line|

    # Detect indented lines as these are rendered as PRE html blocks
    trimmed = line.lstrip
    is_prefixed = ((trimmed.size < line.size) and (trimmed[0] != '*'[0]))
    result << "{{{\n" if (is_prefixed and !in_pre)

    result << "}}}\n" if (!is_prefixed and in_pre)
    in_pre = is_prefixed

    # Don't process special characters when in PRE block
    if in_pre
      result << line << "\n"
    else
      result << convert_formats(line) << "\n"
    end
  end
  result += "}}}\n" if in_pre
  result
end

path = ARGV[0] || "page/U/UsingThePhones.db"
raw_page = File.new(path).read
page2 = raw_page.split(FS + '2')
page3 = raw_page.split(FS + '3')

text = get_section(page3, 'text')

pagename = File.basename(path).split('.').first
author = get_section(page2, 'username')
address = get_section(page2, 'ip')
body = oddmuse_to_trac(text)

puts "writing: #{pagename}.om"
outfile = File.new(path.gsub('.db','.om'),'w')
outfile.puts 'pagename:' + pagename
outfile.puts 'author:' + author
outfile.puts 'address:' + address
outfile.puts body
outfile.close

puts body if ARGV[0].nil?
</pre>
<p>Below, comes the Python side of the equation.  Once I did the heavy lifting in Ruby, I needed to generate all the pages.  As you can see, there's some parsing happening, but its very simple parsing and I was able to apply what simple Python knowledge I still retained pretty effectively:</p>
<pre  name="code" class="python:nocontrols">
import sys
from trac.env import Environment
from trac.wiki.model import WikiPage

print sys.argv[1]
file = open(sys.argv[1], 'r')
pagename = file.readline().split(':')[1].split('\n')[0]
author_name = file.readline().split(':')[1].split('\n')[0]
address = file.readline().split(':')[1].split('\n')[0]

text = file.read()

env = Environment('/srv/www/trac/corporate_wiki')

# Read an existing or new WikiPage:
page = WikiPage(env, pagename)
if page.text != text:
        page.text = text
        page.save(author=author_name, comment='imported from oddmuse wiki', remote_addr=address)
</pre>
<p>As you can see, this file simply takes the command line argument, open the file for reading, pull the various variables out with the remainder of the file going to the page content.</p>
<p>During the conversion, I noticed some pages were failing to convert at all, like "Michael'sTodoList"  The culprit, the tick in the page name and thus the filename.  The scripts themselves weren't the problem, it was the xargs parameter passing that was the issue (getting to that below).  So I ran the below script to rename all the troublesome filenames and then added similar tick to underscore substitution in the main Ruby script above.  </p>
<pre  name="code" class="ruby:nocontrols">
require 'find'
require 'ftools'

total_size = 0

Find.find('./page') do |path|
  if FileTest.directory?(path)
    if File.basename(path)[0] == ?.
      Find.prune       # Don't look any further into this directory.
    else
      next
    end
  else
    if path.match(/[\']/)
      safe_path = path.gsub("'", "_")
      puts path + ' to ' + safe_path
      File.move(path, safe_path)
    end
    end
  end
</pre>
<p>A simple up-front execution of the script was all that was needed to now be able to pick up the missing pages:</p>
<pre  name="code" class="ruby:nocontrols">
ruby fix_unsafe_files.rb
</pre>
<p>Finally, to bring it all together, I utilized find to locate all the *.db Oddmuse files which I had located into the various wiki subfolders where these scripts sat, passing the filename to the script via the xargs utility:</p>
<pre  name="code" class="ruby:nocontrols">
find . -name *.db -print0 | xargs -0 -L 1 ruby rdpage.rb
</pre>
<p>I then essentially repeated the above, but for the generated *.om files, passing to the Python mkpage.py script:</p>
<pre  name="code" class="ruby:nocontrols">
find . -name *.om -print0 | xargs -0 -L 1 python mkpage.py
</pre>
<p>One last thing, before we're done.  Each wiki had attachments.  So I had to think how to get those attachments referenced and linked to the Trac wiki.  A little investigation revealed that each attachment got a database entry in the attachment table.  My task was a bit complicated by the fact that the users over the years in the Oddmuse environment scattered their attachments everywhere and also used varying syntax to refer to them, hence, if you review the main Ruby parsing script, you'll see the "replace_a_url" method above that cleans all those funky URLs up.  So the script I used below simply scans through all the directories where we had files stored and attached them to one "ConvertedAttachments" page.  Probably not the ideal solution, but again, got the job done quickly.</p>
<pre  name="code" class="ruby:nocontrols">
#  type |          id          |  filename  |  size  |    time    | description | author |      ipnr
# ------+----------------------+------------+--------+------------+-------------+--------+----------------
#  wiki | ConvertedAttachments | gotapi.png | 200272 | 1218381947 |             | michael | 192.168.16.100

path = ARGV[0] || 'generate_attachments.rb'
filename = File.basename(path)

puts "insert into attachment values ('wiki', 'ConvertedAttachments', '#{filename}', #{FileTest.size(path)}, null, null, 'oddmuse','192.168.1.246');"
</pre>
<p>So, running the above needs to be piped to a SQL fisle and then executed against your Trac database.  In my case, Postgresql.  Since I had many directories to snatch up, I ran it for each folder as appropriate and simply kept appending until I had all the attachment directories represented.</p>
<pre  name="code" class="ruby:nocontrols">
ls | xargs -0 -L 1 >> attachments.sql
psql trac_db < attachments.sql
</pre>
<p>All in all, not too bad of a conversion for a few hour's work.  Its about 95% correct.  Some of the page names didn't translate to Trac, and could probably do with some regexp search and replace on the page names themselves.  The biggest gain is that we have preserved the information in the old systems by porting it to the new systems we all know and use on a daily basis, so WikiGardening is more likely to keep the content fresher and its one less system for our end-users to figure out how to use.  </p>
<p>I can now retire the server running Oddmuse, stop doing backups and keeping up with documentation and training new system administrators on how to manage Oddmuse AND Trac.  </p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/converting-oddmuse-wiki-to-edgewall-trac/13/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Changing ANSI colors in Terminal on Macs</title>
		<link>http://ramblings.gibberishcode.net/archives/changing-ansi-colors-in-terminal-on-macs/16</link>
		<comments>http://ramblings.gibberishcode.net/archives/changing-ansi-colors-in-terminal-on-macs/16#comments</comments>
		<pubDate>Tue, 09 Sep 2008 15:56:34 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Servers]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[ansi colors]]></category>
		<category><![CDATA[Macs]]></category>
		<category><![CDATA[terminal colors]]></category>
		<category><![CDATA[vi syntax highlight]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=16</guid>
		<description><![CDATA[Probably the most frustrating experience I have had with Macs so far is figuring out how to change the ANSI colors in Terminal (Terminal.app) so that I can read the outputs of man and most especially ls and comments in vi when colorization is activated and I have chosen a dark background theme.
I am using [...]]]></description>
			<content:encoded><![CDATA[<p>Probably the most frustrating experience I have had with Macs so far is figuring out how to change the ANSI colors in Terminal (Terminal.app) so that I can read the outputs of <b>man</b> and most especially <b>ls</b> and comments in <b>vi</b> when colorization is activated and I have chosen a dark background theme.</p>
<p>I am using Mac OS X Leopard 10.5.4 at the time of this writing.  These are the steps I took to fix that most hideous of all colors, dark blue on black background:</p>
<ol>
<li>Set your terminal theme colors to your liking</li>
<li>Set up <b>ls</b> to colorize directory listings by default.  There are two ways to do this:  Either set the CLICOLOR Environment variable or add an alias for ls to include the -G flag.  I chose the CLICOLOR flag:
<pre name="code" class="ruby:nocontrols">
export CLICOLOR=1
</pre>
</li>
<li>Next up, install the ANSI color SIMBL plugin found here: <a href="http://niw.at/articles/2007/11/02/TerminalColoreopard/en">http://niw.at: works of Yoshimasa Niwa</a>.  Make sure Terminal.app is closed while you install the plugin then relaunch Terminal to find under its main menu, &#8220;Color Preferences&#8230;&#8221;</li>
<li>Finally, edit that dark blue away!</li>
</ol>
<p>If you&#8217;re interested in tailoring the output of the colors even further, you can also export the LSCOLORS variable:</p>
<pre name="code" class="ruby:nocontrols">
export LSCOLORS="exfxcxdxbxegedabagacad"
</pre>
<p>And then change according to the manual entry for ls (&#8220;man ls&#8221;):</p>
<table>
<tr>
<th>a</th>
<td>black</td>
</tr>
<tr>
<th>b</th>
<td>red</td>
</tr>
<tr>
<th>c</th>
<td>green</td>
</tr>
<tr>
<th>d</th>
<td>brown</td>
</tr>
<tr>
<th>e</th>
<td>blue</td>
</tr>
<tr>
<th>f</th>
<td>magenta</td>
</tr>
<tr>
<th>g</th>
<td>cyan</td>
</tr>
<tr>
<th>h</th>
<td>light grey</td>
</tr>
<tr>
<th>A</th>
<td>bold black, usually shows up as dark grey</td>
</tr>
<tr>
<th>B</th>
<td>bold red</td>
</tr>
<tr>
<th>C</th>
<td>bold green</td>
</tr>
<tr>
<th>D</th>
<td>bold brown, usually shows up as yellow</td>
</tr>
<tr>
<th>E</th>
<td>bold blue</td>
</tr>
<tr>
<th>F</th>
<td>bold magenta</td>
</tr>
<tr>
<th>G</th>
<td>bold cyan</td>
</tr>
<tr>
<th>H</th>
<td>bold light grey; looks like bright white</td>
</tr>
<tr>
<th>x</th>
<td>default foreground or background</td>
</tr>
</table>
<p>One final trick to get my bash shell exactly like I like it was to set the prompt.  This can likewise be done by editing ~/.profile:</p>
<pre name="code" class="ruby:nocontrols">
PS1="[\u@\h \W] "
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/changing-ansi-colors-in-terminal-on-macs/16/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Configuring ntpd to hand out time to local servers</title>
		<link>http://ramblings.gibberishcode.net/archives/configuring-ntpd-to-hand-out-time-to-local-servers/14</link>
		<comments>http://ramblings.gibberishcode.net/archives/configuring-ntpd-to-hand-out-time-to-local-servers/14#comments</comments>
		<pubDate>Mon, 11 Aug 2008 16:31:51 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Servers]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[ntp client]]></category>
		<category><![CDATA[ntp server]]></category>
		<category><![CDATA[yum]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=14</guid>
		<description><![CDATA[Syncing your servers to public time servers is one of the most common ways of keeping server times in sync.  Apparently the less common approach of configuring one server to sync with public servers and it in turn becomes the authoritative time keeper for the rest of your servers is less well-known.  Digging [...]]]></description>
			<content:encoded><![CDATA[<p>Syncing your servers to public time servers is one of the most common ways of keeping server times in sync.  Apparently the less common approach of configuring one server to sync with public servers and it in turn becomes the authoritative time keeper for the rest of your servers is less well-known.  Digging through the copious ntp documentation, I have to say, its some very, very dense documentation mainly because the jargon isn&#8217;t well translated to a layperson&#8217;s &#8220;How do I?&#8221; inquiry.</p>
<p>I combed the documentation for days trying to figure out exactly how to set up a server to hand out time to all my other servers.  Normally, my Google-fu can pierce just about any need, but &#8220;time&#8221; &#8220;server&#8221; &#8220;local&#8221; and so on are all too common terms in both client-and-server and client-only configurations and by far and away, the bulk of the documentation guides you through the latter.  The documentation that guides you through the former is dense with references to peers, stratum, broadcasting, multi-casting, and so on.</p>
<p>So, here&#8217;s how to set up an NTP service as both client and local time server on CentOS 4:</p>
<pre  name="code" class="ruby:nocontrols">
yum install ntp
</pre>
<p>Then edit the /etc/ntp.conf file and set up the public ntp server pools and uncomment the broadcast line and change IP mask to match your network&#8217;s:</p>
<pre  name="code" class="ruby:nocontrols">
server 0.rhel.pool.ntp.org
server 1.rhel.pool.ntp.org
server 2.rhel.pool.ntp.org
broadcast 192.168.1.255
</pre>
<p>Modify your /etc/sysconfig/iptables to allow other servers to connect:</p>
<pre  name="code" class="ruby:nocontrols">
-A RH-Firewall-1-INPUT -p udp -m udp --dport 123 -j ACCEPT
</pre>
<p>Finally, go to the &#8220;client server&#8221; and install ntp on it just as you did with the ntp server, except, this time, you edit your /etc/ntp.conf file to point to your new local time server.  In my case, I set up two servers to give out times and I added ntp.1 and ntp.2 to my local DNS servers, so my config file for the &#8220;client servers&#8221; uses:</p>
<pre  name="code" class="ruby:nocontrols">
server ntp.1.example.com
server ntp.2.example.com
</pre>
<p>Its really that simple!  Its probably not <strong>the most secure</strong> way to do the job as there&#8217;s plenty of information overload in the ntp documentation on configuring securely.  However, with all of my servers sitting in a trusted VLAN and the DNS entries are only served to these servers and NTP port is blocked between this VLAN and others, I reckon it would be fairly hard to hijack the local ntp services.  In other words, the simple approach is good enough, for now.</p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/configuring-ntpd-to-hand-out-time-to-local-servers/14/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
