summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-09-23 23:50:43 -0500
committerLuke Kanies <luke@madstop.com>2008-09-23 23:50:43 -0500
commitbb23861e334e617b544c11bc75a35c40b36185a2 (patch)
tree18da91858e4fded78a56d673fc69014fdf266676 /lib
parente31df2f7f5e98c524b68cd724cfaa3e308e7b9a1 (diff)
parentac5db5ec115455e54090542870847820357739a2 (diff)
downloadpuppet-bb23861e334e617b544c11bc75a35c40b36185a2.tar.gz
puppet-bb23861e334e617b544c11bc75a35c40b36185a2.tar.xz
puppet-bb23861e334e617b544c11bc75a35c40b36185a2.zip
Merge branch 'feature/master/1481'
This merges in the new fileserving code -- we're now using REST to do fileserving, rather than xmlrpc. Conflicts: lib/puppet/parameter.rb lib/puppet/type/file.rb spec/unit/type/file.rb
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/file_serving/base.rb (renamed from lib/puppet/file_serving/file_base.rb)14
-rw-r--r--lib/puppet/file_serving/configuration.rb5
-rw-r--r--lib/puppet/file_serving/content.rb37
-rw-r--r--lib/puppet/file_serving/fileset.rb4
-rw-r--r--lib/puppet/file_serving/indirection_hooks.rb45
-rw-r--r--lib/puppet/file_serving/metadata.rb6
-rw-r--r--lib/puppet/file_serving/terminus_helper.rb14
-rw-r--r--lib/puppet/indirector/direct_file_server.rb10
-rw-r--r--lib/puppet/indirector/file_metadata/file.rb4
-rw-r--r--lib/puppet/indirector/file_metadata/modules.rb2
-rw-r--r--lib/puppet/indirector/file_server.rb3
-rw-r--r--lib/puppet/indirector/indirection.rb10
-rw-r--r--lib/puppet/indirector/module_files.rb9
-rw-r--r--lib/puppet/indirector/request.rb53
-rw-r--r--lib/puppet/indirector/rest.rb42
-rw-r--r--lib/puppet/network/format.rb12
-rw-r--r--lib/puppet/network/format_handler.rb5
-rw-r--r--lib/puppet/network/formats.rb23
-rwxr-xr-xlib/puppet/network/handler/fileserver.rb2
-rw-r--r--lib/puppet/network/http/handler.rb13
-rw-r--r--lib/puppet/network/http/mongrel/rest.rb2
-rw-r--r--lib/puppet/network/http/webrick/rest.rb2
-rw-r--r--lib/puppet/type.rb11
-rw-r--r--lib/puppet/type/file.rb451
-rwxr-xr-xlib/puppet/type/file/source.rb201
25 files changed, 440 insertions, 540 deletions
diff --git a/lib/puppet/file_serving/file_base.rb b/lib/puppet/file_serving/base.rb
index e87d683aa..c59a54786 100644
--- a/lib/puppet/file_serving/file_base.rb
+++ b/lib/puppet/file_serving/base.rb
@@ -6,8 +6,10 @@ require 'puppet/file_serving'
# The base class for Content and Metadata; provides common
# functionality like the behaviour around links.
-class Puppet::FileServing::FileBase
- attr_accessor :key
+class Puppet::FileServing::Base
+ # This is for external consumers to store the source that was used
+ # to retrieve the metadata.
+ attr_accessor :source
# Does our file exist?
def exist?
@@ -21,17 +23,15 @@ class Puppet::FileServing::FileBase
# 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
-
- if relative_path.nil? or relative_path == ""
+ if relative_path.nil? or relative_path == "" or relative_path == "."
path
else
File.join(path, relative_path)
end
end
- def initialize(key, options = {})
- @key = key
+ def initialize(path, options = {})
+ self.path = path
@links = :manage
options.each do |param, value|
diff --git a/lib/puppet/file_serving/configuration.rb b/lib/puppet/file_serving/configuration.rb
index 9c38aaa19..bceecc30c 100644
--- a/lib/puppet/file_serving/configuration.rb
+++ b/lib/puppet/file_serving/configuration.rb
@@ -98,13 +98,14 @@ class Puppet::FileServing::Configuration
# Reparse the configuration if necessary.
readconfig
- raise(ArgumentError, "Cannot find file: Invalid path '%s'" % uri) unless uri =~ %r{/([-\w]+)/?}
+ raise(ArgumentError, "Cannot find file: Invalid path '%s'" % uri) unless uri =~ %r{^([-\w]+)(/|$)}
# the dir is based on one of the mounts
# so first retrieve the mount path
mount = path = nil
+
# Strip off the mount name.
- mount_name, path = uri.sub(%r{^/}, '').split(File::Separator, 2)
+ mount_name, path = uri.split(File::Separator, 2)
return nil unless mount = @mounts[mount_name]
diff --git a/lib/puppet/file_serving/content.rb b/lib/puppet/file_serving/content.rb
index 9398513e7..c1ecff749 100644
--- a/lib/puppet/file_serving/content.rb
+++ b/lib/puppet/file_serving/content.rb
@@ -4,31 +4,46 @@
require 'puppet/indirector'
require 'puppet/file_serving'
-require 'puppet/file_serving/file_base'
+require 'puppet/file_serving/base'
require 'puppet/file_serving/indirection_hooks'
# A class that handles retrieving file contents.
# It only reads the file when its content is specifically
# asked for.
-class Puppet::FileServing::Content < Puppet::FileServing::FileBase
+class Puppet::FileServing::Content < Puppet::FileServing::Base
extend Puppet::Indirector
indirects :file_content, :extend => Puppet::FileServing::IndirectionHooks
- attr_reader :path
+ attr_writer :content
+
+ def self.supported_formats
+ [:raw]
+ end
+
+ def self.from_raw(content)
+ instance = new("/this/is/a/fake/path")
+ instance.content = content
+ instance
+ end
+
+ # Collect our data.
+ def collect
+ return if stat.ftype == "directory"
+ content
+ end
# Read the content of our file in.
def content
- # This stat can raise an exception, too.
- raise(ArgumentError, "Cannot read the contents of links unless following links") if stat().ftype == "symlink"
+ unless defined?(@content) and @content
+ # This stat can raise an exception, too.
+ raise(ArgumentError, "Cannot read the contents of links unless following links") if stat().ftype == "symlink"
- ::File.read(full_path())
+ @content = ::File.read(full_path())
+ end
+ @content
end
- # Just return the file contents as the yaml. This allows us to
- # avoid escaping or any such thing. LAK:NOTE Not really sure how
- # this will behave if the file contains yaml... I think the far
- # side needs to understand that it's a plain string.
- def to_yaml
+ def to_raw
content
end
end
diff --git a/lib/puppet/file_serving/fileset.rb b/lib/puppet/file_serving/fileset.rb
index fe54350b1..a90734a2b 100644
--- a/lib/puppet/file_serving/fileset.rb
+++ b/lib/puppet/file_serving/fileset.rb
@@ -20,7 +20,7 @@ class Puppet::FileServing::Fileset
# Now strip off the leading path, so each file becomes relative, and remove
# any slashes that might end up at the beginning of the path.
- result = files.collect { |file| file.sub(%r{^#{@path}/*}, '') }
+ result = files.collect { |file| file.sub(@path, '').sub(%r{^/},'') }
# And add the path itself.
result.unshift(".")
@@ -30,6 +30,8 @@ class Puppet::FileServing::Fileset
# Should we ignore this path?
def ignore?(path)
+ return false if @ignore == [nil]
+
# 'detect' normally returns the found result, whereas we just want true/false.
! @ignore.detect { |pattern| File.fnmatch?(pattern, path) }.nil?
end
diff --git a/lib/puppet/file_serving/indirection_hooks.rb b/lib/puppet/file_serving/indirection_hooks.rb
index 66ed169dc..15564cf3d 100644
--- a/lib/puppet/file_serving/indirection_hooks.rb
+++ b/lib/puppet/file_serving/indirection_hooks.rb
@@ -9,36 +9,37 @@ require 'puppet/file_serving'
# in file-serving indirections. This is necessary because
# the terminus varies based on the URI asked for.
module Puppet::FileServing::IndirectionHooks
- PROTOCOL_MAP = {"puppet" => :rest, "file" => :file, "puppetmounts" => :file_server}
+ PROTOCOL_MAP = {"puppet" => :rest, "file" => :file}
# Pick an appropriate terminus based on the protocol.
def select_terminus(request)
- full_uri = request.key
- # Short-circuit to :file if it's a fully-qualified path.
- return PROTOCOL_MAP["file"] if full_uri =~ /^#{::File::SEPARATOR}/
- begin
- uri = URI.parse(URI.escape(full_uri))
- rescue => detail
- raise ArgumentError, "Could not understand URI %s: %s" % [full_uri, detail.to_s]
- end
+ # We rely on the request's parsing of the URI.
- terminus = PROTOCOL_MAP[uri.scheme] || raise(ArgumentError, "URI protocol '%s' is not supported for file serving" % uri.scheme)
+ # Short-circuit to :file if it's a fully-qualified path or specifies a 'file' protocol.
+ return PROTOCOL_MAP["file"] if request.key =~ /^#{::File::SEPARATOR}/
+ return PROTOCOL_MAP["file"] if request.protocol == "file"
- # This provides a convenient mechanism for people to write configurations work
- # well in both a networked and local setting.
- if uri.host.nil? and uri.scheme == "puppet" and Puppet.settings[:name] == "puppet"
- terminus = :file_server
+ # We're heading over the wire the protocol is 'puppet' and we've got a server name or we're not named 'puppet'
+ if request.protocol == "puppet" and (request.server or Puppet.settings[:name] != "puppet")
+ return PROTOCOL_MAP["puppet"]
+ end
+
+ if request.protocol and PROTOCOL_MAP[request.protocol].nil?
+ raise(ArgumentError, "URI protocol '%s' is not currently supported for file serving" % request.protocol)
end
+ # If we're still here, we're using the file_server or modules.
+
# This is the backward-compatible module terminus.
- if terminus == :file_server and uri.path =~ %r{^/([^/]+)\b}
- modname = $1
- if modname == "modules"
- terminus = :modules
- elsif terminus(:modules).find_module(modname, request.options[:node])
- Puppet.warning "DEPRECATION NOTICE: Found file '%s' in module without using the 'modules' mount; please prefix path with '/modules'" % uri.path
- terminus = :modules
- end
+ modname = request.key.split("/")[0]
+
+ if modname == "modules"
+ terminus = :modules
+ elsif terminus(:modules).find_module(modname, request.options[:node])
+ Puppet.warning "DEPRECATION NOTICE: Found file '%s' in module without using the 'modules' mount; please prefix path with 'modules/'" % request.key
+ terminus = :modules
+ else
+ terminus = :file_server
end
return terminus
diff --git a/lib/puppet/file_serving/metadata.rb b/lib/puppet/file_serving/metadata.rb
index beecaef48..1cc3fa355 100644
--- a/lib/puppet/file_serving/metadata.rb
+++ b/lib/puppet/file_serving/metadata.rb
@@ -5,12 +5,12 @@
require 'puppet'
require 'puppet/indirector'
require 'puppet/file_serving'
-require 'puppet/file_serving/file_base'
+require 'puppet/file_serving/base'
require 'puppet/util/checksums'
require 'puppet/file_serving/indirection_hooks'
# A class that handles retrieving file metadata.
-class Puppet::FileServing::Metadata < Puppet::FileServing::FileBase
+class Puppet::FileServing::Metadata < Puppet::FileServing::Base
include Puppet::Util::Checksums
@@ -47,7 +47,7 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::FileBase
# Retrieve the attributes for this file, relative to a base directory.
# Note that File.stat raises Errno::ENOENT if the file is absent and this
# method does not catch that exception.
- def collect_attributes
+ def collect
real_path = full_path()
stat = stat()
@owner = stat.uid
diff --git a/lib/puppet/file_serving/terminus_helper.rb b/lib/puppet/file_serving/terminus_helper.rb
index e5da0e29f..b51e27297 100644
--- a/lib/puppet/file_serving/terminus_helper.rb
+++ b/lib/puppet/file_serving/terminus_helper.rb
@@ -9,10 +9,20 @@ require 'puppet/file_serving/fileset'
module Puppet::FileServing::TerminusHelper
# Create model instances for all files in a fileset.
def path2instances(request, path)
- args = [:links, :ignore, :recurse].inject({}) { |hash, param| hash[param] = request.options[param] if request.options[param]; hash }
+ args = [:links, :ignore, :recurse].inject({}) do |hash, param|
+ if request.options.include?(param) # use 'include?' so the values can be false
+ hash[param] = request.options[param]
+ elsif request.options.include?(param.to_s)
+ hash[param] = request.options[param.to_s]
+ end
+ hash[param] = true if hash[param] == "true"
+ hash[param] = false if hash[param] == "false"
+ hash
+ end
Puppet::FileServing::Fileset.new(path, args).files.collect do |file|
- inst = model.new(File.join(request.key, file), :path => path, :relative_path => file)
+ inst = model.new(path, :relative_path => file)
inst.links = request.options[:links] if request.options[:links]
+ inst.collect
inst
end
end
diff --git a/lib/puppet/indirector/direct_file_server.rb b/lib/puppet/indirector/direct_file_server.rb
index b3b4886f3..bcda92366 100644
--- a/lib/puppet/indirector/direct_file_server.rb
+++ b/lib/puppet/indirector/direct_file_server.rb
@@ -12,16 +12,14 @@ class Puppet::Indirector::DirectFileServer < Puppet::Indirector::Terminus
include Puppet::FileServing::TerminusHelper
def find(request)
- uri = key2uri(request.key)
- return nil unless FileTest.exists?(uri.path)
- instance = model.new(request.key, :path => uri.path)
+ return nil unless FileTest.exists?(request.key)
+ instance = model.new(request.key)
instance.links = request.options[:links] if request.options[:links]
return instance
end
def search(request)
- uri = key2uri(request.key)
- return nil unless FileTest.exists?(uri.path)
- path2instances(request, uri.path)
+ return nil unless FileTest.exists?(request.key)
+ path2instances(request, request.key)
end
end
diff --git a/lib/puppet/indirector/file_metadata/file.rb b/lib/puppet/indirector/file_metadata/file.rb
index c46015c38..bb586489d 100644
--- a/lib/puppet/indirector/file_metadata/file.rb
+++ b/lib/puppet/indirector/file_metadata/file.rb
@@ -11,7 +11,7 @@ class Puppet::Indirector::FileMetadata::File < Puppet::Indirector::DirectFileSer
def find(request)
return unless data = super
- data.collect_attributes
+ data.collect
return data
end
@@ -19,7 +19,7 @@ class Puppet::Indirector::FileMetadata::File < Puppet::Indirector::DirectFileSer
def search(request)
return unless result = super
- result.each { |instance| instance.collect_attributes }
+ result.each { |instance| instance.collect }
return result
end
diff --git a/lib/puppet/indirector/file_metadata/modules.rb b/lib/puppet/indirector/file_metadata/modules.rb
index 5ed7a8a45..4598c2175 100644
--- a/lib/puppet/indirector/file_metadata/modules.rb
+++ b/lib/puppet/indirector/file_metadata/modules.rb
@@ -11,7 +11,7 @@ class Puppet::Indirector::FileMetadata::Modules < Puppet::Indirector::ModuleFile
def find(*args)
return unless instance = super
- instance.collect_attributes
+ instance.collect
instance
end
end
diff --git a/lib/puppet/indirector/file_server.rb b/lib/puppet/indirector/file_server.rb
index b0df7ff5d..46a590f9c 100644
--- a/lib/puppet/indirector/file_server.rb
+++ b/lib/puppet/indirector/file_server.rb
@@ -25,8 +25,9 @@ class Puppet::Indirector::FileServer < Puppet::Indirector::Terminus
# Find our key using the fileserver.
def find(request)
return nil unless path = find_path(request)
- result = model.new(request.key, :path => path)
+ result = model.new(path)
result.links = request.options[:links] if request.options[:links]
+ result.collect
return result
end
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
index a9fff75b8..04c3aed23 100644
--- a/lib/puppet/indirector/indirection.rb
+++ b/lib/puppet/indirector/indirection.rb
@@ -262,7 +262,11 @@ class Puppet::Indirector::Indirection
return unless terminus.respond_to?(:authorized?)
unless terminus.authorized?(request)
- raise ArgumentError, "Not authorized to call %s on %s with %s" % [request.method, request.key, request.options.inspect]
+ msg = "Not authorized to call %s on %s" % [request.method, request.key]
+ unless request.options.empty?
+ msg += " with %s" % request.options.inspect
+ end
+ raise ArgumentError, msg
end
end
@@ -270,7 +274,9 @@ class Puppet::Indirector::Indirection
def prepare(request)
# Pick our terminus.
if respond_to?(:select_terminus)
- terminus_name = select_terminus(request)
+ unless terminus_name = select_terminus(request)
+ raise ArgumentError, "Could not determine appropriate terminus for %s" % request
+ end
else
terminus_name = terminus_class
end
diff --git a/lib/puppet/indirector/module_files.rb b/lib/puppet/indirector/module_files.rb
index cf5c29cab..7c5cf278f 100644
--- a/lib/puppet/indirector/module_files.rb
+++ b/lib/puppet/indirector/module_files.rb
@@ -21,7 +21,7 @@ class Puppet::Indirector::ModuleFiles < Puppet::Indirector::Terminus
# Make sure our file path starts with /modules, so that we authorize
# against the 'modules' mount.
- path = uri.path =~ /^\/modules/ ? uri.path : "/modules" + uri.path
+ path = uri.path =~ /^modules\// ? uri.path : "modules/" + uri.path
configuration.authorized?(path, :node => request.node, :ipaddress => request.ip)
end
@@ -30,7 +30,7 @@ class Puppet::Indirector::ModuleFiles < Puppet::Indirector::Terminus
def find(request)
return nil unless path = find_path(request)
- result = model.new(request.key, :path => path)
+ result = model.new(path)
result.links = request.options[:links] if request.options[:links]
return result
end
@@ -66,9 +66,8 @@ class Puppet::Indirector::ModuleFiles < Puppet::Indirector::Terminus
def find_path(request)
uri = key2uri(request.key)
- # Strip off /modules if it's there -- that's how requests get routed to this terminus.
- # Also, strip off the leading slash if present.
- module_name, relative_path = uri.path.sub(/^\/modules\b/, '').sub(%r{^/}, '').split(File::Separator, 2)
+ # Strip off modules/ if it's there -- that's how requests get routed to this terminus.
+ module_name, relative_path = uri.path.sub(/^modules\//, '').sub(%r{^/}, '').split(File::Separator, 2)
# And use the environment to look up the module.
return nil unless mod = find_module(module_name, request.node)
diff --git a/lib/puppet/indirector/request.rb b/lib/puppet/indirector/request.rb
index 98fa38885..49cc01aab 100644
--- a/lib/puppet/indirector/request.rb
+++ b/lib/puppet/indirector/request.rb
@@ -1,10 +1,13 @@
require 'puppet/indirector'
-# Provide any attributes or functionality needed for indirected
-# instances.
+# This class encapsulates all of the information you need to make an
+# Indirection call, and as a a result also handles REST calls. It's somewhat
+# analogous to an HTTP Request object, except tuned for our Indirector.
class Puppet::Indirector::Request
attr_accessor :indirection_name, :key, :method, :options, :instance, :node, :ip, :authenticated
+ attr_accessor :server, :port, :uri, :protocol
+
# Is this an authenticated request?
def authenticated?
# Double negative, so we just get true or false
@@ -28,7 +31,15 @@ class Puppet::Indirector::Request
end
if key.is_a?(String) or key.is_a?(Symbol)
- @key = key
+ # If the request key is a URI, then we need to treat it specially,
+ # because it rewrites the key. We could otherwise strip server/port/etc
+ # info out in the REST class, but it seemed bad design for the REST
+ # class to rewrite the key.
+ if key.to_s =~ /^\w+:\/\// # it's a URI
+ set_uri_key(key)
+ else
+ @key = key
+ end
else
@instance = key
@key = @instance.name
@@ -39,4 +50,40 @@ class Puppet::Indirector::Request
def indirection
Puppet::Indirector::Indirection.instance(@indirection_name)
end
+
+ # Are we trying to interact with multiple resources, or just one?
+ def plural?
+ method == :search
+ end
+
+ private
+
+ # Parse the key as a URI, setting attributes appropriately.
+ def set_uri_key(key)
+ @uri = key
+ begin
+ uri = URI.parse(URI.escape(key))
+ rescue => detail
+ raise ArgumentError, "Could not understand URL %s: %s" % [source, detail.to_s]
+ end
+
+ # Just short-circuit these to full paths
+ if uri.scheme == "file"
+ @key = uri.path
+ return
+ end
+
+ @server = uri.host if uri.host
+
+ # If the URI class can look up the scheme, it will provide a port,
+ # otherwise it will default to '0'.
+ if uri.port.to_i == 0 and uri.scheme == "puppet"
+ @port = Puppet.settings[:masterport].to_i
+ else
+ @port = uri.port.to_i
+ end
+
+ @protocol = uri.scheme
+ @key = uri.path.sub(/^\//, '')
+ end
end
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb
index 4389dfb7e..5ac25f02d 100644
--- a/lib/puppet/indirector/rest.rb
+++ b/lib/puppet/indirector/rest.rb
@@ -1,8 +1,33 @@
require 'net/http'
require 'uri'
+require 'puppet/network/http_pool'
+
# Access objects via REST
class Puppet::Indirector::REST < Puppet::Indirector::Terminus
+
+ class << self
+ attr_reader :server_setting, :port_setting
+ end
+
+ # Specify the setting that we should use to get the server name.
+ def self.use_server_setting(setting)
+ @server_setting = setting
+ end
+
+ def self.server
+ return Puppet.settings[server_setting || :server]
+ end
+
+ # Specify the setting that we should use to get the port.
+ def self.use_port_setting(setting)
+ @port_setting = setting
+ end
+
+ def self.port
+ return Puppet.settings[port_setting || :masterport].to_i
+ end
+
# Figure out the content type, turn that into a format, and use the format
# to extract the body of the response.
def deserialize(response, multiple = false)
@@ -33,20 +58,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
end
def network(request)
- if request.key =~ /^\w+:\/\// # it looks like a URI
- begin
- uri = URI.parse(URI.escape(request.key))
- rescue => detail
- raise ArgumentError, "Could not understand URL %s: %s" % [source, detail.to_s]
- end
- server = uri.host || Puppet[:server]
- port = uri.port.to_i == 0 ? Puppet[:masterport].to_i : uri.port.to_i
- else
- server = Puppet[:server]
- port = Puppet[:masterport].to_i
- end
-
- Puppet::Network::HttpPool.http_instance(server, port)
+ Puppet::Network::HttpPool.http_instance(request.server || self.class.server, request.port || self.class.port)
end
def find(request)
@@ -77,7 +89,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
private
- # Create the qurey string, if options are present.
+ # Create the query string, if options are present.
def query_string(request)
return "" unless request.options and ! request.options.empty?
"?" + request.options.collect { |key, value| "%s=%s" % [key, value] }.join("&")
diff --git a/lib/puppet/network/format.rb b/lib/puppet/network/format.rb
index 5f259fa49..21aead7cc 100644
--- a/lib/puppet/network/format.rb
+++ b/lib/puppet/network/format.rb
@@ -5,7 +5,7 @@ require 'puppet/provider/confiner'
class Puppet::Network::Format
include Puppet::Provider::Confiner
- attr_reader :name, :mime
+ attr_reader :name, :mime, :weight
def initialize(name, options = {}, &block)
@name = name.to_s.downcase.intern
@@ -17,6 +17,13 @@ class Puppet::Network::Format
self.mime = "text/%s" % name
end
+ if weight = options[:weight]
+ @weight = weight
+ options.delete(:weight)
+ else
+ @weight = 5
+ end
+
unless options.empty?
raise ArgumentError, "Unsupported option(s) %s" % options.keys
end
@@ -55,7 +62,8 @@ class Puppet::Network::Format
end
def supported?(klass)
- klass.respond_to?(intern_method) and
+ suitable? and
+ klass.respond_to?(intern_method) and
klass.respond_to?(intern_multiple_method) and
klass.respond_to?(render_multiple_method) and
klass.instance_methods.include?(render_method)
diff --git a/lib/puppet/network/format_handler.rb b/lib/puppet/network/format_handler.rb
index 4c9f4e59e..f3c3380e1 100644
--- a/lib/puppet/network/format_handler.rb
+++ b/lib/puppet/network/format_handler.rb
@@ -61,7 +61,10 @@ module Puppet::Network::FormatHandler
end
def supported_formats
- format_handler.formats.collect { |f| format_handler.format(f) }.find_all { |f| f.supported?(self) }.collect { |f| f.name }
+ format_handler.formats.collect { |f| format_handler.format(f) }.find_all { |f| f.supported?(self) }.collect { |f| f.name }.sort do |a, b|
+ # It's an inverse sort -- higher weight formats go first.
+ format_handler.format(b).weight <=> format_handler.format(a).weight
+ end
end
end
diff --git a/lib/puppet/network/formats.rb b/lib/puppet/network/formats.rb
index 8e4c59fb3..85e8ce6f8 100644
--- a/lib/puppet/network/formats.rb
+++ b/lib/puppet/network/formats.rb
@@ -42,7 +42,7 @@ Puppet::Network::FormatHandler.create(:marshal, :mime => "text/marshal") do
Marshal.dump(instance)
end
- # Yaml monkey-patches Array, so this works.
+ # Marshal monkey-patches Array, so this works.
def render_multiple(instances)
Marshal.dump(instances)
end
@@ -54,3 +54,24 @@ Puppet::Network::FormatHandler.create(:marshal, :mime => "text/marshal") do
end
Puppet::Network::FormatHandler.create(:s, :mime => "text/plain")
+
+# A very low-weight format so it'll never get chosen automatically.
+Puppet::Network::FormatHandler.create(:raw, :mime => "application/x-raw", :weight => 1) do
+ def intern_multiple(klass, text)
+ raise NotImplementedError
+ end
+
+ def render_multiple(instances)
+ raise NotImplementedError
+ end
+
+ # LAK:NOTE The format system isn't currently flexible enough to handle
+ # what I need to support raw formats just for individual instances (rather
+ # than both individual and collections), but we don't yet have enough data
+ # to make a "correct" design.
+ # So, we hack it so it works for singular but fail if someone tries it
+ # on plurals.
+ def supported?(klass)
+ true
+ end
+end
diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb
index 183979429..14319ef96 100755
--- a/lib/puppet/network/handler/fileserver.rb
+++ b/lib/puppet/network/handler/fileserver.rb
@@ -75,7 +75,7 @@ class Puppet::Network::Handler
return "" unless metadata.exist?
begin
- metadata.collect_attributes
+ metadata.collect
rescue => detail
puts detail.backtrace if Puppet[:trace]
Puppet.err detail
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb
index 6f5117b16..7c7abccf5 100644
--- a/lib/puppet/network/http/handler.rb
+++ b/lib/puppet/network/http/handler.rb
@@ -12,7 +12,18 @@ module Puppet::Network::HTTP::Handler
# Which format to use when serializing our response. Just picks
# the first value in the accept header, at this point.
def format_to_use(request)
- accept_header(request).split(/,\s*/)[0]
+ unless header = accept_header(request)
+ raise ArgumentError, "An Accept header must be provided to pick the right format"
+ end
+
+ format = nil
+ header.split(/,\s*/).each do |name|
+ next unless format = Puppet::Network::FormatHandler.format(name)
+ next unless format.suitable?
+ return name
+ end
+
+ raise "No specified acceptable formats (%s) are functional on this machine" % header
end
def initialize_for_puppet(args = {})
diff --git a/lib/puppet/network/http/mongrel/rest.rb b/lib/puppet/network/http/mongrel/rest.rb
index d265dde86..45d21ea62 100644
--- a/lib/puppet/network/http/mongrel/rest.rb
+++ b/lib/puppet/network/http/mongrel/rest.rb
@@ -35,7 +35,7 @@ class Puppet::Network::HTTP::MongrelREST < Mongrel::HttpHandler
# return the key included in the request path
def request_key(request)
# LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = request.params[Mongrel::Const::REQUEST_PATH].split('/')[2]
+ x = request.params[Mongrel::Const::REQUEST_PATH].split('/', 3)[2]
end
# return the request body
diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/network/http/webrick/rest.rb
index 13f795fb2..f06914365 100644
--- a/lib/puppet/network/http/webrick/rest.rb
+++ b/lib/puppet/network/http/webrick/rest.rb
@@ -36,7 +36,7 @@ class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet
def request_key(request)
# LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = request.path.split('/')[2]
+ x = request.path.split('/', 3)[2]
end
def body(request)
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 11e8c8248..eb663968e 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -793,7 +793,6 @@ class Type
obj.remove
end
@parameters.clear
- self.class.delete(self)
@parent = nil
@@ -1519,6 +1518,7 @@ class Type
# to an object...
tname, name = value
reference = Puppet::ResourceReference.new(tname, name)
+ reference.catalog = resource.catalog
# Either of the two retrieval attempts could have returned
# nil.
@@ -1932,7 +1932,10 @@ class Type
# Figure out of there are any objects we can automatically add as
# dependencies.
- def autorequire
+ def autorequire(rel_catalog = nil)
+ rel_catalog ||= catalog
+ raise(Puppet::DevError, "You cannot add relationships without a catalog") unless rel_catalog
+
reqs = []
self.class.eachautorequire { |type, block|
# Ignore any types we can't find, although that would be a bit odd.
@@ -1954,11 +1957,11 @@ class Type
next
end
end
-
+
reqs << Puppet::Relationship.new(dep, self)
}
}
-
+
return reqs
end
diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb
index c6ab2570c..370ce1b4f 100644
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@ -155,8 +155,6 @@ module Puppet
engine, so shell metacharacters are fully supported, e.g. ``[a-z]*``.
Matches that would descend into the directory structure are ignored,
e.g., ``*/*``."
-
- defaultto false
validate do |value|
unless value.is_a?(Array) or value.is_a?(String) or value == false
@@ -277,11 +275,6 @@ module Puppet
@depthfirst = false
-
- def argument?(arg)
- @arghash.include?(arg)
- end
-
# Determine the user to write files as.
def asuser
if self.should(:owner) and ! self.should(:owner).is_a?(Symbol)
@@ -329,7 +322,23 @@ module Puppet
# Create any children via recursion or whatever.
def eval_generate
- recurse()
+ return nil unless self.recurse?
+
+ raise(Puppet::DevError, "Cannot generate resources for recursion without a catalog") unless catalog
+
+ recurse.reject do |resource|
+ catalog.resource(:file, resource[:path])
+ end.each do |child|
+ catalog.add_resource child
+ catalog.relationship_graph.add_edge self, child
+ end
+ end
+
+ def flush
+ # We want to make sure we retrieve metadata anew on each transaction.
+ @parameters.each do |name, param|
+ param.flush if param.respond_to?(:flush)
+ end
end
# Deal with backups.
@@ -455,194 +464,21 @@ module Puppet
@title.sub!(/\/$/, "") unless @title == "/"
- # Clean out as many references to any file paths as possible.
- # This was the source of many, many bugs.
- @arghash = tmphash
- @arghash.delete(self.class.namevar)
-
- [:source, :parent].each do |param|
- if @arghash.include?(param)
- @arghash.delete(param)
- end
- end
-
@stat = nil
end
-
- # Build a recursive map of a link source
- def linkrecurse(recurse)
- target = @parameters[:target].should
-
- method = :lstat
- if self[:links] == :follow
- method = :stat
- end
-
- targetstat = nil
- unless FileTest.exist?(target)
- return
- end
- # Now stat our target
- targetstat = File.send(method, target)
- unless targetstat.ftype == "directory"
- return
- end
-
- # Now that we know our corresponding target is a directory,
- # change our type
- self[:ensure] = :directory
-
- unless FileTest.readable? target
- self.notice "Cannot manage %s: permission denied" % self.name
- return
- end
-
- children = Dir.entries(target).reject { |d| d =~ /^\.+$/ }
-
- # Get rid of ignored children
- if @parameters.include?(:ignore)
- children = handleignore(children)
- end
-
- added = []
- children.each do |file|
- Dir.chdir(target) do
- longname = File.join(target, file)
-
- # Files know to create directories when recursion
- # is enabled and we're making links
- args = {
- :recurse => recurse,
- :ensure => longname
- }
-
- if child = self.newchild(file, true, args)
- added << child
- end
- end
- end
-
- added
- end
-
- # Build up a recursive map of what's around right now
- def localrecurse(recurse)
- unless FileTest.exist?(self[:path]) and self.stat.directory?
- #self.info "%s is not a directory; not recursing" %
- # self[:path]
- return
- end
-
- unless FileTest.readable? self[:path]
- self.notice "Cannot manage %s: permission denied" % self.name
- return
- end
-
- children = Dir.entries(self[:path])
-
- #Get rid of ignored children
- if @parameters.include?(:ignore)
- children = handleignore(children)
- end
-
- added = []
- children.each { |file|
- file = File.basename(file)
- next if file =~ /^\.\.?$/ # skip . and ..
- options = {:recurse => recurse}
-
- if child = self.newchild(file, true, options)
- added << child
- end
- }
-
- added
- end
# Create a new file or directory object as a child to the current
# object.
- def newchild(path, local, hash = {})
- raise(Puppet::DevError, "File recursion cannot happen without a catalog") unless catalog
-
- # make local copy of arguments
- args = symbolize_options(@arghash)
-
- # There's probably a better way to do this, but we don't want
- # to pass this info on.
- if v = args[:ensure]
- v = symbolize(v)
- args.delete(:ensure)
- end
-
- if path =~ %r{^#{File::SEPARATOR}}
- self.devfail(
- "Must pass relative paths to PFile#newchild()"
- )
- else
- path = File.join(self[:path], path)
- end
-
- args[:path] = path
-
- unless hash.include?(:recurse)
- if args.include?(:recurse)
- if args[:recurse].is_a?(Integer)
- args[:recurse] -= 1 # reduce the level of recursion
- end
- end
-
- end
-
- hash.each { |key,value|
- args[key] = value
- }
-
- child = nil
-
- # The child might already exist because 'localrecurse' runs
- # before 'sourcerecurse'. I could push the override stuff into
- # a separate method or something, but the work is the same other
- # than this last bit, so it doesn't really make sense.
- if child = catalog.resource(:file, path)
- unless child.parent.object_id == self.object_id
- self.debug "Not managing more explicit file %s" %
- path
- return nil
- end
+ def newchild(path)
+ full_path = File.join(self[:path], path)
- # This is only necessary for sourcerecurse, because we might have
- # created the object with different 'should' values than are
- # set remotely.
- unless local
- args.each { |var,value|
- next if var == :path
- next if var == :name
-
- # behave idempotently
- unless child.should(var) == value
- child[var] = value
- end
- }
- end
- return nil
- else # create it anew
- #notice "Creating new file with args %s" % args.inspect
- args[:parent] = self
- begin
- # This method is used by subclasses of :file, so use the class name rather than hard-coding
- # :file.
- return nil unless child = catalog.create_implicit_resource(self.class.name, args)
- rescue => detail
- self.notice "Cannot manage: %s" % [detail]
- return nil
- end
+ # the right-side hash wins in the merge.
+ options = to_hash.merge(:path => full_path, :implicit => true).reject { |param, value| value.nil? }
+ [:parent, :recurse, :target].each do |param|
+ options.delete(param) if options.include?(param)
end
- # LAK:FIXME This shouldn't be necessary, but as long as we're
- # modeling the relationship graph specifically, it is.
- catalog.relationship_graph.add_edge self, child
-
- return child
+ return self.class.create(options)
end
# Files handle paths specially, because they just lengthen their
@@ -672,70 +508,121 @@ module Puppet
@parameters.include?(:purge) and (self[:purge] == :true or self[:purge] == "true")
end
- # Recurse into the directory. This basically just calls 'localrecurse'
- # and maybe 'sourcerecurse', returning the collection of generated
- # files.
+ def make_children(metadata)
+ metadata.collect { |meta| newchild(meta.relative_path) }
+ end
+
+ # Recursively generate a list of file resources, which will
+ # be used to copy remote files, manage local files, and/or make links
+ # to map to another directory.
def recurse
- # are we at the end of the recursion?
- return unless self.recurse?
-
- recurse = self[:recurse]
- # we might have a string, rather than a number
- if recurse.is_a?(String)
- if recurse =~ /^[0-9]+$/
- recurse = Integer(recurse)
- else # anything else is infinite recursion
- recurse = true
- end
+ children = recurse_local
+
+ if self[:target]
+ recurse_link(children)
+ elsif self[:source]
+ recurse_remote(children)
end
- if recurse.is_a?(Integer)
- recurse -= 1
+ return children.values.sort { |a, b| a[:path] <=> b[:path] }
+ end
+
+ # A simple method for determining whether we should be recursing.
+ def recurse?
+ return false unless @parameters.include?(:recurse)
+
+ val = @parameters[:recurse].value
+
+ if val and (val == true or val > 0)
+ return true
+ else
+ return false
end
-
- children = []
-
- # We want to do link-recursing before normal recursion so that all
- # of the target stuff gets copied over correctly.
- if @parameters.include? :target and ret = self.linkrecurse(recurse)
- children += ret
+ end
+
+ # Recurse the target of the link.
+ def recurse_link(children)
+ perform_recursion(self[:target]).each do |meta|
+ if meta.relative_path == "."
+ self[:ensure] = :directory
+ next
+ end
+
+ children[meta.relative_path] ||= newchild(meta.relative_path)
+ if meta.ftype == "directory"
+ children[meta.relative_path][:ensure] = :directory
+ else
+ children[meta.relative_path][:ensure] = :link
+ children[meta.relative_path][:target] = meta.full_path
+ end
+ end
+ children
+ end
+
+ # Recurse the file itself, returning a Metadata instance for every found file.
+ def recurse_local
+ result = perform_recursion(self[:path])
+ return {} unless result
+ result.inject({}) do |hash, meta|
+ next hash if meta.relative_path == "."
+
+ hash[meta.relative_path] = newchild(meta.relative_path)
+ hash
end
- if ret = self.localrecurse(recurse)
- children += ret
+ end
+
+ # Recurse against our remote file.
+ def recurse_remote(children)
+ sourceselect = self[:sourceselect]
+
+ total = self[:source].collect do |source|
+ next unless result = perform_recursion(source)
+ result.each { |data| data.source = "%s/%s" % [source, data.relative_path] }
+ break result if result and ! result.empty? and sourceselect == :first
+ result
+ end.flatten
+
+ # This only happens if we have sourceselect == :all
+ unless sourceselect == :first
+ found = []
+ total.reject! do |data|
+ result = found.include?(data.relative_path)
+ found << data.relative_path unless found.include?(data.relative_path)
+ result
+ end
end
- # These will be files pulled in by the file source
- sourced = false
- if @parameters.include?(:source)
- ret, sourced = self.sourcerecurse(recurse)
- if ret
- children += ret
+ total.each do |meta|
+ if meta.relative_path == "."
+ property(:source).metadata = meta
+ next
end
+ children[meta.relative_path] ||= newchild(meta.relative_path)
+ children[meta.relative_path][:source] = meta.source
+ children[meta.relative_path][:checksum] = :md5 if meta.ftype == "file"
+
+ children[meta.relative_path].property(:source).metadata = meta
end
- # The purge check needs to happen after all of the other recursion.
+ # If we're purging resources, then delete any resource that isn't on the
+ # remote system.
if self.purge?
- children.each do |child|
- if (sourced and ! sourced.include?(child[:path])) or ! child.managed?
+ # Make a hash of all of the resources we found remotely -- all we need is the
+ # fast lookup, the values don't matter.
+ remotes = total.inject({}) { |hash, meta| hash[meta.relative_path] = true; hash }
+
+ children.each do |name, child|
+ unless remotes.include?(name)
child[:ensure] = :absent
end
end
end
-
+
children
end
- # A simple method for determining whether we should be recursing.
- def recurse?
- return false unless @parameters.include?(:recurse)
-
- val = @parameters[:recurse].value
-
- if val and (val == true or val > 0)
- return true
- else
- return false
- end
+ def perform_recursion(path)
+ Puppet::FileServing::Metadata.search(path, :links => self[:links], :recurse => self[:recurse], :ignore => self[:ignore])
end
# Remove the old backup.
@@ -796,108 +683,22 @@ module Puppet
# a wrapper method to make sure the file exists before doing anything
def retrieve
unless stat = self.stat(true)
- # If the file doesn't exist but we have a source, then call
- # retrieve on that property
propertyvalues = properties().inject({}) { |hash, property|
hash[property] = :absent
hash
}
+ # If the file doesn't exist but we have a source, then call
+ # retrieve on the source property so it will set the 'should'
+ # values all around.
if @parameters.include?(:source)
- propertyvalues[:source] = @parameters[:source].retrieve
+ @parameters[:source].copy_source_values
end
return propertyvalues
end
- return currentpropvalues()
- end
-
- # This recurses against the remote source and makes sure the local
- # and remote structures match. It's run after 'localrecurse'. This
- # method only does anything when its corresponding remote entry is
- # a directory; in that case, this method creates file objects that
- # correspond to any contained remote files.
- def sourcerecurse(recurse)
- # we'll set this manually as necessary
- if @arghash.include?(:ensure)
- @arghash.delete(:ensure)
- end
-
- r = false
- if recurse
- unless recurse == 0
- r = 1
- end
- end
-
- ignore = self[:ignore]
-
- result = []
- found = []
-
- # Keep track of all the files we found in the source, so we can purge
- # appropriately.
- sourced = []
-
- success = false
-
- @parameters[:source].should.each do |source|
- sourceobj, path = uri2obj(source)
-
- # okay, we've got our source object; now we need to
- # build up a local file structure to match the remote
- # one
-
- server = sourceobj.server
-
- desc = server.list(path, self[:links], r, ignore)
- if desc == ""
- next
- end
-
- success = true
-
- # Now create a new child for every file returned in the list.
- result += desc.split("\n").collect { |line|
- file, type = line.split("\t")
- next if file == "/" # skip the listing object
- name = file.sub(/^\//, '')
-
- # This makes sure that the first source *always* wins
- # for conflicting files.
- next if found.include?(name)
-
- # For directories, keep all of the sources, so that
- # sourceselect still works as planned.
- if type == "directory"
- newsource = @parameters[:source].should.collect do |tmpsource|
- tmpsource + file
- end
- else
- newsource = source + file
- end
- args = {:source => newsource}
- if type == file
- args[:recurse] = nil
- end
-
- found << name
- sourced << File.join(self[:path], name)
-
- self.newchild(name, false, args)
- }.reject {|c| c.nil? }
-
- if self[:sourceselect] == :first
- return [result, sourced]
- end
- end
-
- unless success
- raise Puppet::Error, "None of the provided sources exist"
- end
-
- return [result, sourced]
+ currentpropvalues()
end
# Set the checksum, from another property. There are multiple
diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb
index 2514d3d1e..e43706051 100755
--- a/lib/puppet/type/file/source.rb
+++ b/lib/puppet/type/file/source.rb
@@ -1,3 +1,7 @@
+
+require 'puppet/file_serving/content'
+require 'puppet/file_serving/metadata'
+
module Puppet
# Copy files from a local or remote source. This state *only* does any work
# when the remote file is an actual file; in that case, this state copies
@@ -62,8 +66,14 @@ module Puppet
uncheckable
validate do |source|
- unless @resource.uri2obj(source)
- raise Puppet::Error, "Invalid source %s" % source
+ begin
+ uri = URI.parse(URI.escape(source))
+ rescue => detail
+ self.fail "Could not understand source %s: %s" % [source, detail.to_s]
+ end
+
+ unless uri.scheme.nil? or %w{file puppet}.include?(uri.scheme)
+ self.fail "Cannot use URLs of type '%s' as source for fileserving" % [uri.scheme]
end
end
@@ -77,72 +87,67 @@ module Puppet
end
def change_to_s(currentvalue, newvalue)
- # newvalue = "{md5}" + @stats[:checksum]
+ # newvalue = "{md5}" + @metadata.checksum
if @resource.property(:ensure).retrieve == :absent
- return "creating from source %s with contents %s" % [@source, @stats[:checksum]]
+ return "creating from source %s with contents %s" % [metadata.source, @metadata.checksum]
else
- return "replacing from source %s with contents %s" % [@source, @stats[:checksum]]
+ return "replacing from source %s with contents %s" % [metadata.source, @metadata.checksum]
end
end
def checksum
- if defined?(@stats)
- @stats[:checksum]
+ if defined?(@metadata)
+ @metadata.checksum
else
nil
end
end
- # Ask the file server to describe our file.
- def describe(source)
- sourceobj, path = @resource.uri2obj(source)
- server = sourceobj.server
+ # Look up (if necessary) and return remote content.
+ def content
+ raise Puppet::DevError, "No source for content was stored with the metadata" unless metadata.source
- begin
- desc = server.describe(path, @resource[:links])
- rescue Puppet::Network::XMLRPCClientError => detail
- fail detail, "Could not describe %s: %s" % [path, detail]
+ unless defined?(@content) and @content
+ unless tmp = Puppet::FileServing::Content.find(@metadata.source)
+ fail "Could not find any content at %s" % @metadata.source
+ end
+ @content = tmp.content
end
+ @content
+ end
- return nil if desc == ""
+ # Copy the values from the source to the resource. Yay.
+ def copy_source_values
+ devfail "Somehow got asked to copy source values without any metadata" unless metadata
- # Collect everything except the checksum
- values = desc.split("\t")
- other = values.pop
- args = {}
- pinparams.zip(values).each { |param, value|
- if value =~ /^[0-9]+$/
- value = value.to_i
- end
- unless value.nil?
- args[param] = value
+ # Take each of the stats and set them as states on the local file
+ # if a value has not already been provided.
+ [:owner, :mode, :group, :checksum].each do |param|
+ next if param == :owner and Puppet::Util::SUIDManager.uid != 0
+ unless value = @resource[param] and value != :absent
+ @resource[param] = metadata.send(param)
end
- }
-
- # Now decide whether we're doing checksums or symlinks
- if args[:type] == "link"
- args[:target] = other
- else
- args[:checksum] = other
end
- # we can't manage ownership unless we're root, so don't even try
- unless Puppet::Util::SUIDManager.uid == 0
- args.delete(:owner)
+ @resource[:ensure] = metadata.ftype
+
+ if metadata.ftype == "link"
+ @resource[:target] = metadata.destination
end
-
- return args
end
-
- # Use the info we get from describe() to check if we're in sync.
+
+ # Remove any temporary attributes we manage.
+ def flush
+ @metadata = nil
+ @content = nil
+ end
+
+ # Use the remote metadata to see if we're in sync.
+ # LAK:NOTE This method should still get refactored.
def insync?(currentvalue)
- if currentvalue == :nocopy
- return true
- end
-
# the only thing this actual state can do is copy files around. Therefore,
# only pay attention if the remote is a file.
- unless @stats[:type] == "file"
+ unless @metadata.ftype == "file"
return true
end
@@ -153,15 +158,13 @@ module Puppet
end
# Now, we just check to see if the checksums are the same
parentchecksum = @resource.property(:checksum).retrieve
- result = (!parentchecksum.nil? and (parentchecksum == @stats[:checksum]))
+ result = (!parentchecksum.nil? and (parentchecksum == @metadata.checksum))
# Diff the contents if they ask it. This is quite annoying -- we need to do this in
# 'insync?' because they might be in noop mode, but we don't want to do the file
# retrieval twice, so we cache the value.
- if ! result and Puppet[:show_diff] and File.exists?(@resource[:path]) and ! @stats[:_diffed]
- @stats[:_remote_content] = get_remote_content
- string_file_diff(@resource[:path], @stats[:_remote_content])
- @stats[:_diffed] = true
+ if ! result and Puppet[:show_diff] and File.exists?(@resource[:path])
+ string_file_diff(@resource[:path], content)
end
return result
end
@@ -171,57 +174,39 @@ module Puppet
end
def found?
- ! (@stats.nil? or @stats[:type].nil?)
+ ! (@metadata.nil? or @metadata.ftype.nil?)
end
- # This basically calls describe() on our file, and then sets all
- # of the local states appropriately. If the remote file is a normal
- # file then we set it to copy; if it's a directory, then we just mark
- # that the local directory should be created.
- def retrieve(remote = true)
- sum = nil
- @source = nil
-
- # This is set to false by the File#retrieve function on the second
- # retrieve, so that we do not do two describes.
- if remote
- # Find the first source that exists. @shouldorig contains
- # the sources as specified by the user.
- @should.each { |source|
- if @stats = self.describe(source)
- @source = source
- break
+ # Provide, and retrieve if necessary, the metadata for this file. Fail
+ # if we can't find data about this host, and fail if there are any
+ # problems in our query.
+ attr_writer :metadata
+ def metadata
+ unless defined?(@metadata) and @metadata
+ return @metadata = nil unless should
+ should.each do |source|
+ begin
+ if data = Puppet::FileServing::Metadata.find(source)
+ @metadata = data
+ @metadata.source = source
+ break
+ end
+ rescue => detail
+ fail detail, "Could not retrieve file metadata for %s: %s" % [source, detail]
end
- }
- end
-
- if !found?
- raise Puppet::Error, "No specified source was found from" + @should.inject("") { |s, source| s + " #{source},"}.gsub(/,$/,"")
- end
-
- case @stats[:type]
- when "directory", "file", "link":
- @resource[:ensure] = @stats[:type] unless @resource.deleting?
- else
- self.info @stats.inspect
- self.err "Cannot use files of type %s as sources" % @stats[:type]
- return :nocopy
+ end
+ fail "Could not retrieve information from source(s) %s" % @should.join(", ") unless @metadata
end
+ return @metadata
+ end
- # Take each of the stats and set them as states on the local file
- # if a value has not already been provided.
- @stats.each { |stat, value|
- next if stat == :checksum
- next if stat == :type
-
- # was the stat already specified, or should the value
- # be inherited from the source?
- @resource[stat] = value unless @resource.argument?(stat)
- }
-
- return @stats[:checksum]
+ # Just call out to our copy method. Hopefully we'll refactor 'source' to
+ # be a parameter soon, in which case 'retrieve' is unnecessary.
+ def retrieve
+ copy_source_values
end
+ # Return the whole array, rather than the first item.
def should
@should
end
@@ -238,11 +223,9 @@ module Puppet
end
def sync
- contents = @stats[:_remote_content] || get_remote_content()
-
- exists = File.exists?(@resource[:path])
+ exists = FileTest.exist?(@resource[:path])
- @resource.write(contents, :source, @stats[:checksum])
+ @resource.write(content, :source, @metadata.checksum)
if exists
return :file_changed
@@ -250,27 +233,5 @@ module Puppet
return :file_created
end
end
-
- private
-
- def get_remote_content
- raise Puppet::DevError, "Got told to copy non-file %s" % @resource[:path] unless @stats[:type] == "file"
-
- sourceobj, path = @resource.uri2obj(@source)
-
- begin
- contents = sourceobj.server.retrieve(path, @resource[:links])
- rescue => detail
- self.fail "Could not retrieve %s: %s" % [path, detail]
- end
-
- contents = CGI.unescape(contents) unless sourceobj.server.local
-
- if contents == ""
- self.notice "Could not retrieve contents for %s" % @source
- end
-
- return contents
- end
end
end