diff options
-rw-r--r-- | CHANGELOG | 19 | ||||
-rw-r--r-- | conf/gentoo/puppet/puppet.conf | 58 | ||||
-rw-r--r-- | ext/ldap/puppet.schema | 7 | ||||
-rw-r--r-- | lib/puppet/defaults.rb | 1 | ||||
-rw-r--r-- | lib/puppet/indirector/node/exec.rb | 2 | ||||
-rw-r--r-- | lib/puppet/indirector/node/ldap.rb | 5 | ||||
-rw-r--r-- | lib/puppet/node/catalog.rb | 10 | ||||
-rw-r--r-- | lib/puppet/parser/compiler.rb | 1 | ||||
-rw-r--r-- | lib/puppet/parser/resource.rb | 37 | ||||
-rw-r--r-- | lib/puppet/provider/package/portage.rb | 8 | ||||
-rw-r--r-- | lib/puppet/sslcertificates/ca.rb | 30 | ||||
-rwxr-xr-x | lib/puppet/type/file/checksum.rb | 3 | ||||
-rwxr-xr-x | lib/puppet/type/tidy.rb | 2 | ||||
-rw-r--r-- | lib/puppet/util/settings.rb | 96 | ||||
-rwxr-xr-x | spec/unit/indirector/node/exec.rb | 6 | ||||
-rwxr-xr-x | spec/unit/indirector/node/ldap.rb | 195 | ||||
-rwxr-xr-x | spec/unit/node/catalog.rb | 2 | ||||
-rwxr-xr-x | spec/unit/parser/resource.rb | 161 | ||||
-rwxr-xr-x | test/language/resource.rb | 159 |
19 files changed, 422 insertions, 380 deletions
@@ -1,3 +1,22 @@ + The change in checksums from 'timestamp' to 'mtime' no longer + result in updates on every run (#1116). + + Aliases again work in relationships (#1094). + + The CA serial file will no longer ever be owned by + root (#1041). + + Fixing the rest of #1113: External node commands can specify + an environment and Puppet will now use it. + + Partially fixing #1113: LDAP nodes now support environments, + and the schema has been updated accordingly. + + Always duplicating resource defaults in the parser, so that + stacked metaparameter values do not result in all resources + that receive a given default also getting those stacked + values. + 0.24.2 Fixing #1062 by moving the yamldir setting to its own yaml section. This should keep the yamldir from being created diff --git a/conf/gentoo/puppet/puppet.conf b/conf/gentoo/puppet/puppet.conf index 1d62c90e4..70dcb02da 100644 --- a/conf/gentoo/puppet/puppet.conf +++ b/conf/gentoo/puppet/puppet.conf @@ -1,29 +1,29 @@ -[main] - # Where Puppet stores dynamic and growing data. - # The default value is '/var/puppet'. - vardir = /var/lib/puppet - - # The Puppet log directory. - # The default value is '$vardir/log'. - logdir = /var/log/puppet - - # Where Puppet PID files are kept. - # The default value is '$vardir/run'. - rundir = /var/run/puppet - - # Where SSL certificates are kept. - # The default value is '$confdir/ssl'. - ssldir = $vardir/ssl - -[puppetd] - # The file in which puppetd stores a list of the classes - # associated with the retrieved configuratiion. Can be loaded in - # the separate ``puppet`` executable using the ``--loadclasses`` - # option. - # The default value is '$confdir/classes.txt'. - classfile = $vardir/classes.txt - - # Where puppetd caches the local configuration. An - # extension indicating the cache format is added automatically. - # The default value is '$confdir/localconfig'. - localconfig = $vardir/localconfig +[main] + # Where Puppet stores dynamic and growing data. + # The default value is '/var/puppet'. + vardir = /var/lib/puppet + + # The Puppet log directory. + # The default value is '$vardir/log'. + logdir = /var/log/puppet + + # Where Puppet PID files are kept. + # The default value is '$vardir/run'. + rundir = /var/run/puppet + + # Where SSL certificates are kept. + # The default value is '$confdir/ssl'. + ssldir = $vardir/ssl + +[puppetd] + # The file in which puppetd stores a list of the classes + # associated with the retrieved configuratiion. Can be loaded in + # the separate ``puppet`` executable using the ``--loadclasses`` + # option. + # The default value is '$confdir/classes.txt'. + classfile = $vardir/classes.txt + + # Where puppetd caches the local configuration. An + # extension indicating the cache format is added automatically. + # The default value is '$confdir/localconfig'. + localconfig = $vardir/localconfig diff --git a/ext/ldap/puppet.schema b/ext/ldap/puppet.schema index b7c715ec2..bbad23eab 100644 --- a/ext/ldap/puppet.schema +++ b/ext/ldap/puppet.schema @@ -12,6 +12,11 @@ attributetype ( 1.1.3.9 NAME 'parentnode' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +attributetype ( 1.1.3.9 NAME 'environment' + DESC 'Puppet Node Environment' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + objectclass ( 1.1.1.2 NAME 'puppetClient' SUP top AUXILIARY DESC 'Puppet Client objectclass' - MAY ( puppetclass $ parentnode )) + MAY ( puppetclass $ parentnode $ environment )) diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 6dbd7d043..2f5992d22 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -258,6 +258,7 @@ module Puppet :serial => { :default => "$cadir/serial", :owner => "$user", :group => "$group", + :mode => 0600, :desc => "Where the serial number for certificates is stored." }, :autosign => { :default => "$confdir/autosign.conf", diff --git a/lib/puppet/indirector/node/exec.rb b/lib/puppet/indirector/node/exec.rb index ed76bce94..71f4fa8e1 100644 --- a/lib/puppet/indirector/node/exec.rb +++ b/lib/puppet/indirector/node/exec.rb @@ -30,7 +30,7 @@ class Puppet::Node::Exec < Puppet::Indirector::Exec def create_node(name, result) node = Puppet::Node.new(name) set = false - [:parameters, :classes].each do |param| + [:parameters, :classes, :environment].each do |param| if value = result[param] node.send(param.to_s + "=", value) set = true diff --git a/lib/puppet/indirector/node/ldap.rb b/lib/puppet/indirector/node/ldap.rb index dd11f4e9b..9320f3ba1 100644 --- a/lib/puppet/indirector/node/ldap.rb +++ b/lib/puppet/indirector/node/ldap.rb @@ -36,11 +36,14 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap information[:parameters][param] = value unless information[:parameters].include?(param) end + information[:environment] ||= parent_info[:environment] + parent = parent_info[:parent] end node.classes = information[:classes].uniq unless information[:classes].empty? node.parameters = information[:parameters] unless information[:parameters].empty? + node.environment = information[:environment] if information[:environment] node.fact_merge return node @@ -87,6 +90,8 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap hash end + result[:environment] = result[:parameters]["environment"] if result[:parameters]["environment"] + return result end diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb index f885a41ee..ecda472be 100644 --- a/lib/puppet/node/catalog.rb +++ b/lib/puppet/node/catalog.rb @@ -84,6 +84,7 @@ class Puppet::Node::Catalog < Puppet::PGraph # Create an alias for a resource. def alias(resource, name) + #set $1 resource.ref =~ /^(.+)\[/ newref = "%s[%s]" % [$1 || resource.class.name, name] @@ -475,6 +476,15 @@ class Puppet::Node::Catalog < Puppet::PGraph vertices.each do |resource| next if resource.respond_to?(:virtual?) and resource.virtual? + #This is hackity hack for 1094 + #Aliases aren't working in the ral catalog because the current instance of the resource + #has a reference to the catalog being converted. . . So, give it a reference to the new one + #problem solved. . . + if resource.is_a?(Puppet::TransObject) + resource = resource.dup + resource.catalog = result + end + newres = resource.send(convert) # We can't guarantee that resources don't munge their names diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index 70cd6e11a..8fba41121 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -366,7 +366,6 @@ class Puppet::Parser::Compiler # Make sure all of our resources and such have done any last work # necessary. def finish - #@catalog.resources.each do |name| @catalog.vertices.each do |resource| # Add in any resource overrides. if overrides = resource_overrides(resource) diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index b001e165b..4b48ff6cf 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -233,6 +233,20 @@ class Puppet::Parser::Resource @ref.to_s end + # Define a parameter in our resource. + def set_parameter(param, value = nil) + if value + param = Puppet::Parser::Resource::Param.new( + :name => param, :value => value, :source => self.source + ) + elsif ! param.is_a?(Puppet::Parser::Resource::Param) + raise ArgumentError, "Must pass a parameter or all necessary values" + end + + # And store it in our parameter hash. + @params[param.name] = param + end + def to_hash @params.inject({}) do |hash, ary| param = ary[1] @@ -331,7 +345,7 @@ class Puppet::Parser::Resource unless @params.include?(name) self.debug "Adding default for %s" % name - @params[name] = param + @params[name] = param.dup end end end @@ -370,11 +384,8 @@ class Puppet::Parser::Resource # The parameter is already set. Fail if they're not allowed to override it. unless param.source.child_of?(current.source) - if Puppet[:trace] - puts caller - end - msg = "Parameter '%s' is already set on %s" % - [param.name, self.to_s] + puts caller if Puppet[:trace] + msg = "Parameter '%s' is already set on %s" % [param.name, self.to_s] if current.source.to_s != "" msg += " by %s" % current.source end @@ -426,20 +437,6 @@ class Puppet::Parser::Resource end end - # Define a parameter in our resource. - def set_parameter(param, value = nil) - if value - param = Puppet::Parser::Resource::Param.new( - :name => param, :value => value, :source => self.source - ) - elsif ! param.is_a?(Puppet::Parser::Resource::Param) - raise ArgumentError, "Must pass a parameter or all necessary values" - end - - # And store it in our parameter hash. - @params[param.name] = param - end - # Make sure the resource's parameters are all valid for the type. def validate @params.each do |name, param| diff --git a/lib/puppet/provider/package/portage.rb b/lib/puppet/provider/package/portage.rb index dccfeaf56..f795d0302 100644 --- a/lib/puppet/provider/package/portage.rb +++ b/lib/puppet/provider/package/portage.rb @@ -10,8 +10,8 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa defaultfor :operatingsystem => :gentoo def self.instances - result_format = /(\S+) (\S+) \[([^\[]*)(\[[^\]]*\])?\] \[[^0-9]*([^\s:\[]*)(\[[^\]]*\])?(:\S*)?\] ([\S]*) (.*)/ - result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :overlay, :slot, :vendor, :description] + result_format = /(\S+) (\S+) \[(?:([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\([^\)]+\))?(?:\[([^\]]+)\])?[ ]*)*\] \[(?:(?:\{M\})?(?:\([~*]+\))?([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\(([^\)]+)\))?(?:![mf])*(?:\[([^\]]+)\])?)?\] ([\S]*) (.*)/ + result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :slot, :overlay, :vendor, :description] search_format = "{installedversionsshort}<category> <name> [<installedversionsshort>] [<best>] <homepage> <description>{}" @@ -67,8 +67,8 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa end def query - result_format = /(\S+) (\S+) \[([^\[]*)(\[[^\]]*\])?\] \[[^0-9]*([^\s:\[]*)(\[[^\]]*\])?(:\S*)?\] ([\S]*) (.*)/ - result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :overlay, :slot, :vendor, :description] + result_format = /(\S+) (\S+) \[(?:([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\([^\)]+\))?(?:\[([^\]]+)\])?[ ]*)*\] \[(?:(?:\{M\})?(?:\([~*]+\))?([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\(([^\)]+)\))?(?:![mf])*(?:\[([^\]]+)\])?)?\] ([\S]*) (.*)/ + result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :slot, :overlay, :vendor, :description] search_field = @resource[:category] ? "--category-name" : "--name" search_value = package_name diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb index 888bcf5b2..7386318f4 100644 --- a/lib/puppet/sslcertificates/ca.rb +++ b/lib/puppet/sslcertificates/ca.rb @@ -238,33 +238,6 @@ class Puppet::SSLCertificates::CA } end - # Create an exclusive lock for reading and writing, and do the - # writing in a tmp file. - def readwritelock(file, mode = 0600) - tmpfile = file + ".tmp" - sync = Sync.new - unless FileTest.directory?(File.dirname(tmpfile)) - raise Puppet::DevError, "Cannot create %s; directory %s does not exist" % - [file, File.dirname(file)] - end - sync.synchronize(Sync::EX) do - File.open(file, "r+", mode) do |rf| - rf.lock_exclusive do - File.open(tmpfile, "w", mode) do |tf| - yield tf - end - begin - File.rename(tmpfile, file) - rescue => detail - Puppet.err "Could not rename %s to %s: %s" % - [file, tmpfile, detail] - end - end - end - end - end - - # Sign a given certificate request. def sign(csr) unless csr.is_a?(OpenSSL::X509::Request) @@ -278,9 +251,8 @@ class Puppet::SSLCertificates::CA end serial = nil - readwritelock(@config[:serial]) { |f| + Puppet.settings.readwritelock(:serial) { |f| serial = File.read(@config[:serial]).chomp.hex - # increment the serial f << "%04X" % (serial + 1) } diff --git a/lib/puppet/type/file/checksum.rb b/lib/puppet/type/file/checksum.rb index debb5a7db..3be147cb7 100755 --- a/lib/puppet/type/file/checksum.rb +++ b/lib/puppet/type/file/checksum.rb @@ -66,6 +66,9 @@ Puppet::Type.type(:file).newproperty(:checksum) do raise ArgumentError, "A type must be specified to cache a checksum" end type = symbolize(type) + type = :mtime if type == :timestamp + type = :ctime if type == :time + unless state = @resource.cached(:checksums) self.debug "Initializing checksum hash" state = {} diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb index dacf037ac..fe8bde9ab 100755 --- a/lib/puppet/type/tidy.rb +++ b/lib/puppet/type/tidy.rb @@ -1,5 +1,5 @@ module Puppet - newtype(:tidy, Puppet.type(:file)) do + newtype(:tidy, :parent => Puppet.type(:file)) do @doc = "Remove unwanted files based on specific criteria. Multiple criteria are OR'd together, so a file that is too large but is not old enough will still get tidied." diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index 5f4a98558..f4055c304 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -243,14 +243,7 @@ class Puppet::Util::Settings # Make a directory with the appropriate user, group, and mode def mkdir(default) - obj = nil - unless obj = @config[default] - raise ArgumentError, "Unknown default %s" % default - end - - unless obj.is_a? CFile - raise ArgumentError, "Default %s is not a file" % default - end + obj = get_config_file_default(default) Puppet::Util::SUIDManager.asuser(obj.owner, obj.group) do mode = obj.mode || 0750 @@ -649,49 +642,15 @@ Generated on #{Time.now}. end # Open a file with the appropriate user, group, and mode - def write(default, *args) - obj = nil - unless obj = @config[default] - raise ArgumentError, "Unknown default %s" % default - end - - unless obj.is_a? CFile - raise ArgumentError, "Default %s is not a file" % default - end - - chown = nil - if Puppet::Util::SUIDManager.uid == 0 - chown = [obj.owner, obj.group] - else - chown = [nil, nil] - end - Puppet::Util::SUIDManager.asuser(*chown) do - mode = obj.mode || 0640 - - if args.empty? - args << "w" - end - - args << mode - - File.open(value(obj.name), *args) do |file| - yield file - end - end + def write(default, *args, &bloc) + obj = get_config_file_default(default) + writesub(default, value(obj.name), *args, &bloc) end # Open a non-default file under a default dir with the appropriate user, # group, and mode - def writesub(default, file, *args) - obj = nil - unless obj = @config[default] - raise ArgumentError, "Unknown default %s" % default - end - - unless obj.is_a? CFile - raise ArgumentError, "Default %s is not a file" % default - end - + def writesub(default, file, *args, &bloc) + obj = get_config_file_default(default) chown = nil if Puppet::Util::SUIDManager.uid == 0 chown = [obj.owner, obj.group] @@ -716,8 +675,51 @@ Generated on #{Time.now}. end end + def readwritelock(default, *args, &bloc) + file = value(get_config_file_default(default).name) + tmpfile = file + ".tmp" + sync = Sync.new + unless FileTest.directory?(File.dirname(tmpfile)) + raise Puppet::DevError, "Cannot create %s; directory %s does not exist" % + [file, File.dirname(file)] + end + + sync.synchronize(Sync::EX) do + File.open(file, "r+", 0600) do |rf| + rf.lock_exclusive do + if File.exist?(tmpfile) + raise Puppet::Error, ".tmp file already exists for %s; Aborting locked write. Check the .tmp file and delete if appropriate" % + [file] + end + + writesub(default, tmpfile, *args, &bloc) + + begin + File.rename(tmpfile, file) + rescue => detail + Puppet.err "Could not rename %s to %s: %s" % + [file, tmpfile, detail] + end + end + end + end + end + private + def get_config_file_default(default) + obj = nil + unless obj = @config[default] + raise ArgumentError, "Unknown default %s" % default + end + + unless obj.is_a? CFile + raise ArgumentError, "Default %s is not a file" % default + end + + return obj + end + # Create the transportable objects for users and groups. def add_user_resources(section, obj, done) resources = [] diff --git a/spec/unit/indirector/node/exec.rb b/spec/unit/indirector/node/exec.rb index 744a32b0a..5e6a9b1da 100755 --- a/spec/unit/indirector/node/exec.rb +++ b/spec/unit/indirector/node/exec.rb @@ -59,4 +59,10 @@ describe Puppet::Node::Exec, " when handling the results of the command" do @node.expects(:fact_merge) @searcher.find(@name) end + + it "should set the node's environment if one is provided" do + @result[:environment] = "yay" + @node.expects(:environment=).with "yay" + @searcher.find(@name) + end end diff --git a/spec/unit/indirector/node/ldap.rb b/spec/unit/indirector/node/ldap.rb index 95b73de60..2a4f240ed 100755 --- a/spec/unit/indirector/node/ldap.rb +++ b/spec/unit/indirector/node/ldap.rb @@ -5,27 +5,26 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/indirector/node/ldap' describe Puppet::Node::Ldap do - before :each do - @searcher = Puppet::Node::Ldap.new - @entries = {} - entries = @entries - - @connection = mock 'connection' - @entry = mock 'entry' - @connection.stubs(:search).yields(@entry) - @searcher.stubs(:connection).returns(@connection) - @searcher.stubs(:class_attributes).returns([]) - @searcher.stubs(:parent_attribute).returns(nil) - @searcher.stubs(:search_base).returns(:yay) - @searcher.stubs(:search_filter).returns(:filter) - - @node = mock 'node' - @node.stubs(:fact_merge) - @name = "mynode" - Puppet::Node.stubs(:new).with(@name).returns(@node) - end - - describe Puppet::Node::Ldap, " when searching for nodes" do + describe "when searching for nodes" do + before :each do + @searcher = Puppet::Node::Ldap.new + @entries = {} + entries = @entries + + @connection = mock 'connection' + @entry = mock 'entry' + @connection.stubs(:search).yields(@entry) + @searcher.stubs(:connection).returns(@connection) + @searcher.stubs(:class_attributes).returns([]) + @searcher.stubs(:parent_attribute).returns(nil) + @searcher.stubs(:search_base).returns(:yay) + @searcher.stubs(:search_filter).returns(:filter) + + @node = mock 'node' + @node.stubs(:fact_merge) + @name = "mynode" + Puppet::Node.stubs(:new).with(@name).returns(@node) + end it "should return nil if no results are found in ldap" do @connection.stubs(:search) @@ -61,6 +60,13 @@ describe Puppet::Node::Ldap do @searcher.find("mynode") end + it "should set the node's environment to the environment of the results" do + @entry.stubs(:to_hash).returns("environment" => ["test"]) + @node.stubs(:parameters=) + @node.expects(:environment=).with("test") + @searcher.find("mynode") + end + it "should retain false parameter values" do @entry.stubs(:to_hash).returns("one" => [false]) @node.expects(:parameters=).with("one" => false) @@ -78,91 +84,114 @@ describe Puppet::Node::Ldap do @node.expects(:parameters=).with("one" => ["a", "b"]) @searcher.find("mynode") end - end - describe Puppet::Node::Ldap, " when a parent node is specified" do + describe "and a parent node is specified" do + before do + @parent = mock 'parent' + @parent_parent = mock 'parent_parent' - before do - @parent = mock 'parent' - @parent_parent = mock 'parent_parent' + @searcher.meta_def(:search_filter) do |name| + return name + end + @connection.stubs(:search).with { |*args| args[2] == @name }.yields(@entry) + @connection.stubs(:search).with { |*args| args[2] == 'parent' }.yields(@parent) + @connection.stubs(:search).with { |*args| args[2] == 'parent_parent' }.yields(@parent_parent) - @searcher.meta_def(:search_filter) do |name| - return name + @searcher.stubs(:parent_attribute).returns(:parent) end - @connection.stubs(:search).with { |*args| args[2] == @name }.yields(@entry) - @connection.stubs(:search).with { |*args| args[2] == 'parent' }.yields(@parent) - @connection.stubs(:search).with { |*args| args[2] == 'parent_parent' }.yields(@parent_parent) - @searcher.stubs(:parent_attribute).returns(:parent) - end + it "should fail if the parent cannot be found" do + @connection.stubs(:search).with { |*args| args[2] == 'parent' }.returns("whatever") - it "should fail if the parent cannot be found" do - @connection.stubs(:search).with { |*args| args[2] == 'parent' }.returns("whatever") + @entry.stubs(:to_hash).returns({}) + @entry.stubs(:vals).with(:parent).returns(%w{parent}) - @entry.stubs(:to_hash).returns({}) - @entry.stubs(:vals).with(:parent).returns(%w{parent}) + proc { @searcher.find("mynode") }.should raise_error(Puppet::Error) + end - proc { @searcher.find("mynode") }.should raise_error(Puppet::Error) - end + it "should add any parent classes to the node's classes" do + @entry.stubs(:to_hash).returns({}) + @entry.stubs(:vals).with(:parent).returns(%w{parent}) + @entry.stubs(:vals).with("classes").returns(%w{a b}) - it "should add any parent classes to the node's classes" do - @entry.stubs(:to_hash).returns({}) - @entry.stubs(:vals).with(:parent).returns(%w{parent}) - @entry.stubs(:vals).with("classes").returns(%w{a b}) + @parent.stubs(:to_hash).returns({}) + @parent.stubs(:vals).with("classes").returns(%w{c d}) + @parent.stubs(:vals).with(:parent).returns(nil) - @parent.stubs(:to_hash).returns({}) - @parent.stubs(:vals).with("classes").returns(%w{c d}) - @parent.stubs(:vals).with(:parent).returns(nil) + @searcher.stubs(:class_attributes).returns(%w{classes}) + @node.expects(:classes=).with(%w{a b c d}) + @searcher.find("mynode") + end - @searcher.stubs(:class_attributes).returns(%w{classes}) - @node.expects(:classes=).with(%w{a b c d}) - @searcher.find("mynode") - end + it "should add any parent parameters to the node's parameters" do + @entry.stubs(:to_hash).returns("one" => "two") + @entry.stubs(:vals).with(:parent).returns(%w{parent}) - it "should add any parent parameters to the node's parameters" do - @entry.stubs(:to_hash).returns("one" => "two") - @entry.stubs(:vals).with(:parent).returns(%w{parent}) + @parent.stubs(:to_hash).returns("three" => "four") + @parent.stubs(:vals).with(:parent).returns(nil) - @parent.stubs(:to_hash).returns("three" => "four") - @parent.stubs(:vals).with(:parent).returns(nil) + @node.expects(:parameters=).with("one" => "two", "three" => "four") + @searcher.find("mynode") + end - @node.expects(:parameters=).with("one" => "two", "three" => "four") - @searcher.find("mynode") - end + it "should prefer node parameters over parent parameters" do + @entry.stubs(:to_hash).returns("one" => "two") + @entry.stubs(:vals).with(:parent).returns(%w{parent}) - it "should prefer node parameters over parent parameters" do - @entry.stubs(:to_hash).returns("one" => "two") - @entry.stubs(:vals).with(:parent).returns(%w{parent}) + @parent.stubs(:to_hash).returns("one" => "three") + @parent.stubs(:vals).with(:parent).returns(nil) - @parent.stubs(:to_hash).returns("one" => "three") - @parent.stubs(:vals).with(:parent).returns(nil) + @node.expects(:parameters=).with("one" => "two") + @searcher.find("mynode") + end - @node.expects(:parameters=).with("one" => "two") - @searcher.find("mynode") - end + it "should use the parent's environment if the node has none" do + @entry.stubs(:to_hash).returns({}) + @entry.stubs(:vals).with(:parent).returns(%w{parent}) - it "should recursively look up parent information" do - @entry.stubs(:to_hash).returns("one" => "two") - @entry.stubs(:vals).with(:parent).returns(%w{parent}) + @parent.stubs(:to_hash).returns("environment" => ["parent"]) + @parent.stubs(:vals).with(:parent).returns(nil) - @parent.stubs(:to_hash).returns("three" => "four") - @parent.stubs(:vals).with(:parent).returns(['parent_parent']) + @node.stubs(:parameters=) + @node.expects(:environment=).with("parent") + @searcher.find("mynode") + end - @parent_parent.stubs(:to_hash).returns("five" => "six") - @parent_parent.stubs(:vals).with(:parent).returns(nil) - @parent_parent.stubs(:vals).with(:parent).returns(nil) + it "should prefer the node's environment to the parent's" do + @entry.stubs(:to_hash).returns("environment" => %w{child}) + @entry.stubs(:vals).with(:parent).returns(%w{parent}) - @node.expects(:parameters=).with("one" => "two", "three" => "four", "five" => "six") - @searcher.find("mynode") - end + @parent.stubs(:to_hash).returns("environment" => ["parent"]) + @parent.stubs(:vals).with(:parent).returns(nil) + + @node.stubs(:parameters=) + @node.expects(:environment=).with("child") + @searcher.find("mynode") + end + + it "should recursively look up parent information" do + @entry.stubs(:to_hash).returns("one" => "two") + @entry.stubs(:vals).with(:parent).returns(%w{parent}) + + @parent.stubs(:to_hash).returns("three" => "four") + @parent.stubs(:vals).with(:parent).returns(['parent_parent']) - it "should not allow loops in parent declarations" do - @entry.stubs(:to_hash).returns("one" => "two") - @entry.stubs(:vals).with(:parent).returns(%w{parent}) + @parent_parent.stubs(:to_hash).returns("five" => "six") + @parent_parent.stubs(:vals).with(:parent).returns(nil) + @parent_parent.stubs(:vals).with(:parent).returns(nil) - @parent.stubs(:to_hash).returns("three" => "four") - @parent.stubs(:vals).with(:parent).returns([@name]) - proc { @searcher.find("mynode") }.should raise_error(ArgumentError) + @node.expects(:parameters=).with("one" => "two", "three" => "four", "five" => "six") + @searcher.find("mynode") + end + + it "should not allow loops in parent declarations" do + @entry.stubs(:to_hash).returns("one" => "two") + @entry.stubs(:vals).with(:parent).returns(%w{parent}) + + @parent.stubs(:to_hash).returns("three" => "four") + @parent.stubs(:vals).with(:parent).returns([@name]) + proc { @searcher.find("mynode") }.should raise_error(ArgumentError) + end end end end diff --git a/spec/unit/node/catalog.rb b/spec/unit/node/catalog.rb index 604dabbb6..360dd87f2 100755 --- a/spec/unit/node/catalog.rb +++ b/spec/unit/node/catalog.rb @@ -304,6 +304,8 @@ describe Puppet::Node::Catalog, " when converting to a RAL catalog" do resource = stub 'resource', :name => "changer2", :title => "changer2", :ref => "Test[changer2]", :catalog= => nil, :remove => nil + #changer is going to get duplicated as part of a fix for aliases 1094 + changer.expects(:dup).returns(changer) changer.expects(:to_type).returns(resource) newconfig = nil diff --git a/spec/unit/parser/resource.rb b/spec/unit/parser/resource.rb index 9ce7b391b..1948a3c07 100755 --- a/spec/unit/parser/resource.rb +++ b/spec/unit/parser/resource.rb @@ -14,6 +14,36 @@ describe Puppet::Parser::Resource do @scope = @compiler.topscope end + def mkresource(args = {}) + args[:source] ||= "source" + args[:scope] ||= stub('scope', :source => mock('source')) + + {:type => "resource", :title => "testing", :source => "source", :scope => "scope"}.each do |param, value| + args[param] ||= value + end + + params = args[:params] || {:one => "yay", :three => "rah"} + if args[:params] == :none + args.delete(:params) + else + args[:params] = paramify(args[:source], params) + end + + Puppet::Parser::Resource.new(args) + end + + def param(name, value, source) + Puppet::Parser::Resource::Param.new(:name => name, :value => value, :source => source) + end + + def paramify(source, hash) + hash.collect do |name, value| + Puppet::Parser::Resource::Param.new( + :name => name, :value => value, :source => source + ) + end + end + it "should be isomorphic if it is builtin and models an isomorphic type" do Puppet::Type.type(:file).expects(:isomorphic?).returns(true) @resource = Puppet::Parser::Resource.new(:type => "file", :title => "whatever", :scope => @scope, :source => @source).isomorphic?.should be_true @@ -29,6 +59,30 @@ describe Puppet::Parser::Resource do @resource = Puppet::Parser::Resource.new(:type => "whatever", :title => "whatever", :scope => @scope, :source => @source).isomorphic?.should be_true end + it "should have a array-indexing method for retrieving parameter values" do + @resource = mkresource + @resource[:one].should == "yay" + end + + describe "when initializing" do + before do + @arguments = {:type => "resource", :title => "testing", :scope => stub('scope', :source => mock('source'))} + end + + [:type, :title, :scope].each do |name| + it "should fail unless #{name.to_s} is specified" do + try = @arguments.dup + try.delete(name) + lambda { Puppet::Parser::Resource.new(try) }.should raise_error(ArgumentError) + end + end + + it "should set the reference correctly" do + res = Puppet::Parser::Resource.new(@arguments) + res.ref.should == "Resource[testing]" + end + end + describe "when evaluating" do before do @type = Puppet::Parser::Resource @@ -60,11 +114,10 @@ describe Puppet::Parser::Resource do describe "when finishing" do before do - @definition = @parser.newdefine "mydefine" @class = @parser.newclass "myclass" @nodedef = @parser.newnode("mynode")[0] - @resource = Puppet::Parser::Resource.new(:type => "mydefine", :title => "whatever", :scope => @scope, :source => @source) + @resource = Puppet::Parser::Resource.new(:type => "file", :title => "whatever", :scope => @scope, :source => @source) end it "should do nothing if it has already been finished" do @@ -73,6 +126,32 @@ describe Puppet::Parser::Resource do @resource.finish end + it "should add all defaults available from the scope" do + @resource.scope.expects(:lookupdefaults).with(@resource.type).returns(:owner => param(:owner, "default", @resource.source)) + @resource.finish + + @resource[:owner].should == "default" + end + + it "should not replace existing parameters with defaults" do + @resource.set_parameter :owner, "oldvalue" + @resource.scope.expects(:lookupdefaults).with(@resource.type).returns(:owner => :replaced) + @resource.finish + + @resource[:owner].should == "oldvalue" + end + + it "should add a copy of each default, rather than the actual default parameter instance" do + newparam = param(:owner, "default", @resource.source) + other = newparam.dup + other.value = "other" + newparam.expects(:dup).returns(other) + @resource.scope.expects(:lookupdefaults).with(@resource.type).returns(:owner => newparam) + @resource.finish + + @resource[:owner].should == "other" + end + it "should copy metaparams from its scope" do @scope.setvar("noop", "true") @@ -82,7 +161,7 @@ describe Puppet::Parser::Resource do end it "should not copy metaparams that it already has" do - @resource.class.publicize_methods(:set_parameter) { @resource.set_parameter("noop", "false") } + @resource.set_parameter("noop", "false") @scope.setvar("noop", "true") @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @@ -91,7 +170,7 @@ describe Puppet::Parser::Resource do end it "should stack relationship metaparams from its container if it already has them" do - @resource.class.publicize_methods(:set_parameter) { @resource.set_parameter("require", "resource") } + @resource.set_parameter("require", "resource") @scope.setvar("require", "container") @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @@ -100,7 +179,7 @@ describe Puppet::Parser::Resource do end it "should flatten the array resulting from stacking relationship metaparams" do - @resource.class.publicize_methods(:set_parameter) { @resource.set_parameter("require", ["resource1", "resource2"]) } + @resource.set_parameter("require", ["resource1", "resource2"]) @scope.setvar("require", %w{container1 container2}) @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @@ -167,4 +246,76 @@ describe Puppet::Parser::Resource do lambda { @resource.tag("good_tag") }.should_not raise_error(Puppet::ParseError) end end + + describe "when merging overrides" do + before do + @source = "source1" + @resource = mkresource :source => @source + @override = mkresource :source => @source + end + + it "should fail when the override was not created by a parent class" do + @override.source = "source2" + @override.source.expects(:child_of?).with("source1").returns(false) + assert_raise(Puppet::ParseError, "Allowed unrelated resources to override") do + @resource.merge(@override) + end + end + + it "should succeed when the override was created in the current scope" do + @resource.source = "source3" + @override.source = @resource.source + @override.source.expects(:child_of?).with("source3").never + params = {:a => :b, :c => :d} + @override.expects(:params).returns(params) + @resource.expects(:override_parameter).with(:b) + @resource.expects(:override_parameter).with(:d) + @resource.merge(@override) + end + + it "should succeed when a parent class created the override" do + @resource.source = "source3" + @override.source = "source4" + @override.source.expects(:child_of?).with("source3").returns(true) + params = {:a => :b, :c => :d} + @override.expects(:params).returns(params) + @resource.expects(:override_parameter).with(:b) + @resource.expects(:override_parameter).with(:d) + @resource.merge(@override) + end + + it "should add new parameters when the parameter is not set" do + @source.stubs(:child_of?).returns true + @override.set_parameter(:testing, "value") + @resource.merge(@override) + + @resource[:testing].should == "value" + end + + it "should replace existing parameter values" do + @source.stubs(:child_of?).returns true + @resource.set_parameter(:testing, "old") + @override.set_parameter(:testing, "value") + + @resource.merge(@override) + + @resource[:testing].should == "value" + end + + it "should add values to the parameter when the override was created with the '+>' syntax" do + @source.stubs(:child_of?).returns true + param = Puppet::Parser::Resource::Param.new(:name => :testing, :value => "testing", :source => @resource.source) + param.add = true + + @override.set_parameter(param) + + @resource.set_parameter(:testing, "other") + + @resource.merge(@override) + + @resource[:testing].should == %w{other testing} + end + + + end end diff --git a/test/language/resource.rb b/test/language/resource.rb index 608e7c995..b3eaf0390 100755 --- a/test/language/resource.rb +++ b/test/language/resource.rb @@ -23,95 +23,6 @@ class TestResource < PuppetTest::TestCase mocha_verify end - def test_initialize - args = {:type => "resource", :title => "testing", - :scope => mkscope} - # Check our arg requirements - args.each do |name, value| - try = args.dup - try.delete(name) - assert_raise(ArgumentError, "Did not fail when %s was missing" % name) do - Parser::Resource.new(try) - end - end - - res = nil - assert_nothing_raised do - res = Parser::Resource.new(args) - end - - ref = res.instance_variable_get("@ref") - assert_equal("Resource", ref.type, "did not set resource type") - assert_equal("testing", ref.title, "did not set resource title") - end - - def test_merge - res = mkresource - other = mkresource - - # First try the case where the resource is not allowed to override - res.source = "source1" - other.source = "source2" - other.source.expects(:child_of?).with("source1").returns(false) - assert_raise(Puppet::ParseError, "Allowed unrelated resources to override") do - res.merge(other) - end - - # Next try it when the sources are equal. - res.source = "source3" - other.source = res.source - other.source.expects(:child_of?).with("source3").never - params = {:a => :b, :c => :d} - other.expects(:params).returns(params) - res.expects(:override_parameter).with(:b) - res.expects(:override_parameter).with(:d) - res.merge(other) - - # And then parentage is involved - other = mkresource - res.source = "source3" - other.source = "source4" - other.source.expects(:child_of?).with("source3").returns(true) - params = {:a => :b, :c => :d} - other.expects(:params).returns(params) - res.expects(:override_parameter).with(:b) - res.expects(:override_parameter).with(:d) - res.merge(other) - end - - # the [] method - def test_array_accessors - res = mkresource - params = res.instance_variable_get("@params") - assert_nil(res[:missing], "Found a missing parameter somehow") - params[:something] = stub(:value => "yay") - assert_equal("yay", res[:something], "Did not correctly call value on the parameter") - - res.expects(:title).returns(:mytitle) - assert_equal(:mytitle, res[:title], "Did not call title when asked for it as a param") - end - - # Make sure any defaults stored in the scope get added to our resource. - def test_add_defaults - res = mkresource - params = res.instance_variable_get("@params") - params[:a] = :b - res.scope.expects(:lookupdefaults).with(res.type).returns(:a => :replaced, :c => :d) - res.expects(:debug) - - res.send(:add_defaults) - assert_equal(:d, params[:c], "Did not set default") - assert_equal(:b, params[:a], "Replaced parameter with default") - end - - def test_finish - res = mkresource - res.expects(:add_defaults) - res.expects(:add_metaparams) - res.expects(:validate) - res.finish - end - # Make sure we paramcheck our params def test_validate res = mkresource @@ -123,43 +34,6 @@ class TestResource < PuppetTest::TestCase res.send(:validate) end - def test_override_parameter - res = mkresource - params = res.instance_variable_get("@params") - - # There are three cases, with the second having two options: - - # No existing parameter. - param = stub(:name => "myparam") - res.send(:override_parameter, param) - assert_equal(param, params["myparam"], "Override was not added to param list") - - # An existing parameter that we can override. - source = stub(:child_of? => true) - # Start out without addition - params["param2"] = stub(:source => :whatever) - param = stub(:name => "param2", :source => source, :add => false) - res.send(:override_parameter, param) - assert_equal(param, params["param2"], "Override was not added to param list") - - # Try with addition. - params["param2"] = stub(:value => :a, :source => :whatever) - param = stub(:name => "param2", :source => source, :add => true, :value => :b) - param.expects(:value=).with([:a, :b]) - res.send(:override_parameter, param) - assert_equal(param, params["param2"], "Override was not added to param list") - - # And finally, make sure we throw an exception when the sources aren't related - source = stub(:child_of? => false) - params["param2"] = stub(:source => :whatever, :file => :f, :line => :l) - old = params["param2"] - param = stub(:name => "param2", :source => source, :file => :f, :line => :l) - assert_raise(Puppet::ParseError, "Did not fail when params conflicted") do - res.send(:override_parameter, param) - end - assert_equal(old, params["param2"], "Param was replaced irrespective of conflict") - end - def test_set_parameter res = mkresource params = res.instance_variable_get("@params") @@ -420,37 +294,4 @@ class TestResource < PuppetTest::TestCase assert(newres.exported?, "Exported defined resource generated non-exported resources") assert(newres.virtual?, "Exported defined resource generated non-virtual resources") end - - # Make sure tags behave appropriately. - def test_tags - scope_resource = stub 'scope_resource', :tags => %w{srone srtwo} - scope = stub 'scope', :resource => scope_resource - resource = Puppet::Parser::Resource.new(:type => "file", :title => "yay", :scope => scope, :source => mock('source')) - - # Make sure we get the type and title - %w{yay file}.each do |tag| - assert(resource.tags.include?(tag), "Did not tag resource with %s" % tag) - end - - # make sure we can only set legal tags - ["an invalid tag", "-anotherinvalid", "bad*tag"].each do |tag| - assert_raise(Puppet::ParseError, "Tag #{tag} was considered valid") do - resource.tag tag - end - end - - # make sure good tags make it through. - tags = %w{good-tag yaytag GoodTag another_tag a ab A} - tags.each do |tag| - assert_nothing_raised("Tag #{tag} was considered invalid") do - resource.tag tag - end - end - - # make sure we get each of them. - ptags = resource.tags - tags.each do |tag| - assert(ptags.include?(tag.downcase), "missing #{tag}") - end - end end |