summaryrefslogtreecommitdiffstats
path: root/lib/puppet/util
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-03-31 23:56:09 -0500
committerLuke Kanies <luke@madstop.com>2008-03-31 23:56:09 -0500
commit88dc49cb7b0efe757c92ce28c807b91335acb07a (patch)
tree13fe4561f1f524f97a8bb2c1ff84c1ef981d0241 /lib/puppet/util
parent4165edaeb71ee2883b1bb85ff39a52d5628b259f (diff)
parenta8592f1009040ebf30a98268610915cc33bb3f63 (diff)
downloadpuppet-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.rb10
-rw-r--r--lib/puppet/util/checksums.rb64
-rw-r--r--lib/puppet/util/constant_inflector.rb15
-rw-r--r--lib/puppet/util/diff.rb4
-rw-r--r--lib/puppet/util/fileparsing.rb3
-rwxr-xr-xlib/puppet/util/filetype.rb10
-rw-r--r--lib/puppet/util/graph.rb2
-rw-r--r--lib/puppet/util/settings.rb268
-rw-r--r--lib/puppet/util/tagging.rb40
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