diff options
-rw-r--r-- | lib/puppet/network/http/handler.rb | 5 | ||||
-rw-r--r-- | lib/puppet/network/http/mongrel.rb | 10 | ||||
-rw-r--r-- | lib/puppet/network/http/mongrel/rest.rb | 13 | ||||
-rw-r--r-- | lib/puppet/network/http/webrick.rb | 25 | ||||
-rw-r--r-- | lib/puppet/network/http/webrick/rest.rb | 4 | ||||
-rw-r--r-- | lib/puppet/network/server.rb | 6 | ||||
-rw-r--r-- | spec/integration/network/server.rb | 85 | ||||
-rw-r--r-- | spec/unit/network/http/mongrel.rb | 4 | ||||
-rw-r--r-- | spec/unit/network/server.rb | 53 |
9 files changed, 175 insertions, 30 deletions
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb index 773381c8d..7679bf320 100644 --- a/lib/puppet/network/http/handler.rb +++ b/lib/puppet/network/http/handler.rb @@ -1,4 +1,5 @@ -class Puppet::Network::HTTP::Handler +module Puppet::Network::HTTP::Handler + def initialize(args = {}) raise ArgumentError unless @server = args[:server] raise ArgumentError unless @handler = args[:handler] @@ -77,7 +78,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 d948836cd..941ef0e43 100644 --- a/lib/puppet/network/http/mongrel.rb +++ b/lib/puppet/network/http/mongrel.rb @@ -13,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 diff --git a/lib/puppet/network/http/mongrel/rest.rb b/lib/puppet/network/http/mongrel/rest.rb index 6c24e360c..7cb6f67bf 100644 --- a/lib/puppet/network/http/mongrel/rest.rb +++ b/lib/puppet/network/http/mongrel/rest.rb @@ -1,36 +1,45 @@ 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 private - + + # have this mongrel @server listen for /foo and /foos REST endpoints 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/webrick.rb b/lib/puppet/network/http/webrick.rb index 894e12473..3fd643612 100644 --- a/lib/puppet/network/http/webrick.rb +++ b/lib/puppet/network/http/webrick.rb @@ -1,10 +1,12 @@ require 'webrick' require 'webrick/https' require 'puppet/network/http/webrick/rest' +require 'thread' class Puppet::Network::HTTP::WEBrick def initialize(args = {}) @listening = false + @mutex = Mutex.new end def listen(args = {}) @@ -12,24 +14,33 @@ 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 diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/network/http/webrick/rest.rb index 8cda079e2..923e002e3 100644 --- a/lib/puppet/network/http/webrick/rest.rb +++ b/lib/puppet/network/http/webrick/rest.rb @@ -1,6 +1,8 @@ require 'puppet/network/http/handler' -class Puppet::Network::HTTP::WEBrickREST < Puppet::Network::HTTP::Handler +class Puppet::Network::HTTP::WEBrickREST + + include Puppet::Network::HTTP::Handler # WEBrick uses a service() method to respond to requests. Simply delegate to the handler response() method. def service(request, response) diff --git a/lib/puppet/network/server.rb b/lib/puppet/network/server.rb index 9e6b82469..cab14519b 100644 --- a/lib/puppet/network/server.rb +++ b/lib/puppet/network/server.rb @@ -1,3 +1,5 @@ +require 'puppet/network/http' + class Puppet::Network::Server attr_reader :server_type, :protocols, :address, :port @@ -8,7 +10,7 @@ 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 = [] + @protocols = [ :rest ] @listening = false @routes = {} self.register(args[:handlers]) if args[:handlers] @@ -38,8 +40,8 @@ class Puppet::Network::Server def listen raise "Cannot listen -- already listening." if listening? - http_server.listen(@routes.dup) @listening = true + http_server.listen(:address => address, :port => port, :handlers => @routes.keys, :protocols => protocols) end def unlisten diff --git a/spec/integration/network/server.rb b/spec/integration/network/server.rb new file mode 100644 index 000000000..932161b08 --- /dev/null +++ b/spec/integration/network/server.rb @@ -0,0 +1,85 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/network/server' +require 'socket' + +describe Puppet::Network::Server do + describe "when using webrick" do + before :each do + Puppet[:servertype] = 'webrick' + @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :node ] } + end + + describe "before listening" do + it "should not be reachable at the specified address and port" do + lambda { TCPSocket.new('127.0.0.1', 34343) }.should raise_error + end + end + + describe "when listening" do + it "should be reachable on the specified address and port" do + @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) + @server.listen + lambda { TCPSocket.new('127.0.0.1', 34343) }.should_not raise_error + end + + it "should not allow multiple servers to listen on the same address and port" do + @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) + @server.listen + @server2 = Puppet::Network::Server.new(@params.merge(:port => 34343)) + lambda { @server2.listen }.should raise_error + end + + after :each do + @server.unlisten if @server.listening? + end + end + + describe "after unlistening" do + it "should not be reachable on the port and address assigned" do + @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) + @server.listen + @server.unlisten + lambda { TCPSocket.new('127.0.0.1', 34343) }.should raise_error(Errno::ECONNREFUSED) + end + end + end + + describe "when using mongrel" do + before :each do + Puppet[:servertype] = 'mongrel' + @params = { :address => "127.0.0.1", :port => 34346, :handlers => [ :node ] } + @server = Puppet::Network::Server.new(@params) + end + + describe "before listening" do + it "should not be reachable at the specified address and port" do + lambda { TCPSocket.new('127.0.0.1', 34346) }.should raise_error(Errno::ECONNREFUSED) + end + end + + describe "when listening" do + it "should be reachable on the specified address and port" do + @server.listen + lambda { TCPSocket.new('127.0.0.1', 34346) }.should_not raise_error + end + + it "should not allow multiple servers to listen on the same address and port" do + @server.listen + @server2 = Puppet::Network::Server.new(@params) + lambda { @server2.listen }.should raise_error + end + end + + describe "after unlistening" do + it "should not be reachable on the port and address assigned" do + @server.listen + @server.unlisten + lambda { TCPSocket.new('127.0.0.1', 34346) }.should raise_error(Errno::ECONNREFUSED) + end + end + + after :each do + @server.unlisten if @server.listening? + end + end +end
\ No newline at end of file diff --git a/spec/unit/network/http/mongrel.rb b/spec/unit/network/http/mongrel.rb index a837c9daa..cd23ed9e1 100644 --- a/spec/unit/network/http/mongrel.rb +++ b/spec/unit/network/http/mongrel.rb @@ -106,13 +106,13 @@ describe Puppet::Network::HTTP::Mongrel, "when turning off listening" do it "should order mongrel server to stop" do @server.listen(@listen_params) - @mock_mongrel.expects(:graceful_shutdown) + @mock_mongrel.expects(:stop) @server.unlisten end it "should not be listening" do @server.listen(@listen_params) - @mock_mongrel.stubs(:graceful_shutdown) + @mock_mongrel.stubs(:stop) @server.unlisten @server.should_not be_listening end diff --git a/spec/unit/network/server.rb b/spec/unit/network/server.rb index 3e29807ad..e4afbc3c2 100644 --- a/spec/unit/network/server.rb +++ b/spec/unit/network/server.rb @@ -161,8 +161,12 @@ describe Puppet::Network::Server, "in general" do Proc.new { @server2.unregister(:bar) }.should raise_error(ArgumentError) end - it "should provide a means of determining which style of service is being offered to clients" do - @server.protocols.should == [] + it "should provide a means of determining which protocols are in use" do + @server.should respond_to(:protocols) + end + + it "should only support the REST protocol at this time" do + @server.protocols.should == [ :rest ] end it "should provide a means of determining the listening address" do @@ -230,23 +234,54 @@ describe Puppet::Network::Server, "when listening is being turned on" do @mock_http_server_class = mock('http server class') Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class) Puppet.stubs(:[]).with(:servertype).returns(:suparserver) - @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337) + @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337, :handlers => [:node]) @mock_http_server = mock('http server') @mock_http_server.stubs(:listen) end - it "should fetch an instance of an HTTP server when listening is turned on" do - mock_http_server_class = mock('http server class') - mock_http_server_class.expects(:new).returns(@mock_http_server) - @server.expects(:http_server_class).returns(mock_http_server_class) + it "should fetch an instance of an HTTP server" do + @server.stubs(:http_server_class).returns(@mock_http_server_class) + @mock_http_server_class.expects(:new).returns(@mock_http_server) @server.listen end - it "should cause the HTTP server to listen when listening is turned on" do + it "should cause the HTTP server to listen" do + @server.stubs(:http_server).returns(@mock_http_server) @mock_http_server.expects(:listen) - @server.expects(:http_server).returns(@mock_http_server) @server.listen end + + it "should pass the listening address to the HTTP server" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen).with do |args| + args[:address] == '127.0.0.1' + end + @server.listen + end + + it "should pass the listening port to the HTTP server" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen).with do |args| + args[:port] == 31337 + end + @server.listen + end + + it "should pass a list of handlers to the HTTP server" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen).with do |args| + args[:handlers] == [ :node ] + end + @server.listen + end + + it "should pass a list of protocols to the HTTP server" do + @server.stubs(:http_server).returns(@mock_http_server) + @mock_http_server.expects(:listen).with do |args| + args[:protocols] == [ :rest ] + end + @server.listen + end end describe Puppet::Network::Server, "when listening is being turned off" do |