diff options
| author | Luke Kanies <luke@madstop.com> | 2008-03-31 23:56:09 -0500 |
|---|---|---|
| committer | Luke Kanies <luke@madstop.com> | 2008-03-31 23:56:09 -0500 |
| commit | 88dc49cb7b0efe757c92ce28c807b91335acb07a (patch) | |
| tree | 13fe4561f1f524f97a8bb2c1ff84c1ef981d0241 /lib/puppet/util | |
| parent | 4165edaeb71ee2883b1bb85ff39a52d5628b259f (diff) | |
| parent | a8592f1009040ebf30a98268610915cc33bb3f63 (diff) | |
| download | puppet-88dc49cb7b0efe757c92ce28c807b91335acb07a.tar.gz puppet-88dc49cb7b0efe757c92ce28c807b91335acb07a.tar.xz puppet-88dc49cb7b0efe757c92ce28c807b91335acb07a.zip | |
Merge branch 'master' into master_no_global_resources
Conflicts:
lib/puppet/node/catalog.rb
lib/puppet/type/pfile.rb
lib/puppet/type/pfilebucket.rb
lib/puppet/util/filetype.rb
spec/unit/node/catalog.rb
spec/unit/other/transbucket.rb
spec/unit/ral/provider/mount/parsed.rb
spec/unit/ral/types/file.rb
spec/unit/ral/types/interface.rb
spec/unit/ral/types/mount.rb
spec/unit/ral/types/package.rb
spec/unit/ral/types/schedule.rb
spec/unit/ral/types/service.rb
test/language/compile.rb
test/language/lexer.rb
test/language/snippets.rb
test/lib/puppettest.rb
test/ral/types/basic.rb
test/ral/types/cron.rb
test/ral/types/exec.rb
test/ral/types/file.rb
test/ral/types/file/target.rb
test/ral/types/filebucket.rb
test/ral/types/fileignoresource.rb
test/ral/types/filesources.rb
test/ral/types/group.rb
test/ral/types/host.rb
test/ral/types/parameter.rb
test/ral/types/sshkey.rb
test/ral/types/tidy.rb
test/ral/types/user.rb
test/ral/types/yumrepo.rb
Diffstat (limited to 'lib/puppet/util')
| -rw-r--r-- | lib/puppet/util/autoload.rb | 10 | ||||
| -rw-r--r-- | lib/puppet/util/checksums.rb | 64 | ||||
| -rw-r--r-- | lib/puppet/util/constant_inflector.rb | 15 | ||||
| -rw-r--r-- | lib/puppet/util/diff.rb | 4 | ||||
| -rw-r--r-- | lib/puppet/util/fileparsing.rb | 3 | ||||
| -rwxr-xr-x | lib/puppet/util/filetype.rb | 10 | ||||
| -rw-r--r-- | lib/puppet/util/graph.rb | 2 | ||||
| -rw-r--r-- | lib/puppet/util/settings.rb | 268 | ||||
| -rw-r--r-- | lib/puppet/util/tagging.rb | 40 |
9 files changed, 218 insertions, 198 deletions
diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb index a52575522..535d9ef2e 100644 --- a/lib/puppet/util/autoload.rb +++ b/lib/puppet/util/autoload.rb @@ -1,6 +1,9 @@ +require 'puppet/util/warnings' + # Autoload paths, either based on names or all at once. class Puppet::Util::Autoload include Puppet::Util + include Puppet::Util::Warnings @autoloaders = {} @loaded = [] @@ -109,9 +112,8 @@ class Puppet::Util::Autoload Dir.glob("#{dir}/*.rb").each do |file| name = File.basename(file).sub(".rb", '').intern next if loaded?(name) - rubypath = File.join(@path, name.to_s) begin - Kernel.require rubypath + Kernel.require file loaded(name, file) rescue => detail if Puppet[:trace] @@ -123,8 +125,6 @@ class Puppet::Util::Autoload end end - private - # Yield each subdir in turn. def eachdir searchpath.each do |dir| @@ -137,7 +137,7 @@ class Puppet::Util::Autoload def searchpath # JJM: Search for optional lib directories in each module bundle. module_lib_dirs = Puppet[:modulepath].split(":").collect do |d| - Dir.glob("%s/*/lib" % d).select do |f| + Dir.glob("%s/*/{plugins,lib}" % d).select do |f| FileTest.directory?(f) end end.flatten diff --git a/lib/puppet/util/checksums.rb b/lib/puppet/util/checksums.rb index 6f6ea59b5..15d2eadd1 100644 --- a/lib/puppet/util/checksums.rb +++ b/lib/puppet/util/checksums.rb @@ -1,37 +1,75 @@ +# A stand-alone module for calculating checksums +# in a generic way. module Puppet::Util::Checksums + # Calculate a checksum using Digest::MD5. def md5(content) require 'digest/md5' Digest::MD5.hexdigest(content) end - def md5_file(filename) + # Calculate a checksum of the first 500 chars of the content using Digest::MD5. + def md5lite(content) + md5(content[0..511]) + end + + # Calculate a checksum of a file's content using Digest::MD5. + def md5_file(filename, lite = false) require 'digest/md5' - incr_digest = Digest::MD5.new() - File.open(filename, 'r') do |file| - file.each_line do |line| - incr_digest << line - end - end + digest = Digest::MD5.new() + return checksum_file(digest, filename, lite) + end + + # Calculate a checksum of the first 500 chars of a file's content using Digest::MD5. + def md5lite_file(filename) + md5_file(filename, true) + end - return incr_digest.hexdigest + # Return the :mtime timestamp of a file. + def mtime_file(filename) + File.stat(filename).send(:mtime) end + # Calculate a checksum using Digest::SHA1. def sha1(content) require 'digest/sha1' Digest::SHA1.hexdigest(content) end - def sha1_file(filename) + # Calculate a checksum of the first 500 chars of the content using Digest::SHA1. + def sha1lite(content) + sha1(content[0..511]) + end + + # Calculate a checksum of a file's content using Digest::SHA1. + def sha1_file(filename, lite = false) require 'digest/sha1' - incr_digest = Digest::SHA1.new() + digest = Digest::SHA1.new() + return checksum_file(digest, filename, lite) + end + + # Calculate a checksum of the first 500 chars of a file's content using Digest::SHA1. + def sha1lite_file(filename) + sha1_file(filename, true) + end + + # Return the :ctime of a file. + def ctime_file(filename) + File.stat(filename).send(:ctime) + end + + private + + # Perform an incremental checksum on a file. + def checksum_file(digest, filename, lite = false) File.open(filename, 'r') do |file| - file.each_line do |line| - incr_digest << line + while content = file.read(512) + digest << content + break if lite end end - return incr_digest.hexdigest + return digest.hexdigest end end diff --git a/lib/puppet/util/constant_inflector.rb b/lib/puppet/util/constant_inflector.rb new file mode 100644 index 000000000..eeeaa0632 --- /dev/null +++ b/lib/puppet/util/constant_inflector.rb @@ -0,0 +1,15 @@ +# Created on 2008-02-12 +# Copyright Luke Kanies + +# A common module for converting between constants and +# file names. +module Puppet::Util::ConstantInflector + def file2constant(file) + # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] + x = file.split("/").collect { |name| name.capitalize }.join("::").gsub(/_+(.)/) { |term| $1.capitalize } + end + + def constant2file(constant) + constant.to_s.gsub(/([a-z])([A-Z])/) { |term| $1 + "_" + $2 }.gsub("::", "/").downcase + end +end diff --git a/lib/puppet/util/diff.rb b/lib/puppet/util/diff.rb index e6ff57108..f37ea0850 100644 --- a/lib/puppet/util/diff.rb +++ b/lib/puppet/util/diff.rb @@ -27,7 +27,7 @@ module Puppet::Util::Diff output = "" - diffs = Diff::LCS.diff(data_old, data_new) + diffs = ::Diff::LCS.diff(data_old, data_new) return output if diffs.empty? oldhunk = hunk = nil @@ -35,7 +35,7 @@ module Puppet::Util::Diff diffs.each do |piece| begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, + hunk = ::Diff::LCS::Hunk.new(data_old, data_new, piece, context_lines, file_length_difference) file_length_difference = hunk.file_length_difference diff --git a/lib/puppet/util/fileparsing.rb b/lib/puppet/util/fileparsing.rb index 8e39719c8..23d02ea60 100644 --- a/lib/puppet/util/fileparsing.rb +++ b/lib/puppet/util/fileparsing.rb @@ -223,7 +223,8 @@ module Puppet::Util::FileParsing # Split text into separate lines using the record separator. def lines(text) # Remove any trailing separators, and then split based on them - text.sub(/#{self.line_separator}\Q/,'').split(self.line_separator) + # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] + x = text.sub(/#{self.line_separator}\Q/,'').split(self.line_separator) end # Split a bunch of text into lines and then parse them individually. diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb index 95f48e10e..ae078fff4 100755 --- a/lib/puppet/util/filetype.rb +++ b/lib/puppet/util/filetype.rb @@ -106,8 +106,14 @@ class Puppet::Util::FileType # Overwrite the file. def write(text) backup() + raise("Cannot create file %s in absent directory" % @path) unless FileTest.exist?(File.dirname(@path)) - File.open(@path, "w") { |f| f.print text; f.flush } + + require "tempfile" + tf = Tempfile.new("puppet") + tf.print text; tf.flush + FileUtils.cp(tf.path, @path) + tf.close end end @@ -168,7 +174,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/graph.rb b/lib/puppet/util/graph.rb index a9744578b..d1ef36f8e 100644 --- a/lib/puppet/util/graph.rb +++ b/lib/puppet/util/graph.rb @@ -16,7 +16,7 @@ module Puppet::Util::Graph self.each do |child| unless block_given? and ! yield(child) - graph.add_edge!(self, child) + graph.add_edge(self, child) if child.respond_to?(:to_graph) child.to_graph(graph, &block) diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index b672d9564..089389a09 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -44,19 +44,6 @@ class Puppet::Util::Settings return value end - # A simplified equality operator. - # LAK: For some reason, this causes mocha to not be able to mock - # the 'value' method, and it's not used anywhere. -# def ==(other) -# self.each { |myname, myobj| -# unless other[myname] == value(myname) -# return false -# end -# } -# -# return true -# end - # Generate the list of valid arguments, in a format that GetoptLong can # understand, and add them to the passed option list. def addargs(options) @@ -225,6 +212,9 @@ class Puppet::Util::Settings # A central concept of a name. @name = nil + + # The list of sections we've used. + @used = [] end # Return a given object's file metadata. @@ -243,14 +233,7 @@ class Puppet::Util::Settings # Make a directory with the appropriate user, group, and mode def mkdir(default) - obj = nil - unless obj = @config[default] - raise ArgumentError, "Unknown default %s" % default - end - - unless obj.is_a? CFile - raise ArgumentError, "Default %s is not a file" % default - end + obj = get_config_file_default(default) Puppet::Util::SUIDManager.asuser(obj.owner, obj.group) do mode = obj.mode || 0750 @@ -329,94 +312,6 @@ class Puppet::Util::Settings end end - # Parse the configuration file. As of May 2007, this is a backward-compatibility method and - # will be deprecated soon. - def old_parse(file) - text = nil - - if file.is_a? Puppet::Util::LoadedFile - @file = file - else - @file = Puppet::Util::LoadedFile.new(file) - end - - # Don't create a timer for the old style parsing. - # settimer() - - begin - text = File.read(@file.file) - rescue Errno::ENOENT - raise Puppet::Error, "No such file %s" % file - rescue Errno::EACCES - raise Puppet::Error, "Permission denied to file %s" % file - end - - @values = Hash.new { |names, name| - names[name] = {} - } - - # Get rid of the values set by the file, keeping cli values. - self.clear(true) - - section = "puppet" - metas = %w{owner group mode} - values = Hash.new { |hash, key| hash[key] = {} } - text.split(/\n/).each { |line| - case line - when /^\[(\w+)\]$/: section = $1 # Section names - when /^\s*#/: next # Skip comments - when /^\s*$/: next # Skip blanks - when /^\s*(\w+)\s*=\s*(.+)$/: # settings - var = $1.intern - if var == :mode - value = $2 - else - value = munge_value($2) - end - - # Only warn if we don't know what this config var is. This - # prevents exceptions later on. - unless @config.include?(var) or metas.include?(var.to_s) - Puppet.warning "Discarded unknown configuration parameter %s" % var.inspect - next # Skip this line. - end - - # Mmm, "special" attributes - if metas.include?(var.to_s) - unless values.include?(section) - values[section] = {} - end - values[section][var.to_s] = value - - # If the parameter is valid, then set it. - if section == Puppet[:name] and @config.include?(var) - #@config[var].value = value - @values[:main][var] = value - end - next - end - - # Don't override set parameters, since the file is parsed - # after cli arguments are handled. - unless @config.include?(var) and @config[var].setbycli - Puppet.debug "%s: Setting %s to '%s'" % [section, var, value] - @values[:main][var] = value - end - @config[var].section = symbolize(section) - - metas.each { |meta| - if values[section][meta] - if @config[var].respond_to?(meta + "=") - @config[var].send(meta + "=", values[section][meta]) - end - end - } - else - raise Puppet::Error, "Could not match line %s" % line - end - } - end - # Create a new element. The value is passed in because it's used to determine # what kind of element we're creating, but the value itself might be either # a default or a value, so we can't actually assign it. @@ -509,19 +404,19 @@ class Puppet::Util::Settings objects += add_user_resources(section, obj, done) end + value = obj.value + # Only files are convertable to transportable resources. - if obj.respond_to? :to_transportable - next if value(obj.name) =~ /^\/dev/ - transobjects = obj.to_transportable - transobjects = [transobjects] unless transobjects.is_a? Array - transobjects.each do |trans| - # transportable could return nil - next unless trans - unless done[:file].include? trans.name - @created << trans.name - objects << trans - done[:file][trans.name] = trans - end + next unless obj.respond_to? :to_transportable and transobjects = obj.to_transportable + + transobjects = [transobjects] unless transobjects.is_a? Array + transobjects.each do |trans| + # transportable could return nil + next unless trans + unless done[:file].include? trans.name + @created << trans.name + objects << trans + done[:file][trans.name] = trans end end end @@ -670,23 +565,36 @@ Generated on #{Time.now}. # you can 'use' a section as many times as you want. def use(*sections) @@sync.synchronize do # yay, thread-safe - unless defined? @used - @used = [] - end + sections = sections.reject { |s| @used.include?(s.to_sym) } + + return if sections.empty? bucket = to_transportable(*sections) - config = bucket.to_catalog - config.host_config = false - config.apply do |transaction| - if failures = transaction.any_failed? - raise "Could not configure for running; got %s failure(s)" % failures + begin + catalog = bucket.to_catalog + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err "Could not create resources for managing Puppet's files and directories: %s" % detail + + # We need some way to get rid of any resources created during the catalog creation + # but not cleaned up. + return + end + + begin + catalog.host_config = false + catalog.apply do |transaction| + if failures = transaction.any_failed? + raise "Could not configure for running; got %s failure(s)" % failures + end end + ensure + catalog.clear end - config.clear sections.each { |s| @used << s } - @used.uniq + @used.uniq! end end @@ -737,49 +645,15 @@ Generated on #{Time.now}. end # Open a file with the appropriate user, group, and mode - def write(default, *args) - obj = nil - unless obj = @config[default] - raise ArgumentError, "Unknown default %s" % default - end - - unless obj.is_a? CFile - raise ArgumentError, "Default %s is not a file" % default - end - - chown = nil - if Puppet::Util::SUIDManager.uid == 0 - chown = [obj.owner, obj.group] - else - chown = [nil, nil] - end - Puppet::Util::SUIDManager.asuser(*chown) do - mode = obj.mode || 0640 - - if args.empty? - args << "w" - end - - args << mode - - File.open(value(obj.name), *args) do |file| - yield file - end - end + def write(default, *args, &bloc) + obj = get_config_file_default(default) + writesub(default, value(obj.name), *args, &bloc) end # Open a non-default file under a default dir with the appropriate user, # group, and mode - def writesub(default, file, *args) - obj = nil - unless obj = @config[default] - raise ArgumentError, "Unknown default %s" % default - end - - unless obj.is_a? CFile - raise ArgumentError, "Default %s is not a file" % default - end - + def writesub(default, file, *args, &bloc) + obj = get_config_file_default(default) chown = nil if Puppet::Util::SUIDManager.uid == 0 chown = [obj.owner, obj.group] @@ -804,8 +678,51 @@ Generated on #{Time.now}. end end + def readwritelock(default, *args, &bloc) + file = value(get_config_file_default(default).name) + tmpfile = file + ".tmp" + sync = Sync.new + unless FileTest.directory?(File.dirname(tmpfile)) + raise Puppet::DevError, "Cannot create %s; directory %s does not exist" % + [file, File.dirname(file)] + end + + sync.synchronize(Sync::EX) do + File.open(file, "r+", 0600) do |rf| + rf.lock_exclusive do + if File.exist?(tmpfile) + raise Puppet::Error, ".tmp file already exists for %s; Aborting locked write. Check the .tmp file and delete if appropriate" % + [file] + end + + writesub(default, tmpfile, *args, &bloc) + + begin + File.rename(tmpfile, file) + rescue => detail + Puppet.err "Could not rename %s to %s: %s" % + [file, tmpfile, detail] + end + end + end + end + end + private + def get_config_file_default(default) + obj = nil + unless obj = @config[default] + raise ArgumentError, "Unknown default %s" % default + end + + unless obj.is_a? CFile + raise ArgumentError, "Default %s is not a file" % default + end + + return obj + end + # Create the transportable objects for users and groups. def add_user_resources(section, obj, done) resources = [] @@ -1124,7 +1041,7 @@ Generated on #{Time.now}. # the variable 'dir', or adding a slash at the end. def munge(value) # If it's not a fully qualified path... - if value.is_a?(String) and value !~ /^\$/ and value !~ /^\// + if value.is_a?(String) and value !~ /^\$/ and value !~ /^\// and value != 'false' # Make it one value = File.join(Dir.getwd, value) end @@ -1153,12 +1070,15 @@ Generated on #{Time.now}. def to_transportable type = self.type return nil unless type - path = @parent.value(self.name).split(File::SEPARATOR) - path.shift # remove the leading nil - objects = [] path = self.value + return nil unless path.is_a?(String) + return nil if path =~ /^\/dev/ + return nil if Puppet::Type.type(:file)[path] # skip files that are in our global resource list. + + objects = [] + # Skip plain files that don't exist, since we won't be managing them anyway. return nil unless self.name.to_s =~ /dir$/ or File.exist?(path) or self.create obj = Puppet::TransObject.new(path, "file") diff --git a/lib/puppet/util/tagging.rb b/lib/puppet/util/tagging.rb new file mode 100644 index 000000000..e06e13a2c --- /dev/null +++ b/lib/puppet/util/tagging.rb @@ -0,0 +1,40 @@ +# Created on 2008-01-19 +# Copyright Luke Kanies + +# A common module to handle tagging. +module Puppet::Util::Tagging + # Add a tag to our current list. These tags will be added to all + # of the objects contained in this scope. + def tag(*ary) + @tags ||= [] + + qualified = [] + + ary.collect { |tag| tag.to_s.downcase }.each do |tag| + fail(Puppet::ParseError, "Invalid tag %s" % tag.inspect) unless valid_tag?(tag) + qualified << tag if tag.include?("::") + @tags << tag unless @tags.include?(tag) + end + + # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] + qualified.collect { |name| x = name.split("::") }.flatten.each { |tag| @tags << tag unless @tags.include?(tag) } + end + + # Are we tagged with the provided tag? + def tagged?(tag) + defined?(@tags) and @tags.include?(tag.to_s) + end + + # Return a copy of the tag list, so someone can't ask for our tags + # and then modify them. + def tags + @tags ||= [] + @tags.dup + end + + private + + def valid_tag?(tag) + tag =~ /^\w[-\w:.]*$/ + end +end |
