summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Rakefile2
-rw-r--r--lib/puppet/parser/functions/augeas.rb68
-rw-r--r--spec/spec.opts6
-rw-r--r--spec/spec_helper.rb28
-rw-r--r--spec/unit/puppet/parser/functions/augeas_spec.rb83
5 files changed, 187 insertions, 0 deletions
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..14f1c24
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,2 @@
+require 'rubygems'
+require 'puppetlabs_spec_helper/rake_tasks'
diff --git a/lib/puppet/parser/functions/augeas.rb b/lib/puppet/parser/functions/augeas.rb
new file mode 100644
index 0000000..08026f7
--- /dev/null
+++ b/lib/puppet/parser/functions/augeas.rb
@@ -0,0 +1,68 @@
+#
+# augeas.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:augeas, :type => :rvalue, :doc => <<-EOS
+Modifies a string using Augeas.
+
+*Example:*
+
+ augeas("proc /proc proc nodev,noexec,nosuid 0 0\n", 'Fstab.lns', ['rm ./1/opt[3]'])
+
+Would result in:
+
+ "proc /proc proc nodev,noexec 0 0\n"
+ EOS
+ ) do |arguments|
+ unless Puppet.features.augeas?
+ raise Puppet::ParseError, ('augeas(): this function requires the augeas feature. See http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Augeas#Pre-requisites for how to activate it.')
+ end
+
+ # Check that 2 arguments have been given ...
+ raise(Puppet::ParseError, 'augeas(): Wrong number of arguments ' +
+ "given (#{arguments.size} for 3)") if arguments.size != 3
+
+ content = arguments[0]
+ lens = arguments[1]
+ changes = arguments[2]
+
+ # Check arguments
+ raise(Puppet::ParseError, 'augeas(): content must be a string') unless content.is_a?(String)
+ raise(Puppet::ParseError, 'augeas(): lens must be a string') unless lens.is_a?(String)
+ raise(Puppet::ParseError, 'augeas(): changes must be an array') unless changes.is_a?(Array)
+
+ require 'augeas'
+ aug = Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD)
+ augeas_version = aug.get('/augeas/version')
+ raise(Puppet::ParseError, 'augeas(): requires Augeas 1.0.0 or greater') unless Puppet::Util::Package.versioncmp(augeas_version, '1.0.0') >= 0
+ raise(Puppet::ParseError, 'augeas(): requires ruby-augeas 0.5.0 or greater') unless aug.methods.include?('text_store')
+
+ result = nil
+ begin
+ aug.set('/input', content)
+ aug.text_store(lens, '/input', '/store')
+ unless aug.match("/augeas/text/store//error").empty?
+ error = aug.get("/augeas/text/store//error/message")
+ raise Puppet::ParseError, "augeas(): Failed to parse string with lens #{lens}: #{error}"
+ end
+
+ # Apply changes
+ aug.context = '/store'
+ changes.each do |c|
+ r = aug.srun(c)
+ raise Puppet::ParseError, "augeas(): Failed to apply change to tree" unless r and r[0] >= 0
+ end
+ unless aug.text_retrieve(lens, '/input', '/store', '/output')
+ error = aug.get("/augeas/text/store//error/message")
+ raise Puppet::ParseError, "augeas(): Failed to apply changes with lens #{lens}: #{error}"
+ end
+ result = aug.get("/output")
+ ensure
+ aug.close
+ end
+ return result
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/spec/spec.opts b/spec/spec.opts
new file mode 100644
index 0000000..91cd642
--- /dev/null
+++ b/spec/spec.opts
@@ -0,0 +1,6 @@
+--format
+s
+--colour
+--loadby
+mtime
+--backtrace
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..931d35c
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,28 @@
+dir = File.expand_path(File.dirname(__FILE__))
+$LOAD_PATH.unshift File.join(dir, 'lib')
+
+# Don't want puppet getting the command line arguments for rake or autotest
+ARGV.clear
+
+require 'puppet'
+require 'facter'
+require 'mocha'
+gem 'rspec', '>=2.0.0'
+require 'rspec/expectations'
+
+require 'puppetlabs_spec_helper/module_spec_helper'
+
+RSpec.configure do |config|
+ # FIXME REVISIT - We may want to delegate to Facter like we do in
+ # Puppet::PuppetSpecInitializer.initialize_via_testhelper(config) because
+ # this behavior is a duplication of the spec_helper in Facter.
+ config.before :each do
+ # Ensure that we don't accidentally cache facts and environment between
+ # test cases. This requires each example group to explicitly load the
+ # facts being exercised with something like
+ # Facter.collection.loader.load(:ipaddress)
+ Facter::Util::Loader.any_instance.stubs(:load_all)
+ Facter.clear
+ Facter.clear_messages
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/augeas_spec.rb b/spec/unit/puppet/parser/functions/augeas_spec.rb
new file mode 100644
index 0000000..9c48773
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/augeas_spec.rb
@@ -0,0 +1,83 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe 'the augeas function' do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should fail if the augeas feature is not present" do
+ Puppet.features.expects(:augeas?).returns(false)
+ expect { scope.function_augeas([]) }.to raise_error(Puppet::ParseError, /requires the augeas feature/)
+ end
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("augeas").should == "function_augeas"
+ end
+
+ context "when passing wrong arguments" do
+ before :each do
+ Puppet.features.stubs(:augeas?).returns(true)
+ end
+
+ it "should raise a ParseError if there are no arguments" do
+ expect { scope.function_augeas([]) }.to raise_error(Puppet::ParseError, /Wrong number of arguments/)
+ end
+
+ it "should raise a ParseError if content is not a string" do
+ expect { scope.function_augeas([['foo'], 'Fstab.lns', []]) }.to raise_error(Puppet::ParseError, /content must be a string/)
+ end
+
+ it "should raise a ParseError if lens is not a string" do
+ expect { scope.function_augeas(['foo', ['Fstab.lns'], []]) }.to raise_error(Puppet::ParseError, /lens must be a string/)
+ end
+
+ it "should raise a ParseError if changes is not an array" do
+ expect { scope.function_augeas(['foo', 'Fstab.lns', 'changes']) }.to raise_error(Puppet::ParseError, /changes must be an array/)
+ end
+ end
+
+ if Puppet.features.augeas?
+ context "when passing invalid input" do
+ it "should fail to parse input with lens" do
+ expect { scope.function_augeas(['foo', 'Fstab.lns', []]) }.to raise_error(Puppet::ParseError, /Failed to parse string with lens Fstab.lns:/)
+ end
+ end
+
+ context "when passing illegal changes" do
+ it "should fail to apply illegal change" do
+ expect { scope.function_augeas(["\n", 'Fstab.lns', ['foo bar']]) }.to raise_error(Puppet::ParseError, /Failed to apply change to tree/)
+ end
+ end
+
+ context "when generating an invalid tree" do
+ it "should fail to apply changes with wrong tree" do
+ expect { scope.function_augeas(["\n", 'Fstab.lns', ['set ./1/opt 3']]) }.to raise_error(Puppet::ParseError, /Failed to apply changes with lens Fstab.lns:/)
+ end
+ end
+
+ context "when applying valid changes" do
+ it "should remove the 3rd option" do
+ result = scope.function_augeas(["proc /proc proc nodev,noexec,nosuid 0 0\n", 'Fstab.lns', ['rm ./1/opt[3]']])
+ result.class.should == String
+ #result.should == "proc /proc proc nodev,noexec 0 0\n"
+ end
+
+ it "should set a 4th option" do
+ result = scope.function_augeas(["proc /proc proc nodev,noexec,nosuid 0 0\n", 'Fstab.lns', ['ins opt after ./1/opt[last()]', 'set ./1/opt[last()] nofoo']])
+ result.class.should == String
+ #result.should == "proc /proc proc nodev,noexec,nosuid,nofoo 0 0\n"
+ end
+ end
+
+ context "when using old libs" do
+ it "should not work with Augeas prior to 1.0.0" do
+ Augeas.any_instance.expects(:get).with('/augeas/version').returns('0.10.0')
+ expect { scope.function_augeas(["\n", 'Fstab.lns', []]) }.to raise_error(Puppet::ParseError, /requires Augeas 1\.0\.0/)
+ end
+
+ it "should not work with ruby-augeas prior to 0.5.0" do
+ Augeas.any_instance.expects(:methods).returns([])
+ expect { scope.function_augeas(["\n", 'Fstab.lns', []]) }.to raise_error(Puppet::ParseError, /requires ruby-augeas 0\.5\.0/)
+ end
+ end
+ end
+end