diff options
author | James Turnbull <james@lovedthanlost.net> | 2008-10-29 15:46:16 +1100 |
---|---|---|
committer | James Turnbull <james@lovedthanlost.net> | 2008-10-29 15:46:16 +1100 |
commit | a83b3ffb3fdf8fecf1aeac27851c2d25ebd8d94d (patch) | |
tree | ab630de8d5f6a5d7049db1ad2c61c7b6eaae8ef7 | |
parent | 56f3be66a437f5c2c60187d34681813ec7246228 (diff) | |
parent | 751dc7b09f7802189e14e9bb17ab4b01ed31b164 (diff) | |
download | puppet-a83b3ffb3fdf8fecf1aeac27851c2d25ebd8d94d.tar.gz puppet-a83b3ffb3fdf8fecf1aeac27851c2d25ebd8d94d.tar.xz puppet-a83b3ffb3fdf8fecf1aeac27851c2d25ebd8d94d.zip |
Merge branch 'augeas' into 0.24.x
-rw-r--r-- | lib/puppet/feature/base.rb | 3 | ||||
-rw-r--r-- | lib/puppet/provider/augeas/augeas.rb | 188 | ||||
-rw-r--r-- | lib/puppet/type/augeas.rb | 150 |
3 files changed, 341 insertions, 0 deletions
diff --git a/lib/puppet/feature/base.rb b/lib/puppet/feature/base.rb index 518e9b419..0b12d730a 100644 --- a/lib/puppet/feature/base.rb +++ b/lib/puppet/feature/base.rb @@ -22,3 +22,6 @@ Puppet.features.add(:mongrel, :libs => %w{rubygems mongrel puppet/network/http_s # We have lcs diff Puppet.features.add :diff, :libs => %w{diff/lcs diff/lcs/hunk} + +# We have augeas +Puppet.features.add(:augeas, :libs => ["augeas"]) diff --git a/lib/puppet/provider/augeas/augeas.rb b/lib/puppet/provider/augeas/augeas.rb new file mode 100644 index 000000000..a487e2ac5 --- /dev/null +++ b/lib/puppet/provider/augeas/augeas.rb @@ -0,0 +1,188 @@ +#-- +# Copyright (C) 2008 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Author: Bryan Kearney <bkearney@redhat.com> + +require 'augeas' if Puppet.features.augeas? + +Puppet::Type.type(:augeas).provide(:augeas) do +#class Puppet::Provider::Augeas < Puppet::Provider + include Puppet::Util + + confine :true => Puppet.features.augeas? + + has_features :parse_commands, :need_to_run?,:execute_changes + + # Extracts an 2 dimensional array of commands which are in the + # form of command path value. + # The input can be + # - A string with one command + # - A string with many commands per line + # - An array of strings. + def parse_commands(data) + commands = Array.new() + if data.is_a?(String) + data.each_line do |line| + cmd_array = Array.new() + tokens = line.split(" ") + cmd = tokens.shift() + file = tokens.shift() + other = tokens.join(" ") + cmd_array << cmd if !cmd.nil? + cmd_array << file if !file.nil? + cmd_array << other if other != "" + commands << cmd_array + end + elsif data.is_a?(Array) + data.each do |datum| + commands.concat(parse_commands(datum)) + end + end + + return commands + end + + def open_augeas + flags = 0 + (flags = 1 << 2 ) if self.resource[:type_check] == :true + root = self.resource[:root] + load_path = self.resource[:load_path] + debug("Opening augeas with root #{root}, lens path #{load_path}, flags #{flags}") + Augeas.open(root, load_path,flags) + end + + # Used by the need_to_run? method to process get filters. Returns + # true if there is a match, false if otherwise + # Assumes a syntax of get /files/path [COMPARATOR] value + def process_get(cmd_array) + return_value = false + + #validate and tear apart the command + fail ("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 4 + cmd = cmd_array.shift() + path = cmd_array.shift() + comparator = cmd_array.shift() + arg = cmd_array.join(" ") + + #check the value in augeas + aug = open_augeas() + result = aug.get(path) || '' + unless result.nil? + case comparator + when "!=": + return_value = true if !(result == arg) + when "=~": + regex = Regexp.new(arg) + loc = result=~ regex + return_value = true if ! loc.nil? + else + return_value = true if (result.send(comparator, arg)) + end + end + return_value + end + + # Used by the need_to_run? method to process match filters. Returns + # true if there is a match, false if otherwise + def process_match(cmd_array) + return_value = false + + #validate and tear apart the command + fail("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 4 + cmd = cmd_array.shift() + path = cmd_array.shift() + verb = cmd_array.shift() + + #Get the values from augeas + aug = open_augeas() + result = aug.match(path) || '' + # Now do the work + if (!result.nil?) + case verb + when "size": + fail("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length != 2 + comparator = cmd_array.shift() + arg = cmd_array.shift().to_i + return_value = true if (result.size.send(comparator, arg)) + when "include": + arg = cmd_array.join(" ") + return_value = true if result.include?(arg) + when "==": + begin + arg = cmd_array.join(" ") + new_array = eval arg + return_value = true if result == new_array + rescue + fail("Invalid array in command: #{cmd_array.join(" ")}") + end + end + end + return_value + end + + # Determines if augeas acutally needs to run. + def need_to_run? + return_value = true + filter = resource[:onlyif] + unless (filter == "") + cmd_array = filter.split + command = cmd_array[0]; + cmd_array[1]= File.join(resource[:context], cmd_array[1]) + begin + data = nil + case command + when "get" then return_value = process_get(cmd_array) + when "match" then return_value = process_match(cmd_array) + end + rescue Exception => e + fail("Error sending command '#{command}' with params #{cmd_array[1..-1].inspect}/#{e.message}") + end + end + return_value + end + + # Actually execute the augeas changes. + def execute_changes + aug = open_augeas + commands = self.resource[:changes] + commands.each do |cmd_array| + fail("invalid command #{cmd_array.join[" "]}") if cmd_array.length < 2 + command = cmd_array[0] + cmd_array.shift() + cmd_array[0]=File.join(resource[:context], cmd_array[0]) + debug("sending command '#{command}' with params #{cmd_array.inspect}") + begin + case command + when "set": aug.set(cmd_array[0], cmd_array[1]) + when "rm", "remove": aug.rm(cmd_array[0]) + when "clear": aug.clear(cmd_array[0]) + when "insert", "ins": aug.insert(cmd_array[0]) + else fail("Command '#{command}' is not supported") + end + rescue Exception => e + fail("Error sending command '#{command}' with params #{cmd_array.inspect}/#{e.message}") + end + end + success = aug.save() + if (success != true) + fail("Save failed with return code #{success}") + end + + return :executed + end + +end diff --git a/lib/puppet/type/augeas.rb b/lib/puppet/type/augeas.rb new file mode 100644 index 000000000..20b5bbbc9 --- /dev/null +++ b/lib/puppet/type/augeas.rb @@ -0,0 +1,150 @@ +#-- +# Copyright (C) 2008 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Publicretu +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Author: Bryan Kearney <bkearney@redhat.com> + +Puppet::Type.newtype(:augeas) do + include Puppet::Util + + feature :parse_commands, "Parse the command string" + feature :need_to_run?, "If the command should run" + feature :execute_changes, "Actually make the changes" + + @doc = "Apply the changes (single or array of changes) to the filesystem + via the augeas tool. + + Requires: + - augeas to be installed (http://www.augeas.net) + - ruby-augeas bindings + + Sample usage with a string: + augeas{\"test1\" : + context => \"/files/etc/sysconfig/firstboot\", + changes => \"set RUN_FIRSTBOOT YES\" + onlyif => \"match other_value size > 0\" + } + + Sample usage with an array and custom lenses: + augeas{\"jboss_conf\": + context => \"/files\", + changes => [ + \"set /etc/jbossas/jbossas.conf/JBOSS_IP $ipaddress\", + \"set /etc/jbossas/jbossas.conf/JAVA_HOME /usr\" + ], + load_path => \"$/usr/share/jbossas/lenses\", + } + " + + newparam (:name) do + desc "The name of this task. Used for uniqueness" + isnamevar + end + + newparam (:context) do + desc "Optional context path. This value is pre-pended to the paths of all changes" + defaultto "" + end + + newparam (:onlyif) do + desc "Optional augeas command and comparisons to control the execution of this type. + Supported onlyif syntax: + get [AUGEAS_PATH] [COMPARATOR] [STRING] + match [MATCH_PATH] size [COMPARATOR] [INT] + match [MATCH_PATH] include [STRING] + match [MATCH_PATH] == [AN_ARRAY] + + where + AUGEAS_PATH is a valid path scoped by the context + MATCH_PATH is a valid match synatx scoped by the context + COMPARATOR is in the set [> >= != == <= <] + STRING is a string + INT is a number + AN_ARRAY is in the form ['a string', 'another'] " + defaultto "" + end + + + newparam(:changes) do + desc "The changes which should be applied to the filesystem. This + can be either a string which contains a command or an array of commands. + Commands supported are: + + set [PATH] [VALUE] Sets the value VALUE at loction PATH + rm [PATH] Removes the node at location PATH + remove [PATH] Synonym for rm + clear [PATH] Keeps the node at PATH, but removes the value. + ins [PATH] Inserts an empty node at PATH. + insert [PATH] Synonym for ins + + If the parameter 'context' is set that that value is prepended to PATH" + + munge do |value| + provider.parse_commands(value) + end + end + + + newparam(:root) do + desc "A file system path; all files loaded by Augeas are loaded underneath ROOT" + defaultto "/" + end + + newparam(:load_path) do + desc "Optional colon separated list of directories; these directories are searched for schema definitions" + defaultto "" + end + + + newparam(:type_check) do + desc "Set to true if augeas should perform typechecking. Optional, defaults to false" + newvalues(:true, :false) + + defaultto :false + end + + # This is the acutal meat of the code. It forces + # augeas to be run and fails or not based on the augeas return + # code. + newproperty(:returns) do |property| + include Puppet::Util + desc "The expected return code from the augeas command. Should not be set" + + defaultto 0 + + # Make output a bit prettier + def change_to_s(currentvalue, newvalue) + return "executed successfully" + end + + # if the onlyif resource is provided, then the value is parsed. + # a return value of 0 will stop exection becuase it matches the + # default value. + def retrieve + if @resource.provider.need_to_run?() + :need_to_run + else + 0 + end + end + + # Actually execute the command. + def sync + @resource.provider.execute_changes() + end + end + +end |