summaryrefslogtreecommitdiffstats
path: root/lib/puppet/client
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-01-24 06:01:58 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-01-24 06:01:58 +0000
commitae2575b45de1e8f4c0ec956cebe0eed2bafbcf57 (patch)
tree9c2b7c839087c285c228374f525315e55c392a34 /lib/puppet/client
parent18e8e74a2e3b4c5d092fc0aae38bbc5455d4db48 (diff)
downloadpuppet-ae2575b45de1e8f4c0ec956cebe0eed2bafbcf57.tar.gz
puppet-ae2575b45de1e8f4c0ec956cebe0eed2bafbcf57.tar.xz
puppet-ae2575b45de1e8f4c0ec956cebe0eed2bafbcf57.zip
Adding the event-loop stuff to the repository and switching to using it. Also, breaking many classes out into their own class files.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@848 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet/client')
-rw-r--r--lib/puppet/client/ca.rb17
-rw-r--r--lib/puppet/client/dipper.rb78
-rw-r--r--lib/puppet/client/file.rb20
-rw-r--r--lib/puppet/client/log.rb17
-rw-r--r--lib/puppet/client/master.rb244
-rw-r--r--lib/puppet/client/proxy.rb27
-rw-r--r--lib/puppet/client/status.rb7
7 files changed, 410 insertions, 0 deletions
diff --git a/lib/puppet/client/ca.rb b/lib/puppet/client/ca.rb
new file mode 100644
index 000000000..11989230c
--- /dev/null
+++ b/lib/puppet/client/ca.rb
@@ -0,0 +1,17 @@
+class Puppet::Client::CAClient < Puppet::Client::ProxyClient
+ @drivername = :CA
+
+ # set up the appropriate interface methods
+ @handler = Puppet::Server::CA
+ self.mkmethods
+
+ def initialize(hash = {})
+ if hash.include?(:CA)
+ hash[:CA] = Puppet::Server::CA.new()
+ end
+
+ super(hash)
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/client/dipper.rb b/lib/puppet/client/dipper.rb
new file mode 100644
index 000000000..281d0bab7
--- /dev/null
+++ b/lib/puppet/client/dipper.rb
@@ -0,0 +1,78 @@
+module Puppet
+ class Client
+ # The client class for filebuckets.
+ class Dipper < Puppet::Client
+ @drivername = :Bucket
+
+ def initialize(hash = {})
+ if hash.include?(:Path)
+ bucket = Puppet::Server::FileBucket.new(
+ :Bucket => hash[:Path]
+ )
+ hash.delete(:Path)
+ hash[:Bucket] = bucket
+ end
+
+ super(hash)
+ 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 = @driver.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
+ if tmp = @driver.getfile(sum)
+ newcontents = Base64.decode64(tmp)
+ newsum = Digest::MD5.hexdigest(newcontents)
+ changed = nil
+ unless FileTest.writable?(file)
+ changed = File.stat(file).mode
+ File.chmod(changed | 0200, file)
+ end
+ File.open(file,File::WRONLY|File::TRUNC) { |of|
+ of.print(newcontents)
+ }
+ if changed
+ File.chmod(changed, file)
+ end
+ else
+ Puppet.err "Could not find file with checksum %s" % sum
+ return nil
+ end
+ #puts "Done"
+ return newsum
+ else
+ return nil
+ end
+
+ end
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/client/file.rb b/lib/puppet/client/file.rb
new file mode 100644
index 000000000..116624003
--- /dev/null
+++ b/lib/puppet/client/file.rb
@@ -0,0 +1,20 @@
+class Puppet::Client::FileClient < Puppet::Client::ProxyClient
+ @drivername = :FileServer
+
+ # set up the appropriate interface methods
+ @handler = Puppet::Server::FileServer
+
+ self.mkmethods
+
+ def initialize(hash = {})
+ if hash.include?(:FileServer)
+ unless hash[:FileServer].is_a?(Puppet::Server::FileServer)
+ raise Puppet::DevError, "Must pass an actual FS object"
+ end
+ end
+
+ super(hash)
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/client/log.rb b/lib/puppet/client/log.rb
new file mode 100644
index 000000000..e20c0532c
--- /dev/null
+++ b/lib/puppet/client/log.rb
@@ -0,0 +1,17 @@
+class Puppet::Client::LogClient < Puppet::Client::ProxyClient
+ @drivername = :Logger
+
+ # set up the appropriate interface methods
+ @handler = Puppet::Server::Logger
+ self.mkmethods
+
+ def initialize(hash = {})
+ if hash.include?(:Logger)
+ hash[:Logger] = Puppet::Server::Logger.new()
+ end
+
+ super(hash)
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/client/master.rb b/lib/puppet/client/master.rb
new file mode 100644
index 000000000..f0204c418
--- /dev/null
+++ b/lib/puppet/client/master.rb
@@ -0,0 +1,244 @@
+# The client for interacting with the puppetmaster config server.
+class Puppet::Client::MasterClient < Puppet::Client
+ @drivername = :Master
+
+ def self.facts
+ facts = {}
+ Facter.each { |name,fact|
+ facts[name] = fact.downcase
+ }
+
+ facts
+ end
+
+ # This method is how the client receives the tree of Transportable
+ # objects. For now, just descend into the tree and perform and
+ # necessary manipulations.
+ def apply
+ dostorage()
+ unless defined? @objects
+ raise Puppet::Error, "Cannot apply; objects not defined"
+ end
+
+ #Puppet.err :yay
+ #p @objects
+ #Puppet.err :mark
+ #@objects = @objects.to_type
+ # this is a gross hack... but i don't see a good way around it
+ # set all of the variables to empty
+ Puppet::Transaction.init
+
+ # For now we just evaluate the top-level object, but eventually
+ # there will be schedules and such associated with each object,
+ # and probably with the container itself.
+ transaction = @objects.evaluate
+ #transaction = Puppet::Transaction.new(objects)
+ transaction.toplevel = true
+ begin
+ transaction.evaluate
+ rescue Puppet::Error => detail
+ Puppet.err "Could not apply complete configuration: %s" %
+ detail
+ rescue => detail
+ Puppet.err "Found a bug: %s" % detail
+ if Puppet[:debug]
+ puts detail.backtrace
+ end
+ ensure
+ Puppet::Storage.store
+ end
+ Puppet::Metric.gather
+ Puppet::Metric.tally
+ if Puppet[:rrdgraph] == true
+ Metric.store
+ Metric.graph
+ end
+
+ return transaction
+ end
+
+ # Cache the config
+ def cache(text)
+ Puppet.info "Caching configuration at %s" % self.cachefile
+ confdir = File.dirname(Puppet[:localconfig])
+ unless FileTest.exists?(confdir)
+ Puppet.recmkdir(confdir, 0770)
+ end
+ File.open(self.cachefile + ".tmp", "w", 0660) { |f|
+ f.print text
+ }
+ File.rename(self.cachefile + ".tmp", self.cachefile)
+ end
+
+ def cachefile
+ unless defined? @cachefile
+ @cachefile = Puppet[:localconfig] + ".yaml"
+ end
+ @cachefile
+ end
+
+ # Initialize and load storage
+ def dostorage
+ begin
+ Puppet::Storage.init
+ Puppet::Storage.load
+ rescue => detail
+ Puppet.err "Corrupt state file %s: %s" % [Puppet[:checksumfile], detail]
+ begin
+ File.unlink(Puppet[:checksumfile])
+ retry
+ rescue => detail
+ raise Puppet::Error.new("Cannot remove %s: %s" %
+ [Puppet[statefile], detail])
+ end
+ end
+ end
+
+ # Check whether our configuration is up to date
+ def fresh?
+ unless defined? @configstamp
+ return false
+ end
+
+ # We're willing to give a 2 second drift
+ if @driver.freshness - @configstamp < 1
+ return true
+ else
+ return false
+ end
+ end
+
+ # Retrieve the config from a remote server. If this fails, then
+ # use the cached copy.
+ def getconfig
+ if self.fresh?
+ Puppet.info "Config is up to date"
+ return
+ end
+ Puppet.debug("getting config")
+ dostorage()
+
+ facts = self.class.facts
+
+ unless facts.length > 0
+ raise Puppet::ClientError.new(
+ "Could not retrieve any facts"
+ )
+ end
+
+ objects = nil
+ if @local
+ # If we're local, we don't have to do any of the conversion
+ # stuff.
+ objects = @driver.getconfig(facts, "yaml")
+ @configstamp = Time.now.to_i
+
+ if objects == ""
+ raise Puppet::Error, "Could not retrieve configuration"
+ end
+ else
+ textobjects = ""
+
+ textfacts = CGI.escape(YAML.dump(facts))
+
+ # error handling for this is done in the network client
+ begin
+ textobjects = @driver.getconfig(textfacts, "yaml")
+ rescue => detail
+ Puppet.err "Could not retrieve configuration: %s" % detail
+ end
+
+ fromcache = false
+ if textobjects == ""
+ textobjects = self.retrievecache
+ if textobjects == ""
+ raise Puppet::Error.new(
+ "Cannot connect to server and there is no cached configuration"
+ )
+ end
+ Puppet.notice "Could not get config; using cached copy"
+ fromcache = true
+ end
+
+ begin
+ textobjects = CGI.unescape(textobjects)
+ @configstamp = Time.now.to_i
+ rescue => detail
+ raise Puppet::Error, "Could not CGI.unescape configuration"
+ end
+
+ if @cache and ! fromcache
+ self.cache(textobjects)
+ end
+
+ begin
+ objects = YAML.load(textobjects)
+ rescue => detail
+ raise Puppet::Error,
+ "Could not understand configuration: %s" %
+ detail.to_s
+ end
+ end
+
+ unless objects.is_a?(Puppet::TransBucket)
+ raise NetworkClientError,
+ "Invalid returned objects of type %s" % objects.class
+ end
+
+ if classes = objects.classes
+ self.setclasses(classes)
+ else
+ Puppet.info "No classes to store"
+ end
+
+ # Clear all existing objects, so we can recreate our stack.
+ if defined? @objects
+ Puppet::Type.allclear
+ end
+ @objects = nil
+
+ # First create the default scheduling objects
+ Puppet.type(:schedule).mkdefaultschedules
+
+ # Now convert the objects to real Puppet objects
+ @objects = objects.to_type
+
+ if @objects.nil?
+ raise Puppet::Error, "Configuration could not be processed"
+ end
+ #@objects = objects
+
+ # and perform any necessary final actions before we evaluate.
+ Puppet::Type.finalize
+
+ return @objects
+ end
+
+ # Retrieve the cached config
+ def retrievecache
+ if FileTest.exists?(self.cachefile)
+ return File.read(self.cachefile)
+ else
+ return ""
+ end
+ end
+
+ # The code that actually runs the configuration.
+ def run
+ self.getconfig
+ self.apply
+ end
+
+ def setclasses(ary)
+ begin
+ File.open(Puppet[:classfile], "w") { |f|
+ f.puts ary.join("\n")
+ }
+ rescue => detail
+ Puppet.err "Could not create class file %s: %s" %
+ [Puppet[:classfile], detail]
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/client/proxy.rb b/lib/puppet/client/proxy.rb
new file mode 100644
index 000000000..2ea0a87f9
--- /dev/null
+++ b/lib/puppet/client/proxy.rb
@@ -0,0 +1,27 @@
+# unlike the other client classes (again, this design sucks) this class
+# is basically just a proxy class -- it calls its methods on the driver
+# and that's about it
+class Puppet::Client::ProxyClient < Puppet::Client
+ def self.mkmethods
+ interface = @handler.interface
+ namespace = interface.prefix
+
+ interface.methods.each { |ary|
+ method = ary[0]
+ Puppet.debug "%s: defining %s.%s" % [self, namespace, method]
+ self.send(:define_method,method) { |*args|
+ begin
+ @driver.send(method, *args)
+ rescue XMLRPC::FaultException => detail
+ #Puppet.err "Could not call %s.%s: %s" %
+ # [namespace, method, detail.faultString]
+ #raise NetworkClientError,
+ # "XMLRPC Error: %s" % detail.faultString
+ raise NetworkClientError, detail.faultString
+ end
+ }
+ }
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/client/status.rb b/lib/puppet/client/status.rb
new file mode 100644
index 000000000..ed1445e04
--- /dev/null
+++ b/lib/puppet/client/status.rb
@@ -0,0 +1,7 @@
+class Puppet::Client::StatusClient < Puppet::Client::ProxyClient
+ # set up the appropriate interface methods
+ @handler = Puppet::Server::ServerStatus
+ self.mkmethods
+end
+
+# $Id$