diff --git a/Gemfile b/Gemfile index e2f4f26..e8ffc24 100644 --- a/Gemfile +++ b/Gemfile @@ -1,17 +1,15 @@ source 'https://rubygems.org' group :development, :test do - gem 'rake' gem 'rspec-puppet' gem 'metadata-json-lint' gem 'puppetlabs_spec_helper' - gem 'puppet-lint', :git => 'https://github.com/rodjek/puppet-lint.git' + gem 'puppet-lint', '>= 1.0', '< 3.0' gem 'puppet-lint-absolute_classname-check' gem 'puppet-lint-alias-check' gem 'puppet-lint-empty_string-check' gem 'puppet-lint-file_ensure-check' gem 'puppet-lint-file_source_rights-check' - gem 'puppet-lint-fileserver-check' gem 'puppet-lint-leading_zero-check' gem 'puppet-lint-spaceship_operator_without_tag-check' gem 'puppet-lint-trailing_comma-check' @@ -29,4 +27,15 @@ end # rspec must be v2 for ruby 1.8.7 if RUBY_VERSION >= '1.8.7' and RUBY_VERSION < '1.9' gem 'rspec', '~> 2.0' + gem 'rake', '~> 10.0' +else + gem 'rake' +end + +if RUBY_VERSION < '2.0' + # json 2.x requires ruby 2.0. Lock to 1.8 + gem 'json', '~> 1.8' + gem 'json_pure', '~> 1.0' +else + gem 'json' end diff --git a/README.md b/README.md index 864ba40..14e8d19 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,38 @@ Manage user and group limits via Puppet This module manages the limits of the PAM module pam_limits. +It creates files in `/etc/security/limits.d` and does not manage the file `/etc/security/limits.conf` + ## How to use -`include ::limits` + +### Set limits using title pattern: + +```puppet + limits::limits{'*/nofile': + hard => 1048576, + soft => 1048576, + } + limits::limits{'root/nofile': both => 1048576; } +``` + +### Using hiera + +Puppet: + +```puppet + include ::limits +``` + +Hiera: + +```yaml + limits::entries: + 'root/nofile': + both: 1048576 + '*/memlock': + both: unlimited +``` ## Compatibility @@ -16,7 +45,7 @@ parser) and v4 with Ruby versions 1.8.7 (Puppet v3 only), 1.9.3, 2.0.0 and ### Purge limits.d directory -The class `limits` will purge the limit.d directory as default. +The class `limits` will purge the limits.d directory as default. You can explicit change this with the parameter `purge_limits_d_dir` or just do not call the class. @@ -31,7 +60,7 @@ or just do not call the class. soft => 16384, } ``` -### Do NOT purge limits.d directory explicit +### Do NOT purge limits.d directory explicitly ```puppet class { 'limits': @@ -57,3 +86,16 @@ or just do not call the class. } ``` One of hard, soft or both must be set! + +### Do not manage /etc/security/limits.d + +In an effort to make this module compatible with similar modules, e.g. +[puppet-module-pam](https://github.com/ghoneycutt/puppet-module-pam), management +of `/etc/security/limits.d` can be disabled by way of the `manage_limits_d_dir` +class parameter: + +```puppet +class { 'limits': + manage_limits_d_dir => false, +} +``` diff --git a/manifests/init.pp b/manifests/init.pp index c0ef7d2..d93f55c 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,17 +1,20 @@ # == Class: limits # class limits ( - $purge_limits_d_dir = true, - $entries_hash = hiera_hash(limits::entries, {}) + $purge_limits_d_dir = true, + $entries_hash = hiera_hash(limits::entries, {}), + $manage_limits_d_dir = true, ) inherits ::limits::params { - file { $limits::params::limits_dir: - ensure => 'directory', - owner => 'root', - group => 'root', - force => true, - purge => $purge_limits_d_dir, - recurse => true, + if $manage_limits_d_dir == true { + file { $limits::params::limits_dir: + ensure => 'directory', + owner => 'root', + group => 'root', + force => true, + purge => $purge_limits_d_dir, + recurse => true, + } } ### Create instances for integration with Hiera diff --git a/manifests/limits.pp b/manifests/limits.pp index 4c85d33..52b8aa9 100644 --- a/manifests/limits.pp +++ b/manifests/limits.pp @@ -1,20 +1,57 @@ # == Define: limits::limits # +# Parameters: +# $title - should be of the form user/limit_type if $user and $limt_type are not present +# $user - user +# $limit_type - limit type / item +# $hard - hard limit +# $soft - soft limit +# $both - set both limits (-) +# +# Example: +# limits::limits{'*/nofile': +# hard => 12345, +# soft => 123, +# } +# limits::limits{'root/nofile': both => 1234; } +# +# Manages: +# limit file in limits.d with the values provided define limits::limits( - $user, - $limit_type, - $ensure = present, - $hard = undef, - $soft = undef, - $both = undef + $ensure = present, + $user = undef, + $limit_type = undef, + $hard = undef, + $soft = undef, + $both = undef, ) { - include ::limits::params + include ::limits + + # minimal validation + unless $hard or $soft or $both { fail('$hard, $soft or $both is required') } + unless $title =~ /\// { + unless $user and $limit_type { fail('when not using the title pattern, $user and $limit_type are required') } + } + + $key = split($title, '/') + $real_user = $user ? { + undef => $key[0], + default => $user, + } + $real_type = $limit_type ? { + undef => $key[1], + default => $limit_type, + } - if $name =~ /\.conf$/ { - $target_file = "${limits::params::limits_dir}${name}" + if $title =~ /\.conf$/ { + $target_file = "${limits::params::limits_dir}/${title}" } else { - $target_file = "${limits::params::limits_dir}${name}.conf" + if $real_user == '*' { + $target_file = "${limits::params::limits_dir}/default_${real_type}.conf" + } else { + $target_file = "${limits::params::limits_dir}/${real_user}_${real_type}.conf" + } } file { $target_file: diff --git a/manifests/params.pp b/manifests/params.pp index 25eee2c..0e0698f 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -1,7 +1,7 @@ class limits::params { case $::osfamily { - 'Debian','Gentoo','RedHat': { - $limits_dir = '/etc/security/limits.d/' + 'Debian','Gentoo','RedHat','Suse': { + $limits_dir = '/etc/security/limits.d' } default: { fail("Unsupported platform: ${::osfamily}/${::operatingsystem}") diff --git a/metadata.json b/metadata.json index 0cd74f6..07bc414 100644 --- a/metadata.json +++ b/metadata.json @@ -1,6 +1,6 @@ { "name": "saz-limits", - "version": "2.3.0", + "version": "2.4.0", "author": "saz", "summary": "Manage user limits via puppet", "description": "Manage user limits via puppet", @@ -26,6 +26,9 @@ }, { "operatingsystem": "Gentoo" + }, + { + "operatingsystem": "Suse" } ], "requirements": [ diff --git a/spec/classes/limits_spec.rb b/spec/classes/limits_spec.rb index bb06150..bf05597 100644 --- a/spec/classes/limits_spec.rb +++ b/spec/classes/limits_spec.rb @@ -3,6 +3,7 @@ let :default_params do { + :manage_limits_d_dir => true, :purge_limits_d_dir => true } end @@ -10,9 +11,12 @@ [ {}, { :purge_limits_d_dir => false + }, + { + :manage_limits_d_dir => false } ].each do |param_set| - describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do + describe "when #{param_set == {} ? "using default" : "specifying #{param_set}"} class parameters" do let :param_hash do default_params.merge(param_set) @@ -22,7 +26,7 @@ param_set end - ['Debian', 'Gentoo', 'RedHat'].each do |osfamily| + ['Debian', 'Gentoo', 'RedHat', 'Suse'].each do |osfamily| let :facts do { @@ -34,14 +38,19 @@ it { should contain_class('limits::params') } - it { should contain_file('/etc/security/limits.d/').with( - 'ensure' => 'directory', - 'owner' => 'root', - 'group' => 'root', - 'force' => true, - 'recurse' => true, - 'purge' => param_hash[:purge_limits_d_dir] - )} + it do + if params[:manage_limits_d_dir] == false + should_not contain_file('/etc/security/limits.d') + else + should contain_file('/etc/security/limits.d').with( + 'ensure' => 'directory', + 'owner' => 'root', + 'group' => 'root', + 'force' => true, + 'recurse' => true, + 'purge' => param_hash[:purge_limits_d_dir]) + end + end end end end diff --git a/spec/defines/limits_spec.rb b/spec/defines/limits_spec.rb index 088aa50..db163fd 100644 --- a/spec/defines/limits_spec.rb +++ b/spec/defines/limits_spec.rb @@ -1,6 +1,5 @@ require 'spec_helper' describe 'limits::limits', :type => :define do - let(:title) { 'username_nofile' } let(:filename) { '/etc/security/limits.d/username_nofile.conf' } let :facts do @@ -8,110 +7,163 @@ :osfamily => 'Debian' } end - - let :params do - { - :user => 'username', - :limit_type => 'nofile', - :ensure => 'present', - :hard => '16384', - :soft => '16384' - } - end - - describe "when creating a limits entry not ending in .conf" do - - it { should contain_limits__limits('username_nofile').with({ + context 'default' do + let(:title) { 'username_nofile' } + let :params do + { :user => 'username', :limit_type => 'nofile', :ensure => 'present', :hard => '16384', :soft => '16384' - }) - } - - it { should contain_file(filename).with({ - 'ensure' => 'present', - 'content' => "# Managed by Puppet\n\n# \nusername hard nofile 16384\nusername soft nofile 16384\n", - 'owner' => 'root', - 'group' => 'root', - }) - } - - end + } + end - describe "when creating a limits entry ending in .conf" do + describe "when creating a limits entry not ending in .conf" do + it { should compile.with_all_deps } + it { should contain_class('limits') } + it { should contain_limits__limits('username_nofile').with({ + :user => 'username', + :limit_type => 'nofile', + :ensure => 'present', + :hard => '16384', + :soft => '16384' + }) + } + it { should contain_file(filename).with({ + 'ensure' => 'present', + 'content' => "# Managed by Puppet\n\n# \nusername hard nofile 16384\nusername soft nofile 16384\n", + 'owner' => 'root', + 'group' => 'root', + }) + } + end - let(:title) { 'username_nofile.conf' } + describe "when creating a limits entry ending in .conf" do + let(:title) { 'username_nofile.conf' } + it { should contain_limits__limits('username_nofile.conf').with({ + :user => 'username', + :limit_type => 'nofile', + :ensure => 'present', + :hard => '16384', + :soft => '16384' + }) + } + it { should contain_file(filename).with({ + 'ensure' => 'present', + 'content' => "# Managed by Puppet\n\n# \nusername hard nofile 16384\nusername soft nofile 16384\n", + 'owner' => 'root', + 'group' => 'root', + }) + } + end - it { should contain_limits__limits('username_nofile.conf').with({ + describe "when removing an limits entry" do + let :params do + { :user => 'username', :limit_type => 'nofile', - :ensure => 'present', + :ensure => 'absent', :hard => '16384', :soft => '16384' - }) - } - - it { should contain_file(filename).with({ - 'ensure' => 'present', - 'content' => "# Managed by Puppet\n\n# \nusername hard nofile 16384\nusername soft nofile 16384\n", - 'owner' => 'root', - 'group' => 'root', - }) - } + } + end + it { should contain_file(filename).with({ + 'ensure' => 'absent', + 'content' => "# Managed by Puppet\n\n# \nusername hard nofile 16384\nusername soft nofile 16384\n", + 'owner' => 'root', + 'group' => 'root', + }) + } - end + end - describe "when removing an limits entry" do - let :params do - { - :user => 'username', - :limit_type => 'nofile', - :ensure => 'absent', - :hard => '16384', - :soft => '16384' + context "when creating a limits entry setting both limits" do + let :params do + { + :user => 'username', + :limit_type => 'nofile', + :ensure => 'present', + :both => '16384' + } + end + let(:title) { 'username_nofile.conf' } + it { should contain_limits__limits('username_nofile.conf').with({ + :user => 'username', + :limit_type => 'nofile', + :ensure => 'present', + :both => '16384' + }) + } + it { should contain_file(filename).with({ + 'ensure' => 'present', + 'content' => "# Managed by Puppet\n\n# \nusername - nofile 16384\n", + 'owner' => 'root', + 'group' => 'root', + }) } end - - it { should contain_file(filename).with({ - 'ensure' => 'absent', - 'content' => "# Managed by Puppet\n\n# \nusername hard nofile 16384\nusername soft nofile 16384\n", - 'owner' => 'root', - 'group' => 'root', - }) - } end - - context "when creating a limits entry setting both limits" do - - let :params do - { - :user => 'username', - :limit_type => 'nofile', - :ensure => 'present', - :both => '16384' + context "title pattern" do + + describe "default/nofile" do + let(:title) { '*/nofile' } + let :params do + { + :both => '16384' + } + end + it { should compile.with_all_deps } + it { should contain_file('/etc/security/limits.d/default_nofile.conf').with({ + 'ensure' => 'present', + 'content' => "# Managed by Puppet\n\n# \n* - nofile 16384\n", + 'owner' => 'root', + 'group' => 'root', + }) } end - let(:title) { 'username_nofile.conf' } - - it { should contain_limits__limits('username_nofile.conf').with({ - :user => 'username', - :limit_type => 'nofile', - :ensure => 'present', - :both => '16384' - }) - } - - it { should contain_file(filename).with({ - 'ensure' => 'present', - 'content' => "# Managed by Puppet\n\n# \nusername - nofile 16384\n", - 'owner' => 'root', - 'group' => 'root', - }) - } - + describe "root/nofile" do + let(:title) { 'root/nofile' } + let :params do + { + :hard => '12345' + } + end + it { should contain_file('/etc/security/limits.d/root_nofile.conf').with({ + 'ensure' => 'present', + 'content' => "# Managed by Puppet\n\n# \nroot hard nofile 12345\n", + 'owner' => 'root', + 'group' => 'root', + }) + } + end end + context "validation" do + describe "missing user" do + let(:title) { 'nofile' } + let :params do + { + :limit_type => 'nofile', + :both => '16384' + } + end + it { should compile.and_raise_error(/when not using the title pattern/) } + end + describe "missing type" do + let(:title) { 'nofile.conf' } + let :params do + { + :user => 'foo', + :both => '16384' + } + end + it { should compile.and_raise_error(/when not using the title pattern/) } + end + describe "missing limit" do + let(:title) { 'root/nofile' } + it { should compile.and_raise_error(/\$hard, \$soft or \$both is required/) } + end + end end diff --git a/templates/limits.erb b/templates/limits.erb index bff2f3c..4ea650f 100644 --- a/templates/limits.erb +++ b/templates/limits.erb @@ -2,12 +2,12 @@ # <% if @both then -%> -<%= "%-12s" % @user %> - <%= "%-14s" % @limit_type %> <%= @both %> +<%= "%-12s" % @real_user %> - <%= "%-14s" % @real_type %> <%= @both %> <% else -%> <% if @hard then -%> -<%= "%-12s" % @user %> hard <%= "%-14s" % @limit_type %> <%= @hard %> +<%= "%-12s" % @real_user %> hard <%= "%-14s" % @real_type %> <%= @hard %> <% end -%> <% if @soft then -%> -<%= "%-12s" % @user %> soft <%= "%-14s" % @limit_type %> <%= @soft %> +<%= "%-12s" % @real_user %> soft <%= "%-14s" % @real_type %> <%= @soft %> <% end -%> <% end -%>