Set sysctl.conf parameters with Puppet

This was a breeze in CFEngine... But I'm in a Puppet environment now, and need to be able to assign/ensure/check certain sysctl.conf variables. In the CFEngine world, I could simply check for specific lines within a config file... I've found a small reference to a sysctl module on the Puppet wiki and a project in github that appears to do what I want.

But neither are really documented well. I'm simply looking for a way to edit a couple of values like net.core.rmem_default and net.core.wmem_max. In the format of the project hosted on github, the config in my init.pp manifest should look like:

class sysctl {

sysctl::value {
        "net.core.rmem_default": value => "9000000";
        "net.core.wmem_default": value => "9000000";
        "net.core.rmem_max": value => "16777216";
        "net.core.wmem_max": value => "16777216";
        }
}

Going through forums and mailing lists, there seems to be confusion over the difference between Puppet plugins and modules. The terms are almost used interchangeably... I ended up needing to enable pluginsync on my clients in order to get past some hairy errors. I thought this was a module!

The current client errors:

info: Loading downloaded plugin /var/lib/puppet/lib/puppet/type/sysctl.rb
info: Loading downloaded plugin /var/lib/puppet/lib/puppet/provider/sysctl/parsed.rb
err: Could not retrieve catalog from remote server: Error 400 on SERVER: Puppet::Parser::AST::Resource failed with error 
ArgumentError: Invalid resource type sysctl::value at /var/lib/puppet/base/modules/sysctl/manifests/init.pp:12 on node shimano.deore.abc.net
    warning: Not using cache on failed catalog
    err: Could not retrieve catalog; skipping run

Any thoughts on how to accomplish this with the least amount of pain?

Edit: Am I affected by this bug?

Edit: Fixed using Augeas library as suggested by Jeff Ferland and from the Puppet wiki.

I created a sysctl module...

class sysctl {

  # nested class/define
  define conf ( $value ) {

    # $name is provided by define invocation

    # guid of this entry
    $key = $name

    $context = "/files/etc/sysctl.conf"

     augeas { "sysctl_conf/$key":
       context => "$context",
       onlyif  => "get $key != '$value'",
       changes => "set $key '$value'",
       notify  => Exec["sysctl"],
     }

  }

   file { "sysctl_conf":
      name => $operatingsystem ? {
        default => "/etc/sysctl.conf",
      },
   }

   exec { "/sbin/sysctl -p":
      alias => "sysctl",
      refreshonly => true,
      subscribe => File["sysctl_conf"],
   }

}

...and another module to set the relevant settings...

class prod_sysctl {

include sysctl

sysctl::conf {

  # increase PID rollover value
  "kernel.pid_max": value =>  "1048576";
  }
}

Solution 1:

Specific answer: Immediately speaking, you're calling sysctl::value, but value isn't declared in your sysctl class. See this example that uses a sysctl::conf declaration. Without the define value, there is no sysctl::value subclass for you to call.


General answer and guidance: The Augeas construct (see also its type reference documentation) that is part of current versions of Puppet allows maintaining lines in a configuration file and even respects context, so it can manage files such as a git configuration. The example below is both to demonstrate functionality and to point you to a great reference collection of Puppet configs -- the live configuration store for Wikipedia servers.

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = https://gerrit.wikimedia.org/r/p/operations/puppet
[branch "production"]
    remote = origin
    merge = refs/heads/production

One simple example from the above configuration documentation would be this:

augeas { "sshd_config":
 context => "/files/etc/ssh/sshd_config",
  changes => [
    "set PermitRootLogin no",
  ],
}

So, if you want to manage your /etc/sysctl.conf, enter the following:

augeas { "sysctl":
 context => "/files/etc/sysctl.conf",
  changes => [
    "set kernel.sysrq = 0",
    #and whatever other lines are interesting to you
  ],
}

The Augeas example also has a construct for a sysctl class based on Augeus that is similar to what you posted in your question, so that may also shed some light.

Solution 2:

I've used this module in the past with RHEL5: puppet-sysctl

To use it, you'll have to install the module to your modules folder (probably /etc/puppet/modules/sysctl) include the class on your node: (include sysctl) and then call the def resource like this:

class s_sysctl::rhel_defaults {
    include sysctl

    # Controls IP packet forwarding
    sysctl::set_value { "net.ipv4.ip_forward": 
                         value => 0 
    }

    # Controls source route verification
    sysctl::set_value { "net.ipv4.conf.default.rp_filter": value => 1 }
}

So you might be wondering, where does this code actually go? I like to organize my puppet tree like this:

site.pp -> nodes.pp -> roles.pp -> /etc/puppet/site-modules/s_sysctl -> /etc/puppet/modules/sysctl

So that way, site-modules contains hiera data, or tunables, and the modules stay generic, plugable and "modular".