Skip to content

Commit

Permalink
Merge pull request jhoblitt#14 from jhoblitt/feature/validate_gmetad_…
Browse files Browse the repository at this point in the history
…clusters

Feature/validate gmetad clusters
  • Loading branch information
Joshua Hoblitt committed May 16, 2014
2 parents aa98bee + fbbeb0e commit 221b474
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 14 deletions.
114 changes: 114 additions & 0 deletions lib/puppet/parser/functions/ganglia_validate_clusters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
module Puppet::Parser::Functions

newfunction(:ganglia_validate_clusters, :doc => <<-'ENDHEREDOC') do |args|
The following values will pass:
* [{ 'name' => 'my cluster', 'address' => 'localhost' }]
* [{ 'name' => 'my cluster', 'address' => 'localhost', 'polling_interval' => 10 }]
* [
{
'name' => 'foo',
'address' => [
'foo1.example.org',
'foo2.example.org',
'foo3.example.org',
],
},
{
'name' => 'bar',
'address' => [
'bar1.example.org',
'bar2.example.org',
'bar3.example.org'
],
'polling_interval' => 42,
},
{
'name' => 'baz',
'address' => [
'baz1.example.org',
'baz2.example.org',
'baz3.example.org',
],
},
]
The following values will fail, causing compilation to abort:
* true
* false
* {}
* 'foo'
* undef
* []
* ['foo', 'bar']
* [{}, {}]
* [{ 'address' => 'localhost' }]
* [{ 'name' => ['my cluster'], 'address' => 'localhost' }]
* [{ 'name' => 'my cluster' }]
* [{ 'name' => 'my cluster', 'address' => {'a' => 1} }]
* [{ 'name' => 'my cluster', 'address' => 'localhost', 'polling_interval' => [ 10 ] }]
* [{ 'name' => 'my cluster', 'address' => 'localhost', 'polling_interval' => 10, 'foo' => 1, 'bar' => 2 }]
ENDHEREDOC

Puppet::Parser::Functions.autoloader.loadall

# we accept only one arg
unless args.length == 1 then
raise Puppet::ParseError, ("ganglia_validate_clusters(): wrong number of arguments (#{args.length}; must be 1)")
end

# which must be an array
function_validate_array(args)

# that is not empty
clusters = args[0]
unless clusters.length > 0
raise Puppet::ParseError, ("ganglia_validate_clusters(): passed Array may not be empty")
end

# which must contain only Hashes
clusters.each do |c|
function_validate_hash([c])

# that are not empty
unless c.length > 0
raise Puppet::ParseError, ("ganglia_validate_clusters(): nested Hash may not be empty")
end

# and must contain the name key
unless c.has_key?('name')
raise Puppet::ParseError, ("ganglia_validate_clusters(): nested Hash must contain a name key")
end
# which is a string
unless c['name'].is_a?(String)
raise Puppet::ParseError, ("ganglia_validate_clusters(): nested Hash name key must be a String")
end

# and must contain the address key
unless c.has_key?('address')
raise Puppet::ParseError, ("ganglia_validate_clusters(): nested Hash must contain an address key")
end
# which is a string or an array
unless c['address'].is_a?(String) || c['address'].is_a?(Array)
raise Puppet::ParseError, ("ganglia_validate_clusters(): nested Hash address key must be a String or Array")
end

# if the optional polling_interval key is set
if c.has_key?('polling_interval')
# it must be a string (int really)
unless c['polling_interval'].is_a?(String) || c['polling_interval'].is_a?(Integer)
raise Puppet::ParseError, ("ganglia_validate_clusters(): nested Hash polling_interval key must be a String or Integer")
end
end

# any other keys should be rejected
extras = c.keys - %w{ name address polling_interval }
if extras.length > 0
raise Puppet::ParseError, ("ganglia_validate_clusters(): nested Hash contains unknown keys (#{extras.sort.join(' ')})")
end
end
end

end
2 changes: 1 addition & 1 deletion manifests/gmetad.pp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
$clusters = [ { 'name' => 'my cluster', 'address' => 'localhost' } ],
$gridname = undef,
) inherits ganglia::params {
validate_array($clusters)
ganglia_validate_clusters($clusters)
validate_string($gridname)

anchor{ 'ganglia::gmetad::begin': } ->
Expand Down
50 changes: 37 additions & 13 deletions spec/classes/gmetad_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,43 @@
describe 'ganglia::gmetad' do
let(:facts) {{ :osfamily => 'RedHat', :operatingsystemmajrelease => 6 }}

context 'with clusters' do
clusters = [
{
'name' => 'test',
'address' => ['test1.example.org', 'test2.example.org'],
},
]
context 'clusters =>' do
context '<good example>' do
clusters = [
{
'name' => 'test',
'address' => ['test1.example.org', 'test2.example.org'],
},
]

let(:params) { {:clusters => clusters} }
it do
should contain_class('ganglia::gmetad')
should contain_file('/etc/ganglia/gmetad.conf')
end
end
let(:params) {{ :clusters => clusters }}
it do
should contain_class('ganglia::gmetad')
should contain_file('/etc/ganglia/gmetad.conf')
end
end # <good example>

context '[]' do
let(:params) {{ :clusters => [] }}
it do
expect { should compile }.to raise_error(Puppet::Error, /Array may not be empty/)
end
end # <invalid example>

context '<invalid example>' do
clusters = [
{
'name' => 'test',
'address' => ['test1.example.org', 'test2.example.org'],
'foo' => 1,
},
]

let(:params) {{ :clusters => clusters }}
it do
expect { should compile }.to raise_error(Puppet::Error, /unknown keys/)
end
end # <invalid example>
end # clusters =>
end

120 changes: 120 additions & 0 deletions spec/functions/ganglia_validate_clusters_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
require 'spec_helper'

describe 'ganglia_validate_clusters', :type => :puppet_function do
it 'should fail with no params' do
expect { subject.call([]) }.
to raise_error(Puppet::ParseError)
end

it 'should fail with > 1 param' do
expect { subject.call(['a', 'b']) }.
to raise_error(Puppet::ParseError, /wrong number of arguments/)
end

[ true, false, {}, "foo", nil ].each do |input|
it 'should fail when not called with an array' do
expect { subject.call([input]) }.
to raise_error(Puppet::ParseError, /is not an Array/)
end
end

it 'should fail when passed an empty array' do
expect { subject.call([[]]) }.
to raise_error(Puppet::ParseError, /Array may not be empty/)
end

it 'should fail when passed an array of anything but hashes' do
clusters = ['foo', 'bar']
expect { subject.call([clusters]) }.
to raise_error(Puppet::ParseError, /is not a Hash/)
end

it 'should fail when passed an array of empty hashes' do
clusters = [{}, {}]
expect { subject.call([clusters]) }.
to raise_error(Puppet::ParseError, /Hash may not be empty/)
end

it 'should fail when name key is missing ' do
clusters = [{ 'address' => 'localhost' }]
expect { subject.call([clusters]) }.
to raise_error(Puppet::ParseError, /must contain a name key/)
end

it 'should fail when name key is not a string' do
clusters = [{ 'name' => ['my cluster'], 'address' => 'localhost' }]
expect { subject.call([clusters]) }.
to raise_error(Puppet::ParseError, /name key must be a String/)
end

it 'should fail when address key is missing' do
clusters = [{ 'name' => 'my cluster' }]
expect { subject.call([clusters]) }.
to raise_error(Puppet::ParseError, /must contain an address key/)
end

it 'should fail when address key is not a string|array' do
clusters = [{ 'name' => 'my cluster', 'address' => {'a' => 1} }]
expect { subject.call([clusters]) }.
to raise_error(Puppet::ParseError, /address key must be a String or Array/)
end

it 'work with optional polling_interval key' do
clusters = [{ 'name' => 'my cluster', 'address' => 'localhost', 'polling_interval' => '10' }]
subject.call([clusters])
end

it 'work with optional polling_interval key' do
clusters = [{ 'name' => 'my cluster', 'address' => 'localhost', 'polling_interval' => 10 }]
subject.call([clusters])
end

it 'should fail when polling_interval key is not a String' do
clusters = [{ 'name' => 'my cluster', 'address' => 'localhost', 'polling_interval' => [ 10 ] }]
expect { subject.call([clusters]) }.
to raise_error(Puppet::ParseError, /polling_interval key must be a String or Integer/)
end

it 'should fail with unknown keys' do
clusters = [{ 'name' => 'my cluster', 'address' => 'localhost', 'polling_interval' => 10, 'foo' => 1, 'bar' => 2 }]
expect { subject.call([clusters]) }.
to raise_error(Puppet::ParseError, /contains unknown keys \(bar foo\)/)
end

it 'work with reasonable input - simple example' do
clusters = [{ 'name' => 'my cluster', 'address' => 'localhost' }]
subject.call([clusters])
end

it 'work with reasonable input - complex example' do
clusters = [
{
'name' => 'foo',
'address' => [
'foo1.example.org',
'foo2.example.org',
'foo3.example.org',
],
},
{
'name' => 'bar',
'address' => [
'bar1.example.org',
'bar2.example.org',
'bar3.example.org'
],
'polling_interval' => 42,
},
{
'name' => 'baz',
'address' => [
'baz1.example.org',
'baz2.example.org',
'baz3.example.org',
],
},
]
subject.call([clusters])
end
end

0 comments on commit 221b474

Please sign in to comment.