Skip to content

Commit 4d24bd3

Browse files
author
Jeff McCune
committed
Merge branch 'raphink-validate_augeas'
* raphink-validate_augeas: Add an URL to a doc on how to activate augeas in puppet validate_augeas: requires augeas validate_augeas: Ensure tmpfile is closed and unlinked validate_augeas: Ensure augeas handler gets closed Add validate_augeas function closes 114
2 parents f6a63ee + c5f0309 commit 4d24bd3

2 files changed

Lines changed: 183 additions & 0 deletions

File tree

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
module Puppet::Parser::Functions
2+
newfunction(:validate_augeas, :doc => <<-'ENDHEREDOC') do |args|
3+
Perform validation of a string using an Augeas lens
4+
The first argument of this function should be a string to
5+
test, and the second argument should be the name of the Augeas lens to use.
6+
If Augeas fails to parse the string with the lens, the compilation will
7+
abort with a parse error.
8+
9+
A third argument can be specified, listing paths which should
10+
not be found in the file. The `$file` variable points to the location
11+
of the temporary file being tested in the Augeas tree.
12+
13+
For example, if you want to make sure your passwd content never contains
14+
a user `foo`, you could write:
15+
16+
validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo'])
17+
18+
Or if you wanted to ensure that no users used the '/bin/barsh' shell,
19+
you could use:
20+
21+
validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]']
22+
23+
If a fourth argument is specified, this will be the error message raised and
24+
seen by the user.
25+
26+
A helpful error message can be returned like this:
27+
28+
validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas')
29+
30+
ENDHEREDOC
31+
unless Puppet.features.augeas?
32+
raise Puppet::ParseError, ("validate_augeas(): this function requires the augeas feature. See http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Augeas#Pre-requisites for how to activate it.")
33+
end
34+
35+
if (args.length < 2) or (args.length > 4) then
36+
raise Puppet::ParseError, ("validate_augeas(): wrong number of arguments (#{args.length}; must be 2, 3, or 4)")
37+
end
38+
39+
msg = args[3] || "validate_augeas(): Failed to validate content against #{args[1].inspect}"
40+
41+
require 'augeas'
42+
aug = Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD)
43+
begin
44+
content = args[0]
45+
46+
# Test content in a temporary file
47+
tmpfile = Tempfile.new("validate_augeas")
48+
begin
49+
tmpfile.write(content)
50+
ensure
51+
tmpfile.close
52+
end
53+
54+
# Check for syntax
55+
lens = args[1]
56+
aug.transform(
57+
:lens => lens,
58+
:name => 'Validate_augeas',
59+
:incl => tmpfile.path
60+
)
61+
aug.load!
62+
63+
unless aug.match("/augeas/files#{tmpfile.path}//error").empty?
64+
error = aug.get("/augeas/files#{tmpfile.path}//error/message")
65+
msg += " with error: #{error}"
66+
raise Puppet::ParseError, (msg)
67+
end
68+
69+
# Launch unit tests
70+
tests = args[2] || []
71+
aug.defvar('file', "/files#{tmpfile.path}")
72+
tests.each do |t|
73+
msg += " testing path #{t}"
74+
raise Puppet::ParseError, (msg) unless aug.match(t).empty?
75+
end
76+
ensure
77+
aug.close
78+
tmpfile.unlink
79+
end
80+
end
81+
end
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
require 'spec_helper'
2+
3+
describe Puppet::Parser::Functions.function(:validate_augeas), :if => Puppet.features.augeas? do
4+
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
5+
6+
# The subject of these examplres is the method itself.
7+
subject do
8+
# This makes sure the function is loaded within each test
9+
function_name = Puppet::Parser::Functions.function(:validate_augeas)
10+
scope.method(function_name)
11+
end
12+
13+
context 'Using Puppet::Parser::Scope.new' do
14+
15+
describe 'Garbage inputs' do
16+
inputs = [
17+
[ nil ],
18+
[ [ nil ] ],
19+
[ { 'foo' => 'bar' } ],
20+
[ { } ],
21+
[ '' ],
22+
[ "one", "one", "MSG to User", "4th arg" ],
23+
]
24+
25+
inputs.each do |input|
26+
it "validate_augeas(#{input.inspect}) should fail" do
27+
expect { subject.call [input] }.to raise_error Puppet::ParseError
28+
end
29+
end
30+
end
31+
32+
describe 'Valid inputs' do
33+
inputs = [
34+
[ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns' ],
35+
[ "proc /proc proc nodev,noexec,nosuid 0 0\n", 'Fstab.lns'],
36+
]
37+
38+
inputs.each do |input|
39+
it "validate_augeas(#{input.inspect}) should not fail" do
40+
expect { subject.call input }.not_to raise_error
41+
end
42+
end
43+
end
44+
45+
describe "Valid inputs which should raise an exception without a message" do
46+
# The intent here is to make sure valid inputs raise exceptions when they
47+
# don't specify an error message to display. This is the behvior in
48+
# 2.2.x and prior.
49+
inputs = [
50+
[ "root:x:0:0:root\n", 'Passwd.lns' ],
51+
[ "127.0.1.1\n", 'Hosts.lns' ],
52+
]
53+
54+
inputs.each do |input|
55+
it "validate_augeas(#{input.inspect}) should fail" do
56+
expect { subject.call input }.to raise_error /validate_augeas.*?matched less than it should/
57+
end
58+
end
59+
end
60+
61+
describe "Nicer Error Messages" do
62+
# The intent here is to make sure the function returns the 3rd argument
63+
# in the exception thrown
64+
inputs = [
65+
[ "root:x:0:0:root\n", 'Passwd.lns', [], 'Failed to validate passwd content' ],
66+
[ "127.0.1.1\n", 'Hosts.lns', [], 'Wrong hosts content' ],
67+
]
68+
69+
inputs.each do |input|
70+
it "validate_augeas(#{input.inspect}) should fail" do
71+
expect { subject.call input }.to raise_error /#{input[2]}/
72+
end
73+
end
74+
end
75+
76+
describe "Passing simple unit tests" do
77+
inputs = [
78+
[ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']],
79+
[ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']],
80+
]
81+
82+
inputs.each do |input|
83+
it "validate_augeas(#{input.inspect}) should fail" do
84+
expect { subject.call input }.not_to raise_error
85+
end
86+
end
87+
end
88+
89+
describe "Failing simple unit tests" do
90+
inputs = [
91+
[ "foobar:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']],
92+
[ "root:x:0:0:root:/root:/bin/sh\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']],
93+
]
94+
95+
inputs.each do |input|
96+
it "validate_augeas(#{input.inspect}) should fail" do
97+
expect { subject.call input }.to raise_error /testing path/
98+
end
99+
end
100+
end
101+
end
102+
end

0 commit comments

Comments
 (0)