<?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>Puppet Labs &#187; Blog</title>
	<atom:link href="http://puppetlabs.com/category/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://puppetlabs.com</link>
	<description>Puppet Labs: IT Automation Software for System Administrators</description>
	<lastBuildDate>Wed, 23 May 2012 21:49:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Module of the Week: puppetlabs/razor &#8211; Razor Provisioning Application</title>
		<link>http://puppetlabs.com/blog/puppet-razor-module/</link>
		<comments>http://puppetlabs.com/blog/puppet-razor-module/#comments</comments>
		<pubDate>Wed, 23 May 2012 16:01:23 +0000</pubDate>
		<dc:creator>Nan Liu</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[General News]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[Module of the Week]]></category>
		<category><![CDATA[Modules]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Provisioning]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[bare metal]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[EMC]]></category>
		<category><![CDATA[how to]]></category>
		<category><![CDATA[module of the week]]></category>
		<category><![CDATA[modules]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[provisioning]]></category>
		<category><![CDATA[puppet labs]]></category>
		<category><![CDATA[Razor]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=14441</guid>
		<description><![CDATA[Purpose Razor Provisioning Software Module puppetlabs/razor Puppet Version 2.7+ Platforms Ubuntu Precise Razor is next generation provisioning software that handles bare metal hardware and virtual server provisioning with inventory discovery and tagging, rule-based policy management, and extensible broker plugin integration. The usage of Razor for provisioning is discussed briefly in this blog, and additional information [...]]]></description>
			<content:encoded><![CDATA[<table class="minimalist-table" width="664">
<tbody>
<tr>
<td><strong>Purpose</strong></td>
<td>Razor Provisioning Software</td>
</tr>
<tr>
<td><strong>Module</strong></td>
<td><a href="http://forge.puppetlabs.com/puppetlabs/razor">puppetlabs/razor</a></td>
</tr>
<tr>
<td><strong>Puppet Version</strong></td>
<td>2.7+</td>
</tr>
<tr>
<td><strong>Platforms</strong></td>
<td>Ubuntu Precise</td>
</tr>
</tbody>
</table>
<p>Razor is next generation provisioning software that handles bare metal hardware and virtual server provisioning with inventory discovery and tagging, rule-based policy management, and extensible broker plugin integration. The usage of Razor for provisioning is discussed briefly in this blog, and additional information is available on a separate <a href="http://nickapedia.com/2012/05/21/lex-parsimoniae-cloud-provisioning-with-a-razor">post</a> by Nick Weaver, one of authors of the Razor project. Broker handoffs will be discussed in a follow up article.</p>
<p>Razor is currently released as a beta for preview, so there are no installation packages yet. The Razor module is intended to simplify the process for installing Razor, since it handles all application dependencies, and clones the Razor repo from GitHub.</p>
<p>The module is limited to Ubuntu Precise due to the availability of nodejs packages. In Debian, these packages are available in sid, so install this module only if you are comfortable adding the unstable repo. Razor puppet module support for other platforms will be evaluated as we continue to develop Razor (this is not the same as node provisioning platforms which includes Debian, Ubuntu, RedHat, OpenSuSE, and VMware ESX).</p>
<h2>Installing the module</h2>
<table class="minimalist-table" width="664">
<tbody>
<tr>
<td><strong>Complexity</strong></td>
<td>Easy</td>
</tr>
<tr>
<td><strong>Installation Time</strong></td>
<td>5 minutes</td>
</tr>
</tbody>
</table>
<p>On puppet 2.7.14 an PE 2.5, puppet module tool will automatically download and install all dependencies from forge.</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ puppet module install puppetlabs-razor
Preparing to install into /etc/puppet/modules ...
Downloading from http://forge.puppetlabs.com ...
Installing -- do not interrupt ...
/etc/puppet/modules
└─┬ puppetlabs-razor <span class="br0">&#40;</span>v0.1.0<span class="br0">&#41;</span>
├─┬ puppetlabs-mongodb <span class="br0">&#40;</span>v0.0.1<span class="br0">&#41;</span>
│ └── puppetlabs-apt <span class="br0">&#40;</span>v0.0.3<span class="br0">&#41;</span>
├── puppetlabs-nodejs <span class="br0">&#40;</span>v0.2.0<span class="br0">&#41;</span>
├── puppetlabs-stdlib <span class="br0">&#40;</span>v2.3.2<span class="br0">&#41;</span>
├── puppetlabs-tftp <span class="br0">&#40;</span>v0.1.0<span class="br0">&#41;</span>
├── puppetlabs-vcsrepo <span class="br0">&#40;</span>v0.0.4<span class="br0">&#41;</span>
└── saz-sudo <span class="br0">&#40;</span>v2.0.0<span class="br0">&#41;</span></pre></div></div>

<p>Once all the modules have been installed, the appropriate permission should be applied to the files under the modules folder:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ chown -R puppet:puppet /etc/puppet/modules</pre></div></div>

<h2>Configuring the module</h2>
<table class="minimalist-table" width="664">
<tbody>
<tr>
<td><strong>Complexity</strong></td>
<td>Easy</td>
</tr>
<tr>
<td><strong>Installation Time</strong></td>
<td>5 minutes</td>
</tr>
</tbody>
</table>
<p>The puppetlabs/razor module does not deploy DHCP service. The DHCP server needs to specify the initial boot file as pxelinux.0 and next-server option should direct traffic to the tftp server.If you currently don’t have DHCP service in your environment, and have control over your network environment, the <a>puppetlabs/dhcp</a> module will deploy dhcp services.</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">class <span class="br0">&#123;</span> 'dhcp':
  dnsdomain   =&gt; <span class="br0">&#91;</span>
                   'puppetlabs.lan,
                   '1.0.10.in-addr.arpa',
                 <span class="br0">&#93;</span>,
  nameservers =&gt; <span class="br0">&#91;</span>'10.0.1.20'<span class="br0">&#93;</span>,
  ntpservers  =&gt; <span class="br0">&#91;</span>'us.pool.ntp.org'<span class="br0">&#93;</span>,
  interfaces  =&gt; <span class="br0">&#91;</span>'eth0'<span class="br0">&#93;</span>,
  pxeserver   =&gt; '10.0.1.50',
  pxefilename =&gt; 'pxelinux.0',
<span class="br0">&#125;</span></pre></div></div>

<p>If you want to test Razor on your local system in a virtual environment such as VMware Fusion 4, simply add the following lines into /Library/Preferences/VMware Fusion/vmnet8/dhcpd.conf the appropriate DHCP subnet and substitute $tftp_server_address with the Razor VM node ipaddress:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">filename &quot;pxelinux.0&quot;;
next-server $<span class="br0">&#123;</span>tftp_server_ipaddress<span class="br0">&#125;</span>;</pre></div></div>

<p>At the moment, the tftp service and razor service will be deployed to the same system. On the puppet master assign the razor class to the appropriate node, and trigger a puppet agent run afterwards:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">node razor_host <span class="br0">&#123;</span>
  class <span class="br0">&#123;</span> 'razor':
    username  =&gt; 'razor',
    directory =&gt; '/opt/razor',
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Razor can also be deployed directly to the system with the modules installed via:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">puppet apply /etc/puppet/modules/razor/tests/init.pp --verbose</pre></div></div>

<p>At this point, login to the Razor installation directory and execute Razor to confirm the application is installed successfully:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ razor
ProjectRazor - v0.1.6.0
&nbsp;
	Usage:
	project_razor <span class="br0">&#91;</span>slice name<span class="br0">&#93;</span> <span class="br0">&#91;</span>command argument<span class="br0">&#93;</span> <span class="br0">&#91;</span>command argument<span class="br0">&#93;</span>...
	 Switches:
		 --debug        : Enables printing proper Ruby stacktrace
		 --verbose      : Enables verbose object printing
		 --no-color-out : Disables console color. Useful for script wrapping.
&nbsp;
Loaded slices:
	<span class="br0">&#91;</span>bmc<span class="br0">&#93;</span> <span class="br0">&#91;</span>broker<span class="br0">&#93;</span> <span class="br0">&#91;</span>image<span class="br0">&#93;</span> <span class="br0">&#91;</span>log<span class="br0">&#93;</span> <span class="br0">&#91;</span>model<span class="br0">&#93;</span> <span class="br0">&#91;</span>node<span class="br0">&#93;</span>
	<span class="br0">&#91;</span>policy<span class="br0">&#93;</span> <span class="br0">&#91;</span>tag<span class="br0">&#93;</span></pre></div></div>

<h2>Example usage</h2>
<p>The example below will show the minimal steps from the end of Razor installation to provisioning an Ubuntu Precise system. We will focus on the process of getting a new system provisioned with Ubuntu.</p>
<p>Razor needs a micro kernel (MK) image upon initial pxeboot to detect hardware information and register systems to the inventory of nodes. The MK image is available on GitHub, and it should be loaded into razor image service first:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ wget https://github.com/downloads/puppetlabs/Razor/rz_mk_dev-image.0.8.8.0.iso
$ razor image add mk ./rz_mk_dev-image.0.8.8.0.iso
Attempting to add, please wait...
New image added successfully
Images:
	UUID: 1nnkuB5BiH1C93HOO0PTFi
	Type: MicroKernel Image
	ISO Filename: rz_mk_dev-image.0.8.8.0.iso
	Path: /mnt/nfs/Razor/image/mk/1nnkuB5BiH1C93HOO0PTFi
	Status: Valid
	Version: 0.8.9.0
	Build Time: <span style="">2012</span>-05-09 <span style="">13</span>:<span style="">11</span>:01 -0700</pre></div></div>

<p>Once the razor MK images is loaded into Razor, new system connected to the network performing network boot will obtain a dhcp address, boot the microkernel and register with Razor. We can get a list of systems discovered via this process via the Razor node:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ razor node
Discovered Nodes
         UUID           Last Checkin                  Tags
5PfILygjPv4WTayOnTOYMk  <span style="">32</span> seconds     <span class="br0">&#91;</span>cpus_1,memsize_4GiB,nics_1,vmware_vm<span class="br0">&#93;</span>
26k3If4FI7HpsZIn7N7BXu  <span style="">45</span> seconds     <span class="br0">&#91;</span>cpus_2,memsize_16GiB,nics_2,vmware_vm<span class="br0">&#93;</span>
66XZwZUJOpRXosg5SHHdbW  <span style="">7</span> seconds      <span class="br0">&#91;</span>cpus_4,memsize_96GiB,nics_4,physical<span class="br0">&#93;</span></pre></div></div>

<p>Attributes regarding specific nodes can be drilled down into further details by specifying its UUID:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ razor node attrib 5PfILygjPv4WTayOnTOYMk
Node Attributes:
          	Name                        Value
	architecture              i386
	domain                    localdomain
	fqdn                      mk000C294F881F.localdomain
	hardwareisa               unknown
	hardwaremodel             i686
	hostname                  mk000C294F881F
...</pre></div></div>

<p>To provision a node, an Ubuntu Precise ISO should also be loaded along with a model which associates an instance of model template configuration with a specific ISO image:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ razor image add os ../ubuntu-<span style="">12.04</span>-server-amd64.iso ubuntu_precise <span style="">12.04</span>
Attempting to add, please wait...
New image added successfully
Images:
	UUID: 274HnNlQF5jvbo0y6U0aok
	Type: OS Install
	ISO Filename: ubuntu-<span style="">12.04</span>-server-amd64.iso
	Path: /mnt/nfs/Razor/image/os/274HnNlQF5jvbo0y6U0aok
	Status: Valid
	OS Name: ubuntu_precise
	OS Version: <span style="">12.04</span></pre></div></div>

<p>Once the MK and operating system images are loaded into razor, we can create a deployment model using that image. First, list the available model templates:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ razor model get template
Model Templates:
Template Name         Description         
centos_6        CentOS <span style="">6</span> Model            
debian_wheezy   Debian Wheezy Model       
opensuse_12     OpenSuSE Suse <span style="">12</span> Model    
ubuntu_oneiric  Ubuntu Oneiric Model      
ubuntu_precise  Ubuntu Precise Model      
vmware_esxi_5   VMware ESXi <span style="">5</span> Deployment</pre></div></div>

<p>Next, select the ubuntu_precise template along with the iso_uuid generated when the ISO was loaded into Razor. This will trigger a series of configuration questions applicable for the Precise model template:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ razor model add template=ubuntu_precise label=install_precise image_uuid=274HnNlQF5jvbo0y6U0aok
--- Building Model <span class="br0">&#40;</span>ubuntu_precise<span class="br0">&#41;</span>:
Please enter node hostname prefix <span class="br0">&#40;</span>will append node number<span class="br0">&#41;</span> <span class="br0">&#40;</span>example: node<span class="br0">&#41;</span>
default: node
<span class="br0">&#40;</span>QUIT to cancel<span class="br0">&#41;</span>
&gt; ubuntu
Please enter root password <span class="br0">&#40;</span>&gt; <span style="">8</span> characters<span class="br0">&#41;</span> <span class="br0">&#40;</span>example: P@ssword!<span class="br0">&#41;</span>
default: test1234
<span class="br0">&#40;</span>QUIT to cancel<span class="br0">&#41;</span>
&gt; testEnvPass!
Model created
Label =&gt;  install_precise
Template =&gt;  linux_deploy
Description =&gt;  Ubuntu Precise Model
UUID =&gt;  3LCN86Cpx0Te3Of5WbORkQ
Image UUID =&gt;  274HnNlQF5jvbo0y6U0aok</pre></div></div>

<p>The newly created model contains the hostname (which will be appended with node number), root password, and the ISO for deployment. We can certainly perform more customization within the preseed file, but in most cases this process is deferred to Puppet via broker plugin which will configure the target puppet master to handoff the node for management. At this point we can deploy this operating system, and based on our initial hardware inventory we will target nodes with 4GB of memory that are VMware virtual systems.</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ razor policy add template=linux_deploy label=precise model_uuid=3LCN86Cpx0Te3Of5WbORkQ broker_uuid=none tags=memsize_4GiB,vmware_vm enabled=true
Policy created
UUID =&gt;  41o1z77j2R4ZsgjD9KTpPe
Line Number =&gt;  <span style="">2</span>
Label =&gt;  precise
Enabled =&gt;  true
Template =&gt;  linux_deploy
Description =&gt;  Policy for deploying a Linux-based operating system.
Tags =&gt;  <span class="br0">&#91;</span>vmware_vm<span class="br0">&#93;</span>
Model Label =&gt;  install_precise
Broker Target =&gt;  none
Bound Count =&gt;  <span style="">0</span></pre></div></div>

<p>At this point we review our policy rules and based on razor node output we expect one system that matches the tag requirements to deploy Precise.</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">$ razor policy
Policies
#  Enabled     Label         Tags              Label          Count           UUID
<span style="">0</span>  true     precise  <span class="br0">&#91;</span>memsize_4GiB,vmware_vm<span class="br0">&#93;</span>  install_precise  <span style="">0</span>      41o1z77j2R4ZsgjD9KTpPe</pre></div></div>

<p>In the future, other systems that match this policy rule will also deploy Precise. Once the appropriate nodes install Precise, we can either remove this policy completely via ‘policy remove &lt;uuid&gt;’ or temporarily disable it via ‘policy disable &lt;uuid&gt;’.</p>
<h2>Conclusion</h2>
<p>The Razor puppet module provides a quick and easy way to install Razor for testing. The module could benefit from additional puppet class parameters for razor::nodejs and razor::tftp that separates those components especially when tftp can be installed on a separate system. There are also manual processes in Razor such as loading ISO’s that could benefit from a Puppet type/provider. We certainly welcome recommendations for additional Razor service deployment platform, and contributions from our community for enhancements to this module and its dependencies.</p>
<p><em>Learn More:</em></p>
<ul>
<li><a href="http://puppetlabs.com/blog/introducing-razor-a-next-generation-provisioning-solution/">Introducing Razor, a Next-Generation Provisioning Solution</a></li>
<li><a href="http://nickapedia.com/2012/05/21/lex-parsimoniae-cloud-provisioning-with-a-razor">Lex Parsimoniae : Cloud Provisioning with a Razor</a></li>
<li><a href="http://forge.puppetlabs.com/puppetlabs/razor">puppetlabs/razor</a></li>
<li><a href="http://puppetlabs.com/resources/webinars/">Join the Razor webinar</a></li>
<li>Participate in the <a href="http://puppetlabs.com/blog/open-source-twitter-chat-on-may-28th-puppetize/">Razor Twitter chat</a> at #puppetize – 2012-05-28 18:00 UTC</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/puppet-razor-module/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Introducing Razor, A Next-Generation Provisioning Solution</title>
		<link>http://puppetlabs.com/blog/introducing-razor-a-next-generation-provisioning-solution/</link>
		<comments>http://puppetlabs.com/blog/introducing-razor-a-next-generation-provisioning-solution/#comments</comments>
		<pubDate>Wed, 23 May 2012 13:16:02 +0000</pubDate>
		<dc:creator>Nan Liu</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[EMC]]></category>
		<category><![CDATA[IT automation]]></category>
		<category><![CDATA[provisioning]]></category>
		<category><![CDATA[Razor]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=14368</guid>
		<description><![CDATA[Puppet Labs is really excited to introduce Razor, a next-generation hardware provisioning solution developed collaboratively with our friends at EMC. I&#8217;ll be diving into details about specific Razor features in a series of blog posts, which includes installation via a Puppet module, but in this post I&#8217;ll focus on a high level overview of Razor&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>Puppet Labs is really excited to introduce Razor, a next-generation hardware provisioning solution developed collaboratively with our friends at EMC.  I&#8217;ll be diving into details about specific Razor features in a series of blog posts, which includes installation via a Puppet module, but in this post I&#8217;ll focus on a high level overview of Razor&#8217;s features and the problem it&#8217;s solving.</p>
<h2>Problems With Current Solutions</h2>
<p>EMC actually initiated Razor in response to challenges they were having internally with existing hardware provisioning technologies.  In building-up test and burn-in environments for their own software solutions, EMC found themselves bottlenecked by provisioning tools that were vendor-specific, monolithic, and closed.  Moreover, public and private clouds gave their Development &#038; QA teams infrastructure that responded nimbly and on-demand; why couldn’t their hardware infrastructure give them the same responsiveness and efficiencies?</p>
<p>To remedy, EMC first surveyed the landscape of provisioning technologies.  Given the importance of provisioning as the first, critical step in building compute infrastructure, surely someone had innovated a solution to these problems?  But nothing seemed to really address the needs of the system administrators responsible for infrastructure, so EMC set out to solve the problem themselves.</p>
<h2>Enter Puppet</h2>
<p>EMC was already very familiar with Puppet Labs and our products, and these served as an inspiration and foundation for Razor.  Specifically, the EMC team sought to bring Puppet’s declarative, model-based approach of configuring software to the provisioning of server hardware with an operating system.  In addition, Puppet Labs’ metadata-driven enterprise message bus and node inventory technologies, MCollective and Facter respectively, were critical enabling components for Razor.</p>
<p>Further considerations in selecting to partner with Puppet Labs were the pervasiveness of its open source technologies as well as its active and engaged community.  EMC’s Razor team recognized that existing provisioning technologies were handicapped by their tight association with a single vendor, and open sourcing Razor to an active community was the surest way to avoid a similar fate.</p>
<h2>Razor: Cloud Agility and Efficiency for Hardware Infrastructure</h2>
<p>OK, enough already … what’s different about Razor?</p>
<p>First, during boot the Razor client auto-discovers the inventory of the server hardware – CPUs, disk, memory, everything – and feeds this to the Razor server in real-time.  This means you always have the latest, most up-to-date information about every server in your data center, eliminating the need for manual inventory processes and tools.</p>
<p>Second, Razor knows the latest state of every server, and this state is updated with the auto-discovered inventory data.  Razor also maintains a set of rules to match the appropriate operating system images with server capabilities as expressed in metadata.  This match is made dynamically, so any change in the underlying hardware is automatically detected, reflected in the model, and can potentially result in the selection of a different operating system image – all automatically.</p>
<p>Third, Razor is integrated with Puppet for a seamless hand-off.  After Razor selects the operating system image it then automatically installs the Puppet agent and classifies the node.  Puppet picks up the ball and begins configuring the operating system, and so on up the stack.</p>
<p>Fourth, in contrast to other provisioning technologies Razor is open, pluggable, and programmable.  Hardware has a unique boot sequence? No problem, create a new model.  Want to change how operating system images are selected? Just update the rules via the Razor CLI.  Need to support a new OS?  Easy.  Razor is all about giving choice, agility, and automation to the system administrator so they can eliminate the repetitive and menial from their day.</p>
<p>What this all means is that now Razor and Puppet enable the system administrator to automate the entire infrastructure stack, from bare metal to fully deployed applications on the cloud.</p>
<h2>Check It Out</h2>
<p>Nigel Kersten, Puppet Labs’ CTO, will be on stage during Chad’s World at EMC World today at 5:30pm PDT to demo Razor, and we’re also in the EMC Innovation Center on the show floor.  Also, our friends from the EMC CTO’s Office – Dan Hushon, Chuck Hollis, Nick Weaver – have blog posts out today (<a href="http://www.vdatacloud.com/blogs/2012/05/23/project-razor-emc-and-puppet-labs/" target="_blank">here</a>, <a href="http://chucksblog.emc.com/chucks_blog/2012/05/of-puppet-and-razor.html" target="_blank">here</a>, and <a href="http://nickapedia.com/2012/05/21/lex-parsimoniae-cloud-provisioning-with-a-razor" target="_blank">here</a>, respectively) sharing the details of EMC’s work and perspective on Razor.</p>
<p>Razor is available for download now from the <a href="http://forge.puppetlabs.com/puppetlabs/razor" target="_blank">Puppet Forge</a>.  Check it out &#8211; we’re looking forward to your feedback.  And stay tuned for more Razor blog posts soon!</p>
<p>- Nan</p>
<h2>Learn More</h2>
<ul>
<li><b>Participate</b> in the Razor <a href="http://puppetlabs.com/blog/open-source-twitter-chat-on-may-28th-puppetize/">Twitter chat</a> at #puppetize &#8211; Mon May 28 11am PDT</li>
<li><b>Join</b> the <a href="http://puppetlabs.com/resources/webinars/">webinar</a> with EMC &#8211; Tue May 29 11am PDT</li>
<li><b>Download</b> Razor from the <a href="http://forge.puppetlabs.com/puppetlabs/razor" target="_blank">Puppet Forge</a></li>
<li><b>Read</b> the docs on <a href="https://github.com/puppetlabs/Razor/wiki" target="_blank">Github</a>
<li><b>Check-out</b> the official <a href="http://puppetlabs.com/company/news/press-releases/">press release</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/introducing-razor-a-next-generation-provisioning-solution/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>The Design Behind Puppet Sites</title>
		<link>http://puppetlabs.com/blog/the-design-behind-puppet-sites/</link>
		<comments>http://puppetlabs.com/blog/the-design-behind-puppet-sites/#comments</comments>
		<pubDate>Tue, 22 May 2012 20:29:45 +0000</pubDate>
		<dc:creator>Daniel Sauble</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[Company]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Extending Puppet]]></category>
		<category><![CDATA[General News]]></category>
		<category><![CDATA[Opinion and Interview]]></category>
		<category><![CDATA[Puppet Lore]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[User Experience]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[feedback]]></category>
		<category><![CDATA[puppet]]></category>
		<category><![CDATA[puppet sites]]></category>
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=14420</guid>
		<description><![CDATA[Design is an integral part of the way we build software at Puppet Labs. More specifically, we strive to answer a very simple question: what does the user need? This isn’t always an easy question to answer, but we’ve been happy with our success in doing so. User empathy is our conduit for user satisfaction. [...]]]></description>
			<content:encoded><![CDATA[<p>Design is an integral part of the way we build software at Puppet Labs. More specifically, we strive to answer a very simple question: what does the user need? This isn’t always an easy question to answer, but we’ve been happy with our success in doing so. User empathy is our conduit for user satisfaction.</p>
<p>In real-life terms, what does design at Puppet look like? Let me show you a project that just finished its initial design phase: Puppet Sites.</p>
<h2>What do users need?</h2>
<p>Puppet admins want to spend their time managing nodes that are under Puppet control. They <em>don’t</em> want to spend their time adding nodes to their deployments. On the contrary, their goal is to start managing new nodes as quickly as possible. We formalize this need in the following way:</p>
<p>As a Puppet admin <b>I want</b> to easily add new nodes to my deployment <b>so that</b> I can start managing them as quickly as possible.</p>
<h2>How do we we satisfy user needs?</h2>
<p>The current workflow for adding nodes to a deployment is as follows:</p>
<ol>
<li>Configure puppet.conf with the location of the master/CA</li>
<li>Perform an agent run on the node</li>
<li>Login to the CA</li>
<li>Sign the node’s certificate</li>
<li>Perform another agent run on the node</li>
</ol>
<p>The problem with the existing workflow is that it appears to have nothing to do with adding new nodes to a deployment and everything to do with signing certificates. There’s a disconnect between the workflow and the user need.</p>
<p>To fix this, we did three things:</p>
<ol>
<li>We introduced the concept of a site. A site is a service that owns the list of nodes in your deployment, the authentication mechanism for adding new nodes to your deployment, and the configuration of Puppet services in your deployment.</li>
<li>We changed the semantics of the workflow, so that it directly addresses the user need.</li>
<li>We eliminated the overhead of signing into the CA and manually signing node certificates. There are secure ways to do this that don’t involve user interaction over SSH.</li>
</ol>
<p>The workflow now resembles the following:</p>
<ol>
<li>Login to the site host</li>
<li>Generate a pre-shared key</li>
<li>Join a node to the site using the pre-shared key</li>
<li>Repeat step 3 for every node you want to add to the site</li>
</ol>
<p>We now have a workflow to fulfill the user’s goal. But notice that we’re still not talking about sites in technical terms. This workflow could apply equally well to a <a href="http://puppetlabs.com/blog/puppet-faces-what-the-heck-are-faces/">Puppet Face</a>, a REST API, or a Dashboard plugin.</p>
<h2>How do users interact with our workflows?</h2>
<p>It’s all well and good to produce a general workflow for addressing a user need, but eventually you have to tie it to a real user interface. For the initial release of Puppet Sites, we decided to focus on two user interfaces: a Puppet Face and a REST API.</p>
<p>A designer is nothing without regular interaction with customers. While designing user interaction, we stayed engaged with our internal operations and professional services teams. After several rounds of feedback, the design of the Puppet Face for the workflow given above resembles the following:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">node02$ <span style="color: #c20cb9; font-weight: bold;">ssh</span> admin<span style="color: #000000; font-weight: bold;">@</span>site02.domain.com
Last <span style="color: #c20cb9; font-weight: bold;">login</span>: Mon May  <span style="color: #000000;">7</span> <span style="color: #000000;">18</span>:<span style="color: #000000;">15</span>:<span style="color: #000000;">43</span> <span style="color: #000000;">2012</span>
site02$ <span style="color: #c20cb9; font-weight: bold;">mount</span> <span style="color: #000000; font-weight: bold;">/</span>media<span style="color: #000000; font-weight: bold;">/</span>usbdisk
site02$ puppet site generate key <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>media<span style="color: #000000; font-weight: bold;">/</span>usbdisk<span style="color: #000000; font-weight: bold;">/</span>site.key
site02$ <span style="color: #c20cb9; font-weight: bold;">umount</span> <span style="color: #000000; font-weight: bold;">/</span>media<span style="color: #000000; font-weight: bold;">/</span>usbdisk
site02$ <span style="color: #7a0874; font-weight: bold;">exit</span>
node02$ <span style="color: #c20cb9; font-weight: bold;">mount</span> <span style="color: #000000; font-weight: bold;">/</span>media<span style="color: #000000; font-weight: bold;">/</span>usbdisk
node02$ puppet node <span style="color: #c20cb9; font-weight: bold;">join</span> site02.domain.com <span style="color: #000000; font-weight: bold;">&lt;</span> <span style="color: #000000; font-weight: bold;">/</span>media<span style="color: #000000; font-weight: bold;">/</span>usbdisk<span style="color: #000000; font-weight: bold;">/</span>site.key
Trying to add node02.domain.com to the site at site02.domain.com...
 Use <span style="color: #000000; font-weight: bold;">`</span>puppet site status node02.domain.com<span style="color: #000000; font-weight: bold;">`</span> to confirm success
 To stop waiting <span style="color: #000000; font-weight: bold;">for</span> the <span style="color: #7a0874; font-weight: bold;">command</span> to <span style="color: #7a0874; font-weight: bold;">complete</span>, press Ctrl-C.
   The <span style="color: #7a0874; font-weight: bold;">command</span> will still <span style="color: #7a0874; font-weight: bold;">complete</span> <span style="color: #000000; font-weight: bold;">in</span> the background.
Added node02.domain.com to the site at site02.domain.com</pre></div></div>

<h2>What do users think?</h2>
<p>We strive to make our design process as agile as our engineering process. We specifically avoid a waterfall model, where the design is completed in an ivory tower, then handed over the wall for implementation. Instead, our designers sanity check their design with internal and external users, talk to architects and engineers to make sure they aren’t violating the laws of physics, and stay involved in the project until it ships, making course corrections as necessary.</p>
<p>The Puppet Sites project is still underway, but we’ve already discovered mistakes made early in the process, and corrected them. Each group of users has been vital to this iterative process.</p>
<p>Our internal users made us aware that omitting a pre-shared key system was a poor idea. By themselves, the two other fixes—changing semantics and introducing sites—weren’t sufficient to solve the user goal of “quickly” adding nodes to their deployments.</p>
<p>Our architects made us aware of a “law of physics” deal-breaker in the design, where users could have passed their pre-shared key as a flag to <tt style="font: 12px Courier New">puppet node join</tt>. This would have exposed the key to sniffer processes on the host machine, and represented an unacceptable security risk.</p>
<p>Our external users helped us realize that the concept of a “site” is foggy at best and they didn’t really understand the problem it was designed to solve. Also, they were concerned that we were deprecating existing functionality without providing a drop-in replacement. We’ve been working to ameliorate these concerns by formulating clearer stories around the problems that sites solve.</p>
<h2>Design at Puppet Labs</h2>
<p>Of course, Puppet Sites does far more than just provide admins with an easy way to add new nodes to their deployments. For the sake of brevity, I’ve only highlighted this one user story. However, having a site also helps Puppet admins who want to&#8230;</p>
<ul>
<li>&#8230;get a list of all the nodes in their deployment with a single command, so they don’t have to trawl multiple services to get this information.</li>
<li>&#8230;centrally manage the configuration of all nodes in their deployments, so they don’t have to manually manage puppet.conf on each node.</li>
<li>&#8230;access information about Puppet services from their manifests, so they don’t have to hardcode the location of their services into their manifests.</li>
</ul>
<p>You can expect Puppet Sites to be available soon, as a point release for Puppet 3.0.</p>
<p>In summary, the UX team at Puppet produces three main artifacts: user stories, workflows, and wireframes.</p>
<ul>
<li>User stories allow us to talk about the needs of our users in a non-technical, goal-oriented way.</li>
<li>Workflows describe the tasks users go through to achieve their goals.</li>
<li>Wireframes are mockups of the actual systems that users use to complete these tasks.</li>
</ul>
<p>Not all of our projects follow this process exactly, but, in general, the above holds true. User story to workflow to wireframe. Rinse and repeat as necessary. That’s how we do design at Puppet Labs.</p>
<p><em>Learn More</em></p>
<ul>
<li><a href="http://puppetlabs.com/blog/what-is-user-experience-in-puppet/">What is User Experience in Puppet?</a></li>
<li><a href="http://puppetlabs.com/blog/looking-forward-to-2012-design-big-data-in-the-infrastructure-and-devops/">Looking Forward to 2012: Design, Big Data in the Infrastructure, and DevOps</a></li>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/the-design-behind-puppet-sites/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Open Source Twitter Chat on May 28th: #Puppetize</title>
		<link>http://puppetlabs.com/blog/open-source-twitter-chat-on-may-28th-puppetize/</link>
		<comments>http://puppetlabs.com/blog/open-source-twitter-chat-on-may-28th-puppetize/#comments</comments>
		<pubDate>Mon, 21 May 2012 22:21:56 +0000</pubDate>
		<dc:creator>michelle</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Extending Puppet]]></category>
		<category><![CDATA[General News]]></category>
		<category><![CDATA[MCollective]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[mcollective]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[puppet]]></category>
		<category><![CDATA[PuppetDB]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=14352</guid>
		<description><![CDATA[We’ve had a lot of open source goodness this month, and we want to talk about it and get your feedback. We’re hosting an hour-long Twitter chat on May 28 at 11 am PDT to answer your questions and converse about new releases like PuppetDB, MCollective 2.0, Puppet 3.0 (currently in RC), and more. We’ll [...]]]></description>
			<content:encoded><![CDATA[<p>We’ve had a lot of open source goodness this month, and we want to talk about it and get your feedback. We’re hosting an hour-long Twitter chat on May 28 at 11 am PDT to answer your questions and converse about new releases like PuppetDB, MCollective 2.0, Puppet 3.0 (currently in RC), and more.</p>
<p>We’ll have Michael Stahnke, our community manager; Deepak Giridharagopal, major developer of PuppetDB; R.I. Pienaar, author of MCollective; and Nan Liu, integration specialist, ready to respond and converse on Twitter.</p>
<p>Just tag your tweets and questions with #puppetize to join the conversation, and we’ll tag our responses. If you want to follow what’s going on, just track #puppetize for the full stream. To get an idea of what this is like, check out a snippet of the last Twitter chat we had:</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/puppetizetwitterchat1.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/puppetizetwitterchat1.png" alt="" title="puppetizetwitterchat1" width="563" height="856" class="aligncenter size-full wp-image-14353" /></a></p>
<p>We look forward to talking with you on 2012-05-28 18:00 UTC!</p>
<p><em>Learn More:</em></p>
<ul>
<li><a href="http://puppetlabs.com/blog/introducing-puppetdb-put-your-data-to-work/">Introducing PuppetDB</li>
<li><a href="http://puppetlabs.com/blog/announcing-the-marionette-collective-2-0/">Announcing the Marionette Collective 2.0</li>
<li><a href="https://twitter.com/#!/puppetlabs">Puppet Labs on Twitter</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/open-source-twitter-chat-on-may-28th-puppetize/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Module of the Week: pdxcat/amanda &#8211; Advanced Network Backup</title>
		<link>http://puppetlabs.com/blog/module-of-the-week-pdxcat-amanda-advanced-network-backup/</link>
		<comments>http://puppetlabs.com/blog/module-of-the-week-pdxcat-amanda-advanced-network-backup/#comments</comments>
		<pubDate>Sat, 19 May 2012 17:36:36 +0000</pubDate>
		<dc:creator>Reid Vandewiele</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Extending Puppet]]></category>
		<category><![CDATA[guest post]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[Module of the Week]]></category>
		<category><![CDATA[Modules]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Systems Management]]></category>
		<category><![CDATA[Configuration Management]]></category>
		<category><![CDATA[module of the week]]></category>
		<category><![CDATA[modules]]></category>
		<category><![CDATA[pdxcat]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[systems management]]></category>
		<category><![CDATA[testing modules]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=14299</guid>
		<description><![CDATA[The following is a guest post by Reid Vandewiele, a system administrator at the Portland State University Computer Action Team (PDX CAT). Reid, William Van Hevelingen, Spencer Krum and other CATs are big contributors to various modules on the Puppet Forge and also host a few of their own. They are active members of the [...]]]></description>
			<content:encoded><![CDATA[<p><em>The following is a guest post by Reid Vandewiele, a system administrator at the Portland State University Computer Action Team (PDX CAT). Reid, William Van Hevelingen, Spencer Krum and other CATs are big contributors to various modules on the Puppet Forge and also <a href="http://forge.puppetlabs.com/pdxcat">host a few of their own</a>. They are active members of the Puppet community and can usually be found on IRC under the monikers marut, blkperl and nibalizer, respectively. Thanks guys for the awesome guest post!</em></p>
<table class="minimalist-table" width="664">
<tbody>
<tr>
<td><strong>Purpose</strong></td>
<td>Provides amanda server and client configuration</td>
</tr>
<tr>
<td><strong>Module</strong></td>
<td><a href="http://forge.puppetlabs.com/pdxcat/amanda">pdxcat/amanda</a></td>
</tr>
<tr>
<td><strong>Puppet Version</strong></td>
<td>2.7+</td>
</tr>
<tr>
<td><strong>Platforms</strong></td>
<td>Debian, Solaris, FreeBSD, SuSE</td>
</tr>
</tbody>
</table>
<p>The Advanced Maryland Automatic Network Disk Archiver, or <a href="http://www.amanda.org/">Amanda</a> for short, is a network backup solution in the same class as Bacula. Proponents tout its smart automatic planner, use of native tools to perform data dumps, ability to recover data from tape in the absence of the tool itself, and the available commercial support through <a href="http://www.zmanda.com/">Zmanda</a>. A venerable bastion of free and open source software, Amanda has been around since 1991 and is still actively maintained with the most recent stable version having been released on February 12, 2012.</p>
<p>Let’s Puppetize that!</p>
<p><span id="more-14299"></span></p>
<p>The pdxcat/amanda module was developed to handle the installation and basic configuration of the client and server components of the Amanda system in a heterogeneous computing environment. Besides the core classes, the module ships a couple of defined types to assist in setting up multi-server authentication. In the most basic configuration, however, it is only necessary to include amanda::server and/or amanda::client on a given node.</p>
<h2>Installing the module</h2>
<table class="minimalist-table" width="664">
<tbody>
<tr>
<td><strong>Complexity</strong></td>
<td>Easy</td>
</tr>
<tr>
<td><strong>Installation Time</strong></td>
<td>5 minutes</td>
</tr>
</tbody>
</table>
<p>The newest version of pdxcat/amanda can always be obtained from GitHub. That said, it’s a heck of a lot easier and faster to install it from the Puppet Forge. In this example I’ll be using three machines all running Ubuntu 12.04 “Precise” (please see the addendum for an important disclosure regarding the use of this version). This means that I won’t be able to demonstrate pdxcat/amanda on Solaris or FreeBSD, but that’s one of the beautiful aspects of Puppet for well-maintained modules: The steps I take to configure my Ubuntu machines using Puppet should translate directly to performing the same configuration on any supported platform. Now on to the Puppet Forge:</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_pmt.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_pmt.png" alt="" title="amanda_pmt" width="657" height="208" class="aligncenter size-full wp-image-14300" /></a></p>
<p>The Amanda software follows the traditional Unix philosophy of “do one thing and do it well,” letting appropriate pre-existing utilities dump data at the system level, and relying on either inetd or ssh for network transport. Amanda does not attempt to reinvent the wheel. The pdxcat/amanda Puppet module correspondingly utilizes and has a dependency on pdxcat/xinetd (a fork of ghoneycutt/xinetd) in addition to its dependency on the utility module ripienaar/concat.</p>
<p>The Puppet Module Tool (PMT) handled that minor bit of complexity for me. After issuing just one command I’m all ready to go.</p>
<p>Well, almost. I actually ran into snag with this setup that needs to be addressed but which due to the off-topic nature I’m disinclined to cover in detail.</p>
<p>Every time Ubuntu comes out with a new release I do this and every time I forget. It’s a Bad Idea (TM) to assume that less than three weeks after launch the newest bleeding-edge version of Ubuntu will “just work”. As it turns out, at the time of writing the stock Amanda packages that ship with Ubuntu 12.04 were broken. See <a href="https://bugs.launchpad.net/ubuntu/+source/amanda/+bug/932064">Bug 932064</a>. I’m sure it will be fixed soon, but in the meantime &#8211; and In order to finish this blog post &#8211; I was forced to backport Amanda packages from Quantal into my repo to test the module on 12.04 VMs. C&#8217;est la vie.</p>
<h2>Resource Overview</h2>
<p>The README provides a decent overview of the resources intended for the end user, but it doesn’t go into a lot of detail beyond the most basic usage and parameters. It introduces two classes and three defined types. To get at the gory details though, it’s necessary to open up the manifests themselves. I personally like to use GitHub for this when inspecting unfamiliar modules but as the PMT has just installed the files in /etc/puppet/modules, they’re only a few keystrokes away.</p>
<h3>Amanda::Server</h3>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_server.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_server.png" alt="" title="amanda_server" width="657" height="262" class="aligncenter size-full wp-image-14301" /></a></p>
<p>The server class exposes nine parameters to the user, none of which are required. This means that if I wanted to, I could literally issue `include amanda::server` to handle the software installation and take a pass on any additional functionality.</p>
<p>What additional functionality is available mostly has to do with installing one or more manually written Amanda configs &#8211; a term which in-context refers to a set of files and directories that together constitute all the information Amanda needs to perform backups. Most of the parameters are tied into this and will be addressed later in the configuring section.</p>
<p>The xinetd parameter is standalone, and boolean. When true, the pdxcat/xinetd module will be used to install the Amanda server-side services (amindexd, amidxtaped) in xinetd. False, and no xinetd services will be installed.</p>
<h3>Amanda::Client</h3>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_client.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_client.png" alt="" title="amanda_client" width="657" height="154" class="aligncenter size-full wp-image-14302" /></a></p>
<p>The client class is much simpler in comparison. This makes sense, since all native Amanda logic is located on the server and the client software usually serves only as a dumb data dumper. The interesting configuration in the client class has to do with setting up authentication to the remote Amanda server.</p>
<p>The remote_user parameter is used to tell the client what unix user the server will be running as (important because Amanda cares, part of the authentication determination), and the server parameter tells the client what backup server will be used. Like in the server class, the xinetd parameter tells the client whether or not to install xinetd services (amdump, in this case).</p>
<p>If more than one backup server/user is being used at a site, the amanda::amandahosts defined type can be used to specify that kind of additional information.</p>
<h3>Defined Types</h3>
<p>When the client and server classes aren’t precise enough, more manual configuration is possible using the defined types provided: amanda::amandahosts, amanda::config, and amanda::ssh_authorized_key. We won’t get into detail about them here. Suffice it to say that they provide a handy platform-agnostic way of tweaking Amanda nuts and bolts in a way that takes advantage of the module’s knowledge of platform quirks.</p>
<p>For those interested the defined types, the README file for the module contains examples and additional information. It’s certainly worth the extra foray into the code because as it turns out, outside of the (surprisingly gnarly) package installation, most pdxcat/amanda class logic is a wrapper for using these defines. The additional exploration will also expose why pdxcat/amanda declares a dependency on ripienaar/concat (Dun dun dun!).</p>
<p>(Spoiler: the .amandahosts file is managed with the concat pattern.)</p>
<h2>Testing the module</h2>
<p>The top-level view of the module is somewhat misleading when it comes to tests.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_tests.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_tests.png" alt="" title="amanda_tests" width="657" height="226" class="aligncenter size-full wp-image-14304" /></a></p>
<p>At first it appears that the module may contain both smoke tests and rspec tests, but as it turns out the existence of tests/ and spec/ directories is a false positive. The directories are empty in the 0.1.2 release.</p>
<p>Not to be daunted by so ephemeral a problem as missing tests, let’s forge bravely ahead to perform what sanity checking we can.  Syntax validation and style evaluation are two easy checks to run, as previous articles in this series have demonstrated. Note that while the Puppet syntax checker is included in core, the puppet-lint tool is not and to use it you’ll need to install the `puppet-lint` gem.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_lint.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_lint.png" alt="" title="amanda_lint" width="657" height="136" class="aligncenter size-full wp-image-14305" /></a></p>
<p>Pretty good! No syntax errors and no heinous violations of style. This is by no means to say that the code is perfect (or even necessarily good), but adherence to the recommendations set forth in the <a href="http://docs.puppetlabs.com/guides/style_guide.html">Puppet Labs Style Guide</a> says something meaningful about maintainability and potential community involvement. It suggests that the maintainers are up to date and in sync with the greater Puppet community &#8230;or alternatively that they are aware of puppet-lint and are suckers for perfect output. Whatever works. :-)</p>
<p>The absence of smoke tests is something that could be easily rectified. In fact, the module’s README file already has all the necessary code in it. Filling in the smoke tests for this module will almost literally be a cut-n-paste operation.</p>
<h2>Configuring the module</h2>
<table class="minimalist-table" width="664">
<tbody>
<tr>
<td>Complexity</td>
<td>Easy</td>
</tr>
<tr>
<td>Installation Time</td>
<td>5 minutes</td>
</tr>
</tbody>
</table>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_site.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_site.png" alt="" title="amanda_site" width="657" height="280" class="aligncenter size-full wp-image-14306" /></a></p>
<p>The client class seems pretty straight-forward and even intuitive, but there’s definitely something strange going on with the server. Luckily the <a href="https://github.com/pdxcat/puppet-module-amanda/blob/0.1.2/README.md">README</a> does a pretty good job of explaining what is going on.</p>
<p>The short version is that the configs_source parameter works kind of like a Puppet File source parameter “puppet:///” URI, but without the “puppet:///” part. That is, “modules/data/amanda” means the “files/amanda” directory out of the “data” module. Okay&#8230; Weird, but okay. Let’s just roll with it for a minute and see where this leads.</p>
<p>The “configs” parameter is an array of values that is intended to specify which Amanda configs are to be installed on the server. It is combined with the configs_source parameter to produce the name of a directory to effectively rsync from the puppet master to the agent. Here we are syncing all files and directories from the master’s $modulepath/data/files/amanda/daily and $modulepath/data/files/amanda/archive to the node’s /etc/amanda/daily and /etc/amanda/archive.</p>
<p>Besides configs and configs_source, there are a few more parameters that can be used to more finely define the behavior of that sync operation. Those parameters are:</p>
<ul>
<li>configs_directory &#8211; The basedir on the node to which the config directories will be synced</li>
<li>manage_configs_directory &#8211; Whether or not to declare a file resource to manage the configs_directory</li>
<li>owner &#8211; The owner to apply to all files synced as part of a config</li>
<li>group &#8211; The group to apply to all files synced as part of a config</li>
<li>file_mode &#8211; The mode to apply to all regular files synced as part of a config</li>
<li>directory_mode &#8211; The mode to apply to all directories synced as part of a config</li>
</ul>
<p>Under the hood config syncing is accomplished by using a custom function in the Amanda module to ferret out the list of files while the catalog is being compiled on the master. It was implemented this way largely to eliminate the need to enumerate all the files that make up an Amanda config, and from a purely functional perspective it works great. It seems a little out of sync with the feel of other puppet resources but I can’t think of a better way to do it yet and so I’m inclined to give it my blessing and move on to the test run.</p>
<h2>Example usage</h2>
<p>We’ve walked through the config. Now let’s see how it runs on our virtual Amanda server node.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_puppet_server.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_puppet_server.png" alt="" title="amanda_puppet_server" width="657" height="460" class="aligncenter size-full wp-image-14307" /></a></p>
<p>&#8230;Wait, what? The error message reads: “Unable to find referenced module ‘data’ at [...]”. Oh. Right, I just finished talking all about how the configs parameter and configs_source parameter works, but I didn’t actually set it all up. The Amanda module is letting me know in no uncertain terms that it’s not gonna happen until I do.</p>
<p>Setting aside for the moment the details of what an Amanda config looks like, I’ll just sketch out the “data” module that I told Amanda I would be using.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_data.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_data.png" alt="" title="amanda_data" width="657" height="118" class="aligncenter size-full wp-image-14308" /></a></p>
<p>Cool. Let’s roll the server again.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_server_apply.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_server_apply.png" alt="" title="amanda_server_apply" width="657" height="242" class="aligncenter size-full wp-image-14309" /></a></p>
<p>A wall of blue and green text (most of which is omitted here) scrolls by. As far as the Amanda module is concerned, the server is ready to go. Let’s do the same thing on the client.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_client_apply.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_client_apply.png" alt="" title="amanda_client_apply" width="653" height="219" class="aligncenter size-full wp-image-14310" /></a></p>
<p>Board is green. Stepping back for a moment, we should now have the following systems in place:</p>
<ul>
<li>puppet.local, on which we installed the pdxcat/amanda module and set up node definitions for server.local and client.local.</li>
<li>server.local, with an Amanda server set up and the mock “daily” and “archive” configs installed.</li>
<li>client.local, for which server.local should be able to perform a backup.</li>
</ul>
<p>It all looks pretty good, but I have to break the fourth wall and talk about Amanda again for a minute. In order to test and verify that this all works we need to actually have an Amanda config, and not just the empty directory sketch-up I did to get the catalog(s) to compile. At its simplest, an Amanda config needs to have an amanda.conf file and a disklist file. I’m going to install now the following contrived example.</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;"># File: amanda.conf
define tapetype &quot;vtape&quot; {
    length 64 mbytes
}
define changer &quot;vtapes&quot; {
  tpchanger &quot;chg-disk:/tmp&quot;
}
define dumptype &quot;default&quot; {
  program &quot;GNUTAR&quot;
  auth &quot;bsdtcp&quot;
}
dumpcycle 7 days
dumpuser &quot;backup&quot;
indexdir &quot;/var/tmp/amanda/index&quot;
infofile &quot;/etc/amanda/daily/curinfo&quot;
labelstr &quot;^V[0-9][0-9][0-9]$&quot;
logdir &quot;/etc/amanda/daily&quot;
mailto &quot;root@server.local&quot;
org &quot;pdxcat/amanda&quot;
runspercycle 1
runtapes 1
tapecycle 9
tapetype &quot;vtape&quot;
tpchanger &quot;vtapes&quot;
&nbsp;
# File: disklist
client.local /etc default</pre></div></div>

<p>What this config will do is backup the /etc directory of the client machine to “virtual tapes” in /tmp on the server. Brilliant, I know. Now to install the config, we just need to include the files in the “data” module, as specified in the Puppet configuration for server.local, which if you will recall was given the parameters</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">configs        =&gt; [ 'daily', 'archive' ],
configs_source =&gt; 'modules/data/amanda’,</pre></div></div>

<p>First, install the files in the “data” module on the puppetmaster.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_files.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_files.png" alt="" title="amanda_files" width="657" height="136" class="aligncenter size-full wp-image-14315" /></a></p>
<p>So, pausing for a moment: Why is it that we are specifying that the configs come from the “data” module? Why aren’t we installing them in the Amanda module instead?</p>
<p>The simple answer is we’re splitting things up like this because we can. The pdxcat/amanda module follows best practice in providing an interface that allows full utilization of the module without the need to modify any of the files and directories provided. Ideally, a reusable module can be thought of and used as a library. When writing a text munger in C, one calls library functions like read() and write(), but doesn’t typically patch their libc.so. Seperation of data and code is a common maintainability practice, and just as applicable to configuration management &#8211; especially once your Puppet installation starts getting big.</p>
<p>The “data” module used here represents a site-local module containing non-reusable data or code that is specific to our operation &#8211; data such as the amanda.conf and disklist files we just created. Using the configs_source parameter in the amanda::server class lets us cleanly tie together reusable function from the Amanda module and custom information from our own data module.</p>
<p>Enough talking. Let’s kick off a Puppet to run on the server to make this all more real.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_configs.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_configs.png" alt="" title="amanda_configs" width="657" height="316" class="aligncenter size-full wp-image-14320" /></a></p>
<p>Note that the two config files from the “data” module have been installed in /etc/amanda/daily by amanda::server.</p>
<p>For this demo, there’s a manual config-specific step necessary to make the virtual Amanda server pretend that it’s a real boy. Normally a backup server would have some hardware attached to it on which to store the backup data it receives from clients. Maybe a giant disk array, or a standalone tape robot&#8230; Something corporeal that is referenced in the config.</p>
<p>Recall from the config given previously that we have opted to use /tmp. Here follows an appropriate hack to initialize our “backup tapes”.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_labeling.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_labeling.png" alt="" title="amanda_labeling" width="657" height="280" class="aligncenter size-full wp-image-14321" /></a></p>
<p>And that’s it. We have an Amanda server on which Amanda was set up and the config installed by Puppet, and we have a client machine on which Amanda was installed and configured by Puppet to allow the server to perform backups. There was some manual setup necessary on the server to install “tapes” on which to save backup data, but we’re finally able to answer the important question “Does it work?” with a resounding “Yes!”</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_dump.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/amanda_dump.png" alt="" title="amanda_dump" width="657" height="406" class="aligncenter size-full wp-image-14322" /></a></p>
<p>The check command ran and returned without error. The amdump command ran and returned silently, in typical Unix fashion. Amanda sends the full report to the user specified in the config (in this case root) but I’ll spare you the gory details of the long and verbose output. Suffice it to say that the backup test was successful.</p>
<h2>Conclusion</h2>
<p>The pdxcat/amanda Puppet module provides a good head-start towards managing the Amanda backup solution. Writing the configs is still left up to the administrator, but installing and ensuring them once written is easy and fast. Much of the legwork on the server side can be handled by Puppet, and all of the client-side configuration is effectively automated. The notable client configuration that is missing (configuration which was not used in this demonstration) is the amanda-client.conf file, which could have been used to set up client-side restore operation defaults.</p>
<p>Looking through the module code it feels like there is a lot of complexity around installing the client/server packages, but at its core the functionality provided by the module is simple and focused.</p>
<p>What the module does:</p>
<ul>
<li>Install Amanda client and/or server packages</li>
<li>Configure the client(s) to allow the server to perform backups</li>
<li>Ensure config files written by an administrator are installed on the server</li>
<li>Support a variety of platforms</li>
</ul>
<ul>
<li>What the module doesn’t do:</li>
<li>Parameterize or build Amanda config files (server-side)</li>
<li>Manage the Amanda disklist or otherwise provide for puppet-integrated configuration of backup targets</li>
<li>Schedule the backup runs</li>
<li>Provide tests</li>
</ul>
<p>Of particular note is that testing the module at present requires some upfront knowledge of Amanda and the writing of a custom config. Well wait a second, we just did all that work, right? How about turning it into an all-in-one stand-alone smoke test for the Puppet module?</p>
<p>Writing this post has brought to light a couple of awesome ideas that would make the Amanda module even better, some of which wouldn’t even take all that much time to code. In no particular order, here’s the brainstorm list from the review:</p>
<ol>
<li>Smoke tests for the classes and defines</li>
<li>>Integrated smoke test for a server that includes setting up a contrived Amanda config</li>
<li>Rspec tests for the classes, defines, and functions</li>
<li>Allow management of amanda-client.conf through the amanda::client class</li>
<li>Provide a defined type to schedule backup runs for a specified config</li>
</ol>
<p>Since the first draft of this blog post was written, brainstorm item #1 has been added to the module on Github, a couple of bugs have been fixed, and the “demo” config that was written for this blog post has been turned into a working smoke test, completing brainstorm item #2. Fixing that item #2 is especially exciting as it significantly reduces the overhead for installing and testing the Amanda module (albeit with just a single VM), whittling it down to these five commands on Ubuntu:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;"># puppet module install pdxcat-amanda
# puppet apply /etc/puppet/modules/amanda/tests/demo.pp
# su - backup
$ amcheck demo
$ amdump demo</pre></div></div>

<p>The detailed results will be mailed to root@localhost. These changes are available in the at-the-time-of-writing newest pdxcat/amanda release from the Puppet Forge, pdxcat/amanda 0.1.3.</p>
<p>A solid set of core classes and a good collection of defined type tools already makes pdxcat/amanda well worth using for deploying Amanda with Puppet. There are certainly areas that could be improved, but all in all it’s a decent module for a potentially complicated application.</p>
<p><em>Learn More</em></p>
<ul>
<li><a href="https://github.com/pdxcat/puppet-module-amanda">PDXCat/Amanda GitHub Project</a></li>
<li><a href="http://docs.puppetlabs.com/guides/style_guide.html">Puppet Style Guide</a></li>
<li><a href="http://puppetlabs.com/blog/using-puppet-lint-to-save-yourself-from-style-faux-pas/">Puppet Lint</a></li>
<li><a href="http://puppetlabs.com/blog/the-problem-with-separating-data-from-puppet-code/">Puppet: Separating Data and Code Part 1</a>, <a href="http://puppetlabs.com/blog/first-look-installing-and-using-hiera/">Part 2</a></li>
<li><a href="http://puppetlabs.com/category/blog/module-of-the-week-blog/">Previous Modules of the Week</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/module-of-the-week-pdxcat-amanda-advanced-network-backup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing PuppetDB: Put Your Data to Work</title>
		<link>http://puppetlabs.com/blog/introducing-puppetdb-put-your-data-to-work/</link>
		<comments>http://puppetlabs.com/blog/introducing-puppetdb-put-your-data-to-work/#comments</comments>
		<pubDate>Fri, 18 May 2012 15:06:12 +0000</pubDate>
		<dc:creator>Nick Lewis</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Extending Puppet]]></category>
		<category><![CDATA[General News]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[product release]]></category>
		<category><![CDATA[Systems Management]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Configuration Management]]></category>
		<category><![CDATA[developer]]></category>
		<category><![CDATA[feedback]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[puppet labs]]></category>
		<category><![CDATA[PuppetDB]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=14255</guid>
		<description><![CDATA[PuppetDB is the next-generation open source storage service for Puppet-produced data. Today, this includes catalogs and facts, and will be extended in the near future. The initial release provides a drop-in replacement for both storeconfigs and inventory service. We’ve designed PuppetDB to empower Puppet deployments, and built it from the ground up with performance in [...]]]></description>
			<content:encoded><![CDATA[<p>PuppetDB is the next-generation open source storage service for Puppet-produced data. Today, this includes catalogs and facts, and will be extended in the near future. The initial release provides a drop-in replacement for both storeconfigs and inventory service.</p>
<p>We’ve designed PuppetDB to empower Puppet deployments, and built it from the ground up with performance in mind. It’s built on technologies known for their performance, and is highly parallel, making full use of available resources. It also stores all of its data asynchronously, freeing up the master to go compile more catalogs. Beyond that, we’ve devoted copious time to benchmarking and optimizing the performance.</p>
<h2>Why PuppetDB?</h2>
<p>The most immediate benefit of PuppetDB is improved performance for storeconfigs users, but even for others, it has a lot to offer. As a centralized store, PuppetDB knows about every node, resource, relationship, and fact across your entire infrastructure. All this information is easily queryable, so you can integrate it into your tools and workflow, or just satisfy your curiosity. It also provides a platform on which powerful new tooling will be built.</p>
<p>And if you’re not using storeconfigs, you should be. At its heart, storeconfigs can be thought of as “higher-order Puppet.” It’s a way for multiple nodes to interact with each other through Puppet, which is an immensely powerful feature. In any case where one node knows what another node is doing, storeconfigs may help.</p>
<p>For instance, storeconfigs can be used to configure a monitoring service, without knowing upfront any of the nodes or services being monitored. Each node to be monitored can simply define what ought to be checked, and those checks can be collected on the node doing the monitoring. Or it can be used to share SSH authorized keys, by having each node export its key, and collect everyone else’s.</p>
<h2>Built for performance</h2>
<p>Let’s talk about performance. I told you it was a key design goal, but just how much faster is PuppetDB than the existing solution? To find out, I ran an experiment against the old, ActiveRecord storeconfigs implementation.</p>
<p>I compiled and saved a catalog of 650 resources, using an initially empty PostgreSQL database. Compilation took 5.6 seconds. With nothing in the database, it took 53 seconds to store the catalog. That’s brushing right up on the agent’s timeout, risking an outright failure. With the database now primed, I submitted the same catalog a second time, unmodified, which took 4 seconds.</p>
<p>To find out how PuppetDB performs, we have much more information available to us. The service is highly instrumented to keep metrics on every aspect of its performance, all of which is made available over HTTP and JMX.</p>
<p><a href="http://puppetlabs.com/wp-content/uploads/2012/05/puppetdb_screenshot.png"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/puppetdb_screenshot.png" alt="PuppetDB dashboard" title="puppetdb_screenshot" width="640" height="737" class="aligncenter size-full wp-image-14256" /></a></p>
<p>This is the PuppetDB dashboard, which uses the HTTP metrics API to give an overview of the current state of the system. The dashboard comes built-in, and updates live, even on your mobile device! Taking a look at this screenshot (taken from our internal PuppetDB instance), we can see the backlog of work, how long command processing is taking, how much work has been done, how large the database is, and much more. And yet this is still only a small subset of the metrics we track and make available.</p>
<p>In particular, we see that the queue is empty, meaning PuppetDB is keeping up with demand. Looking at the number of nodes and resources in the population, we can easily calculate that the average size of a catalog is ~670 resources. The average time to process a command is 394ms. This is around 130x faster than the worst case time of old-school storeconfigs, and 10x better than the case where catalogs are already present. We also see that PuppetDB is responding to storeconfigs queries in only 65ms.</p>
<p>Admittedly, these numbers are somewhat incomparable; for instance, the very first catalog stored in PuppetDB may take some extra time, but catalogs which are unchanged will be negligible. But this gives some indication of the improvement we’re talking about. It’s also important to note that all of this storage is asynchronous, freeing up the master to continue serving catalogs. Previously, the master would have been occupied waiting for storeconfigs.</p>
<h2>Reliable data store</h2>
<p>So we can see that PuppetDB stores your data more quickly, but what about the data itself? After all, that’s what you really care about. PuppetDB makes a few promises about its data: it will be complete, it will be accurate, and it will be current.</p>
<p>Every aspect of the catalog is stored, including edges and unexported resources, which are omitted in old storeconfigs and the popular thin_storeconfigs mode respectively. Nuances of the catalog like resource aliases are also respected, ensuring that every resource and edge is present and accurately represented.</p>
<p>It’s downright difficult to lose your data with PuppetDB. It takes great care not to let that happen, by accepting it into a persistent queue, and trying up to sixteen times (even across service restarts) to handle the command, ensuring that if the data is good, it will make it into the database. And if it somehow still doesn’t make it in, the command will be saved away with plenty of forensic data for later investigation and reprocessing.</p>
<p>In that vein, when configured to use PuppetDB, Puppet will refuse to serve catalogs if PuppetDB is down and the catalog can’t be persisted. This means the data PuppetDB has will always be current; an agent will never use a catalog that PuppetDB doesn’t know about.</p>
<p>And it’s secure. All communication between the puppet master and PuppetDB happens over SSL, authenticated with the same certificates as used for communication between puppet master and agents. Similarly, if PuppetDB and its database are separate, it’s a simple matter to secure their connection.</p>
<h2>Plays well with others</h2>
<p>PuppetDB is a key component of the <a href="http://docs.puppetlabs.com/guides/puppet_data_library.html">Puppet Data Library</a>, and brings that to bear in its <a href="http://docs.puppetlabs.com/puppetdb/0.9/spec_q_resource.html">query API</a>. Resources, facts, nodes, and metrics can all be queried over HTTP. For resources and nodes, there is a simple query language which can be used to form arbitrarily complex requests. The public API is the same one that Puppet uses to make storeconfigs queries (using the <<||>> operator) of PuppetDB, but provides a superset of the functionality provided by storeconfigs. The API is fully documented and versioned, for use in scripts, Faces, or custom Puppet functions.</p>
<p>PuppetDB is faster, smarter, and has more complete data than ever before. If you’re a current storeconfigs user, there’s no reason not to try it out immediately. If you don’t use storeconfigs (and especially if performance was the reason), now is the time to start.  We know that storeconfigs, while being a powerful and important feature, has historically been a pain point for users. One of the goals of PuppetDB is to alleviate that and personally, I want a world in which everyone uses storeconfigs and loves it. PuppetDB offers great power over and insight into your infrastructure, and it’s only going to get bigger and better.</p>
<p><em>Learn More</em></p>
<ul>
<li>Download the open beta of PuppetDB from our <a href="http://apt.puppetlabs.com/">APT repository</a>, <a href="http://yum.puppetlabs.com/">YUM repository</a>, or <a href="https://github.com/puppetlabs/puppetdb">GitHub</a>.</li>
<li>Read the <a href="http://docs.puppetlabs.com/puppetdb/0.9/">PuppetDB documentation</a>.</li>
<li>Open tickets on the <a href="http://projects.puppetlabs.com/projects/puppetdb">PuppetDB project</a>.</li>
<li>Come see Deepak Giridharagopal talk in-depth about the development and design decisions, and ask all your usage questions this Saturday at <a href="http://puppetcampla.eventbrite.com/">Puppet Camp Los Angeles</a>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/introducing-puppetdb-put-your-data-to-work/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Removing lint from the Puppet’s belly button of fluffy automation chaos, or: Using puppet-lint to save yourself from style faux pas</title>
		<link>http://puppetlabs.com/blog/using-puppet-lint-to-save-yourself-from-style-faux-pas/</link>
		<comments>http://puppetlabs.com/blog/using-puppet-lint-to-save-yourself-from-style-faux-pas/#comments</comments>
		<pubDate>Mon, 14 May 2012 20:42:22 +0000</pubDate>
		<dc:creator>Ben Hughes</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[Extending Puppet]]></category>
		<category><![CDATA[General News]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[automated testing]]></category>
		<category><![CDATA[how to]]></category>
		<category><![CDATA[puppet]]></category>
		<category><![CDATA[Puppet Enterprise]]></category>
		<category><![CDATA[puppet-lint]]></category>
		<category><![CDATA[sysadmin]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=14174</guid>
		<description><![CDATA[Wouldn&#8217;t it be nice if you never made a mistake or a typo again? Okay, that&#8217;s a slightly misleading offer. How about just never committing such gaffes in with your code? &#8220;How?&#8221; I hear you cry. With the illustrious Tim Sharpe&#8217;s puppet-lint and some version control derring-do! Following on from Adrien&#8217;s wonderful post on syntax [...]]]></description>
			<content:encoded><![CDATA[<p>Wouldn&#8217;t it be nice if you never made a mistake or a typo again? Okay, that&#8217;s a slightly misleading offer. How about just never committing such gaffes in with your code? &#8220;How?&#8221; I hear you cry. With the illustrious Tim Sharpe&#8217;s <a href="https://github.com/rodjek/puppet-lint">puppet-lint</a> and some version control derring-do!</p>
<p>Following on from Adrien&#8217;s wonderful post on <a href="http://puppetlabs.com/blog/verifying-puppet-checking-syntax-and-writing-automated-tests/">syntax checking and writing tests</a>, you have a way of checking the syntax and style guide from the command line. Using this approach, even on a mature (like a fine wine) Puppet code base, you can move towards having beautiful, aligned, ordered manifests—the type of manifests you&#8217;d be happy taking home to meet the family.</p>
<p>Puppet-lint takes the Puppet Labs Style Guide and places it nicely in a command line tool. Think of it as a <a href="http://www.python.org/dev/peps/pep-0008/">programmatic PEP-8</a> for those from a Pythonic world. Now, where this comes in handy is when you&#8217;re using revision control (which is all the time, obviously!), because you can tie the two together. Yes, every time you try and commit your code to your RCS, it checks the files you&#8217;re committing, and makes sure you haven&#8217;t used a tab where there should be a space.</p>
<p>In Puppet Labs&#8217; kickass Operations department, we&#8217;re ever so slightly keen on <a href="http://git-scm.com/">Git</a>, not least due to the wonderful GitHub. RCSHub just doesn&#8217;t cut it for us these days.</p>
<p>With Git, as with many an RCS, you&#8217;re free to define hooks to do weird and wondrous things upon certain actions. This chapter on <a href="http://git-scm.com/book/en/Customizing-Git-Git-Hooks">git hooks</a> from <em>Customizing Git</em>  explains them in detail. If you’re using Subversion, then this <a href="http://svnbook.red-bean.com/en/1.7/svn.ref.reposhooks.pre-commit.html">pre-commit documentation</a> suggests what you can do on the server side to accomplish the same thing.</p>
<p>For this, the pre-commit hook is the one we want to utilise. I first make a bash script to get a list of the files that change in the commit. Then, the hook script goes through them one at a time, seeing if they&#8217;re Puppet manifests by name, and running puppet-lint on them as it goes. If any of the manifests fail linting, it exits there and then I may go fix them at my leisure!</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/bash</span>
<span style="color: #666666; font-style: italic;"># Requires bash, as it uses the [[ ]] syntax.</span>
<span style="color: #666666; font-style: italic;">#</span>
<span style="color: #666666; font-style: italic;"># If it's puppet code, lint it up.</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># I we don't have puppet-lint, so just exit and leave them be.</span>
<span style="color: #c20cb9; font-weight: bold;">which</span> puppet-lint <span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">1</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">exit</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Variables goes hither</span>
<span style="color: #7a0874; font-weight: bold;">declare</span> <span style="color: #660033;">-a</span> FILES
<span style="color: #007800;">IFS</span>=<span style="color: #ff0000;">&quot;
&quot;</span>
<span style="color: #007800;">FILES</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #c20cb9; font-weight: bold;">diff</span> <span style="color: #660033;">--cached</span> <span style="color: #660033;">--name-only</span> <span style="color: #660033;">--diff-filter</span>=ACM <span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">for</span> <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #800000;">${FILES[@]}</span>
<span style="color: #000000; font-weight: bold;">do</span>
  <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$file</span> =~ \.<span style="color: #000000; font-weight: bold;">*</span>.pp\$ <span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
  <span style="color: #000000; font-weight: bold;">then</span>
    puppet-lint <span style="color: #660033;">--with-filename</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$file</span>&quot;</span>
    <span style="color: #007800;">RC</span>=<span style="color: #007800;">$?</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$RC</span> <span style="color: #660033;">-ne</span> <span style="color: #000000;">0</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>
    <span style="color: #000000; font-weight: bold;">then</span>
      <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #007800;">$RC</span>
    <span style="color: #000000; font-weight: bold;">fi</span>
  <span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #000000; font-weight: bold;">done</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">0</span></pre></div></div>

<p>I save that file to .git/hooks/pre-commit in my repository, give it a light sprinkling of &#8216;chmod +x&#8217;, a dash of &#8216;gem install puppet-lint&#8217; and I am ready to roll.</p>
<h2>Exhibit A, the Larch</h2>
<p>So let&#8217;s see this bad-boy in use, I hear you cry! Let&#8217;s take a manifest that breaks all of the rules, and see what happens&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">node <span style="color:#996600;">'hubert.humphrey.edu'</span> <span style="color:#006600; font-weight:bold;">&#123;</span>
&nbsp;
	user<span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#996600;">&quot;mhunter&quot;</span>:
	   managehome <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>,
	   home <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;/home/mhunter&quot;</span>,
	   comment <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'Mark Hunter'</span>,
	   <span style="color:#9966CC; font-weight:bold;">ensure</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'present'</span>
   <span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
<span style="color:#006600; font-weight:bold;">&#125;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;"><span class="br0">&#91;</span>enlil:puppetlabs-modules<span class="br0">&#93;</span>% git commit hubert.pp
hubert.pp - WARNING: double quoted string containing no variables on line <span style="">3</span>
hubert.pp - WARNING: double quoted string containing no variables on line <span style="">5</span>
hubert.pp - WARNING: =&gt; on line isn't properly aligned for resource on line <span style="">5</span>
hubert.pp - WARNING: =&gt; on line isn't properly aligned for resource on line <span style="">6</span>
hubert.pp - WARNING: =&gt; on line isn't properly aligned for resource on line <span style="">7</span>
hubert.pp - ERROR: two-space soft tabs not used on line <span style="">4</span>
hubert.pp - ERROR: two-space soft tabs not used on line <span style="">5</span>
hubert.pp - ERROR: two-space soft tabs not used on line <span style="">6</span>
hubert.pp - ERROR: two-space soft tabs not used on line <span style="">7</span>
hubert.pp - ERROR: two-space soft tabs not used on line <span style="">8</span>
hubert.pp - ERROR: trailing whitespace found on line <span style="">2</span>
hubert.pp - WARNING: ensure found on line but it's not the first attribute on line <span style="">7</span></pre></div></div>

<p>Woah, that&#8217;s a lot of errors. By default, puppet-lint will let warnings through, but stop dead on errors, and we got them all! I&#8217;ll tidy this manifest up&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">node <span style="color:#996600;">'hubert.humphrey.edu'</span> <span style="color:#006600; font-weight:bold;">&#123;</span>
&nbsp;
  user<span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#996600;">'mhunter'</span>:
    <span style="color:#9966CC; font-weight:bold;">ensure</span>     <span style="color:#006600; font-weight:bold;">=&gt;</span> present,
    managehome <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>,
    home       <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'/home/mhunter'</span>,
    comment    <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'Mark Hunter'</span>,
  <span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
<span style="color:#006600; font-weight:bold;">&#125;</span></pre></div></div>

<p>Much more readable, and now when I try and commit it, I get:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;"><span class="br0">&#91;</span>enlil:puppetlabs-modules<span class="br0">&#93;</span>% git commit hubert.pp
<span class="br0">&#91;</span>master <span style="">6020331</span><span class="br0">&#93;</span> Add in a new pupil to the school!
 <span style="">1</span> file changed, <span style="">10</span> insertions<span class="br0">&#40;</span>+<span class="br0">&#41;</span>
 create mode <span style="">100644</span> hubert.pp</pre></div></div>

<p>Clean, and the best part is I don&#8217;t have to alter my workflow, I can just carry on editing with Vim, commit my work as normal, and just be kindly reminded when a manifest has things that need tidying up.</p>
<p><em>Learn More</em></p>
<ul>
<li><a href="http://docs.puppetlabs.com/guides/style_guide.html">Puppet Labs style guide</a></li>
<li><a href="https://github.com/rodjek/puppet-lint">puppet-lint</a></li>
<li><a href="http://puppetlabs.com/blog/verifying-puppet-checking-syntax-and-writing-automated-tests/">Verifying Puppet: Checking Syntax and Writing Automated Tests</a></li>
<li><a href="http://geek.jasonhancock.com/2012/04/18/puppet-svn-pre-commit-hook/">Puppet-lint SubVersion commit hook by Jason Hancock</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/using-puppet-lint-to-save-yourself-from-style-faux-pas/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Introducing Puppet Labs Boundary Module</title>
		<link>http://puppetlabs.com/blog/introducing-puppet-labs-boundary-module/</link>
		<comments>http://puppetlabs.com/blog/introducing-puppet-labs-boundary-module/#comments</comments>
		<pubDate>Fri, 11 May 2012 17:52:41 +0000</pubDate>
		<dc:creator>James Turnbull</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[Extending Puppet]]></category>
		<category><![CDATA[Modules]]></category>
		<category><![CDATA[Systems Management]]></category>
		<category><![CDATA[Configuration Management]]></category>
		<category><![CDATA[modules]]></category>
		<category><![CDATA[monitoring]]></category>
		<category><![CDATA[puppet forge]]></category>
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=14064</guid>
		<description><![CDATA[Boundary is a network analysis tool that allows fast analysis and an ultra-fine resolution of data. To achieve this speed and resolution of data, Boundary employs software meters, installed on your application servers, that examine the header information of every packet and securely stream it to the Boundary service once a second. We&#8217;re excited to announce [...]]]></description>
			<content:encoded><![CDATA[<p>Boundary is a network analysis tool that allows fast analysis and an ultra-fine resolution of data. To achieve this speed and resolution of data, Boundary employs software meters, installed on your application servers, that examine the header information of every packet and securely stream it to the Boundary service once a second. We&#8217;re excited to announce our Boundary module to install and manage <a title="Boundary" href="http://www.boundary.com">Boundary</a> network meters, developed in conjunction with the Boundary team and the Puppet community, has reached <a title="Boundary module on the Puppet Forge" href="http://forge.puppetlabs.com/puppetlabs/boundary">v1 and is released onto the Puppet Forge</a>! The module also contains support for sending reports from Puppet to <a title="Boundary" href="http://www.boundary.com">Boundary</a>.</p>
<p>To use the module you need to download it from the Puppet Forge onto your Puppet master using the module tools:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;"># puppet module install puppetlabs-boundary</pre></div></div>

<p>You can then use the module to install and manage the Boundary meters that monitor your network traffic and send the results to Boundary.  To create a new meter you will need your Boundary ID and API key and create a `boundary_meter` resource like so:</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">boundary_meter <span class="br0">&#123;</span> &quot;db.example.com&quot;:
  ensure =&gt; present,
  id =&gt; &quot;abcde12345&quot;,
  apikey =&gt; &quot;abcde12345&quot;,
  tags =&gt; <span class="br0">&#91;</span> &quot;production&quot;, &quot;newyork&quot;, &quot;mysql&quot;, &quot;appcluster1&quot; <span class="br0">&#93;</span>,
<span class="br0">&#125;</span></pre></div></div>

<p>This resource will create a meter called &#8220;db.example.com&#8221; and add the tags production, newyork, mysql and appcluster1 (or the tags of your choice).  After you run Puppet you will be able to see your meter in the Boundary console.  We can also easily delete the meter by ensuring it is `absent`.</p>
<p>You can find the <a title="Boundary module on GitHub" href="https://github.com/puppetlabs/puppetlabs-boundary">source code on GitHub</a> and we welcome bug reports, ideas and features from the Puppet community. Thanks to <a title="Joe Williams" href="https://github.com/joewilliams">Joe Williams</a>, <a title="Jeff Hulten" href="https://github.com/jhulten">Jeff Hulten</a>, <a title="Andrew Loe" href="https://github.com/loe">W. Andrew Loe III</a>, <a title="Alessandro Franceschi" href="https://github.com/example42">Alessandro Franceschi</a> and <a title="Scott Smith" href="https://github.com/ohlol">Scott Smith</a> for their contributions to the current module.</p>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/introducing-puppet-labs-boundary-module/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Announcing The Marionette Collective 2.0</title>
		<link>http://puppetlabs.com/blog/announcing-the-marionette-collective-2-0/</link>
		<comments>http://puppetlabs.com/blog/announcing-the-marionette-collective-2-0/#comments</comments>
		<pubDate>Wed, 09 May 2012 16:52:58 +0000</pubDate>
		<dc:creator>R.I. Pienaar</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[Extending Puppet]]></category>
		<category><![CDATA[General News]]></category>
		<category><![CDATA[MCollective]]></category>
		<category><![CDATA[product release]]></category>
		<category><![CDATA[mcollective]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[puppet labs]]></category>
		<category><![CDATA[R.I. Pienaar]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=13976</guid>
		<description><![CDATA[I am proud to announce the release of the next major production version of The Marionette Collective (MCollective). This release brings together almost a year&#8217;s worth of work and introduces great improvements in security, stability, platform support and new features in the core messaging layer. The major areas of advance are below: Complete messaging protocol [...]]]></description>
			<content:encoded><![CDATA[<p>I am proud to announce the release of the next major production version of The Marionette Collective (MCollective). This release brings together almost a year&#8217;s worth of work and introduces great improvements in security, stability, platform support and new features in the core messaging layer.</p>
<p>The major areas of advance are below:</p>
<ul>
<li>Complete messaging protocol rewrite to enable direct style connectivity that would allow programs to bypass normal discovery instead using their own data sources</li>
<li>An additional more robust messaging paradigm supporting a more assured addressing and delivery scheme</li>
<li>Batched mode allowing users to address machines in small groups thus avoiding thundering herd and enabling more granular changes</li>
<li>A more complete language for expressing discovery that includes and/or/not style queries across the infrastructure</li>
<li>Improved Stomp connection security using normal industry standard Certificate Authority validated TLS</li>
<li>New connector that uses ActiveMQ-specific features for better performance and scalability</li>
<li>Security of the SSL and AES security plugins have been improved for tamper protection by middle men</li>
<li>A message validity period has been introduced to lower the window of message replay attacks</li>
<li>Better error handling and better logging for Stomp connections</li>
<li>JSON output from the ‘rpc’ application</li>
<li>Ability to pipe RPC requests into each other creating a chain of related RPC calls</li>
<li>Better validations, better error handling and better documentation creation from the DDL</li>
<li>Performance improvements in the CLI, more consistently formatted output of received data</li>
<li>A Ruby GEM of the client is now made available on rubygems.org</li>
<li>The rc script for Debian based systems have been improved to prevent duplicate daemons from running</li>
<li>Built in packager for plugins into native OS packages—RedHat and Debian supported</li>
<li>MS Windows Support</li>
</ul>
<p>The full <a href="http://docs.puppetlabs.com/mcollective/releasenotes.html">release notes</a> for this release expands on key areas of the above list and you can download this release from our <a href="http://info.puppetlabs.com/download-puppet-open-source.html">download area</a>, <a href="http://yum.puppetlabs.com/">Yum repository</a> or our <a href="http://apt.puppetlabs.com/">Apt repository</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/announcing-the-marionette-collective-2-0/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Upcoming Puppet Events: New Camps, PuppetConf, and Velocity</title>
		<link>http://puppetlabs.com/blog/upcoming-puppet-events-new-camps-puppetconf-and-velocity/</link>
		<comments>http://puppetlabs.com/blog/upcoming-puppet-events-new-camps-puppetconf-and-velocity/#comments</comments>
		<pubDate>Tue, 08 May 2012 15:46:24 +0000</pubDate>
		<dc:creator>jose</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[Conferences and Workshops]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[General News]]></category>
		<category><![CDATA[Puppet Camp]]></category>
		<category><![CDATA[PuppetConf]]></category>
		<category><![CDATA[conference]]></category>
		<category><![CDATA[Events]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[puppet labs]]></category>

		<guid isPermaLink="false">http://puppetlabs.com/?p=13937</guid>
		<description><![CDATA[Puppet Labs has been a busy place in the last month: we announced PuppetConf and released the very first seats for the Puppet Professional Certification Program (more details coming soon), we also announced our support for OpenStack and we announced PuppetDB, affectionately known around the office as project Greyskull. As we move ahead into May [...]]]></description>
			<content:encoded><![CDATA[<p>Puppet Labs has been a busy place in the last month: we announced <a href="http://www.puppetconf.com">PuppetConf</a> and released the very first seats for the Puppet Professional Certification Program (more details coming soon), we also announced our support for <a href="http://puppetlabs.com/solutions/openstack/">OpenStack</a> and we announced PuppetDB, affectionately known around the office as project Greyskull. As we move ahead into May and June we hope to see you at some of the following events:</p>
<p>May 19 &#8211; <a href="http://puppetcampla.eventbrite.com">Puppet Camp Los Angeles</a>: Senior Developer Deepak Giridharagopal will introduce PuppetDB, and the Puppet projects team lead Daniel Pittman will share the Puppet roadmap for 2012.</p>
<p>May 21 &#8211; Find us at <a href="http://www.emcworld.com/">EMC world</a>, we&#8217;ll be around and looking to find you. Follow us <a href="http://www.twitter.com/puppetlabs">@puppetlabs</a> to find out where we are.</p>
<p>We&#8217;ve announced new Puppet Camps for June and July:</p>
<ul>
<li><a href="http://puppetcampsea.eventbrite.com">Southeast Asia</a> in Kuala Lumpur on June 5th</li>
<li><a href="http://puppetcampsydney.eventbrite.com">Sydney</a> on June 8th (tickets are almost gone!)</li>
<li><a href="http://www.puppetlabs.com/puppetcamp">District of Columbia</a> on June 19th
<li>
<li>Puppet Camp <a href="http://puppetcampboston.eventbrite.com/">Boston</a> on June 22</li>
<li><a href="http://puppetcampchicago.eventbrite.com">Chicago</a> on July 23rd</li>
<p>And don&#8217;t forget about our previously announced our European camps in <a href="http://puppetcampdublin.eventbrite.com">Dublin</a>, Ireland on July 6th and <a href="http://puppetcamp-geneva-at-lsmconf.eventbrite.com">Geneva</a>, Switzerland on July 11th.</p>
<p>After the end of July we&#8217;ll be working to produce an epic <a href="http://www.puppetconf.com">PuppetConf</a> in San Francisco on September 27th and 28th. Register now to guarantee a seat. Like many of our Puppet Camps, PuppetConf is sure to sell out.</p>
<p>We&#8217;re also happy to offer you a 10% discount to <a href="http://www.velocityconf.com">Velocity</a> on June 25-28. Just use code PUPPETLABS when you register and then come find us at booth #517 and check out presentations from <a href="http://velocityconf.com/velocity2012/public/schedule/detail/23203">James Turnbull</a> and <a href="http://velocityconf.com/velocity2012/public/schedule/detail/23639">Luke Kanies</a> at Velocity.</p>
<p><a href="http://velocityconf.com/velocity2012"><img src="http://puppetlabs.com/wp-content/uploads/2012/05/468x60.png" alt="" title="Velocity Conf" width="468" height="60" class="aligncenter size-full wp-image-13946" /></a></p>
<p>We&#8217;re looking forward to connecting with you this summer.</p>
]]></content:encoded>
			<wfw:commentRss>http://puppetlabs.com/blog/upcoming-puppet-events-new-camps-puppetconf-and-velocity/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

