Skip to content

Commit

Permalink
Add defined type for handling custom configs
Browse files Browse the repository at this point in the history
Initially I was looking to handle custom configs by creating a temporary
file, validating that file, and creating a file under apache's
`$confd_dir` only if that validation passed. Ubuntu caused issues for me
though, and apachectl was unable to validate config files under
non-default paths. Thus, I ended up with a file resource and two execs,
to remove the config if invalid, and notify the httpd service if valid.

There were some bugs with existing acceptance tests, so fixed those too.
  • Loading branch information
Morgan Haskel committed Sep 4, 2014
1 parent 08c29d0 commit f4ecfa2
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 7 deletions.
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
4. [Usage - The classes and defined types available for configuration](#usage)
* [Classes and Defined Types](#classes-and-defined-types)
* [Class: apache](#class-apache)
* [Defined Type: apache::custom_config](#defined-type-apachecustom_config)
* [Class: apache::default_mods](#class-apachedefault_mods)
* [Defined Type: apache::mod](#defined-type-apachemod)
* [Classes: apache::mod::*](#classes-apachemodname)
Expand Down Expand Up @@ -429,6 +430,46 @@ Changes the location of the configuration directory your virtual host configurat

The name of the Apache package to install. This is automatically detected in `::apache::params`. You may need to override this if you are using a non-standard Apache package, such as those from Red Hat's software collections.

####Defined Type: `apache::custom_config`

Allows you to create custom configs for Apache. The configuration files will only be added to the Apache confd dir if the file is valid. An error will be raised during the puppet run if the file is invalid and `$verify_config` is `true`.

```puppet
apache::custom_config { 'test':
content => '# Test',
}
```

**Parameters within `apache::custom_config`:**

#####`ensure`

Specify whether the configuration file is present or absent. Defaults to 'present'. Valid values are 'present' and 'absent'.

#####`confdir`

The directory to place the configuration file in. Defaults to `$::apache::confd_dir`.

#####`content`

The content of the configuration file. Only one of `$content` and `$source` can be specified.

#####`priority`

The priority of the configuration file, used for ordering. Defaults to '25'.

#####`source`

The source of the configuration file. Only one of `$content` and `$source` can be specified.

#####`verify_command`

The command to use to verify the configuration file. It should use a fully qualified command. Defaults to '/usr/sbin/apachectl -t'. The `$verify_command` will only be used if `$verify_config` is `true`. If the `$verify_command` fails the configuration file will be deleted, the Apache service will not be notified, and an error will be raised during the puppet run.

#####`verify_config`

Boolean to specify whether the configuration file should be validated before the Apache service is notified. Defaults to `true`.

####Class: `apache::default_mods`

Installs default Apache modules based on what OS you are running.
Expand Down
60 changes: 60 additions & 0 deletions manifests/custom_config.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# See README.md for usage information
define apache::custom_config (
$ensure = 'present',
$confdir = $::apache::confd_dir,
$content = undef,
$priority = '25',
$source = undef,
$verify_command = '/usr/sbin/apachectl -t',
$verify_config = true,
) {

if $content and $source {
fail('Only one of $content and $source can be specified.')
}

if $ensure == 'present' and ! $content and ! $source {
fail('One of $content and $source must be specified.')
}

validate_re($ensure, '^(present|absent)$',
"${ensure} is not supported for ensure.
Allowed values are 'present' and 'absent'.")

validate_bool($verify_config)

## Apache include does not always work with spaces in the filename
$filename = regsubst($name, ' ', '_', 'G')

if ! $verify_config or $ensure == 'absent' {
$notifies = Service['httpd']
} else {
$notifies = undef
}

file { "apache_${name}":
ensure => $ensure,
path => "${confdir}/${priority}-${filename}.conf",
content => $content,
source => $source,
require => Package['httpd'],
notify => $notifies,
}

if $ensure == 'present' and $verify_config {
exec { "service notify for ${name}":
command => $verify_command,
subscribe => File["apache_${name}"],
refreshonly => true,
notify => Service['httpd'],
before => Exec["remove ${name} if invalid"],
}

exec { "remove ${name} if invalid":
command => "/bin/rm ${confdir}/${priority}-${filename}.conf",
unless => $verify_command,
subscribe => File["apache_${name}"],
refreshonly => true,
}
}
}
10 changes: 4 additions & 6 deletions spec/acceptance/apache_parameters_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
end

if fact('osfamily') == 'FreeBSD'
describe file("#{confd_dir}/no-accf.conf.erb") do
describe file("#{$confd_dir}/no-accf.conf.erb") do
it { is_expected.not_to be_file }
end
end
Expand Down Expand Up @@ -80,9 +80,8 @@ class { 'apache':
pp = <<-EOS
class { 'apache':
purge_configs => false,
purge_vdir => false,
purge_vhost_dir => false,
vhost_dir => "#{confd_dir}.vhosts"
vhost_dir => "#{$confd_dir}.vhosts"
}
EOS
shell("touch #{$confd_dir}/test.conf")
Expand All @@ -105,9 +104,8 @@ class { 'apache':
pp = <<-EOS
class { 'apache':
purge_configs => true,
purge_vdir => true,
purge_vhost_dir => true,
vhost_dir => "#{confd_dir}.vhosts"
vhost_dir => "#{$confd_dir}.vhosts"
}
EOS
shell("touch #{$confd_dir}/test.conf")
Expand Down Expand Up @@ -202,7 +200,7 @@ class { 'apache': httpd_dir => '/tmp', service_ensure => stopped }
end
end

describe file("#{$confd_dir}/mime.conf") do
describe file("#{$mod_dir}/mime.conf") do
it { is_expected.to be_file }
it { is_expected.to contain 'AddLanguage eo .eo' }
end
Expand Down
38 changes: 38 additions & 0 deletions spec/acceptance/custom_config_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'spec_helper_acceptance'
require_relative './version.rb'

describe 'apache::custom_config define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'invalid config' do
it 'should not add the config' do
pp = <<-EOS
class { 'apache': }
apache::custom_config { 'acceptance_test':
content => 'INVALID',
}
EOS

apply_manifest(pp, :expect_failures => true)
end

describe file("#{$confd_dir}/25-acceptance_test.conf") do
it { is_expected.not_to be_file }
end
end

context 'valid config' do
it 'should add the config' do
pp = <<-EOS
class { 'apache': }
apache::custom_config { 'acceptance_test':
content => '# just a comment',
}
EOS

apply_manifest(pp, :catch_failures => true)
end

describe file("#{$confd_dir}/25-acceptance_test.conf") do
it { is_expected.to contain '# just a comment' }
end
end
end
5 changes: 4 additions & 1 deletion spec/acceptance/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
case _osfamily
when 'RedHat'
$confd_dir = '/etc/httpd/conf.d'
$mod_dir = '/etc/httpd/conf.d'
$conf_file = '/etc/httpd/conf/httpd.conf'
$ports_file = '/etc/httpd/conf/ports.conf'
$vhost_dir = '/etc/httpd/conf.d'
Expand All @@ -22,7 +23,8 @@
$apache_version = '2.2'
end
when 'Debian'
$confd_dir = '/etc/apache2/mods-available'
$confd_dir = '/etc/apache2/conf.d'
$mod_dir = '/etc/apache2/mods-available'
$conf_file = '/etc/apache2/apache2.conf'
$ports_file = '/etc/apache2/ports.conf'
$vhost = '/etc/apache2/sites-available/15-default.conf'
Expand All @@ -41,6 +43,7 @@
end
when 'FreeBSD'
$confd_dir = '/usr/local/etc/apache22/Includes'
$mod_dir = '/usr/local/etc/apache22/Modules'
$conf_file = '/usr/local/etc/apache22/httpd.conf'
$ports_file = '/usr/local/etc/apache22/Includes/ports.conf'
$vhost = '/usr/local/etc/apache22/Vhosts/15-default.conf'
Expand Down
137 changes: 137 additions & 0 deletions spec/defines/custom_config_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
require 'spec_helper'

describe 'apache::custom_config', :type => :define do
let :pre_condition do
'class { "apache": }'
end
let :title do
'rspec'
end
let :facts do
{
:osfamily => 'Debian',
:operatingsystemrelease => '6',
:concat_basedir => '/',
:lsbdistcodename => 'squeeze',
:operatingsystem => 'Debian',
:id => 'root',
:kernel => 'Linux',
:path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
}
end
context 'defaults with content' do
let :params do
{
'content' => '# Test',
}
end
it { is_expected.to contain_exec("service notify for rspec").with({
'refreshonly' => 'true',
'subscribe' => 'File[apache_rspec]',
'command' => '/usr/sbin/apachectl -t',
'notify' => 'Service[httpd]',
'before' => 'Exec[remove rspec if invalid]',
})
}
it { is_expected.to contain_exec("remove rspec if invalid").with({
'unless' => '/usr/sbin/apachectl -t',
'subscribe' => 'File[apache_rspec]',
'refreshonly' => 'true',
})
}
it { is_expected.to contain_file("apache_rspec").with({
'ensure' => 'present',
'content' => '# Test',
'require' => 'Package[httpd]',
})
}
end
context 'set everything with source' do
let :params do
{
'confdir' => '/dne',
'priority' => '30',
'source' => 'puppet:///modules/apache/test',
'verify_command' => '/bin/true',
}
end
it { is_expected.to contain_exec("service notify for rspec").with({
'command' => '/bin/true',
})
}
it { is_expected.to contain_exec("remove rspec if invalid").with({
'command' => '/bin/rm /dne/30-rspec.conf',
'unless' => '/bin/true',
})
}
it { is_expected.to contain_file("apache_rspec").with({
'path' => '/dne/30-rspec.conf',
'ensure' => 'present',
'source' => 'puppet:///modules/apache/test',
'require' => 'Package[httpd]',
})
}
end
context 'verify_config => false' do
let :params do
{
'content' => '# test',
'verify_config' => false,
}
end
it { is_expected.to_not contain_exec('service notify for rspec') }
it { is_expected.to_not contain_exec('remove rspec if invalid') }
it { is_expected.to contain_file('apache_rspec').with({
'notify' => 'Service[httpd]'
})
}
end
context 'ensure => absent' do
let :params do
{
'ensure' => 'absent'
}
end
it { is_expected.to_not contain_exec('service notify for rspec') }
it { is_expected.to_not contain_exec('remove rspec if invalid') }
it { is_expected.to contain_file('apache_rspec').with({
'ensure' => 'absent',
})
}
end
describe 'validation' do
context 'both content and source' do
let :params do
{
'content' => 'foo',
'source' => 'bar',
}
end
it do
expect {
should compile
}.to raise_error(Puppet::Error, /Only one of \$content and \$source can be specified\./)
end
end
context 'neither content nor source' do
it do
expect {
should compile
}.to raise_error(Puppet::Error, /One of \$content and \$source must be specified\./)
end
end
context 'bad ensure' do
let :params do
{
'content' => 'foo',
'ensure' => 'foo',
}
end
it do
expect {
should compile
}.to raise_error(Puppet::Error, /is not supported for ensure/)
end
end
end
end

0 comments on commit f4ecfa2

Please sign in to comment.