Yes! Of course there is! Here’s the money shot, first, so if you’re just looking for copypasta, you can move on.
node default {
package { 'rubygems':
ensure => installed,
}
exec { 'gem install rspec-puppet > /tmp/rspec.out':
path => '/usr/bin',
creates => '/var/lib/gems/1.8/gems/rspec-puppet-0.1.3/',
require => Package['rubygems'],
}
}
OK, so what’s that all about?
What it does
It installs the package named rubygems which, on at least some Debian-ish systems, provides the ‘gem’ command, beloved of Rubyists and with which I’m attempting to become better acquainted THEN it runs a command to install the rspec-puppet gem, IF the system doesn’t already have version 0.1.3 of the gem installed in a ruby version 1.8 environment. It does these things if you put it onto a system which has puppet installed and execute the command ‘sudo puppet apply <file>’ on newer puppet installs or just ‘sudo puppet <file>’ on older puppet installs.
Interestingly, this is the second version of this manifest. The first lacked the require attribute and so when I ran it on my test system, it failed to execute the gem install, first, and then installed the rubygems package. Puppet is tricky like that and if you require things happen in a certain order, you have to make that happen. You could consider that a strength or an annoyance; I didn’t think much about it until I saw a presentation by Jason Wright at Puppetcamp 2010 where he talked about how his group had designed their Puppet manifests to run once and if a second run introduced a change, it was considered an error.
Why do this?
So continuing with my simplest thing iteration of using AWS, I thought I’d try to bootstrap up a masterless Puppet environment. Why? Well, because I have no idea what my environment will look like. At this point I should probably emphasize that all of this is for my own personal AWS stuff and while I do use Puppet at my dayjob and I do use AWS at my dayjob, my usage of both is quite a bit different, there.
More specifically, we have carved out essentially a standard-if-evolving application stack and put infrastructure in place to support that but here I’m just sort of dabbling with ideas. One of those ideas is the idea of running Puppet without a Puppetmaster node or nodes.
It used to be a somewhat heretical idea to do without a Puppetmaster, though I gather PuppetLabs now fully embraces the idea, which is good. While having a central Puppetmaster has some advantages (centralized source of truth, centralized reporting), it has (for me, in AWS) some disadvantages (requires a dedicated persistent node, requires managing The Cert Situation, potentially requires special scaling considerations). There are many many use cases where running a Puppetmaster is brilliant idea.
But if you don’t run one, you trade that for needing to solve some things on your own.
The problems I’m solving right now are ‘where does a node get its catalog’ (my answer of the moment: github) and ‘how does the node know what manifests to apply’ (maotm: a manual application via puppet agent invocations). Neither of these are yet well-solved by me, I’d say, but I’m bootstrapping to something which I suspect will look more like ‘catalogs live in S3, the nodes use s3fs to get them, instance tags are used to decide which manifests to apply’. But I think I’m on the right track by writing manifests which refer to node default, because now I don’t have to worry about updating if my instance identifier changes.
Oh, and the whole point of this stupid manifest is that now I can spin up an instance to develop my Puppet catalog on and get ready to test my Puppet manifests. I haven’t quite convinced myself that I should write a test to test this manifest which sets up the ability to test a manifest (y0, d4wg) but doing so would have a sickly sweet kind of self-referentialism to it.