diff options
Diffstat (limited to 'lib/puppet/network')
| -rwxr-xr-x | lib/puppet/network/handler/fileserver.rb | 84 | ||||
| -rw-r--r-- | lib/puppet/network/handler/master.rb | 2 | ||||
| -rw-r--r-- | lib/puppet/network/http_server/rack.rb | 148 | ||||
| -rw-r--r-- | lib/puppet/network/xmlrpc/client.rb | 9 |
4 files changed, 191 insertions, 52 deletions
diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb index 14319ef96..160dab1bb 100755 --- a/lib/puppet/network/handler/fileserver.rb +++ b/lib/puppet/network/handler/fileserver.rb @@ -70,7 +70,9 @@ class Puppet::Network::Handler mount.debug("Describing %s for %s" % [url, client]) if client # use the mount to resolve the path for us. - metadata = Puppet::FileServing::Metadata.new(url, :path => mount.file_path(path, client), :links => links) + return "" unless full_path = mount.file_path(path, client) + + metadata = Puppet::FileServing::Metadata.new(url, :path => full_path, :links => links) return "" unless metadata.exist? @@ -654,55 +656,38 @@ class Puppet::Network::Handler # and "bad batch". # def list(relpath, recurse, ignore, client = nil) - reclist(file_path(relpath, client), 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 = "/#{relpath}" if relpath[0] != ?/ #/ - - return unless FileTest.exists?(abspath) - - desc = [relpath] - - ftype = File.stat(abspath).ftype - - desc << ftype - if recurse.is_a?(Integer) - recurse -= 1 + abspath = file_path(relpath, client) + if FileTest.exists?(abspath) + if FileTest.directory?(abspath) and recurse + return reclist(abspath, recurse, ignore) + else + return [["/", File.stat(abspath).ftype]] + end end + return nil + 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, abspath, ignore) - end - children.each { |child| - next if child =~ /^\.\.?$/ - reclist(basepath, File.join(abspath, child), recurse, ignore).each { |cobj| - ary << cobj - } - } + def reclist(abspath, recurse, ignore) + require 'puppet/file_serving' + require 'puppet/file_serving/fileset' + args = { :recurse => recurse, :links => :follow } + args[:ignore] = ignore if ignore + fs = Puppet::FileServing::Fileset.new(abspath, args) + ary = fs.files.collect do |file| + if file == "." + file = "/" + else + file = File.join("/", file ) end + stat = fs.stat(File.join(abspath, file)) + next if stat.nil? + [ file, stat.ftype ] end return ary.compact end - # Deal with ignore parameters. - def handleignore(files, path, ignore_patterns) - ignore_patterns.each do |ignore| - files.delete_if do |entry| - File.fnmatch(ignore, entry, File::FNM_DOTMATCH) - end - end - return files - end - end + end # A special mount class specifically for the plugins mount -- just # has some magic to effectively do a union mount of the 'plugins' @@ -730,7 +715,7 @@ class Puppet::Network::Handler end def file_path(relpath, client = nil) - mod = valid_modules.map { |m| mod_path_exists?(m, relpath, client) ? m : nil }.compact.first + return nil unless mod = valid_modules.map { |m| mod_path_exists?(m, relpath, client) ? m : nil }.compact.first mod_file_path(mod, relpath, client) end @@ -738,9 +723,16 @@ class Puppet::Network::Handler def list(relpath, recurse, ignore, client = nil) result = [] valid_modules.each do |m| - ary = reclist(mod_file_path(m, relpath, client), nil, recurse, ignore) - ary = [] if ary.nil? - result += ary + modpath = mod_file_path(m, relpath, client) + if FileTest.exists?(modpath) + if FileTest.directory?(modpath) and recurse + ary = reclist(modpath, recurse, ignore) + ary = [] if ary.nil? + result += ary + else + result += [["/", File.stat(modpath).ftype]] + end + end end result end diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb index 05ae7b9a2..71b633a09 100644 --- a/lib/puppet/network/handler/master.rb +++ b/lib/puppet/network/handler/master.rb @@ -24,7 +24,7 @@ class Puppet::Network::Handler # Tell a client whether there's a fresh config for it def freshness(client = nil, clientip = nil) # Always force a recompile. Newer clients shouldn't do this (as of April 2008). - return 0 + return Time.now.to_i end def initialize(hash = {}) diff --git a/lib/puppet/network/http_server/rack.rb b/lib/puppet/network/http_server/rack.rb new file mode 100644 index 000000000..806007a05 --- /dev/null +++ b/lib/puppet/network/http_server/rack.rb @@ -0,0 +1,148 @@ +# Author: Christian Hofstaedtler <hofstaedtler@inqnet.at> +# Copyright (c) 2006 Manuel Holtgrewe, 2007 Luke Kanies, +# 2008 Christian Hofstaedtler +# +# This file is mostly based on the mongrel module, which is part of +# the standard puppet distribution. +# +# puppet/network/http_server/mongrel.rb has the following license, +# and is based heavily on a file retrieved from: +# http://ttt.ggnore.net/2006/11/15/xmlrpc-with-mongrel-and-ruby-off-rails/ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +require 'puppet' +require 'puppet/network/handler' +require 'puppet/sslcertificates' + +require 'xmlrpc/server' +require 'puppet/network/xmlrpc/server' +require 'puppet/network/http_server' +require 'puppet/network/client_request' +require 'puppet/network/handler' + +require 'resolv' +require 'rack' + +# A handler for a Rack-style puppet(master)d. For the most part, it works +# exactly the same as HTTPServer::Mongrel: +# After checking whether the request itself is sane, the handler forwards +# it to an internal instance of XMLRPC::BasicServer to process it. +module Puppet::Network + class HTTPServer::Rack + attr_reader :xmlrpc_server + + def initialize(handlers) + @debug = false + if Puppet[:debug] + @debug = true + end + + Puppet.info "Starting Rack server for puppet version %s" % Puppet.version + if Puppet[:name] != "puppetmasterd" then + Puppet.warn 'Rack server is not named "puppetmasterd", this may be not what you want. ($0 = %s)' % $0 + end + + @xmlrpc_server = Puppet::Network::XMLRPCServer.new + handlers.each do |name, args| + unless handler = Puppet::Network::Handler.handler(name) + raise ArgumentError, "Invalid handler %s" % name + end + h = handler.new(args) + @xmlrpc_server.add_handler(handler.interface, h) + end + Puppet.info "Rack server is waiting to serve requests." + end + + # Validate a rack-style request (in env), and run the requested XMLRPC + # call. + def process(env) + # time to serve a request + req = Rack::Request.new(env) + + if @debug then + Puppet.info "Handling request, details:" + env.each do |name, val| + l = " env: %s ->" % name + l = l + ' %s' % val + Puppet.info l + end + end + + if not req.post? then + return [405, { "Content-Type" => "text/html" }, "Method Not Allowed"] + end + if req.media_type() != "text/xml" then + return [400, { "Content-Type" => "text/html" }, "Bad Request"] + end + if req.content_length().to_i <= 0 then + return [411, { "Content-Type" => "text/html" }, "Length Required"] + end + + body = '' + req.body().each { |line| body = body + line } + if @debug then + Puppet.info "Request Body: %s" % body + end + if body.size != req.content_length().to_i then + if @debug then + Puppet.info "body length didnt match %d" % body.size + Puppet.info " vs. -> %d" % req.content_length().to_i + end + return [400, { "Content-Type" => "text/html" }, "Bad Request Length"] + end + info = client_info(env) + begin + data = @xmlrpc_server.process(body, info) + return [200, { "Content-Type" => "text/xml; charset=utf-8" }, data] + rescue => detail + Puppet.err "Rack: Internal Server Error: XMLRPC_Server.process problem. Details follow: " + detail.backtrace.each { |line| Puppet.err " --> %s" % line } + return [500, { "Content-Type" => "text/html" }, "Internal Server Error"] + end + end + + private + + def client_info(request) + ip = request["REMOTE_ADDR"] + # JJM #906 The following dn.match regular expression is forgiving + # enough to match the two Distinguished Name string contents + # coming from Apache, Pound or other reverse SSL proxies. + if dn = request[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/) + client = dn_matchdata[1].to_str + valid = (request[Puppet[:ssl_client_verify_header]] == 'SUCCESS') + else + begin + client = Resolv.getname(ip) + rescue => detail + Puppet.err "Could not resolve %s: %s" % [ip, detail] + client = "unknown" + end + valid = false + end + info = Puppet::Network::ClientRequest.new(client, ip, valid) + return info + end + end +end + diff --git a/lib/puppet/network/xmlrpc/client.rb b/lib/puppet/network/xmlrpc/client.rb index dfd4a95a7..c79f91d57 100644 --- a/lib/puppet/network/xmlrpc/client.rb +++ b/lib/puppet/network/xmlrpc/client.rb @@ -35,10 +35,6 @@ module Puppet::Network interface.methods.each { |ary| method = ary[0] - if public_method_defined?(method) - raise Puppet::DevError, "Method %s is already defined" % - method - end newclient.send(:define_method,method) { |*args| Puppet.debug "Calling %s.%s" % [namespace, method] begin @@ -52,7 +48,6 @@ module Puppet::Network ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str| if detail.message.include?(str) Puppet.warning "Certificate validation failed; consider using the certname configuration option" - break end end raise XMLRPCClientError, @@ -75,6 +70,10 @@ module Puppet::Network Puppet.warning "Other end went away; restarting connection and retrying" self.recycle_connection retry + rescue Timeout::Error => detail + Puppet.err "Connection timeout calling %s.%s: %s" % + [namespace, method, detail.to_s] + raise XMLRPCClientError.new("Connection Timeout").set_backtrace(detail.backtrace) rescue => detail if detail.message =~ /^Wrong size\. Was \d+, should be \d+$/ Puppet.warning "XMLRPC returned wrong size. Retrying." |
