Entries in puppet (1)

Monday
Jul302012

Frustrating little nuance when using puppet exec directive

I've been building puppet configuration for CloudStack's Devcloud environment recently, and I ended up spending a ton of time arguing with the configuration.  One of the most annoying behaviours that I ran into are some very specific requirements about executing shell scripts within a puppet "exec" type.

I started with this shell script (configebtables.sh):

mac=`/sbin/ifconfig xenbr0 |/bin/grep HWaddr |/usr/bin/awk '{print $5}'`
/sbin/ebtables -I FORWARD -d ! $mac -i eth0 -p IPV4 --ip-prot udp --ip-dport 67:68 -j DROP

Then I added these directives to my puppet manifest:

file { '/tmp/configebtables.sh':
 ensure  => 'file',
 source  => 'puppet:///modules/puppet-devcloud/configebtables.sh',
 group   => '0',
 mode    => '777',
 owner   => '0',
 }

exec { "/tmp/configebtables.sh":
 require => [
  File['/tmp/configebtables.sh'],
  Service['ebtables']
 ],
 subscribe => Package['ebtables'],
 refreshonly => true,
 cwd       => '/',
 path      => '/sbin/:/usr/bin/:/bin',
}

That looks like it shouldn't be a problem, right? Wrong.

Here's what you get out of puppet when it's run:

notice: /Stage[main]/Puppet-devcloud/File[/tmp/configebtables.sh]/ensure: defined content as '{md5}1291473c3c5dc9108157b9fdcf2706b9'
err: /Stage[main]/Puppet-devcloud/Exec[/tmp/configebtables.sh]: Failed to call refresh: /tmp/configebtables.sh returned 1 instead of one of [0] at /etc/puppet/modules-0/puppet-devcloud/manifests/init.pp:60

Natuarally, I tested the script manually, and confirmed that the exit code is consistently coming back as 0. Nothing obvious stood out in the puppet documentation either. I added an "exit 0" line to the end of the script, and it still reported an exit code of 1. As far as I was concerned, puppet was getting confused about the actual return code.

It's not confused though. In actuality, it turns out that you really need to specify "#!/bin/sh" (or other appropriate shell env) at the top of any script that you'll be calling via an "exec" directive.

OK, perhaps this isn't all that silly when you think about how to "properly" write a robust shell script... But now I know.