lib/puppet/server/fileserver.rb in puppet-0.13.6 vs lib/puppet/server/fileserver.rb in puppet-0.16.0

- old
+ new

@@ -1,12 +1,12 @@ require 'puppet' require 'webrick/httpstatus' require 'cgi' module Puppet +class FileServerError < Puppet::Error; end class Server - class FileServerError < Puppet::Error; end class FileServer < Handler attr_accessor :local Puppet.setdefaults("fileserver", :fileserverconfig => ["$confdir/fileserver.conf", @@ -14,76 +14,64 @@ #CHECKPARAMS = %w{checksum type mode owner group} CHECKPARAMS = [:mode, :type, :owner, :group, :checksum] @interface = XMLRPC::Service::Interface.new("fileserver") { |iface| - iface.add_method("string describe(string)") - iface.add_method("string list(string, boolean, array)") - iface.add_method("string retrieve(string)") + iface.add_method("string describe(string, string)") + iface.add_method("string list(string, string, boolean, array)") + iface.add_method("string retrieve(string, string)") } def authcheck(file, mount, client, clientip) unless mount.allowed?(client, clientip) - Puppet.warning "%s cannot access %s in %s" % - [client, mount, file] + mount.warning "%s cannot access %s" % + [client, file] raise Puppet::Server::AuthorizationError, "Cannot access %s" % mount end end - # Run 'retrieve' on a file. This gets the actual parameters, so - # we can pass them to the client. - def check(dir) - unless FileTest.exists?(dir) - Puppet.notice "File source %s does not exist" % dir - return nil - end - - obj = nil - unless obj = Puppet.type(:file)[dir] - obj = Puppet.type(:file).create( - :name => dir, - :check => CHECKPARAMS - ) - end - # we should really have a timeout here -- we don't - # want to actually check on every connection, maybe no more - # than every 60 seconds or something - #@files[mount].evaluate - obj.evaluate - - return obj - end - # Describe a given file. This returns all of the manageable aspects # of that file. - def describe(file, client = nil, clientip = nil) + def describe(file, links = :ignore, client = nil, clientip = nil) readconfig + + links = links.intern if links.is_a? String + + if links == :manage + raise Puppet::FileServerError, "Cannot currently copy links" + end + mount, path = splitpath(file) authcheck(file, mount, client, clientip) if client - Puppet.debug "Describing %s for %s" % [file, client] + mount.debug "Describing %s for %s" % [file, client] end sdir = nil unless sdir = subdir(mount, path) mount.notice "Could not find subdirectory %s" % "//%s/%s" % [mount, path] return "" end obj = nil - unless obj = self.check(sdir) + unless obj = mount.check(sdir, links) return "" end + #if links == :ignore and obj[:type] == "link" + # mount.info "Ignoring link %s" % obj.name + # return "" + #end + desc = [] CHECKPARAMS.each { |check| if state = obj.state(check) unless state.is - mount.notice "Manually retrieving info for %s" % check + mount.debug "Manually retrieving info for %s" % check state.retrieve end desc << state.is else if check == "checksum" and obj.state(:type).is == "file" @@ -146,18 +134,18 @@ readconfig end end # List a specific directory's contents. - def list(dir, recurse = false, ignore = false, client = nil, clientip = nil) + def list(dir, links = :ignore, recurse = false, ignore = false, client = nil, clientip = nil) readconfig mount, path = splitpath(dir) authcheck(dir, mount, client, clientip) if client - Puppet.debug "Listing %s for %s" % [dir, client] + mount.debug "Listing %s for %s" % [dir, client] end subdir = nil unless subdir = subdir(mount, path) mount.notice "Could not find subdirectory %s" % @@ -197,11 +185,11 @@ end if FileTest.directory?(path) if FileTest.readable?(path) @mounts[name] = Mount.new(name, path) - @mounts[name].info "Mounted" + @mounts[name].info "Mounted %s" % path else raise FileServerError, "%s is not readable" % path end else raise FileServerError, "%s is not a directory" % path @@ -309,18 +297,19 @@ @configstatted = Time.now end # Retrieve a file from the local disk and pass it to the remote # client. - def retrieve(file, client = nil, clientip = nil) + def retrieve(file, links = :ignore, client = nil, clientip = nil) readconfig + links = links.intern if links.is_a? String mount, path = splitpath(file) authcheck(file, mount, client, clientip) if client - Puppet.info "Sending %s to %s" % [file, client] + mount.info "Sending %s to %s" % [file, client] end fpath = nil if path fpath = File.join(mount.path, path) @@ -330,12 +319,23 @@ unless FileTest.exists?(fpath) return "" end - str = File.read(fpath) + links = links.intern if links.is_a? String + if links == :ignore and FileTest.symlink?(fpath) + return "" + end + + str = nil + if links == :manage + raise Puppet::Error, "Cannot copy links yet." + else + str = File.read(fpath) + end + if @local return str else return CGI.escape(str) end @@ -351,11 +351,12 @@ name.sub(/\/#{mount.name}/, mount.path).gsub(%r{/+}, '/').sub( %r{/$}, '' ) end - # Recursively list the directory. + # Recursively list the directory. FIXME This should be using + # puppet objects, not directly listing. def reclist(mount, root, path, recurse, ignore) # Take out the root of the path. name = path.sub(root, '') if name == "" name = "/" @@ -439,18 +440,47 @@ end dirname end + def to_s + "fileserver" + end + # A simple class for wrapping mount points. Instances of this class # don't know about the enclosing object; they're mainly just used for # authorization. class Mount < AuthStore attr_reader :path, :name Puppet::Util.logmethods(self, true) + # Run 'retrieve' on a file. This gets the actual parameters, so + # we can pass them to the client. + def check(dir, links) + unless FileTest.exists?(dir) + self.notice "File source %s does not exist" % dir + return nil + end + + obj = fileobj(dir, links) + + # FIXME we should really have a timeout here -- we don't + # want to actually check on every connection, maybe no more + # than every 60 seconds or something. It'd be nice if we + # could use the builtin scheduling to do this. + + # Retrieval is enough here, because we don't want to cache + # any information in the state file, and we don't want to generate + # any state changes or anything. We don't even need to sync + # the checksum, because we're always going to hit the disk + # directly. + obj.retrieve + + return obj + end + # Create out orbject. It must have a name. def initialize(name, path = nil) unless name =~ %r{^\w+$} raise FileServerError, "Invalid name format '%s'" % name end @@ -460,29 +490,68 @@ self.path = path else @path = nil end + @comp = Puppet.type(:component).create( + :name => "mount[#{name}]" + ) + #@comp.type = "mount" + #@comp.name = name + super() end + def fileobj(path, links) + obj = nil + if obj = Puppet.type(:file)[path] + # This can only happen in local fileserving, but it's an + # important one. It'd be nice if we didn't just set + # the check params every time, but I'm not sure it's worth + # the effort. + obj[:check] = CHECKPARAMS + else + obj = Puppet.type(:file).create( + :name => path, + :check => CHECKPARAMS + ) + + @comp.push(obj) + end + + if links == :manage + links = :follow + end + + # This, ah, might be completely redundant + unless obj[:links] == links + obj[:links] = links + end + + return obj + end + # Set the path. def path=(path) unless FileTest.exists?(path) raise FileServerError, "%s does not exist" % path end @path = path end def to_s - if @path - @name + ":" + @path - else - @name - end + #if @path + # "mount[#{@name}]" + ":" + @path + #else + # "mount[#{@name}]" + #end + "mount[#{@name}]" end + def type?(file) + end + # Verify our configuration is valid. This should really check to # make sure at least someone will be allowed, but, eh. def valid? unless @path raise FileServerError, "No path specified" @@ -491,6 +560,6 @@ end end end end -# $Id: fileserver.rb 962 2006-03-01 22:28:27Z luke $ +# $Id: fileserver.rb 989 2006-03-06 21:19:34Z luke $