Entries filed under: Users

Back to Index

Three Puppet Camps in Europe on the way

Posted on
By
jose
in
Blog, Community, General News, Puppet Camp, User Experience, Users
Responses
0 Comments

We’re happy to announce three European Puppet Camps:

Edinburgh, Scotland March 23 (only 20 tickets left!)

Register

Stockholm, Sweden March 28 (20 tickets left!)

Register

Amsterdam, Netherlands April 2

Register

Puppet Camps are 1-day community events for local audiences. Typically we’ll feature 3-5 local speakers along with a Puppet Labs Engineer. Schedules for all three Puppet Camps are available, but may change as more talks are submitted.

Teyo Tyree, the VP of Business Development and co-founder of Puppet Labs, will be at all three events. RI Pienaar, the creator of MCollective (the backbone of Puppet Enterprises Live Management feature), will also be at Edinburgh. Core contributors to the Puppet project and interesting users are participating in all of the camps.

Puppet Camp Edinburgh is hosted in conjunction with FLOSS UK’s spring conference. Puppet Camp Amsterdam is being co-hosted by Cloudera and (Puppet Labs’ local partner) AmazicSource. We’re in the process of expanding Puppet Camps from a bi-annual format to a roadshow appearing frequently throughout the year.

This year we are planning to hit New York, DC, Chicago, and either Melbourne or Sydney, but we’re also having conversations with organizers in Berlin and Geneva. If you think your city has enough interest in Puppet to support a 100+ person event, shoot us an email.

Our end user conference PuppetConf will be held at the Mission Bay Conference Center in San Francisco, CA on September 27th and 28th. Look for more details on PuppetConf in the next few weeks, along with a call for participation.

Introducing the Puppet Labs Community Manager

Posted on
By
Mike Stahnke
in
Blog, Community, General News, User Experience, Users
Responses
1 Comment »

Hello, I’m Michael Stahnke and I’m the new community manager at Puppet Labs. I’ll provide a little bit of background about myself, but then I want to jump into the important stuff around the Puppet community.

I joined Puppet Labs in April of 2011 as the first Release Manager. I was a member of the community and using Puppet since late 2006. I learned about Puppet from being a member of the Fedora Project’s Infrastructure group. I also was one of the people helping get EPEL launched (Extra Packages for Enterprise Linux) very early on. I still contribute regularly to Fedora/EPEL, and of course to Puppet, Facter, Dashboard, Hiera and Mcollective. I also love Infrastructure Operations.

There’s obviously a ton I could write about in regards to community. The community around Puppet is awesome. It’s certainly a key reason I wanted to use Puppet, learn about it, learn Ruby, and join Puppet Labs. Today I’d like to focus on what my goals for the community are, and address some areas where we’ve fallen short in the past.

My main goal for the Puppet Community shouldn’t be any different than the goals of the Puppet project:

I want infrastructure problems to go away.

I want quality system administrators to have more time to explore their domain, and make their infrastructure services an investment rather than a cost center. I want infrastructure engineers to spend time on differentiating activities rather than having every shop reinvent time synchronization, DNS management, and authentication setups.

One of the real reasons I liked Puppet when I got started with it was the community. There were smart people here. I don’t just mean people good at Puppet, but people who solved difficult systems management problems. The people in the community discussed solutions for provisioning, patching, packaging, deployment, compliance, auditing, disaster recovery and everything else that was consuming my day as an infrastructure admin. So the Puppet community centered (and centers) around people who were (and are) awesome at infrastructure. I’m very interested in continuing to foster those types of discussions.

Beyond that, I have some more concrete goals around community and Puppet.

I’d like to enable the community to host Puppet User Groups or meet-ups. This means developing a formula for what works, a budget process, and hopefully the output is something like a “user-group-in-a-box” kit.

I want to define and recognize contributors. We spend a lot of time focused on contributors providing us with code. We love you, please keep doing it. We also want contributors to be recognized for things like documentation, filing excellent bug reports, leading/attending user groups, uploading modules to the forge, integrating Puppet with other tools, etc.

In the current event bucket, we have the process around Google Summer of Code 2012. We participated in GSOC in 2010, and liked it a lot. This year we’d like to participate again. This means we need awesome ideas for projects. We’ve started an idea page at http://projects.puppetlabs.com/projects/puppet/wiki/GSOC12, please contribute if you have any ideas for GSOC 2012.

In sitting down to identify gaps in the community, or friction points, a few items bubbled up quickly. So, we’re going to address them as soon as we can.

  1. It is difficult to find material about the Open Source projects on our main website.
  2. We don’t do a super job recognizing members of the community.
  3. We don’t capture a lot of information about what you, the community, are doing. This type of input can make our product and documentation much better.

In the near future, look for some new content on our website, around community and the open source ecosystem.

I have several ideas on what we’ll do to fix these gaps. Some of this will require some patience and experimentation to get right as well. If you have comments and suggestions around the Puppet community, I’m available via Twitter (@stahnma), Freenode (stahnma), and email (stahnma@puppetlabs.com).

Look for a lot more to come in the future around community goals and involvement.

Additional Resources

Puppet Camp Atlanta: Success!

Posted on
By
jose
in
Blog, Community, Conferences and Workshops, DevOps, General News, Puppet Camp, Users
Responses
2 Comments »

Puppet Camp Atlanta was a fantastic community event and is be the template for our continuing Puppet Camp series. In many ways Atlanta was an experiment to see if our community could support a 1-day event structure. It can, and the meeting was productive and filled with rich content. A loose speaking schedule allowed for a lot of great conversations over coffee and open Q&A sessions with Puppet Engineers. More than ever before, the Puppet team felt as though we were able to connect with participants to help tackle the tough issues that our users face in real world situations. I strongly encourage you to participate in an upcoming Puppet Camp in your city.

We have 7 Puppet Camps in the works, so look for your city on our complete list. If you don’t see your greater area represented and think you can help us find 100 puppeteers eager to converse, reach out and we’ll see what we can do to bring an event to your city.

And don’t forget PuppetConf is September 27th and 28th at the Mission Bay Conference Center in San Francisco, California. A call for participation, registration details, and sponsorship prospectus will be available by March. PuppetConf has an estimated 60 speaking opportunities and will span all topics operations, DevOps, Puppet, and the Puppet Ecosystem.

Puppet Triage-A-Thon: The Results are In!

Posted on
By
James Turnbull
in
Blog, Community, General News, Open Source, Users
Responses
1 Comment »

The first Puppet Triage-a-thon was a huge success. Thank you so much to everyone who attended and contributed! Some of our favorite stats from the event:

  • We started the day with 2292 open tickets. Over the course of the day 565 tickets were triaged. We also closed 115 tickets. That’s almost 25% of the open tickets triaged and 5% closed!
  • Seventeen community patches were submitted! (And many of these were merged during the day.) Several patches were from people who’ve never contributed before, which is awesome.
  • We had about 50 people involved globally. Individuals and teams participated from Germany, Mexico, Australia, United Kingdom, France, and across the United States. And a big shout-out to the Atlanta Puppet Users group who had a team of five people!  We also had about 10 community members onsite in the Puppet Labs offices locally in Portland.

Our top contributors from the community were:

  1. Dominic Cleal
  2. Devon Peters
  3. Patrick Otto
  4. Oliver Hookins

They’ll be the recipients of $100 Amazon gift vouchers. The full list of participants is here, along with the tally of tickets triaged: http://triageathon.puppetlabs.com/

Everyone who contributed will receive a Puppet Labs t-shirt. If you participated you’ll receive an email shortly asking you for your preferred t-shirt size and where you’d like us to send it.

We’re going to continue to run these events in the future to keep the ticket database fresh and up-to-date.

Thanks again to everyone who came along and contributed and made it such a great success and an awesome amount of fun!

Puppet Wins ‘Best Open Source Configuration Management Tool’

Posted on
By
michelle
in
Blog, Community, DevOps, General News, Open Source, Users
Responses
0 Comments

We’re excited that Puppet has been chosen as the 2011 Best Open Source Configuration Management Tool by Linux Journal readers. This is the second year in a row Puppet has earned the honor, and we can’t thank our enthusiastic users and community enough.

Linux Journal Readers' Choice

From the Linux Journal article: “If you manage greater than zero servers, you will benefit from using a tool like Puppet.”

Related Content:

Deploying Applications and Bringing Puppet Information to the CLI with Puppi

Posted on
By
Alessandro Franceschi
in
Blog, Community, Extending Puppet, How to, Open Source, Puppet Camp, Tips, Users
Responses
0 Comments

With Puppet we build infrastructures, piece by piece, manifest after manifest. We control how nodes are configured, what services they provide, how they are checked.
We manage where web applications stay and sometimes how they are built, tested, and deployed.

Puppet has a lot of knowledge about our systems. Every catalog we receive is an unique source of data that is exactly what brings our servers to the desired state. The more information we provide in our manifests about the system, the more we can things we can do with it. Puppi tries to bring this knowledge to the command line.

Present

Puppi was initially developed to standardize different procedures of web applications deployments and it has evolved into a shell command that provides handy and quick actions useful for the system administrator. Now it is stable enough to have reached version 1.0 (currently in RC state) the features initially planned are present, it’s used in production and no big changes are planned for this version. See the presentation held at The Puppet Camp Europe 2011 for some videos and further details.

Puppi’s most useful actions are:

  • deploy: to manage the whole deploy workflow with a single keystroke
  • check: to verify the general system’s health and specific checks on the application deployed
  • log: to quickly tail some or all the known logs
  • info: to show the output of a custom set of preconfigured commands
  • rollback: to quickly rollback a deployed application

Puppi is currently entirely provided as a Puppet module, you include it and you have the whole Puppi functionality:

  • the bash command /usr/sbin/puppi
  • its configuration directory /etc/puppi, with plenty of files and dirs configured by Puppet defines like puppi::check, puppi::info etc
  • a set of (customizable) defines that build deploy procedures, like puppi::project::maven that retrieves Java artifacts generated by Maven
  • some general use native scripts that are used to accomplish the different steps of a deployment
  • a set of defines to populate the output of Puppi actions
  • some default content for Puppi info, log and check actions to make Puppi useful out of the box.

There are not other modules prerequisites, but for full functionality you need on the systems where you place Puppi these commands: wget, mail, rsync and the most common Nagios Plugins.
Note also that Puppi is entirely self-contained, it doesn’t need external services to run. Once deployed, all its actions are based on local files and data; checks are local, info scripts are local, deploy procedures need only the availability of the defined source to work.

How to Use

The Puppi module provides some deploy procedures that cover many typical scenarios.
For example, to retrieve a war from $source and deploy it in $deploy_root, keeping a copy for rollback and notifying $report_email, you need this:

 
puppi::project::war { "myapp":
    source           => "http://repo.example42.com/deploy/prod/myapp.war",
    deploy_root      => "/store/tomcat/myapp/webapps",
    report_email     => "sysadmins@example42.com",    
}

All the existing deploy procedure have a set of optional arguments that make them more flexible. Here a more complex case:

puppi::project::maven { "supersite":
    source           => "http://nexus.example42.com/nexus/content/repositories/releases/it/example42/supersite/",
    deploy_root      => "/usr/local/tomcat/supersite/webapps",
    config_suffix    => "cfg",
    config_root      => "/srv/htdocs/supersite",
    document_suffix  => "css",
    document_root    => "/srv/htdocs/supersite",
    firewall_src_ip  => $site ? {
        dr      => "192.168.101.1/30",
        main    => "192.168.1.1/30",
    },
    backup_retention => "3",
    init_script      => "tomcat",
    report_email     => "sysadmins@example42.com",
    enable           => "true",
}

This does the following actions in sequence:

  1. Retrieves the maven-metadata.xml from $source
  2. Blocks access from a loadbalancer IP
  3. Backups the existing data for rollback operations
  4. Deletes older backups (3 archives are kept, instead of the default 5)
  5. Deploys the release war in $deploy_root
  6. Unpacks a configurations tarball tagged with the Maven qualifier $config_suffix in $config_root
  7. Unpacks a static files tarball tagged with the Maven qualifier $document_suffix in $document_root
  8. Restarts tomcat and notifies via mail

All this can be triggered with the command “puppi deploy supersite” and if something fails you can “puppi rollback supersite”.

The above puppi::project::maven (or tar|war|list|dir|mysql..) defines build up the logic and the sequence of commands run in deployment and rollback operations using basic Puppi defines like puppi::project, puppi::deploy, puppi::rollback, puppi::init.
You can use the existing puppi::project::* procedures or build up your own ones, to manage special cases. The same bash scripts they use (“native scripts”, stored in puppi/files/scripts/) can be replaced by custom scripts, in whatever language.

The other Puppi actions require simpler constructs, for example you can manage a single check (we use Nagios plugins, as they are so common) with:

puppi::check { "Port_Apache":
    command  => "check_tcp -H ${fqdn} -p 80" ,
}

or insert more elaborated checks in your defines (for example when you create virtualhosts, using data you may already provide):

puppi::check { "Url_$name":
    enable   => $enable,
    command  => "check_http -I '${target}' -p '${port}' -u '${url}' -s '${pattern}'" ,
}

The logs to tail with Puppi log are defined by the puppi::log define (note that with a simple selector you can adapt the commands to run according the underlining OS):

puppi::log { "auth":
    description => "Users and authentication" ,
    log => $operatingsystem ? { 
        redhat => "/var/log/secure",
        darwin => "/var/log/secure.log",
        ubuntu => ["/var/log/user.log","/var/log/auth.log"],
}

Also in this case you can insert a puppi::log inside an existing define, using the data it inherently has:

puppi::log { "tomcat-${instance_name}":
    log => "${tomcat::params::storedir}/${instance_name}/logs/catalina.out"
}

You can manage the output of “puppi info network” with something like:

puppi::info { "network":
    description => "Network settings and stats" ,
    run         => [ "ifconfig" , "route -n" , "cat /etc/resolv.conf" , "netstat -natup | grep LISTEN" ],
}

or build more elaborated info subclasses using custom templates and specific data:

puppi::info::instance { "tomcat-${instance_name}":
    servicename => "tomcat-${instance_name}",
    processname => "${instance_name}",
    configdir   => "${tomcat::params::storedir}/${instance_name}/conf/",
    bindir      => "${tomcat::params::storedir}/${instance_name}/bin/",
    pidfile     => "${instance_rundir}/tomcat-${instance_name}.pid",
    datadir     => "${instance_path}/webapps",
    logdir      => "${instance_logdir}",
    httpport    => "${instance_httpport}",
    controlport => "${instance_controlport}",
    ajpport     => "${instance_ajpport}",
    description => "Info for ${instance_name} Tomcat instance" ,
}

Examples are endless, you can easily extend and customize the existing defines and you can integrate them in your modules according to the needs you have.

The Joys of Collectivism

Puppi’s purpose is not only to provide a command tool based on Puppet data, that helps the sysadmin to gather info, deploy applications, troubleshoot and check systems—it can be run manually from the local system, automatically via a cron job or triggered by a web interface. It can be used to summarize a set of common actions to be sudoed by non-privileged users, and it can be called by an agent of an orchestration tool.

Puppi enters into a new scale with the MCollective agent Puppi and the command mc-puppi: Whatever can be done locally with Puppi can be repeated on the whole infrastructure with the same syntax, using the power of MCollective. This becomes particularly interesting when your deploy procedures involve actions on different nodes, or when you need to quickly check the system’s health on a multitude of nodes. A command like “mc-puppi check” runs and shows the equivalent of ALL your Nagios checks on your WHOLE MCollective domain. There may be thousands; you have them in few seconds. I like to consider this a real-time distributed instant infrastructure test. Something like “mc-puppi info network” instead provides immediate overview of the network configuration and status of all your nodes, and if verbosity bothers you, just grep what you need.

A missing piece in the Puppi world is a web frontend that gathers the reports of the deployments, collects information about nodes, shows the results of local checks, and possibly lets users trigger deploy procedures via a central web console. The development of a web interface to Puppi, although planned since the beginning, has not yet started. The main reason is that it was considered a priority to have a stable command and a MCollective agent, another reason it’s time to make decisions about Puppi, and possibly these have to be shared.

Future

Puppet development is growing quickly. At the Puppet Camp Europe 2011 Luke presented Puppet Faces, and it’s clear that version 2.7 introduces us to a new era in Puppet evolution. There are some common points in Faces and Puppi: they both bring parts of Puppet to the CLI and they are expandable with actions. Actually, it just seems natural that Puppi’s future is to become a Puppet Face.
Now it’s a bash script that executes bundles of bash scripts, based on data more or less elegantly provided by Puppet modules. It works also on older Puppet versions (at least 0.25) so that it can be widely adopted and integrated in current layouts. The next version is probably going to be in ruby, directly use Puppet APIs and possibly be based on a more standardized modules data model. And of course, it is going to work only with Puppet 2.7 and later.
It may become something different, maybe even with a different name, but as far as I’m concerned it should keep the principles it’s based upon:

  • Be based on Puppet data: Puppet knows the infrastructure, we want this knowledge and intelligence integrated in commands we run on the shell. The way this data is currently provided is not optimized (every piece of Puppi information is basically a Puppet resource (generally a file) and this is an overhead we should avoid), we could rely directly on the catalog, which seems the most natural source, but in order to do this I suspect some kind of standardization is needed at the module level
  • Provide a simple single line standard command to run an application deployment (one keystroke to deploy them all)
  • Provide useful actions that can be used from the CLI, an orchestrator agent or a web interface to show info, status, and working details on systems and applications (I would keep the check/info/log actions, as I’m finding them quite useful)
  • It can be run manually or automatically, locally or from a central orchestrator and, possibly, also via a web interface

A Puppi webapp should let different users request, trigger, and view the results of a deploy, gather info from the systems (via rest?), and, in order to become an inventory frontend on steroids with as much detail on the system as users want, receive and show checks and possibly be able to search and correlate the large amount of data it could receive.

The truth is, development on the next Puppi and its web frontend is something that I would like to do in collaboration with Puppet Labs and interested members of the community.
Puppi 1.0 was done by me for a customer’s needs with the knowledge and the requirements I had at my disposal.
Puppi 2.0 (whatever the name and the shape) does not have immediate operative requirements; its design, how data is fed from modules, and how it’s integrated in Puppet should be discussed and shared.

Anyone interested? Leave a comment here, or email me directly.

Guest Post: A Puffy in the Corporate Aquarium, The Sequel

Posted on
By
Antoine Jacoutot
in
Blog, How to, Tips, Users
Responses
0 Comments

After I wrote an article for the OpenBSD Journal about my job at M:tier explaining how we were deploying OpenBSD in several production setups, I’ve been asked several times to extend the part regarding our usage of Puppet.

Most of our solution management is handled by Puppet, from unattended installation and configuration to daily maintenance and security updates.

Unfortunately and for obvious reasons, I cannot go into the tiny details of our setup, but hopefully this article will share some light on how Puppet improved our deployment of OpenBSD and assorted applications amongst several sites over the world from a unique central place.

Generic Setup

Before going into more technical details, I’ll explain how we deploy Puppet itself as well as the recipes and manifests.

Why Puppet?

Part of our job involves managing several customers with different sites in different countries. We are providing a generic IT solution (servers and desktops) that we have to tweak according to the customers wishes. From the start it was obvious that maintaining one setup per site would not be possible as it would involve a lot of (duplicate) work.

After some brainstorming and testing Puppet was chosen because it allowed us to maintain a generic solution that could still be easily modified using simple variables and “if” constructs. Going this way we ended up with 95% of the recipes, manifests, and configurations being shared amongst all of our customers. Adding a new site or customer is just a matter of configuring the remaining 5%.

All of our Puppet variables are stored within a redundant LDAP setup. We chose LDAP to allow easy modification from the local administrators over a graphical interface. It was important because these people did not know anything about Unix when we first implemented the setup. So for them, it’s only a matter of opening the LDAP graphical interface and change a value to have it propagated wherever it needs to be.

The Quick and Dirty Picture

The way it works is as follows: On all sites, we have a synchronisation job that pulls all the latest packages from our central repository. One of these packages is called “mtier-puppet” and contains the puppetmaster configuration, recipes, and manifests. It is automatically installed on the puppetmaster that manages the local site. Note that we are using a fully redundant puppetmaster setup (they both install the same mtier-puppet package and synchronize puppet certificates using a puppet job). Both puppetmaster servers share the same virtual IP over CARP (Common Address Redundancy Protocol).

All the files for all customers are stored within a version control system. When a configuration change is requested, a commit to the repository will automatically trigger the build of a new mtier-puppet package. This allows us to keep everything in one place which not only makes it easy to share files between different installations but also allows for quick comparison of the different Puppet configurations. This also means that when a enhancement or fix is needed on one site, all sites will benefit from it as well by only touching one file.

We have also implemented a “plocal” recipe that allows the local staff to override their default setup (for testing and/or quickly changing a configuration without the need to wait for a new mtier-puppet package).

The way Puppet is run during installation or production is exactly the same. For bootstrapping machines, we use a pxeboot setup that installs only the base OpenBSD system. When this is done, puppetd runs automatically and installs the necessary packages and configurations then run some post-installation commands like: ‘squid -z’ to initialize the Squid Proxy cache ‘aide -i -V0′ to create a reference sum of the installation ‘update-desktop-database’, ‘gtk-update-icon-cache’… for the desktops etc.

Technical Aspects

Auto-Signing/Domain

We use the autosign feature of Puppet to free the local system administrators from the hassle of handling SSL certificates. This way we just have to clear the certificates if a machine gets reinstalled.

Fileserver Modules

Apart from the default fileserver modules we use several ones to fetch data from the server (anti-virus signatures, SSL certificates (https), etc).

Custom Modules

* parser (multi_source_template)
A modified version of the available multi_source_template module.
Our modification makes it possible to create a template files with a
.plocal extension (see above). These files are always picked first by
this function so in case we need a fast way to override the default
templates on a machine or a site, we just have to create this file.

Multi level walk-tree (using /etc/fstab for the example):

  • customer/site/machine/etc/fstab.plocal
  • customer/site/machine/etc/fstab
  • customer/site/generic/etc/fstab.plocal
  • customer/site/generic/etc/fstab
  • customer/generic/etc/fstab.plocal
  • customer/generic/etc/fstab
  • generic/etc/fstab.plocal
  • generic/etc/fstab

In addition if a .plocal change gets delegated to the original file, and
the md5 sum of fstab.plocal equals fstab, the plocal file gets removed
automatically.

This is an extract of our multi_source_template.rb function:

       sources.each do |file|
           Puppet.debug("Looking for #{file} in #{environment}")
           if FileTest.exists?("#{file}")
               if FileTest.exists?("#{file}.plocal")
                   Puppet.info("Found #{file}.plocal in #{environment}")
                   if Digest::MD5.hexdigest(File.read(file)) == Digest::MD5.hexdigest(File.read("#{file}.plocal"))
                     Puppet.info("#{file}.plocal is identical to #{file} in #{environment} removing #{file}.plocal")
                     File.unlink("#{file}.plocal")
                   else
                     file = "#{file}.plocal"
                   end
               end

* provider (package)
The official support for the OpenBSD pkg tools in Puppet is not fully in
shape yet, so we had to extend it to support all of our needs, for e.g.
using a double `-’ in a package name to allow for version-less FLAVORs
(OpenBSD-specific concept that is in some ways similar the USE flags in
Gentoo Linux); or forcing the “update” and “updatedepends” flags every
time a package gets installed or updated.

require 'puppet/provider/package'
 
# This package provider is based on the OpenBSD pkg provider from puppet with some
# modifications to handle updates, and forces.
 
Puppet::Type.type(:package).provide :mtier, :parent => :openbsd, :source => :openbsd do
   include Puppet::Util::Execution
   desc "OpenBSD's form of ``pkg_add`` support."
 
   commands :pkginfo => "pkg_info", :pkgadd => "pkg_add", :pkgdelete => "pkg_delete"
 
   defaultfor :operatingsystem => :openbsd
   confine :operatingsystem => :openbsd
 
   def self.instances
       packages = []
 
       begin
           execpipe(listcmd()) do |process|
               # our regex for matching pkg_info output
               regex = %r{^(\S+)-([^-\s]+)\s+(.+)}
               fields = [:name, :ensure, :flavor, :description]
               hash = {}
 
               # now turn each returned line into a package object
               process.each { |line|
                   if match = regex.match(line)
                       pkgname, hash[:description] = line.split(/\s+/)
                       pkgname =~ /^(.*?)\-(\d.*)$/
                       stem = $1
                       rest = $2.split('-')
 
                       hash[:name] = stem
                       hash[:ensure] = rest.shift
                       hash[:flavor] = rest.join('-')
                       if hash[:flavor] != ''
                         hash[:name] = hash[:name] + "--" + hash[:flavor]
                       end
 
                       yup = nil
                       name = hash[:name]
                       hash[:provider] = self.name
 
                       packages << new(hash)
 
                       hash = {}
                   else
                       # Print a warning on lines we can't match, but move
                       # on, since it should be non-fatal
                       warning("Failed to match line %s" % line)
                   end
               }
           end
 
           return packages
       rescue Puppet::ExecutionFailure
           return nil
       end
   end
 
   def self.listcmd
       [command(:pkginfo), " -a"]
   end
 
   def install
       should = @resource.should(:ensure)
 
       unless @resource[:source]
           raise Puppet::Error,
               "You must specify a package source for BSD packages"
       end
 
       if @resource[:source] =~ /\/$/
           withenv :PKG_PATH => @resource[:source], :http_proxy => nil, :ftp_proxy => nil do
               output = pkgadd "-r", "-D", "update", "-D", "updatedepends", @resource[:name]
               if output =~ /Can't find\s*(.+)/
                   raise Puppet::Error, output.chop!
               end
           end
       else
           pkgadd @resource[:source]
       end
   end
 
   def query
       hash = {}
       info = pkginfo @resource[:name]
 
       # Search for the version info
       if info =~ /Information for (inst:)?#{@resource[:name]}(-\S+)?/
           hash[:ensure] = $2 ? $2 : $1
       else
           return nil
       end
 
       # And the description
       if info =~ /Comment:\s*\n(.+)/
           hash[:description] = $1
       end
 
       return hash
   end
 
   def uninstall
       pkgdelete @resource[:name]
   end
end

Manifests

We basically use generic, machine and service-specific recipes, that are
being evaluated from LDAP where we store the machines.
Our classes.plocal directory also enables us to override the default
templates just as we do for our template files (like fstab.plocal).
There is nothing specific about this, we use dependencies and run-stages
for some of the recipes.

e.g. our “aide” recipe (aide is an intrusion detection environment):

class aide {
       class { paide: stage => post }
}
 
class paide {
       package {
               "aide":
                       ensure => installed,
                       source => "$protocol://$server/pub/OpenBSD/$operatingsystemrelease/packages/$hardwaremodel/",
                       require => File["/etc/ssl/pkgca.pem"];
       }
 
       file {
               "/etc/aide.conf":
                       ensure => file,
                       owner => root,
                       group => wheel,
                       mode => 0644,
                       require => Package["aide"],
                       content => multi_source_template("$templatedir/customer/$customer/$site/$hostname/etc/aide.conf",
                                                         "$templatedir/customer/$customer/$site/generic/etc/aide.conf",
                                                         "$templatedir/customer/$customer/generic/etc/aide.conf",
                                                         "$templatedir/generic/etc/aide.conf");
       }
 
       exec {
               "aidedb":
                       command => "aide -i -V0; mv /var/db/aide.db.new.gz /var/db/aide.db.gz",
                       timeout => 300,
                       user => "root",
                       path => "/bin:/sbin:/usr/sbin:/usr/bin:/usr/local/bin",
                       unless => "test -f /var/db/aide.db.gz",
                       require => [ File["/etc/aide.conf"], Package["aide"] ];
       }
 
}

Puppet Modifications

By default, Puppet only tries to connect to LDAP once, then errors out.
Our tests indicated that this was not enough so we had to bump this to
at least 10 retries.

* The defnode facter variable
Since we have desktop and server machines enlisted in LDAP all of the
nodes are getting pulled from there, but we have hundreds of
workstations so there is no point in listing them all in LDAP and we
cannot use the default node because that is used to store default
settings applicable to all machines.
So by specifying the “defnode” facter variable on puppetd invocation the
server will use that to perform a Puppet run for a workstation or a
laptop.

This is the patch that we use for that feature.

--- lib/puppet/indirector/node/ldap.rb.orig     Thu Sep 23 01:17:21 2010
+++ lib/puppet/indirector/node/ldap.rb  Fri Nov 12 11:15:22 2010
@@ -1,3 +1,4 @@
+require 'facter'
 require 'puppet/node'
 require 'puppet/indirector/ldap'
 
@@ -29,6 +30,9 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap
  def find(request)
    names = [request.key]
    names << request.key.sub(/\..+/, '') if request.key.include?(".") # we assume it's an fqdn
+
+    defnode = Puppet::Node::Facts.find(request.key).values['defnode']
+    names << defnode if defnode
    names << "default"
 
    node = nil
@@ -174,6 +178,14 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap
    parent_info = name2hash(parent) || raise(Puppet::Error.new("Could not find parent node '#{parent}'"))
    information[:classes] += parent_info[:classes]
    parent_info[:parameters].each do |param, value|
+      if (param =~ /^puppet[^class].*$/)
+          if information[:parameters][param].kind_of? String
+              information[:parameters][param] = information[:parameters][param].split("\n")
+          end
+          if information[:parameters][param]
+              information[:parameters][param] += parent_info[:parameters][param].to_a
+          end
+      end
      # Specifically test for whether it's set, so false values are handled correctly.
      information[:parameters][param] = value unless information[:parameters].include?(param)
    end

nginx

Due to the high connection rate to Puppet (especially during the
installation phase where dozen of machines are installed concurrently)
we had to start using nginx with mongrel as a frontend for Puppet.

In the End

Since most of the time we use a generic Puppet deployment, we had to pay
attention in the way the recipes were evaluated to make sure the low-end
machines (like the firewalls or routers) didn’t have to spend too much
CPU time in processing them (remember that we use a lot of shared
manifests and recipes between for e.g. all “servers” which includes
firewalls and routers).

Note that all modifications we do to Puppet itself and that make sense
are merged back to the official OpenBSD package and are available in the
ports tree at: http://www.openbsd.org/cgi-bin/cvsweb/ports/sysutils/ruby-puppet/patches/

On and on it did take us quite some time to get a Puppet environment
that was right for our needs but it was very much worth the effort
because we now have a base that can be easily extended and updated.
Moreover, it is now much easier to check the status of the updates on
all the machines we manage.

As we got acquainted more and more with Puppet we became really hooked
to it and there is no way we will go back anytime soon: as far as we are
concerned, choosing Puppet ended up being a total win and success for
us.

This article was written by Antoine Jacoutot (ajacoutot@openbsd.org) and
Robert Nagy (robert@openbsd.org).

What is User Experience in Puppet?

Posted on
By
Randall Hansen
in
Blog, Community, User Experience, Users
Responses
1 Comment »

Since starting at Puppet Labs four months ago, many friends have asked me why. “Puppet is a systems tool, right? Isn’t it all command line? Where’s the user experience? Don’t you usually work on the web? Are you designing their website?”

To the contrary, I’m happy to say that for the first time since the Internet was invented I’m working at a company whose web site doesn’t need much of my attention. We have fantastic people working on it already, and I think it’s quite good.

There’s a lot of user experience in Puppet if you look. That will be an easier argument to make if we have a good idea of what user experience is.

What is User Experience?

Back in the day, much of this was called Human Computer Interaction, or HCI. It is the theory and practice of how people interact with computers. Computers at the time were slow-moving and without much rich user interaction, and this started as academic work—a meeting point between psychology and computer science.

As we got faster at building software and interaction became richer, we began to apply HCI principles to one-off projects. “How can this corporate or consulting project succeed?” was the question. Usability became well-established as a discipline and method.

With the Internet, richer interaction is possible not just with a product but with a company. Perception of the company matters, including installing and using the product, filing bugs and receiving responses, updating software, finding and reading documentation, and interacting with the community. The path of the customer through this process is user experience.

So wait, is this just tarted-up brand psychology? No, because the heart of user experience is a deep interaction with software, and the user’s need to get something done.

The desire for, and techniques of, measuring much of this come from usability. How many people succeeded or failed? How many were frustrated, how many had positive or negative impressions of the product?

These metrics are all useful, but mine is simpler: Joy. My metric is joy.

I want people to look forward to using Puppet. I want people to enjoy using Puppet not because it has no bugs or prevents mistakes, but because it has a personality. A good tool is something you can relate to because you understand how and why it works. Enabling that emotional connection and building a framework around it is what I call user experience.

Is that ambitious? Absolutely, but good goals always should be.

What is User Experience at Puppet?

Certainly a lot of the work in Puppet is done by one computer talking to another, but all of that work is initiated and mediated by a human being. Without a human operator Puppet has nothing to do, and every interaction with each component of Puppet is user experience.

The Command Line

My first answer to my friends about working at Puppet is that for 25 years I’ve been a victim of bad command line tools and now it’s payback time. It’s been a great pleasure over the last few months to help create a first-class command line experience.

The command line is different from the GUI in fundamental ways. There’s very little context, no affordances, and interaction mostly relies on memory and low-density text display. Interaction principles are the same, though, and a successful user experience has the same properties regardless of the interface used to accomplish it.

For instance, we should be careful and deliberate about presenting help on the command line. We can’t use the GUI trick of contextual help; most help must be asked for explicitly. How do we tell our users that help is available? How much detail do we show at once? We’ve thought about this a lot for our new Faces commands.

The GUI

The graphical user interface is what most people think about when they hear “user experience” or “interface design.” Puppet’s GUIs today are the Forge and Dashboard.

The Forge is a place where Puppet users can find and share Puppet modules. It keeps accumulating useful modules, but has not seen much development from us in the last year. We have big plans, and will be talking about those soon in public.

Dashboard is a reporting tool and external node classifier. Its reporting features have improved, and we expect to ship version 1.2 in the near future with improved summary reporting and useful at-a-glance views of your nodes.

The DSL, or Puppet Language

Puppet’s DSL, also called the Puppet Language, is how Puppet users model the desired state of their systems. For example, this is the clearest and most compact way we’ve come up with for defining the properties we care about for one file:

    file { '/var/log/syslog':
      ensure => present,
      mode   => '0644',
    }

There are many user experience considerations here. This looks a little like Ruby code, but in fact it isn’t. Is the potential confusion to a new user worth the other benefits? What are those benefits and how do we weigh them?

For another example, there’s ticket #7599, discussing whether the trailing commas after “present” and “0644″ should be mandatory. Technical considerations aside, what would be the effect of making these optional, or even of prohibiting their use? Given that they are now required, would there be a migration costs for existing users? Would it be worth it?

The External API

An API is a structured way of issuing commands to a remote server and receiving responses. It’s a common way for web-based (and other) applications to communicate with each other. REST is one way of defining an API. Many Puppet commands are addressable via API.

Most user experience concerns here concern consistency and documentation. If a DELETE command works in one context it should work in another. Documentation should be clear and easy to access.

Not all of Puppet has an API, and not all of the APIs are as good as we would like. This is important to us and we will continue to improve.

The Internal API

The Internal API is a way of using Ruby both to define resources and to interact with Puppet internals. We have good documentation about how to define resources with the Ruby API. Our own Daniel Pittman has been writing a
series
of
posts
about our new Faces API and how to interact with it. These are a great introduction to manipulating Puppet’s internals.

The Future

It’s a mistake to think of this work as magic or guru-driven design. In fact its most important component is connection with the real users of our products. Puppet Camp was fantastic for this; our upcoming PuppetConf (watch for more information Monday) will be another great opportunity. We’re also starting more robust in-house usability testing for new work.

Next up in this space: What is user experience on the CLI? This will be a detailed look at user interaction on the command line, and extraction of useful principles to inform our work.

Case Study: Swisstopo Chooses Puppet To Help Move Them To The Cloud

Posted on
By
michelle
in
Blog, Cloud, Community, DevOps, Opinion and Interview, Systems Management, Users
Responses
0 Comments

Swisstopo is Switzerland’s national cartography agency, providing customers with both physical and digital maps, many of which are also available to mobile phones with a GPS. Wanting to transition their infrastructure to the cloud, Swisstopo used Puppet to streamline their servers and increase uptime.

Hanspeter Christ, Deputy Head of the Federal Spatial Data Infrastructure (FSDI) within Swisstopo explains the benefits of Puppet:

“The biggest benefit from our investments is not from moving to the cloud, but more that we have ‘Puppetized’ our servers. We have become more efficient in provisioning servers so we can easily get 100 of them up and running in a very short time.”

To learn more, read the rest of the Swisstopo case study

Chicago DevOps Hackathon Advanced Track: Hit the Ground Running

Posted on
By
Jacob Helwig
in
Blog, Community, DevOps, Tips, Users
Responses
0 Comments

Back on Saturday, March 5, 2011, Teyo and I led a hackathon for the Chicago DevOps group. We divided the meetup into two groups. Teyo led a training session for people less familiar with Puppet and those wishing to learn how to write custom facts, and functions for use in their Puppet manifests. I led a developer boot-strapping and hacking on Puppet core session for people looking to get their hands dirty working on the Puppet code itself.

Before the hackathon, I’d setup 32-bit VirtualBox, and VMWare VMs with Git, Ruby, RVM, MySQL, and all of the Ruby gems needed to do development on Puppet, Puppet Dashboard, and Facter. After making sure that everyone had a copy of the VM, we walked through the end-to-end process of
working on an existing ticket from forking the repository on GitHub to submitting code to the developer mailing list and updating the ticket. All of what ended up being in the end-to-end walk-through is covered in the Development Lifecycle wiki document, but it’s always nice to see it done “live.”

We started with ticket #6513, since it was a pretty simple code change, and would provide a pretty good example of how to write some tests for the code change we were doing. We ended up using ruby-debug to help track down the bug, and to make sure the suspected fix would, indeed, fix the problem. When it came to testing what we’d changed we also renaming an existing test to better describe what it was testing, and ended up with a two commit patch series to address the bad test name, and to handle our fix with the new test. After mailing the patches out to the puppet-dev mailing list, pushing the topic branch out to my fork on GitHub, and updating the ticket to show that the fix was available in a testing branch and what the location of that was, it was just about time for lunch.

After lunch, we split up with each person grabbing tickets that looked interesting to them from a list I’d compiled of Puppet, Puppet Dashboard, and Facter tickets that looked doable in a single sitting. We ended up the day with submitted fixes for three issues (two in Puppet, and one in Facter, several tickets being triaged as likely having been fixed since they’d been reported, and one person tackling a larger issue, but running out of time polishing up his tests before we decided to call it a day.

I was extremely happy with how productive the developer boot-strapping portion of the hackathon was, and look forward to the possibility of additional future contributions from everyone that attended.