diff options
Diffstat (limited to 'lib/puppet/network/handler/fileserver.rb')
-rwxr-xr-x | lib/puppet/network/handler/fileserver.rb | 249 |
1 files changed, 174 insertions, 75 deletions
diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb index dd00450be..dd8cfbf58 100755 --- a/lib/puppet/network/handler/fileserver.rb +++ b/lib/puppet/network/handler/fileserver.rb @@ -17,6 +17,7 @@ class Puppet::Network::Handler # Special filserver module for puppet's module system MODULES = "modules" + PLUGINS = "plugins" @interface = XMLRPC::Service::Interface.new("fileserver") { |iface| iface.add_method("string describe(string, string)") @@ -99,6 +100,7 @@ class Puppet::Network::Handler end } self.mount(nil, MODULES) + self.mount(nil, PLUGINS) else @passedconfig = false readconfig(false) # don't check the file the first time. @@ -114,13 +116,11 @@ class Puppet::Network::Handler end obj = nil - unless FileTest.exists?(path) + unless mount.path_exists?(path) return "" end - # We pass two paths here, but reclist internally changes one - # of the arguments when called internally. - desc = reclist(mount, path, path, recurse, ignore) + desc = mount.list(path, recurse, ignore) if desc.length == 0 mount.notice "Got no information on //%s/%s" % @@ -167,13 +167,15 @@ class Puppet::Network::Handler mount.info "Sending %s to %s" % [url, client] end - unless FileTest.exists?(path) + unless mount.path_exists?(path) + mount.debug "#{mount} reported that #{path} does not exist" return "" end links = links.intern if links.is_a? String if links == :ignore and FileTest.symlink?(path) + mount.debug "I think that #{path} is a symlink and we're ignoring them" return "" end @@ -181,7 +183,7 @@ class Puppet::Network::Handler if links == :manage raise Puppet::Error, "Cannot copy links yet." else - str = File.read(path) + str = mount.read_file(path) end if @local @@ -210,6 +212,9 @@ class Puppet::Network::Handler end end + # Take a URL and some client info and return a mount and relative + # path pair. + # def convert(url, client, clientip) readconfig @@ -219,26 +224,9 @@ class Puppet::Network::Handler authcheck(url, mount, client, clientip) - path = nil - unless path = mount.subdir(stub, client) - mount.notice "Could not find subdirectory %s" % - "//%s/%s" % [mount, stub] - return "" - end - - return mount, path + return mount, stub end - # Deal with ignore parameters. - def handleignore(children, path, ignore) - ignore.each { |ignore| - Dir.glob(File.join(path,ignore), File::FNM_DOTMATCH) { |match| - children.delete(File.basename(match)) - } - } - return children - end - # Return the mount for the Puppet modules; allows file copying from # the modules. def modules_mount(module_name, client) @@ -291,8 +279,8 @@ class Puppet::Network::Handler value = $2 case var when "path": - if mount.name == MODULES - Puppet.warning "The '#{MODULES}' module can not have a path. Ignoring attempt to set it" + if mount.name == MODULES or mount.name == PLUGINS + Puppet.warning "The '#{mount.name}' module can not have a path. Ignoring attempt to set it" else begin mount.path = value @@ -349,6 +337,12 @@ class Puppet::Network::Handler mount.allow("*") newmounts[MODULES] = mount end + + unless newmounts[PLUGINS] + mount = PluginMount.new(PLUGINS) + mount.allow("*") + newmounts[PLUGINS] = mount + end # Verify each of the mounts are valid. # We let the check raise an error, so that it can raise an error @@ -362,54 +356,13 @@ class Puppet::Network::Handler @mounts = newmounts end - # 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 = "/" - end - - if name == path - raise FileServerError, "Could not match %s in %s" % - [root, path] - end - - desc = [name] - ftype = File.stat(path).ftype - - desc << ftype - if recurse.is_a?(Integer) - recurse -= 1 - end - - ary = [desc] - if recurse == true or (recurse.is_a?(Integer) and recurse > -1) - if ftype == "directory" - children = Dir.entries(path) - if ignore - children = handleignore(children, path, ignore) - end - children.each { |child| - next if child =~ /^\.\.?$/ - reclist(mount, root, File.join(path, child), recurse, ignore).each { |cobj| - ary << cobj - } - } - end - end - - return ary.reject { |c| c.nil? } - end - # Split the path into the separate mount point and path. def splitpath(dir, client) # the dir is based on one of the mounts # so first retrieve the mount path mount = nil path = nil - if dir =~ %r{/([-\w]+)/?} + if dir =~ %r{/([-\w]+)} # Strip off the mount name. mount_name, path = dir.sub(%r{^/}, '').split(File::Separator, 2) @@ -422,8 +375,8 @@ class Puppet::Network::Handler raise FileServerError, "Fileserver error: Invalid path '%s'" % dir end - if path == "" - path = nil + if path.nil? or path == '' + path = '/' elsif path # Remove any double slashes that might have occurred path = URI.unescape(path.gsub(/\/\//, "/")) @@ -449,7 +402,7 @@ class Puppet::Network::Handler Puppet::Util.logmethods(self, true) def getfileobject(dir, links) - unless FileTest.exists?(dir) + unless path_exists?(dir) self.debug "File source %s does not exist" % dir return nil end @@ -556,7 +509,7 @@ class Puppet::Network::Handler def fileobj(path, links) obj = nil - if obj = Puppet.type(:file)[path] + if obj = Puppet.type(:file)[real_path(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 @@ -564,7 +517,7 @@ class Puppet::Network::Handler obj[:check] = CHECKPARAMS else obj = Puppet.type(:file).create( - :name => path, + :name => real_path(path), :check => CHECKPARAMS ) end @@ -581,6 +534,17 @@ class Puppet::Network::Handler return obj end + # Read the contents of the file at the relative path given. + def read_file(relpath) + File.read(real_path(relpath)) + end + + # Determine the real path on disk for the given mount-relative + # path + def real_path(relpath) + File.join(self.path(nil), relpath) + end + # Cache this manufactured map, since if it's used it's likely # to get used a lot. def localmap @@ -626,6 +590,12 @@ class Puppet::Network::Handler @path = path end + # Verify that the path given exists within this mount's subtree. + # + def path_exists?(relpath) + File.exists?(File.join(path(nil), relpath)) + end + # Return the current values for the object. def properties(obj) obj.retrieve.inject({}) { |props, ary| props[ary[0].name] = ary[1]; props } @@ -637,7 +607,7 @@ class Puppet::Network::Handler basedir = self.path(client) dirname = if dir - File.join(basedir, dir.split("/").join(File::SEPARATOR)) + File.join(basedir, *dir.split("/")) else basedir end @@ -657,7 +627,7 @@ class Puppet::Network::Handler # Verify our configuration is valid. This should really check to # make sure at least someone will be allowed, but, eh. def valid? - if name == MODULES + if name == MODULES or name == PLUGINS return @path.nil? else return ! @path.nil? @@ -672,6 +642,135 @@ class Puppet::Network::Handler result.instance_variable_set(:@name, name) return result end + + # List the contents of the relative path +relpath+ of this mount. + # + # +recurse+ is the number of levels to recurse into the tree, + # or false to provide no recursion or true if you just want to + # go for broke. + # + # +ignore+ is an array of filenames to ignore when traversing + # the list. + # + # The return value of this method is a complex nest of arrays, + # which describes a directory tree. Each file or directory is + # represented by an array, where the first element is the path + # of the file (relative to the root of the mount), and the + # second element is the type. A directory is represented by an + # array as well, where the first element is a "directory" array, + # while the remaining elements are other file or directory + # arrays. Confusing? Hell yes. + # + def list(relpath, recurse, ignore) + reclist(File.join(path(nil), relpath), nil, recurse, ignore) + end + + # Recursively list the files in this tree. + def reclist(basepath, abspath, recurse, ignore) + abspath = basepath if abspath.nil? + relpath = abspath.sub(%r{^#{basepath}}, '') + relpath = '/' if relpath == '' + + desc = [relpath] + + ftype = File.stat(abspath).ftype + + desc << ftype + if recurse.is_a?(Integer) + recurse -= 1 + end + + ary = [desc] + if recurse == true or (recurse.is_a?(Integer) and recurse > -1) + if ftype == "directory" + children = Dir.entries(abspath) + if ignore + children = handleignore(children, relpath, ignore) + end + children.each { |child| + next if child =~ /^\.\.?$/ + reclist(basepath, File.join(abspath, child), recurse, ignore).each { |cobj| + ary << cobj + } + } + end + end + + return ary.compact + end + + # Deal with ignore parameters. + def handleignore(children, path, ignore) + ignore.each { |ignore| + Dir.glob(File.join(path,ignore), File::FNM_DOTMATCH) { |match| + children.delete(File.basename(match)) + } + } + return children + end + end + + # A special mount class specifically for the plugins mount -- just + # has some magic to effectively do a union mount of the 'plugins' + # directory of all modules. + # + class PluginMount < Mount + def path(client) + '' + end + + def path_exists?(relpath) + !valid_modules.find { |m| File.exists?(File.join(m, PLUGINS, relpath)) }.nil? + end + + def real_path(relpath) + mod = valid_modules.map { |m| File.exists?(File.join(m, PLUGINS, relpath)) ? m : nil }.compact.first + File.join(mod, PLUGINS, relpath) + end + + def reclist(basepath, abspath, recurse, ignore) + abspath = basepath if abspath.nil? + relpath = abspath.sub(%r{^#{basepath}}, '') + relpath = "/#{relpath}" unless relpath[0] == ?/ #/ + + desc = [relpath] + + ftype = File.stat(real_path(abspath)).ftype + + desc << ftype + if recurse.is_a?(Integer) + recurse -= 1 + end + + ary = [desc] + if recurse == true or (recurse.is_a?(Integer) and recurse > -1) + if ftype == "directory" + valid_modules.each do |mod| + children = Dir.entries(File.join(mod, PLUGINS, abspath)) + if ignore + children = handleignore(children, relpath, ignore) + end + children.each { |child| + next if child =~ /^\.\.?$/ + reclist(basepath, File.join(abspath, child), recurse, ignore).each { |cobj| + ary << cobj + } + } + end + end + end + + return ary.compact + end + + private + def valid_modules + Puppet::Module.all.find_all { |m| File.directory?(File.join(m, PLUGINS)) } + end + + def add_to_filetree(f, filetree) + first, rest = f.split(File::SEPARATOR, 2) + end end end end |