Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

We're starting to use Puppet as a way of managing configuration across our various servers. We have a Portage repository with a few packages of our own, with each machine using Layman to manage the overlays.

It's easy enough to install packages in puppet, but how should we make sure Layman is configured? Is there a module out there?

share|improve this question
add comment

2 Answers

up vote 3 down vote accepted

I don't know the gentoo, portage or layman specifics, and I don't see any existing modules in the puppet module forge but from a quick look at some gentoo layman documentation it looks like it would be fairly straightforward to write it yourself with Puppet:

stage { "first": before => Stage[main] } # Set up first stage, before main

class layman { # "overlays"?
  package { "layman": ensure => present }
  # Then everything else (file, execs, whatever) to configure layman,
  # overlays, etc
  # Looks to me like you need to change /etc/make.conf, /etc/layman/layman.cfg
  # and write some execs that run "layman -a <overlay-name>"
  # depending on output of "layman -i <overlay-name>"
  # or possibly grepping /var/lib/layman/overlays.xmls
}

class{"layman": stage => "first"} # Set layman class to run in the first stage

Instead of using stages you could instead have require => Class[layman] on all the package statements that need it. Using require is more verbose; I'd use it if I only needed a few things, or if I was requiring a specific overlay. I believe you should generally avoid using requires that cross stage boundaries, however, as it's both redundant and likely to tickle weird bugs.

Alternate, depending on what you need, avoids stages and only does explicit require ordering. I do stuff like this with RHEL and yum repos:

# In a "layman" module.
class layman {
  [...]
}

define layman::overlay() {
  exec {
    "layman -a $name":
      require => Class[layman],
      creates => "/var/lib/layman/${name}",
  }
}

class layman::overlay::php {
  layman::overlay { "php": }
}

class layman::overlay::apache2 {
  layman::overlay { "apache2": }
}

class apache {
  include layman::overlay::apache2
  package { "apache2":
    ensure => present,
    require => Class[layman::overlay::apache2];
  }
  file { "/etc/apache2/conf.d/whatever.conf":
    source => "...",
    require => Package[apache2],
    notify => Service[apache2];
  }
  service { "apache2":
    ensure => running,
    enable => true,
    require => [ Package[apache2], File["/etc/apache2/conf.d/whatever.conf"] ];
  }

}

# "yoursite" module or "somephpapp" module
class yoursite::somephpapp {
  include apache
  include layman::overlay::php
  package { "somephpapp":
    ensure => present,
    require => [ Class[apache], Class[layman::overlay::php] ];
  }
  file {
    "/path/to/somephpapp.conf":
      source => "...",
      require => Package[somephpapp],
      notify => Service[apache2]; # probably not actually required, example
  }
}
share|improve this answer
add comment

Further to freiheit's answer, here's what I ended up with.

class packages-layman {
    Exec { path => '/usr/bin:/bin:/usr/sbin:/sbin', loglevel => 'debug' }

    package { 'app-portage/layman': ensure => 'installed' }

    file { '/etc/eix-sync.conf':
        ensure => present,
        content => '*',
    }

    line { 'layman-make.conf-overlay':
        file => '/etc/make.conf',
        line => 'source /var/lib/layman/make.conf',
    }

    exec { 'layman-list':
        command => 'layman -o "http://dev.mycompany.com" -L',
        require => [
            Package['app-portage/layman'],
            Service['openvpn']
        ],
    }

    exec { 'layman-my-overlay':
        command => 'layman -o "http://dev.mycompany.com" -a myoverlay',
        returns => [0,1],
        require => Exec['layman-list'],
    }

    exec { 'layman-eix-sync':
        command => 'eix-sync',
        require => [
            File['/etc/eix-sync.conf'],
            Line['layman-make.conf-overlay'],
            Exec['layman-my-overlay'],
        ],
    }
}

Note that the 'layman-list' exec is there to overcome what appears to be a bug in the version of layman on Gentoo that prevents overlays from working until they've been listed.

Puppet can choose to run commands in any random order, so the order of the various tasks is enforced with all the require entries. To make sure a task happens after this one, use a require like so:

package { 'app-misc/my-custom-package':
    ensure => 'installed',
    require => Exec['layman-eix-sync']
}

It needs this definition of line from the Puppet wiki to let you edit single lines of a bigger file:

define line($file, $line, $ensure = 'present') {
    case $ensure {
        default : { err ( "unknown ensure value ${ensure}" ) }
        present: {
            exec { "/bin/echo '${line}' >> '${file}'":
                unless => "/bin/grep -qFx '${line}' '${file}'"
            }
        }
        absent: {
            exec { "/usr/bin/perl -ni -e 'print unless /^\\Q${line}\\E\$/' '${file}'":
                onlyif => "/bin/grep -qFx '${line}' '${file}'"
            }
        }
    }
}
share|improve this answer
    
There is of course one problem with this solution: it runs eix-sync every time, which a typical puppet agent that means every half hour. That's way more often than is considered 'polite'. –  Marcus Downing Mar 21 '11 at 14:27
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.