<?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>mind the explanatory gap</title>
	<atom:link href="http://explanatorygap.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://explanatorygap.net</link>
	<description>many a slip 'twixt mind and lip...</description>
	<lastBuildDate>Tue, 01 Feb 2011 22:50:45 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>My first (product) baby &#8211; Puppet Enterprise 1.0</title>
		<link>http://explanatorygap.net/2011/02/02/my-first-product-baby-puppet-enterprise-1-0/</link>
		<comments>http://explanatorygap.net/2011/02/02/my-first-product-baby-puppet-enterprise-1-0/#comments</comments>
		<pubDate>Tue, 01 Feb 2011 22:50:45 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[puppet]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=302</guid>
		<description><![CDATA[Today we (Puppet Labs) announced the release of Puppet Enterprise 1.0. This has been the big project I&#8217;ve been working on since I left Google for the life of being a product manager at a startup software company. Lack of sleep, worrying about names, trying impose order on the birthing process&#8230;. it&#8217;s not that unlike [...]]]></description>
				<content:encoded><![CDATA[<p>Today we (<a href="http://www.puppetlabs.com">Puppet Labs</a>) announced the release of <a href="http://www.puppetlabs.com/puppet/puppet-enterprise/">Puppet Enterprise 1.0</a>.</p>
<p>This has been the big project I&#8217;ve been working on since I left Google for the life of being a product manager at a startup software company. Lack of sleep, worrying about names, trying impose order on the birthing process&#8230;. it&#8217;s not that unlike real babies.</p>
<p>I&#8217;m proud of Puppet Enterprise.</p>
<p>Puppet is an awesomely powerful tool, but it does take some effort to get a scalable deployment going. It&#8217;s not a lot of work if you&#8217;re a reasonably experienced sysadmin, but some people simply don&#8217;t have the time.</p>
<p>We&#8217;ve launched with support for RHEL, CentOS, OEL, Debian and Ubuntu, and I&#8217;m particularly looking forward to our upcoming Mac OS X version.  I may have left the MacEnterprise.org world behind, but all my Mac IT peeps still hold a special place in my heart.</p>
<p>There&#8217;s barely time to take a breath now 1.0 is out, as I&#8217;m heading off to <a href="http://www.fosdem.org">FOSDEM</a> in a couple of days to run the <a href="http://fosdem2011.puppetlabs.com/">configuration management devroom</a> with <a href="http://www.kartar.net/">James Turnbull</a>.</p>
<p>I&#8217;m planning to conduct some in-depth quality control inspections of Belgian beer while I&#8217;m in Brussels. Suggestions for inspection locations are more than welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2011/02/02/my-first-product-baby-puppet-enterprise-1-0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Farewell Google, Hello Puppet Labs</title>
		<link>http://explanatorygap.net/2010/10/24/farewell-google-hello-puppet-labs/</link>
		<comments>http://explanatorygap.net/2010/10/24/farewell-google-hello-puppet-labs/#comments</comments>
		<pubDate>Sat, 23 Oct 2010 23:51:56 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[puppet]]></category>
		<category><![CDATA[ramblings]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=295</guid>
		<description><![CDATA[Last week I resigned from Google. It&#8217;s been a crazy 4 years. Helping set up the largest Mac deployment I&#8217;ve ever dealt with, getting into Puppet, learning a lot of Python, discovering how robust you can make bash, moving to the Linux teams, learning from a lot of awfully smart people, and dealing with the [...]]]></description>
				<content:encoded><![CDATA[<p>Last week I resigned from Google.</p>
<p>It&#8217;s been a crazy 4 years. Helping set up the largest Mac deployment I&#8217;ve ever dealt with, getting into Puppet, learning a lot of Python, discovering how robust you can make bash, moving to the Linux teams, learning from a lot of <strong>awfully</strong> smart people, and dealing with the fallout from the Operation Aurora attacks earlier this year&#8230; it&#8217;s hard to believe it&#8217;s only been 4 years in some ways.</p>
<p>It felt right to put something up here about this, but don&#8217;t expect any earth shattering revelations or horror stories.</p>
<p>I thoroughly enjoyed working at Google. I loved working with so many talented people, and I loved getting to work on infrastructure at scale that was developed by smart people.</p>
<p>However, the time was right to leave. The endless suburbia of the Bay Area was starting to get to us, and I&#8217;ve been very close to the Puppet Labs folks for a long time now, so when they offered me the position of Product Manager, and a chance to finally put my money where my mouth is about Puppet&#8230; well I couldn&#8217;t turn it down.</p>
<p>We have a lot of work to do at Puppet Labs, but it&#8217;s exciting work, as I honestly feel that we have a great chance of helping to fundamentally improve our industry. What more could I ask for out of a job?</p>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2010/10/24/farewell-google-hello-puppet-labs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using crankd to run Puppet on network events</title>
		<link>http://explanatorygap.net/2010/10/17/using-crankd-to-run-puppet-on-network-events/</link>
		<comments>http://explanatorygap.net/2010/10/17/using-crankd-to-run-puppet-on-network-events/#comments</comments>
		<pubDate>Sun, 17 Oct 2010 03:28:49 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[macosx]]></category>
		<category><![CDATA[puppet]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=292</guid>
		<description><![CDATA[Gary Larizza has put together a great article that covers setting up crankd and Puppet to automatically apply system updates to Mac laptops when they appear on the corporate network. http://glarizza.posterous.com/using-crankd-to-react-to-network-events This is exactly what Chris and I wrote it for initially, so it&#8217;s great to see this info out there. Now I have somewhere [...]]]></description>
				<content:encoded><![CDATA[<p>Gary Larizza has put together a great article that covers setting up crankd and Puppet to automatically apply system updates to Mac laptops when they appear on the corporate network.</p>
<p><a href="http://glarizza.posterous.com/using-crankd-to-react-to-network-events">http://glarizza.posterous.com/using-crankd-to-react-to-network-events</a></p>
<p>This is exactly what Chris and I wrote it for initially, so it&#8217;s great to see this info out there.</p>
<p>Now I have somewhere to point Greg if he bugs me about it again. :)</p>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2010/10/17/using-crankd-to-run-puppet-on-network-events/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>pymacds &#8211; managing DirectoryServices with Python</title>
		<link>http://explanatorygap.net/2010/10/13/pymacds-managing-directoryservices-with-python/</link>
		<comments>http://explanatorygap.net/2010/10/13/pymacds-managing-directoryservices-with-python/#comments</comments>
		<pubDate>Tue, 12 Oct 2010 18:49:38 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[macosx]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[software and scripts]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=284</guid>
		<description><![CDATA[[updated - 0.3 out with more useful wrapper methods] I just added the pymacds module to the pymacadmin project. To install the eggs for Python2.5 (OS X 10.5 only comes with 2.5) or Python2.6 (OS X 10.6 comes with both), run something like: curl -O http://pymacadmin.googlecode.com/files/pymacds-0.3-py2.5.egg sudo easy_install-2.5 pymacds-0.3-py2.5.egg or curl -O http://pymacadmin.googlecode.com/files/pymacds-0.3-py2.6.egg sudo easy_install-2.6 [...]]]></description>
				<content:encoded><![CDATA[<p>[updated - 0.3 out with more useful wrapper methods]</p>
<p>I just added the pymacds module to the <a href="http://code.google.com/p/pymacadmin/">pymacadmin</a> project.</p>
<p>To install the eggs for Python2.5 (OS X 10.5 only comes with 2.5) or Python2.6 (OS X 10.6 comes with both), run something like:</p>
<p><code><br />
curl -O http://pymacadmin.googlecode.com/files/pymacds-0.3-py2.5.egg<br />
sudo easy_install-2.5 pymacds-0.3-py2.5.egg<br />
</code></p>
<p>or</p>
<p><code><br />
curl -O http://pymacadmin.googlecode.com/files/pymacds-0.3-py2.6.egg<br />
sudo easy_install-2.6 pymacds-0.3-py2.6.egg<br />
</code></p>
<p>Once you&#8217;ve done this, you can use it like:</p>
<p><code><br />
nigelk$ python2.5<br />
Python 2.5.4 (r254:67916, Feb 11 2010, 00:50:55)<br />
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin<br />
Type "help", "copyright", "credits" or "license" for more information.<br />
&gt;&gt;&gt; import pymacds<br />
&gt;&gt;&gt; pymacds.UserAttribute('nigelk', 'NFSHomeDirectory')<br />
[u'/Users/nigelk']<br />
&gt;&gt;&gt; pymacds.GetSearchNodes()<br />
['/Local/Default', '/BSD/local', '/LDAPv3/my.ldap.node']<br />
&gt;&gt;&gt; pymacds.GetContactsNodes()<br />
['/LDAPv3/my.ldap.node']<br />
&gt;&gt;&gt;<br />
</code></p>
<p>There are a few other useful methods, listing them here rather than going through them one by one. We&#8217;re particularly fond of the Ensure* methods for triggering DirectoryService node addition/removal on network events via crankd.</p>
<p><code><br />
FlushCache():<br />
GetSearchNodes():<br />
GetContactsNodes():<br />
AddNodeToSearchPath(node):<br />
AddNodeToContactsPath(node):<br />
DeleteNodeFromSearchPath(node):<br />
DeleteNodeFromContactsPath(node):<br />
EnsureSearchNodePresent(node):<br />
EnsureSearchNodeAbsent(node):<br />
EnsureContactsNodePresent(node):<br />
EnsureContactsNodeAbsent(node):<br />
DSQuery(dstype, objectname, attribute=None):<br />
DSSet(dstype, objectname, attribute=None, value=None):<br />
DSDelete(dstype, objectname, attribute=None, value=None):<br />
UserAttribute(username, attribute):<br />
GroupAttribute(groupname, attribute):<br />
AddUserToLocalGroup(username, group):<br />
RemoveUserFromLocalGroup(username, group):<br />
</code></p>
<p>Code contributions welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2010/10/13/pymacds-managing-directoryservices-with-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>python subprocess over shell</title>
		<link>http://explanatorygap.net/2010/05/10/python-subprocess-over-shell/</link>
		<comments>http://explanatorygap.net/2010/05/10/python-subprocess-over-shell/#comments</comments>
		<pubDate>Mon, 10 May 2010 04:16:54 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[*nix]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[ramblings]]></category>
		<category><![CDATA[Snippets]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=256</guid>
		<description><![CDATA[One of my common gripes is when people struggle with complicated shell scripts that would be much simpler in a scripting language like Python, Ruby or Perl. I used to abuse PHP for this, but saw the light. If you&#8217;re talking about replacing shell scripts, all of these are pretty much equivalent, but I don&#8217;t [...]]]></description>
				<content:encoded><![CDATA[<p>One of my common gripes is when people struggle with complicated shell scripts that would be much simpler in a scripting language like Python, Ruby or Perl. I used to abuse PHP for this, but saw the light.</p>
<p>If you&#8217;re talking about replacing shell scripts, all of these are pretty much equivalent, but I don&#8217;t really do Perl for no particular reason, I&#8217;m a big fan of Python for general purpose work just because of the rich module system, and at least <a href="http://python.org/about/quotes/">&#8220;dozens of engineers&#8221; use it at work.</a>.</p>
<p>The reason we generally write shell scripts is because we want to execute a bunch of external processes in an automated way. </p>
<p>In this area you can whip something basic up fastest in shell, yes, but at some point you&#8217;re going to have to repay that <a href="http://explanatorygap.net/2009/10/02/the-complexity-debt/">technical debt</a> if you need to get past a certain point.</p>
<p>Besides, <a href="http://mywiki.wooledge.org/BashPitfalls">it&#8217;s not like shell scripting always stays simple and easy</a>&#8230; and the overhead of moving to a more powerful language isn&#8217;t that huge.</p>
<p>If I&#8217;m sure the scope of a script will be small, or I don&#8217;t have the option of moving to structured data format for input and output with external commands, or I don&#8217;t have to futz around with arrays, I&#8217;ll stick with bash.</p>
<p>But, if I want to work with dictionary objects or talk in a protocol like LDAP or model things as objects, or need complex handling and passing around of stdin/stdout/exit statuses, or know some module handles lots of edge cases for me, I&#8217;ll move to Python or Ruby.  I quite like both, but feel that Python is more utilitarian, and simply due to whitespace enforcement and <a href="http://www.logilab.org/857">extensive linters</a> is a good fit for code that may need to be picked up and understood quickly by a co-worker.</p>
<p>When it comes to getting started with Python, I still suggest <a href="http://www.diveintopython.org/">Dive into Python</a> for people. Just flipping through Chapters 1-3 equips you with an awful lot.</p>
<p>Anyway, some people think Python is hard, but it&#8217;s not really. I think of Python as being extremely utilitarian, which makes it a great fit for sysadmin work.</p>
<p>Someone posted on the <a href="http://www.macenterprise.org">MacEnterprise</a> list a question about working out what PPD was in use by each printer on the system in OS X, and someone gave a good shell example using the usual suspects of for, grep and awk.</p>
<p>There&#8217;s nothing really wrong with doing this, but I&#8217;ve come to distrust parsing non-structured output if I need to keep this solution working across many multiple versions of operating systems, or even between OS X major versions given Apple&#8217;s history.  One of the big advantages of moving to Python is being able to parse and manipulate property lists, which can get really painful in shell.  You end up writing out lots of temp files or giving up on dealing with error conditions. </p>
<p>Anyway, so lets see what it&#8217;s like executing a command in Python with the subprocess module. We&#8217;re asking System Profiler for printer info, and telling it to return the output in XML plist format.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="co1">#!/usr/bin/python</span></p>
<p><span class="kw1">import</span> <span class="kw3">subprocess</span></p>
<p>
command = <span class="br0">&#91;</span><span class="st0">&#8216;system_profiler&#8217;</span>, <span class="st0">&#8216;-xml&#8217;</span>, <span class="st0">&#8216;SPPrintersDataType&#8217;</span><span class="br0">&#93;</span><br />
task = <span class="kw3">subprocess</span>.<span class="me1">Popen</span><span class="br0">&#40;</span>command,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stdout=<span class="kw3">subprocess</span>.<span class="me1">PIPE</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stderr=<span class="kw3">subprocess</span>.<span class="me1">PIPE</span><span class="br0">&#41;</span></p>
<p><span class="br0">&#40;</span>stdout, stderr<span class="br0">&#41;</span> = task.<span class="me1">communicate</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="kw1">print</span> stdout</div>
<p>To skim through those lines, we&#8217;re</p>
<ul>
<li>setting the python shebang</li>
<li>importing the subprocess module</li>
<li>defining a list called &#8216;command&#8217; to store the command we want to run</li>
<li>creating a subprocess Popen object to run our command called &#8216;task&#8217;</li>
<li>setting standard out and standard error to go to our own pipes</li>
<li>getting standard out and standard error from the task.</li>
<li>printing standard out</li>
</ul>
<p>This really isn&#8217;t much work, and if you really only wanted this functionality, there are other <a href="http://docs.python.org/library/subprocess.html#convenience-functions">convenience functions</a> that you can use to make this even shorter, or write your own convenience function.</p>
<p>But we have all sorts of options now.</p>
<p>We can send standard input to the task:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="br0">&#40;</span>stdout, stderr<span class="br0">&#41;</span> = task.<span class="me1">communicate</span><span class="br0">&#40;</span>stdin<span class="br0">&#41;</span></div>
<p>We can ask what the exit status is easily:</p>
<div class="dean_ch" style="white-space: wrap;">status = task.<span class="me1">returncode</span></div>
<p>and if we get None we know the process hasn&#8217;t terminated yet.</p>
<p>And if we want to do something a bit more complicated we can search through the structured data plist output easily like:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="co1">#!/usr/bin/python</span></p>
<p><span class="kw1">import</span> plistlib<br />
<span class="kw1">import</span> <span class="kw3">subprocess</span></p>
<p>
command = <span class="br0">&#91;</span><span class="st0">&#8216;system_profiler&#8217;</span>, <span class="st0">&#8216;-xml&#8217;</span>, <span class="st0">&#8216;SPPrintersDataType&#8217;</span><span class="br0">&#93;</span><br />
task = <span class="kw3">subprocess</span>.<span class="me1">Popen</span><span class="br0">&#40;</span>command,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stdout=<span class="kw3">subprocess</span>.<span class="me1">PIPE</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stderr=<span class="kw3">subprocess</span>.<span class="me1">PIPE</span><span class="br0">&#41;</span></p>
<p><span class="br0">&#40;</span>stdout, stderr<span class="br0">&#41;</span> = task.<span class="me1">communicate</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
printers = plistlib.<span class="me1">readPlistFromString</span><span class="br0">&#40;</span>stdout<span class="br0">&#41;</span><br />
printers = printers<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#8216;_items&#8217;</span><span class="br0">&#93;</span></p>
<p><span class="kw1">for</span> printer <span class="kw1">in</span> printers:<br />
&nbsp; <span class="kw1">print</span> <span class="st0">&#8216;Name: &#8216;</span> + printer<span class="br0">&#91;</span><span class="st0">&#8216;_name&#8217;</span><span class="br0">&#93;</span><br />
&nbsp; <span class="kw1">print</span> <span class="st0">&#8216;PPD: &#8216;</span> + printer<span class="br0">&#91;</span><span class="st0">&#8216;ppd&#8217;</span><span class="br0">&#93;</span><br />
&nbsp;</div>
<p>This is easier to extend than the standard for/grep/awk/sed equivalents tend to be, and much easier for a co-worker to pick up and understand. It comes close to documenting itself, just needs some comments about the structure of Apple&#8217;s output, and some try/except blocks in case the output is malformed or does change.</p>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2010/05/10/python-subprocess-over-shell/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Seeking input for possible Mac IT Conference</title>
		<link>http://explanatorygap.net/2010/05/02/seeking-input-for-possible-mac-it-conference/</link>
		<comments>http://explanatorygap.net/2010/05/02/seeking-input-for-possible-mac-it-conference/#comments</comments>
		<pubDate>Sat, 01 May 2010 16:39:57 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[macosx]]></category>
		<category><![CDATA[macosxserver]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=254</guid>
		<description><![CDATA[The MacEnterprise steering committee has been talking about doing this for way too long, but the recent lack of significant IT tracks at WWDC has spurred us into action. MacEnterprise is planning to partner with various other groups to get a Mac IT focused conference started. This is all very much up in the air, [...]]]></description>
				<content:encoded><![CDATA[<p>The <a href="http://www.macenterprise.org">MacEnterpris</a>e steering committee has been talking about doing this<br />
for way too long, but the recent lack of significant IT tracks at WWDC<br />
has spurred us into action.</p>
<p>MacEnterprise is planning to partner with various other groups to get<br />
a Mac IT focused conference started.</p>
<p>This is all very much up in the air, and at this stage we&#8217;re seeking<br />
input as to how the community would like this conference to be<br />
organized.</p>
<p>At this stage, we would like you to provide input on Google Moderator<br />
as to ideas for the conference. You can submit ideas as well as vote<br />
on other ideas here:</p>
<p><a href="http://goo.gl/mod/4COQ">http://goo.gl/mod/4COQ<br />
</a><br />
Additionally, there is some discussion going on on Twitter, under the<br />
#MacITConference hashtag.</p>
<p><a href="http://twitter.com/#search?q=%23MacITConference">http://twitter.com/#search?q=%23MacITConference<br />
</a><br />
Once we get a little bit better idea of the structure, we&#8217;ll be<br />
calling for speakers and looking for sponsorship partners.</p>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2010/05/02/seeking-input-for-possible-mac-it-conference/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Profiling puppetmasterd with ruby-prof</title>
		<link>http://explanatorygap.net/2010/03/11/profiling-puppetmasterd-with-ruby-prof/</link>
		<comments>http://explanatorygap.net/2010/03/11/profiling-puppetmasterd-with-ruby-prof/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 17:14:12 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[puppet]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=245</guid>
		<description><![CDATA[So I&#8217;m not hugely happy with the CPU consumption of puppetmasterd under heavy load, and so I&#8217;ve been trying to work out where the bottlenecks lie. Unfortunately I&#8217;ve yet to find a smoking gun, but here&#8217;s a reasonably simple way to produce profiles of puppetmasterd. Install ruby-prof from gems. Stop any apache/mongrel/nginx instances of puppetmasterd [...]]]></description>
				<content:encoded><![CDATA[<p>So I&#8217;m not hugely happy with the CPU consumption of puppetmasterd under heavy load, and so I&#8217;ve been trying to work out where the bottlenecks lie. </p>
<p>Unfortunately I&#8217;ve yet to find a smoking gun, but here&#8217;s a reasonably simple way to produce profiles of puppetmasterd.</p>
<ul>
<li>Install ruby-prof from gems.</li>
<li>Stop any apache/mongrel/nginx instances of puppetmasterd you may have running</li>
<li>Edit /usr/sbin/puppetmasterd and replace the last few lines with:
<div class="dean_ch" style="white-space: wrap;"><span class="kw3">require</span> <span class="st0">&#8216;rubygems&#8217;</span><br />
<span class="kw3">require</span> <span class="st0">&#8216;ruby-prof&#8217;</span></p>
<p>result = RubyProf.<span class="me1">profile</span> <span class="kw1">do</span><br />
&nbsp; <span class="kw3">require</span> <span class="st0">&#8216;puppet/application/puppetmasterd&#8217;</span><br />
&nbsp; <span class="re2">Puppet::Application</span><span class="br0">&#91;</span><span class="re3">:puppetmasterd</span><span class="br0">&#93;</span>.<span class="me1">run</span><br />
<span class="kw1">end</span> </p>
<p>printer = <span class="re2">RubyProf::GraphHtmlPrinter</span>.<span class="me1">new</span><span class="br0">&#40;</span>result<span class="br0">&#41;</span></p>
<p><span class="kw4">File</span>.<span class="kw3">open</span><span class="br0">&#40;</span><span class="st0">&#8216;/tmp/ruby-profile.html&#8217;</span>, <span class="st0">&#8216;w&#8217;</span><span class="br0">&#41;</span> <span class="kw1">do</span> |file|<br />
&nbsp; printer.<span class="kw3">print</span><span class="br0">&#40;</span>file, <span class="br0">&#123;</span>:min_percent =&gt; <span class="nu0">10</span>, <span class="re3">:print_file</span> =&gt; <span class="kw2">true</span><span class="br0">&#125;</span><span class="br0">&#41;</span><br />
<span class="kw1">end</span></div>
</li>
<li>Start a webrick puppetmasterd with &#8211;no-daemonize</li>
<li>Do a client run against it</li>
<li>Hit Ctrl-C to interrupt your puppetmasterd</li>
<li>wait for the html output to be generated</li>
</ul>
<p>It&#8217;s worth filtering the min_percent value. Without it, I ended up with 300+MB HTML files with no images that took my dev server a <b>long</b> time to write to disk. With it, I end up with a couple of megs.</p>
<p>You can see an example output at:<br />
<a href="http://www.explanatorygap.net/crap/ruby-profile.html">http://www.explanatorygap.net/crap/ruby-profile.html<br />
</a><br />
with the interesting thread being at:<br />
<a href="http://www.explanatorygap.net/crap/ruby-profile.html#70121801903160">http://www.explanatorygap.net/crap/ruby-profile.html#70121801903160</a></p>
<p>Interpretation suggestions welcome :)</p>
<p><b>Edit</b>:</p>
<p>Brice had a great suggestion of using CallTreePrinter instead of GraphHtmlPrinter and analysing the output with kcachegrind (which is utterly amazing). Obviously your output file shouldn&#8217;t be html then&#8230;</p>
<p>I&#8217;ve put a <a href="http://explanatorygap.net/crap/puppetmasterd-calltree-profile.txt">CallTree output up here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2010/03/11/profiling-puppetmasterd-with-ruby-prof/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Finally&#8230; a sanctioned way of activating the screen saver.</title>
		<link>http://explanatorygap.net/2009/11/25/finally-a-sanctioned-way-of-activating-the-screen-saver/</link>
		<comments>http://explanatorygap.net/2009/11/25/finally-a-sanctioned-way-of-activating-the-screen-saver/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 15:30:47 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[macosx]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=240</guid>
		<description><![CDATA[Ever since I started managing Macs in a corporate environment, I&#8217;ve been annoyed that Apple has failed to offer a sanctioned way of locking the screen via a keyboard command. This is a reasonably common requirement in a lot of corporate deployments. Sure we can use hot corners etc, or we can use one of [...]]]></description>
				<content:encoded><![CDATA[<p>Ever since I started managing Macs in a corporate environment, I&#8217;ve been annoyed that Apple has failed to offer a sanctioned way of locking the screen via a keyboard command.  This is a reasonably common requirement in a lot of corporate deployments. Sure we can use hot corners etc, or we can use one of the sanctioned methods to activate the loginwindow via Fast User Switching, but the former isn&#8217;t for everyone, and the latter sucks because it will tear down userspace VPN/802.1x connections.</p>
<p>We have reasonable MCX controls to require a password for the screensaver, but nothing to actually activate it. There are a bunch of private API calls you can use to achieve this, but using private APIs makes me feel dirty.</p>
<p>When I first started poking at Automator again in 10.6, I was pleased to notice that we have a &#8220;Start Screen Saver&#8221; action.  This means that we can save such an Automator workflow as a Service, and then assign a keyboard command to it such that we can activate it from any application.</p>
<p>Unfortunately this action is buggy. If you activate the workflow and wiggle the mouse around, you&#8217;ll get an error dialog after unlocking the screen.</p>
<p>Luckily we have another way of achieving the same goal. The System Events AppleScript dictionary contains the same functionality.</p>
<p><code><br />
tell application "System Events"<br />
  start current screen saver<br />
end tell<br />
</code></p>
<p>So you can simply create an Automator &#8220;Service&#8221; workflow and add a &#8220;Run AppleScript&#8221; action with the following code snippet.</p>
<p><code><br />
on run {input, parameters}</p>
<p>  tell app "System Events"<br />
    start current screen saver<br />
  end tell</p>
<p>  return input<br />
end run<br />
</code></p>
<p>Save it, and assign a hot key, and you can finally activate the screensaver from the keyboard.</p>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2009/11/25/finally-a-sanctioned-way-of-activating-the-screen-saver/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Apple have documented the binary plist format</title>
		<link>http://explanatorygap.net/2009/10/30/apple-have-documented-the-binary-plist-format/</link>
		<comments>http://explanatorygap.net/2009/10/30/apple-have-documented-the-binary-plist-format/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 20:00:54 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[macosx]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=236</guid>
		<description><![CDATA[Thanks to Dave Dribin for pointing this out. In http://opensource.apple.com/source/CF/CF-550/CFBinaryPList.c So really there&#8217;s no reason why we can&#8217;t have plistlib etc for Ruby/Python/whatever deal with binary plists on non-Mac platforms. /* HEADER &#160; &#160; magic number (&#34;bplist&#34;) &#160; &#160; file format version OBJECT TABLE &#160; &#160; variable-sized objects &#160; &#160; Object Formats (marker byte followed [...]]]></description>
				<content:encoded><![CDATA[<p>Thanks to <a href="http://www.dribin.org/dave/">Dave Dribin</a> for pointing this out.</p>
<p>In <a href="http://opensource.apple.com/source/CF/CF-550/CFBinaryPList.c">http://opensource.apple.com/source/CF/CF-550/CFBinaryPList.c</a></p>
<p>So really there&#8217;s no reason why we can&#8217;t have plistlib etc for Ruby/Python/whatever deal with binary plists on non-Mac platforms.</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="coMULTI">/*<br />
HEADER<br />
&nbsp; &nbsp; magic number (&quot;bplist&quot;)<br />
&nbsp; &nbsp; file format version</p>
<p>OBJECT TABLE<br />
&nbsp; &nbsp; variable-sized objects</p>
<p>&nbsp; &nbsp; Object Formats (marker byte followed by additional info in some cases)<br />
&nbsp; &nbsp; null&nbsp; &nbsp; 0000 0000<br />
&nbsp; &nbsp; bool&nbsp; &nbsp; 0000 1000&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // false<br />
&nbsp; &nbsp; bool&nbsp; &nbsp; 0000 1001&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // true<br />
&nbsp; &nbsp; fill&nbsp; &nbsp; 0000 1111&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // fill byte<br />
&nbsp; &nbsp; int&nbsp;0001 nnnn&nbsp; &nbsp;&#8230;&nbsp;&nbsp; &nbsp; // # of bytes is 2^nnnn, big-endian bytes<br />
&nbsp; &nbsp; real&nbsp; &nbsp; 0010 nnnn&nbsp; &nbsp;&#8230;&nbsp;&nbsp; &nbsp; // # of bytes is 2^nnnn, big-endian bytes<br />
&nbsp; &nbsp; date&nbsp; &nbsp; 0011 0011&nbsp; &nbsp;&#8230;&nbsp;&nbsp; &nbsp; // 8 byte float follows, big-endian bytes<br />
&nbsp; &nbsp; data&nbsp; &nbsp; 0100 nnnn&nbsp; &nbsp;[int]&nbsp; &nbsp;&#8230;&nbsp;// nnnn is number of bytes unless 1111 then int count follows, followed by bytes<br />
&nbsp; &nbsp; string&nbsp; 0101 nnnn&nbsp; &nbsp;[int]&nbsp; &nbsp;&#8230;&nbsp;// ASCII string, nnnn is # of chars, else 1111 then int count, then bytes<br />
&nbsp; &nbsp; string&nbsp; 0110 nnnn&nbsp; &nbsp;[int]&nbsp; &nbsp;&#8230;&nbsp;// Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t<br />
&nbsp; &nbsp; &nbsp; &nbsp; 0111 xxxx&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // unused<br />
&nbsp; &nbsp; uid&nbsp;1000 nnnn&nbsp; &nbsp;&#8230;&nbsp;&nbsp; &nbsp; // nnnn+1 is # of bytes<br />
&nbsp; &nbsp; &nbsp; &nbsp; 1001 xxxx&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // unused<br />
&nbsp; &nbsp; array&nbsp; &nbsp;1010 nnnn&nbsp; &nbsp;[int]&nbsp; &nbsp;objref*&nbsp;// nnnn is count, unless &#8217;1111&#8242;, then int count follows<br />
&nbsp; &nbsp; &nbsp; &nbsp; 1011 xxxx&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // unused<br />
&nbsp; &nbsp; set&nbsp;1100 nnnn&nbsp; &nbsp;[int]&nbsp; &nbsp;objref* // nnnn is count, unless &#8217;1111&#8242;, then int count follows<br />
&nbsp; &nbsp; dict&nbsp; &nbsp; 1101 nnnn&nbsp; &nbsp;[int]&nbsp; &nbsp;keyref* objref*&nbsp;// nnnn is count, unless &#8217;1111&#8242;, then int count follows<br />
&nbsp; &nbsp; &nbsp; &nbsp; 1110 xxxx&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // unused<br />
&nbsp; &nbsp; &nbsp; &nbsp; 1111 xxxx&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // unused</p>
<p>OFFSET TABLE<br />
&nbsp; &nbsp; list of ints, byte size of which is given in trailer<br />
&nbsp; &nbsp; &#8212; these are the byte offsets into the file<br />
&nbsp; &nbsp; &#8212; number of these is in the trailer</p>
<p>TRAILER<br />
&nbsp; &nbsp; byte size of offset ints in offset table<br />
&nbsp; &nbsp; byte size of object refs in arrays and dicts<br />
&nbsp; &nbsp; number of offsets in offset table (also is number of objects)<br />
&nbsp; &nbsp; element # in offset table which is top level object<br />
&nbsp; &nbsp; offset table offset</p>
<p>*/</span><br />
&nbsp;</div>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2009/10/30/apple-have-documented-the-binary-plist-format/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Puppet 0.25.1 debs done&#8230; but delayed.</title>
		<link>http://explanatorygap.net/2009/10/29/puppet-0-25-1-debs-done-but-delayed/</link>
		<comments>http://explanatorygap.net/2009/10/29/puppet-0-25-1-debs-done-but-delayed/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 14:48:34 +0000</pubDate>
		<dc:creator>nigel kersten</dc:creator>
				<category><![CDATA[puppet]]></category>

		<guid isPermaLink="false">http://explanatorygap.net/?p=233</guid>
		<description><![CDATA[We&#8217;ve uploaded the 0.25.1 debs, but due to this work, it might take a little while before they appear. http://blog.ganneff.de/blog/2009/10/27/debian-ftpmaster-meeting.html It will appear here when done. http://packages.debian.org/sid/puppet Instructions for building yourself&#8230;. $ git clone git://git.debian.org/pkg-puppet/puppet.git $ cd puppet $ git-buildpackage --git-upstream-branch=origin/upstream]]></description>
				<content:encoded><![CDATA[<p>We&#8217;ve uploaded the 0.25.1 debs, but due to this work, it might take a little while before they appear.<br />
<a href="http://blog.ganneff.de/blog/2009/10/27/debian-ftpmaster-meeting.html">http://blog.ganneff.de/blog/2009/10/27/debian-ftpmaster-meeting.html</a></p>
<p>It will appear here when done.<br />
<a href="http://packages.debian.org/sid/puppet">http://packages.debian.org/sid/puppet</a></p>
<p>Instructions for building yourself&#8230;.</p>
<p><code>$ git clone git://git.debian.org/pkg-puppet/puppet.git<br />
$ cd puppet<br />
$ git-buildpackage --git-upstream-branch=origin/upstream<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://explanatorygap.net/2009/10/29/puppet-0-25-1-debs-done-but-delayed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 1.047 seconds -->
<!-- Cached page served by WP-Cache -->
