From f68fe0045d3519d545d8e63b7ee470ece74fcc3f Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 23 Aug 2005 16:55:24 +0000 Subject: moving all server handlers into a specific server subdirectory git-svn-id: https://reductivelabs.com/svn/puppet/trunk@579 980ebf18-57e1-0310-9a29-db15c13687c0 --- lib/puppet.rb | 1 + lib/puppet/ca.rb | 155 ---------------------- lib/puppet/client.rb | 10 +- lib/puppet/filebucket.rb | 277 --------------------------------------- lib/puppet/fileserver.rb | 260 ------------------------------------ lib/puppet/master.rb | 88 ------------- lib/puppet/server.rb | 37 ++++-- lib/puppet/server/ca.rb | 159 ++++++++++++++++++++++ lib/puppet/server/filebucket.rb | 277 +++++++++++++++++++++++++++++++++++++++ lib/puppet/server/fileserver.rb | 264 +++++++++++++++++++++++++++++++++++++ lib/puppet/server/master.rb | 92 +++++++++++++ lib/puppet/server/servlet.rb | 112 ++++++++++++++++ lib/puppet/servlet.rb | 110 ---------------- lib/puppet/type/pfile.rb | 4 +- lib/puppet/type/pfilebucket.rb | 2 +- test/bucket/tc_bucket.rb | 284 ---------------------------------------- test/executables/tc_puppetca.rb | 7 +- test/language/tc_snippets.rb | 2 +- test/other/tc_selector.rb | 37 ------ test/server/tc_bucket.rb | 283 +++++++++++++++++++++++++++++++++++++++ test/server/tc_ca.rb | 13 +- test/server/tc_fileserver.rb | 36 +++-- test/server/tc_master.rb | 18 +-- test/server/tc_server.rb | 18 +-- 24 files changed, 1254 insertions(+), 1292 deletions(-) delete mode 100644 lib/puppet/ca.rb delete mode 100755 lib/puppet/filebucket.rb delete mode 100755 lib/puppet/fileserver.rb delete mode 100644 lib/puppet/master.rb create mode 100644 lib/puppet/server/ca.rb create mode 100755 lib/puppet/server/filebucket.rb create mode 100755 lib/puppet/server/fileserver.rb create mode 100644 lib/puppet/server/master.rb create mode 100644 lib/puppet/server/servlet.rb delete mode 100644 lib/puppet/servlet.rb delete mode 100644 test/bucket/tc_bucket.rb delete mode 100644 test/other/tc_selector.rb create mode 100644 test/server/tc_bucket.rb diff --git a/lib/puppet.rb b/lib/puppet.rb index a4507e09f..64a3821a9 100644 --- a/lib/puppet.rb +++ b/lib/puppet.rb @@ -206,5 +206,6 @@ module Puppet end end +require 'puppet/server' require 'puppet/type' require 'puppet/storage' diff --git a/lib/puppet/ca.rb b/lib/puppet/ca.rb deleted file mode 100644 index 9a6f8aeda..000000000 --- a/lib/puppet/ca.rb +++ /dev/null @@ -1,155 +0,0 @@ -require 'openssl' -require 'puppet' -require 'puppet/sslcertificates' -require 'xmlrpc/server' - -# Much of this was taken from QuickCert: -# http://segment7.net/projects/ruby/QuickCert/ - -module Puppet - class CAError < Puppet::Error; end - class CA - attr_reader :ca - - def self.interface - XMLRPC::Service::Interface.new("puppetca") { |iface| - iface.add_method("array getcert(csr)") - } - end - - def autosign?(hostname) - # simple values are easy - asign = Puppet[:autosign] - if asign == true or asign == false - return asign - end - - # we only otherwise know how to handle files - unless asign =~ /^\// - raise Puppet::Error, "Invalid autosign value %s" % - asign - end - - unless FileTest.exists?(asign) - Puppet.warning "Autosign is enabled but %s is missing" % asign - return false - end - File.open(asign) { |f| - f.each { |line| - line.chomp! - if line =~ /^[.\w-]+$/ and line == hostname - Puppet.info "%s exactly matched %s" % [hostname, line] - return true - else - begin - rx = Regexp.new(line) - rescue => detail - Puppet.err( - "Could not create regexp out of autosign line %s: %s" % - [line, detail] - ) - next - end - - if hostname =~ rx - Puppet.info "%s matched %s" % [hostname, line] - return true - end - end - } - } - - return false - end - - def initialize(hash = {}) - @ca = Puppet::SSLCertificates::CA.new() - end - - # our client sends us a csr, and we either store it for later signing, - # or we sign it right away - def getcert(csrtext, request = nil) - # okay, i need to retrieve the hostname from the csr, and then - # verify that i get the same hostname through reverse lookup or - # something - - Puppet.info "Someone's trying for a cert" - csr = OpenSSL::X509::Request.new(csrtext) - - subject = csr.subject - - nameary = subject.to_a.find { |ary| - ary[0] == "CN" - } - - if nameary.nil? - Puppet.err "Invalid certificate request" - return "invalid" - end - - hostname = nameary[1] - - unless @ca - Puppet.notice "Host %s asked for signing from non-CA master" % hostname - return "" - end - - # okay, we're now going to store the public key if we don't already - # have it - public_key = csr.public_key - unless FileTest.directory?(Puppet[:publickeydir]) - Puppet.recmkdir(Puppet[:publickeydir]) - end - pkeyfile = File.join(Puppet[:publickeydir], [hostname, "pem"].join('.')) - - if FileTest.exists?(pkeyfile) - currentkey = File.open(pkeyfile) { |k| k.read } - unless currentkey == public_key.to_s - raise Puppet::Error, "public keys for %s differ" % hostname - end - else - File.open(pkeyfile, "w", 0644) { |f| - f.print public_key.to_s - } - end - unless FileTest.directory?(Puppet[:certdir]) - Puppet.recmkdir(Puppet[:certdir], 0770) - end - certfile = File.join(Puppet[:certdir], [hostname, "pem"].join(".")) - - #puts hostname - #puts certfile - - unless FileTest.directory?(Puppet[:csrdir]) - Puppet.recmkdir(Puppet[:csrdir], 0770) - end - # first check to see if we already have a signed cert for the host - cert, cacert = ca.getclientcert(hostname) - if cert and cacert - Puppet.info "Retrieving existing certificate for %s" % hostname - Puppet.info "Cert: %s; Cacert: %s" % [cert.class, cacert.class] - return [cert.to_pem, cacert.to_pem] - elsif @ca - if self.autosign?(hostname) - # okay, we don't have a signed cert - # if we're a CA and autosign is turned on, then go ahead and sign - # the csr and return the results - Puppet.info "Signing certificate for %s" % hostname - cert, cacert = @ca.sign(csr) - Puppet.info "Cert: %s; Cacert: %s" % [cert.class, cacert.class] - return [cert.to_pem, cacert.to_pem] - else # just write out the csr for later signing - if @ca.getclientcsr(hostname) - Puppet.info "Not replacing existing request from %s" % hostname - else - Puppet.info "Storing certificate request for %s" % hostname - @ca.storeclientcsr(csr) - end - return ["", ""] - end - else - raise "huh?" - end - end - end -end diff --git a/lib/puppet/client.rb b/lib/puppet/client.rb index 1282a5900..7998f2ff8 100644 --- a/lib/puppet/client.rb +++ b/lib/puppet/client.rb @@ -5,13 +5,13 @@ require 'puppet' require 'puppet/sslcertificates' require 'puppet/type' -require 'puppet/server' require 'facter' require 'openssl' require 'puppet/transaction' require 'puppet/transportable' require 'puppet/metric' require 'puppet/daemon' +require 'puppet/server' $noclientnetworking = false begin @@ -33,9 +33,9 @@ module Puppet class NetworkClient < XMLRPC::Client #include Puppet::Daemon - @@handlers = [Puppet::FileServer, Puppet::CA, Puppet::Master] + #@@handlers = [Puppet::FileServer, Puppet::CA, Puppet::Server::Master] - @@handlers.each { |handler| + Puppet::Server.eachhandler { |name, handler| interface = handler.interface namespace = interface.prefix @@ -169,12 +169,12 @@ module Puppet @driver = Puppet::NetworkClient.new(args) @local = false - when Puppet::Master: + when Puppet::Server::Master: @driver = hash[:Server] @local = true else raise ClientError.new("Server must be a hostname or a " + - "Puppet::Master object") + "Puppet::Server::Master object") end else raise ClientError.new("Must pass :Server to client") diff --git a/lib/puppet/filebucket.rb b/lib/puppet/filebucket.rb deleted file mode 100755 index f0e717146..000000000 --- a/lib/puppet/filebucket.rb +++ /dev/null @@ -1,277 +0,0 @@ -#!/usr/bin/ruby -w - -#-------------------- -# accept and serve files -# -# $Id$ - - -require 'webrick' -#require 'webrick/https' -require 'xmlrpc/server' -require 'xmlrpc/client' -#require 'webrick/httpstatus' -require 'facter' -require 'digest/md5' -require 'base64' - -class BucketError < RuntimeError; end - -module FileBucket - DEFAULTPORT = 8139 - # this doesn't work for relative paths - def FileBucket.mkdir(dir) - if FileTest.exist?(dir) - return false - else - tmp = dir.sub(/^\//,'') - path = [File::SEPARATOR] - tmp.split(File::SEPARATOR).each { |dir| - path.push dir - unless FileTest.exist?(File.join(path)) - Dir.mkdir(File.join(path)) - end - } - return true - end - end - - def FileBucket.paths(base,md5) - return [ - File.join(base, md5), - File.join(base, md5, "contents"), - File.join(base, md5, "paths") - ] - end - - #--------------------------------------------------------------- - class Bucket - def initialize(hash) - # build our AST - - if hash.include?(:ConflictCheck) - @conflictchk = hash[:ConflictCheck] - hash.delete(:ConflictCheck) - else - @conflictchk = true - end - - if hash.include?(:Path) - @bucket = hash[:Path] - hash.delete(:Path) - else - if defined? Puppet - @bucket = Puppet[:bucketdir] - else - @bucket = File.expand_path("~/.filebucket") - end - end - - # XXX this should really be done using Puppet::Type instances... - FileBucket.mkdir(@bucket) - end - - # accept a file from a client - def addfile(string,path) - #puts "entering addfile" - contents = Base64.decode64(string) - #puts "string is decoded" - - md5 = Digest::MD5.hexdigest(contents) - #puts "md5 is made" - - bpath, bfile, pathpath = FileBucket.paths(@bucket,md5) - - # if it's a new directory... - if FileBucket.mkdir(bpath) - # ...then just create the file - #puts "creating file" - File.open(bfile, File::WRONLY|File::CREAT) { |of| - of.print contents - } - #puts "File is created" - else # if the dir already existed... - # ...we need to verify that the contents match the existing file - if @conflictchk - unless FileTest.exists?(bfile) - raise(BucketError, - "No file at %s for sum %s" % [bfile,md5], caller) - end - - curfile = "" - File.open(bfile) { |of| - curfile = of.read - } - - # if the contents don't match, then we've found a conflict - # unlikely, but quite bad - if curfile != contents - raise(BucketError, - "Got passed new contents for sum %s" % md5, caller) - end - end - #puts "Conflict check is done" - end - - # in either case, add the passed path to the list of paths - paths = nil - addpath = false - if FileTest.exists?(pathpath) - File.open(pathpath) { |of| - paths = of.readlines - } - - # unless our path is already there... - unless paths.include?(path) - addpath = true - end - else - addpath = true - end - #puts "Path is checked" - - # if it's a new file, or if our path isn't in the file yet, add it - if addpath - File.open(pathpath, File::WRONLY|File::CREAT|File::APPEND) { |of| - of.puts path - } - #puts "Path is added" - end - - return md5 - end - - def getfile(md5) - bpath, bfile, bpaths = FileBucket.paths(@bucket,md5) - - unless FileTest.exists?(bfile) - return false - end - - contents = nil - File.open(bfile) { |of| - contents = of.read - } - - return Base64.encode64(contents) - end - - private - - def on_init - @default_namespace = 'urn:filebucket-server' - add_method(self, 'addfile', 'string', 'path') - add_method(self, 'getfile', 'md5') - end - - def cert(filename) - OpenSSL::X509::Certificate.new(File.open(File.join(@dir, filename)) { |f| - f.read - }) - end - - def key(filename) - OpenSSL::PKey::RSA.new(File.open(File.join(@dir, filename)) { |f| - f.read - }) - end - - end - #--------------------------------------------------------------- - - class BucketWebserver < WEBrick::HTTPServer - def initialize(hash) - unless hash.include?(:Port) - hash[:Port] = FileBucket::DEFAULTPORT - end - servlet = XMLRPC::WEBrickServlet.new - @bucket = FileBucket::Bucket.new(hash) - #puts @bucket - servlet.add_handler("bucket",@bucket) - super - - self.mount("/RPC2", servlet) - end - end - - class BucketClient < XMLRPC::Client - @@methods = [ :addfile, :getfile ] - - @@methods.each { |method| - self.send(:define_method,method) { |*args| - begin - call("bucket.%s" % method.to_s,*args) - rescue => detail - #puts detail - end - } - } - - def initialize(hash) - hash[:Path] ||= "/RPC2" - hash[:Server] ||= "localhost" - hash[:Port] ||= FileBucket::DEFAULTPORT - super(hash[:Server],hash[:Path],hash[:Port]) - end - end - - class Dipper - def initialize(hash) - if hash.include?(:Server) - @bucket = FileBucket::BucketClient.new( - :Server => hash[:Server] - ) - elsif hash.include?(:Bucket) - @bucket = hash[:Bucket] - elsif hash.include?(:Path) - @bucket = FileBucket::Bucket.new( - :Path => hash[:Path] - ) - end - end - - def backup(file) - unless FileTest.exists?(file) - raise(BucketError, "File %s does not exist" % file, caller) - end - contents = File.open(file) { |of| of.read } - - string = Base64.encode64(contents) - #puts "string is created" - - sum = @bucket.addfile(string,file) - #puts "file %s is added" % file - return sum - end - - def restore(file,sum) - restore = true - if FileTest.exists?(file) - contents = File.open(file) { |of| of.read } - - cursum = Digest::MD5.hexdigest(contents) - - # if the checksum has changed... - # this might be extra effort - if cursum == sum - restore = false - end - end - - if restore - #puts "Restoring %s" % file - newcontents = Base64.decode64(@bucket.getfile(sum)) - newsum = Digest::MD5.hexdigest(newcontents) - File.open(file,File::WRONLY|File::TRUNC) { |of| - of.print(newcontents) - } - #puts "Done" - return newsum - else - return nil - end - - end - end - #--------------------------------------------------------------- -end diff --git a/lib/puppet/fileserver.rb b/lib/puppet/fileserver.rb deleted file mode 100755 index f04c337af..000000000 --- a/lib/puppet/fileserver.rb +++ /dev/null @@ -1,260 +0,0 @@ -require 'puppet' -require 'cgi' - -module Puppet - class FileServerError < Puppet::Error; end - class FileServer - attr_accessor :local - - #CHECKPARAMS = %w{checksum type mode owner group} - CHECKPARAMS = [:mode, :type, :owner, :group, :checksum] - - def self.interface - XMLRPC::Service::Interface.new("fileserver") { |iface| - iface.add_method("string describe(string)") - iface.add_method("string list(string, boolean)") - iface.add_method("string retrieve(string)") - } - end - - 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::PFile[dir] - obj = Puppet::Type::PFile.new( - :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 - - def describe(file) - mount, path = splitpath(file) - - subdir = nil - unless subdir = subdir(mount, path) - Puppet.notice "Could not find subdirectory %s" % - "//%s/%s" % [mount, path] - return "" - end - - obj = nil - unless obj = self.check(subdir) - return "" - end - - desc = [] - CHECKPARAMS.each { |check| - if state = obj.state(check) - unless state.is - Puppet.notice "Manually retrieving info for %s" % check - state.retrieve - end - desc << state.is - else - if check == "checksum" and obj.state(:type).is == "file" - Puppet.notice "File %s does not have data for %s" % - [obj.name, check] - end - desc << nil - end - } - - return desc.join("\t") - end - - def initialize(hash = {}) - @mounts = {} - @files = {} - - if hash[:Local] - @local = hash[:Local] - else - @local = false - end - end - - def list(dir, recurse = false, sum = "md5") - mount, path = splitpath(dir) - - subdir = nil - unless subdir = subdir(mount, path) - Puppet.notice "Could not find subdirectory %s" % - "//%s/%s" % [mount, path] - return "" - end - - obj = nil - unless FileTest.exists?(subdir) - return "" - end - - #rmdir = File.dirname(File.join(@mounts[mount], path)) - rmdir = nameswap(dir, mount) - desc = self.reclist(rmdir, subdir, recurse) - - if desc.length == 0 - Puppet.notice "Got no information on //%s/%s" % - [mount, path] - return "" - end - - desc.collect { |sub| - sub.join("\t") - }.join("\n") - end - - def mount(dir, name) - if @mounts.include?(name) - if @mounts[name] != dir - raise FileServerError, "%s is already mounted at %s" % - [@mounts[name], name] - else - # it's already mounted; no problem - return - end - end - - unless name =~ %r{^\w+$} - raise FileServerError, "Invalid name format '%s'" % name - end - - unless FileTest.exists?(dir) - raise FileServerError, "%s does not exist" % dir - end - - if FileTest.directory?(dir) - if FileTest.readable?(dir) - Puppet.info "Mounting %s at %s" % [dir, name] - @mounts[name] = dir - else - raise FileServerError, "%s is not readable" % dir - end - else - raise FileServerError, "%s is not a directory" % dir - end - end - - # recursive listing function - def reclist(root, path, recurse) - #desc = [obj.name.sub(%r{#{root}/?}, '')] - name = path.sub(root, '') - if name == "" - name = "/" - end - - if name == path - raise Puppet::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" - Dir.entries(path).each { |child| - next if child =~ /^\.\.?$/ - self.reclist(root, File.join(path, child), recurse).each { |cobj| - ary << cobj - } - } - end - end - - return ary.reject { |c| c.nil? } - end - - def retrieve(file) - mount, path = splitpath(file) - - unless (@mounts.include?(mount)) - # FIXME I really need some better way to pass and handle xmlrpc errors - raise FileServerError, "%s not mounted" % mount - end - - fpath = nil - if path - fpath = File.join(@mounts[mount], path) - else - fpath = @mounts[mount] - end - - unless FileTest.exists?(fpath) - return "" - end - - str = File.read(fpath) - - if @local - return str - else - return CGI.escape(str) - end - end - - private - - def nameswap(name, mount) - name.sub(/\/#{mount}/, @mounts[mount]).gsub(%r{//}, '/').sub( - %r{/$}, '' - ) - #Puppet.info "Swapped %s to %s" % [name, newname] - #newname - end - - def splitpath(dir) - # the dir is based on one of the mounts - # so first retrieve the mount path - mount = nil - path = nil - if dir =~ %r{/(\w+)/?} - mount = $1 - path = dir.sub(%r{/#{mount}/?}, '') - - unless @mounts.include?(mount) - raise FileServerError, "%s not mounted" % mount - end - else - raise FileServerError, "Invalid path '%s'" % dir - end - - if path == "" - path = nil - end - return mount, path - end - - def subdir(mount, dir) - basedir = @mounts[mount] - - dirname = nil - if dir - dirname = File.join(basedir, dir.split("/").join(File::SEPARATOR)) - else - dirname = basedir - end - - return dirname - end - end -end - -# $Id$ diff --git a/lib/puppet/master.rb b/lib/puppet/master.rb deleted file mode 100644 index bbfeaf557..000000000 --- a/lib/puppet/master.rb +++ /dev/null @@ -1,88 +0,0 @@ -require 'openssl' -require 'puppet' -require 'puppet/parser/interpreter' -require 'puppet/sslcertificates' -require 'xmlrpc/server' - -module Puppet - class MasterError < Puppet::Error; end - class Master - attr_accessor :ast, :local - attr_reader :ca - - def self.interface - XMLRPC::Service::Interface.new("puppetmaster") { |iface| - iface.add_method("string getconfig(string)") - } - end - - def initialize(hash = {}) - - # build our AST - @file = hash[:File] || Puppet[:manifest] - @parser = Puppet::Parser::Parser.new() - @parser.file = @file - @ast = @parser.parse - hash.delete(:File) - - if hash[:Local] - @local = hash[:Local] - else - @local = false - end - - if hash.include?(:CA) and hash[:CA] - @ca = Puppet::SSLCertificates::CA.new() - else - @ca = nil - end - end - - def getconfig(facts, request = nil) - if request - #Puppet.warning request.inspect - end - if @local - # we don't need to do anything, since we should already - # have raw objects - Puppet.debug "Our client is local" - else - Puppet.debug "Our client is remote" - - # XXX this should definitely be done in the protocol, somehow - begin - facts = Marshal::load(CGI.unescape(facts)) - rescue => detail - puts "AAAAA" - puts detail - exit - end - end - - Puppet.debug("Creating interpreter") - - begin - interpreter = Puppet::Parser::Interpreter.new( - :ast => @ast, - :facts => facts - ) - rescue => detail - return detail.to_s - end - - Puppet.debug("Running interpreter") - begin - retobjects = interpreter.run() - rescue => detail - Puppet.err detail.to_s - return "" - end - - if @local - return retobjects - else - return CGI.escape(Marshal::dump(retobjects)) - end - end - end -end diff --git a/lib/puppet/server.rb b/lib/puppet/server.rb index 28bb1bd46..5707e6f0d 100644 --- a/lib/puppet/server.rb +++ b/lib/puppet/server.rb @@ -8,9 +8,6 @@ require 'puppet' require 'puppet/daemon' -require 'puppet/servlet' -require 'puppet/master' -require 'puppet/ca' $noservernetworking = false @@ -51,13 +48,25 @@ module Puppet class Server < WEBrick::HTTPServer include Puppet::Daemon - # a bit of a hack for now, but eh, wadda ya gonna do? - @@handlers = { - :Master => Puppet::Master, - :CA => Puppet::CA, - :Status => Puppet::ServerStatus - } + @@handlers = {} +# # a bit of a hack for now, but eh, wadda ya gonna do? +# @@handlers = { +# :Master => Puppet::Server::Master, +# :CA => Puppet::Server::CA, +# :Status => Puppet::ServerStatus +# } + def self.addhandler(name, handler) + @@handlers[name] = handler + end + + Puppet::Server.addhandler(:Status, Puppet::ServerStatus) + + def self.eachhandler + @@handlers.each { |name, klass| + yield(name, klass) + } + end def self.inithandler(handler,args) unless @@handlers.include?(handler) raise ServerError, "Invalid handler %s" % handler @@ -91,7 +100,7 @@ module Puppet # okay, i need to retrieve my cert and set it up, somehow # the default case will be that i'm also the ca - if ca = @handlers.find { |handler| handler.is_a?(Puppet::CA) } + if ca = @handlers.find { |handler| handler.is_a?(Puppet::Server::CA) } @driver = ca @secureinit = true self.fqdn @@ -120,10 +129,16 @@ module Puppet # have a global state # mount has to be called after the server is initialized - self.mount("/RPC2", Puppet::Servlet, @handlers) + self.mount("/RPC2", Puppet::Server::Servlet, @handlers) end end end #--------------------------------------------------------------- end + +require 'puppet/server/servlet' +require 'puppet/server/master' +require 'puppet/server/ca' +require 'puppet/server/fileserver' +require 'puppet/server/filebucket' diff --git a/lib/puppet/server/ca.rb b/lib/puppet/server/ca.rb new file mode 100644 index 000000000..65074c3f6 --- /dev/null +++ b/lib/puppet/server/ca.rb @@ -0,0 +1,159 @@ +require 'openssl' +require 'puppet' +require 'puppet/sslcertificates' +require 'xmlrpc/server' + +# Much of this was taken from QuickCert: +# http://segment7.net/projects/ruby/QuickCert/ + +module Puppet +class Server + class CAError < Puppet::Error; end + class CA + attr_reader :ca + + def self.interface + XMLRPC::Service::Interface.new("puppetca") { |iface| + iface.add_method("array getcert(csr)") + } + end + + Puppet::Server.addhandler(:CA, self) + + def autosign?(hostname) + # simple values are easy + asign = Puppet[:autosign] + if asign == true or asign == false + return asign + end + + # we only otherwise know how to handle files + unless asign =~ /^\// + raise Puppet::Error, "Invalid autosign value %s" % + asign + end + + unless FileTest.exists?(asign) + Puppet.warning "Autosign is enabled but %s is missing" % asign + return false + end + File.open(asign) { |f| + f.each { |line| + line.chomp! + if line =~ /^[.\w-]+$/ and line == hostname + Puppet.info "%s exactly matched %s" % [hostname, line] + return true + else + begin + rx = Regexp.new(line) + rescue => detail + Puppet.err( + "Could not create regexp out of autosign line %s: %s" % + [line, detail] + ) + next + end + + if hostname =~ rx + Puppet.info "%s matched %s" % [hostname, line] + return true + end + end + } + } + + return false + end + + def initialize(hash = {}) + @ca = Puppet::SSLCertificates::CA.new() + end + + # our client sends us a csr, and we either store it for later signing, + # or we sign it right away + def getcert(csrtext, request = nil) + # okay, i need to retrieve the hostname from the csr, and then + # verify that i get the same hostname through reverse lookup or + # something + + Puppet.info "Someone's trying for a cert" + csr = OpenSSL::X509::Request.new(csrtext) + + subject = csr.subject + + nameary = subject.to_a.find { |ary| + ary[0] == "CN" + } + + if nameary.nil? + Puppet.err "Invalid certificate request" + return "invalid" + end + + hostname = nameary[1] + + unless @ca + Puppet.notice "Host %s asked for signing from non-CA master" % hostname + return "" + end + + # okay, we're now going to store the public key if we don't already + # have it + public_key = csr.public_key + unless FileTest.directory?(Puppet[:publickeydir]) + Puppet.recmkdir(Puppet[:publickeydir]) + end + pkeyfile = File.join(Puppet[:publickeydir], [hostname, "pem"].join('.')) + + if FileTest.exists?(pkeyfile) + currentkey = File.open(pkeyfile) { |k| k.read } + unless currentkey == public_key.to_s + raise Puppet::Error, "public keys for %s differ" % hostname + end + else + File.open(pkeyfile, "w", 0644) { |f| + f.print public_key.to_s + } + end + unless FileTest.directory?(Puppet[:certdir]) + Puppet.recmkdir(Puppet[:certdir], 0770) + end + certfile = File.join(Puppet[:certdir], [hostname, "pem"].join(".")) + + #puts hostname + #puts certfile + + unless FileTest.directory?(Puppet[:csrdir]) + Puppet.recmkdir(Puppet[:csrdir], 0770) + end + # first check to see if we already have a signed cert for the host + cert, cacert = ca.getclientcert(hostname) + if cert and cacert + Puppet.info "Retrieving existing certificate for %s" % hostname + Puppet.info "Cert: %s; Cacert: %s" % [cert.class, cacert.class] + return [cert.to_pem, cacert.to_pem] + elsif @ca + if self.autosign?(hostname) + # okay, we don't have a signed cert + # if we're a CA and autosign is turned on, then go ahead and sign + # the csr and return the results + Puppet.info "Signing certificate for %s" % hostname + cert, cacert = @ca.sign(csr) + Puppet.info "Cert: %s; Cacert: %s" % [cert.class, cacert.class] + return [cert.to_pem, cacert.to_pem] + else # just write out the csr for later signing + if @ca.getclientcsr(hostname) + Puppet.info "Not replacing existing request from %s" % hostname + else + Puppet.info "Storing certificate request for %s" % hostname + @ca.storeclientcsr(csr) + end + return ["", ""] + end + else + raise "huh?" + end + end + end +end +end diff --git a/lib/puppet/server/filebucket.rb b/lib/puppet/server/filebucket.rb new file mode 100755 index 000000000..f0e717146 --- /dev/null +++ b/lib/puppet/server/filebucket.rb @@ -0,0 +1,277 @@ +#!/usr/bin/ruby -w + +#-------------------- +# accept and serve files +# +# $Id$ + + +require 'webrick' +#require 'webrick/https' +require 'xmlrpc/server' +require 'xmlrpc/client' +#require 'webrick/httpstatus' +require 'facter' +require 'digest/md5' +require 'base64' + +class BucketError < RuntimeError; end + +module FileBucket + DEFAULTPORT = 8139 + # this doesn't work for relative paths + def FileBucket.mkdir(dir) + if FileTest.exist?(dir) + return false + else + tmp = dir.sub(/^\//,'') + path = [File::SEPARATOR] + tmp.split(File::SEPARATOR).each { |dir| + path.push dir + unless FileTest.exist?(File.join(path)) + Dir.mkdir(File.join(path)) + end + } + return true + end + end + + def FileBucket.paths(base,md5) + return [ + File.join(base, md5), + File.join(base, md5, "contents"), + File.join(base, md5, "paths") + ] + end + + #--------------------------------------------------------------- + class Bucket + def initialize(hash) + # build our AST + + if hash.include?(:ConflictCheck) + @conflictchk = hash[:ConflictCheck] + hash.delete(:ConflictCheck) + else + @conflictchk = true + end + + if hash.include?(:Path) + @bucket = hash[:Path] + hash.delete(:Path) + else + if defined? Puppet + @bucket = Puppet[:bucketdir] + else + @bucket = File.expand_path("~/.filebucket") + end + end + + # XXX this should really be done using Puppet::Type instances... + FileBucket.mkdir(@bucket) + end + + # accept a file from a client + def addfile(string,path) + #puts "entering addfile" + contents = Base64.decode64(string) + #puts "string is decoded" + + md5 = Digest::MD5.hexdigest(contents) + #puts "md5 is made" + + bpath, bfile, pathpath = FileBucket.paths(@bucket,md5) + + # if it's a new directory... + if FileBucket.mkdir(bpath) + # ...then just create the file + #puts "creating file" + File.open(bfile, File::WRONLY|File::CREAT) { |of| + of.print contents + } + #puts "File is created" + else # if the dir already existed... + # ...we need to verify that the contents match the existing file + if @conflictchk + unless FileTest.exists?(bfile) + raise(BucketError, + "No file at %s for sum %s" % [bfile,md5], caller) + end + + curfile = "" + File.open(bfile) { |of| + curfile = of.read + } + + # if the contents don't match, then we've found a conflict + # unlikely, but quite bad + if curfile != contents + raise(BucketError, + "Got passed new contents for sum %s" % md5, caller) + end + end + #puts "Conflict check is done" + end + + # in either case, add the passed path to the list of paths + paths = nil + addpath = false + if FileTest.exists?(pathpath) + File.open(pathpath) { |of| + paths = of.readlines + } + + # unless our path is already there... + unless paths.include?(path) + addpath = true + end + else + addpath = true + end + #puts "Path is checked" + + # if it's a new file, or if our path isn't in the file yet, add it + if addpath + File.open(pathpath, File::WRONLY|File::CREAT|File::APPEND) { |of| + of.puts path + } + #puts "Path is added" + end + + return md5 + end + + def getfile(md5) + bpath, bfile, bpaths = FileBucket.paths(@bucket,md5) + + unless FileTest.exists?(bfile) + return false + end + + contents = nil + File.open(bfile) { |of| + contents = of.read + } + + return Base64.encode64(contents) + end + + private + + def on_init + @default_namespace = 'urn:filebucket-server' + add_method(self, 'addfile', 'string', 'path') + add_method(self, 'getfile', 'md5') + end + + def cert(filename) + OpenSSL::X509::Certificate.new(File.open(File.join(@dir, filename)) { |f| + f.read + }) + end + + def key(filename) + OpenSSL::PKey::RSA.new(File.open(File.join(@dir, filename)) { |f| + f.read + }) + end + + end + #--------------------------------------------------------------- + + class BucketWebserver < WEBrick::HTTPServer + def initialize(hash) + unless hash.include?(:Port) + hash[:Port] = FileBucket::DEFAULTPORT + end + servlet = XMLRPC::WEBrickServlet.new + @bucket = FileBucket::Bucket.new(hash) + #puts @bucket + servlet.add_handler("bucket",@bucket) + super + + self.mount("/RPC2", servlet) + end + end + + class BucketClient < XMLRPC::Client + @@methods = [ :addfile, :getfile ] + + @@methods.each { |method| + self.send(:define_method,method) { |*args| + begin + call("bucket.%s" % method.to_s,*args) + rescue => detail + #puts detail + end + } + } + + def initialize(hash) + hash[:Path] ||= "/RPC2" + hash[:Server] ||= "localhost" + hash[:Port] ||= FileBucket::DEFAULTPORT + super(hash[:Server],hash[:Path],hash[:Port]) + end + end + + class Dipper + def initialize(hash) + if hash.include?(:Server) + @bucket = FileBucket::BucketClient.new( + :Server => hash[:Server] + ) + elsif hash.include?(:Bucket) + @bucket = hash[:Bucket] + elsif hash.include?(:Path) + @bucket = FileBucket::Bucket.new( + :Path => hash[:Path] + ) + end + end + + def backup(file) + unless FileTest.exists?(file) + raise(BucketError, "File %s does not exist" % file, caller) + end + contents = File.open(file) { |of| of.read } + + string = Base64.encode64(contents) + #puts "string is created" + + sum = @bucket.addfile(string,file) + #puts "file %s is added" % file + return sum + end + + def restore(file,sum) + restore = true + if FileTest.exists?(file) + contents = File.open(file) { |of| of.read } + + cursum = Digest::MD5.hexdigest(contents) + + # if the checksum has changed... + # this might be extra effort + if cursum == sum + restore = false + end + end + + if restore + #puts "Restoring %s" % file + newcontents = Base64.decode64(@bucket.getfile(sum)) + newsum = Digest::MD5.hexdigest(newcontents) + File.open(file,File::WRONLY|File::TRUNC) { |of| + of.print(newcontents) + } + #puts "Done" + return newsum + else + return nil + end + + end + end + #--------------------------------------------------------------- +end diff --git a/lib/puppet/server/fileserver.rb b/lib/puppet/server/fileserver.rb new file mode 100755 index 000000000..43e08655f --- /dev/null +++ b/lib/puppet/server/fileserver.rb @@ -0,0 +1,264 @@ +require 'puppet' +require 'cgi' + +module Puppet +class Server + class FileServerError < Puppet::Error; end + class FileServer + attr_accessor :local + + #CHECKPARAMS = %w{checksum type mode owner group} + CHECKPARAMS = [:mode, :type, :owner, :group, :checksum] + + def self.interface + XMLRPC::Service::Interface.new("fileserver") { |iface| + iface.add_method("string describe(string)") + iface.add_method("string list(string, boolean)") + iface.add_method("string retrieve(string)") + } + end + + Puppet::Server.addhandler(:FileServer, self) + + 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::PFile[dir] + obj = Puppet::Type::PFile.new( + :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 + + def describe(file) + mount, path = splitpath(file) + + subdir = nil + unless subdir = subdir(mount, path) + Puppet.notice "Could not find subdirectory %s" % + "//%s/%s" % [mount, path] + return "" + end + + obj = nil + unless obj = self.check(subdir) + return "" + end + + desc = [] + CHECKPARAMS.each { |check| + if state = obj.state(check) + unless state.is + Puppet.notice "Manually retrieving info for %s" % check + state.retrieve + end + desc << state.is + else + if check == "checksum" and obj.state(:type).is == "file" + Puppet.notice "File %s does not have data for %s" % + [obj.name, check] + end + desc << nil + end + } + + return desc.join("\t") + end + + def initialize(hash = {}) + @mounts = {} + @files = {} + + if hash[:Local] + @local = hash[:Local] + else + @local = false + end + end + + def list(dir, recurse = false, sum = "md5") + mount, path = splitpath(dir) + + subdir = nil + unless subdir = subdir(mount, path) + Puppet.notice "Could not find subdirectory %s" % + "//%s/%s" % [mount, path] + return "" + end + + obj = nil + unless FileTest.exists?(subdir) + return "" + end + + #rmdir = File.dirname(File.join(@mounts[mount], path)) + rmdir = nameswap(dir, mount) + desc = self.reclist(rmdir, subdir, recurse) + + if desc.length == 0 + Puppet.notice "Got no information on //%s/%s" % + [mount, path] + return "" + end + + desc.collect { |sub| + sub.join("\t") + }.join("\n") + end + + def mount(dir, name) + if @mounts.include?(name) + if @mounts[name] != dir + raise FileServerError, "%s is already mounted at %s" % + [@mounts[name], name] + else + # it's already mounted; no problem + return + end + end + + unless name =~ %r{^\w+$} + raise FileServerError, "Invalid name format '%s'" % name + end + + unless FileTest.exists?(dir) + raise FileServerError, "%s does not exist" % dir + end + + if FileTest.directory?(dir) + if FileTest.readable?(dir) + Puppet.info "Mounting %s at %s" % [dir, name] + @mounts[name] = dir + else + raise FileServerError, "%s is not readable" % dir + end + else + raise FileServerError, "%s is not a directory" % dir + end + end + + # recursive listing function + def reclist(root, path, recurse) + #desc = [obj.name.sub(%r{#{root}/?}, '')] + name = path.sub(root, '') + if name == "" + name = "/" + end + + if name == path + raise Puppet::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" + Dir.entries(path).each { |child| + next if child =~ /^\.\.?$/ + self.reclist(root, File.join(path, child), recurse).each { |cobj| + ary << cobj + } + } + end + end + + return ary.reject { |c| c.nil? } + end + + def retrieve(file) + mount, path = splitpath(file) + + unless (@mounts.include?(mount)) + # FIXME I really need some better way to pass and handle xmlrpc errors + raise FileServerError, "%s not mounted" % mount + end + + fpath = nil + if path + fpath = File.join(@mounts[mount], path) + else + fpath = @mounts[mount] + end + + unless FileTest.exists?(fpath) + return "" + end + + str = File.read(fpath) + + if @local + return str + else + return CGI.escape(str) + end + end + + private + + def nameswap(name, mount) + name.sub(/\/#{mount}/, @mounts[mount]).gsub(%r{//}, '/').sub( + %r{/$}, '' + ) + #Puppet.info "Swapped %s to %s" % [name, newname] + #newname + end + + def splitpath(dir) + # the dir is based on one of the mounts + # so first retrieve the mount path + mount = nil + path = nil + if dir =~ %r{/(\w+)/?} + mount = $1 + path = dir.sub(%r{/#{mount}/?}, '') + + unless @mounts.include?(mount) + raise FileServerError, "%s not mounted" % mount + end + else + raise FileServerError, "Invalid path '%s'" % dir + end + + if path == "" + path = nil + end + return mount, path + end + + def subdir(mount, dir) + basedir = @mounts[mount] + + dirname = nil + if dir + dirname = File.join(basedir, dir.split("/").join(File::SEPARATOR)) + else + dirname = basedir + end + + return dirname + end + end +end +end + +# $Id$ diff --git a/lib/puppet/server/master.rb b/lib/puppet/server/master.rb new file mode 100644 index 000000000..f3f0411e9 --- /dev/null +++ b/lib/puppet/server/master.rb @@ -0,0 +1,92 @@ +require 'openssl' +require 'puppet' +require 'puppet/parser/interpreter' +require 'puppet/sslcertificates' +require 'xmlrpc/server' + +module Puppet +class Server + class MasterError < Puppet::Error; end + class Master + attr_accessor :ast, :local + attr_reader :ca + + def self.interface + XMLRPC::Service::Interface.new("puppetmaster") { |iface| + iface.add_method("string getconfig(string)") + } + end + + Puppet::Server.addhandler(:Master, self) + + def initialize(hash = {}) + + # build our AST + @file = hash[:File] || Puppet[:manifest] + @parser = Puppet::Parser::Parser.new() + @parser.file = @file + @ast = @parser.parse + hash.delete(:File) + + if hash[:Local] + @local = hash[:Local] + else + @local = false + end + + if hash.include?(:CA) and hash[:CA] + @ca = Puppet::SSLCertificates::CA.new() + else + @ca = nil + end + end + + def getconfig(facts, request = nil) + if request + #Puppet.warning request.inspect + end + if @local + # we don't need to do anything, since we should already + # have raw objects + Puppet.debug "Our client is local" + else + Puppet.debug "Our client is remote" + + # XXX this should definitely be done in the protocol, somehow + begin + facts = Marshal::load(CGI.unescape(facts)) + rescue => detail + puts "AAAAA" + puts detail + exit + end + end + + Puppet.debug("Creating interpreter") + + begin + interpreter = Puppet::Parser::Interpreter.new( + :ast => @ast, + :facts => facts + ) + rescue => detail + return detail.to_s + end + + Puppet.debug("Running interpreter") + begin + retobjects = interpreter.run() + rescue => detail + Puppet.err detail.to_s + return "" + end + + if @local + return retobjects + else + return CGI.escape(Marshal::dump(retobjects)) + end + end + end +end +end diff --git a/lib/puppet/server/servlet.rb b/lib/puppet/server/servlet.rb new file mode 100644 index 000000000..4db9f6c0e --- /dev/null +++ b/lib/puppet/server/servlet.rb @@ -0,0 +1,112 @@ +require 'xmlrpc/server' + +module Puppet +class Server + class ServletError < RuntimeError; end + class Servlet < XMLRPC::WEBrickServlet + attr_accessor :request + + # this is just a duplicate of the normal method; it's here for + # debugging when i need it + def self.get_instance(server, *options) + self.new(server, *options) + end + + def initialize(server, handlers) + #Puppet.info server.inspect + + # the servlet base class does not consume any arguments + # and its BasicServer base class only accepts a 'class_delim' + # option which won't change in Puppet at all + # thus, we don't need to pass any args to our base class, + # and we can consume them all ourselves + super() + + handlers.each { |handler| + Puppet.debug "adding handler for %s" % handler.class + self.add_handler(handler.class.interface, handler) + } + + @request = nil + self.set_service_hook { |obj, *args| + #raise "crap!" + if @request + args.push @request + #obj.call(args, @request) + end + begin + obj.call(*args) + rescue => detail + Puppet.warning obj.inspect + Puppet.err "Could not call: %s" % detail.to_s + end + } + end + + def service(request, response) + @request = request + if @request.client_cert + Puppet.info "client cert is %s" % @request.client_cert + end + if @request.server_cert + Puppet.info "server cert is %s" % @request.server_cert + end + #p @request + begin + super + rescue => detail + Puppet.err "Could not service request: %s: %s" % + [detail.class, detail] + end + @request = nil + end + + private + + # this is pretty much just a copy of the original method but with more + # feedback + def dispatch(methodname, *args) + #Puppet.warning "dispatch on %s called with %s" % + # [methodname, args.inspect] + for name, obj in @handler + if obj.kind_of? Proc + unless methodname == name + Puppet.debug "obj is proc but %s != %s" % + [methodname, name] + next + end + else + unless methodname =~ /^#{name}(.+)$/ + Puppet.debug "methodname did not match" + next + end + unless obj.respond_to? $1 + Puppet.debug "methodname does not respond to %s" % $1 + next + end + obj = obj.method($1) + end + + if check_arity(obj, args.size) + if @service_hook.nil? + return obj.call(*args) + else + return @service_hook.call(obj, *args) + end + else + Puppet.debug "arity is incorrect" + end + end + + if @default_handler.nil? + raise XMLRPC::FaultException.new( + ERR_METHOD_MISSING, + "Method #{methodname} missing or wrong number of parameters!" + ) + else + @default_handler.call(methodname, *args) + end + end + end +end +end diff --git a/lib/puppet/servlet.rb b/lib/puppet/servlet.rb deleted file mode 100644 index 3fa965fa3..000000000 --- a/lib/puppet/servlet.rb +++ /dev/null @@ -1,110 +0,0 @@ -require 'xmlrpc/server' - -module Puppet - class ServletError < RuntimeError; end - class Servlet < XMLRPC::WEBrickServlet - attr_accessor :request - - # this is just a duplicate of the normal method; it's here for - # debugging when i need it - def self.get_instance(server, *options) - self.new(server, *options) - end - - def initialize(server, handlers) - #Puppet.info server.inspect - - # the servlet base class does not consume any arguments - # and its BasicServer base class only accepts a 'class_delim' - # option which won't change in Puppet at all - # thus, we don't need to pass any args to our base class, - # and we can consume them all ourselves - super() - - handlers.each { |handler| - Puppet.debug "adding handler for %s" % handler.class - self.add_handler(handler.class.interface, handler) - } - - @request = nil - self.set_service_hook { |obj, *args| - #raise "crap!" - if @request - args.push @request - #obj.call(args, @request) - end - begin - obj.call(*args) - rescue => detail - Puppet.warning obj.inspect - Puppet.err "Could not call: %s" % detail.to_s - end - } - end - - def service(request, response) - @request = request - if @request.client_cert - Puppet.info "client cert is %s" % @request.client_cert - end - if @request.server_cert - Puppet.info "server cert is %s" % @request.server_cert - end - #p @request - begin - super - rescue => detail - Puppet.err "Could not service request: %s: %s" % - [detail.class, detail] - end - @request = nil - end - - private - - # this is pretty much just a copy of the original method but with more - # feedback - def dispatch(methodname, *args) - #Puppet.warning "dispatch on %s called with %s" % - # [methodname, args.inspect] - for name, obj in @handler - if obj.kind_of? Proc - unless methodname == name - Puppet.debug "obj is proc but %s != %s" % - [methodname, name] - next - end - else - unless methodname =~ /^#{name}(.+)$/ - Puppet.debug "methodname did not match" - next - end - unless obj.respond_to? $1 - Puppet.debug "methodname does not respond to %s" % $1 - next - end - obj = obj.method($1) - end - - if check_arity(obj, args.size) - if @service_hook.nil? - return obj.call(*args) - else - return @service_hook.call(obj, *args) - end - else - Puppet.debug "arity is incorrect" - end - end - - if @default_handler.nil? - raise XMLRPC::FaultException.new( - ERR_METHOD_MISSING, - "Method #{methodname} missing or wrong number of parameters!" - ) - else - @default_handler.call(methodname, *args) - end - end - end -end diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb index 4eab8ca5b..ddfb2aae3 100644 --- a/lib/puppet/type/pfile.rb +++ b/lib/puppet/type/pfile.rb @@ -7,7 +7,7 @@ require 'etc' require 'uri' require 'fileutils' require 'puppet/type/state' -require 'puppet/fileserver' +require 'puppet/server/fileserver' module Puppet # we first define all of the state that our file will use @@ -1577,7 +1577,7 @@ module Puppet case uri.scheme when "file": - sourceobj.server = Puppet::FileServer.new( + sourceobj.server = Puppet::Server::FileServer.new( :Local => true ) sourceobj.server.mount("/", "localhost") diff --git a/lib/puppet/type/pfilebucket.rb b/lib/puppet/type/pfilebucket.rb index 7fa059979..da931244c 100755 --- a/lib/puppet/type/pfilebucket.rb +++ b/lib/puppet/type/pfilebucket.rb @@ -2,7 +2,7 @@ # $Id$ -require 'puppet/filebucket' +require 'puppet/server/filebucket' module Puppet class Type diff --git a/test/bucket/tc_bucket.rb b/test/bucket/tc_bucket.rb deleted file mode 100644 index 3aa045fc1..000000000 --- a/test/bucket/tc_bucket.rb +++ /dev/null @@ -1,284 +0,0 @@ -if __FILE__ == $0 - $:.unshift '../../lib' - $:.unshift '../../../../library/trunk/lib/' - $:.unshift '../../../../library/trunk/test/' - $puppetbase = "../.." - $debug = true -else - $debug = false -end - -require 'puppet/filebucket' -require 'test/unit' -require 'puppettest.rb' -require 'base64' - -# $Id$ - - -$external = true -if ARGV[1] and ARGV[1] == "external" - $external = true -else - # default to external - #$external = false -end -class TestBucket < Test::Unit::TestCase - def debug(string) - if $debug - puts([Time.now,string].join(" ")) - end - end - - def filelist - files = [] - #/etc/passwd /etc/syslog.conf /etc/hosts - %w{ - who /tmp/bigfile sh uname /etc/passwd /etc/syslog.conf /etc/hosts - }.each { |file| - if file =~ /^\// - if FileTest.exists?(file) - files.push file - end - else - begin - path = %x{which #{file}} - rescue => detail - #STDERR.puts "Could not search for binaries: %s" % detail - next - end - - if path != "" - files.push path.chomp - end - end - } - - return files - end - - def setup - @bucket = File::SEPARATOR + File.join("tmp","filebuckettesting") - end - - def teardown - system("rm -rf %s" % @bucket) - if defined? $pid - system("kill -9 #{$pid} 2>/dev/null") - end - end - - def test_localserver - files = filelist() - server =nil - assert_nothing_raised { - server = FileBucket::Bucket.new( - :Bucket => @bucket - ) - } - files.each { |file| - contents = File.open(file) { |of| of.read } - - md5 = nil - assert_nothing_raised { - #STDERR.puts("adding %s" % file) if $debug - md5 = server.addfile(Base64.encode64(contents),file) - } - newcontents = nil - assert_nothing_raised { - #STDERR.puts("getting %s" % file) if $debug - newcontents = Base64.decode64(server.getfile(md5)) - } - - assert( - contents == newcontents - ) - } - end - - def test_localboth - files = filelist() - - tmpdir = File.join(@bucket,"tmpfiledir") - FileBucket.mkdir(tmpdir) - - server = nil - client = nil - threads = [] - assert_nothing_raised { - server = FileBucket::Bucket.new( - :Bucket => @bucket - ) - } - - #sleep(30) - assert_nothing_raised { - client = FileBucket::Dipper.new( - :Bucket => server - ) - } - files.each { |file| - name = File.basename(file) - tmppath = File.join(tmpdir,name) - - # copy the files to our tmp directory so we can modify them... - #STDERR.puts("copying %s" % file) if $debug - File.open(tmppath,File::WRONLY|File::TRUNC|File::CREAT) { |wf| - File.open(file) { |rf| - wf.print(rf.read) - } - } - - assert(FileTest.exists?(tmppath)) - - osum = nil - tsum = nil - nsum = nil - assert_nothing_raised { - #STDERR.puts("backing up %s" % file) if $debug - osum = client.backup(file) - } - assert_nothing_raised { - #STDERR.puts("backing up %s" % tmppath) if $debug - tsum = client.backup(tmppath) - } - - assert(tsum == osum) - - File.open(tmppath,File::WRONLY|File::TRUNC) { |wf| - wf.print "This is some test text\n" - } - assert_nothing_raised { - #STDERR.puts("backing up %s" % tmppath) if $debug - nsum = client.backup(tmppath) - } - - assert(tsum != nsum) - - assert_nothing_raised { - #STDERR.puts("restoring %s" % tmppath) if $debug - nsum = client.restore(tmppath,tsum) - } - - contents = File.open(tmppath) { |rf| - #STDERR.puts("reading %s" % tmppath) if $debug - rf.read - } - csum = Digest::MD5.hexdigest(contents) - assert(tsum == csum) - } - end - - def test_webxmlmix - files = filelist() - - tmpdir = File.join(@bucket,"tmpfiledir") - FileBucket.mkdir(tmpdir) - - server = nil - client = nil - port = FileBucket::DEFAULTPORT - serverthread = nil - pid = nil - if $external - $pid = fork { - server = FileBucket::BucketWebserver.new( - :Bucket => @bucket, - :Port => port - ) - trap(:INT) { server.shutdown } - trap(:TERM) { server.shutdown } - server.start - } - sleep 3 - #puts "pid is %s" % pid - #exit - else - assert_nothing_raised { - server = FileBucket::BucketWebserver.new( - :Bucket => @bucket, - :Port => port - ) - } - assert_nothing_raised() { - trap(:INT) { server.shutdown } - serverthread = Thread.new { - server.start - } - } - end - - assert_nothing_raised { - client = FileBucket::Dipper.new( - :Server => "localhost", - :Port => port - ) - } - files.each { |file| - name = File.basename(file) - tmppath = File.join(tmpdir,name) - - # copy the files to our tmp directory so we can modify them... - #STDERR.puts("copying %s" % file) if $debug - File.open(tmppath,File::WRONLY|File::TRUNC|File::CREAT) { |wf| - File.open(file) { |rf| - wf.print(rf.read) - } - } - - assert(FileTest.exists?(tmppath)) - - osum = nil - tsum = nil - nsum = nil - assert_nothing_raised { - #STDERR.puts("backing up %s" % file) if $debug - osum = client.backup(file) - } - assert_nothing_raised { - #STDERR.puts("backing up %s" % tmppath) if $debug - tsum = client.backup(tmppath) - } - - assert(tsum == osum) - - File.open(tmppath,File::WRONLY|File::TRUNC) { |wf| - wf.print "This is some test text\n" - } - assert_nothing_raised { - #STDERR.puts("backing up %s" % tmppath) if $debug - nsum = client.backup(tmppath) - } - - assert(tsum != nsum) - - assert_nothing_raised { - #STDERR.puts("restoring %s" % tmppath) if $debug - nsum = client.restore(tmppath,tsum) - } - - assert_equal(tsum, nsum) - - contents = File.open(tmppath) { |rf| - #STDERR.puts("reading %s" % tmppath) if $debug - rf.read - } - csum = Digest::MD5.hexdigest(contents) - assert(tsum == csum) - } - - if $external - unless $pid - raise "Uh, we don't have a child pid" - end - system("kill %s" % $pid) - else - server.shutdown - - # make sure everything's complete before we stop - assert_nothing_raised() { - serverthread.join(60) - } - end - end -end diff --git a/test/executables/tc_puppetca.rb b/test/executables/tc_puppetca.rb index e657de483..6f799c670 100755 --- a/test/executables/tc_puppetca.rb +++ b/test/executables/tc_puppetca.rb @@ -1,7 +1,6 @@ if __FILE__ == $0 $:.unshift '../../lib' - $:.unshift '../../../../library/trunk/lib/' - $:.unshift '../../../../library/trunk/test/' + $:.unshift '..' $puppetbase = "../.." end @@ -54,7 +53,7 @@ class TestPuppetCA < Test::Unit::TestCase @@tmpfiles << Puppet[:ssldir] Puppet[:autosign] = false assert_nothing_raised { - ca = Puppet::CA.new() + ca = Puppet::Server::CA.new() } #Puppet.warning "SSLDir is %s" % Puppet[:ssldir] #system("find %s" % Puppet[:ssldir]) @@ -70,7 +69,7 @@ class TestPuppetCA < Test::Unit::TestCase output = nil assert_nothing_raised { - output = %x{puppetca --list --ssldir=#{Puppet[:ssldir]} 2>&1}.chomp.split("\n") + output = %x{puppetca --list --ssldir=#{Puppet[:ssldir]} 2>&1}.chomp.split("\n").reject { |line| line =~ /warning:/ } # stupid ssl.rb } #Puppet.warning "SSLDir is %s" % Puppet[:ssldir] #system("find %s" % Puppet[:ssldir]) diff --git a/test/language/tc_snippets.rb b/test/language/tc_snippets.rb index da1172f63..d1aaa023c 100755 --- a/test/language/tc_snippets.rb +++ b/test/language/tc_snippets.rb @@ -296,7 +296,7 @@ class TestSnippets < Test::Unit::TestCase testname = ("test_" + mname).intern self.send(:define_method, testname) { # first parse the file - server = Puppet::Master.new( + server = Puppet::Server::Master.new( :File => File.join($snippetbase, file), :Local => true ) diff --git a/test/other/tc_selector.rb b/test/other/tc_selector.rb deleted file mode 100644 index 47e0d9ff5..000000000 --- a/test/other/tc_selector.rb +++ /dev/null @@ -1,37 +0,0 @@ -if __FILE__ == $0 - $:.unshift '..' - $:.unshift '../../lib' - $puppetbase = "../../../../language/trunk" -end - -require 'puppet/selector' -require 'facter' -require 'test/unit' - -# $Id$ - -class TestSelector < Test::Unit::TestCase - def setup - @os = Facter["operatingsystem"].value - @hostname = Facter["hostname"].value - - Puppet[:loglevel] = :debug if __FILE__ == $0 - end - - def test_values - selector = nil - assert_nothing_raised() { - selector = Puppet::Selector.new { |select| - select.add("value1") { - Facter["hostname"].value == @hostname - } - } - } - - assert_equal( - "value1", - selector.evaluate() - ) - - end -end diff --git a/test/server/tc_bucket.rb b/test/server/tc_bucket.rb new file mode 100644 index 000000000..c4ad3d774 --- /dev/null +++ b/test/server/tc_bucket.rb @@ -0,0 +1,283 @@ +if __FILE__ == $0 + $:.unshift '../../lib' + $:.unshift '..' + $puppetbase = "../.." + $debug = true +else + $debug = false +end + +require 'puppet' +require 'test/unit' +require 'puppettest.rb' +require 'base64' + +# $Id$ + + +$external = true +if ARGV[1] and ARGV[1] == "external" + $external = true +else + # default to external + #$external = false +end +class TestBucket < Test::Unit::TestCase + def debug(string) + if $debug + puts([Time.now,string].join(" ")) + end + end + + def filelist + files = [] + #/etc/passwd /etc/syslog.conf /etc/hosts + %w{ + who /tmp/bigfile sh uname /etc/passwd /etc/syslog.conf /etc/hosts + }.each { |file| + if file =~ /^\// + if FileTest.exists?(file) + files.push file + end + else + begin + path = %x{which #{file}} + rescue => detail + #STDERR.puts "Could not search for binaries: %s" % detail + next + end + + if path != "" + files.push path.chomp + end + end + } + + return files + end + + def setup + @bucket = File::SEPARATOR + File.join("tmp","filebuckettesting") + end + + def teardown + system("rm -rf %s" % @bucket) + if defined? $pid + system("kill -9 #{$pid} 2>/dev/null") + end + end + + def test_localserver + files = filelist() + server =nil + assert_nothing_raised { + server = FileBucket::Bucket.new( + :Bucket => @bucket + ) + } + files.each { |file| + contents = File.open(file) { |of| of.read } + + md5 = nil + assert_nothing_raised { + #STDERR.puts("adding %s" % file) if $debug + md5 = server.addfile(Base64.encode64(contents),file) + } + newcontents = nil + assert_nothing_raised { + #STDERR.puts("getting %s" % file) if $debug + newcontents = Base64.decode64(server.getfile(md5)) + } + + assert( + contents == newcontents + ) + } + end + + def test_localboth + files = filelist() + + tmpdir = File.join(@bucket,"tmpfiledir") + FileBucket.mkdir(tmpdir) + + server = nil + client = nil + threads = [] + assert_nothing_raised { + server = FileBucket::Bucket.new( + :Bucket => @bucket + ) + } + + #sleep(30) + assert_nothing_raised { + client = FileBucket::Dipper.new( + :Bucket => server + ) + } + files.each { |file| + name = File.basename(file) + tmppath = File.join(tmpdir,name) + + # copy the files to our tmp directory so we can modify them... + #STDERR.puts("copying %s" % file) if $debug + File.open(tmppath,File::WRONLY|File::TRUNC|File::CREAT) { |wf| + File.open(file) { |rf| + wf.print(rf.read) + } + } + + assert(FileTest.exists?(tmppath)) + + osum = nil + tsum = nil + nsum = nil + assert_nothing_raised { + #STDERR.puts("backing up %s" % file) if $debug + osum = client.backup(file) + } + assert_nothing_raised { + #STDERR.puts("backing up %s" % tmppath) if $debug + tsum = client.backup(tmppath) + } + + assert(tsum == osum) + + File.open(tmppath,File::WRONLY|File::TRUNC) { |wf| + wf.print "This is some test text\n" + } + assert_nothing_raised { + #STDERR.puts("backing up %s" % tmppath) if $debug + nsum = client.backup(tmppath) + } + + assert(tsum != nsum) + + assert_nothing_raised { + #STDERR.puts("restoring %s" % tmppath) if $debug + nsum = client.restore(tmppath,tsum) + } + + contents = File.open(tmppath) { |rf| + #STDERR.puts("reading %s" % tmppath) if $debug + rf.read + } + csum = Digest::MD5.hexdigest(contents) + assert(tsum == csum) + } + end + + def test_webxmlmix + files = filelist() + + tmpdir = File.join(@bucket,"tmpfiledir") + FileBucket.mkdir(tmpdir) + + server = nil + client = nil + port = FileBucket::DEFAULTPORT + serverthread = nil + pid = nil + if $external + $pid = fork { + server = FileBucket::BucketWebserver.new( + :Bucket => @bucket, + :Port => port + ) + trap(:INT) { server.shutdown } + trap(:TERM) { server.shutdown } + server.start + } + sleep 3 + #puts "pid is %s" % pid + #exit + else + assert_nothing_raised { + server = FileBucket::BucketWebserver.new( + :Bucket => @bucket, + :Port => port + ) + } + assert_nothing_raised() { + trap(:INT) { server.shutdown } + serverthread = Thread.new { + server.start + } + } + end + + assert_nothing_raised { + client = FileBucket::Dipper.new( + :Server => "localhost", + :Port => port + ) + } + files.each { |file| + name = File.basename(file) + tmppath = File.join(tmpdir,name) + + # copy the files to our tmp directory so we can modify them... + #STDERR.puts("copying %s" % file) if $debug + File.open(tmppath,File::WRONLY|File::TRUNC|File::CREAT) { |wf| + File.open(file) { |rf| + wf.print(rf.read) + } + } + + assert(FileTest.exists?(tmppath)) + + osum = nil + tsum = nil + nsum = nil + assert_nothing_raised { + #STDERR.puts("backing up %s" % file) if $debug + osum = client.backup(file) + } + assert_nothing_raised { + #STDERR.puts("backing up %s" % tmppath) if $debug + tsum = client.backup(tmppath) + } + + assert(tsum == osum) + + File.open(tmppath,File::WRONLY|File::TRUNC) { |wf| + wf.print "This is some test text\n" + } + assert_nothing_raised { + #STDERR.puts("backing up %s" % tmppath) if $debug + nsum = client.backup(tmppath) + } + + assert(tsum != nsum) + + assert_nothing_raised { + #STDERR.puts("restoring %s" % tmppath) if $debug + nsum = client.restore(tmppath,tsum) + } + + assert_equal(tsum, nsum) + + contents = File.open(tmppath) { |rf| + #STDERR.puts("reading %s" % tmppath) if $debug + rf.read + } + csum = Digest::MD5.hexdigest(contents) + assert(tsum == csum) + } + + if $external + unless $pid + raise "Uh, we don't have a child pid" + end + system("kill %s" % $pid) + else + server.shutdown + + # make sure everything's complete before we stop + assert_nothing_raised() { + serverthread.join(60) + } + end + end +end diff --git a/test/server/tc_ca.rb b/test/server/tc_ca.rb index 9fb579638..e3f768b39 100644 --- a/test/server/tc_ca.rb +++ b/test/server/tc_ca.rb @@ -1,12 +1,11 @@ if __FILE__ == $0 $:.unshift '../../lib' - $:.unshift '../../../../library/trunk/lib/' - $:.unshift '../../../../library/trunk/test/' + $:.unshift '..' $puppetbase = "../.." end require 'puppet' -require 'puppet/ca' +require 'puppet/server/ca' require 'puppet/sslcertificates' require 'openssl' require 'test/unit' @@ -54,7 +53,7 @@ class TestCA < Test::Unit::TestCase ca = nil assert_nothing_raised { - ca = Puppet::CA.new() + ca = Puppet::Server::CA.new() } key = nil @@ -106,7 +105,7 @@ class TestCA < Test::Unit::TestCase ca = nil caserv = nil assert_nothing_raised { - caserv = Puppet::CA.new() + caserv = Puppet::Server::CA.new() } assert_nothing_raised { ca = caserv.ca @@ -163,7 +162,7 @@ class TestCA < Test::Unit::TestCase caserv = nil assert_nothing_raised { - caserv = Puppet::CA.new() + caserv = Puppet::Server::CA.new() } key = nil @@ -212,7 +211,7 @@ class TestCA < Test::Unit::TestCase caserv = nil file = File.join($puppetbase, "examples", "code", "head") assert_nothing_raised { - caserv = Puppet::CA.new() + caserv = Puppet::Server::CA.new() } assert(caserv.autosign?("hostmatch.domain.com")) diff --git a/test/server/tc_fileserver.rb b/test/server/tc_fileserver.rb index ad9b6298c..93b31db58 100755 --- a/test/server/tc_fileserver.rb +++ b/test/server/tc_fileserver.rb @@ -4,14 +4,12 @@ if __FILE__ == $0 end $:.unshift '../lib' - $:.unshift '../../../library/trunk/lib/' - $:.unshift '../../../library/trunk/test/' $puppetbase = ".." end require 'puppet' -require 'puppet/fileserver' +require 'puppet/server/fileserver' require 'test/unit' require 'puppettest.rb' @@ -34,24 +32,24 @@ class TestFileServer < TestPuppet def test_namefailures server = nil assert_nothing_raised { - server = Puppet::FileServer.new( + server = Puppet::Server::FileServer.new( :Local => true ) } - assert_raise(Puppet::FileServerError) { + assert_raise(Puppet::Server::FileServerError) { server.mount("/tmp", "invalid+name") } - assert_raise(Puppet::FileServerError) { + assert_raise(Puppet::Server::FileServerError) { server.mount("/tmp", "invalid-name") } - assert_raise(Puppet::FileServerError) { + assert_raise(Puppet::Server::FileServerError) { server.mount("/tmp", "invalid name") } - assert_raise(Puppet::FileServerError) { + assert_raise(Puppet::Server::FileServerError) { server.mount("/tmp", "") } end @@ -69,10 +67,10 @@ class TestFileServer < TestPuppet } file = nil - checks = Puppet::FileServer::CHECKPARAMS + checks = Puppet::Server::FileServer::CHECKPARAMS assert_nothing_raised { - server = Puppet::FileServer.new( + server = Puppet::Server::FileServer.new( :Local => true ) } @@ -114,7 +112,7 @@ class TestFileServer < TestPuppet file = nil assert_nothing_raised { - server = Puppet::FileServer.new( + server = Puppet::Server::FileServer.new( :Local => true ) } @@ -165,10 +163,10 @@ class TestFileServer < TestPuppet } file = nil - checks = Puppet::FileServer::CHECKPARAMS + checks = Puppet::Server::FileServer::CHECKPARAMS assert_nothing_raised { - server = Puppet::FileServer.new( + server = Puppet::Server::FileServer.new( :Local => true ) } @@ -200,7 +198,7 @@ class TestFileServer < TestPuppet def test_mountroot server = nil assert_nothing_raised { - server = Puppet::FileServer.new( + server = Puppet::Server::FileServer.new( :Local => true ) } @@ -230,7 +228,7 @@ class TestFileServer < TestPuppet def test_recursionlevels server = nil assert_nothing_raised { - server = Puppet::FileServer.new( + server = Puppet::Server::FileServer.new( :Local => true ) } @@ -275,7 +273,7 @@ class TestFileServer < TestPuppet def test_listedpath server = nil assert_nothing_raised { - server = Puppet::FileServer.new( + server = Puppet::Server::FileServer.new( :Local => true ) } @@ -312,7 +310,7 @@ class TestFileServer < TestPuppet def test_widelists server = nil assert_nothing_raised { - server = Puppet::FileServer.new( + server = Puppet::Server::FileServer.new( :Local => true ) } @@ -354,10 +352,10 @@ class TestFileServer < TestPuppet } file = nil - checks = Puppet::FileServer::CHECKPARAMS + checks = Puppet::Server::FileServer::CHECKPARAMS assert_nothing_raised { - server = Puppet::FileServer.new( + server = Puppet::Server::FileServer.new( :Local => true ) } diff --git a/test/server/tc_master.rb b/test/server/tc_master.rb index be61b232b..fce6ea925 100644 --- a/test/server/tc_master.rb +++ b/test/server/tc_master.rb @@ -1,27 +1,15 @@ if __FILE__ == $0 if Dir.getwd =~ /test\/server$/ Dir.chdir("..") - #puts "Unfortunately, you must be in the test dir to run this test." - #puts "Yes, I know it's different than all of the others." - #exit end $:.unshift '../lib' - $:.unshift '../../../library/trunk/lib/' - $:.unshift '../../../library/trunk/test/' $puppetbase = ".." end -#if __FILE__ == $0 -# $:.unshift '../../lib' -# $:.unshift '../../../../library/trunk/lib/' -# $:.unshift '../../../../library/trunk/test/' -# $puppetbase = "../.." -#end - require 'puppet' -require 'puppet/master' +require 'puppet/server' require 'puppet/client' require 'test/unit' require 'puppettest.rb' @@ -68,7 +56,7 @@ class TestMaster < Test::Unit::TestCase master = nil assert_nothing_raised() { # this is the default server setup - master = Puppet::Master.new( + master = Puppet::Server::Master.new( :File => file, :Local => true ) @@ -108,7 +96,7 @@ class TestMaster < Test::Unit::TestCase master = nil assert_nothing_raised() { # this is the default server setup - master = Puppet::Master.new( + master = Puppet::Server::Master.new( :File => file, :Local => true ) diff --git a/test/server/tc_server.rb b/test/server/tc_server.rb index d3a4ea305..d75d981ae 100644 --- a/test/server/tc_server.rb +++ b/test/server/tc_server.rb @@ -1,26 +1,12 @@ if __FILE__ == $0 $:.unshift '../../lib' - $:.unshift '../../../../library/trunk/lib/' - $:.unshift '../../../../library/trunk/test/' + $:.unshift '..' $puppetbase = "../.." end -#if __FILE__ == $0 -# $:.unshift '../lib' -# $:.unshift '../../../library/trunk/lib/' -# $:.unshift '../../../library/trunk/test/' -# $puppetbase = ".." -# -# -# if Dir.getwd !~ /test$/ -# puts "Unfortunately, you must be in the test dir to run this test." -# puts "Yes, I know it's different than all of the others." -# exit -# end -#end require 'puppet' require 'cgi' -require 'puppet/server' +#require 'puppet/server' require 'facter' require 'puppet/client' require 'xmlrpc/client' -- cgit