summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-04-11 15:21:50 -0500
committerLuke Kanies <luke@madstop.com>2008-04-11 15:21:50 -0500
commitd834242db13a827a34340c5f2e51c8df532d5196 (patch)
treecdd98ee63103082a81dac7e91e13b60458685780 /lib/puppet
parentfb05ef3c96038d67a46eb142202af186ad6cb0b3 (diff)
parentd9846fc3f06f61fcb4b8806740f77747a7f6939e (diff)
downloadpuppet-d834242db13a827a34340c5f2e51c8df532d5196.tar.gz
puppet-d834242db13a827a34340c5f2e51c8df532d5196.tar.xz
puppet-d834242db13a827a34340c5f2e51c8df532d5196.zip
Merge branch '0.24.x'
Conflicts: spec/unit/network/server.rb
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/indirector/indirection.rb5
-rw-r--r--lib/puppet/indirector/node/rest.rb2
-rw-r--r--lib/puppet/indirector/rest.rb54
-rw-r--r--lib/puppet/network/http/handler.rb32
-rw-r--r--lib/puppet/network/http/mongrel.rb17
-rw-r--r--lib/puppet/network/http/mongrel/rest.rb22
-rw-r--r--lib/puppet/network/http/mongrel/xmlrpc.rb4
-rw-r--r--lib/puppet/network/http/webrick.rb43
-rw-r--r--lib/puppet/network/http/webrick/rest.rb17
-rw-r--r--lib/puppet/network/http/webrick/xmlrpc.rb4
-rw-r--r--lib/puppet/network/server.rb44
11 files changed, 156 insertions, 88 deletions
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
index 15358a801..05464f8c9 100644
--- a/lib/puppet/indirector/indirection.rb
+++ b/lib/puppet/indirector/indirection.rb
@@ -225,14 +225,14 @@ class Puppet::Indirector::Indirection
request = request(:destroy, key, *args)
terminus = prepare(request)
- terminus.destroy(request)
+ result = terminus.destroy(request)
if cache? and cached = cache.find(request(:find, key, *args))
# Reuse the existing request, since it's equivalent.
cache.destroy(request)
end
- nil
+ result
end
# Search for more than one instance. Should always return an array.
@@ -242,7 +242,6 @@ class Puppet::Indirector::Indirection
if result = terminus.search(request)
raise Puppet::DevError, "Search results from terminus %s are not an array" % terminus.name unless result.is_a?(Array)
-
result.each do |instance|
instance.expiration ||= self.expiration
end
diff --git a/lib/puppet/indirector/node/rest.rb b/lib/puppet/indirector/node/rest.rb
index c5d2f97fb..d8b75f6e7 100644
--- a/lib/puppet/indirector/node/rest.rb
+++ b/lib/puppet/indirector/node/rest.rb
@@ -1,7 +1,7 @@
require 'puppet/node'
require 'puppet/indirector/rest'
-class Puppet::Node::REST < Puppet::Indirector::REST
+class Puppet::Node::Rest < Puppet::Indirector::REST
desc "This will eventually be a REST-based mechanism for finding nodes. It is currently non-functional."
# TODO/FIXME
end
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb
index 7b7c932c4..d33150fc2 100644
--- a/lib/puppet/indirector/rest.rb
+++ b/lib/puppet/indirector/rest.rb
@@ -1,8 +1,56 @@
-require 'puppet/indirector/rest'
+require 'net/http'
+require 'uri'
# Access objects via REST
class Puppet::Indirector::REST < Puppet::Indirector::Terminus
- def find(name, options = {})
- indirection.model.new(name)
+
+ def rest_connection_details
+ { :host => Puppet[:server], :port => Puppet[:masterport].to_i }
+ end
+
+ def network_fetch(path)
+ network {|conn| conn.get("/#{path}").body }
+ end
+
+ def network_delete(path)
+ network {|conn| conn.delete("/#{path}").body }
+ end
+
+ def network_put(path, data)
+ network {|conn| conn.put("/#{path}", data).body }
+ end
+
+ def find(request)
+ network_result = network_fetch("#{indirection.name}/#{request.key}")
+ raise YAML.load(network_result) if exception?(network_result)
+ indirection.model.from_yaml(network_result)
+ end
+
+ def search(request)
+ network_results = network_fetch("#{indirection.name}s/#{request.key}")
+ raise YAML.load(network_results) if exception?(network_results)
+ YAML.load(network_results.to_s).collect {|result| indirection.model.from_yaml(result) }
+ end
+
+ def destroy(request)
+ network_result = network_delete("#{indirection.name}/#{request.key}")
+ raise YAML.load(network_result) if exception?(network_result)
+ YAML.load(network_result.to_s)
+ end
+
+ def save(request)
+ network_result = network_put("#{indirection.name}/", request.instance.to_yaml)
+ raise YAML.load(network_result) if exception?(network_result)
+ indirection.model.from_yaml(network_result)
+ end
+
+ private
+
+ def network(&block)
+ Net::HTTP.start(rest_connection_details[:host], rest_connection_details[:port]) {|conn| yield(conn) }
+ end
+
+ def exception?(yaml_string)
+ yaml_string =~ %r{--- !ruby/exception}
end
end
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb
index 773381c8d..7113c92d3 100644
--- a/lib/puppet/network/http/handler.rb
+++ b/lib/puppet/network/http/handler.rb
@@ -1,9 +1,9 @@
-class Puppet::Network::HTTP::Handler
- def initialize(args = {})
+module Puppet::Network::HTTP::Handler
+
+ def initialize_for_puppet(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
@@ -18,38 +18,46 @@ class Puppet::Network::HTTP::Handler
end
private
+
+ def model
+ @model
+ end
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
+ 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 }
+ result = model.search(args).collect {|result| result.to_yaml }.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)
+ result = model.destroy(key, args)
encode_result(request, response, YAML.dump(result))
end
def do_save(request, response)
- data = body(request)
+ data = body(request).to_s
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
+ # args = params(request)
+ obj = model.from_yaml(data)
+ result = save_object(obj).to_yaml
encode_result(request, response, result)
end
+
+ def save_object(obj)
+ obj.save
+ end
def do_exception(request, response, exception, status=404)
- encode_result(request, response, exception.to_s, status)
+ encode_result(request, response, exception.to_yaml, status)
end
def find_model_for_handler(handler)
@@ -77,7 +85,7 @@ class Puppet::Network::HTTP::Handler
%r{/#{@handler.to_s}s$}.match(path(request))
end
- # methods specific to a given web server
+ # methods to be overridden by the including web server class
def register_handler
raise NotImplementedError
diff --git a/lib/puppet/network/http/mongrel.rb b/lib/puppet/network/http/mongrel.rb
index 8ea669531..9a4531c7a 100644
--- a/lib/puppet/network/http/mongrel.rb
+++ b/lib/puppet/network/http/mongrel.rb
@@ -1,7 +1,6 @@
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 = {})
@@ -14,20 +13,20 @@ class Puppet::Network::HTTP::Mongrel
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])
-
+ @server = Mongrel::HttpServer.new(args[:address], args[:port])
setup_handlers
- @server.run
@listening = true
+ @server.run
end
def unlisten
raise "Mongrel server is not listening" unless listening?
- @server.graceful_shutdown
+ @server.stop
+ @server = nil
@listening = false
end
@@ -39,16 +38,16 @@ class Puppet::Network::HTTP::Mongrel
def setup_handlers
@protocols.each do |protocol|
+ klass = class_for_protocol(protocol)
@handlers.each do |handler|
- class_for_protocol(protocol).new(:server => @server, :handler => handler)
+ @server.register('/' + handler.to_s, klass.new(:server => @server, :handler => handler))
+ @server.register('/' + handler.to_s + 's', klass.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
index 6c24e360c..2a3d4f143 100644
--- a/lib/puppet/network/http/mongrel/rest.rb
+++ b/lib/puppet/network/http/mongrel/rest.rb
@@ -1,36 +1,44 @@
require 'puppet/network/http/handler'
-class Puppet::Network::HTTP::MongrelREST < Puppet::Network::HTTP::Handler
+class Puppet::Network::HTTP::MongrelREST < Mongrel::HttpHandler
+
+ include Puppet::Network::HTTP::Handler
+
+ def initialize(args={})
+ super()
+ initialize_for_puppet(args)
+ end
private
-
- def register_handler
- @server.register('/' + @handler.to_s, self)
- @server.register('/' + @handler.to_s + 's', self)
- end
-
+
+ # which HTTP verb was used in this request
def http_method(request)
request.params[Mongrel::Const::REQUEST_METHOD]
end
+ # what path was requested?
def path(request)
# LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
x = '/' + request.params[Mongrel::Const::REQUEST_PATH].split('/')[1]
end
+ # return the key included in the request path
def request_key(request)
# LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
x = request.params[Mongrel::Const::REQUEST_PATH].split('/')[2]
end
+ # return the request body
def body(request)
request.body
end
+ # return the query params for this request
def params(request)
Mongrel::HttpRequest.query_parse(request.params["QUERY_STRING"])
end
+ # produce the body of the response
def encode_result(request, response, result, status = 200)
response.start(status) do |head, body|
body.write(result)
diff --git a/lib/puppet/network/http/mongrel/xmlrpc.rb b/lib/puppet/network/http/mongrel/xmlrpc.rb
deleted file mode 100644
index 92acd4f0e..000000000
--- a/lib/puppet/network/http/mongrel/xmlrpc.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-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
index c4b2ed3c6..3a37e2071 100644
--- a/lib/puppet/network/http/webrick.rb
+++ b/lib/puppet/network/http/webrick.rb
@@ -1,11 +1,17 @@
require 'webrick'
require 'webrick/https'
require 'puppet/network/http/webrick/rest'
-require 'puppet/network/http/webrick/xmlrpc'
+require 'thread'
class Puppet::Network::HTTP::WEBrick
def initialize(args = {})
@listening = false
+ @mutex = Mutex.new
+ end
+
+ def self.class_for_protocol(protocol)
+ return Puppet::Network::HTTP::WEBrickREST if protocol.to_sym == :rest
+ raise "Unknown protocol [#{protocol}]."
end
def listen(args = {})
@@ -13,39 +19,44 @@ class Puppet::Network::HTTP::WEBrick
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
+
+ @mutex.synchronize do
+ raise "WEBrick server is already listening" if @listening
+ @listening = true
+ @thread = Thread.new { @server.start }
+ end
end
def unlisten
- raise "WEBrick server is not listening" unless listening?
- @server.shutdown
- @listening = false
+ @mutex.synchronize do
+ raise "WEBrick server is not listening" unless @listening
+ @server.shutdown
+ @thread.join
+ @server = nil
+ @listening = false
+ end
end
def listening?
- @listening
+ @mutex.synchronize do
+ @listening
+ end
end
-
+
private
def setup_handlers
@protocols.each do |protocol|
+ klass = self.class.class_for_protocol(protocol)
@handlers.each do |handler|
- class_for_protocol(protocol).new(:server => @server, :handler => handler)
+ @server.mount('/' + handler.to_s, klass, handler)
+ @server.mount('/' + handler.to_s + 's', klass, 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
index 8cda079e2..b43912196 100644
--- a/lib/puppet/network/http/webrick/rest.rb
+++ b/lib/puppet/network/http/webrick/rest.rb
@@ -1,19 +1,22 @@
require 'puppet/network/http/handler'
-class Puppet::Network::HTTP::WEBrickREST < Puppet::Network::HTTP::Handler
+class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet
+
+ include Puppet::Network::HTTP::Handler
+
+ def initialize(server, handler)
+ raise ArgumentError, "server is required" unless server
+ super(server)
+ initialize_for_puppet(:server => server, :handler => handler)
+ end
# 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
diff --git a/lib/puppet/network/http/webrick/xmlrpc.rb b/lib/puppet/network/http/webrick/xmlrpc.rb
deleted file mode 100644
index 793708f8a..000000000
--- a/lib/puppet/network/http/webrick/xmlrpc.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-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 f2c8dc18c..cab14519b 100644
--- a/lib/puppet/network/server.rb
+++ b/lib/puppet/network/server.rb
@@ -10,44 +10,44 @@ class Puppet::Network::Server
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]
+ @protocols = [ :rest ]
+ @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 }
+ raise ArgumentError, "Indirection names are required." if indirections.empty?
+ indirections.flatten.each { |i| @routes[i.to_sym] = true }
end
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
+ 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
+ indirections.flatten.each do |i|
+ @routes.delete(i.to_sym)
+ end
end
def listening?
- @listening
+ @listening
end
def listen
- raise "Cannot listen -- already listening." if listening?
- http_server.listen(@routes.dup)
- @listening = true
+ raise "Cannot listen -- already listening." if listening?
+ @listening = true
+ http_server.listen(:address => address, :port => port, :handlers => @routes.keys, :protocols => protocols)
end
def unlisten
- raise "Cannot unlisten -- not currently listening." unless listening?
- http_server.unlisten
- @listening = false
+ raise "Cannot unlisten -- not currently listening." unless listening?
+ http_server.unlisten
+ @listening = false
end
def http_server_class