summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-03-09 23:17:34 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-03-09 23:17:34 +0000
commitb336e7e59d3497b96dd42b6dbc1855176e6e830d (patch)
tree0442207e70709db2237a5131bbe6922e998bba45
parentb6d829b66bc83f943e929b3f6b036b3aff11187f (diff)
Parameters and states can now register regexes as allowed values. Also, there are (finally) tests associated with params and states, although they should be much more comprehensive.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@999 980ebf18-57e1-0310-9a29-db15c13687c0
-rw-r--r--lib/puppet/parameter.rb92
-rw-r--r--lib/puppet/type.rb9
-rw-r--r--lib/puppet/type/state.rb74
-rwxr-xr-xlib/puppet/type/symlink.rb16
-rw-r--r--test/types/parameter.rb107
-rw-r--r--test/types/state.rb92
-rwxr-xr-xtest/types/symlink.rb26
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