diff options
-rw-r--r-- | lib/puppet/parameter.rb | 92 | ||||
-rw-r--r-- | lib/puppet/type.rb | 9 | ||||
-rw-r--r-- | lib/puppet/type/state.rb | 74 | ||||
-rwxr-xr-x | lib/puppet/type/symlink.rb | 16 | ||||
-rw-r--r-- | test/types/parameter.rb | 107 | ||||
-rw-r--r-- | test/types/state.rb | 92 | ||||
-rwxr-xr-x | test/types/symlink.rb | 26 |
7 files changed, 360 insertions, 56 deletions
diff --git a/lib/puppet/parameter.rb b/lib/puppet/parameter.rb index cee53afbf..81b5cb68c 100644 --- a/lib/puppet/parameter.rb +++ b/lib/puppet/parameter.rb @@ -30,6 +30,12 @@ module Puppet @doc = str end + def initvars + @parametervalues = [] + @aliasvalues = {} + @parameterregexes = [] + end + # This is how we munge the value. Basically, this is our # opportunity to convert the value from one form into another. def munge(&block) @@ -56,10 +62,6 @@ module Puppet #@munger = block end - #def inspect - # "Parameter(#{self.name})" - #end - # Mark whether we're the namevar. def isnamevar @isnamevar = true @@ -118,27 +120,46 @@ module Puppet end end + # Does the value match any of our regexes? + def match?(value) + value = value.to_s unless value.is_a? String + @parameterregexes.find { |r| + r = r[0] if r.is_a? Array # States use a hash here + r =~ value + } + end + # Define a new value for our parameter. def newvalues(*names) - @parametervalues ||= [] - names.each { |name| - if @parametervalues.include?(name) - Puppet.warning "%s already has a value for %s" % - [name, name] + name = name.intern if name.is_a? String + + case name + when Symbol + if @parametervalues.include?(name) + Puppet.warning "%s already has a value for %s" % + [name, name] + end + @parametervalues << name + when Regexp + if @parameterregexes.include?(name) + Puppet.warning "%s already has a value for %s" % + [name, name] + end + @parameterregexes << name + else + raise ArgumentError, "Invalid value %s of type %s" % + [name, name.class] end - @parametervalues << name } end def aliasvalue(name, other) - @parametervalues ||= [] unless @parametervalues.include?(other) raise Puppet::DevError, "Cannot alias nonexistent value %s" % other end - @aliasvalues ||= {} @aliasvalues[name] = other end @@ -146,11 +167,12 @@ module Puppet @aliasvalues[name] end + def regexes + return @parameterregexes.dup + end + # Return the list of valid values. def values - @parametervalues ||= [] - @aliasvalues ||= {} - #[@aliasvalues.keys, @parametervalues.keys].flatten if @parametervalues.is_a? Array return @parametervalues.dup @@ -240,7 +262,7 @@ module Puppet # If the specified value is allowed, then munge appropriately. munge do |value| - if self.class.values.empty? + if self.class.values.empty? and self.class.regexes.empty? # This parameter isn't using defined values to do its work. return value end @@ -254,25 +276,51 @@ module Puppet retval = intern elsif other = self.class.alias(intern) retval = other + elsif ary = self.class.match?(value) + retval = value else + # If it passed the validation but is not a registered value, + # we just return it as is. retval = value end + retval end # Verify that the passed value is valid. validate do |value| - values = self.class.values - if values.empty? + vals = self.class.values + regs = self.class.regexes + + if regs.is_a? Hash # this is true on states + regs = regs.keys + end + if vals.empty? and regs.empty? # This parameter isn't using defined values to do its work. return end + newval = value unless value.is_a?(Symbol) - value = value.to_s.intern + newval = value.to_s.intern end - unless values.include?(value) or self.class.alias(value) - self.fail "Invalid '%s' value '%s'. Valid values are '%s'" % - [self.class.name, value, values.join(", ")] + + unless vals.include?(newval) or + self.class.alias(newval) or + self.class.match?(value) # We match the string, not the symbol + str = "Invalid '%s' value %s. " % + [self.class.name, value.inspect] + + unless vals.empty? + str += "Valid values are %s. " % vals.join(", ") + end + + unless regs.empty? + str += "Valid values match %s." % regs.collect { |r| + r.to_s + }.join(", ") + end + + raise ArgumentError, str end end diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index 9adcf54b4..a50f24f75 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -417,6 +417,9 @@ class Type < Puppet::Element param = Class.new(Puppet::Parameter) do @name = name end + + param.initvars + param.ismetaparameter param.class_eval(&block) const_set("MetaParam" + name.to_s.capitalize,param) @@ -440,6 +443,9 @@ class Type < Puppet::Element param = Class.new(Puppet::Parameter) do @name = name end + + param.initvars + param.element = self param.class_eval(&block) const_set("Parameter" + name.to_s.capitalize,param) @@ -475,6 +481,9 @@ class Type < Puppet::Element s = Class.new(parent) do @name = name end + + s.initvars + const_set("State" + name.to_s.capitalize,s) s.class_eval(&block) @states ||= [] diff --git a/lib/puppet/type/state.rb b/lib/puppet/type/state.rb index 38cf7fc9e..17a004056 100644 --- a/lib/puppet/type/state.rb +++ b/lib/puppet/type/state.rb @@ -18,26 +18,34 @@ class State < Puppet::Parameter class << self attr_accessor :unmanaged attr_reader :name + end - #def inspect - # "State(%s)" % self.name - #end - - #def to_s - # self.inspect - #end + # Create the value management variables. + def self.initvars + @parametervalues = {} + @aliasvalues = {} + @parameterregexes = {} end - # Parameters just use 'newvalues', since there's no work associated with them. + # Parameters just use 'newvalues', since there's no work associated with them, + # but states have blocks associated with their allowed values. def self.newvalue(name, &block) - @parametervalues ||= {} + name = name.intern if name.is_a? String - if @parametervalues.include?(name) - Puppet.warning "%s already has a value for %s" % [name, name] - end - @parametervalues[name] = block + case name + when Symbol + if @parametervalues.include?(name) + Puppet.warning "%s reassigning value %s" % [self.name, name] + end + @parametervalues[name] = block - define_method("set_" + name.to_s, &block) + define_method("set_" + name.to_s, &block) + when Regexp + @parameterregexes[name] = block + else + raise ArgumentError, "Invalid value %s of type %s" % + [name, name.class] + end end # Call the method associated with a given value. @@ -49,22 +57,26 @@ class State < Puppet::Parameter value = self.should method = "set_" + value.to_s - unless self.respond_to?(method) - self.fail "%s is not a valid value for %s" % - [value, self.class.name] - end - self.debug "setting %s (currently %s)" % [value, self.is] + event = nil + if self.respond_to?(method) + self.debug "setting %s (currently %s)" % [value, self.is] - begin - event = self.send(method) - rescue Puppet::Error - raise - rescue => detail - if Puppet[:debug] - puts detail.backtrace + begin + event = self.send(method) + rescue Puppet::Error + raise + rescue => detail + if Puppet[:debug] + puts detail.backtrace + end + self.fail "Could not set %s on %s: %s" % + [value, self.class.name, detail] end - self.fail "Could not set %s on %s: %s" % - [value, self.class.name, detail] + elsif ary = self.class.match?(value) + event = ary[1].call(value) + else + self.fail "%s is not a valid value for %s" % + [value, self.class.name] end if event and event.is_a?(Symbol) @@ -186,7 +198,11 @@ class State < Puppet::Parameter # return the full path to us, for logging and rollback; not currently # used def path - return [@parent.path, self.name].join("/") + if defined? @parent and @parent + return [@parent.path, self.name].join("/") + else + return self.name + end end # Only return the first value diff --git a/lib/puppet/type/symlink.rb b/lib/puppet/type/symlink.rb index a0b36f0cf..cb05c3a88 100755 --- a/lib/puppet/type/symlink.rb +++ b/lib/puppet/type/symlink.rb @@ -65,7 +65,7 @@ module Puppet end # this is somewhat complicated, because it could exist and be - # a file + # a link def sync case self.should when :absent @@ -101,6 +101,8 @@ module Puppet copyparam(Puppet.type(:file), :path) newparam(:recurse) do + attr_reader :setparent + desc "If target is a directory, recursively create directories (using `file`'s `source` parameter) and link all contained files. For instance:: @@ -109,7 +111,7 @@ module Puppet # in /opt/csw; link it into /usr/local symlink { \"/usr/local\": ensure => \"/opt/csw\", - recurse => 1 + recurse => true } @@ -120,13 +122,16 @@ module Puppet @stat = nil @target = @parent.state(:ensure).should + self.setparent() + end + + def setparent # we want to remove our state, because we're creating children # to do the links if FileTest.exist?(@target) - @stat = File.stat(@target) + @stat = File.lstat(@target) else - @parent.info "Target %s must exist for recursive links" % - @target + @setparent = false return end @@ -168,6 +173,7 @@ module Puppet dir = Puppet.type(:file).implicitcreate(args) dir.parent = @parent @parent.push dir + @setparent = true end end diff --git a/test/types/parameter.rb b/test/types/parameter.rb new file mode 100644 index 000000000..d95ef461d --- /dev/null +++ b/test/types/parameter.rb @@ -0,0 +1,107 @@ +if __FILE__ == $0 + $:.unshift '..' + $:.unshift '../../lib' + $puppetbase = "../.." +end + +require 'puppet/type' +require 'puppettest' +require 'test/unit' + +class TestState < Test::Unit::TestCase + include TestPuppet + + def newparam(name = :fakeparam) + assert_nothing_raised { + param = Class.new(Puppet::Parameter) do + @name = :fakeparam + end + param.initvars + + return param + } + end + + def newinst(param) + assert_nothing_raised { + return param.new + } + end + + # Test the basic newvalue stuff. + def test_newvalue + param = newparam() + + # Try it with both symbols and strings. + assert_nothing_raised { + param.newvalues(:one, "two") + } + + inst = newinst(param) + + assert_nothing_raised { + inst.value = "one" + } + + assert_equal(:one, inst.value) + + assert_nothing_raised { + inst.value = :two + } + assert_equal(:two, inst.value) + + assert_raise(ArgumentError) { + inst.value = :three + } + assert_equal(:two, inst.value) + end + + # Test using regexes. + def test_regexvalues + param = newparam + + assert_nothing_raised { + param.newvalues(/^\d+$/) + } + assert(param.match?("14")) + assert(param.match?(14)) + + inst = newinst(param) + + assert_nothing_raised { + inst.value = 14 + } + + assert_nothing_raised { + inst.value = "14" + } + + assert_raise(ArgumentError) { + inst.value = "a14" + } + end + + # Test using both. Equality should beat matching. + def test_regexesandnormals + param = newparam + + assert_nothing_raised { + param.newvalues(:one, /^\w+$/) + } + + inst = newinst(param) + + assert_nothing_raised { + inst.value = "one" + } + + assert_equal(:one, inst.value, "Value used regex instead of equality") + + assert_nothing_raised { + inst.value = "two" + } + assert_equal("two", inst.value, "Matched value didn't take") + end +end + +# $Id$ diff --git a/test/types/state.rb b/test/types/state.rb new file mode 100644 index 000000000..88df6575d --- /dev/null +++ b/test/types/state.rb @@ -0,0 +1,92 @@ +if __FILE__ == $0 + $:.unshift '..' + $:.unshift '../../lib' + $puppetbase = "../.." +end + +require 'puppet/type' +require 'puppettest' +require 'test/unit' + +class TestState < Test::Unit::TestCase + include TestPuppet + + def newinst(state) + inst = nil + assert_nothing_raised { + return state.new(:parent => nil) + } + end + + def newstate(name = :fakestate) + assert_nothing_raised { + state = Class.new(Puppet::State) do + @name = :fakeparam + end + state.initvars + + return state + } + end + + def test_newvalue + state = newstate() + + assert_nothing_raised { + state.newvalue(:one) do + @is = 1 + end + } + + assert_nothing_raised { + state.newvalue("two") do + @is = 2 + end + } + + inst = newinst(state) + + assert_nothing_raised { + inst.should = "one" + } + + assert_equal(:one, inst.should) + assert_nothing_raised { inst.set_one } + assert_equal(1, inst.is) + + assert_nothing_raised { + inst.should = :two + } + + assert_equal(:two, inst.should) + assert_nothing_raised { inst.set_two } + assert_equal(2, inst.is) + end + + def test_newvaluewithregexes + state = newstate() + + assert_nothing_raised { + state.newvalue(/^\w+$/) do |value| + @is = value.upcase + return :regex_matched + end + } + + inst = newinst(state) + + assert_nothing_raised { + inst.should = "yayness" + } + + assert_equal("yayness", inst.should) + + assert_nothing_raised { + inst.sync + } + + assert_equal("yayness".upcase, inst.is) + end +end + +# $Id$ diff --git a/test/types/symlink.rb b/test/types/symlink.rb index a07a2fbb6..21b1e865b 100755 --- a/test/types/symlink.rb +++ b/test/types/symlink.rb @@ -88,4 +88,30 @@ class TestSymlink < Test::Unit::TestCase } } end + + def test_createdrecursion + source = tempfile() + file = File.join(source, "file") + dest = tempfile() + link = File.join(dest, "file") + + objects = [] + objects << Puppet.type(:file).create( + :path => source, + :ensure => "directory" + ) + objects << Puppet.type(:file).create( + :path => file, + :ensure => "file" + ) + objects << Puppet.type(:symlink).create( + :path => dest, + :ensure => source, + :recurse => true + ) + + assert_apply(*objects) + + assert(FileTest.symlink?(link), "Link was not created") + end end |