summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2007-11-12 22:11:40 -0600
committerLuke Kanies <luke@madstop.com>2007-11-12 22:11:40 -0600
commitfa1924eb04a2d6600349eddf13e1f3e62b45d6ce (patch)
tree978aa0e92812f5854978048162c6e2ab752dad72 /lib
parenta535cbbe148802c0afe62cd2d5b29d0768b3a0f0 (diff)
parent72510bfaa65e97f4eaaf246ef8f1c155716967b6 (diff)
downloadpuppet-fa1924eb04a2d6600349eddf13e1f3e62b45d6ce.tar.gz
puppet-fa1924eb04a2d6600349eddf13e1f3e62b45d6ce.tar.xz
puppet-fa1924eb04a2d6600349eddf13e1f3e62b45d6ce.zip
Merge branch 'master' of ssh://reductivelabs.com/opt/rl/git/puppet-luke
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/indirector/facts/memory.rb9
-rw-r--r--lib/puppet/indirector/indirection.rb8
-rw-r--r--lib/puppet/metatype/instances.rb11
-rw-r--r--lib/puppet/metatype/metaparams.rb35
-rw-r--r--lib/puppet/network/client/master.rb171
-rwxr-xr-xlib/puppet/network/handler/runner.rb2
-rw-r--r--lib/puppet/network/http.rb13
-rw-r--r--lib/puppet/network/http/handler.rb109
-rw-r--r--lib/puppet/network/http/mongrel.rb54
-rw-r--r--lib/puppet/network/http/mongrel/rest.rb37
-rw-r--r--lib/puppet/network/http/mongrel/xmlrpc.rb4
-rw-r--r--lib/puppet/network/http/webrick.rb51
-rw-r--r--lib/puppet/network/http/webrick/rest.rb41
-rw-r--r--lib/puppet/network/http/webrick/xmlrpc.rb4
-rw-r--r--lib/puppet/network/server.rb105
-rw-r--r--lib/puppet/node/configuration.rb20
-rw-r--r--lib/puppet/parser/compile.rb30
-rw-r--r--lib/puppet/transaction.rb2
-rw-r--r--lib/puppet/transportable.rb93
-rw-r--r--lib/puppet/type.rb21
-rw-r--r--lib/puppet/type/component.rb4
-rwxr-xr-xlib/puppet/type/pfile/group.rb4
22 files changed, 569 insertions, 259 deletions
diff --git a/lib/puppet/indirector/facts/memory.rb b/lib/puppet/indirector/facts/memory.rb
new file mode 100644
index 000000000..3c10d5964
--- /dev/null
+++ b/lib/puppet/indirector/facts/memory.rb
@@ -0,0 +1,9 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/memory'
+
+class Puppet::Node::Facts::Memory < Puppet::Indirector::Memory
+ desc "Keep track of facts in memory but nowhere else. This is used for
+ one-time compiles, such as what the stand-alone ``puppet`` does.
+ To use this terminus, you must load it with the data you want it
+ to contain."
+end
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
index 9a9b1c0bf..816b4ffc5 100644
--- a/lib/puppet/indirector/indirection.rb
+++ b/lib/puppet/indirector/indirection.rb
@@ -13,6 +13,14 @@ class Puppet::Indirector::Indirection
@@indirections.find { |i| i.name == name }
end
+ # Find an indirected model by name. This is provided so that Terminus classes
+ # can specifically hook up with the indirections they are associated with.
+ def self.model(name)
+ match = @@indirections.find { |i| i.name == name }
+ return nil unless match
+ match.model
+ end
+
attr_accessor :name, :model
# Create and return our cache terminus.
diff --git a/lib/puppet/metatype/instances.rb b/lib/puppet/metatype/instances.rb
index 2f9918067..8cc648e8f 100644
--- a/lib/puppet/metatype/instances.rb
+++ b/lib/puppet/metatype/instances.rb
@@ -99,6 +99,8 @@ class Puppet::Type
end
end
+ # If they've specified a type and called on the base, then
+ # delegate to the subclass.
if type
if typeklass = self.type(type)
return typeklass.create(hash)
@@ -233,19 +235,22 @@ class Puppet::Type
hash.delete :name
end
- unless title
- raise Puppet::Error,
- "You must specify a title for objects of type %s" % self.to_s
+ if configuration = hash[:configuration]
+ hash.delete(:configuration)
end
+ raise(Puppet::Error, "You must specify a title for objects of type %s" % self.to_s) unless title
+
if hash.include? :type
unless self.validattr? :type
hash.delete :type
end
end
+
# okay, now make a transobject out of hash
begin
trans = Puppet::TransObject.new(title, self.name.to_s)
+ trans.configuration = configuration if configuration
hash.each { |param, value|
trans[param] = value
}
diff --git a/lib/puppet/metatype/metaparams.rb b/lib/puppet/metatype/metaparams.rb
index 1ab3f26c1..eb158a47d 100644
--- a/lib/puppet/metatype/metaparams.rb
+++ b/lib/puppet/metatype/metaparams.rb
@@ -94,7 +94,7 @@ class Puppet::Type
# We've got four relationship metaparameters, so this method is used
# to reduce code duplication between them.
- def store_relationship(param, values)
+ def munge_relationship(param, values)
# We need to support values passed in as an array or as a
# resource reference.
result = []
@@ -194,20 +194,24 @@ class Puppet::Type
unless aliases.is_a?(Array)
aliases = [aliases]
end
- @resource.info "Adding aliases %s" % aliases.collect { |a|
- a.inspect
- }.join(", ")
+
+ raise(ArgumentError, "Cannot add aliases without a configuration") unless @resource.configuration
+
+ @resource.info "Adding aliases %s" % aliases.collect { |a| a.inspect }.join(", ")
+
aliases.each do |other|
- if obj = @resource.class[other]
- unless obj == @resource
- self.fail(
- "%s can not create alias %s: object already exists" %
- [@resource.title, other]
- )
+ if obj = @resource.configuration.resource(@resource.class.name, other)
+ unless obj.object_id == @resource.object_id
+ self.fail("%s can not create alias %s: object already exists" % [@resource.title, other])
end
next
end
+
+ # LAK:FIXME Old-school, add the alias to the class.
@resource.class.alias(other, @resource)
+
+ # Newschool, add it to the configuration.
+ @resource.configuration.alias(@resource, other)
end
end
end
@@ -247,7 +251,16 @@ class Puppet::Type
end
def munge(rels)
- @resource.store_relationship(self.class.name, rels)
+ @resource.munge_relationship(self.class.name, rels)
+ end
+
+ def validate_relationship
+ @value.each do |value|
+ unless @resource.configuration.resource(*value)
+ description = self.class.direction == :in ? "dependency" : "dependent"
+ raise Puppet::Error, "Could not find #{description} %s[%s]" % [value[0].to_s.capitalize, value[1]]
+ end
+ end
end
# Create edges from each of our relationships. :in
diff --git a/lib/puppet/network/client/master.rb b/lib/puppet/network/client/master.rb
index 5408cabe4..ea351ddc3 100644
--- a/lib/puppet/network/client/master.rb
+++ b/lib/puppet/network/client/master.rb
@@ -139,63 +139,57 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
facts = self.class.facts
end
- if self.configuration or FileTest.exists?(self.cachefile)
- if self.fresh?(facts)
- Puppet.info "Config is up to date"
- if self.configuration
- return
- end
- if oldtext = self.retrievecache
- begin
- @configuration = YAML.load(oldtext).to_configuration
- rescue => detail
- Puppet.warning "Could not load cached configuration: %s" % detail
- end
- return
- end
- end
- end
- Puppet.debug("getting config")
+ raise Puppet::Network::ClientError.new("Could not retrieve any facts") unless facts.length > 0
# Retrieve the plugins.
- if Puppet[:pluginsync]
- getplugins()
- end
+ getplugins() if Puppet[:pluginsync]
- unless facts.length > 0
- raise Puppet::Network::ClientError.new(
- "Could not retrieve any facts"
- )
+ if (self.configuration or FileTest.exist?(self.cachefile)) and self.fresh?(facts)
+ Puppet.info "Configuration is up to date"
+ return if use_cached_config
end
- unless objects = get_actual_config(facts)
- @configuration = nil
+ Puppet.debug("Retrieving configuration")
+
+ # If we can't retrieve the configuration, just return, which will either
+ # fail, or use the in-memory configuration.
+ unless yaml_objects = get_actual_config(facts)
+ use_cached_config(true)
return
end
- unless objects.is_a?(Puppet::TransBucket)
- raise NetworkClientError,
- "Invalid returned objects of type %s" % objects.class
+ begin
+ objects = YAML.load(yaml_objects)
+ rescue => detail
+ msg = "Configuration could not be translated from yaml"
+ msg += "; using cached configuration" if use_cached_config(true)
+ Puppet.warning msg
+ return
end
self.setclasses(objects.classes)
# Clear all existing objects, so we can recreate our stack.
- if self.configuration
- clear()
- end
+ clear() if self.configuration
# Now convert the objects to a puppet configuration graph.
- @configuration = objects.to_configuration
+ begin
+ @configuration = objects.to_configuration
+ rescue => detail
+ clear()
+ puts detail.backtrace if Puppet[:trace]
+ msg = "Configuration could not be instantiated: %s" % detail
+ msg += "; using cached configuration" if use_cached_config(true)
+ Puppet.warning msg
+ return
+ end
- if @configuration.nil?
- raise Puppet::Error, "Configuration could not be processed"
+ if ! @configuration.from_cache
+ self.cache(yaml_objects)
end
# Keep the state database up to date.
@configuration.host_config = true
-
- return @configuration
end
# A simple proxy method, so it's easy to test.
@@ -270,11 +264,9 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
Puppet.err "Could not retrieve configuration: %s" % detail
end
- if defined? @configuration and @configuration
+ if self.configuration
@configuration.retrieval_duration = duration
- unless @local
- Puppet.notice "Starting configuration run"
- end
+ Puppet.notice "Starting configuration run" unless @local
benchmark(:notice, "Finished configuration run") do
@configuration.apply(options)
end
@@ -500,34 +492,16 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
# Actually retrieve the configuration, either from the server or from a
# local master.
def get_actual_config(facts)
- if @local
- return get_local_config(facts)
- else
- begin
- Timeout::timeout(self.class.timeout) do
- return get_remote_config(facts)
- end
- rescue Timeout::Error
- Puppet.err "Configuration retrieval timed out"
- return nil
+ begin
+ Timeout::timeout(self.class.timeout) do
+ return get_remote_config(facts)
end
+ rescue Timeout::Error
+ Puppet.err "Configuration retrieval timed out"
+ return nil
end
end
- # Retrieve a configuration from a local master.
- def get_local_config(facts)
- # If we're local, we don't have to do any of the conversion
- # stuff.
- objects = @driver.getconfig(facts, "yaml")
- @compile_time = Time.now
-
- if objects == ""
- raise Puppet::Error, "Could not retrieve configuration"
- end
-
- return objects
- end
-
# Retrieve a config from a remote master.
def get_remote_config(facts)
textobjects = ""
@@ -545,45 +519,18 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
end
rescue => detail
- puts detail.backtrace
Puppet.err "Could not retrieve configuration: %s" % detail
-
- unless Puppet[:usecacheonfailure]
- @configuration = nil
- Puppet.warning "Not using cache on failed configuration"
- return
- end
+ return nil
end
end
- fromcache = false
- if textobjects == ""
- unless textobjects = self.retrievecache
- raise Puppet::Error.new(
- "Cannot connect to server and there is no cached configuration"
- )
- end
- Puppet.warning "Could not get config; using cached copy"
- fromcache = true
- else
- @compile_time = Time.now
- Puppet::Util::Storage.cache(:configuration)[:facts] = facts
- Puppet::Util::Storage.cache(:configuration)[:compile_time] = @compile_time
- end
+ return nil if textobjects == ""
- begin
- objects = YAML.load(textobjects)
- rescue => detail
- raise Puppet::Error,
- "Could not understand configuration: %s" %
- detail.to_s
- end
+ @compile_time = Time.now
+ Puppet::Util::Storage.cache(:configuration)[:facts] = facts
+ Puppet::Util::Storage.cache(:configuration)[:compile_time] = @compile_time
- if @cache and ! fromcache
- self.cache(textobjects)
- end
-
- return objects
+ return textobjects
end
def lockfile
@@ -609,4 +556,32 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
Puppet.info "Sleeping for %s seconds (splay is enabled)" % time
sleep(time)
end
+
+ private
+
+ # Use our cached config, optionally specifying whether this is
+ # necessary because of a failure.
+ def use_cached_config(because_of_failure = false)
+ return true if self.configuration
+
+ if because_of_failure and ! Puppet[:usecacheonfailure]
+ @configuration = nil
+ Puppet.warning "Not using cache on failed configuration"
+ return false
+ end
+
+ return false unless oldtext = self.retrievecache
+
+ begin
+ @configuration = YAML.load(oldtext).to_configuration
+ @configuration.from_cache = true
+ @configuration.host_config = true
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.warning "Could not load cached configuration: %s" % detail
+ clear
+ return false
+ end
+ return true
+ end
end
diff --git a/lib/puppet/network/handler/runner.rb b/lib/puppet/network/handler/runner.rb
index a8d0da9ce..c97e4791a 100755
--- a/lib/puppet/network/handler/runner.rb
+++ b/lib/puppet/network/handler/runner.rb
@@ -43,7 +43,7 @@ class Puppet::Network::Handler
end
if ignoreschedules
- msg += " without schedules"
+ msg += " ignoring schedules"
end
Puppet.notice msg
diff --git a/lib/puppet/network/http.rb b/lib/puppet/network/http.rb
new file mode 100644
index 000000000..062c67c71
--- /dev/null
+++ b/lib/puppet/network/http.rb
@@ -0,0 +1,13 @@
+class Puppet::Network::HTTP
+ def self.server_class_by_type(kind)
+ return Puppet::Network::HTTP::WEBrick if kind.to_sym == :webrick
+ if kind.to_sym == :mongrel
+ raise ArgumentError, "Mongrel is not installed on this platform" unless Puppet.features.mongrel?
+ return Puppet::Network::HTTP::Mongrel
+ end
+ raise ArgumentError, "Unknown HTTP server name [#{kind}]"
+ end
+end
+
+require 'puppet/network/http/webrick'
+require 'puppet/network/http/mongrel'
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb
new file mode 100644
index 000000000..773381c8d
--- /dev/null
+++ b/lib/puppet/network/http/handler.rb
@@ -0,0 +1,109 @@
+class Puppet::Network::HTTP::Handler
+ def initialize(args = {})
+ raise ArgumentError unless @server = args[:server]
+ raise ArgumentError unless @handler = args[:handler]
+ @model = find_model_for_handler(@handler)
+ register_handler
+ end
+
+ # handle an HTTP request
+ def process(request, response)
+ return do_find(request, response) if get?(request) and singular?(request)
+ return do_search(request, response) if get?(request) and plural?(request)
+ return do_destroy(request, response) if delete?(request) and singular?(request)
+ return do_save(request, response) if put?(request) and singular?(request)
+ raise ArgumentError, "Did not understand HTTP #{http_method(request)} request for '#{path(request)}'"
+ rescue Exception => e
+ return do_exception(request, response, e)
+ end
+
+ private
+
+ def do_find(request, response)
+ key = request_key(request) || raise(ArgumentError, "Could not locate lookup key in request path [#{path}]")
+ args = params(request)
+ result = @model.find(key, args).to_yaml
+ encode_result(request, response, result)
+ end
+
+ def do_search(request, response)
+ args = params(request)
+ result = @model.search(args).collect {|obj| obj.to_yaml }
+ encode_result(request, response, result)
+ end
+
+ def do_destroy(request, response)
+ key = request_key(request) || raise(ArgumentError, "Could not locate lookup key in request path [#{path}]")
+ args = params(request)
+ result = @model.destroy(key, args)
+ encode_result(request, response, YAML.dump(result))
+ end
+
+ def do_save(request, response)
+ data = body(request)
+ raise ArgumentError, "No data to save" if !data or data.empty?
+ args = params(request)
+ obj = @model.new
+ result = obj.save(args.merge(:data => data)).to_yaml
+ encode_result(request, response, result)
+ end
+
+ def do_exception(request, response, exception, status=404)
+ encode_result(request, response, exception.to_s, status)
+ end
+
+ def find_model_for_handler(handler)
+ Puppet::Indirector::Indirection.model(handler) ||
+ raise(ArgumentError, "Cannot locate indirection [#{handler}].")
+ end
+
+ def get?(request)
+ http_method(request) == 'GET'
+ end
+
+ def put?(request)
+ http_method(request) == 'PUT'
+ end
+
+ def delete?(request)
+ http_method(request) == 'DELETE'
+ end
+
+ def singular?(request)
+ %r{/#{@handler.to_s}$}.match(path(request))
+ end
+
+ def plural?(request)
+ %r{/#{@handler.to_s}s$}.match(path(request))
+ end
+
+ # methods specific to a given web server
+
+ def register_handler
+ raise NotImplementedError
+ end
+
+ def http_method(request)
+ raise NotImplementedError
+ end
+
+ def path(request)
+ raise NotImplementedError
+ end
+
+ def request_key(request)
+ raise NotImplementedError
+ end
+
+ def body(request)
+ raise NotImplementedError
+ end
+
+ def params(request)
+ raise NotImplementedError
+ end
+
+ def encode_result(request, response, result, status = 200)
+ raise NotImplementedError
+ end
+end
diff --git a/lib/puppet/network/http/mongrel.rb b/lib/puppet/network/http/mongrel.rb
new file mode 100644
index 000000000..8ea669531
--- /dev/null
+++ b/lib/puppet/network/http/mongrel.rb
@@ -0,0 +1,54 @@
+require 'mongrel' if Puppet.features.mongrel?
+
+require 'puppet/network/http/mongrel/rest'
+require 'puppet/network/http/mongrel/xmlrpc'
+
+class Puppet::Network::HTTP::Mongrel
+ def initialize(args = {})
+ @listening = false
+ end
+
+ def listen(args = {})
+ raise ArgumentError, ":handlers must be specified." if !args[:handlers] or args[:handlers].empty?
+ raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
+ raise ArgumentError, ":address must be specified." unless args[:address]
+ raise ArgumentError, ":port must be specified." unless args[:port]
+ raise "Mongrel server is already listening" if listening?
+
+ @protocols = args[:protocols]
+ @handlers = args[:handlers]
+ @server = Mongrel::HttpServer.new(args[:address], args[:port])
+
+ setup_handlers
+
+ @server.run
+ @listening = true
+ end
+
+ def unlisten
+ raise "Mongrel server is not listening" unless listening?
+ @server.graceful_shutdown
+ @listening = false
+ end
+
+ def listening?
+ @listening
+ end
+
+ private
+
+ def setup_handlers
+ @protocols.each do |protocol|
+ @handlers.each do |handler|
+ class_for_protocol(protocol).new(:server => @server, :handler => handler)
+ end
+ end
+ end
+
+ # TODO/FIXME: need a spec which forces delegation to the real class
+ def class_for_protocol(protocol)
+ return Puppet::Network::HTTP::MongrelREST if protocol.to_sym == :rest
+ return Puppet::Network::HTTP::MongrelXMLRPC if protocol.to_sym == :xmlrpc
+ raise ArgumentError, "Unknown protocol [#{protocol}]."
+ end
+end
diff --git a/lib/puppet/network/http/mongrel/rest.rb b/lib/puppet/network/http/mongrel/rest.rb
new file mode 100644
index 000000000..db63613ab
--- /dev/null
+++ b/lib/puppet/network/http/mongrel/rest.rb
@@ -0,0 +1,37 @@
+require 'puppet/network/http/handler'
+
+class Puppet::Network::HTTP::MongrelREST < Puppet::Network::HTTP::Handler
+
+ private
+
+ def register_handler
+ @server.register('/' + @handler.to_s, self)
+ @server.register('/' + @handler.to_s + 's', self)
+ end
+
+ def http_method(request)
+ request.params[Mongrel::Const::REQUEST_METHOD]
+ end
+
+ def path(request)
+ '/' + request.params[Mongrel::Const::REQUEST_PATH].split('/')[1]
+ end
+
+ def request_key(request)
+ request.params[Mongrel::Const::REQUEST_PATH].split('/')[2]
+ end
+
+ def body(request)
+ request.body
+ end
+
+ def params(request)
+ Mongrel::HttpRequest.query_parse(request.params["QUERY_STRING"])
+ end
+
+ def encode_result(request, response, result, status = 200)
+ response.start(status) do |head, body|
+ body.write(result)
+ end
+ end
+end
diff --git a/lib/puppet/network/http/mongrel/xmlrpc.rb b/lib/puppet/network/http/mongrel/xmlrpc.rb
new file mode 100644
index 000000000..92acd4f0e
--- /dev/null
+++ b/lib/puppet/network/http/mongrel/xmlrpc.rb
@@ -0,0 +1,4 @@
+class Puppet::Network::HTTP::MongrelXMLRPC
+ def initialize(args = {})
+ end
+end
diff --git a/lib/puppet/network/http/webrick.rb b/lib/puppet/network/http/webrick.rb
new file mode 100644
index 000000000..c4b2ed3c6
--- /dev/null
+++ b/lib/puppet/network/http/webrick.rb
@@ -0,0 +1,51 @@
+require 'webrick'
+require 'webrick/https'
+require 'puppet/network/http/webrick/rest'
+require 'puppet/network/http/webrick/xmlrpc'
+
+class Puppet::Network::HTTP::WEBrick
+ def initialize(args = {})
+ @listening = false
+ end
+
+ def listen(args = {})
+ raise ArgumentError, ":handlers must be specified." if !args[:handlers] or args[:handlers].empty?
+ raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
+ raise ArgumentError, ":address must be specified." unless args[:address]
+ raise ArgumentError, ":port must be specified." unless args[:port]
+ raise "WEBrick server is already listening" if listening?
+
+ @protocols = args[:protocols]
+ @handlers = args[:handlers]
+ @server = WEBrick::HTTPServer.new(:BindAddress => args[:address], :Port => args[:port])
+ setup_handlers
+ @server.start
+ @listening = true
+ end
+
+ def unlisten
+ raise "WEBrick server is not listening" unless listening?
+ @server.shutdown
+ @listening = false
+ end
+
+ def listening?
+ @listening
+ end
+
+ private
+
+ def setup_handlers
+ @protocols.each do |protocol|
+ @handlers.each do |handler|
+ class_for_protocol(protocol).new(:server => @server, :handler => handler)
+ end
+ end
+ end
+
+ def class_for_protocol(protocol)
+ return Puppet::Network::HTTP::WEBrickREST if protocol.to_sym == :rest
+ return Puppet::Network::HTTP::WEBrickXMLRPC if protocol.to_sym == :xmlrpc
+ raise ArgumentError, "Unknown protocol [#{protocol}]."
+ end
+end
diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/network/http/webrick/rest.rb
new file mode 100644
index 000000000..dd0c84d61
--- /dev/null
+++ b/lib/puppet/network/http/webrick/rest.rb
@@ -0,0 +1,41 @@
+require 'puppet/network/http/handler'
+
+class Puppet::Network::HTTP::WEBrickREST < Puppet::Network::HTTP::Handler
+
+ # WEBrick uses a service() method to respond to requests. Simply delegate to the handler response() method.
+ def service(request, response)
+ process(request, response)
+ end
+
+ private
+
+ def register_handler
+ @server.mount('/' + @handler.to_s, self)
+ @server.mount('/' + @handler.to_s + 's', self)
+ end
+
+ def http_method(request)
+ request.request_method
+ end
+
+ def path(request)
+ '/' + request.path.split('/')[1]
+ end
+
+ def request_key(request)
+ request.path.split('/')[2]
+ end
+
+ def body(request)
+ request.body
+ end
+
+ def params(request)
+ request.query
+ end
+
+ def encode_result(request, response, result, status = 200)
+ response.status = status
+ response.body = result
+ end
+end \ No newline at end of file
diff --git a/lib/puppet/network/http/webrick/xmlrpc.rb b/lib/puppet/network/http/webrick/xmlrpc.rb
new file mode 100644
index 000000000..793708f8a
--- /dev/null
+++ b/lib/puppet/network/http/webrick/xmlrpc.rb
@@ -0,0 +1,4 @@
+class Puppet::Network::HTTP::WEBrickXMLRPC
+ def initialize(args = {})
+ end
+end
diff --git a/lib/puppet/network/server.rb b/lib/puppet/network/server.rb
index 84a71a6b4..50e3bd686 100644
--- a/lib/puppet/network/server.rb
+++ b/lib/puppet/network/server.rb
@@ -1,66 +1,65 @@
class Puppet::Network::Server
- attr_reader :server_type
+ attr_reader :server_type, :protocols, :address, :port
- # which HTTP server subclass actually handles web requests of a certain type? (e.g., :rest => RESTServer)
- def self.server_class_by_name(name)
- klass = (name.to_s + 'Server').to_sym
- const_get klass
- end
-
- # we will actually return an instance of the Server subclass which handles the HTTP web server, instead of
- # an instance of this generic Server class. A tiny bit of sleight-of-hand is necessary to make this happen.
- def self.new(args = {})
- server_type = Puppet[:servertype] or raise "No servertype configuration found."
- obj = self.server_class_by_name(server_type).allocate
- obj.send :initialize, args.merge(:server_type => server_type)
- obj
- end
-
- def initialize(args = {})
- @routes = {}
- @listening = false
- @server_type = args[:server_type]
- self.register(args[:handlers]) if args[:handlers]
- end
+ def initialize(args = {})
+ @server_type = Puppet[:servertype] or raise "No servertype configuration found." # e.g., WEBrick, Mongrel, etc.
+ http_server_class || raise(ArgumentError, "Could not determine HTTP Server class for server type [#{@server_type}]")
+ @address = args[:address] || Puppet[:bindaddress] ||
+ raise(ArgumentError, "Must specify :address or configure Puppet :bindaddress.")
+ @port = args[:port] || Puppet[:masterport] ||
+ raise(ArgumentError, "Must specify :port or configure Puppet :masterport")
+ @protocols = []
+ @listening = false
+ @routes = {}
+ self.register(args[:handlers]) if args[:handlers]
+ end
- def register(*indirections)
- raise ArgumentError, "indirection names are required" if indirections.empty?
- indirections.flatten.each { |i| @routes[i.to_sym] = true }
- end
+ def register(*indirections)
+ raise ArgumentError, "Indirection names are required." if indirections.empty?
+ indirections.flatten.each { |i| @routes[i.to_sym] = true }
+ end
- def unregister(*indirections)
- indirections = @routes.keys if indirections.empty?
- indirections.flatten.each do |i|
- raise(ArgumentError, "indirection [%s] is not known" % i) unless @routes[i.to_sym]
- @routes.delete(i.to_sym)
+ def unregister(*indirections)
+ raise "Cannot unregister indirections while server is listening." if listening?
+ indirections = @routes.keys if indirections.empty?
+
+ indirections.flatten.each do |i|
+ raise(ArgumentError, "Indirection [%s] is unknown." % i) unless @routes[i.to_sym]
+ end
+
+ indirections.flatten.each do |i|
+ @routes.delete(i.to_sym)
+ end
end
- end
- def listening?
- @listening
- end
+ def listening?
+ @listening
+ end
- def listen
- raise "Cannot listen -- already listening" if listening?
- start_web_server
- @listening = true
- end
+ def listen
+ raise "Cannot listen -- already listening." if listening?
+ http_server.listen(@routes.dup)
+ @listening = true
+ end
- def unlisten
- raise "Cannot unlisten -- not currently listening" unless listening?
- stop_web_server
- @listening = false
- end
+ def unlisten
+ raise "Cannot unlisten -- not currently listening." unless listening?
+ http_server.unlisten
+ @listening = false
+ end
+
+ def http_server_class
+ http_server_class_by_type(@server_type)
+ end
private
- def start_web_server
- raise NotImplementedError, "this method needs to be implemented by the actual web server (sub)class"
- end
-
- def stop_web_server
- raise NotImplementedError, "this method needs to be implemented by the actual web server (sub)class"
- end
+ def http_server
+ @http_server ||= http_server_class.new
+ end
+
+ def http_server_class_by_type(kind)
+ Puppet::Network::HTTP.server_class_by_type(kind)
+ end
end
-
diff --git a/lib/puppet/node/configuration.rb b/lib/puppet/node/configuration.rb
index e49090d70..804f357d1 100644
--- a/lib/puppet/node/configuration.rb
+++ b/lib/puppet/node/configuration.rb
@@ -38,6 +38,10 @@ class Puppet::Node::Configuration < Puppet::PGraph
# relationship graph.
attr_accessor :is_relationship_graph
+ # Whether this configuration was retrieved from the cache, which affects
+ # whether it is written back out again.
+ attr_accessor :from_cache
+
# Add classes to our class list.
def add_class(*classes)
classes.each do |klass|
@@ -66,6 +70,16 @@ class Puppet::Node::Configuration < Puppet::PGraph
end
end
+ # Create an alias for a resource.
+ def alias(resource, name)
+ resource.ref =~ /^(.+)\[/
+
+ newref = "%s[%s]" % [$1 || resource.class.name, name]
+ raise(ArgumentError, "Cannot alias %s to %s; resource %s already exists" % [resource.ref, name, newref]) if @resource_table[newref]
+ @resource_table[newref] = resource
+ @aliases[resource.ref] << newref
+ end
+
# Apply our configuration to the local host. Valid options
# are:
# :tags - set the tags that restrict what resources run
@@ -274,6 +288,8 @@ class Puppet::Node::Configuration < Puppet::PGraph
@applying = false
@relationship_graph = nil
+ @aliases = Hash.new { |hash, key| hash[key] = [] }
+
if block_given?
yield(self)
finalize()
@@ -331,7 +347,9 @@ class Puppet::Node::Configuration < Puppet::PGraph
# references to the resource instances.
def remove_resource(*resources)
resources.each do |resource|
- @resource_table.delete(resource.ref) if @resource_table.include?(resource.ref)
+ @resource_table.delete(resource.ref)
+ @aliases[resource.ref].each { |res_alias| @resource_table.delete(res_alias) }
+ @aliases[resource.ref].clear
remove_vertex!(resource) if vertex?(resource)
@relationship_graph.remove_vertex!(resource) if @relationship_graph and @relationship_graph.vertex?(resource)
resource.remove
diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb
index f23b42a35..7f568f1b3 100644
--- a/lib/puppet/parser/compile.rb
+++ b/lib/puppet/parser/compile.rb
@@ -14,7 +14,7 @@ require 'puppet/util/errors'
class Puppet::Parser::Compile
include Puppet::Util
include Puppet::Util::Errors
- attr_reader :topscope, :parser, :node, :facts, :collections, :configuration
+ attr_reader :parser, :node, :facts, :collections, :configuration, :node_scope
# Add a collection to the global list.
def add_collection(coll)
@@ -107,7 +107,7 @@ class Puppet::Parser::Compile
# Evaluate all of the classes specified by the node.
def evaluate_node_classes
- evaluate_classes(@node.classes, @topscope)
+ evaluate_classes(@node.classes, topscope)
end
# Evaluate each specified class in turn. If there are any classes we can't
@@ -142,9 +142,7 @@ class Puppet::Parser::Compile
# Return a resource by either its ref or its type and title.
def findresource(string, name = nil)
- if name
- string = "%s[%s]" % [string.capitalize, name]
- end
+ string = "%s[%s]" % [string.capitalize, name] if name
@resource_table[string]
end
@@ -173,7 +171,7 @@ class Puppet::Parser::Compile
# using the top scope. Adds an edge between the scope and
# its parent to the graph.
def newscope(parent, options = {})
- parent ||= @topscope
+ parent ||= topscope
options[:compile] = self
options[:parser] ||= self.parser
scope = Puppet::Parser::Scope.new(options)
@@ -229,6 +227,12 @@ class Puppet::Parser::Compile
@configuration.add_edge!(scope.resource, resource)
end
+ # The top scope is usually the top-level scope, but if we're using AST nodes,
+ # then it is instead the node's scope.
+ def topscope
+ node_scope || @topscope
+ end
+
private
# If ast nodes are enabled, then see if we can find and evaluate one.
@@ -241,10 +245,7 @@ class Puppet::Parser::Compile
break if astnode = @parser.nodes[name.to_s.downcase]
end
- unless astnode
- astnode = @parser.nodes["default"]
- end
- unless astnode
+ unless (astnode ||= @parser.nodes["default"])
raise Puppet::ParseError, "Could not find default node or by name with '%s'" % node.names.join(", ")
end
@@ -253,6 +254,12 @@ class Puppet::Parser::Compile
resource = Puppet::Parser::Resource.new(:type => "node", :title => astnode.classname, :scope => topscope, :source => topscope.source)
store_resource(topscope, resource)
@configuration.tag(astnode.classname)
+
+ resource.evaluate
+
+ # Now set the node scope appropriately, so that :topscope can
+ # behave differently.
+ @node_scope = class_scope(astnode)
end
# Evaluate our collections and return true if anything returned an object.
@@ -318,6 +325,8 @@ class Puppet::Parser::Compile
@configuration.add_vertex!(@main_resource)
@resource_table["Class[main]"] = @main_resource
+
+ @main_resource.evaluate
end
# Make sure the entire configuration is evaluated.
@@ -408,7 +417,6 @@ class Puppet::Parser::Compile
# A graph for maintaining scope relationships.
@scope_graph = GRATR::Digraph.new
- @scope_graph.add_vertex!(@topscope)
# For maintaining the relationship between scopes and their resources.
@configuration = Puppet::Node::Configuration.new(@node.name)
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index c8fc2f199..ef53889cf 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -311,7 +311,7 @@ class Transaction
ret = eval_resource(resource)
end
- if Puppet[:evaltrace]
+ if Puppet[:evaltrace] and @configuration.host_config?
resource.info "Evaluated in %0.2f seconds" % seconds
end
ret
diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb
index 281ad00d3..6a573489c 100644
--- a/lib/puppet/transportable.rb
+++ b/lib/puppet/transportable.rb
@@ -59,15 +59,11 @@ module Puppet
tmpname = @type
end
trans = TransObject.new(tmpname, :component)
- if defined? @parameters
- @parameters.each { |param,value|
- Puppet.debug "Defining %s on %s of type %s" %
- [param,@name,@type]
- trans[param] = value
- }
- else
- #Puppet.debug "%s[%s] has no parameters" % [@type, @name]
- end
+ @params.each { |param,value|
+ next unless Puppet::Type::Component.validattr?(param)
+ Puppet.debug "Defining %s on %s of type %s" % [param,@name,@type]
+ trans[param] = value
+ }
Puppet::Type::Component.create(trans)
end
@@ -107,16 +103,7 @@ module Puppet
def to_type
retobj = nil
if typeklass = Puppet::Type.type(self.type)
- # FIXME This should really be done differently, but...
- if retobj = typeklass[self.name]
- self.each do |param, val|
- retobj[param] = val
- end
- else
- unless retobj = typeklass.create(self)
- return nil
- end
- end
+ return typeklass.create(self)
else
return to_component
end
@@ -135,7 +122,7 @@ module Puppet
class TransBucket
include Enumerable
- attr_accessor :name, :type, :file, :line, :classes, :keyword, :top
+ attr_accessor :name, :type, :file, :line, :classes, :keyword, :top, :configuration
%w{delete shift include? length empty? << []}.each { |method|
define_method(method) do |*args|
@@ -218,11 +205,13 @@ module Puppet
def to_configuration
configuration = Puppet::Node::Configuration.new(Facter.value("hostname")) do |config|
delver = proc do |obj|
+ obj.configuration = config
unless container = config.resource(obj.to_ref)
container = obj.to_type
config.add_resource container
end
obj.each do |child|
+ child.configuration = config
unless resource = config.resource(child.to_ref)
next unless resource = child.to_type
config.add_resource resource
@@ -252,65 +241,25 @@ module Puppet
end
def to_type
- # this container will contain the equivalent of all objects at
- # this level
- #container = Puppet::Component.new(:name => @name, :type => @type)
- #unless defined? @name
- # raise Puppet::DevError, "TransBuckets must have names"
- #end
unless defined? @type
Puppet.debug "TransBucket '%s' has no type" % @name
end
- usetrans = true
- if usetrans
- tmpname = nil
-
- # Nodes have the same name and type
- if self.name
- tmpname = "%s[%s]" % [@type, self.name]
- else
- tmpname = @type
- end
- trans = TransObject.new(tmpname, :component)
- if defined? @parameters
- @parameters.each { |param,value|
- Puppet.debug "Defining %s on %s of type %s" %
- [param,@name,@type]
- trans[param] = value
- }
- else
- #Puppet.debug "%s[%s] has no parameters" % [@type, @name]
- end
- container = Puppet::Type::Component.create(trans)
+ # Nodes have the same name and type
+ if self.name
+ tmpname = "%s[%s]" % [@type, self.name]
else
- hash = {
- :name => self.name,
- :type => @type
- }
- if defined? @parameters
- @parameters.each { |param,value|
- Puppet.debug "Defining %s on %s of type %s" %
- [param,@name,@type]
- hash[param] = value
- }
- else
- #Puppet.debug "%s[%s] has no parameters" % [@type, @name]
- end
-
- container = Puppet::Type::Component.create(hash)
+ tmpname = @type
end
- #Puppet.info container.inspect
-
- # unless we successfully created the container, return an error
- unless container
- Puppet.warning "Got no container back"
- return nil
+ trans = TransObject.new(tmpname, :component)
+ if defined? @parameters
+ @parameters.each { |param,value|
+ Puppet.debug "Defining %s on %s of type %s" %
+ [param,@name,@type]
+ trans[param] = value
+ }
end
-
- # at this point, no objects at are level are still Transportable
- # objects
- return container
+ return Puppet::Type::Component.create(trans)
end
def param(param,value)
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index b7ff1f664..f5dd0f8dd 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -182,7 +182,7 @@ class Type
# directly from it. This is the main object instantiation mechanism.
if hash.is_a?(Puppet::TransObject)
#self[:name] = hash[:name]
- [:file, :line, :tags].each { |getter|
+ [:file, :line, :tags, :configuration].each { |getter|
if hash.respond_to?(getter)
setter = getter.to_s + "="
if val = hash.send(getter)
@@ -194,10 +194,11 @@ class Type
# XXX This will need to change when transobjects change to titles.
@title = hash.name
hash = hash.to_hash
- elsif hash[:title]
- # XXX This should never happen
- @title = hash[:title]
- hash.delete(:title)
+ else
+ if hash[:title]
+ @title = hash[:title]
+ hash.delete(:title)
+ end
end
# Before anything else, set our parent if it was included
@@ -221,7 +222,7 @@ class Type
if attrs.include?(namevar)
attrs.delete(namevar)
else
- self.devfail "My namevar isn\'t a valid attribute...?"
+ self.devfail "My namevar isn't a valid attribute...?"
end
else
self.devfail "I was not passed a namevar"
@@ -284,6 +285,14 @@ class Type
# Scheduling has to be done when the whole config is instantiated, so
# that file order doesn't matter in finding them.
self.schedule
+
+ # Make sure all of our relationships are valid. Again, must be done
+ # when the entire configuration is instantiated.
+ self.class.relationship_params.collect do |klass|
+ if param = @parameters[klass.name]
+ param.validate_relationship
+ end
+ end.flatten.reject { |r| r.nil? }
end
# Return a cached value
diff --git a/lib/puppet/type/component.rb b/lib/puppet/type/component.rb
index 4dc542a65..7aa24a302 100644
--- a/lib/puppet/type/component.rb
+++ b/lib/puppet/type/component.rb
@@ -93,9 +93,9 @@ Puppet::Type.newtype(:component) do
end
# Initialize a new component
- def initialize(args)
+ def initialize(*args)
@children = []
- super(args)
+ super
# If the title isn't a full resource reference, assume
# we're a class and make an alias for that.
diff --git a/lib/puppet/type/pfile/group.rb b/lib/puppet/type/pfile/group.rb
index 9625b6354..5f7caf342 100755
--- a/lib/puppet/type/pfile/group.rb
+++ b/lib/puppet/type/pfile/group.rb
@@ -6,6 +6,10 @@ module Puppet
name or group ID."
@event = :file_changed
+ validate do |group|
+ raise(Puppet::Error, "Invalid group name '%s'" % group.inspect) unless group and group != ""
+ end
+
def id2name(id)
if id > 70000
return nil