Adding file dependencies to existing service

233 views
Skip to first unread message

Justin

unread,
Jul 23, 2012, 5:09:01 PM7/23/12
to puppet...@googlegroups.com
Hi all,

I'm trying to configure Puppet to allow the creation of multiple memcached instances on a system. However, I'm running into the message that only subclasses can override parameters. Perhaps I'm going about this the wrong way, or maybe I just have something slightly wrong. Any advice is welcome.


class memcached {
    package { 'memcached': ensure => present }

    # do not want basic configuration
    file { '/etc/memcached.conf': ensure => absent }

    service { 'memcached':
        ensure  => running,
        enable  => true,
        require => Package['memcached'],
    }
}

define memcached::instance () {
    include memcached

    $conf = "/etc/memcached_${name}.conf"

    file { $conf: ensure => present }

    Service['memcached'] { require +> File[$conf] }
}

# create first instance in file /etc/memcached_en.conf
memcached::instance { 'en': }

The other thing I'd like to do is have Service['memcached'] set to NOT start unless there is at least one instance, i.e. not start until after the first instance's config file is in place, but that's not a showstopper.

Thanks,
Justin

Christopher Wood

unread,
Jul 23, 2012, 5:33:31 PM7/23/12
to puppet...@googlegroups.com
(inline)

On Mon, Jul 23, 2012 at 02:09:01PM -0700, Justin wrote:
> Hi all,
> I'm trying to configure Puppet to allow the creation of multiple memcached
> instances on a system. However, I'm running into the message that only
> subclasses can override parameters. Perhaps I'm going about this the wrong
> way, or maybe I just have something slightly wrong. Any advice is welcome.
> class memcached {
>     package { 'memcached': ensure => present }
>     # do not want basic configuration
>     file { '/etc/memcached.conf': ensure => absent }
>     service { 'memcached':
>         ensure  => running,
>         enable  => true,
>         require => Package['memcached'],
>     }
> }
> define memcached::instance () {
>     include memcached
>     $conf = "/etc/memcached_${name}.conf"
>     file { $conf: ensure => present }
>     Service['memcached'] { require +> File[$conf] }

This bit is a problem because all defines will declare Service['memcached'] and thus you'll get spammed with duplicate definitions. I solved this by using multiple daemons, useful to me because I want to be able to kill a daemon in an emergency without affecting more than one service. Another generic technique I've found useful is to have several classes in my module, for instance:

1) thing::software class (installs the defaults file per below, installs the package, installs the init script)
2) thing::extraconfig define (includes thing::software, throw a config file in /etc/thing.d/, something inside this notifies the service)
3) thing::service class (includes thing:;software, declares service { 'thing': }, basically exists so the service is separate from the software)

In your manifest where you call all these, you would have to ensure that thing::extraconfig is declared before thing::service.

(Just food for thought.)

> }
> # create first instance in file /etc/memcached_en.conf
> memcached::instance { 'en': }
> The other thing I'd like to do is have Service['memcached'] set to NOT
> start unless there is at least one instance, i.e. not start until after
> the first instance's config file is in place, but that's not a
> showstopper.

By my experimentation, memcached will be started by the postinstall scripts when you install the deb/rpm. One technique I've found useful (on Ubuntu/Debian) is to declare file { "/etc/default/$software": content => "start=no" } before installing said software. Apt won't overwrite the defaults file so the daemon won't start, and you can lay down a custom init script (which doesn't check the defaults file) after your config files are installed.

Here's how I solved the memcached thing to pop up multiple memcached daemons (obviously derived from https://github.com/saz/puppet-memcached):

class memcached::orig_off {

$classname = 'memcached'

package { $classname:
ensure => installed,
}

service { $classname:
ensure => stopped,
enable => false,
hasrestart => true,
hasstatus => true,
require => Package['memcached'],
}

}

define memcached::daemon ( $max_memory = false, $listen_ip = '0.0.0.0', $port = '11211', $max_connections = '8192' ) {

$classname = 'memcached'
$filesource = "puppet:///modules/$classname"

case $::operatingsystem {
ubuntu, debian: {
$user = 'nobody'
$mconfdir = '/etc/monit/conf.d'
}
centos, redhat: {
$user = 'memcached'
$mconfdir = '/etc/monit.d'
}
default: {
fail("Unsupported platform: ${::operatingsystem}")
}
}

$service1 = "memcached${port}"
$config1 = "/etc/memcached${port}.conf"
$config1template = "$classname/memcached_sp.conf.erb"
$init1 = "/usr/local/sbin/start-memcached${port}"
$init1template = "$classname/start_memcached.erb"
$init2 = "/etc/init.d/memcached${port}"
$init2template = "$classname/init_memcached.erb"
$mfile1 = "$mconfdir/${classname}${port}"
$mfile1template = "$classname/memcached_monit.erb"
$logfile = "/var/log/memcached${port}.log"

include memcached::orig_off

file { $init1:
content => template($init1template),
mode => 744,
}

file { $init2:
content => template($init2template),
mode => 744,
}

file { $config1:
content => template($config1template),
require => Class['memcached::orig_off'],
}

service { $service1:
ensure => running,
enable => true,
hasrestart => true,
hasstatus => false,
require => [File[$init1], File[$init2], File[$config1]],
subscribe => File[$config1],
}

file { $mfile1:
content => template($mfile1template),
mode => 600,
require => Service[$service1],
}

}


> Thanks,
> Justin
>
> --
> You received this message because you are subscribed to the Google Groups
> "Puppet Users" group.
> To view this discussion on the web visit
> [1]https://groups.google.com/d/msg/puppet-users/-/fic-AkDAfAoJ.
> To post to this group, send email to puppet...@googlegroups.com.
> To unsubscribe from this group, send email to
> puppet-users...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/puppet-users?hl=en.
>
> References
>
> Visible links
> 1. https://groups.google.com/d/msg/puppet-users/-/fic-AkDAfAoJ

Justin

unread,
Jul 23, 2012, 8:44:01 PM7/23/12
to puppet...@googlegroups.com, christop...@pobox.com
Chris,

Thanks for your  response. Your post got me thinking about a different approach that I'm surprised I didn't think of in the first place. I do prefer to have a single service handling multiple daemons, but I also realized I should be using Hiera for this. So I'm now defining a hash in Hiera on a per-node basis (i.e. %{fqdn}.yaml) like so:

memcached_instances:
  xx: { tcp_port: '11211', max_memory: '512' }
  yy: { tcp_port: '11212', max_memory: '512' }
  zz: { tcp_port: '11213', max_memory: '512' }

and here's what I've boiled my class down to:

class memcached {

    $instances      = hiera_hash('memcached_instances')
    $instance_names = split(inline_template('<%= instances.keys.join(",") %>'), ',')

    package { 'memcached':
        ensure => present
    }

    file { '/etc/memcached.conf':
        ensure  => absent,
        require => Package['memcached'],
    }

    define memcached::instance ( $instance_name = $title ) {
        $log_file        = "/var/log/memcached-${instance_name}.log"
        $user            = 'memcache'
        $max_connections = '1024'

        $tcp_port        = $memcached::instances[$instance_name]['tcp_port']
        $max_memory      = $memcached::instances[$instance_name]['max_memory']

        file { "/etc/memcached_${instance_name}.conf":
            ensure  => present,
            content => template('memcached/etc/memcached.conf.erb'),
        }
    }

    memcached::instance { $instance_names:
        require => Package['memcached'],
        notify  => Service['memcached'],
    }

    service { 'memcached':
        ensure     => running,
        enable     => true,
        hasrestart => true,
        hasstatus  => false,
        require    => Package['memcached'],
    }

}

It could use some work in how it handles other values in the templates, but it seems to work nicely so far and should scale well.

Thanks again for taking the time to post your thoughts and code!

Justin
>    puppet-users+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages