diff options
60 files changed, 970 insertions, 812 deletions
@@ -1,3 +1,12 @@ + Somewhat refactored fileserving so that it no longer caches + any objects, nor does it use Puppet's RAL resources. In the + process, I fixed #894 (you can now copy links) and refactored + other classes as necessary. Mostly it was fixing tests. + + Hopefully partially fixed #1010 -- clients should now fail + to install files whose checksums do not match the checksum + from the server. + Fixed #1018 -- resources now have their namevars added as aliases in the resource catalog, just like they were added in the resource classes. @@ -37,9 +46,9 @@ between the classes, definitions, and nodes, and the Compile class much cleaner. - Exec resources must now have unique names. This is easily accomplished by - just specifying a unique name with whatever (unique or otherwise) command - you need. + Exec resources must now have unique names, although the commands can still + be duplicated. This is easily accomplished by just specifying a unique + name with whatever (unique or otherwise) command you need. Fixed #989 -- missing CRL files are correctly ignored, and the value should be set to 'false' to explicitly not look for these diff --git a/bin/puppet b/bin/puppet index 952ffcbf8..9e1102a3d 100755 --- a/bin/puppet +++ b/bin/puppet @@ -136,6 +136,14 @@ end Puppet.parse_config +# Now parse the config +if Puppet[:config] and File.exists? Puppet[:config] + Puppet.settings.parse(Puppet[:config]) +end + +Puppet.genconfig +Puppet.genmanifest + # If noop is set, then also enable diffs if Puppet[:noop] Puppet[:show_diff] = true @@ -156,14 +164,6 @@ elsif options[:verbose] Puppet::Util::Log.level = :info end -# Now parse the config -if Puppet[:config] and File.exists? Puppet[:config] - Puppet.settings.parse(Puppet[:config]) -end - -Puppet.genconfig -Puppet.genmanifest - # Set our code or file to use. if options[:code] or ARGV.length == 0 Puppet[:code] = options[:code] || STDIN.read diff --git a/conf/namespaceauth.conf b/conf/namespaceauth.conf new file mode 100644 index 000000000..b735fc0c4 --- /dev/null +++ b/conf/namespaceauth.conf @@ -0,0 +1,20 @@ +[fileserver] + allow *.madstop.com + +[puppetmaster] + allow *.madstop.com + +[pelementserver] + allow puppet.madstop.com + +[puppetrunner] + allow culain.madstop.com + +[puppetbucket] + allow *.madstop.com + +[puppetreports] + allow *.madstop.com + +[resource] + allow midden.madstop.com diff --git a/debian/README.source b/debian/README.source index 49b373b40..fd9155241 100644 --- a/debian/README.source +++ b/debian/README.source @@ -1,9 +1,2 @@ -The debian/ directory for this package is maintained in bzr. There are two -primary branches, kept by each maintainer: - -http://www.hezmatt.org/~mpalmer/bzr/puppet.debian (mpalmer) -http://repo.spacepants.org/puppet/puppet.debian (jaq) - -Typically all the changes will be in one (or both) of these branches. They -merge from each other on a regular basis, and the canonical version for a -release just depends on who actually made the upload. +The debian directory is now maintained on Alioth in git. +See http://pkg-puppet.alioth.debian.org/ for more information. diff --git a/debian/changelog b/debian/changelog index 1a33e55c3..69984d622 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,114 @@ +puppet (0.24.1-2) unstable; urgency=low + + * Set rundir correctly (Closes: #460203, #459579) + * Apply patch for puppet#1003 to enable collection of tagged resources + + -- Thom May <thom@debian.org> Wed, 16 Jan 2008 11:08:55 +0100 + +puppet (0.24.1-1) unstable; urgency=low + + * New upstream release (Closes: #445626) + * Set maintainer to pkg-puppet-devel + + -- Thom May <thom@debian.org> Sun, 30 Dec 2007 19:13:47 +0100 + +puppet (0.24.0-1) unstable; urgency=low + + * New upstream release + + -- Thom May <thom@debian.org> Wed, 19 Dec 2007 16:00:34 +0100 + +puppet (0.23.2-15) unstable; urgency=low + + * No change upload setting maintainer to me whilst waiting for an alioth + project. + + -- Thom May <thom@debian.org> Thu, 29 Nov 2007 10:44:50 +0100 + +puppet (0.23.2-14) unstable; urgency=low + + * Orphaning. + * Create /var/lib/puppet in the puppet package. Closes: #452506. + * Start the puppet init script after puppetmaster, to silence whiny bug + reports. Closes: #452064. + * Add a reload command to the Puppet init script. Closes: #452060. + + -- Matthew Palmer <mpalmer@debian.org> Thu, 29 Nov 2007 10:48:21 +1100 + +puppet (0.23.2-13) unstable; urgency=low + + * Drop quotes from an already-quoted value in a query. Closes: #448179. + * Remove excessive quoting from puppet/network/handler/master.rb. + Closes: #448221. + * Force removal of directories during pluginsync. Closes: #448180. + + -- Matthew Palmer <mpalmer@debian.org> Tue, 30 Oct 2007 14:55:19 +1100 + +puppet (0.23.2-12) unstable; urgency=low + + * Create /var/run/puppet and set the perms in the various initscripts, as + well as hardcoding the rundir better in configuration.rb and removing + the explicit rundir setting from puppet.conf. Closes: #447314. + * Apply additional patch given (backwards) to fix export/collect on some + database backends. Closes: #445591 (again!) + + -- Matthew Palmer <mpalmer@debian.org> Sat, 20 Oct 2007 11:28:50 +1000 + +puppet (0.23.2-11) unstable; urgency=low + + * Apply patch from puppet#786 to fix a problem with exported resources not + being properly detected as needing a rerun. Closes: #445591. + * Fix ignore handling for the plugins mount. Closes: #446390. + + -- Matthew Palmer <mpalmer@debian.org> Mon, 15 Oct 2007 09:11:25 +1000 + +puppet (0.23.2-10) unstable; urgency=low + + * Recycle connections when we change (or get) certs. + * Catch and retry more transient errors in the XMLRPC wrapper. + + -- Matthew Palmer <mpalmer@debian.org> Thu, 27 Sep 2007 15:06:11 +1000 + +puppet (0.23.2-9) unstable; urgency=low + + * Recycle the HTTP connection if we get an EPIPE during a request. + Closes: #444177. Thanks to Jos Backus for helping with testing. + + -- Matthew Palmer <mpalmer@debian.org> Thu, 27 Sep 2007 09:55:34 +1000 + +puppet (0.23.2-8) unstable; urgency=low + + * Remove extraneous debugging output accidentally left behind in the last + release. + * Fix spelling mistakes in debian/control and debian/puppet.preinst. + Closes: #444158. + + -- Matthew Palmer <mpalmer@debian.org> Thu, 27 Sep 2007 07:45:07 +1000 + +puppet (0.23.2-7) unstable; urgency=low + + * Ignore ENOENT errors in the module plugin syncing code, since they're + innocuous and expected. + * Allow facts that are downloaded through pluginsync to be used like any + other fact. + * Allow users to still have an old-style plugins mount if they want, by + specifying a path for the mount. Also track down a fault in old-style + fileserving which did strange slash-stripping. Closes: #443932. + + -- Matthew Palmer <mpalmer@debian.org> Tue, 25 Sep 2007 16:41:32 +1000 + +puppet (0.23.2-6) unstable; urgency=low + + * Patch rails/param_name.rb to stop query failures, as per puppet#784. + * Actually honour namevar. + * Only set dbuser if explicitly asked for. + * Fix annoying database deletion error for ParamValue objects. + * Add an accessor for ca_file, since older openssl-ruby only had a writer. + * Fix the fileserver to honour ignore. Thanks to Nathan Ward for the + bug report on IRC. + + -- Matthew Palmer <mpalmer@debian.org> Thu, 20 Sep 2007 16:10:41 +1000 + puppet (0.23.2-5) unstable; urgency=low * Add some NEWS for the ssldir transition. Should have done that earlier. diff --git a/debian/control b/debian/control index 879c9770c..8b0e92e7e 100644 --- a/debian/control +++ b/debian/control @@ -1,8 +1,8 @@ Source: puppet Section: admin Priority: optional -Maintainer: Matthew Palmer <mpalmer@debian.org> -Uploaders: Jamie Wilkinson <jaq@debian.org>, Matthew Palmer <mpalmer@debian.org> +Maintainer: Puppet Package Maintainers <pkg-puppet-devel@lists.alioth.debian.org> +Uploaders: Thom May <thom@debian.org> Build-Depends-Indep: debhelper (>= 4.0.0), ruby (>= 1.8.1) Standards-Version: 3.6.2 diff --git a/debian/puppet.conf b/debian/puppet.conf index e17d039bb..c541c748a 100644 --- a/debian/puppet.conf +++ b/debian/puppet.conf @@ -2,6 +2,7 @@ logdir=/var/log/puppet vardir=/var/lib/puppet ssldir=/var/lib/puppet/ssl +rundir=/var/run/puppet [puppetmasterd] templatedir=/var/lib/puppet/templates diff --git a/debian/puppet.dirs b/debian/puppet.dirs index 95ccc1e1b..9ce18f88e 100644 --- a/debian/puppet.dirs +++ b/debian/puppet.dirs @@ -3,4 +3,5 @@ usr/lib/ruby/1.8 var/log/puppet etc/puppet/files usr/share/vim/addons/ftdetect -usr/share/vim/vim70/syntax +usr/share/vim/vim71/syntax +var/lib/puppet diff --git a/debian/puppet.init b/debian/puppet.init index da9f548cb..063f9273f 100644 --- a/debian/puppet.init +++ b/debian/puppet.init @@ -12,6 +12,10 @@ test -x $DAEMON || exit 0 . /lib/lsb/init-functions +reload_puppet() { + start-stop-daemon --stop --quiet --signal HUP --pidfile /var/run/puppet/$NAME.pid +} + start_puppet() { start-stop-daemon --start --quiet --pidfile /var/run/puppet/$NAME.pid \ --startas $DAEMON -- $DAEMON_OPTS @@ -39,7 +43,12 @@ case "$1" in stop_puppet log_end_msg 0 ;; - restart|force-reload) + reload) + log_begin_msg "Reloading $DESC" + reload_puppet + log_end_msg 0 + ;; + restart|force-reload) log_begin_msg "Restarting $DESC" stop_puppet sleep 1 @@ -47,7 +56,7 @@ case "$1" in log_end_msg 0 ;; *) - echo "Usage: $0 {start|stop|restart|force-reload}" >&2 + echo "Usage: $0 {start|stop|restart|force-reload|reload}" >&2 exit 1 ;; esac diff --git a/debian/rules b/debian/rules index 69bf3a4af..ecabcbad0 100644..100755 --- a/debian/rules +++ b/debian/rules @@ -66,10 +66,10 @@ install: build $(INSTALL) -m0644 debian/puppet.conf $(pkgconfdir)/puppet.conf # Vim auto-syntax-highlighting stuff - $(INSTALL) -m0644 ext/vim/puppet.vim \ - $(CURDIR)/debian/puppet/usr/share/vim/vim70/syntax/puppet.vim - $(INSTALL) -m0644 ext/vim/filetype.vim \ - $(CURDIR)/debian/puppet/usr/share/vim/addons/ftdetect/puppet.vim + $(INSTALL) -m0644 ext/vim/syntax/puppet.vim \ + $(CURDIR)/debian/puppet/usr/share/vim/vim71/syntax/ + $(INSTALL) -m0644 ext/vim/ftdetect/puppet.vim \ + $(CURDIR)/debian/puppet/usr/share/vim/addons/ftdetect/ # Emacs keeping up with the Joneses $(INSTALL) -m0644 ext/emacs/puppet-mode-init.el \ @@ -100,7 +100,8 @@ binary-indep: build install dh_movefiles -i dh_installchangelogs -i CHANGELOG dh_installdocs -i - dh_installinit -i + dh_installinit -ppuppetmaster + dh_installinit -ppuppet -- defaults 21 dh_installlogrotate -i dh_compress -i dh_fixperms -i diff --git a/lib/puppet/dsl.rb b/lib/puppet/dsl.rb index 4fbce556c..966feaf9b 100644 --- a/lib/puppet/dsl.rb +++ b/lib/puppet/dsl.rb @@ -46,58 +46,56 @@ # # apply -module Puppet - # Provide the actual commands for acting like a language. - module DSL - def aspect(name, options = {}, &block) - Puppet::Aspect.new(name, options, &block) - end +require 'puppet' - def acquire(*names) - names.each do |name| - if aspect = Puppet::Aspect[name] - unless aspect.evaluated? - aspect.evaluate - end - else - raise "Could not find aspect %s" % name +# Provide the actual commands for acting like a language. +module Puppet::DSL + def aspect(name, options = {}, &block) + Puppet::DSL::Aspect.new(name, options, &block) + end + + def acquire(*names) + names.each do |name| + if aspect = Puppet::DSL::Aspect[name] + unless aspect.evaluated? + aspect.evaluate end + else + raise "Could not find aspect %s" % name end end + end - def apply - bucket = export() - catalog = bucket.to_catalog - catalog.apply - end + def apply + bucket = export() + catalog = bucket.to_catalog + catalog.apply + end - def export - objects = Puppet::Aspect.collect do |name, aspect| - if aspect.evaluated? - aspect.export - end - end.reject { |a| a.nil? }.flatten.collect do |obj| - obj.to_trans + def export + objects = Puppet::DSL::Aspect.collect do |name, aspect| + if aspect.evaluated? + aspect.export end - bucket = Puppet::TransBucket.new(objects) - bucket.name = "top" - bucket.type = "class" - - return bucket + end.reject { |a| a.nil? }.flatten.collect do |obj| + obj.to_trans end + bucket = Puppet::TransBucket.new(objects) + bucket.name = "top" + bucket.type = "class" - def init - unless Process.uid == 0 - Puppet[:confdir] = File.expand_path("~/.puppet") - Puppet[:vardir] = File.expand_path("~/.puppet/var") - end - Puppet[:user] = Process.uid - Puppet[:group] = Process.gid - Puppet::Util::Log.newdestination(:console) - Puppet::Util::Log.level = :info - end + return bucket + end - private + def init + unless Process.uid == 0 + Puppet[:confdir] = File.expand_path("~/.puppet") + Puppet[:vardir] = File.expand_path("~/.puppet/var") + end + Puppet[:user] = Process.uid + Puppet[:group] = Process.gid + Puppet::Util::Log.newdestination(:console) + Puppet::Util::Log.level = :info end class Aspect @@ -224,10 +222,10 @@ module Puppet end def newresource(type, name, params = {}) - if self.is_a?(Puppet::Aspect) + if self.is_a?(Puppet::DSL::Aspect) source = self else - source = Puppet::Aspect[:main] + source = Puppet::DSL::Aspect[:main] end unless obj = @@objects[type][name] obj = Resource.new :title => name, :type => type.name, @@ -262,7 +260,7 @@ module Puppet env = nil end @node.parameters = Facter.to_hash - @compile = Puppet::Parser::Compile.new(@node, @interp.send(:parser, env)) + @compile = Puppet::Parser::Compiler.new(@node, @interp.send(:parser, env)) @scope = @compile.topscope end @scope diff --git a/lib/puppet/file_serving/file_base.rb b/lib/puppet/file_serving/file_base.rb index 7f169d1ea..06b3ad9ef 100644 --- a/lib/puppet/file_serving/file_base.rb +++ b/lib/puppet/file_serving/file_base.rb @@ -9,16 +9,28 @@ require 'puppet/file_serving' class Puppet::FileServing::FileBase attr_accessor :key + # Does our file exist? + def exist? + begin + stat + return true + rescue => detail + return false + end + end + # Return the full path to our file. Fails if there's no path set. def full_path raise(ArgumentError, "You must set a path to get a file's path") unless self.path - relative_path ? File.join(path, relative_path) : path + if relative_path.nil? or relative_path == "" + path + else + File.join(path, relative_path) + end end def initialize(key, options = {}) - raise ArgumentError.new("Files must not be fully qualified") if path =~ /^#{::File::SEPARATOR}/ - @key = key @links = :manage diff --git a/lib/puppet/file_serving/metadata.rb b/lib/puppet/file_serving/metadata.rb index e26e75844..56712122c 100644 --- a/lib/puppet/file_serving/metadata.rb +++ b/lib/puppet/file_serving/metadata.rb @@ -28,6 +28,25 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::FileBase attr_reader :path, :owner, :group, :mode, :checksum_type, :checksum, :ftype, :destination + PARAM_ORDER = [:mode, :ftype, :owner, :group] + + def attributes_with_tabs + desc = [] + PARAM_ORDER.each { |check| + check = :ftype if check == :type + desc << send(check) + } + + case ftype + when "file", "directory": desc << checksum + when "link": desc << @destination + else + raise ArgumentError, "Cannot manage files of type %s" % ftype + end + + return desc.join("\t") + end + def checksum_type=(type) raise(ArgumentError, "Unsupported checksum type %s" % type) unless respond_to?("%s_file" % type) @@ -45,13 +64,19 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::FileBase @ftype = stat.ftype - # Set the octal mode, but as a string. - @mode = "%o" % (stat.mode & 007777) + # We have to mask the mode, yay. + @mode = stat.mode & 007777 - if stat.ftype == "symlink" + case stat.ftype + when "file": + @checksum = ("{%s}" % @checksum_type) + send("%s_file" % @checksum_type, real_path) + when "directory": # Always just timestamp the directory. + sumtype = @checksum_type.to_s =~ /time/ ? @checksum_type : "ctime" + @checksum = ("{%s}" % sumtype) + send("%s_file" % sumtype, path).to_s + when "link": @destination = File.readlink(real_path) else - @checksum = get_checksum(real_path) + raise ArgumentError, "Cannot manage files of type %s" % stat.ftype end end @@ -59,11 +84,4 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::FileBase @checksum_type = "md5" super end - - private - - # Retrieve our checksum. - def get_checksum(path) - ("{%s}" % @checksum_type) + send("%s_file" % @checksum_type, path) - end end diff --git a/lib/puppet/metatype/evaluation.rb b/lib/puppet/metatype/evaluation.rb index b3b6570b2..08756e988 100644 --- a/lib/puppet/metatype/evaluation.rb +++ b/lib/puppet/metatype/evaluation.rb @@ -125,26 +125,14 @@ class Puppet::Type raise Puppet::DevError, "Parameter ensure defined but missing from current values" end if @parameters.include?(:ensure) and ! ensureparam.insync?(currentvalues[ensureparam]) -# self.info "ensuring %s from %s" % -# [@parameters[:ensure].should, @parameters[:ensure].is] changes << Puppet::PropertyChange.new(ensureparam, currentvalues[ensureparam]) # Else, if the 'ensure' property is correctly absent, then do # nothing elsif @parameters.include?(:ensure) and currentvalues[ensureparam] == :absent - # self.info "Object is correctly absent" return [] else -# if @parameters.include?(:ensure) -# self.info "ensure: Is: %s, Should: %s" % -# [@parameters[:ensure].is, @parameters[:ensure].should] -# else -# self.info "no ensure property" -# end changes = properties().find_all { |property| - unless currentvalues.include?(property) - raise Puppet::DevError, "Property %s does not have a current value", - [property.name] - end + currentvalues[property] ||= :absent ! property.insync?(currentvalues[property]) }.collect { |property| Puppet::PropertyChange.new(property, currentvalues[property]) @@ -152,10 +140,7 @@ class Puppet::Type end if Puppet[:debug] and changes.length > 0 - self.debug("Changing " + changes.collect { |ch| - ch.property.name - }.join(",") - ) + self.debug("Changing " + changes.collect { |ch| ch.property.name }.join(",")) end changes diff --git a/lib/puppet/network/client.rb b/lib/puppet/network/client.rb index 283436e95..0a0a72345 100644 --- a/lib/puppet/network/client.rb +++ b/lib/puppet/network/client.rb @@ -95,9 +95,7 @@ class Puppet::Network::Client # We have to start the HTTP connection manually before we start # sending it requests or keep-alive won't work. - if @driver.respond_to? :start - @driver.start - end + @driver.start if @driver.respond_to? :start @local = false elsif hash.include?(driverparam) @@ -107,8 +105,7 @@ class Puppet::Network::Client end @local = true else - raise Puppet::Network::ClientError, "%s must be passed a Server or %s" % - [self.class, driverparam] + raise Puppet::Network::ClientError, "%s must be passed a Server or %s" % [self.class, driverparam] end end diff --git a/lib/puppet/network/client/master.rb b/lib/puppet/network/client/master.rb index 6d1a0235f..390f3d4e2 100644 --- a/lib/puppet/network/client/master.rb +++ b/lib/puppet/network/client/master.rb @@ -40,8 +40,10 @@ class Puppet::Network::Client::Master < Puppet::Network::Client facts["clientversion"] = Puppet.version.to_s # And add our environment as a fact. - facts["environment"] = Puppet[:environment] - + unless facts.include?("environment") + facts["environment"] = Puppet[:environment] + end + facts end diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb index e6378bf01..a9a95bcfe 100755 --- a/lib/puppet/network/handler/fileserver.rb +++ b/lib/puppet/network/handler/fileserver.rb @@ -5,6 +5,9 @@ require 'cgi' require 'delegate' require 'sync' +require 'puppet/file_serving' +require 'puppet/file_serving/metadata' + class Puppet::Network::Handler AuthStoreError = Puppet::AuthStoreError class FileServerError < Puppet::Error; end @@ -59,40 +62,27 @@ class Puppet::Network::Handler # Describe a given file. This returns all of the manageable aspects # of that file. - def describe(url, links = :ignore, client = nil, clientip = nil) + def describe(url, links = :follow, client = nil, clientip = nil) links = links.intern if links.is_a? String - if links == :manage - raise Puppet::Network::Handler::FileServerError, "Cannot currently copy links" - end - mount, path = convert(url, client, clientip) - if client - mount.debug "Describing %s for %s" % [url, client] - end + mount.debug("Describing %s for %s" % [url, client]) if client + + # Remove any leading slashes, since Metadata doesn't like them, yo. + metadata = Puppet::FileServing::Metadata.new(url, :path => mount.path(client), :relative_path => path.sub(/^\//, ''), :links => links) - obj = nil - unless obj = mount.getfileobject(path, links, client) + return "" unless metadata.exist? + + begin + metadata.collect_attributes + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err detail return "" end - currentvalues = mount.check(obj) - - desc = [] - CHECKPARAMS.each { |check| - if value = currentvalues[check] - desc << value - else - if check == "checksum" and currentvalues[:type] == "file" - mount.notice "File %s does not have data for %s" % - [obj.name, check] - end - desc << nil - end - } - - return desc.join("\t") + return metadata.attributes_with_tabs end # Create a new fileserving module. @@ -140,26 +130,18 @@ class Puppet::Network::Handler def list(url, links = :ignore, recurse = false, ignore = false, client = nil, clientip = nil) mount, path = convert(url, client, clientip) - if client - mount.debug "Listing %s for %s" % [url, client] - end + mount.debug "Listing %s for %s" % [url, client] if client - obj = nil - unless mount.path_exists?(path, client) - return "" - end + return "" unless mount.path_exists?(path, client) desc = mount.list(path, recurse, ignore, client) if desc.length == 0 - mount.notice "Got no information on //%s/%s" % - [mount, path] + mount.notice "Got no information on //%s/%s" % [mount, path] return "" end - - desc.collect { |sub| - sub.join("\t") - }.join("\n") + + desc.collect { |sub| sub.join("\t") }.join("\n") end def local? @@ -213,12 +195,7 @@ class Puppet::Network::Handler return "" end - str = nil - if links == :manage - raise Puppet::Error, "Cannot copy links yet." - else - str = mount.read_file(path, client) - end + str = mount.read_file(path, client) if @local return str diff --git a/lib/puppet/network/http_pool.rb b/lib/puppet/network/http_pool.rb index 99f09a90c..69574d8fd 100644 --- a/lib/puppet/network/http_pool.rb +++ b/lib/puppet/network/http_pool.rb @@ -1,6 +1,9 @@ require 'puppet/sslcertificates/support' require 'net/https' +module Puppet::Network +end + # Manage Net::HTTP instances for keep-alive. module Puppet::Network::HttpPool # This handles reading in the key and such-like. diff --git a/lib/puppet/network/http_server/mongrel.rb b/lib/puppet/network/http_server/mongrel.rb index d340f3d63..6b2325d29 100644 --- a/lib/puppet/network/http_server/mongrel.rb +++ b/lib/puppet/network/http_server/mongrel.rb @@ -33,6 +33,7 @@ require 'xmlrpc/server' require 'puppet/network/xmlrpc/server' require 'puppet/network/http_server' require 'puppet/network/client_request' +require 'puppet/network/handler' require 'puppet/daemon' require 'resolv' diff --git a/lib/puppet/network/http_server/webrick.rb b/lib/puppet/network/http_server/webrick.rb index e4f00dd73..568b4e798 100644 --- a/lib/puppet/network/http_server/webrick.rb +++ b/lib/puppet/network/http_server/webrick.rb @@ -8,6 +8,7 @@ require 'puppet/sslcertificates/support' require 'puppet/network/xmlrpc/webrick_servlet' require 'puppet/network/http_server' require 'puppet/network/client' +require 'puppet/network/handler' module Puppet class ServerError < RuntimeError; end @@ -133,7 +134,7 @@ module Puppet handlers.collect { |handler, args| hclass = nil - unless hclass = Handler.handler(handler) + unless hclass = Puppet::Network::Handler.handler(handler) raise ServerError, "Invalid handler %s" % handler end hclass.new(args) diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb index ee4cedd4b..d680de9a0 100644 --- a/lib/puppet/node/catalog.rb +++ b/lib/puppet/node/catalog.rb @@ -1,4 +1,6 @@ require 'puppet/indirector' +require 'puppet/pgraph' +require 'puppet/transaction' require 'puppet/util/tagging' @@ -69,7 +71,10 @@ class Puppet::Node::Catalog < Puppet::PGraph @resource_table[ref] = resource # If the name and title differ, set up an alias - self.alias(resource, resource.name) if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.name != resource.title + #self.alias(resource, resource.name) if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.name != resource.title + if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.name != resource.title + self.alias(resource, resource.name) if resource.class.isomorphic? + end resource.catalog = self if resource.respond_to?(:catalog=) and ! is_relationship_graph @@ -499,7 +504,7 @@ class Puppet::Node::Catalog < Puppet::PGraph map.clear - result.add_class *self.classes + result.add_class(*self.classes) result.tag(*self.tags) return result diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb index d4b7449fb..d4655c403 100644 --- a/lib/puppet/parser/interpreter.rb +++ b/lib/puppet/parser/interpreter.rb @@ -24,8 +24,13 @@ class Puppet::Parser::Interpreter # evaluate our whole tree def compile(node) - raise Puppet::ParseError, "Could not parse configuration; cannot compile" unless env_parser = parser(node.environment) - return Puppet::Parser::Compiler.new(node, env_parser).compile + raise Puppet::ParseError, "Could not parse configuration; cannot compile on node %s" % node.name unless env_parser = parser(node.environment) + begin + return Puppet::Parser::Compiler.new(node, env_parser).compile + rescue => detail + puts detail.backtrace if Puppet[:trace] + raise Puppet::Error, detail.to_s + " on node %s" % node.name + end end # create our interpreter diff --git a/lib/puppet/provider/package/gem.rb b/lib/puppet/provider/package/gem.rb index f73694779..bb09bc5b0 100755 --- a/lib/puppet/provider/package/gem.rb +++ b/lib/puppet/provider/package/gem.rb @@ -78,7 +78,11 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d command << @resource[:name] end - gemcmd(*command) + output = gemcmd(*command) + # Apparently some stupid gem versions don't exit non-0 on failure + if output.include?("ERROR") + self.fail "Could not install: %s" % output.chomp + end end def latest diff --git a/lib/puppet/provider/package/pkgdmg.rb b/lib/puppet/provider/package/pkgdmg.rb index 2020b6b56..2614d0950 100644 --- a/lib/puppet/provider/package/pkgdmg.rb +++ b/lib/puppet/provider/package/pkgdmg.rb @@ -145,11 +145,8 @@ file system and not via a URL method." begin open(cached_source) do |dmg| xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-noidme", "-mountrandom", "/tmp", dmg.path - ptable = Plist::parse_xml xml_str - # JJM Filter out all mount-paths into a single array, discard the rest. - mounts = ptable['system-entities'].collect { |entity| - entity['mount-point'] - }.select { |mountloc|; mountloc } + # JJM THIS IS A HORRIBLE HACK (Well, actually it's not so bad...) + mounts = xml_str.scan(/<string>(\/tmp.*?)<\/string>/)[0] begin mounts.each do |fspath| Dir.entries(fspath).select { |f| diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb index d9919f58c..274c334a3 100755 --- a/lib/puppet/provider/service/init.rb +++ b/lib/puppet/provider/service/init.rb @@ -110,7 +110,7 @@ Puppet::Type.type(:service).provide :init, :parent => :base do # we just return that; otherwise, we return false, which causes it to # fallback to other mechanisms. def statuscmd - if @resource[:hasstatus] + if @resource[:hasstatus] == :true return [self.initscript, :status] else return false diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb index bd0ce8c92..0c579d0ad 100755 --- a/lib/puppet/sslcertificates.rb +++ b/lib/puppet/sslcertificates.rb @@ -72,7 +72,7 @@ module Puppet::SSLCertificates subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias end key_usage = %w{digitalSignature keyEncipherment} - ext_key_usage = %w{serverAuth clientAuth} + ext_key_usage = %w{serverAuth clientAuth emailProtection} when :ocsp: basic_constraint = "CA:FALSE" key_usage = %w{nonRepudiation digitalSignature} diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index c4e154d47..09003e8f5 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -257,10 +257,7 @@ class Type rescue ArgumentError, Puppet::Error, TypeError raise rescue => detail - error = Puppet::DevError.new( - "Could not set %s on %s: %s" % - [attr, self.class.name, detail] - ) + error = Puppet::DevError.new( "Could not set %s on %s: %s" % [attr, self.class.name, detail]) error.set_backtrace(detail.backtrace) raise error end @@ -422,10 +419,6 @@ end require 'puppet/propertychange' require 'puppet/provider' -require 'puppet/type/component' -require 'puppet/type/file' -require 'puppet/type/filebucket' -require 'puppet/type/tidy' - - +# Always load these types. +require 'puppet/type/component' diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 0ec54d907..3518e8bb3 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -5,10 +5,12 @@ require 'uri' require 'fileutils' require 'puppet/network/handler' require 'puppet/util/diff' +require 'puppet/util/checksums' module Puppet newtype(:file) do include Puppet::Util::MethodHelper + include Puppet::Util::Checksums @doc = "Manages local files, including setting ownership and permissions, creation of both files and directories, and retrieving entire files from remote servers. As Puppet matures, it @@ -173,11 +175,9 @@ module Puppet recursion), and ``follow`` will manage the file to which the link points." - newvalues(:follow, :manage, :ignore) + newvalues(:follow, :manage) - # :ignore and :manage behave equivalently on local files, - # but don't copy remote links - defaultto :ignore + defaultto :manage end newparam(:purge, :boolean => true) do @@ -779,9 +779,7 @@ module Puppet def remove_existing(should) return unless s = stat(true) - unless handlebackup - self.fail "Could not back up; will not replace" - end + self.fail "Could not back up; will not replace" unless handlebackup unless should.to_s == "link" return if s.ftype.to_s == should.to_s @@ -790,8 +788,7 @@ module Puppet case s.ftype when "directory": if self[:force] == :true - debug "Removing existing directory for replacement with %s" % - should + debug "Removing existing directory for replacement with %s" % should FileUtils.rmtree(self[:path]) else notice "Not removing directory; use 'force' to override" @@ -1031,54 +1028,38 @@ module Puppet return [sourceobj, path.sub(/\/\//, '/')] end - # Write out the file. We open the file correctly, with all of the - # uid and mode and such, and then yield the file handle for actual - # writing. - def write(property, usetmp = true) - mode = self.should(:mode) + # Write out the file. Requires the content to be written, + # the property name for logging, and the checksum for validation. + def write(content, property, checksum = nil) + if validate = validate_checksum? + # Use the appropriate checksum type -- md5, md5lite, etc. + sumtype = property(:checksum).checktype + checksum ||= "{#{sumtype}}" + property(:checksum).send(sumtype, content) + end remove_existing(:file) - # The temporary file - path = nil - if usetmp - path = self[:path] + ".puppettmp" - else - path = self[:path] - end - - # As the correct user and group - write_if_writable(File.dirname(path)) do - f = nil - # Open our file with the correct modes - if mode - Puppet::Util.withumask(000) do - f = File.open(path, - File::CREAT|File::WRONLY|File::TRUNC, mode) - end - else - f = File.open(path, File::CREAT|File::WRONLY|File::TRUNC) - end + use_temporary_file = (content.length != 0) + path = self[:path] + path += ".puppettmp" if use_temporary_file - # Yield it - yield f + mode = self.should(:mode) # might be nil + umask = mode ? 000 : 022 - f.flush - f.close + Puppet::Util.withumask(umask) do + File.open(path, File::CREAT|File::WRONLY|File::TRUNC, mode) { |f| f.print content } end # And put our new file in place - if usetmp + if use_temporary_file # This is only not true when our file is empty. begin + fail_if_checksum_is_wrong(path, checksum) if validate File.rename(path, self[:path]) rescue => detail - self.err "Could not rename tmp %s for replacing: %s" % - [self[:path], detail] + self.err "Could not rename tmp %s for replacing: %s" % [self[:path], detail] ensure # Make sure the created file gets removed - if FileTest.exists?(path) - File.unlink(path) - end + File.unlink(path) if FileTest.exists?(path) end end @@ -1086,32 +1067,35 @@ module Puppet property_fix # And then update our checksum, so the next run doesn't find it. - # FIXME This is extra work, because it's going to read the whole - # file back in again. - self.setchecksum - + self.setchecksum(checksum) end - - # Run the block as the specified user if the dir is writeable, else - # run it as root (or the current user). - def write_if_writable(dir) - yield - # We're getting different behaviors from different versions of ruby, so... - # asroot = true - # Puppet::Util::SUIDManager.asuser(asuser(), self.should(:group)) do - # if FileTest.writable?(dir) - # asroot = false - # yield - # end - # end - # - # if asroot - # yield - # end + + # Should we validate the checksum of the file we're writing? + def validate_checksum? + if sumparam = @parameters[:checksum] + return sumparam.checktype.to_s !~ /time/ + else + return false + end end private + # Make sure the file we wrote out is what we think it is. + def fail_if_checksum_is_wrong(path, checksum) + if checksum =~ /^\{(\w+)\}.+/ + sumtype = $1 + else + # This shouldn't happen, but if it happens to, it's nicer + # to just use a default sumtype than fail. + sumtype = "md5" + end + newsum = property(:checksum).getsum(sumtype, path) + return if newsum == checksum + + self.fail "File written to disk did not match checksum; discarding changes (%s vs %s)" % [checksum, newsum] + end + # Override the parent method, because we don't want to generate changes # when the file is missing and there is no 'ensure' state. def propertychanges(currentvalues) diff --git a/lib/puppet/type/file/checksum.rb b/lib/puppet/type/file/checksum.rb index 08f48ea21..debb5a7db 100755 --- a/lib/puppet/type/file/checksum.rb +++ b/lib/puppet/type/file/checksum.rb @@ -1,326 +1,271 @@ -# Keep a copy of the file checksums, and notify when they change. +require 'puppet/util/checksums' -# This state never actually modifies the system, it only notices when the system +# Keep a copy of the file checksums, and notify when they change. This +# property never actually modifies the system, it only notices when the system # changes on its own. -module Puppet - Puppet.type(:file).newproperty(:checksum) do - desc "How to check whether a file has changed. This state is used internally - for file copying, but it can also be used to monitor files somewhat - like Tripwire without managing the file contents in any way. You can - specify that a file's checksum should be monitored and then subscribe to - the file from another object and receive events to signify - checksum changes, for instance." +Puppet::Type.type(:file).newproperty(:checksum) do + include Puppet::Util::Checksums - @event = :file_changed + desc "How to check whether a file has changed. This state is used internally + for file copying, but it can also be used to monitor files somewhat + like Tripwire without managing the file contents in any way. You can + specify that a file's checksum should be monitored and then subscribe to + the file from another object and receive events to signify + checksum changes, for instance." - @unmanaged = true + @event = :file_changed - @validtypes = %w{md5 md5lite timestamp mtime time} + @unmanaged = true - def self.validtype?(type) - @validtypes.include?(type) - end + @validtypes = %w{md5 md5lite timestamp mtime time} - @validtypes.each do |ctype| - newvalue(ctype) do - handlesum() - end - end - - str = @validtypes.join("|") + def self.validtype?(type) + @validtypes.include?(type) + end - # This is here because Puppet sets this internally, using - # {md5}...... - newvalue(/^\{#{str}\}/) do + @validtypes.each do |ctype| + newvalue(ctype) do handlesum() end + end - newvalue(:nosum) do - # nothing - :nochange - end + str = @validtypes.join("|") - # If they pass us a sum type, behave normally, but if they pass - # us a sum type + sum, stick the sum in the cache. - munge do |value| - if value =~ /^\{(\w+)\}(.+)$/ - type = symbolize($1) - sum = $2 - cache(type, sum) - return type - else - if FileTest.directory?(@resource[:path]) - return :time - else - return symbolize(value) - end - end - end + # This is here because Puppet sets this internally, using + # {md5}...... + newvalue(/^\{#{str}\}/) do + handlesum() + end - # Store the checksum in the data cache, or retrieve it if only the - # sum type is provided. - def cache(type, sum = nil) - unless type - raise ArgumentError, "A type must be specified to cache a checksum" - end - type = symbolize(type) - unless state = @resource.cached(:checksums) - self.debug "Initializing checksum hash" - state = {} - @resource.cache(:checksums, state) - end + newvalue(:nosum) do + # nothing + :nochange + end - if sum - unless sum =~ /\{\w+\}/ - sum = "{%s}%s" % [type, sum] - end - state[type] = sum + # If they pass us a sum type, behave normally, but if they pass + # us a sum type + sum, stick the sum in the cache. + munge do |value| + if value =~ /^\{(\w+)\}(.+)$/ + type = symbolize($1) + sum = $2 + cache(type, sum) + return type + else + if FileTest.directory?(@resource[:path]) + return :time else - return state[type] + return symbolize(value) end end + end - # Because source and content and whomever else need to set the checksum - # and do the updating, we provide a simple mechanism for doing so. - def checksum=(value) - munge(@should) - self.updatesum(value) + # Store the checksum in the data cache, or retrieve it if only the + # sum type is provided. + def cache(type, sum = nil) + unless type + raise ArgumentError, "A type must be specified to cache a checksum" + end + type = symbolize(type) + unless state = @resource.cached(:checksums) + self.debug "Initializing checksum hash" + state = {} + @resource.cache(:checksums, state) end - def checktype - self.should || :md5 + if sum + unless sum =~ /\{\w+\}/ + sum = "{%s}%s" % [type, sum] + end + state[type] = sum + else + return state[type] end + end - # Checksums need to invert how changes are printed. - def change_to_s(currentvalue, newvalue) - begin - if currentvalue == :absent - return "defined '%s' as '%s'" % - [self.name, self.currentsum] - elsif newvalue == :absent - return "undefined %s from '%s'" % - [self.name, self.is_to_s(currentvalue)] + # Because source and content and whomever else need to set the checksum + # and do the updating, we provide a simple mechanism for doing so. + def checksum=(value) + munge(@should) + self.updatesum(value) + end + + def checktype + self.should || :md5 + end + + # Checksums need to invert how changes are printed. + def change_to_s(currentvalue, newvalue) + begin + if currentvalue == :absent + return "defined '%s' as '%s'" % + [self.name, self.currentsum] + elsif newvalue == :absent + return "undefined %s from '%s'" % + [self.name, self.is_to_s(currentvalue)] + else + if defined? @cached and @cached + return "%s changed '%s' to '%s'" % + [self.name, @cached, self.is_to_s(currentvalue)] else - if defined? @cached and @cached - return "%s changed '%s' to '%s'" % - [self.name, @cached, self.is_to_s(currentvalue)] - else - return "%s changed '%s' to '%s'" % - [self.name, self.currentsum, self.is_to_s(currentvalue)] - end + return "%s changed '%s' to '%s'" % + [self.name, self.currentsum, self.is_to_s(currentvalue)] end - rescue Puppet::Error, Puppet::DevError - raise - rescue => detail - raise Puppet::DevError, "Could not convert change %s to string: %s" % - [self.name, detail] end + rescue Puppet::Error, Puppet::DevError + raise + rescue => detail + raise Puppet::DevError, "Could not convert change %s to string: %s" % + [self.name, detail] end + end - def currentsum - #"{%s}%s" % [self.should, cache(self.should)] - cache(checktype()) - end + def currentsum + cache(checktype()) + end - # Retrieve the cached sum - def getcachedsum - hash = nil - unless hash = @resource.cached(:checksums) - hash = {} - @resource.cache(:checksums, hash) - end + # Retrieve the cached sum + def getcachedsum + hash = nil + unless hash = @resource.cached(:checksums) + hash = {} + @resource.cache(:checksums, hash) + end - sumtype = self.should + sumtype = self.should - if hash.include?(sumtype) - #self.notice "Found checksum %s for %s" % - # [hash[sumtype] ,@resource[:path]] - sum = hash[sumtype] + if hash.include?(sumtype) + #self.notice "Found checksum %s for %s" % + # [hash[sumtype] ,@resource[:path]] + sum = hash[sumtype] - unless sum =~ /^\{\w+\}/ - sum = "{%s}%s" % [sumtype, sum] - end - return sum - elsif hash.empty? - #self.notice "Could not find sum of type %s" % sumtype - return :nosum - else - #self.notice "Found checksum for %s but not of type %s" % - # [@resource[:path],sumtype] - return :nosum + unless sum =~ /^\{\w+\}/ + sum = "{%s}%s" % [sumtype, sum] end + return sum + elsif hash.empty? + #self.notice "Could not find sum of type %s" % sumtype + return :nosum + else + #self.notice "Found checksum for %s but not of type %s" % + # [@resource[:path],sumtype] + return :nosum end + end - # Calculate the sum from disk. - def getsum(checktype) - sum = "" - - checktype = checktype.intern if checktype.is_a? String - case checktype - when :md5, :md5lite: - if ! FileTest.file?(@resource[:path]) - @resource.debug "Cannot MD5 sum %s; using mtime" % - [@resource.stat.ftype] - sum = @resource.stat.mtime.to_s - else - begin - File.open(@resource[:path]) { |file| - hashfunc = Digest::MD5.new - while (!file.eof) - readBuf = file.read(512) - hashfunc.update(readBuf) - if checktype == :md5lite then - break - end - end - sum = hashfunc.hexdigest - } - rescue Errno::EACCES => detail - self.notice "Cannot checksum %s: permission denied" % - @resource[:path] - @resource.delete(self.class.name) - rescue => detail - self.notice "Cannot checksum: %s" % - detail - @resource.delete(self.class.name) - end - end - when :timestamp, :mtime: - sum = @resource.stat.mtime.to_s - #sum = File.stat(@resource[:path]).mtime.to_s - when :time: - sum = @resource.stat.ctime.to_s - #sum = File.stat(@resource[:path]).ctime.to_s - else - raise Puppet::Error, "Invalid sum type %s" % checktype - end + # Calculate the sum from disk. + def getsum(checktype, file = nil) + sum = "" + + checktype = :mtime if checktype == :timestamp + checktype = :ctime if checktype == :time + + file ||= @resource[:path] + + return nil unless FileTest.exist?(file) - return "{#{checktype}}" + sum.to_s + if ! FileTest.file?(file) + checktype = :mtime end + method = checktype.to_s + "_file" - # At this point, we don't actually modify the system, we modify - # the stored state to reflect the current state, and then kick - # off an event to mark any changes. - def handlesum - currentvalue = self.retrieve - if currentvalue.nil? - raise Puppet::Error, "Checksum state for %s is somehow nil" % - @resource.title - end + self.fail("Invalid checksum type %s" % checktype) unless respond_to?(method) - if self.insync?(currentvalue) - self.debug "Checksum is already in sync" - return nil - end - # @resource.debug "%s(%s): after refresh, is '%s'" % - # [self.class.name,@resource.name,@is] + return "{%s}%s" % [checktype, send(method, file)] + end - # If we still can't retrieve a checksum, it means that - # the file still doesn't exist - if currentvalue == :absent - # if they're copying, then we won't worry about the file - # not existing yet - unless @resource.property(:source) - self.warning("File %s does not exist -- cannot checksum" % - @resource[:path] - ) - end - return nil - end - - # If the sums are different, then return an event. - if self.updatesum(currentvalue) - return :file_changed - else - return nil - end + # At this point, we don't actually modify the system, we modify + # the stored state to reflect the current state, and then kick + # off an event to mark any changes. + def handlesum + currentvalue = self.retrieve + if currentvalue.nil? + raise Puppet::Error, "Checksum state for %s is somehow nil" % + @resource.title end - def insync?(currentvalue) - @should = [checktype()] - if cache(checktype()) - return currentvalue == currentsum() - else - # If there's no cached sum, then we don't want to generate - # an event. - return true + if self.insync?(currentvalue) + self.debug "Checksum is already in sync" + return nil + end + # If we still can't retrieve a checksum, it means that + # the file still doesn't exist + if currentvalue == :absent + # if they're copying, then we won't worry about the file + # not existing yet + unless @resource.property(:source) + self.warning("File %s does not exist -- cannot checksum" % @resource[:path]) end + return nil end - # Even though they can specify multiple checksums, the insync? - # mechanism can really only test against one, so we'll just retrieve - # the first specified sum type. - def retrieve(usecache = false) - # When the 'source' is retrieving, it passes "true" here so - # that we aren't reading the file twice in quick succession, yo. - currentvalue = currentsum() - if usecache and currentvalue - return currentvalue - end - - stat = nil - unless stat = @resource.stat - return :absent - end - - if stat.ftype == "link" and @resource[:links] != :follow - self.debug "Not checksumming symlink" - # @resource.delete(:checksum) - return currentvalue - end - - # Just use the first allowed check type - currentvalue = getsum(checktype()) + # If the sums are different, then return an event. + if self.updatesum(currentvalue) + return :file_changed + else + return nil + end + end - # If there is no sum defined, then store the current value - # into the cache, so that we're not marked as being - # out of sync. We don't want to generate an event the first - # time we get a sum. - unless cache(checktype()) - # FIXME we should support an updatechecksums-like mechanism - self.updatesum(currentvalue) - end - - # @resource.debug "checksum state is %s" % self.is + def insync?(currentvalue) + @should = [checktype()] + if cache(checktype()) + return currentvalue == currentsum() + else + # If there's no cached sum, then we don't want to generate + # an event. + return true + end + end + + # Even though they can specify multiple checksums, the insync? + # mechanism can really only test against one, so we'll just retrieve + # the first specified sum type. + def retrieve(usecache = false) + # When the 'source' is retrieving, it passes "true" here so + # that we aren't reading the file twice in quick succession, yo. + currentvalue = currentsum() + return currentvalue if usecache and currentvalue + + stat = nil + return :absent unless stat = @resource.stat + + if stat.ftype == "link" and @resource[:links] != :follow + self.debug "Not checksumming symlink" + # @resource.delete(:checksum) return currentvalue end - # Store the new sum to the state db. - def updatesum(newvalue) - result = false + # Just use the first allowed check type + currentvalue = getsum(checktype()) - if newvalue.is_a?(Symbol) - raise Puppet::Error, "%s has invalid checksum" % @resource.title - end + # If there is no sum defined, then store the current value + # into the cache, so that we're not marked as being + # out of sync. We don't want to generate an event the first + # time we get a sum. + self.updatesum(currentvalue) unless cache(checktype()) + + # @resource.debug "checksum state is %s" % self.is + return currentvalue + end - # if we're replacing, vs. updating - if sum = cache(checktype()) - # unless defined? @should - # raise Puppet::Error.new( - # ("@should is not initialized for %s, even though we " + - # "found a checksum") % @resource[:path] - # ) - # end - - if newvalue == sum - return false - end + # Store the new sum to the state db. + def updatesum(newvalue) + result = false - self.debug "Replacing %s checksum %s with %s" % - [@resource.title, sum, newvalue] - # @resource.debug "currentvalue: %s; @should: %s" % - # [newvalue,@should] - result = true - else - @resource.debug "Creating checksum %s" % newvalue - result = false - end + # if we're replacing, vs. updating + if sum = cache(checktype()) + return false if newvalue == sum - # Cache the sum so the log message can be right if possible. - @cached = sum - cache(checktype(), newvalue) - return result + self.debug "Replacing %s checksum %s with %s" % [@resource.title, sum, newvalue] + result = true + else + @resource.debug "Creating checksum %s" % newvalue + result = false end + + # Cache the sum so the log message can be right if possible. + @cached = sum + cache(checktype(), newvalue) + return result end end - diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb index 6dcda0aa6..1eb1423aa 100755 --- a/lib/puppet/type/file/content.rb +++ b/lib/puppet/type/file/content.rb @@ -1,5 +1,5 @@ module Puppet - Puppet.type(:file).newproperty(:content) do + Puppet::Type.type(:file).newproperty(:content) do include Puppet::Util::Diff desc "Specify the contents of a file as a string. Newlines, tabs, and @@ -47,23 +47,13 @@ module Puppet return result end - # We should probably take advantage of existing md5 sums if they're there, - # but I really don't feel like dealing with the complexity right now. def retrieve - stat = nil - unless stat = @resource.stat - return :absent - end + return :absent unless stat = @resource.stat - if stat.ftype == "link" and @resource[:links] == :ignore - return self.should - end + return self.should if stat.ftype == "link" and @resource[:links] == :ignore # Don't even try to manage the content on directories - if stat.ftype == "directory" and @resource[:links] == :ignore - @resource.delete(:content) - return nil - end + return nil if stat.ftype == "directory" begin currentvalue = File.read(@resource[:path]) @@ -74,12 +64,17 @@ module Puppet end end + # Make sure we're also managing the checksum property. + def should=(value) + super + @resource.newattr(:checksum) unless @resource.property(:checksum) + end # Just write our content out to disk. def sync return_event = @resource.stat ? :file_changed : :file_created - @resource.write(:content) { |f| f.print self.should } + @resource.write(self.should, :content) return return_event end diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb index 3aa918f65..0d2171216 100755 --- a/lib/puppet/type/file/ensure.rb +++ b/lib/puppet/type/file/ensure.rb @@ -46,7 +46,7 @@ module Puppet if property = (@resource.property(:content) || @resource.property(:source)) property.sync else - @resource.write(false) { |f| f.flush } + @resource.write("", :ensure) mode = @resource.should(:mode) end return :file_created @@ -67,14 +67,12 @@ module Puppet "Cannot create %s; parent directory %s does not exist" % [@resource[:path], parent] end - @resource.write_if_writable(parent) do - if mode - Puppet::Util.withumask(000) do - Dir.mkdir(@resource[:path],mode) - end - else - Dir.mkdir(@resource[:path]) + if mode + Puppet::Util.withumask(000) do + Dir.mkdir(@resource[:path],mode) end + else + Dir.mkdir(@resource[:path]) end @resource.send(:property_fix) @resource.setchecksum @@ -101,9 +99,13 @@ module Puppet munge do |value| value = super(value) + # It doesn't make sense to try to manage links unless, well, + # we're managing links. + resource[:links] = :manage if value == :link return value if value.is_a? Symbol @resource[:target] = value + resource[:links] = :manage return :link end diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index a3e533c31..1b0dd3141 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -105,10 +105,13 @@ module Puppet return nil end + return nil if desc == "" + + # Collect everything except the checksum + values = desc.split("\t") + other = values.pop args = {} - pinparams.zip( - desc.split("\t") - ).each { |param, value| + pinparams.zip(values).each { |param, value| if value =~ /^[0-9]+$/ value = value.to_i end @@ -117,16 +120,19 @@ module Puppet end } - # we can't manage ownership as root, so don't even try - unless Puppet::Util::SUIDManager.uid == 0 - args.delete(:owner) + # Now decide whether we're doing checksums or symlinks + if args[:type] == "link" + args[:target] = other + else + args[:checksum] = other end - if args.empty? or (args[:type] == "link" and @resource[:links] == :ignore) - return nil - else - return args + # we can't manage ownership unless we're root, so don't even try + unless Puppet::Util::SUIDManager.uid == 0 + args.delete(:owner) end + + return args end # Have we successfully described the remote source? @@ -172,7 +178,7 @@ module Puppet end def pinparams - Puppet::Network::Handler.handler(:fileserver).params + [:mode, :type, :owner, :group] end # This basically calls describe() on our file, and then sets all @@ -201,7 +207,7 @@ module Puppet end case @stats[:type] - when "directory", "file": + when "directory", "file", "link": @resource[:ensure] = @stats[:type] unless @resource.deleting? else self.info @stats.inspect @@ -235,9 +241,7 @@ module Puppet checks.delete(:checksum) @resource[:check] = checks - unless @resource.property(:checksum) - @resource[:checksum] = :md5 - end + @resource[:checksum] = :md5 unless @resource.property(:checksum) end def sync @@ -245,7 +249,7 @@ module Puppet exists = File.exists?(@resource[:path]) - @resource.write(:source) { |f| f.print contents } + @resource.write(contents, :source, @stats[:checksum]) if exists return :file_changed diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb index 24b187e5f..ee2871ce2 100644 --- a/lib/puppet/type/package.rb +++ b/lib/puppet/type/package.rb @@ -200,7 +200,7 @@ module Puppet package { $ssh: ensure => installed, alias => openssh, - require => package[openssl] + require => Package[openssl] } " diff --git a/lib/puppet/util/checksums.rb b/lib/puppet/util/checksums.rb index 598b3adfa..15d2eadd1 100644 --- a/lib/puppet/util/checksums.rb +++ b/lib/puppet/util/checksums.rb @@ -55,7 +55,7 @@ module Puppet::Util::Checksums end # Return the :ctime of a file. - def timestamp_file(filename) + def ctime_file(filename) File.stat(filename).send(:ctime) end diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb index 1c7734cc4..bbc837e75 100755 --- a/lib/puppet/util/filetype.rb +++ b/lib/puppet/util/filetype.rb @@ -165,7 +165,7 @@ class Puppet::Util::FileType # Remove a specific @path's cron tab. def remove - if Facter.value("operatingsystem") == "FreeBSD" + if %w{Darwin FreeBSD}.include?(Facter.value("operatingsystem")) %x{/bin/echo yes | #{cmdbase()} -r 2>/dev/null} else %x{#{cmdbase()} -r 2>/dev/null} diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index 2c8fc682a..5f4a98558 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -1070,7 +1070,7 @@ Generated on #{Time.now}. return nil unless path.is_a?(String) return nil if path =~ /^\/dev/ - return nil if Puppet::Type::File[path] # skip files that are in our global resource list. + return nil if Puppet::Type.type(:file)[path] # skip files that are in our global resource list. objects = [] diff --git a/lib/puppet/util/tagging.rb b/lib/puppet/util/tagging.rb index 9abb3fb2b..8a50f3458 100644 --- a/lib/puppet/util/tagging.rb +++ b/lib/puppet/util/tagging.rb @@ -34,6 +34,6 @@ module Puppet::Util::Tagging private def valid_tag?(tag) - tag =~ /^\w[-\w:]*$/ + tag =~ /^\w[-\w:.]*$/ end end diff --git a/spec/integration/file_serving/configuration.rb b/spec/integration/file_serving/configuration.rb index b6505f096..6975594a8 100755 --- a/spec/integration/file_serving/configuration.rb +++ b/spec/integration/file_serving/configuration.rb @@ -12,8 +12,6 @@ describe Puppet::FileServing::Configuration, " when finding files with Puppet::F # Just in case it already exists. Puppet::FileServing::Configuration.clear_cache - @config = Puppet::FileServing::Configuration.create - @mount = Puppet::FileServing::Mount.new("mymount") FileTest.stubs(:exists?).with("/my/path").returns(true) FileTest.stubs(:readable?).with("/my/path").returns(true) @@ -25,6 +23,8 @@ describe Puppet::FileServing::Configuration, " when finding files with Puppet::F @parser.stubs(:parse).returns("mymount" => @mount) @parser.stubs(:changed?).returns(true) Puppet::FileServing::Configuration::Parser.stubs(:new).returns(@parser) + + @config = Puppet::FileServing::Configuration.create end it "should return nil if the file does not exist" do diff --git a/spec/unit/file_serving/file_base.rb b/spec/unit/file_serving/file_base.rb index 4c7724f7c..e1a61cd65 100755 --- a/spec/unit/file_serving/file_base.rb +++ b/spec/unit/file_serving/file_base.rb @@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/file_serving/file_base' -describe Puppet::FileServing::FileBase, " when initializing" do +describe Puppet::FileServing::FileBase do it "should accept a key in the form of a URI" do Puppet::FileServing::FileBase.new("puppet://host/module/dir/file").key.should == "puppet://host/module/dir/file" end @@ -30,72 +30,91 @@ describe Puppet::FileServing::FileBase, " when initializing" do FileTest.stubs(:exists?).returns(true) Puppet::FileServing::FileBase.new("puppet://host/module/dir/file", :relative_path => "my/file").relative_path.should == "my/file" end -end -describe Puppet::FileServing::FileBase, " when setting the base path" do - before do - @file = Puppet::FileServing::FileBase.new("puppet://host/module/dir/file") + it "should have a means of determining if the file exists" do + Puppet::FileServing::FileBase.new("blah").should respond_to(:exist?) end - it "should require that the base path be fully qualified" do - FileTest.stubs(:exists?).returns(true) - proc { @file.path = "unqualified/file" }.should raise_error(ArgumentError) + it "should correctly indicate if the file is present" do + File.expects(:lstat).with("/my/file").returns(mock("stat")) + Puppet::FileServing::FileBase.new("blah", :path => "/my/file").exist?.should be_true end -end -describe Puppet::FileServing::FileBase, " when setting the relative path" do - it "should require that the relative path be unqualified" do - @file = Puppet::FileServing::FileBase.new("puppet://host/module/dir/file") - FileTest.stubs(:exists?).returns(true) - proc { @file.relative_path = "/qualified/file" }.should raise_error(ArgumentError) + it "should correctly indicate if the file is asbsent" do + File.expects(:lstat).with("/my/file").raises RuntimeError + Puppet::FileServing::FileBase.new("blah", :path => "/my/file").exist?.should be_false end -end -describe Puppet::FileServing::FileBase, " when determining the full file path" do - before do - @file = Puppet::FileServing::FileBase.new("mykey", :path => "/this/file") - end + describe "when setting the base path" do + before do + @file = Puppet::FileServing::FileBase.new("puppet://host/module/dir/file") + end - it "should return the path if there is no relative path" do - @file.full_path.should == "/this/file" + it "should require that the base path be fully qualified" do + FileTest.stubs(:exists?).returns(true) + proc { @file.path = "unqualified/file" }.should raise_error(ArgumentError) + end end - it "should return the path joined with the relative path if there is a relative path" do - @file.relative_path = "not/qualified" - @file.full_path.should == "/this/file/not/qualified" + describe "when setting the relative path" do + it "should require that the relative path be unqualified" do + @file = Puppet::FileServing::FileBase.new("puppet://host/module/dir/file") + FileTest.stubs(:exists?).returns(true) + proc { @file.relative_path = "/qualified/file" }.should raise_error(ArgumentError) + end end - it "should should fail if there is no path set" do - @file = Puppet::FileServing::FileBase.new("not/qualified") - proc { @file.full_path }.should raise_error(ArgumentError) - end -end + describe "when determining the full file path" do + before do + @file = Puppet::FileServing::FileBase.new("mykey", :path => "/this/file") + end -describe Puppet::FileServing::FileBase, " when stat'ing files" do - before do - @file = Puppet::FileServing::FileBase.new("mykey", :path => "/this/file") - end + it "should return the path if there is no relative path" do + @file.full_path.should == "/this/file" + end - it "should stat the file's full path" do - @file.stubs(:full_path).returns("/this/file") - File.expects(:lstat).with("/this/file").returns stub("stat", :ftype => "file") - @file.stat - end + it "should return the path if the relative_path is set to ''" do + @file.relative_path = "" + @file.full_path.should == "/this/file" + end - it "should fail if the file does not exist" do - @file.stubs(:full_path).returns("/this/file") - File.expects(:lstat).with("/this/file").raises(Errno::ENOENT) - proc { @file.stat }.should raise_error(Errno::ENOENT) - end + it "should return the path joined with the relative path if there is a relative path and it is not set to '/' or ''" do + @file.relative_path = "not/qualified" + @file.full_path.should == "/this/file/not/qualified" + end - it "should use :lstat if :links is set to :manage" do - File.expects(:lstat).with("/this/file").returns stub("stat", :ftype => "file") - @file.stat + it "should should fail if there is no path set" do + @file = Puppet::FileServing::FileBase.new("not/qualified") + proc { @file.full_path }.should raise_error(ArgumentError) + end end - it "should use :stat if :links is set to :follow" do - File.expects(:stat).with("/this/file").returns stub("stat", :ftype => "file") - @file.links = :follow - @file.stat + describe "when stat'ing files" do + before do + @file = Puppet::FileServing::FileBase.new("mykey", :path => "/this/file") + end + + it "should stat the file's full path" do + @file.stubs(:full_path).returns("/this/file") + File.expects(:lstat).with("/this/file").returns stub("stat", :ftype => "file") + @file.stat + end + + it "should fail if the file does not exist" do + @file.stubs(:full_path).returns("/this/file") + File.expects(:lstat).with("/this/file").raises(Errno::ENOENT) + proc { @file.stat }.should raise_error(Errno::ENOENT) + end + + it "should use :lstat if :links is set to :manage" do + File.expects(:lstat).with("/this/file").returns stub("stat", :ftype => "file") + @file.stat + end + + it "should use :stat if :links is set to :follow" do + File.expects(:stat).with("/this/file").returns stub("stat", :ftype => "file") + @file.links = :follow + @file.stat + end end end diff --git a/spec/unit/file_serving/metadata.rb b/spec/unit/file_serving/metadata.rb index d31dd21f0..9743370c1 100755 --- a/spec/unit/file_serving/metadata.rb +++ b/spec/unit/file_serving/metadata.rb @@ -26,8 +26,8 @@ describe Puppet::FileServing::Metadata, " when finding the file to use for setti @metadata.path = @full - # Use a symlink because it's easier to test -- no checksumming - @stat = stub "stat", :uid => 10, :gid => 20, :mode => 0755, :ftype => "symlink" + # Use a link because it's easier to test -- no checksumming + @stat = stub "stat", :uid => 10, :gid => 20, :mode => 0755, :ftype => "link" end it "should accept a base path path to which the file should be relative" do @@ -55,17 +55,19 @@ end describe Puppet::FileServing::Metadata, " when collecting attributes" do before do @path = "/my/file" - @stat = stub 'stat', :uid => 10, :gid => 20, :mode => 0755, :ftype => "file" + # Use a real file mode, so we can validate the masking is done. + @stat = stub 'stat', :uid => 10, :gid => 20, :mode => 33261, :ftype => "file" File.stubs(:lstat).returns(@stat) - @filehandle = mock 'filehandle' - #@filehandle.expects(:read).with(512).returns("some content\n").then.returns(nil) - File.stubs(:open).with(@path, 'r').yields(@filehandle) @checksum = Digest::MD5.hexdigest("some content\n") @metadata = Puppet::FileServing::Metadata.new("file", :path => "/my/file") - @metadata.expects(:md5_file).returns(@checksum) + @metadata.stubs(:md5_file).returns(@checksum) @metadata.collect_attributes end + it "should be able to produce xmlrpc-style attribute information" do + @metadata.should respond_to(:attributes_with_tabs) + end + # LAK:FIXME This should actually change at some point it "should set the owner by id" do @metadata.owner.should be_instance_of(Fixnum) @@ -84,28 +86,63 @@ describe Puppet::FileServing::Metadata, " when collecting attributes" do @metadata.group.should == 20 end - it "should set the mode to a string version of the mode in octal" do - @metadata.mode.should == "755" - end - - it "should set the mode to the file's current mode" do - @metadata.mode.should == "755" + it "should set the mode to the file's masked mode" do + @metadata.mode.should == 0755 end it "should set the checksum to the file's current checksum" do @metadata.checksum.should == "{md5}" + @checksum end - it "should default to a checksum of type MD5" do - @metadata.checksum.should == "{md5}" + @checksum + describe "when managing files" do + it "should default to a checksum of type MD5" do + @metadata.checksum.should == "{md5}" + @checksum + end + + it "should produce tab-separated mode, type, owner, group, and checksum for xmlrpc" do + @metadata.attributes_with_tabs.should == "#{0755.to_s}\tfile\t10\t20\t{md5}#{@checksum}" + end + end + + describe "when managing directories" do + before do + @stat.stubs(:ftype).returns("directory") + @time = Time.now + @metadata.expects(:ctime_file).returns(@time) + @metadata.collect_attributes + end + + it "should only use checksums of type 'ctime' for directories" do + @metadata.checksum.should == "{ctime}" + @time.to_s + end + + it "should produce tab-separated mode, type, owner, group, and checksum for xmlrpc" do + @metadata.attributes_with_tabs.should == "#{0755.to_s}\tdirectory\t10\t20\t{ctime}#{@time.to_s}" + end + end + + describe "when managing links" do + before do + @stat.stubs(:ftype).returns("link") + File.expects(:readlink).with("/my/file").returns("/path/to/link") + @metadata.collect_attributes + end + + it "should read links instead of returning their checksums" do + @metadata.destination.should == "/path/to/link" + end + + it "should produce tab-separated mode, type, owner, group, and destination for xmlrpc" do + @metadata.attributes_with_tabs.should == "#{0755.to_s}\tlink\t10\t20\t/path/to/link" + end end end -describe Puppet::FileServing::Metadata, " when pointing to a symlink" do - it "should store the destination of the symlink in :destination if links are :manage" do +describe Puppet::FileServing::Metadata, " when pointing to a link" do + it "should store the destination of the link in :destination if links are :manage" do file = Puppet::FileServing::Metadata.new("mykey", :links => :manage, :path => "/base/path/my/file") - File.expects(:lstat).with("/base/path/my/file").returns stub("stat", :uid => 1, :gid => 2, :ftype => "symlink", :mode => 0755) + File.expects(:lstat).with("/base/path/my/file").returns stub("stat", :uid => 1, :gid => 2, :ftype => "link", :mode => 0755) File.expects(:readlink).with("/base/path/my/file").returns "/some/other/path" file.collect_attributes @@ -115,7 +152,7 @@ describe Puppet::FileServing::Metadata, " when pointing to a symlink" do it "should not collect the checksum" do file = Puppet::FileServing::Metadata.new("my/file", :links => :manage, :path => "/base/path/my/file") - File.expects(:lstat).with("/base/path/my/file").returns stub("stat", :uid => 1, :gid => 2, :ftype => "symlink", :mode => 0755) + File.expects(:lstat).with("/base/path/my/file").returns stub("stat", :uid => 1, :gid => 2, :ftype => "link", :mode => 0755) File.expects(:readlink).with("/base/path/my/file").returns "/some/other/path" file.collect_attributes diff --git a/spec/unit/network/http_pool.rb b/spec/unit/network/http_pool.rb index 49da7d8f3..503440274 100755 --- a/spec/unit/network/http_pool.rb +++ b/spec/unit/network/http_pool.rb @@ -19,6 +19,7 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt it "should add a certificate store" do Puppet::Network::HttpPool.stubs(:read_cert).returns(true) + Puppet::Network::HttpPool.stubs(:key).returns(:mykey) store = stub "store" OpenSSL::X509::Store.expects(:new).returns(store) store.stubs(:add_file) @@ -47,6 +48,7 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt it "should set the purpose of the cert store to OpenSSL::X509::PURPOSE_SSL_CLIENT" do Puppet::Network::HttpPool.stubs(:read_cert).returns(true) + Puppet::Network::HttpPool.stubs(:key).returns(:mykey) store = stub "store" OpenSSL::X509::Store.expects(:new).returns(store) store.stubs(:add_file) @@ -60,6 +62,7 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt it "should add the client certificate" do Puppet::Network::HttpPool.stubs(:read_cert).returns(true) Puppet::Network::HttpPool.stubs(:cert).returns(:mycert) + Puppet::Network::HttpPool.stubs(:key).returns(:mykey) [:cert_store=, :verify_mode=, :ca_file=, :key=].each { |method| @http.stubs(method) } @http.expects(:cert=).with(:mycert) @@ -79,6 +82,7 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt it "should set the verify mode to OpenSSL::SSL::VERIFY_PEER" do Puppet::Network::HttpPool.stubs(:read_cert).returns(true) + Puppet::Network::HttpPool.stubs(:key).returns(:mykey) [:key=, :cert=, :cert_store=, :ca_file=].each { |method| @http.stubs(method) } @http.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER) diff --git a/spec/unit/node/catalog.rb b/spec/unit/node/catalog.rb index ecbd20487..b1bf5abaa 100755 --- a/spec/unit/node/catalog.rb +++ b/spec/unit/node/catalog.rb @@ -460,6 +460,12 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do proc { @catalog.alias @one, "one" }.should_not raise_error end + it "should be able to look resources up by their aliases" do + @catalog.add_resource @one + @catalog.alias @one, "two" + @catalog.resource(:me, "two").should equal(@one) + end + it "should remove resource aliases when the target resource is removed" do @catalog.add_resource @one @catalog.alias(@one, "other") @@ -468,12 +474,21 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do @catalog.resource("me", "other").should be_nil end - it "should add an alias for the namevar when the title and name differ" do - @one.stubs(:name).returns "other" + it "should add an alias for the namevar when the title and name differ on isomorphic resource types" do resource = Puppet::Type.type(:file).create :path => "/something", :title => "other", :content => "blah" @catalog.add_resource(resource) @catalog.resource(:file, "other").should equal(resource) - @catalog.resource(:file, "/something").should equal(resource) + @catalog.resource(:file, "/something").ref.should == resource.ref + end + + it "should not add an alias for the namevar when the title and name differ on non-isomorphic resource types" do + resource = Puppet::Type.type(:exec).create :command => "/bin/true", :title => "other" + @catalog.add_resource(resource) + @catalog.resource(:exec, resource.title).should equal(resource) + # We can't use .should here, because the resources respond to that method. + if @catalog.resource(:exec, resource.name) + raise "Aliased non-isomorphic resource" + end end after do @@ -601,6 +616,7 @@ end describe Puppet::Node::Catalog, " when creating a relationship graph" do before do + Puppet::Type.type(:component) @catalog = Puppet::Node::Catalog.new("host") @compone = Puppet::Type::Component.create :name => "one" @comptwo = Puppet::Type::Component.create :name => "two", :require => ["class", "one"] diff --git a/spec/unit/other/pgraph.rb b/spec/unit/other/pgraph.rb index 7d66ae331..10ab934a6 100755 --- a/spec/unit/other/pgraph.rb +++ b/spec/unit/other/pgraph.rb @@ -5,6 +5,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/pgraph' require 'puppet/util/graph' class Container diff --git a/spec/unit/other/transaction.rb b/spec/unit/other/transaction.rb index d88f03005..e277a24c0 100755 --- a/spec/unit/other/transaction.rb +++ b/spec/unit/other/transaction.rb @@ -2,6 +2,8 @@ require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/transaction' + describe Puppet::Transaction, " when determining tags" do before do @config = Puppet::Node::Catalog.new diff --git a/spec/unit/parser/interpreter.rb b/spec/unit/parser/interpreter.rb index 7885f0542..eb5dd9aaf 100755 --- a/spec/unit/parser/interpreter.rb +++ b/spec/unit/parser/interpreter.rb @@ -127,6 +127,7 @@ describe Puppet::Parser::Interpreter, " when compiling catalog" do end it "should fail intelligently when no parser can be found" do + @node.stubs(:name).returns("whatever") @interp.expects(:parser).with(:myenv).returns(nil) proc { @interp.compile(@node) }.should raise_error(Puppet::ParseError) end diff --git a/spec/unit/ral/types/file.rb b/spec/unit/ral/types/file.rb index 62fe2f677..b213987bb 100755 --- a/spec/unit/ral/types/file.rb +++ b/spec/unit/ral/types/file.rb @@ -56,6 +56,43 @@ describe Puppet::Type::File do end end + describe "when managing links" do + require 'puppettest/support/assertions' + include PuppetTest + + before do + @basedir = tempfile() + Dir.mkdir(@basedir) + @file = File.join(@basedir, "file") + @link = File.join(@basedir, "link") + + File.open(@file, "w", 0644) { |f| f.puts "yayness"; f.flush } + File.symlink(@file, @link) + + @resource = Puppet.type(:file).create( + :path => @link, + :mode => "755" + ) + end + + after do + teardown + end + + it "should default to managing the link" do + assert_events([], @resource) + # I convert them to strings so they display correctly if there's an error. + ("%o" % (File.stat(@file).mode & 007777)).should == "%o" % 0644 + end + + it "should be able to follow links" do + @resource[:links] = :follow + assert_events([:file_changed], @resource) + + ("%o" % (File.stat(@file).mode & 007777)).should == "%o" % 0755 + end + end + after do Puppet::Type::File.clear end diff --git a/spec/unit/util/checksums.rb b/spec/unit/util/checksums.rb index 31cf24f5b..0e0d06c0d 100755 --- a/spec/unit/util/checksums.rb +++ b/spec/unit/util/checksums.rb @@ -14,7 +14,7 @@ describe Puppet::Util::Checksums do end content_sums = [:md5, :md5lite, :sha1, :sha1lite] - file_only = [:timestamp, :mtime] + file_only = [:ctime, :mtime] content_sums.each do |sumtype| it "should be able to calculate %s sums from strings" % sumtype do @@ -84,11 +84,11 @@ describe Puppet::Util::Checksums do end end - {:timestamp => :ctime, :mtime => :mtime}.each do |sum, method| + [:ctime, :mtime].each do |sum| describe("when using %s" % sum) do - it "should use the '#{method}' on the file to determine the timestamp" do + it "should use the '#{sum}' on the file to determine the ctime" do file = "/my/file" - stat = mock 'stat', method => "mysum" + stat = mock 'stat', sum => "mysum" File.expects(:stat).with(file).returns(stat) diff --git a/spec/unit/util/tagging.rb b/spec/unit/util/tagging.rb index 91cbb213d..d61ee8ccb 100755 --- a/spec/unit/util/tagging.rb +++ b/spec/unit/util/tagging.rb @@ -61,6 +61,10 @@ describe Puppet::Util::Tagging, "when adding tags" do lambda { @tagger.tag("good_tag") }.should_not raise_error(Puppet::ParseError) end + it "should allow tags containing '.' characters" do + lambda { @tagger.tag("good.tag") }.should_not raise_error(Puppet::ParseError) + end + it "should provide a method for testing tag validity" do @tagger.metaclass.publicize_methods(:valid_tag?) { @tagger.should be_respond_to(:valid_tag?) } end diff --git a/test/lib/puppettest.rb b/test/lib/puppettest.rb index 902831e68..e276bdf0f 100755 --- a/test/lib/puppettest.rb +++ b/test/lib/puppettest.rb @@ -36,9 +36,9 @@ class Class def publicize_methods(*methods) saved_private_instance_methods = methods.empty? ? self.private_instance_methods : methods - self.class_eval { public *saved_private_instance_methods } + self.class_eval { public(*saved_private_instance_methods) } yield - self.class_eval { private *saved_private_instance_methods } + self.class_eval { private(*saved_private_instance_methods) } end end @@ -198,7 +198,7 @@ module PuppetTest # If we're running under rake, then disable debugging and such. #if rake? or ! Puppet[:debug] - if defined?($puppet_debug) or ! rake? + #if defined?($puppet_debug) or ! rake? if textmate? Puppet[:color] = false end @@ -210,11 +210,11 @@ module PuppetTest end Puppet::Util::Log.level = :debug #$VERBOSE = 1 - else - Puppet::Util::Log.close - Puppet::Util::Log.newdestination(@logs) - Puppet[:httplog] = tempfile() - end + #else + # Puppet::Util::Log.close + # Puppet::Util::Log.newdestination(@logs) + # Puppet[:httplog] = tempfile() + #end Puppet[:ignoreschedules] = true @@ -267,11 +267,7 @@ module PuppetTest @tmpdir end - def teardown - #@stop = Time.now - #File.open("/tmp/test_times.log", ::File::WRONLY|::File::CREAT|::File::APPEND) { |f| f.puts "%0.4f %s %s" % [@stop - @start, @method_name, self.class] } - @@cleaners.each { |cleaner| cleaner.call() } - + def remove_tmp_files @@tmpfiles.each { |file| unless file =~ /tmp/ puts "Not deleting tmpfile %s" % file @@ -283,6 +279,14 @@ module PuppetTest end } @@tmpfiles.clear + end + + def teardown + #@stop = Time.now + #File.open("/tmp/test_times.log", ::File::WRONLY|::File::CREAT|::File::APPEND) { |f| f.puts "%0.4f %s %s" % [@stop - @start, @method_name, self.class] } + @@cleaners.each { |cleaner| cleaner.call() } + + remove_tmp_files @@tmppids.each { |pid| %x{kill -INT #{pid} 2>/dev/null} diff --git a/test/network/client/master.rb b/test/network/client/master.rb index 696d08bfd..67c47fa6d 100755 --- a/test/network/client/master.rb +++ b/test/network/client/master.rb @@ -211,6 +211,24 @@ end "Lost value to hostname") end + # Make sure that setting environment by fact takes precedence to configuration + def test_setenvironmentwithfact + name = "environment" + value = "test_environment" + + Puppet[:filetimeout] = -1 + Puppet[:factsource] = tempfile() + Dir.mkdir(Puppet[:factsource]) + file = File.join(Puppet[:factsource], "#{name}.rb") + File.open(file, "w") do |f| + f.puts %{Facter.add("#{name}") do setcode { "#{value}" } end } + end + + Puppet::Network::Client.master.getfacts + + assert_equal(value, Puppet::Network::Client.master.facts[name]) + end + # Make sure we load all facts on startup. def test_loadfacts dirs = [tempfile(), tempfile()] diff --git a/test/network/handler/fileserver.rb b/test/network/handler/fileserver.rb index 233e705c6..a705dbf4b 100755 --- a/test/network/handler/fileserver.rb +++ b/test/network/handler/fileserver.rb @@ -109,13 +109,13 @@ class TestFileServer < Test::Unit::TestCase # and verify different iterations of 'root' return the same value list = nil assert_nothing_raised { - list = server.list("/test/", :ignore, true, false) + list = server.list("/test/", :manage, true, false) } assert(list =~ pattern) assert_nothing_raised { - list = server.list("/test", :ignore, true, false) + list = server.list("/test", :manage, true, false) } assert(list =~ pattern) @@ -143,7 +143,7 @@ class TestFileServer < Test::Unit::TestCase list = nil sfile = "/test/tmpfile" assert_nothing_raised { - list = server.list(sfile, :ignore, true, false) + list = server.list(sfile, :manage, true, false) } assert_nothing_raised { @@ -200,7 +200,7 @@ class TestFileServer < Test::Unit::TestCase list = nil sfile = "/test/" assert_nothing_raised { - list = server.list(sfile, :ignore, true, false) + list = server.list(sfile, :manage, true, false) } # create the new file @@ -210,7 +210,7 @@ class TestFileServer < Test::Unit::TestCase newlist = nil assert_nothing_raised { - newlist = server.list(sfile, :ignore, true, false) + newlist = server.list(sfile, :manage, true, false) } # verify the list has changed @@ -239,12 +239,12 @@ class TestFileServer < Test::Unit::TestCase list = nil assert_nothing_raised { - list = server.list("/root/" + testdir, :ignore, true, false) + list = server.list("/root/" + testdir, :manage, true, false) } assert(list =~ pattern) assert_nothing_raised { - list = server.list("/root" + testdir, :ignore, true, false) + list = server.list("/root" + testdir, :manage, true, false) } assert(list =~ pattern) @@ -279,7 +279,7 @@ class TestFileServer < Test::Unit::TestCase # get our list list = nil assert_nothing_raised { - list = server.list("/test/with", :ignore, false, false) + list = server.list("/test/with", :manage, false, false) } # make sure we only got one line, since we're not recursing @@ -288,7 +288,7 @@ class TestFileServer < Test::Unit::TestCase # for each level of recursion, make sure we get the right list [0, 1, 2].each { |num| assert_nothing_raised { - list = server.list("/test/with", :ignore, num, false) + list = server.list("/test/with", :manage, num, false) } count = 0 @@ -332,13 +332,13 @@ class TestFileServer < Test::Unit::TestCase list = nil # and then check a few dirs assert_nothing_raised { - list = server.list("/localhost/with", :ignore, false, false) + list = server.list("/localhost/with", :manage, false, false) } assert(list !~ /with/) assert_nothing_raised { - list = server.list("/localhost/with/some/sub", :ignore, true, false) + list = server.list("/localhost/with/some/sub", :manage, true, false) } assert(list !~ /sub/) @@ -370,7 +370,7 @@ class TestFileServer < Test::Unit::TestCase list = nil assert_nothing_raised { - list = server.list("/localhost/", :ignore, 1, false) + list = server.list("/localhost/", :manage, 1, false) } assert_instance_of(String, list, "Server returned %s instead of string") list = list.split("\n") @@ -402,7 +402,7 @@ class TestFileServer < Test::Unit::TestCase list = nil sfile = "/test/" assert_nothing_raised { - list = server.list(sfile, :ignore, true, false) + list = server.list(sfile, :manage, true, false) } # and describe each file in the list @@ -492,7 +492,7 @@ class TestFileServer < Test::Unit::TestCase mounts.each { |mount, files| mount = "/#{mount}/" assert_nothing_raised { - list = server.list(mount, :ignore, true, false) + list = server.list(mount, :manage, true, false) } assert_nothing_raised { @@ -544,12 +544,12 @@ class TestFileServer < Test::Unit::TestCase assert_raise(Puppet::AuthorizationError, "Host %s, ip %s, allowed %s" % [host, ip, mount]) { - list = server.list(mount, :ignore, true, false, host, ip) + list = server.list(mount, :manage, true, false, host, ip) } when :allow: assert_nothing_raised("Host %s, ip %s, denied %s" % [host, ip, mount]) { - list = server.list(mount, :ignore, true, false, host, ip) + list = server.list(mount, :manage, true, false, host, ip) } end } @@ -602,7 +602,7 @@ class TestFileServer < Test::Unit::TestCase assert_raise(Puppet::Network::Handler::FileServerError, "Invalid mount was mounted") { - server.list(mount, :ignore) + server.list(mount, :manage) } } @@ -654,13 +654,13 @@ class TestFileServer < Test::Unit::TestCase list = nil assert_nothing_raised { - list = server.list("/thing/", :ignore, false, false, + list = server.list("/thing/", :manage, false, false, "test1.domain.com", "127.0.0.1") } assert(list != "", "List returned nothing in rereard test") assert_raise(Puppet::AuthorizationError, "List allowed invalid host") { - list = server.list("/thing/", :ignore, false, false, + list = server.list("/thing/", :manage, false, false, "test2.domain.com", "127.0.0.1") } @@ -675,12 +675,12 @@ class TestFileServer < Test::Unit::TestCase } assert_raise(Puppet::AuthorizationError, "List allowed invalid host") { - list = server.list("/thing/", :ignore, false, false, + list = server.list("/thing/", :manage, false, false, "test1.domain.com", "127.0.0.1") } assert_nothing_raised { - list = server.list("/thing/", :ignore, false, false, + list = server.list("/thing/", :manage, false, false, "test2.domain.com", "127.0.0.1") } @@ -735,7 +735,7 @@ class TestFileServer < Test::Unit::TestCase # Then not results = {} assert_nothing_raised { - server.describe("/mount/link", :ignore).split("\t").zip( + server.describe("/mount/link", :manage).split("\t").zip( Puppet::Network::Handler.fileserver::CHECKPARAMS ).each { |v,p| results[p] = v } } @@ -801,28 +801,28 @@ allow * list = nil sfile = "/host/file.txt" assert_nothing_raised { - list = server.list(sfile, :ignore, true, false, client1, ip) + list = server.list(sfile, :manage, true, false, client1, ip) } assert_equal("/\tfile", list) assert_nothing_raised { - list = server.list(sfile, :ignore, true, false, client2, ip) + list = server.list(sfile, :manage, true, false, client2, ip) } assert_equal("", list) sfile = "/fqdn/file.txt" assert_nothing_raised { - list = server.list(sfile, :ignore, true, false, client1, ip) + list = server.list(sfile, :manage, true, false, client1, ip) } assert_equal("", list) assert_nothing_raised { - list = server.list(sfile, :ignore, true, false, client2, ip) + list = server.list(sfile, :manage, true, false, client2, ip) } assert_equal("/\tfile", list) # check describe sfile = "/host/file.txt" assert_nothing_raised { - list = server.describe(sfile, :ignore, client1, ip).split("\t") + list = server.describe(sfile, :manage, client1, ip).split("\t") } assert_equal(5, list.size) assert_equal("file", list[1]) @@ -830,18 +830,18 @@ allow * assert_equal("{md5}#{md5}", list[4]) assert_nothing_raised { - list = server.describe(sfile, :ignore, client2, ip).split("\t") + list = server.describe(sfile, :manage, client2, ip).split("\t") } assert_equal([], list) sfile = "/fqdn/file.txt" assert_nothing_raised { - list = server.describe(sfile, :ignore, client1, ip).split("\t") + list = server.describe(sfile, :manage, client1, ip).split("\t") } assert_equal([], list) assert_nothing_raised { - list = server.describe(sfile, :ignore, client2, ip).split("\t") + list = server.describe(sfile, :manage, client2, ip).split("\t") } assert_equal(5, list.size) assert_equal("file", list[1]) @@ -851,23 +851,23 @@ allow * # Check retrieve sfile = "/host/file.txt" assert_nothing_raised { - list = server.retrieve(sfile, :ignore, client1, ip).chomp + list = server.retrieve(sfile, :manage, client1, ip).chomp } assert_equal(contents[client1_hostdir].chomp, list) assert_nothing_raised { - list = server.retrieve(sfile, :ignore, client2, ip).chomp + list = server.retrieve(sfile, :manage, client2, ip).chomp } assert_equal("", list) sfile = "/fqdn/file.txt" assert_nothing_raised { - list = server.retrieve(sfile, :ignore, client1, ip).chomp + list = server.retrieve(sfile, :manage, client1, ip).chomp } assert_equal("", list) assert_nothing_raised { - list = server.retrieve(sfile, :ignore, client2, ip).chomp + list = server.retrieve(sfile, :manage, client2, ip).chomp } assert_equal(contents[client2_fqdndir].chomp, list) end @@ -945,12 +945,14 @@ allow * # Now, check that they use Facter info Puppet.notice "The following messages are normal" client = nil - local = Facter["hostname"].value - domain = Facter["domain"].value - fqdn = [local, domain].join(".") - {"%h" => local, # Short name - "%H" => fqdn, # Full name - "%d" => domain, # domain + Facter.stubs(:value).with(:ipaddress).returns("127.0.0.1") + Facter.stubs(:value).with { |v| v.to_s == "hostname" }.returns("myhost") + Facter.stubs(:value).with { |v| v.to_s == "domain" }.returns("mydomain.com") + Facter.stubs(:value).with(:domain).returns("mydomain.com") + + {"%h" => "myhost", # Short name + "%H" => "myhost.mydomain.com", # Full name + "%d" => "mydomain.com", # domain "%%" => "%", # escape "%o" => "%o" # other }.each do |pat, repl| @@ -993,18 +995,18 @@ allow * ret = nil assert_nothing_raised do - ret = server.list("/name", :ignore, false, false, host, ip) + ret = server.list("/name", :manage, false, false, host, ip) end assert_equal("/\tfile", ret) assert_nothing_raised do - ret = server.describe("/name", :ignore, host, ip) + ret = server.describe("/name", :manage, host, ip) end - assert(ret =~ /\tfile\t/, "Did not get valid a description") + assert(ret =~ /\tfile\t/, "Did not get valid a description (#{ret.inspect})") assert_nothing_raised do - ret = server.retrieve("/name", :ignore, host, ip) + ret = server.retrieve("/name", :manage, host, ip) end assert_equal(ret, File.read(file)) @@ -1050,7 +1052,7 @@ allow * mount = "/#{mod.name}/" list = nil assert_nothing_raised { - list = server.list(mount, :ignore, true, false) + list = server.list(mount, :manage, true, false) } list = list.split("\n") if mod.name == "green" @@ -1063,7 +1065,7 @@ allow * end assert_nothing_raised("Host 'allow' denied #{mount}") { - server.list(mount, :ignore, true, false, + server.list(mount, :manage, true, false, 'allow.example.com', "192.168.0.1") } end @@ -1106,7 +1108,7 @@ allow * list = nil mount = "/#{mod.name}/" assert_nothing_raised { - list = server.list(mount, :ignore, true, false) + list = server.list(mount, :manage, true, false) } assert_nothing_raised { @@ -1121,11 +1123,11 @@ allow * # now let's check that things are being correctly forbidden assert_raise(Puppet::AuthorizationError, "Host 'deny' allowed #{mount}") { - server.list(mount, :ignore, true, false, + server.list(mount, :manage, true, false, 'deny.example.com', "192.168.1.1") } assert_nothing_raised("Host 'allow' denied #{mount}") { - server.list(mount, :ignore, true, false, + server.list(mount, :manage, true, false, 'allow.example.com', "192.168.0.1") } end diff --git a/test/network/server/webrick.rb b/test/network/server/webrick.rb index d3408c166..fe6d69ade 100755 --- a/test/network/server/webrick.rb +++ b/test/network/server/webrick.rb @@ -95,7 +95,7 @@ class TestWebrickServer < Test::Unit::TestCase # the client starts its connection immediately, thus throwing # the error. assert_raise(OpenSSL::SSL::SSLError) { - client = Puppet::Network::Client.status.new(:Server => "localhost", :Port => @@port) + Puppet::Network::HttpPool.http_instance("localhost", @@port).start } end diff --git a/test/other/dsl.rb b/test/other/dsl.rb index b4dd0659b..45b51982d 100755 --- a/test/other/dsl.rb +++ b/test/other/dsl.rb @@ -12,7 +12,7 @@ class TestDSL < Test::Unit::TestCase def teardown super - Puppet::Aspect.clear + Puppet::DSL::Aspect.clear end def test_aspect @@ -22,7 +22,7 @@ class TestDSL < Test::Unit::TestCase end end - assert_equal(a, Puppet::Aspect[:yaytest]) + assert_equal(a, Puppet::DSL::Aspect[:yaytest]) # Now make a child aspect b = nil @@ -154,8 +154,7 @@ class TestDSL < Test::Unit::TestCase resource = nil assert_nothing_raised do - resource = a.newresource filetype, path, - :content => "yay", :mode => "640" + resource = a.newresource filetype, path, :content => "yay", :mode => "640" end assert_instance_of(Puppet::Parser::Resource, resource) diff --git a/test/other/transactions.rb b/test/other/transactions.rb index 105698da1..ce2d0d52b 100755 --- a/test/other/transactions.rb +++ b/test/other/transactions.rb @@ -6,10 +6,12 @@ require 'puppet' require 'puppettest' require 'mocha' require 'puppettest/support/resources' +require 'puppettest/support/utils' class TestTransactions < Test::Unit::TestCase include PuppetTest::FileTesting include PuppetTest::Support::Resources + include PuppetTest::Support::Utils class Fakeprop <Puppet::Property attr_accessor :path, :is, :should, :name def should_to_s(value) diff --git a/test/rails/ast.rb b/test/rails/ast.rb index e51fa6cf7..1deaec0f4 100755 --- a/test/rails/ast.rb +++ b/test/rails/ast.rb @@ -44,12 +44,12 @@ class TestRailsAST < PuppetTest::TestCase # And if it is, make sure we throw an error. if bad assert_raise(Puppet::ParseError, "Evaluated '#{string}'") do - str, code = query.evaluate :scope => @scope + str, code = query.evaluate @scope end next else assert_nothing_raised("Could not evaluate '#{string}'") do - str, code = query.evaluate :scope => @scope + str, code = query.evaluate @scope end end assert_nothing_raised("Could not find resource") do diff --git a/test/rails/configuration.rb b/test/rails/configuration.rb index 9e2ddfedd..a878d1381 100755 --- a/test/rails/configuration.rb +++ b/test/rails/configuration.rb @@ -24,7 +24,7 @@ class ConfigurationRailsTests < PuppetTest::TestCase # We need to make sure finished objects are stored in the db. def test_finish_before_store railsinit - compile = mkcompile + compile = mkcompiler parser = compile.parser node = parser.newnode [compile.node.name], :code => AST::ASTArray.new(:children => [ diff --git a/test/ral/manager/type.rb b/test/ral/manager/type.rb index 6c5587ddd..324550acb 100755 --- a/test/ral/manager/type.rb +++ b/test/ral/manager/type.rb @@ -574,8 +574,8 @@ class TestType < Test::Unit::TestCase assert_equal(greater, type.defaultprovider) end - # Make sure that we can have multiple isomorphic objects with the same name, - # but not with non-isomorphic objects. + # Make sure that we can have multiple non-isomorphic objects with the same name, + # but not with isomorphic objects. def test_isomorphic_names # First do execs, since they're not isomorphic. echo = Puppet::Util.binary "echo" diff --git a/test/ral/providers/cron/crontab.rb b/test/ral/providers/cron/crontab.rb index 2da4b1b57..1ff1e34ef 100755 --- a/test/ral/providers/cron/crontab.rb +++ b/test/ral/providers/cron/crontab.rb @@ -344,7 +344,9 @@ class TestCronParsedProvider < Test::Unit::TestCase end end - # Make sure we can create a cron in an empty tab + # Make sure we can create a cron in an empty tab. + # LAK:FIXME This actually modifies the user's crontab, + # which is pretty heinous. def test_mkcron_if_empty setme @provider.filetype = @oldfiletype diff --git a/test/ral/types/file.rb b/test/ral/types/file.rb index aa2e63a89..cbbe818ae 100755 --- a/test/ral/types/file.rb +++ b/test/ral/types/file.rb @@ -9,9 +9,7 @@ require 'fileutils' class TestFile < Test::Unit::TestCase include PuppetTest::Support::Utils include PuppetTest::FileTesting - # hmmm - # this is complicated, because we store references to the created - # objects in a central store + def mkfile(hash) file = nil assert_nothing_raised { @@ -21,8 +19,6 @@ class TestFile < Test::Unit::TestCase end def mktestfile - # because luke's home directory is on nfs, it can't be used for testing - # as root tmpfile = tempfile() File.open(tmpfile, "w") { |f| f.puts rand(100) } @@tmpfiles.push tmpfile @@ -181,7 +177,7 @@ class TestFile < Test::Unit::TestCase assert_equal(inituser, File.stat(file).uid) obj.delete(:owner) - obj[:links] = :ignore + obj[:links] = :follow # And then test 'group' group = nonrootgroup @@ -407,8 +403,7 @@ class TestFile < Test::Unit::TestCase assert(events) - assert(! events.include?(:file_changed), - "File incorrectly changed") + assert(! events.include?(:file_changed), "File incorrectly changed") assert_events([], file) # We have to sleep because the time resolution of the time-based @@ -1046,66 +1041,6 @@ class TestFile < Test::Unit::TestCase "directory mode is incorrect") end - def test_followlinks - File.umask(0022) - - basedir = tempfile() - Dir.mkdir(basedir) - file = File.join(basedir, "file") - link = File.join(basedir, "link") - - File.open(file, "w", 0644) { |f| f.puts "yayness"; f.flush } - File.symlink(file, link) - - obj = nil - assert_nothing_raised { - obj = Puppet.type(:file).create( - :path => link, - :mode => "755" - ) - } - obj.retrieve - - assert_events([], obj) - - # Assert that we default to not following links - assert_equal("%o" % 0644, "%o" % (File.stat(file).mode & 007777)) - - # Assert that we can manage the link directly, but modes still don't change - obj[:links] = :manage - assert_events([], obj) - - assert_equal("%o" % 0644, "%o" % (File.stat(file).mode & 007777)) - - obj[:links] = :follow - assert_events([:file_changed], obj) - - assert_equal("%o" % 0755, "%o" % (File.stat(file).mode & 007777)) - - # Now verify that content and checksum don't update, either - obj.delete(:mode) - obj[:checksum] = "md5" - obj[:links] = :ignore - - assert_events([], obj) - File.open(file, "w") { |f| f.puts "more text" } - assert_events([], obj) - obj[:links] = :follow - assert_events([], obj) - File.open(file, "w") { |f| f.puts "even more text" } - assert_events([:file_changed], obj) - - obj.delete(:checksum) - obj[:content] = "this is some content" - obj[:links] = :ignore - - assert_events([], obj) - File.open(file, "w") { |f| f.puts "more text" } - assert_events([], obj) - obj[:links] = :follow - assert_events([:file_changed], obj) - end - # If both 'ensure' and 'content' are used, make sure that all of the other # properties are handled correctly. def test_contentwithmode @@ -1292,6 +1227,7 @@ class TestFile < Test::Unit::TestCase :title => "localfile", :path => localfile, :content => "rahtest", + :ensure => :file, :backup => false ) @@ -1304,8 +1240,8 @@ class TestFile < Test::Unit::TestCase config.apply assert(FileTest.exists?(dsourcefile), "File did not get copied") - assert(FileTest.exists?(localfile), "File did not get created") - assert(FileTest.exists?(purgee), "File got prematurely purged") + assert(FileTest.exists?(localfile), "Local file did not get created") + assert(FileTest.exists?(purgee), "Purge target got prematurely purged") assert_nothing_raised { destobj[:purge] = true } config.apply @@ -1387,8 +1323,7 @@ class TestFile < Test::Unit::TestCase File.symlink(dir, link) File.open(file, "w") { |f| f.puts "" } assert_equal(dir, File.readlink(link)) - obj = Puppet::Type.newfile :path => link, :ensure => :link, - :target => file, :recurse => false, :backup => "main" + obj = Puppet::Type.newfile :path => link, :ensure => :link, :target => file, :recurse => false, :backup => "main" assert_apply(obj) @@ -1822,5 +1757,26 @@ class TestFile < Test::Unit::TestCase obj = Puppet::Type.newfile(:path => '/', :mode => 0755) assert_equal("/", obj.title, "/ directory was changed to empty string") end -end + # #1010 and #1037 -- write should fail if the written checksum does not + # match the file we thought we were writing. + def test_write_validates_checksum + file = tempfile + inst = Puppet::Type.newfile(:path => file, :content => "something") + + tmpfile = file + ".puppettmp" + + wh = mock 'writehandle', :print => nil + rh = mock 'readhandle' + rh.expects(:read).with(512).times(2).returns("other").then.returns(nil) + File.expects(:open).with { |*args| args[0] == tmpfile and args[1] != "r" }.yields(wh) + File.expects(:open).with { |*args| args[0] == tmpfile and args[1] == "r" }.yields(rh) + + File.stubs(:rename) + FileTest.stubs(:exist?).returns(true) + FileTest.stubs(:file?).returns(true) + + inst.expects(:fail) + inst.write("something", :whatever) + end +end diff --git a/test/ral/types/filesources.rb b/test/ral/types/filesources.rb index 02bf8a5b3..a7bb6fefa 100755 --- a/test/ral/types/filesources.rb +++ b/test/ral/types/filesources.rb @@ -84,8 +84,7 @@ class TestFileSources < Test::Unit::TestCase source = tempfile() dest = tempfile() - file = Puppet::Type.newfile :path => dest, :source => source, - :title => "copier" + file = Puppet::Type.newfile :path => dest, :source => source, :title => "copier" property = file.property(:source) @@ -124,17 +123,10 @@ class TestFileSources < Test::Unit::TestCase File.open(target, "w") { |f| f.puts "yay" } File.symlink(target, source) - file[:links] = :ignore - assert_nil(property.describe(source), - "Links were not ignored") - file[:links] = :manage - # We can't manage links at this point - assert_raise(Puppet::Network::Handler::FileServerError) do - property.describe(source) - end + assert_equal("link", property.describe(source)[:type]) - # And then make sure links get followed, otherwise + # And then make sure links get followed file[:links] = :follow assert_equal("file", property.describe(source)[:type]) end @@ -753,29 +745,18 @@ class TestFileSources < Test::Unit::TestCase assert_nothing_raised { file = Puppet.type(:file).create( :name => dest, - :source => link + :source => link, + :links => :follow ) } - # Default to skipping links - assert_events([], file) - assert(! FileTest.exists?(dest), "Created link") - - # Now follow the links - file[:links] = :follow assert_events([:file_created], file) assert(FileTest.file?(dest), "Destination is not a file") # Now copy the links - #assert_raise(Puppet::Network::Handler::FileServerError) { - trans = nil - assert_nothing_raised { - file[:links] = :manage - comp = mk_catalog(file) - trans = comp.apply - } - - assert(trans.failed?(file), "Object did not fail to copy links") + file[:links] = :manage + assert_events([:link_created], file) + assert(FileTest.symlink?(dest), "Destination is not a link") end def test_changes |