diff options
46 files changed, 415 insertions, 168 deletions
@@ -1,5 +1,23 @@ The environment is now available as a variable in the manifests. + Fixed #1043 -- autoloading now searches the plugins directory + in each module, in addition to the lib directory. The 'lib' + directory is also deprecated, but supported for now to give + people a chance to convert. + + Fixed #1003 -- Applying DavidS's patch to fix searching for + tags in sql. + + Fixed #992 -- Puppet is now compatible with gems 1.0.1. + + Fixed #968 again, this time with tests -- parseonly works, + including not compiling the configurations, and also storeconfigs + is no longer required during parse-testing. + + Fixed #1021 -- the problem was that my method of determining + the in-degree sometimes resulted in a lower number than the + number of in-edges. + Fixed #997 -- virtual defined types are no longer evaluated. NOTE: This introduces a behaviour change, in that you previously could realize a resource within a virtual defined resource, and now diff --git a/bin/puppet b/bin/puppet index f5d230a7a..952ffcbf8 100755 --- a/bin/puppet +++ b/bin/puppet @@ -171,6 +171,16 @@ else Puppet[:manifest] = ARGV.shift end +if Puppet[:parseonly] + begin + Puppet::Parser::Interpreter.new.parser(Puppet[:environment]) + rescue => detail + Puppet.err detail + exit 1 + end + exit 0 +end + # Collect our facts. facts = Puppet::Node::Facts.find("me") facts.name = facts.values["hostname"] @@ -198,8 +208,6 @@ begin # Compile our catalog catalog = Puppet::Node::Catalog.find(node) - exit(0) if Puppet[:parseonly] - # Translate it to a RAL catalog catalog = catalog.to_ral diff --git a/bin/puppetdoc b/bin/puppetdoc index be86cc618..82e4c076b 100755 --- a/bin/puppetdoc +++ b/bin/puppetdoc @@ -128,11 +128,19 @@ else else with_contents = true end + exit_code = 0 options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name| - section = Puppet::Util::Reference.reference(name) - - # Add the per-section text, but with no ToC - text += section.send(options[:format], with_contents) + raise "Could not find reference %s" % name unless section = Puppet::Util::Reference.reference(name) + + begin + # Add the per-section text, but with no ToC + text += section.send(options[:format], with_contents) + rescue => detail + puts detail.backtrace + $stderr.puts "Could not generate reference %s: %s" % [name, detail] + exit_code = 1 + next + end end unless with_contents # We've only got one reference @@ -147,6 +155,8 @@ else else puts text end + + exit exit_code end diff --git a/bin/puppetmasterd b/bin/puppetmasterd index bae11c831..a00186b68 100755 --- a/bin/puppetmasterd +++ b/bin/puppetmasterd @@ -87,7 +87,6 @@ options = [ [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ], [ "--logdest", "-l", GetoptLong::REQUIRED_ARGUMENT ], - [ "--noca", GetoptLong::NO_ARGUMENT ], [ "--nobucket", GetoptLong::NO_ARGUMENT ], [ "--noreports", GetoptLong::NO_ARGUMENT ], [ "--nonodes", GetoptLong::NO_ARGUMENT ], diff --git a/bin/puppetrun b/bin/puppetrun index fe981dadf..c92b59fc6 100755 --- a/bin/puppetrun +++ b/bin/puppetrun @@ -274,7 +274,7 @@ else end # Now parse the config -config = File.join(Puppet[:confdir], "puppetmasterd.conf") +config = File.join(Puppet[:confdir], "puppet.conf") Puppet.parse_config(config) if File.exists? config diff --git a/conf/freebsd/puppetd b/conf/freebsd/puppetd index bf718a027..4a5ae59ca 100644 --- a/conf/freebsd/puppetd +++ b/conf/freebsd/puppetd @@ -18,7 +18,7 @@ pidfile="/var/run/$name.pid" # read configuration and set defaults load_rc_config "$name" : ${puppetd_enable="NO"} -: ${puppetd_config="/usr/local/etc/puppetd.conf"} +: ${puppetd_config="/usr/local/etc/puppet.conf"} : ${puppetd_flags=""} command_args="--config $puppetd_config $puppetd_flags" diff --git a/conf/freebsd/puppetmasterd b/conf/freebsd/puppetmasterd index 6f217dc8c..d41e0031b 100644 --- a/conf/freebsd/puppetmasterd +++ b/conf/freebsd/puppetmasterd @@ -18,7 +18,7 @@ pidfile="/var/run/$name.pid" # read configuration and set defaults load_rc_config "$name" : ${puppetmasterd_enable="NO"} -: ${puppetmasterd_config="/usr/local/etc/puppetmasterd.conf"} +: ${puppetmasterd_config="/usr/local/etc/puppet.conf"} : ${puppetmasterd_flags=""} command_args="--config $puppetmasterd_config $puppetmasterd_flags" diff --git a/conf/solaris/smf/puppetd.xml b/conf/solaris/smf/puppetd.xml index e2a1d89e9..ad1b45231 100644 --- a/conf/solaris/smf/puppetd.xml +++ b/conf/solaris/smf/puppetd.xml @@ -18,7 +18,7 @@ grouping='require_all' restart_on='none' type='path'> - <service_fmri value='file:///etc/puppet/puppetd.conf'/> + <service_fmri value='file:///etc/puppet/puppet.conf'/> </dependency> <dependency name='loopback' diff --git a/conf/solaris/smf/puppetmasterd.xml b/conf/solaris/smf/puppetmasterd.xml index e89e832fc..17c52916f 100644 --- a/conf/solaris/smf/puppetmasterd.xml +++ b/conf/solaris/smf/puppetmasterd.xml @@ -18,7 +18,7 @@ grouping='require_all' restart_on='none' type='path'> - <service_fmri value='file:///etc/puppet/puppetmasterd.conf'/> + <service_fmri value='file:///etc/puppet/puppet.conf'/> </dependency> <dependency name='loopback' diff --git a/conf/suse/puppet.spec b/conf/suse/puppet.spec index 6d4e9f538..f1fa0ba2d 100644 --- a/conf/suse/puppet.spec +++ b/conf/suse/puppet.spec @@ -5,7 +5,7 @@ Summary: A network tool for managing many disparate systems Name: puppet -Version: 0.18.4 +Version: 0.24.1 Release: 3%{?dist} License: GPL Group: System Environment/Base @@ -15,11 +15,11 @@ Source: http://reductivelabs.com/downloads/puppet/%{name}-%{version}.tgz Patch0: puppet.suse.patch Patch1: puppet.service.patch -Requires: ruby >= 1.8.1 -Requires: facter >= 1.1.4 +Requires: ruby >= 1.8.6 +Requires: facter >= 1.3.7 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildArchitectures: noarch -BuildRequires: ruby >= 1.8.1 +BuildRequires: ruby >= 1.8.6 %description Puppet lets you centrally manage every important aspect of your system using a @@ -67,9 +67,7 @@ find %{buildroot}%{ruby_sitelibdir} -type f -perm +ugo+x -print0 | xargs -0 -r % %{__install} -Dp -m0644 %{confdir}/server.sysconfig %{buildroot}%{_sysconfdir}/sysconfig/puppetmaster %{__install} -Dp -m0755 %{suseconfdir}/server.init %{buildroot}%{_initrddir}/puppetmaster %{__install} -Dp -m0644 %{confdir}/fileserver.conf %{buildroot}%{_sysconfdir}/puppet/fileserver.conf -%{__install} -Dp -m0644 %{confdir}/puppetd.conf %{buildroot}%{_sysconfdir}/puppet/puppetd.conf -%{__ln_s} puppetd.conf %{buildroot}%{_sysconfdir}/puppet/puppetmasterd.conf -%{__ln_s} puppetd.conf %{buildroot}%{_sysconfdir}/puppet/puppetca.conf +%{__install} -Dp -m0644 %{confdir}/puppet.conf %{buildroot}%{_sysconfdir}/puppet/puppet.conf %{__install} -Dp -m0644 %{confdir}/logrotate %{buildroot}%{_sysconfdir}/logrotate.d/puppet %files @@ -79,7 +77,7 @@ find %{buildroot}%{ruby_sitelibdir} -type f -perm +ugo+x -print0 | xargs -0 -r % %{ruby_sitelibdir}/* %{_initrddir}/puppet %config(noreplace) %{_sysconfdir}/sysconfig/puppet -%config(noreplace) %{_sysconfdir}/puppet/puppetd.conf +%config(noreplace) %{_sysconfdir}/puppet/puppet.conf %doc CHANGELOG COPYING LICENSE README TODO examples %exclude %{_sbindir}/puppetdoc %config(noreplace) %{_sysconfdir}/logrotate.d/puppet @@ -131,6 +129,10 @@ fi %{__rm} -rf %{buildroot} %changelog +* Sat Feb 16 2008 James Turnbull <james@lovedthanlost.net> - 0.24.1-1 +- Fixed puppet configuation file references to match single puppet.conf file +- Update versions for 0.24.1 release + * Tue Aug 3 2006 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.18.4-3 - Replaced puppet-bin.patch with %build section from David's spec diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index e0c37cd35..2699dc6e1 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -51,7 +51,7 @@ class Puppet::Parser::Collector search = "(exported=? AND restype=?)" values = [true, @type] - search += " AND (?)" and values << @equery if @equery + search += " AND (%s)" % @equery if @equery # We're going to collect objects from rails, but we don't want any # objects from this host. diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra index 0fd644b3a..484efe83c 100644 --- a/lib/puppet/parser/grammar.ra +++ b/lib/puppet/parser/grammar.ra @@ -151,7 +151,7 @@ resourceoverride: resourceref LBRACE anyparams endcomma RBRACE { virtualresource: at resource { type = val[0] - if type == :exported and ! Puppet[:storeconfigs] + if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] error "You cannot collect without storeconfigs being set" end @@ -192,7 +192,7 @@ collection: classref collectrhand { else args[:form] = val[1] end - if args[:form] == :exported and ! Puppet[:storeconfigs] + if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] error "You cannot collect exported resources without storeconfigs being set" end result = ast AST::Collection, args diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb index 1d93193dd..d4b7449fb 100644 --- a/lib/puppet/parser/interpreter.rb +++ b/lib/puppet/parser/interpreter.rb @@ -42,6 +42,26 @@ class Puppet::Parser::Interpreter @parsers = {} end + # Return the parser for a specific environment. + def parser(environment) + if ! @parsers[environment] or @parsers[environment].reparse? + # This will throw an exception if it does not succeed. We only + # want to get rid of the old parser if we successfully create a new + # one. + begin + tmp = create_parser(environment) + @parsers[environment].clear if @parsers[environment] + @parsers[environment] = tmp + rescue => detail + # If a parser already exists, than assume that we logged the + # exception elsewhere and reuse the parser. If one doesn't + # exist, then reraise. + raise detail unless @parsers[environment] + end + end + @parsers[environment] + end + private # Create a new parser object and pre-parse the configuration. @@ -67,24 +87,4 @@ class Puppet::Parser::Interpreter raise error end end - - # Return the parser for a specific environment. - def parser(environment) - if ! @parsers[environment] or @parsers[environment].reparse? - # This will throw an exception if it does not succeed. We only - # want to get rid of the old parser if we successfully create a new - # one. - begin - tmp = create_parser(environment) - @parsers[environment].clear if @parsers[environment] - @parsers[environment] = tmp - rescue => detail - # If a parser already exists, than assume that we logged the - # exception elsewhere and reuse the parser. If one doesn't - # exist, then reraise. - raise detail unless @parsers[environment] - end - end - @parsers[environment] - end end diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb index 6661650ba..51026ea1b 100644 --- a/lib/puppet/parser/lexer.rb +++ b/lib/puppet/parser/lexer.rb @@ -33,7 +33,11 @@ class Puppet::Parser::Lexer end def to_s - "Lexer token %s" % @name.to_s + if self.string + @string + else + @name.to_s + end end end diff --git a/lib/puppet/parser/parser.rb b/lib/puppet/parser/parser.rb index c3279d4e7..e27a209fc 100644 --- a/lib/puppet/parser/parser.rb +++ b/lib/puppet/parser/parser.rb @@ -29,7 +29,7 @@ module Puppet class Parser < Racc::Parser -module_eval <<'..end grammar.ra modeval..id9134b179f4', 'grammar.ra', 638 +module_eval <<'..end grammar.ra modeval..idfef5d70c9f', 'grammar.ra', 638 # It got too annoying having code in a file that needs to be compiled. require 'puppet/parser/parser_support' @@ -39,8 +39,9 @@ require 'puppet/parser/parser_support' # mode: ruby # End: +# $Id$ -..end grammar.ra modeval..id9134b179f4 +..end grammar.ra modeval..idfef5d70c9f ##### racc 1.4.5 generates ### @@ -956,7 +957,7 @@ module_eval <<'.,.,', 'grammar.ra', 174 def _reduce_38( val, _values, result ) type = val[0] - if type == :exported and ! Puppet[:storeconfigs] + if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] error "You cannot collect without storeconfigs being set" end @@ -1009,7 +1010,7 @@ module_eval <<'.,.,', 'grammar.ra', 199 else args[:form] = val[1] end - if args[:form] == :exported and ! Puppet[:storeconfigs] + if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] error "You cannot collect exported resources without storeconfigs being set" end result = ast AST::Collection, args diff --git a/lib/puppet/pgraph.rb b/lib/puppet/pgraph.rb index 71547802e..3bcc2ced0 100644 --- a/lib/puppet/pgraph.rb +++ b/lib/puppet/pgraph.rb @@ -19,23 +19,6 @@ class Puppet::PGraph < Puppet::SimpleGraph super end - # Make sure whichever edge has a label keeps the label - def copy_label(source, target, label) - # 'require' relationships will not have a label, - # and all 'subscribe' relationships have the same - # label, at least for now. - - # Labels default to {}, so we can't just test for nil. - newlabel = label || {} - oldlabel = edge_label(source, target) || {} - if ! newlabel.empty? and oldlabel.empty? - edge_label_set(source, target, label) - # We should probably check to see if the labels both exist - # and don't match, but we'd just throw an error which the user - # couldn't do anyting about. - end - end - # Which resources a given resource depends upon. def dependents(resource) tree_from_vertex(resource).keys @@ -115,23 +98,11 @@ class Puppet::PGraph < Puppet::SimpleGraph t = edge.target end - # We don't want to add multiple copies of the - # same edge, but we *do* want to make sure we - # keep labels around. - # XXX This will *not* work when we support multiple - # types of labels, and only works now because - # you can only do simple subscriptions. - if edge?(s, t) - copy_label(s, t, edge.label) - next - end add_edge(s, t, edge.label) end # Now get rid of the edge, so remove_vertex! works correctly. remove_edge!(edge) - Puppet.debug "%s: %s => %s: %s" % [container, - edge.source, edge.target, edge?(edge.source, edge.target)] end end remove_vertex!(container) diff --git a/lib/puppet/provider/nameservice/directoryservice.rb b/lib/puppet/provider/nameservice/directoryservice.rb index b2ccfbd4e..e2e68b2ca 100644 --- a/lib/puppet/provider/nameservice/directoryservice.rb +++ b/lib/puppet/provider/nameservice/directoryservice.rb @@ -139,10 +139,12 @@ class DirectoryService < Puppet::Provider::NameService dscl_output.split("\n").each do |line| # JJM: Split the attribute name and the list of values. ds_attribute, ds_values_string = line.split(':') + + # Split sets the values to nil if there's nothing after the : + ds_values_string ||= "" # JJM: skip this attribute line if the Puppet::Type doesn't care about it. - next unless (@@ds_to_ns_attribute_map.keys.include?(ds_attribute) \ - and type_properties.include? @@ds_to_ns_attribute_map[ds_attribute]) + next unless (@@ds_to_ns_attribute_map.keys.include?(ds_attribute) and type_properties.include? @@ds_to_ns_attribute_map[ds_attribute]) # JJM: We asked dscl to output url encoded values so we're able # to machine parse on whitespace. We need to urldecode: @@ -178,11 +180,8 @@ class DirectoryService < Puppet::Provider::NameService # This method spits out proper DSCL commands for us. # We EXPECT name to be @resource[:name] when called from an instance object. - # JJM: With dscl, the domain "/" is always the default local domain. - # The domain /Search will search all domains, and you may - # get at specific domains with /LDAPv3/server1.foobar.com, - # /LDAPv3/server2.foobar.com, etc... - command_vector = [ command(:dscl), "-url", "/" ] + # There are two ways to specify paths in 10.5. See man dscl. + command_vector = [ command(:dscl), "-url", "." ] # JJM: The actual action to perform. See "man dscl" # Common actiosn: -create, -delete, -merge, -append, -passwd command_vector << ds_action diff --git a/lib/puppet/provider/package/gem.rb b/lib/puppet/provider/package/gem.rb index 6e777a735..f73694779 100755 --- a/lib/puppet/provider/package/gem.rb +++ b/lib/puppet/provider/package/gem.rb @@ -23,14 +23,14 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d end begin - list = execute(command).split("\n\n").collect do |set| + list = execute(command).split("\n").collect do |set| if gemhash = gemsplit(set) gemhash[:provider] = :gem gemhash else nil end - end.reject { |p| p.nil? } + end.compact rescue Puppet::ExecutionFailure => detail raise Puppet::Error, "Could not list gems: %s" % detail end @@ -44,8 +44,8 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d def self.gemsplit(desc) case desc - when /^\*\*\*/: return nil - when /^(\S+)\s+\((.+)\)\n/ + when /^\*\*\*/, /^\s*$/, /^\s+/; return nil + when /^(\S+)\s+\((.+)\)/ name = $1 version = $2.split(/,\s*/)[0] return { diff --git a/lib/puppet/provider/package/portage.rb b/lib/puppet/provider/package/portage.rb index 03274a78d..dccfeaf56 100644 --- a/lib/puppet/provider/package/portage.rb +++ b/lib/puppet/provider/package/portage.rb @@ -39,7 +39,7 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa return packages rescue Puppet::ExecutionFailure => detail - raise Puppet::PackageError.new(detail) + raise Puppet::Error.new(detail) end end @@ -99,14 +99,14 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa case packages.size when 0 not_found_value = "%s/%s" % [@resource[:category] ? @resource[:category] : "<unspecified category>", @resource[:name]] - raise Puppet::PackageError.new("No package found with the specified name [#{not_found_value}]") + raise Puppet::Error.new("No package found with the specified name [#{not_found_value}]") when 1 return packages[0] else - raise Puppet::PackageError.new("More than one package with the specified name [#{search_value}], please use the category parameter to disambiguate") + raise Puppet::Error.new("More than one package with the specified name [#{search_value}], please use the category parameter to disambiguate") end rescue Puppet::ExecutionFailure => detail - raise Puppet::PackageError.new(detail) + raise Puppet::Error.new(detail) end end diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb index 233242a1c..e54fb13df 100755 --- a/lib/puppet/provider/service/debian.rb +++ b/lib/puppet/provider/service/debian.rb @@ -14,6 +14,7 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do # Remove the symlinks def disable update "-f", @resource[:name], "remove" + update @resource[:name], "stop 1 2 3 4 5 6 ." end def enabled? @@ -29,6 +30,7 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do end def enable + update "-f", @resource[:name], "remove" update @resource[:name], "defaults" end end diff --git a/lib/puppet/provider/service/gentoo.rb b/lib/puppet/provider/service/gentoo.rb index 2dcc3e9c1..adbee6970 100644 --- a/lib/puppet/provider/service/gentoo.rb +++ b/lib/puppet/provider/service/gentoo.rb @@ -8,6 +8,10 @@ Puppet::Type.type(:service).provide :gentoo, :parent => :init do defaultfor :operatingsystem => :gentoo + def self.defpath + superclass.defpath + end + def disable begin output = update :del, @resource[:name], :default diff --git a/lib/puppet/reference/node_source.rb b/lib/puppet/reference/node_source.rb deleted file mode 100644 index 29a01f850..000000000 --- a/lib/puppet/reference/node_source.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'puppet/node' - -noderef = Puppet::Util::Reference.newreference :node_source, :doc => "Sources of node configuration information" do - Puppet::Network::Handler.node.docs -end - -noderef.header = " -Nodes can be searched for in different locations. This document describes those different locations. -" diff --git a/lib/puppet/reference/report.rb b/lib/puppet/reference/report.rb deleted file mode 100644 index a8086f8bc..000000000 --- a/lib/puppet/reference/report.rb +++ /dev/null @@ -1,21 +0,0 @@ -report = Puppet::Util::Reference.newreference :report, :doc => "All available transaction reports" do - Puppet::Network::Handler.report.reportdocs -end - -report.header = " -Puppet clients can report back to the server after each transaction. This -transaction report is sent as a YAML dump of the -``Puppet::Transaction::Report`` class and includes every log message that was -generated during the transaction along with as many metrics as Puppet knows how -to collect. See `ReportsAndReporting Reports and Reporting`:trac: -for more information on how to use reports. - -Currently, clients default to not sending in reports; you can enable reporting -by setting the ``report`` parameter to true. - -To use a report, set the ``reports`` parameter on the server; multiple -reports must be comma-separated. You can also specify ``none`` to disable -reports entirely. - -Puppet provides multiple report handlers that will process client reports: -" diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb index 503e4814c..48f393f77 100644 --- a/lib/puppet/simple_graph.rb +++ b/lib/puppet/simple_graph.rb @@ -51,10 +51,12 @@ class Puppet::SimpleGraph # Create methods for returning the degree and edges. [:in, :out].each do |direction| - define_method("%s_degree" % direction) do - @adjacencies[direction].length - end - + # LAK:NOTE If you decide to create methods for directly + # testing the degree, you'll have to get the values and flatten + # the results -- you might have duplicate edges, which can give + # a false impression of what the degree is. That's just + # as expensive as just getting the edge list, so I've decided + # to only add this method. define_method("%s_edges" % direction) do @adjacencies[direction].values.flatten end @@ -126,8 +128,9 @@ class Puppet::SimpleGraph # Collect each of our vertices, with the number of in-edges each has. @vertices.each do |name, wrapper| - zeros << wrapper if wrapper.in_degree == 0 - degree[wrapper.vertex] = wrapper.in_edges + edges = wrapper.in_edges + zeros << wrapper if edges.length == 0 + degree[wrapper.vertex] = edges end # Iterate over each 0-degree vertex, decrementing the degree of diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index def9e44e4..c4e154d47 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -423,8 +423,8 @@ end require 'puppet/propertychange' require 'puppet/provider' require 'puppet/type/component' -require 'puppet/type/pfile' -require 'puppet/type/pfilebucket' +require 'puppet/type/file' +require 'puppet/type/filebucket' require 'puppet/type/tidy' diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb index 7d3b1abe1..f8049236f 100755 --- a/lib/puppet/type/exec.rb +++ b/lib/puppet/type/exec.rb @@ -288,7 +288,7 @@ module Puppet # Rebuild the database, but only when the file changes exec { newaliases: path => [\"/usr/bin\", \"/usr/sbin\"], - subscribe => file[\"/etc/aliases\"], + subscribe => File[\"/etc/aliases\"], refreshonly => true } diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/file.rb index c32a4d474..65ee7e72e 100644 --- a/lib/puppet/type/pfile.rb +++ b/lib/puppet/type/file.rb @@ -1159,13 +1159,13 @@ module Puppet # We put all of the properties in separate files, because there are so many # of them. The order these are loaded is important, because it determines # the order they are in the property lit. - require 'puppet/type/pfile/checksum' - require 'puppet/type/pfile/content' # can create the file - require 'puppet/type/pfile/source' # can create the file - require 'puppet/type/pfile/target' # creates a different type of file - require 'puppet/type/pfile/ensure' # can create the file - require 'puppet/type/pfile/owner' - require 'puppet/type/pfile/group' - require 'puppet/type/pfile/mode' - require 'puppet/type/pfile/type' + require 'puppet/type/file/checksum' + require 'puppet/type/file/content' # can create the file + require 'puppet/type/file/source' # can create the file + require 'puppet/type/file/target' # creates a different type of file + require 'puppet/type/file/ensure' # can create the file + require 'puppet/type/file/owner' + require 'puppet/type/file/group' + require 'puppet/type/file/mode' + require 'puppet/type/file/type' end diff --git a/lib/puppet/type/pfile/checksum.rb b/lib/puppet/type/file/checksum.rb index 08f48ea21..08f48ea21 100755 --- a/lib/puppet/type/pfile/checksum.rb +++ b/lib/puppet/type/file/checksum.rb diff --git a/lib/puppet/type/pfile/content.rb b/lib/puppet/type/file/content.rb index 6dcda0aa6..6dcda0aa6 100755 --- a/lib/puppet/type/pfile/content.rb +++ b/lib/puppet/type/file/content.rb diff --git a/lib/puppet/type/pfile/ensure.rb b/lib/puppet/type/file/ensure.rb index 3aa918f65..3aa918f65 100755 --- a/lib/puppet/type/pfile/ensure.rb +++ b/lib/puppet/type/file/ensure.rb diff --git a/lib/puppet/type/pfile/group.rb b/lib/puppet/type/file/group.rb index 5f7caf342..5f7caf342 100755 --- a/lib/puppet/type/pfile/group.rb +++ b/lib/puppet/type/file/group.rb diff --git a/lib/puppet/type/pfile/mode.rb b/lib/puppet/type/file/mode.rb index 8674e0a88..8674e0a88 100755 --- a/lib/puppet/type/pfile/mode.rb +++ b/lib/puppet/type/file/mode.rb diff --git a/lib/puppet/type/pfile/owner.rb b/lib/puppet/type/file/owner.rb index 6f9bbd6a2..6f9bbd6a2 100755 --- a/lib/puppet/type/pfile/owner.rb +++ b/lib/puppet/type/file/owner.rb diff --git a/lib/puppet/type/pfile/source.rb b/lib/puppet/type/file/source.rb index 3dfb5cccd..3dfb5cccd 100755 --- a/lib/puppet/type/pfile/source.rb +++ b/lib/puppet/type/file/source.rb diff --git a/lib/puppet/type/pfile/target.rb b/lib/puppet/type/file/target.rb index a0e5dc401..a0e5dc401 100644 --- a/lib/puppet/type/pfile/target.rb +++ b/lib/puppet/type/file/target.rb diff --git a/lib/puppet/type/pfile/type.rb b/lib/puppet/type/file/type.rb index 65539795b..65539795b 100755 --- a/lib/puppet/type/pfile/type.rb +++ b/lib/puppet/type/file/type.rb diff --git a/lib/puppet/type/pfilebucket.rb b/lib/puppet/type/filebucket.rb index b268610e9..b268610e9 100755 --- a/lib/puppet/type/pfilebucket.rb +++ b/lib/puppet/type/filebucket.rb diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb index a52575522..535d9ef2e 100644 --- a/lib/puppet/util/autoload.rb +++ b/lib/puppet/util/autoload.rb @@ -1,6 +1,9 @@ +require 'puppet/util/warnings' + # Autoload paths, either based on names or all at once. class Puppet::Util::Autoload include Puppet::Util + include Puppet::Util::Warnings @autoloaders = {} @loaded = [] @@ -109,9 +112,8 @@ class Puppet::Util::Autoload Dir.glob("#{dir}/*.rb").each do |file| name = File.basename(file).sub(".rb", '').intern next if loaded?(name) - rubypath = File.join(@path, name.to_s) begin - Kernel.require rubypath + Kernel.require file loaded(name, file) rescue => detail if Puppet[:trace] @@ -123,8 +125,6 @@ class Puppet::Util::Autoload end end - private - # Yield each subdir in turn. def eachdir searchpath.each do |dir| @@ -137,7 +137,7 @@ class Puppet::Util::Autoload def searchpath # JJM: Search for optional lib directories in each module bundle. module_lib_dirs = Puppet[:modulepath].split(":").collect do |d| - Dir.glob("%s/*/lib" % d).select do |f| + Dir.glob("%s/*/{plugins,lib}" % d).select do |f| FileTest.directory?(f) end end.flatten diff --git a/lib/puppet/util/checksums.rb b/lib/puppet/util/checksums.rb index 6f6ea59b5..598b3adfa 100644 --- a/lib/puppet/util/checksums.rb +++ b/lib/puppet/util/checksums.rb @@ -1,37 +1,75 @@ +# A stand-alone module for calculating checksums +# in a generic way. module Puppet::Util::Checksums + # Calculate a checksum using Digest::MD5. def md5(content) require 'digest/md5' Digest::MD5.hexdigest(content) end - def md5_file(filename) + # Calculate a checksum of the first 500 chars of the content using Digest::MD5. + def md5lite(content) + md5(content[0..511]) + end + + # Calculate a checksum of a file's content using Digest::MD5. + def md5_file(filename, lite = false) require 'digest/md5' - incr_digest = Digest::MD5.new() - File.open(filename, 'r') do |file| - file.each_line do |line| - incr_digest << line - end - end + digest = Digest::MD5.new() + return checksum_file(digest, filename, lite) + end + + # Calculate a checksum of the first 500 chars of a file's content using Digest::MD5. + def md5lite_file(filename) + md5_file(filename, true) + end - return incr_digest.hexdigest + # Return the :mtime timestamp of a file. + def mtime_file(filename) + File.stat(filename).send(:mtime) end + # Calculate a checksum using Digest::SHA1. def sha1(content) require 'digest/sha1' Digest::SHA1.hexdigest(content) end - def sha1_file(filename) + # Calculate a checksum of the first 500 chars of the content using Digest::SHA1. + def sha1lite(content) + sha1(content[0..511]) + end + + # Calculate a checksum of a file's content using Digest::SHA1. + def sha1_file(filename, lite = false) require 'digest/sha1' - incr_digest = Digest::SHA1.new() + digest = Digest::SHA1.new() + return checksum_file(digest, filename, lite) + end + + # Calculate a checksum of the first 500 chars of a file's content using Digest::SHA1. + def sha1lite_file(filename) + sha1_file(filename, true) + end + + # Return the :ctime of a file. + def timestamp_file(filename) + File.stat(filename).send(:ctime) + end + + private + + # Perform an incremental checksum on a file. + def checksum_file(digest, filename, lite = false) File.open(filename, 'r') do |file| - file.each_line do |line| - incr_digest << line + while content = file.read(512) + digest << content + break if lite end end - return incr_digest.hexdigest + return digest.hexdigest end end diff --git a/man/man8/puppet.8 b/man/man8/puppet.8 index 1bfea08f9..2eefc6a0a 100644 --- a/man/man8/puppet.8 +++ b/man/man8/puppet.8 @@ -20,10 +20,81 @@ Run a stand\-alone +puppet+ script. .\" depart_block_quote .SH DESCRIPTION -This is the standalone puppet execution script; use it to execute -individual scripts that you write. If you need to execute site\-wide -scripts, use +puppetd+ and +puppetmasterd+. +This document is intended as a secondary reference only. Please refer to the complete documentation on the +.B puppet +website: +.PP +\h"4"http://www.reductivelabs.com/trac/puppet/wiki/DocumentationStart +.PP +Every +.B puppet +executable (with the exception of +.B puppetdoc +) accepts all of the arguments below, but not all of the arguments make sense for every executable. Each argument has a section listed with it in parentheses; often, that section will map to an executable (e.g., +.B puppetd +), in which case it probably only makes sense for that one executable. If +.B puppet +is listed as the section, it is most likely an option that is valid for everyone. +.PP +This will not always be the case. I have tried to be as thorough as possible in the descriptions of the arguments, so it should be obvious whether an argument is appropriate or not. +.PP +These arguments can be supplied to the executables either as command-line arugments or in the configuration file for the appropriate executable. For instance, the command-line invocation below would set the configuration directory to /private/puppet: +.PP +\h"4"$ puppetd --confdir=/private/puppet +.PP +Note that boolean options are turned on and off with a slightly different syntax on the command line: +.PP +\h"4"$ puppetd --storeconfigs +.PP +\h"4"$ puppetd --no-storeconfigs +.PP +The invocations above will enable and disable, respectively, the storage of the client configuration. +.PP +As mentioned above, the configuration parameters can also be stored in a configuration file located in the configuration directory (/etc/puppet by default). The file is called puppet.conf. +.PP +The file, which follows INI-style formatting, should contain a bracketed heading named for each executable, followed by pairs of parameters with their values. Here is an example of a very simple puppet.conf file: +.PP +\h"4"[puppetd] +.br +\h"4"confdir = /private/puppet +.br +\h"4"storeconfigs = true +.br +.PP +Note that boolean parameters must be explicitly specified as true or false as seen above. +.PP +If you're starting out with a fresh configuration, you may wish to let the executable generate a template configuration file for you by invoking the executable in question with the --genconfig command. The executable will print a template configuration to standard output, which can be redirected to a file like so: +.PP +\h"4"$ puppetd --genconfig > /etc/puppet/puppet.conf +.PP +Note that this invocation will "clobber" (throw away) the contents of any pre-existing puppet.conf file, so make a backup of your present config if it contains valuable information. +.PP +Like the --genconfig argument, the executables also accept a --genmanifest argument, which will generate a manifest that can be used to manage all of +.B Puppet's +directories and files and prints it to standard output. This can likewise be redirected to a file: +.PP +\h"4"$ puppetd --genmanifest > /etc/puppet/manifests/site.pp +.PP +.B Puppet +can also create user and group accounts for itself (one puppet group and one puppet user) if it is invoked as root with the --mkusers argument: +.PP +\h"4"$ puppetd --mkusers +.PP +.SH SIGNALS +The +.B puppetd +and +.B puppetmasterd +executables catch some signals for special handling. Both daemons catch (SIGHUP), which forces the server to restart tself. Predictably, interrupt and terminate (SIGINT and SIGHUP) will shut down the server, whether it be an instance of +.B puppetd +or +.B puppetmasterd. +.PP +Sending the SIGUSR1 signal to an instance of +.B puppetd +will cause it to immediately begin a new configuration transaction with the server. This signal has no effect on +.B puppetmasterd. .SH OPTIONS Note that any configuration parameter that\'s valid in the configuration diff --git a/spec/unit/ral/types/file.rb b/spec/unit/ral/types/file.rb index 1e20b06f4..7202e23e5 100755 --- a/spec/unit/ral/types/file.rb +++ b/spec/unit/ral/types/file.rb @@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/../../../spec_helper' -require 'puppet/type/pfile' +require 'puppet/type/file' describe Puppet::Type::File, " when used with replace=>false and content" do before do diff --git a/spec/unit/simple_graph.rb b/spec/unit/simple_graph.rb index c8fe14cf3..e1e42e40f 100755 --- a/spec/unit/simple_graph.rb +++ b/spec/unit/simple_graph.rb @@ -266,4 +266,15 @@ describe Puppet::SimpleGraph, " when sorting the graph" do add_edges :a => :b, :b => :e, :c => :a, :d => :c proc { @graph.topsort }.should_not raise_error end + + # Our graph's add_edge method is smart enough not to add + # duplicate edges, so we use the objects, which it doesn't + # check. + it "should be able to sort graphs with duplicate edges" do + one = Puppet::Relationship.new(:a, :b) + @graph.add_edge(one) + two = Puppet::Relationship.new(:a, :b) + @graph.add_edge(two) + proc { @graph.topsort }.should_not raise_error + end end diff --git a/spec/unit/util/checksums.rb b/spec/unit/util/checksums.rb new file mode 100755 index 000000000..31cf24f5b --- /dev/null +++ b/spec/unit/util/checksums.rb @@ -0,0 +1,99 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-9-22. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/util/checksums' + +describe Puppet::Util::Checksums do + before do + @summer = Object.new + @summer.extend(Puppet::Util::Checksums) + end + + content_sums = [:md5, :md5lite, :sha1, :sha1lite] + file_only = [:timestamp, :mtime] + + content_sums.each do |sumtype| + it "should be able to calculate %s sums from strings" % sumtype do + @summer.should be_respond_to(sumtype) + end + end + + [content_sums, file_only].flatten.each do |sumtype| + it "should be able to calculate %s sums from files" % sumtype do + @summer.should be_respond_to(sumtype.to_s + "_file") + end + end + + {:md5 => Digest::MD5, :sha1 => Digest::SHA1}.each do |sum, klass| + describe("when using %s" % sum) do + it "should use #{klass} to calculate string checksums" do + klass.expects(:hexdigest).with("mycontent").returns "whatever" + @summer.send(sum, "mycontent").should == "whatever" + end + + it "should use incremental #{klass} sums to calculate file checksums" do + digest = mock 'digest' + klass.expects(:new).returns digest + + file = "/path/to/my/file" + + fh = mock 'filehandle' + fh.expects(:read).with(512).times(3).returns("firstline").then.returns("secondline").then.returns(nil) + #fh.expects(:read).with(512).returns("secondline") + #fh.expects(:read).with(512).returns(nil) + + File.expects(:open).with(file, "r").yields(fh) + + digest.expects(:<<).with "firstline" + digest.expects(:<<).with "secondline" + digest.expects(:hexdigest).returns :mydigest + + @summer.send(sum.to_s + "_file", file).should == :mydigest + end + end + end + + {:md5lite => Digest::MD5, :sha1lite => Digest::SHA1}.each do |sum, klass| + describe("when using %s" % sum) do + it "should use #{klass} to calculate string checksums from the first 512 characters of the string" do + content = "this is a test" * 100 + klass.expects(:hexdigest).with(content[0..511]).returns "whatever" + @summer.send(sum, content).should == "whatever" + end + + it "should use #{klass} to calculate a sum from the first 512 characters in the file" do + digest = mock 'digest' + klass.expects(:new).returns digest + + file = "/path/to/my/file" + + fh = mock 'filehandle' + fh.expects(:read).with(512).returns('my content') + + File.expects(:open).with(file, "r").yields(fh) + + digest.expects(:<<).with "my content" + digest.expects(:hexdigest).returns :mydigest + + @summer.send(sum.to_s + "_file", file).should == :mydigest + end + end + end + + {:timestamp => :ctime, :mtime => :mtime}.each do |sum, method| + describe("when using %s" % sum) do + it "should use the '#{method}' on the file to determine the timestamp" do + file = "/my/file" + stat = mock 'stat', method => "mysum" + + File.expects(:stat).with(file).returns(stat) + + @summer.send(sum.to_s + "_file", file).should == "mysum" + end + end + end +end diff --git a/test/executables/puppetbin.rb b/test/executables/puppetbin.rb index 218787c92..08329efb6 100755 --- a/test/executables/puppetbin.rb +++ b/test/executables/puppetbin.rb @@ -83,5 +83,22 @@ class TestPuppetBin < Test::Unit::TestCase assert(FileTest.exists?(path), "Failed to create config'ed file") end + + def test_parseonly + path = tempfile() + manifest = tempfile() + puppet = %x{which puppet}.chomp + if puppet == "" + Puppet.info "cannot find puppet; cannot test parseonly" + return + end + code = 'File <<| |>> + include nosuchclass' + + assert_nothing_raised { + IO.popen("#{puppet} --parseonly", 'w') { |p| p.puts code } + } + assert($? == 0, "parseonly test exited with code %s" % $?.to_i) + end end diff --git a/test/lib/puppettest.rb b/test/lib/puppettest.rb index 6c95985bf..902831e68 100755 --- a/test/lib/puppettest.rb +++ b/test/lib/puppettest.rb @@ -17,6 +17,8 @@ Dir["#{mainlib}/../vendor/gems/**"].each do |path| end end +require 'mocha' + # Only load the test/unit class if we're not in the spec directory. # Else we get the bogus 'no tests, no failures' message. unless Dir.getwd =~ /spec/ @@ -315,7 +317,6 @@ module PuppetTest rescue Timeout::Error # just move on end - mocha_verify end def logstore diff --git a/test/util/autoload.rb b/test/util/autoload.rb index 6babed774..de503ab99 100755 --- a/test/util/autoload.rb +++ b/test/util/autoload.rb @@ -103,10 +103,10 @@ TestAutoload.newthing(:#{name.to_s}) assert(loader.send(:searchpath).include?(dir), "searchpath does not include the libdir") end - # This causes very strange behaviour in the tests. We need to make sure we - # require the same path that a user would use, otherwise we'll result in - # a reload of the - def test_require_does_not_cause_reload + # This tests #1027, which was caused by using the unqualified + # path for requires, which was initially done so that the kernel + # would keep track of which files got loaded. + def test_require_uses_full_path loadname = "testing" loader = Puppet::Util::Autoload.new(self.class, loadname) @@ -120,7 +120,26 @@ TestAutoload.newthing(:#{name.to_s}) Dir.expects(:glob).with("#{dir}/*.rb").returns(file) - Kernel.expects(:require).with(File.join(loadname, subname)) + Kernel.expects(:require).with(file) loader.loadall end + + def test_searchpath_includes_plugin_dirs + moddir = "/what/ever" + libdir = "/other/dir" + Puppet.settings.stubs(:value).with(:modulepath).returns(moddir) + Puppet.settings.stubs(:value).with(:libdir).returns(libdir) + + loadname = "testing" + loader = Puppet::Util::Autoload.new(self.class, loadname) + + # Currently, include both plugins and libs. + paths = %w{plugins lib}.inject({}) { |hash, d| hash[d] = File.join(moddir, "testing", d); FileTest.stubs(:directory?).with(hash[d]).returns(true); hash } + Dir.expects(:glob).with("#{moddir}/*/{plugins,lib}").returns(paths.values) + + searchpath = loader.searchpath + paths.each do |dir, path| + assert(searchpath.include?(path), "search path did not include path for %s" % dir) + end + end end |