One of my very early frustrations with puppet was that it allows variables to be used when they were undefined. Primarily this bit me by not catching typos in variable names which were often very hard to track down. I was very pleased when Puppetlabs introduced a strict_variables mode which throws an error if a manifest attempts to use an undefined variable.

I recently need to check for the existence of a fact. Without strict_variables, this is straight-forward:

if $::some_fact {
  # do stuff here
}

If the fact "some_fact" exists, the variable is a non-empty string and evaluates as true in boolean context. If the fact doesn't exist, the variable is an empty string which evaluates as false in boolean context.

But, with strict_variables enforced, this throws an error:

Error: Undefined variable "::some_fact"; Undefined variable "some_fact" at line ...

The solution is to use the getvar function from stdlib:

if getvar('::some_fact') {
  # do stuff here
}

This works exactly the same as in the previous example, but doesn't throw an error if "some_fact" doesn't exist.

The team at bitly has written an http reverse proxy that provides authentication using Google's OAuth2 API. They write about it in a blog post.

The proxy is written in Go but builds to a single, statically-linked executable, ie. there are no complex run-time dependencies, which is great.

I've built an RPM for EL7 which also includes a sample systemd unit file, and sample configuration file. Both source and binary RPMs are available in my yum repo.

Additionally, I've create a puppet module that installs the RPM, creates a systemd service, and sets up an nginx front end to the proxy service. The module is available from the Puppetforge, and also on github.

I'd be interested in any feedback/comments/bug reports/pull requests.

I recently had need to install uwsgi on EL7 (CentOS 7, actually, but RHEL 7 will be the same).

I ended up rebuilding the uwsgi SRPM from Fedora 21 which was relatively straight-forward but it required a few tweaks to the .spec file. I also had to build a chain of dependencies: mongodb, perl-Cora, libecb, perl-EV, libev, zeromq, perl-BDB, perl-AnyEvent-BDB, perl-AnyEvent-AIO.

All packages (including SRPMs) are in my repo: http://repo.yo61.net/el/7/

I'm setting up a new puppet master running under passenger on CentOS 7 using packages from the puppetlabs and foreman repos. I used a fork of Stephen Johnson's puppet module to set everything up (with puppet apply). All went swimmingly, except I would see this error in the logs the first time the puppet master app loaded (ie. the first time it got a request):

[ 2014-11-07 23:22:13.2600 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] *** Phusion Passenger: no passenger_native_support.so found for the current Ruby interpreter. Compiling one (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)...
[ 2014-11-07 23:22:13.2600 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] # mkdir -p /usr/share/gems/gems/passenger-4.0.18/lib/phusion_passenger/locations.ini/buildout/ruby/ruby-2.0.0-x86_64-linux
[ 2014-11-07 23:22:13.2600 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] Not a valid directory. Trying a different one...
[ 2014-11-07 23:22:13.2600 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] -------------------------------
[ 2014-11-07 23:22:13.2600 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] # mkdir -p /var/lib/puppet/.passenger/native_support/4.0.18/ruby-2.0.0-x86_64-linux
[ 2014-11-07 23:22:13.2600 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] # cd /var/lib/puppet/.passenger/native_support/4.0.18/ruby-2.0.0-x86_64-linux
[ 2014-11-07 23:22:13.2600 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] # /usr/bin/ruby '/usr/share/gems/gems/passenger-4.0.18/ruby_extension_source/extconf.rb'
[ 2014-11-07 23:22:13.3048 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] /usr/bin/ruby: No such file or directory -- /usr/share/gems/gems/passenger-4.0.18/ruby_extension_source/extconf.rb (LoadError)
[ 2014-11-07 23:22:13.3156 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] Compilation failed.
[ 2014-11-07 23:22:13.3156 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] -------------------------------
[ 2014-11-07 23:22:13.3157 2603/7f1a0660e700 Pool2/Spawner.h:159 ]: [App 2643 stderr] Ruby native_support extension not loaded. Continuing without native_support.

I double checked, and I do have the native libs installed – they're in the rubygem-passenger-native-libs rpm – the main library is in /usr/lib64/gems/ruby/passenger-4.0.18/native/passenger_native_support.so.

Digging in the passenger code, it tries to load the native libs by doing:

require 'native/passenger_native_support'

If I hacked this to:

require '/usr/lib64/gems/ruby/passenger-4.0.18/native/passenger_native_support'

then it loaded correctly.

It seems that /usr/lib64/gems/ruby/passenger-4.0.18 is not in the ruby load path.

Additional directories can be added to the ruby load path by setting an environment variable, RUBYLIB.

To set RUBYLIB for the apache process, I added the following line to /etc/sysconfig/httpd and restarted apache:

RUBYLIB=/usr/lib64/gems/ruby/passenger-4.0.18

The passenger native libraries now load correctly.

I was writing some basic RSpec tests for a puppet module this morning, methodically adding in fixtures and hiera data items to get the module to compile under the spec tests.

Then I hit this error:

Failures:

1) profile_puppet::master supported operating systems profile_puppet::master class without any parameters on redhat 6.4 should compile into a catalogue without dependency cycles
Failure/Error: it { should compile.with_all_deps }
NoMethodError:
undefined method `groups' for nil:NilClass
# ./spec/classes/init_spec.rb:36:in `block (5 levels) in '

Uh oh, that doesn't look good. I did what I always do in such circumstances and googled the error message: puppet NoMethodError: undefined method `groups' for nil:NilClass. The first hit was https://tickets.puppetlabs.com/browse/PUP-1547 which describes my situation completely (I am testing for RHEL 6.4 on OSX).

What's even better is that the ticket was updated 3 days ago with a pull request that fixes the issue. I applied the change locally, it worked perfectly, and I was able to complete my task.

Try doing that with proprietary software.

In his talk at Puppetconf 2013, James Fryman mentioned a blog post by James White which contains a list of guidelines for management which has come to be known as the jameswhite manifesto.

Here’s the same list but unconstrained by a fixed-width text box so you can actually read it. 🙂

Rules

On Infrastructure

  • There is one system, not a collection of systems.
  • The desired state of the system should be a known quantity.
  • The “known quantity” must be machine parseable.
  • The actual state of the system must self-correct to the desired state.
  • The only authoritative source for the actual state of the system is the system.
  • The entire system must be deployable using source media and text files.

On Buying Software

  • Keep the components in the infrastructure simple so it will be better understood.
  • All products must authenticate and authorize from external, configurable sources.
  • Use small tools that interoperate well, not one “do everything poorly” product.
  • Do not implement any product that no one in your organization has administered.
  • “Administered” does not mean saw it in a rigged demo, online or otherwise.
  • If you must deploy the product, hire someone who has implemented it before to do so.

On Automation

  • Do not author any code you would not buy.
  • Do not implement any product that does not provide an API.
  • The provided API must have all functionality that the application provides.
  • The provided API must be tailored to more than one language and platform.
  • Source code counts as an API, and may be restricted to one language or platform.
  • The API must include functional examples and not requre someone to be an expert on the product to use.
  • Do not use any product with configurations that are not machine parseable and machine writeable.
  • All data stored in the product must be machine readable and writeable by applications other than the product itself.
  • Writing hacks around the deficiencies in a product should be less work than writing the product’s functionality.

In general

  • Keep the disparity in your architecture to an absolute minimum.
  • Use Set Theory to accomplish this.
  • Do not improve manual processes if you can automate them instead.
  • Do not buy software that requires bare-metal.
  • Manual data transfers and datastores maintained manually are to be avoided.

I'm a big fan of provisioning tools, particularly puppet.

Sometimes I just want to quickly throw a clean install on a new machine that I can then use to provision other machines (and even to re-configure the puppetmaster).

So, I wrote a script to do just that. The only requirement is a minimal install of your favourite CentOS/Red Hat/Fedora OS and the script will do the rest.

It's available from github: https://github.com/robinbowes/puppet-server-bootstrap

I recently offered to help out with the hosting of a WordPress  site. It’s currently hosted somewhere with no shell access – just ftp – and there are a lot of images to transfer.

I quickly figured out I could use wget to mirror the site, using something like:

wget -m ftp://username:password@example.com

However, this broke in this case because the username for the site contained an @ character (the username was user@example.com).

Turns out the solution was to encode the special chars using HTML notation. This is the command that did the trick:

wget -m ftp://user%40example.com:password@example.com

This is one of those “dead easy so why so hard” issues.

I use chrome on Fedora 18 on my home desktop. I have put up with a non-working java plugin for some time (to be honest, I’ve not been to bothered given java’s history of security issues).

Here’s how to enable the java plugin under chrome on Fedora 18 using icedtea (openjdk).

sudo yum install icedtea-web
sudo mkdir -p /usr/lib64/firefox/plugins
sudo ln -s /usr/lib64/IcedTeaPlugin.so /usr/lib64/firefox/plugins/libjavaplugin.so

Now restart chrome and go here to test the java plugin now works.