8

I'm writing a script to automate setting up Puppet agent configuration files in Docker.

Basically, I need to ensure that the following section is in /etc/puppet/puppet.conf:

[agent]
server=$PUPPETMASTER_HOSTNAME
masterport=$PUPPETMASTER_PORT

What I've been doing so far in my Puppet agent runit script is this:

function write_puppet_config () {
    read -d '' puppet_config <<EOF
[agent]
server=$1
masterport=$2
EOF

    echo -e "$puppet_config" >> /etc/puppet/puppet.conf
}

# default puppet master port is 8410
test -z "$PUPPET_MASTER_TCP_PORT" && export PUPPET_MASTER_TCP_PORT="8410"

# if there is a puppet master host defined, rewrite the config to match
if [ ! -z "$PUPPET_MASTER_TCP_HOST" ]; then 
    write_puppet_config "$PUPPET_MASTER_TCP_HOST" "$PUPPET_MASTER_TCP_PORT"
fi

The problem should be pretty apparent. If the Puppet configuration already specifies the configuration, I'm just appending another [agent] section, which is bad.

I could just switch on conditional logic (ie: grep if it's there and then rewrite it with sed if it is), but is there a way to do an edit from the command line? I'd like to basically run a command which says "if there isn't an agent section, add it, and then make sure that server and masterport are set to the right values in that section."

I know that structured tools like this exist for XML, but what about INI-style files?

5
  • 2
    Use Perl and metacpan.org/pod/Config::IniFiles
    – choroba
    Jun 17, 2014 at 15:55
  • You should let puppet configure the puppet.conf. Just run with you master specified on the command line: puppet agent -t --server yourmaster.
    – jordanm
    Jun 17, 2014 at 15:55
  • @jordanm I'll probably actually end up doing that, but I'm still interested to see an actual solution for this. Jun 17, 2014 at 16:36
  • @choroba, if you submitted that as an answer with a working example, I'd probably accept it as an answer. Jun 17, 2014 at 16:45
  • Since your're already using Puppet, why not use Puppet for everything? The inifile Puppet module was made for this exact purpose.
    – emning
    Nov 9, 2014 at 15:38

3 Answers 3

25

Have a look at crudini, which is a shell tool designed for this

conf=/etc/puppet/puppet.conf
crudini --set "$conf" agent server "$PUPPET_MASTER_TCP_HOST"
crudini --set "$conf" agent masterport "$PUPPET_MASTER_TCP_PORT"

or a single atomic invocation like:

echo "
[agent]
server=$1
masterport=$2" |

crudini --merge /etc/puppet/puppet.conf
6

Here are a few script examples. These are bare minimum and don't bother with error checking, command line options, etc. I've indicated whether I've run the script myself to verify its correctness.

Ruby

Install the inifile rubygem for this script. This script is tested.

#!/usr/bin/env ruby
# filename: ~/config.rb

require 'inifile'

PUPPETMASTER_HOSTNAME='hello'
PUPPETMASTER_PORT='world'

ini = IniFile::load('/etc/puppet/puppet.conf')
ini['agent']['server'] = PUPPETMASTER_HOSTNAME
ini['agent']['masterport'] = PUPPETMASTER_PORT
ini.save

Usage:

$ chmod 700 ~/config.rb
$ sudo ~/config.rb     # or, if using rvm, rvmsudo ~/config.rb

Perl

Install Config::IniFiles using cpan or your OS package manager (if there is a package available). This script is untested as I've stopped using perl on my system. It may need a little work, and corrections are welcome.

#!/usr/bin/env perl
# filename: ~/config.pl

use Config::IniFiles;

my $PUPPETMASTER_HOSTNAME='perl';
my $PUPPETMASTER_PORT='1234';

my $ini = Config::IniFiles->new(-file => '/etc/puppet/puppet.conf');

if (! $ini->SectionExists('agent')) {
    $ini->AddSection('agent');
}

if ($ini->exists('agent', 'server')) {
    $ini->setval('agent', 'server', $PUPPETMASTER_HOSTNAME);
}
else {
    $ini->newval('agent', 'server', $PUPPETMASTER_HOSTNAME);
}

if ($ini->exists('agent', 'masterport')) {
    $ini->setval('agent', 'masterport', $PUPPETMASTER_PORT);
}
else {
    $ini->newval('agent', 'masterport', $PUPPETMASTER_PORT);
}

$ini->RewriteConfig();

Usage:

$ chmod 700 ~/config.pl
$ sudo ~/config.pl

awk

This script is more Bash and *nix friendly and uses a common utility of *nix OS's, awk. This script is tested.

#!/usr/bin/env awk
# filename: ~/config.awk

BEGIN {
    in_agent_section=0;
    is_host_done=0;
    is_port_done=0;
    host = "awk.com";
    port = "4567";
}

in_agent_section == 1 {
    if ($0 ~ /^server[[:space:]]*=/) {
        print "server="host;
        is_host_done = 1;
        next;
    }
    else if ($0 ~ /^masterport[[:space:]]*=/) {
        print "masterport="port;
        is_port_done = 1;
        next;
    }
    else if ($0 ~ /^\[/) {
        in_agent_section = 0;
        if (! is_host_done) {
            print "server="host;
        }
        if (! is_port_done) {
            print "masterport="port;
        }
    }
}

/^\[agent\]/ {
    in_agent_section=1;
}

{ print; }

Usage:

$ awk -f ~/config.awk < /etc/puppet/puppet.conf > /tmp/puppet.conf
$ sudo mv /tmp/puppet.conf /etc/puppet/puppet.conf
3

If you can afford to install external tools, than I would recommend Augeas - this is the only tool for working with config files you will ever need. It represents configs as a tree. Read more here.

1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .