summaryrefslogtreecommitdiffstats
path: root/lib/puppet/server
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2007-02-08 01:39:39 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2007-02-08 01:39:39 +0000
commit7e07e3dc843798bdbc7a03428ca054adaff2fb72 (patch)
tree34d0f9f8c2ee11bdc281e6e4d18cad444253fe36 /lib/puppet/server
parent6d8068eddd0d29ec53f62557eb53f6ebb8e40591 (diff)
downloadpuppet-7e07e3dc843798bdbc7a03428ca054adaff2fb72.tar.gz
puppet-7e07e3dc843798bdbc7a03428ca054adaff2fb72.tar.xz
puppet-7e07e3dc843798bdbc7a03428ca054adaff2fb72.zip
Moving all of the client and server code into a single network/ directory. In other words, more code structure cleanup.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@2179 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet/server')
-rw-r--r--lib/puppet/server/authconfig.rb177
-rwxr-xr-xlib/puppet/server/authstore.rb229
-rw-r--r--lib/puppet/server/ca.rb155
-rwxr-xr-xlib/puppet/server/filebucket.rb169
-rwxr-xr-xlib/puppet/server/fileserver.rb591
-rwxr-xr-xlib/puppet/server/logger.rb54
-rw-r--r--lib/puppet/server/master.rb214
-rwxr-xr-xlib/puppet/server/report.rb176
-rwxr-xr-xlib/puppet/server/resource.rb191
-rwxr-xr-xlib/puppet/server/rights.rb78
-rwxr-xr-xlib/puppet/server/runner.rb64
-rw-r--r--lib/puppet/server/servlet.rb277
12 files changed, 0 insertions, 2375 deletions
diff --git a/lib/puppet/server/authconfig.rb b/lib/puppet/server/authconfig.rb
deleted file mode 100644
index d43371a77..000000000
--- a/lib/puppet/server/authconfig.rb
+++ /dev/null
@@ -1,177 +0,0 @@
-require 'puppet/util/loadedfile'
-require 'puppet/server/rights'
-
-module Puppet
-class Server
-
-class ConfigurationError < Puppet::Error; end
-
-class AuthConfig < Puppet::Util::LoadedFile
- Puppet.config.setdefaults(:puppet,
- :authconfig => [ "$confdir/namespaceauth.conf",
- "The configuration file that defines the rights to the different
- namespaces and methods. This can be used as a coarse-grained
- authorization system for both ``puppetd`` and ``puppetmasterd``."
- ]
- )
-
- # Just proxy the setting methods to our rights stuff
- [:allow, :deny].each do |method|
- define_method(method) do |*args|
- @rights.send(method, *args)
- end
- end
-
- # Here we add a little bit of semantics. They can set auth on a whole namespace
- # or on just a single method in the namespace.
- def allowed?(name, host, ip)
- namespace, method = name.to_s.split(".")
- unless namespace and method
- raise ArgumentError, "Invalid method name %s" % name
- end
-
- name = name.intern if name.is_a? String
- namespace = namespace.intern
- method = method.intern
-
- read()
-
- if @rights.include?(name)
- return @rights[name].allowed?(host, ip)
- elsif @rights.include?(namespace)
- return @rights[namespace].allowed?(host, ip)
- else
- return false
- end
- end
-
- # Does the file exist? Puppetmasterd does not require it, but
- # puppetd does.
- def exists?
- FileTest.exists?(@file)
- end
-
- def initialize(file = nil, parsenow = true)
- @file ||= Puppet[:authconfig]
-
- unless @file
- raise Puppet::DevError, "No authconfig file defined"
- end
- return unless self.exists?
- super(@file)
- @rights = Rights.new
- @configstamp = @configstatted = nil
- @configtimeout = 60
-
- if parsenow
- read()
- end
- end
-
- # Read the configuration file.
- def read
- return unless FileTest.exists?(@file)
-
- if @configstamp
- if @configtimeout and @configstatted
- if Time.now - @configstatted > @configtimeout
- @configstatted = Time.now
- tmp = File.stat(@file).ctime
-
- if tmp == @configstamp
- return
- else
- Puppet.notice "%s vs %s" % [tmp, @configstamp]
- end
- else
- return
- end
- else
- Puppet.notice "%s and %s" % [@configtimeout, @configstatted]
- end
- end
-
- parse()
-
- @configstamp = File.stat(@file).ctime
- @configstatted = Time.now
- end
-
- private
-
- def parse
- newrights = Puppet::Server::Rights.new
- begin
- File.open(@file) { |f|
- right = nil
- count = 1
- f.each { |line|
- case line
- when /^\s*#/: next # skip comments
- when /^\s*$/: next # skip blank lines
- when /\[([\w.]+)\]/: # "namespace" or "namespace.method"
- name = $1
- if newrights.include?(name)
- raise FileServerError, "%s is already set at %s" %
- [newrights[name], name]
- end
- newrights.newright(name)
- right = newrights[name]
- when /^\s*(\w+)\s+(.+)$/:
- var = $1
- value = $2
- case var
- when "allow":
- value.split(/\s*,\s*/).each { |val|
- begin
- right.info "allowing %s access" % val
- right.allow(val)
- rescue AuthStoreError => detail
- raise ConfigurationError, "%s at line %s of %s" %
- [detail.to_s, count, @config]
- end
- }
- when "deny":
- value.split(/\s*,\s*/).each { |val|
- begin
- right.info "denying %s access" % val
- right.deny(val)
- rescue AuthStoreError => detail
- raise ConfigurationError, "%s at line %s of %s" %
- [detail.to_s, count, @config]
- end
- }
- else
- raise ConfigurationError,
- "Invalid argument '%s' at line %s" % [var, count]
- end
- else
- raise ConfigurationError, "Invalid line %s: %s" % [count, line]
- end
- count += 1
- }
- }
- rescue Errno::EACCES => detail
- Puppet.err "Configuration error: Cannot read %s; cannot serve" % @file
- #raise Puppet::Error, "Cannot read %s" % @config
- rescue Errno::ENOENT => detail
- Puppet.err "Configuration error: '%s' does not exit; cannot serve" %
- @file
- #raise Puppet::Error, "%s does not exit" % @config
- #rescue FileServerError => detail
- # Puppet.err "FileServer error: %s" % detail
- end
-
- # Verify each of the rights are valid.
- # We let the check raise an error, so that it can raise an error
- # pointing to the specific problem.
- newrights.each { |name, right|
- right.valid?
- }
- @rights = newrights
- end
-end
-end
-end
-
-# $Id$
diff --git a/lib/puppet/server/authstore.rb b/lib/puppet/server/authstore.rb
deleted file mode 100755
index b0f63b68a..000000000
--- a/lib/puppet/server/authstore.rb
+++ /dev/null
@@ -1,229 +0,0 @@
-# standard module for determining whether a given hostname or IP has access to
-# the requested resource
-
-require 'ipaddr'
-
-module Puppet
-class Server
- class AuthStoreError < Puppet::Error; end
- class AuthorizationError < Puppet::Error; end
-
- class AuthStore
- # This has to be an array, not a hash, else it loses its ordering.
- ORDER = [
- [:ip, [:ip]],
- [:name, [:hostname, :domain]]
- ]
-
- Puppet::Util.logmethods(self, true)
-
- def allow(pattern)
- # a simple way to allow anyone at all to connect
- if pattern == "*"
- @globalallow = true
- else
- store(pattern, @allow)
- end
- end
-
- def allowed?(name, ip)
- if name or ip
- # This is probably unnecessary, and can cause some weirdnesses in
- # cases where we're operating over localhost but don't have a real
- # IP defined.
- unless name and ip
- raise Puppet::DevError, "Name and IP must be passed to 'allowed?'"
- end
- # else, we're networked and such
- else
- # we're local
- return true
- end
-
- # yay insecure overrides
- if @globalallow
- return true
- end
-
- value = nil
- ORDER.each { |nametype, array|
- if nametype == :ip
- value = IPAddr.new(ip)
- else
- value = name.split(".").reverse
- end
-
-
- array.each { |type|
- [[@deny, false], [@allow, true]].each { |ary|
- hash, retval = ary
- if hash.include?(type)
- hash[type].each { |pattern|
- if match?(nametype, value, pattern)
- return retval
- end
- }
- end
- }
- }
- }
-
- self.info "defaulting to no access for %s" % name
- # default to false
- return false
- end
-
- def deny(pattern)
- store(pattern, @deny)
- end
-
- def initialize
- @globalallow = nil
- @allow = Hash.new { |hash, key|
- hash[key] = []
- }
- @deny = Hash.new { |hash, key|
- hash[key] = []
- }
- end
-
- private
-
- def match?(nametype, value, pattern)
- if value == pattern # simplest shortcut
- return true
- end
-
- case nametype
- when :ip: matchip?(value, pattern)
- when :name: matchname?(value, pattern)
- else
- raise Puppet::DevError, "Invalid match type %s" % nametype
- end
- end
-
- def matchip?(value, pattern)
- # we're just using builtin stuff for this, thankfully
- if pattern.include?(value)
- return true
- else
- return false
- end
- end
-
- def matchname?(value, pattern)
- # yay, horribly inefficient
- if pattern[-1] != '*' # the pattern has no metachars and is not equal
- # thus, no match
- #Puppet.info "%s is not equal with no * in %s" % [value, pattern]
- return false
- else
- # we know the last field of the pattern is '*'
- # if everything up to that doesn't match, we're definitely false
- if pattern[0..-2] != value[0..pattern.length-2]
- #Puppet.notice "subpatterns didn't match; %s vs %s" %
- # [pattern[0..-2], value[0..pattern.length-2]]
- return false
- end
-
- case value.length <=> pattern.length
- when -1: # value is shorter than pattern
- if pattern.length - value.length == 1
- # only ever allowed when the value is the domain of a
- # splatted pattern
- #Puppet.info "allowing splatted domain %s" % [value]
- return true
- else
- return false
- end
- when 0: # value is the same length as pattern
- if pattern[-1] == "*"
- #Puppet.notice "same length with *"
- return true
- else
- return false
- end
- when 1: # value is longer than pattern
- # at this point we've already verified that everything up to
- # the '*' in the pattern matches, so we are true
- return true
- end
- end
- end
-
- def store(pattern, hash)
- type, value = type(pattern)
-
- if type and value
- # this won't work once we get beyond simple stuff...
- hash[type] << value
- else
- raise AuthStoreError, "Invalid pattern %s" % pattern
- end
- end
-
- def type(pattern)
- type = value = nil
- case pattern
- when /^(\d+\.){3}\d+$/:
- type = :ip
- begin
- value = IPAddr.new(pattern)
- rescue ArgumentError => detail
- raise AuthStoreError, "Invalid IP address pattern %s" % pattern
- end
- when /^(\d+\.){3}\d+\/(\d+)$/:
- mask = Integer($2)
- if mask < 1 or mask > 32
- raise AuthStoreError, "Invalid IP mask %s" % mask
- end
- type = :ip
- begin
- value = IPAddr.new(pattern)
- rescue ArgumentError => detail
- raise AuthStoreError, "Invalid IP address pattern %s" % pattern
- end
- when /^(\d+\.){1,3}\*$/: # an ip address with a '*' at the end
- type = :ip
- match = $1
- match.sub!(".", '')
- ary = pattern.split(".")
-
- mask = case ary.index(match)
- when 0: 8
- when 1: 16
- when 2: 24
- else
- raise AuthStoreError, "Invalid IP pattern %s" % pattern
- end
-
- ary.pop
- while ary.length < 4
- ary.push("0")
- end
-
- begin
- value = IPAddr.new(ary.join(".") + "/" + mask.to_s)
- rescue ArgumentError => detail
- raise AuthStoreError, "Invalid IP address pattern %s" % pattern
- end
- when /^[\d.]+$/: # necessary so incomplete IP addresses can't look
- # like hostnames
- raise AuthStoreError, "Invalid IP address pattern %s" % pattern
- when /^([a-zA-Z][-\w]*\.)+[-\w]+$/: # a full hostname
- type = :hostname
- value = pattern.split(".").reverse
- when /^\*(\.([a-zA-Z][-\w]*)){1,}$/:
- type = :domain
- value = pattern.split(".").reverse
- else
- raise AuthStoreError, "Invalid pattern %s" % pattern
- end
-
- return [type, value]
- end
- end
-end
-end
-#
-# $Id$
diff --git a/lib/puppet/server/ca.rb b/lib/puppet/server/ca.rb
deleted file mode 100644
index 10fafc940..000000000
--- a/lib/puppet/server/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 Server
- class CAError < Puppet::Error; end
- class CA < Handler
- attr_reader :ca
-
- @interface = XMLRPC::Service::Interface.new("puppetca") { |iface|
- iface.add_method("array getcert(csr)")
- }
-
- def autosign
- if defined? @autosign
- @autosign
- else
- Puppet[:autosign]
- end
- end
-
- # FIXME autosign? should probably accept both hostnames and IP addresses
- def autosign?(hostname)
- # simple values are easy
- if autosign == true or autosign == false
- return autosign
- end
-
- # we only otherwise know how to handle files
- unless autosign =~ /^\//
- raise Puppet::Error, "Invalid autosign value %s" %
- autosign.inspect
- end
-
- unless FileTest.exists?(autosign)
- unless defined? @@warnedonautosign
- @@warnedonautosign = true
- Puppet.info "Autosign is enabled but %s is missing" % autosign
- end
- return false
- end
- auth = Puppet::Server::AuthStore.new
- File.open(autosign) { |f|
- f.each { |line|
- next if line =~ /^\s*#/
- next if line =~ /^\s*$/
- auth.allow(line.chomp)
- }
- }
-
- # for now, just cheat and pass a fake IP address to allowed?
- return auth.allowed?(hostname, "127.1.1.1")
- end
-
- def initialize(hash = {})
- Puppet.config.use(:puppet, :certificates, :ca)
- if hash.include? :autosign
- @autosign = hash[:autosign]
- end
-
- @ca = Puppet::SSLCertificates::CA.new(hash)
- end
-
- # our client sends us a csr, and we either store it for later signing,
- # or we sign it right away
- def getcert(csrtext, client = nil, clientip = nil)
- csr = OpenSSL::X509::Request.new(csrtext)
-
- # Use the hostname from the CSR, not from the network.
- subject = csr.subject
-
- nameary = subject.to_a.find { |ary|
- ary[0] == "CN"
- }
-
- if nameary.nil?
- Puppet.err(
- "Invalid certificate request: could not retrieve server name"
- )
- return "invalid"
- end
-
- hostname = nameary[1]
-
- unless @ca
- Puppet.notice "Host %s asked for signing from non-CA master" % hostname
- return ""
- end
-
- # We used to save the public key, but it's basically unnecessary
- # and it mucks with the permissions requirements.
- # save_pk(hostname, csr.public_key)
-
- certfile = File.join(Puppet[:certdir], [hostname, "pem"].join("."))
-
- # 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) or client.nil?
- if client.nil?
- Puppet.info "Signing certificate for CA server"
- end
- # 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.notice "Host %s has a waiting certificate request" %
- hostname
- @ca.storeclientcsr(csr)
- end
- return ["", ""]
- end
- else
- raise "huh?"
- end
- end
-
- private
-
- # Save the public key.
- def save_pk(hostname, public_key)
- 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
- end
- end
-end
-end
-
-# $Id$
diff --git a/lib/puppet/server/filebucket.rb b/lib/puppet/server/filebucket.rb
deleted file mode 100755
index 56d994366..000000000
--- a/lib/puppet/server/filebucket.rb
+++ /dev/null
@@ -1,169 +0,0 @@
-#--------------------
-# accept and serve files
-
-
-require 'webrick'
-require 'xmlrpc/server'
-require 'xmlrpc/client'
-require 'facter'
-require 'digest/md5'
-require 'puppet/external/base64'
-
-module Puppet
-class Server
- class BucketError < RuntimeError; end
- class FileBucket < Handler
- Puppet.config.setdefaults("puppetmasterd",
- :bucketdir => {
- :default => "$vardir/bucket",
- :mode => 0750,
- :owner => "$user",
- :group => "$group",
- :desc => "Where FileBucket files are stored."
- }
- )
-
- Puppet.config.setdefaults("filebucket",
- :clientbucketdir => {
- :default => "$vardir/clientbucket",
- :mode => 0750,
- :desc => "Where FileBucket files are stored locally."
- }
- )
- @interface = XMLRPC::Service::Interface.new("puppetbucket") { |iface|
- iface.add_method("string addfile(string, string)")
- iface.add_method("string getfile(string)")
- }
-
- Puppet::Util.logmethods(self, true)
- attr_reader :name, :path
-
- # this doesn't work for relative paths
- def FileBucket.paths(base,md5)
- return [
- File.join(base, md5),
- File.join(base, md5, "contents"),
- File.join(base, md5, "paths")
- ]
- end
-
- def initialize(hash)
- if hash.include?(:ConflictCheck)
- @conflictchk = hash[:ConflictCheck]
- hash.delete(:ConflictCheck)
- else
- @conflictchk = true
- end
-
- if hash.include?(:Path)
- @path = hash[:Path]
- hash.delete(:Path)
- else
- if defined? Puppet
- @path = Puppet[:bucketdir]
- else
- @path = File.expand_path("~/.filebucket")
- end
- end
-
- Puppet.config.use(:filebucket)
-
- @name = "Filebucket[#{@path}]"
- end
-
- # accept a file from a client
- def addfile(contents, path, client = nil, clientip = nil)
- if client
- contents = Base64.decode64(contents)
- end
- md5 = Digest::MD5.hexdigest(contents)
-
- bpath, bfile, pathpath = FileBucket.paths(@path,md5)
-
- # if it's a new directory...
- if Puppet.recmkdir(bpath)
- msg = "Adding %s(%s)" % [path, md5]
- msg += " from #{client}" if client
- self.info msg
- # ...then just create the file
- File.open(bfile, File::WRONLY|File::CREAT, 0440) { |of|
- of.print contents
- }
- 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.read(bfile)
-
- # 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)
- else
- msg = "Got duplicate %s(%s)" % [path, md5]
- msg += " from #{client}" if client
- self.info msg
- end
- end
- end
-
- contents = ""
-
- # 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.collect { |l| l.chomp }
- }
-
- # unless our path is already there...
- unless paths.include?(path)
- addpath = true
- end
- else
- addpath = true
- end
-
- # 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
- }
- end
-
- return md5
- end
-
- def getfile(md5, client = nil, clientip = nil)
- bpath, bfile, bpaths = FileBucket.paths(@path,md5)
-
- unless FileTest.exists?(bfile)
- return false
- end
-
- contents = nil
- File.open(bfile) { |of|
- contents = of.read
- }
-
- if client
- return Base64.encode64(contents)
- else
- return contents
- end
- end
-
- def to_s
- self.name
- end
- end
-end
-end
-#
-# $Id$
diff --git a/lib/puppet/server/fileserver.rb b/lib/puppet/server/fileserver.rb
deleted file mode 100755
index 3ea44d785..000000000
--- a/lib/puppet/server/fileserver.rb
+++ /dev/null
@@ -1,591 +0,0 @@
-require 'puppet'
-require 'webrick/httpstatus'
-require 'cgi'
-require 'delegate'
-
-module Puppet
-class FileServerError < Puppet::Error; end
-class Server
- class FileServer < Handler
- attr_accessor :local
-
- Puppet.setdefaults("fileserver",
- :fileserverconfig => ["$confdir/fileserver.conf",
- "Where the fileserver configuration is stored."])
-
- CHECKPARAMS = [:mode, :type, :owner, :group, :checksum]
-
- @interface = XMLRPC::Service::Interface.new("fileserver") { |iface|
- iface.add_method("string describe(string, string)")
- iface.add_method("string list(string, string, boolean, array)")
- iface.add_method("string retrieve(string, string)")
- }
-
- # Describe a given file. This returns all of the manageable aspects
- # of that file.
- def describe(url, links = :ignore, client = nil, clientip = nil)
- links = links.intern if links.is_a? String
-
- if links == :manage
- raise Puppet::FileServerError, "Cannot currently copy links"
- end
-
- mount, path = convert(url, client, clientip)
-
- if client
- mount.debug "Describing %s for %s" % [url, client]
- end
-
- obj = nil
- unless obj = mount.check(path, links)
- return ""
- end
-
- desc = []
- CHECKPARAMS.each { |check|
- if property = obj.property(check)
- unless property.is
- mount.debug "Manually retrieving info for %s" % check
- property.retrieve
- end
- desc << property.is
- else
- if check == "checksum" and obj.property(:type).is == "file"
- mount.notice "File %s does not have data for %s" %
- [obj.name, check]
- end
- desc << nil
- end
- }
-
- return desc.join("\t")
- end
-
- # Create a new fileserving module.
- def initialize(hash = {})
- @mounts = {}
- @files = {}
-
- if hash[:Local]
- @local = hash[:Local]
- else
- @local = false
- end
-
- if hash[:Config] == false
- @noreadconfig = true
- else
- @config = Puppet::Util::LoadedFile.new(
- hash[:Config] || Puppet[:fileserverconfig]
- )
- @noreadconfig = false
- end
-
- if hash.include?(:Mount)
- @passedconfig = true
- unless hash[:Mount].is_a?(Hash)
- raise Puppet::DevError, "Invalid mount hash %s" %
- hash[:Mount].inspect
- end
-
- hash[:Mount].each { |dir, name|
- if FileTest.exists?(dir)
- self.mount(dir, name)
- end
- }
- else
- @passedconfig = false
- readconfig(false) # don't check the file the first time.
- end
- end
-
- # List a specific directory's contents.
- def list(url, links = :ignore, recurse = false, ignore = false, client = nil, clientip = nil)
- mount, path = convert(url, client, clientip)
-
- if client
- mount.debug "Listing %s for %s" % [url, client]
- end
-
- obj = nil
- unless FileTest.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)
-
- if desc.length == 0
- mount.notice "Got no information on //%s/%s" %
- [mount, path]
- return ""
- end
-
- desc.collect { |sub|
- sub.join("\t")
- }.join("\n")
- end
-
- def local?
- self.local
- end
-
- # Mount a new directory with a name.
- def mount(path, name)
- if @mounts.include?(name)
- if @mounts[name] != path
- raise FileServerError, "%s is already mounted at %s" %
- [@mounts[name].path, name]
- else
- # it's already mounted; no problem
- return
- end
- end
-
- # Let the mounts do their own error-checking.
- @mounts[name] = Mount.new(name, path)
- @mounts[name].info "Mounted %s" % path
-
- return @mounts[name]
- end
-
- # Retrieve a file from the local disk and pass it to the remote
- # client.
- def retrieve(url, links = :ignore, client = nil, clientip = nil)
- links = links.intern if links.is_a? String
-
- mount, path = convert(url, client, clientip)
-
- if client
- mount.info "Sending %s to %s" % [url, client]
- end
-
- unless FileTest.exists?(path)
- return ""
- end
-
- links = links.intern if links.is_a? String
-
- if links == :ignore and FileTest.symlink?(path)
- return ""
- end
-
- str = nil
- if links == :manage
- raise Puppet::Error, "Cannot copy links yet."
- else
- str = File.read(path)
- end
-
- if @local
- return str
- else
- return CGI.escape(str)
- end
- end
-
- def umount(name)
- @mounts.delete(name) if @mounts.include? name
- end
-
- private
-
- def authcheck(file, mount, client, clientip)
- # If we're local, don't bother passing in information.
- if local?
- client = nil
- clientip = nil
- end
- unless mount.allowed?(client, clientip)
- mount.warning "%s cannot access %s" %
- [client, file]
- raise Puppet::Server::AuthorizationError, "Cannot access %s" % mount
- end
- end
-
- def convert(url, client, clientip)
- readconfig
-
- url = URI.unescape(url)
-
- mount, stub = splitpath(url, client)
-
- 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
- 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
-
- # Read the configuration file.
- def readconfig(check = true)
- return if @noreadconfig
-
- if check and ! @config.changed?
- return
- end
-
- newmounts = {}
- begin
- File.open(@config.file) { |f|
- mount = nil
- count = 1
- f.each { |line|
- case line
- when /^\s*#/: next # skip comments
- when /^\s*$/: next # skip blank lines
- when /\[(\w+)\]/:
- name = $1
- if newmounts.include?(name)
- raise FileServerError, "%s is already mounted at %s" %
- [newmounts[name], name], count, @config.file
- end
- mount = Mount.new(name)
- newmounts[name] = mount
- when /^\s*(\w+)\s+(.+)$/:
- var = $1
- value = $2
- case var
- when "path":
- begin
- mount.path = value
- rescue FileServerError => detail
- Puppet.err "Removing mount %s: %s" %
- [mount.name, detail]
- newmounts.delete(mount.name)
- end
- when "allow":
- value.split(/\s*,\s*/).each { |val|
- begin
- mount.info "allowing %s access" % val
- mount.allow(val)
- rescue AuthStoreError => detail
- raise FileServerError.new(detail.to_s,
- count, @config.file)
- end
- }
- when "deny":
- value.split(/\s*,\s*/).each { |val|
- begin
- mount.info "denying %s access" % val
- mount.deny(val)
- rescue AuthStoreError => detail
- raise FileServerError.new(detail.to_s,
- count, @config.file)
- end
- }
- else
- raise FileServerError.new("Invalid argument '%s'" % var,
- count, @config.file)
- end
- else
- raise FileServerError.new("Invalid line '%s'" % line.chomp,
- count, @config.file)
- end
- count += 1
- }
- }
- rescue Errno::EACCES => detail
- Puppet.err "FileServer error: Cannot read %s; cannot serve" % @config
- #raise Puppet::Error, "Cannot read %s" % @config
- rescue Errno::ENOENT => detail
- Puppet.err "FileServer error: '%s' does not exist; cannot serve" %
- @config
- #raise Puppet::Error, "%s does not exit" % @config
- #rescue FileServerError => detail
- # Puppet.err "FileServer error: %s" % detail
- end
-
- # Verify each of the mounts are valid.
- # We let the check raise an error, so that it can raise an error
- # pointing to the specific problem.
- newmounts.each { |name, mount|
- unless mount.valid?
- raise FileServerError, "No path specified for mount %s" %
- name
- end
- }
- @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+)/?}
- tmp = $1
- path = dir.sub(%r{/#{tmp}/?}, '')
-
- unless mount = @mounts[tmp]
- raise FileServerError, "Fileserver module '%s' not mounted" % tmp
- end
- else
- raise FileServerError, "Fileserver error: Invalid path '%s'" % dir
- end
-
- if path == ""
- path = nil
- else
- # Remove any double slashes that might have occurred
- path = URI.unescape(path.gsub(/\/\//, "/"))
- end
-
- return mount, path
- 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 :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 a map for a specific client.
- def clientmap(client)
- {
- "h" => client.sub(/\..*$/, ""),
- "H" => client,
- "d" => client.sub(/[^.]+\./, "") # domain name
- }
- end
-
- # Replace % patterns as appropriate.
- def expand(path, client = nil)
- # This map should probably be moved into a method.
- map = nil
-
- if client
- map = clientmap(client)
- else
- Puppet.notice "No client; expanding '%s' with local host" %
- path
- # Else, use the local information
- map = localmap()
- end
- path.gsub(/%(.)/) do |v|
- key = $1
- if key == "%"
- "%"
- else
- map[key] || v
- end
- end
- end
-
- # Do we have any patterns in our path, yo?
- def expandable?
- if defined? @expandable
- @expandable
- else
- false
- end
- end
-
- # Create out object. It must have a name.
- def initialize(name, path = nil)
- unless name =~ %r{^\w+$}
- raise FileServerError, "Invalid name format '%s'" % name
- end
- @name = name
-
- if path
- self.path = path
- else
- @path = nil
- end
-
- 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
- )
- end
-
- if links == :manage
- links = :follow
- end
-
- # This, ah, might be completely redundant
- unless obj[:links] == links
- obj[:links] = links
- end
-
- return obj
- end
-
- # Cache this manufactured map, since if it's used it's likely
- # to get used a lot.
- def localmap
- unless defined? @@localmap
- @@localmap = {
- "h" => Facter.value("hostname"),
- "H" => [Facter.value("hostname"),
- Facter.value("domain")].join("."),
- "d" => Facter.value("domain")
- }
- end
- @@localmap
- end
-
- # Return the path as appropriate, expanding as necessary.
- def path(client = nil)
- if expandable?
- return expand(@path, client)
- else
- return @path
- end
- end
-
- # Set the path.
- def path=(path)
- # FIXME: For now, just don't validate paths with replacement
- # patterns in them.
- if path =~ /%./
- # Mark that we're expandable.
- @expandable = true
- else
- unless FileTest.exists?(path)
- raise FileServerError, "%s does not exist" % path
- end
- unless FileTest.directory?(path)
- raise FileServerError, "%s is not a directory" % path
- end
- unless FileTest.readable?(path)
- raise FileServerError, "%s is not readable" % path
- end
- @expandable = false
- end
- @path = path
- end
-
- # Retrieve a specific directory relative to a mount point.
- # If they pass in a client, then expand as necessary.
- def subdir(dir = nil, client = nil)
- basedir = self.path(client)
-
- dirname = if dir
- File.join(basedir, dir.split("/").join(File::SEPARATOR))
- else
- basedir
- end
-
- dirname
- end
-
- def to_s
- "mount[#{@name}]"
- end
-
- # Verify our configuration is valid. This should really check to
- # make sure at least someone will be allowed, but, eh.
- def valid?
- return false unless @path
-
- return true
- end
- end
- end
-end
-end
-
-# $Id$
diff --git a/lib/puppet/server/logger.rb b/lib/puppet/server/logger.rb
deleted file mode 100755
index aa3521573..000000000
--- a/lib/puppet/server/logger.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require 'yaml'
-
-module Puppet
-class Server
- class LoggerError < RuntimeError; end
-
- # Receive logs from remote hosts.
- class Logger < Handler
- @interface = XMLRPC::Service::Interface.new("puppetlogger") { |iface|
- iface.add_method("void addlog(string)")
- }
-
- # accept a log message from a client, and route it accordingly
- def addlog(message, client = nil, clientip = nil)
- unless message
- raise Puppet::DevError, "Did not receive message"
- end
-
- Puppet.info message.inspect
- # if the client is set, then we're not local
- if client
- begin
- message = YAML.load(CGI.unescape(message))
- #message = message
- rescue => detail
- raise XMLRPC::FaultException.new(
- 1, "Could not unYAML log message from %s" % client
- )
- end
- end
-
- unless message
- raise Puppet::DevError, "Could not resurrect message"
- end
-
- # Mark it as remote, so it's not sent to syslog
- message.remote = true
-
- if client
- if ! message.source or message.source == "Puppet"
- message.source = client
- end
- end
-
- Puppet::Util::Log.newmessage(message)
-
- # This is necessary or XMLRPC gets all pukey
- return ""
- end
- end
-end
-end
-
-# $Id$
diff --git a/lib/puppet/server/master.rb b/lib/puppet/server/master.rb
deleted file mode 100644
index cda6027d0..000000000
--- a/lib/puppet/server/master.rb
+++ /dev/null
@@ -1,214 +0,0 @@
-require 'openssl'
-require 'puppet'
-require 'puppet/parser/interpreter'
-require 'puppet/sslcertificates'
-require 'xmlrpc/server'
-require 'yaml'
-
-module Puppet
-class Server
- class MasterError < Puppet::Error; end
- class Master < Handler
- include Puppet::Util
-
- attr_accessor :ast, :local
- attr_reader :ca
-
- @interface = XMLRPC::Service::Interface.new("puppetmaster") { |iface|
- iface.add_method("string getconfig(string)")
- iface.add_method("int freshness()")
- }
-
- # FIXME At some point, this should be autodocumenting.
- def addfacts(facts)
- # Add our server version to the fact list
- facts["serverversion"] = Puppet.version.to_s
-
- # And then add the server name and IP
- {"servername" => "hostname",
- "serverip" => "ipaddress"
- }.each do |var, fact|
- if obj = Facter[fact]
- facts[var] = obj.value
- else
- Puppet.warning "Could not retrieve fact %s" % fact
- end
- end
- end
-
- # Manipulate the client name as appropriate.
- def clientname(name, ip, facts)
- # Always use the hostname from Facter.
- client = facts["hostname"]
- clientip = facts["ipaddress"]
- if Puppet[:node_name] == 'cert'
- if name
- client = name
- end
- if ip
- clientip = ip
- end
- end
-
- return client, clientip
- end
-
- # Tell a client whether there's a fresh config for it
- def freshness(client = nil, clientip = nil)
- if Puppet.features.rails? and Puppet[:storeconfigs]
- host = Puppet::Rails::Host.find_or_create_by_name(client)
- host.last_freshcheck = Time.now
- if clientip and (! host.ip or host.ip == "")
- host.ip = clientip
- end
- host.save
- end
- if defined? @interpreter
- return @interpreter.parsedate
- else
- return 0
- end
- end
-
- def initialize(hash = {})
- args = {}
-
- # Allow specification of a code snippet or of a file
- if code = hash[:Code]
- args[:Code] = code
- else
- args[:Manifest] = hash[:Manifest] || Puppet[:manifest]
- end
-
- if hash[:Local]
- @local = hash[:Local]
- else
- @local = false
- end
-
- args[:Local] = @local
-
- if hash.include?(:CA) and hash[:CA]
- @ca = Puppet::SSLCertificates::CA.new()
- else
- @ca = nil
- end
-
- Puppet.debug("Creating interpreter")
-
- if hash.include?(:UseNodes)
- args[:UseNodes] = hash[:UseNodes]
- elsif @local
- args[:UseNodes] = false
- end
-
- # This is only used by the cfengine module, or if --loadclasses was
- # specified in +puppet+.
- if hash.include?(:Classes)
- args[:Classes] = hash[:Classes]
- end
-
- @interpreter = Puppet::Parser::Interpreter.new(args)
- end
-
- def getconfig(facts, format = "marshal", client = nil, clientip = nil)
- 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
- case format
- when "marshal":
- Puppet.warning "You should upgrade your client. 'Marshal' will not be supported much longer."
- begin
- facts = Marshal::load(CGI.unescape(facts))
- rescue => detail
- raise XMLRPC::FaultException.new(
- 1, "Could not rebuild facts"
- )
- end
- when "yaml":
- begin
- facts = YAML.load(CGI.unescape(facts))
- rescue => detail
- raise XMLRPC::FaultException.new(
- 1, "Could not rebuild facts"
- )
- end
- else
- raise XMLRPC::FaultException.new(
- 1, "Unavailable config format %s" % format
- )
- end
- end
-
- client, clientip = clientname(client, clientip, facts)
-
- # Add any server-side facts to our server.
- addfacts(facts)
-
- retobjects = nil
-
- # This is hackish, but there's no "silence" option for benchmarks
- # right now
- if @local
- #begin
- retobjects = @interpreter.run(client, facts)
- #rescue Puppet::Error => detail
- # Puppet.err detail
- # raise XMLRPC::FaultException.new(
- # 1, detail.to_s
- # )
- #rescue => detail
- # Puppet.err detail.to_s
- # return ""
- #end
- else
- benchmark(:notice, "Compiled configuration for %s" % client) do
- begin
- retobjects = @interpreter.run(client, facts)
- rescue Puppet::Error => detail
- Puppet.err detail
- raise XMLRPC::FaultException.new(
- 1, detail.to_s
- )
- rescue => detail
- Puppet.err detail.to_s
- return ""
- end
- end
- end
-
- if @local
- return retobjects
- else
- str = nil
- case format
- when "marshal":
- str = Marshal::dump(retobjects)
- when "yaml":
- str = YAML.dump(retobjects)
- else
- raise XMLRPC::FaultException.new(
- 1, "Unavailable config format %s" % format
- )
- end
- return CGI.escape(str)
- end
- end
-
- def local?
- if defined? @local and @local
- return true
- else
- return false
- end
- end
- end
-end
-end
-
-# $Id$
diff --git a/lib/puppet/server/report.rb b/lib/puppet/server/report.rb
deleted file mode 100755
index 4298f8ee6..000000000
--- a/lib/puppet/server/report.rb
+++ /dev/null
@@ -1,176 +0,0 @@
-module Puppet
-class Server
- # A simple server for triggering a new run on a Puppet client.
- class Report < Handler
- class << self
- include Puppet::Util::ClassGen
- end
-
- module ReportBase
- include Puppet::Util::Docs
- attr_writer :useyaml
-
- def useyaml?
- if defined? @useyaml
- @useyaml
- else
- false
- end
- end
- end
-
- @interface = XMLRPC::Service::Interface.new("puppetreports") { |iface|
- iface.add_method("string report(array)")
- }
-
- Puppet.setdefaults(:reporting,
- :reports => ["store",
- "The list of reports to generate. All reports are looked for
- in puppet/reports/<name>.rb, and multiple report names should be
- comma-separated (whitespace is okay)."
- ],
- :reportdir => {:default => "$vardir/reports",
- :mode => 0750,
- :owner => "$user",
- :group => "$group",
- :desc => "The directory in which to store reports
- received from the client. Each client gets a separate
- subdirectory."}
- )
-
- @reports = {}
- @reportloader = Puppet::Util::Autoload.new(self, "puppet/reports")
-
- class << self
- attr_reader :hooks
- end
-
- # Add a new report type.
- def self.newreport(name, options = {}, &block)
- name = symbolize(name)
-
- mod = genmodule(name, :extend => ReportBase, :hash => @reports, :block => block)
-
- if options[:useyaml]
- mod.useyaml = true
- end
-
- mod.send(:define_method, :report_name) do
- name
- end
- end
-
- # Load a report.
- def self.report(name)
- name = name.intern if name.is_a? String
- unless @reports.include? name
- if @reportloader.load(name)
- unless @reports.include? name
- Puppet.warning(
- "Loaded report file for %s but report was not defined" %
- name
- )
- return nil
- end
- else
- return nil
- end
- end
- @reports[symbolize(name)]
- end
-
- def self.reportdocs
- docs = ""
-
- # Use this method so they all get loaded
- reports.sort { |a,b| a.to_s <=> b.to_s }.each do |name|
- mod = self.report(name)
- docs += "## %s\n\n" % name
-
- docs += Puppet::Util::Docs.scrub(mod.doc) + "\n\n"
- end
-
- docs
- end
-
- def self.reports
- @reportloader.loadall
- @reports.keys
- end
-
- def initialize(*args)
- super
- Puppet.config.use(:reporting)
- Puppet.config.use(:metrics)
- end
-
- # Accept a report from a client.
- def report(report, client = nil, clientip = nil)
- # Unescape the report
- unless @local
- report = CGI.unescape(report)
- end
-
- begin
- process(report)
- rescue => detail
- Puppet.err "Could not process report %s: %s" % [$1, detail]
- if Puppet[:trace]
- puts detail.backtrace
- end
- end
- end
-
- private
-
- # Process the report using all of the existing hooks.
- def process(yaml)
- return if Puppet[:reports] == "none"
-
- # First convert the report to real objects
- begin
- report = YAML.load(yaml)
- rescue => detail
- Puppet.warning "Could not load report: %s" % detail
- return
- end
-
- # Used for those reports that accept yaml
- client = report.host
-
- reports().each do |name|
- if mod = self.class.report(name)
- Puppet.info "Processing report %s for %s" % [name, client]
-
- # We have to use a dup because we're including a module in the
- # report.
- newrep = report.dup
- begin
- newrep.extend(mod)
- if mod.useyaml?
- newrep.process(yaml)
- else
- newrep.process
- end
- rescue => detail
- if Puppet[:trace]
- puts detail.backtrace
- end
- Puppet.err "Report %s failed: %s" %
- [name, detail]
- end
- else
- Puppet.warning "No report named '%s'" % name
- end
- end
- end
-
- # Handle the parsing of the reports attribute.
- def reports
- Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
- end
- end
-end
-end
-
-# $Id$
diff --git a/lib/puppet/server/resource.rb b/lib/puppet/server/resource.rb
deleted file mode 100755
index d2bad52f3..000000000
--- a/lib/puppet/server/resource.rb
+++ /dev/null
@@ -1,191 +0,0 @@
-require 'puppet'
-require 'puppet/server'
-
-module Puppet
-
-# Serve Puppet elements. Useful for querying, copying, and, um, other stuff.
-class Server::Resource < Server::Handler
- attr_accessor :local
-
- @interface = XMLRPC::Service::Interface.new("resource") { |iface|
- iface.add_method("string apply(string, string)")
- iface.add_method("string describe(string, string, array, array)")
- iface.add_method("string list(string, array, string)")
- }
-
- # Apply a TransBucket as a transaction.
- def apply(bucket, format = "yaml", client = nil, clientip = nil)
- unless @local
- begin
- case format
- when "yaml":
- bucket = YAML::load(Base64.decode64(bucket))
- else
- raise Puppet::Error, "Unsupported format '%s'" % format
- end
- rescue => detail
- raise Puppet::Error, "Could not load YAML TransBucket: %s" % detail
- end
- end
-
- component = bucket.to_type
-
- # Create a client, but specify the remote machine as the server
- # because the class requires it, even though it's unused
- client = Puppet::Client::MasterClient.new(:Server => client||"localhost")
-
- # Set the objects
- client.objects = component
-
- # And then apply the configuration. This way we're reusing all
- # the code in there. It should probably just be separated out, though.
- transaction = client.apply
-
- # And then clean up
- component.remove
-
- # It'd be nice to return some kind of report, but... at this point
- # we have no such facility.
- return "success"
- end
-
- # Describe a given object. This returns the 'is' values for every property
- # available on the object type.
- def describe(type, name, retrieve = nil, ignore = [], format = "yaml", client = nil, clientip = nil)
- Puppet.info "Describing %s[%s]" % [type.to_s.capitalize, name]
- @local = true unless client
- typeklass = nil
- unless typeklass = Puppet.type(type)
- raise Puppet::Error, "Puppet type %s is unsupported" % type
- end
-
- obj = nil
-
- retrieve ||= :all
- ignore ||= []
-
- if obj = typeklass[name]
- obj[:check] = retrieve
- else
- begin
- obj = typeklass.create(:name => name, :check => retrieve)
- rescue Puppet::Error => detail
- raise Puppet::Error, "%s[%s] could not be created: %s" %
- [type, name, detail]
- end
- end
-
- unless obj
- raise XMLRPC::FaultException.new(
- 1, "Could not create %s[%s]" % [type, name]
- )
- end
-
- trans = obj.to_trans
-
- # Now get rid of any attributes they specifically don't want
- ignore.each do |st|
- if trans.include? st
- trans.delete(st)
- end
- end
-
- # And get rid of any attributes that are nil
- trans.each do |attr, value|
- if value.nil?
- trans.delete(attr)
- end
- end
-
- unless @local
- case format
- when "yaml":
- trans = Base64.encode64(YAML::dump(trans))
- else
- raise XMLRPC::FaultException.new(
- 1, "Unavailable config format %s" % format
- )
- end
- end
-
- return trans
- end
-
- # Create a new fileserving module.
- def initialize(hash = {})
- if hash[:Local]
- @local = hash[:Local]
- else
- @local = false
- end
- end
-
- # List all of the elements of a given type.
- def list(type, ignore = [], base = nil, format = "yaml", client = nil, clientip = nil)
- @local = true unless client
- typeklass = nil
- unless typeklass = Puppet.type(type)
- raise Puppet::Error, "Puppet type %s is unsupported" % type
- end
-
- # They can pass in false
- ignore ||= []
- ignore = [ignore] unless ignore.is_a? Array
- bucket = TransBucket.new
- bucket.type = typeklass.name
-
- typeklass.list.each do |obj|
- next if ignore.include? obj.name
-
- object = TransObject.new(obj.name, typeklass.name)
- bucket << object
- end
-
- unless @local
- case format
- when "yaml":
- begin
- bucket = Base64.encode64(YAML::dump(bucket))
- rescue => detail
- Puppet.err detail
- raise XMLRPC::FaultException.new(
- 1, detail.to_s
- )
- end
- else
- raise XMLRPC::FaultException.new(
- 1, "Unavailable config format %s" % format
- )
- end
- end
-
- return bucket
- end
-
- private
-
- def authcheck(file, mount, client, clientip)
- unless mount.allowed?(client, clientip)
- mount.warning "%s cannot access %s" %
- [client, file]
- raise Puppet::Server::AuthorizationError, "Cannot access %s" % mount
- end
- 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
-
- def to_s
- "resource"
- end
-end
-end
-
-# $Id$
diff --git a/lib/puppet/server/rights.rb b/lib/puppet/server/rights.rb
deleted file mode 100755
index 0ed12a122..000000000
--- a/lib/puppet/server/rights.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-require 'ipaddr'
-require 'puppet/server/authstore'
-
-module Puppet
-class Server
- # Define a set of rights and who has access to them.
- class Rights < Hash
- # We basically just proxy directly to our rights. Each Right stores
- # its own auth abilities.
- [:allow, :allowed?, :deny].each do |method|
- define_method(method) do |name, *args|
- name = name.intern if name.is_a? String
-
- if obj = right(name)
- obj.send(method, *args)
- else
- raise ArgumentError, "Unknown right '%s'" % name
- end
- end
- end
-
- def [](name)
- name = name.intern if name.is_a? String
- super(name)
- end
-
- # Define a new right to which access can be provided.
- def newright(name)
- name = name.intern if name.is_a? String
- shortname = Right.shortname(name)
- if self.include? name
- raise ArgumentError, "Right '%s' is already defined" % name
- else
- self[name] = Right.new(name, shortname)
- end
- end
-
- private
-
- # Retrieve a right by name.
- def right(name)
- name = name.intern if name.is_a? String
- self[name]
- end
-
- # A right.
- class Right < AuthStore
- attr_accessor :name, :shortname
-
- Puppet::Util.logmethods(self, true)
-
- def self.shortname(name)
- name.to_s[0..0]
- end
-
- def initialize(name, shortname = nil)
- @name = name
- @shortname = shortname
- unless @shortname
- @shortname = Right.shortname(name)
- end
- super()
- end
-
- def to_s
- "access[%s]" % @name
- end
-
- # There's no real check to do at this point
- def valid?
- true
- end
- end
- end
-end
-end
-#
-# $Id$
diff --git a/lib/puppet/server/runner.rb b/lib/puppet/server/runner.rb
deleted file mode 100755
index 46fd7a7ae..000000000
--- a/lib/puppet/server/runner.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-module Puppet
-class Server
- class MissingMasterError < RuntimeError # Cannot find the master client
- end
- # A simple server for triggering a new run on a Puppet client.
- class Runner < Handler
- @interface = XMLRPC::Service::Interface.new("puppetrunner") { |iface|
- iface.add_method("string run(string, string)")
- }
-
- # Run the client configuration right now, optionally specifying
- # tags and whether to ignore schedules
- def run(tags = nil, ignoreschedules = false, fg = true, client = nil, clientip = nil)
- # We need to retrieve the client
- master = Puppet::Client::MasterClient.instance
-
- unless master
- raise MissingMasterError, "Could not find the master client"
- end
-
- if Puppet::Util::Pidlock.new(Puppet[:puppetdlockfile]).locked?
- Puppet.notice "Could not trigger run; already running"
- return "running"
- end
-
- if tags == ""
- tags = nil
- end
-
- if ignoreschedules == ""
- ignoreschedules == nil
- end
-
- msg = ""
- if client
- msg = "%s(%s) " % [client, clientip]
- end
- msg += "triggered run" %
- if tags
- msg += " with tags %s" % tags
- end
-
- if ignoreschedules
- msg += " without schedules"
- end
-
- Puppet.notice msg
-
- # And then we need to tell it to run, with this extra info.
- if fg
- master.run(tags, ignoreschedules)
- else
- Puppet.newthread do
- master.run(tags, ignoreschedules)
- end
- end
-
- return "success"
- end
- end
-end
-end
-
-# $Id$
diff --git a/lib/puppet/server/servlet.rb b/lib/puppet/server/servlet.rb
deleted file mode 100644
index 81219ef44..000000000
--- a/lib/puppet/server/servlet.rb
+++ /dev/null
@@ -1,277 +0,0 @@
-require 'xmlrpc/server'
-
-module Puppet
-class Server
- class ServletError < RuntimeError; end
- class Servlet < XMLRPC::WEBrickServlet
- ERR_UNAUTHORIZED = 30
-
- 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
-
- # This is a hackish way to avoid an auth message every time we have a
- # normal operation
- def self.log(msg)
- unless defined? @logs
- @logs = {}
- end
- if @logs.include?(msg)
- @logs[msg] += 1
- else
- Puppet.info msg
- @logs[msg] = 1
- end
- end
-
- def add_handler(interface, handler)
- @loadedhandlers << interface.prefix
- super
- end
-
- # Verify that our client has access. We allow untrusted access to
- # puppetca methods but no others.
- def authorize(request, method)
- namespace = method.sub(/\..+/, '')
- client = request.peeraddr[2]
- if defined? @client and @client
- client = @client
- end
- ip = request.peeraddr[3]
- if request.client_cert
- if @puppetserver.authconfig.exists?
- allowed = @puppetserver.authconfig.allowed?(method, client, ip)
-
- if allowed
- Puppet.debug "Allowing %s(%s) trusted access to %s" %
- [client, ip, method]
- return true
- else
- Puppet.debug "Denying %s(%s) trusted access to %s" %
- [client, ip, method]
- return false
- end
- else
- # This is pretty hackish, but...
- # This means we can't actually test this method at this point.
- # The next release of Puppet will almost definitely require
- # this file to exist or will default to denying all access.
- if Puppet.name == "puppetmasterd" or defined? Test::Unit::TestCase
- Puppet.debug "Allowing %s(%s) trusted access to %s" %
- [client, ip, method]
- return true
- else
- Puppet.debug "Denying %s(%s) trusted access to %s on %s" %
- [client, ip, method, Puppet.name]
- return false
- end
- end
- else
- if method =~ /^puppetca\./
- Puppet.notice "Allowing %s(%s) untrusted access to CA methods" %
- [client, ip]
- else
- Puppet.err "Unauthenticated client %s(%s) cannot call %s" %
- [client, ip, method]
- return false
- end
- end
- end
-
- def available?(method)
- namespace = method.sub(/\..+/, '')
- client = request.peeraddr[2]
- ip = request.peeraddr[3]
- if @loadedhandlers.include?(namespace)
- return true
- else
- Puppet.warning "Client %s(%s) requested unavailable functionality %s" %
- [client, ip, namespace]
- return false
- end
- end
-
- def initialize(server, handlers)
- @puppetserver = server
- @notified = {}
- # 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()
-
- @loadedhandlers = []
- handlers.each { |handler|
- #Puppet.debug "adding handler for %s" % handler.class
- self.add_handler(handler.class.interface, handler)
- }
-
- # Initialize these to nil, but they will get set to values
- # by the 'service' method. These have to instance variables
- # because I don't have a clear line from the service method to
- # the service hook.
- @request = nil
- @client = nil
- @clientip = nil
-
- self.set_service_hook { |obj, *args|
- if @client and @clientip
- args.push(@client, @clientip)
- end
- begin
- obj.call(*args)
- rescue XMLRPC::FaultException
- raise
- rescue Puppet::Server::AuthorizationError => detail
- #Puppet.warning obj.inspect
- #Puppet.warning args.inspect
- Puppet.err "Permission denied: %s" % detail.to_s
- raise XMLRPC::FaultException.new(
- 1, detail.to_s
- )
- rescue Puppet::Error => detail
- #Puppet.warning obj.inspect
- #Puppet.warning args.inspect
- if Puppet[:trace]
- puts detail.backtrace
- end
- Puppet.err detail.to_s
- error = XMLRPC::FaultException.new(
- 1, detail.to_s
- )
- error.set_backtrace detail.backtrace
- raise error
- rescue => detail
- #Puppet.warning obj.inspect
- #Puppet.warning args.inspect
- if Puppet[:trace]
- puts detail.backtrace
- end
- Puppet.err "Could not call: %s" % detail.to_s
- error = XMLRPC::FaultException.new(1, detail.to_s)
- error.set_backtrace detail.backtrace
- raise error
- end
- }
- end
-
- # Handle the actual request. This does some basic collection of
- # data, and then just calls the parent method.
- def service(request, response)
- @request = request
-
- # The only way that @client can be nil is if the request is local.
- if peer = request.peeraddr
- @client = peer[2]
- @clientip = peer[3]
- else
- raise XMLRPC::FaultException.new(
- ERR_UNCAUGHT_EXCEPTION,
- "Could not retrieve client information"
- )
- end
-
- # If they have a certificate (which will almost always be true)
- # then we get the hostname from the cert, instead of via IP
- # info
- if cert = request.client_cert
- nameary = cert.subject.to_a.find { |ary|
- ary[0] == "CN"
- }
-
- if nameary.nil?
- Puppet.warning "Could not retrieve server name from cert"
- else
- unless @client == nameary[1]
- Puppet.debug "Overriding %s with cert name %s" %
- [@client, nameary[1]]
- @client = nameary[1]
- end
- end
- end
- begin
- super
- rescue => detail
- Puppet.err "Could not service request: %s: %s" %
- [detail.class, detail]
- end
- @client = nil
- @clientip = nil
- @request = nil
- end
-
- private
-
- # this is pretty much just a copy of the original method but with more
- # feedback
- # here's where we have our authorization hooks
- def dispatch(methodname, *args)
-
- if defined? @request and @request
- unless self.available?(methodname)
- raise XMLRPC::FaultException.new(
- ERR_UNAUTHORIZED,
- "Functionality %s not available" %
- methodname.sub(/\..+/, '')
- )
- end
- unless self.authorize(@request, methodname)
- raise XMLRPC::FaultException.new(
- ERR_UNAUTHORIZED,
- "Host %s not authorized to call %s" %
- [@request.host, methodname]
- )
- end
- else
- raise Puppet::DevError, "Did not get request in dispatch"
- end
-
- #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