diff --git a/manifests/conf.pp b/manifests/conf.pp index 7e0867d..f532af3 100644 --- a/manifests/conf.pp +++ b/manifests/conf.pp @@ -1,120 +1,120 @@ # Define: sudo::conf # # This module manages sudo configurations # # Parameters: # [*ensure*] # Ensure if present or absent. # Default: present # # [*priority*] # Prefix file name with $priority # Default: 10 # # [*content*] # Content of configuration snippet. # Default: undef # # [*source*] # Source of configuration snippet. # Default: undef # # [*sudo_config_dir*] # Where to place configuration snippets. # Only set this, if your platform is not supported or # you know, what you're doing. # Default: auto-set, platform specific # # Actions: # Installs sudo configuration snippets # # Requires: # Class sudo # # Sample Usage: # sudo::conf { 'admins': # source => 'puppet:///files/etc/sudoers.d/admins', # } # # [Remember: No empty lines between comments and class definition] define sudo::conf( $ensure = present, $priority = 10, $content = undef, $source = undef, $sudo_config_dir = undef, $sudo_file_name = undef ) { include ::sudo # Hack to allow the user to set the config_dir from the # sudo::config parameter, but default to $sudo::params::config_dir # if it is not provided. $sudo::params isn't included before # the parameters are loaded in. $sudo_config_dir_real = $sudo_config_dir ? { undef => $sudo::config_dir, $sudo_config_dir => $sudo_config_dir } # sudo skip file name that contain a "." $dname = regsubst($name, '\.', '-', 'G') if size("x${priority}") == 2 { $priority_real = "0${priority}" } else { $priority_real = $priority } # build current file name with path if $sudo_file_name != undef { $cur_file = "${sudo_config_dir_real}${sudo_file_name}" } else { $cur_file = "${sudo_config_dir_real}${priority_real}_${dname}" } # replace whitespace in file name $cur_file_real = regsubst($cur_file, '\s+', '_', 'G') Class['sudo'] -> Sudo::Conf[$name] if $::osfamily == 'RedHat' { if (versioncmp($::sudoversion, '1.7.2p1') < 0) { warning("Found sudo with version ${::sudoversion}, but at least version 1.7.2p1 is required!") } } if $content != undef { if is_array($content) { $lines = join($content, "\n") $content_real = "${lines}\n" } else { $content_real = "# This file is managed by Puppet; changes may be overwritten\n${content}\n" } } else { $content_real = undef } if $ensure == 'present' { $notify_real = Exec["sudo-syntax-check for file ${cur_file}"] } else { $notify_real = undef } file { "${priority_real}_${dname}": ensure => $ensure, path => $cur_file_real, owner => 'root', group => $sudo::params::config_file_group, mode => '0440', source => $source, content => $content_real, notify => $notify_real, } - exec {"sudo-syntax-check for file ${cur_file_real}": + exec {"sudo-syntax-check for file ${cur_file}": command => "visudo -c -f '${cur_file_real}' || ( rm -f '${cur_file_real}' && exit 1)", refreshonly => true, path => ['/bin', '/sbin', '/usr/bin', '/usr/sbin'], } } diff --git a/spec/defines/sudo_spec.rb b/spec/defines/sudo_spec.rb index 2b662d6..e52313b 100644 --- a/spec/defines/sudo_spec.rb +++ b/spec/defines/sudo_spec.rb @@ -1,130 +1,168 @@ require 'spec_helper' describe 'sudo::conf', :type => :define do let(:title) { 'admins' } let(:filename) { '10_admins' } let(:file_path) { '/etc/sudoers.d/10_admins' } let :facts do { :lsbdistcodename => 'wheezy', :operatingsystemmajrelease => '7', :operatingsystem => 'Debian', :osfamily => 'Debian', :puppetversion => '3.7.0' } end let :params do { :priority => 10, :content => '%admins ALL=(ALL) NOPASSWD: ALL', :sudo_config_dir => '/etc/sudoers.d/' } end describe 'when creating a sudo entry' do it do is_expected.to contain_sudo__conf('admins').with(:priority => params[:priority], :content => params[:content]) end it do is_expected.to contain_file(filename).with('ensure' => 'present', 'content' => "# This file is managed by Puppet; changes may be overwritten\n%admins ALL=(ALL) NOPASSWD: ALL\n", 'owner' => 'root', 'group' => 'root', 'path' => file_path, 'mode' => '0440') end it do is_expected.to contain_exec("sudo-syntax-check for file #{params[:sudo_config_dir]}#{params[:priority]}_#{title}").with('command' => "visudo -c -f '#{params[:sudo_config_dir]}#{params[:priority]}_#{title}' || ( rm -f '#{params[:sudo_config_dir]}#{params[:priority]}_#{title}' && exit 1)", 'refreshonly' => 'true') end it { is_expected.to contain_file(filename).that_notifies("Exec[sudo-syntax-check for file #{params[:sudo_config_dir]}#{params[:priority]}_#{title}]") } it { is_expected.not_to contain_exec("sudo-syntax-check for file #{params[:sudo_config_dir]}#{params[:priority]}_#{title}").that_requires("File[#{filename}]") } it { is_expected.not_to contain_file(filename).that_requires("Exec[sudo-syntax-check for file #{params[:sudo_config_dir]}#{params[:priority]}_#{title}]") } end describe 'when creating a sudo entry with single number priority' do let(:filename) { '05_admins' } let(:file_path) { '/etc/sudoers.d/05_admins' } let :params do { :priority => 5, :content => '%admins ALL=(ALL) NOPASSWD: ALL', :sudo_config_dir => '/etc/sudoers.d/' } end it do is_expected.to contain_sudo__conf('admins').with(:priority => params[:priority], :content => params[:content]) end it do is_expected.to contain_file(filename).with('ensure' => 'present', 'content' => "# This file is managed by Puppet; changes may be overwritten\n%admins ALL=(ALL) NOPASSWD: ALL\n", 'owner' => 'root', 'group' => 'root', 'path' => file_path, 'mode' => '0440') end it do is_expected.to contain_exec("sudo-syntax-check for file #{params[:sudo_config_dir]}0#{params[:priority]}_#{title}").with('command' => "visudo -c -f '#{params[:sudo_config_dir]}0#{params[:priority]}_#{title}' || ( rm -f '#{params[:sudo_config_dir]}0#{params[:priority]}_#{title}' && exit 1)", 'refreshonly' => 'true') end it { is_expected.to contain_file(filename).that_notifies("Exec[sudo-syntax-check for file #{params[:sudo_config_dir]}0#{params[:priority]}_#{title}]") } it { is_expected.not_to contain_exec("sudo-syntax-check for file #{params[:sudo_config_dir]}0#{params[:priority]}_#{title}").that_requires("File[#{filename}]") } it { is_expected.not_to contain_file(filename).that_requires("Exec[sudo-syntax-check for file #{params[:sudo_config_dir]}0#{params[:priority]}_#{title}]") } end + describe 'when creating a sudo entry with whitespace in name' do + let(:title) { 'admins hq' } + let(:filename) { '05_admins hq' } + let(:file_path) { '/etc/sudoers.d/05_admins_hq' } + + let :params do + { + :priority => 5, + :content => '%admins_hq ALL=(ALL) NOPASSWD: ALL', + :sudo_config_dir => '/etc/sudoers.d/' + } + end + + it do + is_expected.to contain_sudo__conf('admins hq').with(:priority => params[:priority], + :content => params[:content]) + end + + it do + is_expected.to contain_file(filename).with('ensure' => 'present', + 'content' => "# This file is managed by Puppet; changes may be overwritten\n%admins_hq ALL=(ALL) NOPASSWD: ALL\n", + 'owner' => 'root', + 'group' => 'root', + 'path' => file_path, + 'mode' => '0440') + end + + it do + is_expected.to contain_exec("sudo-syntax-check for file #{params[:sudo_config_dir]}0#{params[:priority]}_#{title}").with('command' => "visudo -c -f '#{file_path}' || ( rm -f '#{file_path}' && exit 1)", + 'refreshonly' => 'true') + end + + it { is_expected.to contain_file(filename).that_notifies("Exec[sudo-syntax-check for file #{params[:sudo_config_dir]}0#{params[:priority]}_#{title}]") } + + it { is_expected.not_to contain_exec("sudo-syntax-check for file #{params[:sudo_config_dir]}0#{params[:priority]}_#{title}").that_requires("File[#{filename}]") } + it { is_expected.not_to contain_file(filename).that_requires("Exec[sudo-syntax-check for file #{params[:sudo_config_dir]}0#{params[:priority]}_#{title}]") } + end + describe 'when removing an sudo entry' do let :params do { :ensure => 'absent', :priority => 10, :content => '%admins ALL=(ALL) NOPASSWD: ALL', :sudo_config_dir => '/etc/sudoers.d/' } end it do is_expected.to contain_file(filename).with('ensure' => 'absent', 'content' => "# This file is managed by Puppet; changes may be overwritten\n%admins ALL=(ALL) NOPASSWD: ALL\n", 'owner' => 'root', 'group' => 'root', 'path' => file_path, 'mode' => '0440') end end describe 'when removing an sudo entry with single number priority' do let :params do { :ensure => 'absent', :priority => 5, :content => '%admins ALL=(ALL) NOPASSWD: ALL', :sudo_config_dir => '/etc/sudoers.d/' } end let(:filename) { '05_admins' } let(:file_path) { '/etc/sudoers.d/05_admins' } it do is_expected.to contain_file(filename).with('ensure' => 'absent', 'content' => "# This file is managed by Puppet; changes may be overwritten\n%admins ALL=(ALL) NOPASSWD: ALL\n", 'owner' => 'root', 'group' => 'root', 'path' => file_path, 'mode' => '0440') end end end