diff options
-rwxr-xr-x | bin/puppetd | 33 | ||||
-rw-r--r-- | lib/puppet/executables/client/certhandler.rb | 68 | ||||
-rwxr-xr-x | spec/unit/executables/client/certhandler.rb | 80 |
3 files changed, 151 insertions, 30 deletions
diff --git a/bin/puppetd b/bin/puppetd index 96d0e5ee8..2a71c3a8d 100755 --- a/bin/puppetd +++ b/bin/puppetd @@ -162,6 +162,7 @@ trap(:INT) do end require 'puppet' +require 'puppet/executables/client/certhandler' require 'puppet/network/client' require 'getoptlong' @@ -342,36 +343,8 @@ if Puppet[:daemonize] client.daemonize end -unless Puppet::Network::HttpPool.read_cert - # If we don't already have the certificate, then create a client to - # request one. Use the special ca stuff, don't use the normal server and port. - caclient = Puppet::Network::Client.ca.new() - if options[:waitforcert] > 0 - begin - while ! caclient.request_cert do - Puppet.notice "Did not receive certificate" - sleep options[:waitforcert] - end - rescue => detail - Puppet.err "Could not request certificate: %s" % detail.to_s - exit(23) - end - else - unless caclient.request_cert - Puppet.notice "No certificates; exiting" - exit(1) - end - end - - # Now read the new cert in. - if Puppet::Network::HttpPool.read_cert - # If we read it in, then get rid of our existing http connection. - client.recycle_connection - Puppet.notice "Got signed certificate" - else - Puppet.err "Could not read certificates after retrieving them" - exit(34) - end +unless Puppet::Executables::Client::CertHandler.new(options[:waitforcert], options[:onetime]).read_retrieve + client.recycle_connection end objects = [] diff --git a/lib/puppet/executables/client/certhandler.rb b/lib/puppet/executables/client/certhandler.rb new file mode 100644 index 000000000..d2ead3950 --- /dev/null +++ b/lib/puppet/executables/client/certhandler.rb @@ -0,0 +1,68 @@ + +module Puppet + module Executables + module Client + class CertHandler + attr_writer :wait_for_cert, :one_time + + def initialize(wait_time, is_one_time) + @wait_for_cert = wait_time + @one_time = is_one_time + @new_cert = false + end + + def read_retrieve + #NOTE: ACS this is checking that a file exists, maybe next time just do that? + unless read_cert + # If we don't already have the certificate, then create a client to + # request one. Use the special ca stuff, don't use the normal server and port. + retrieve_cert + end + + !@new_cert + end + + def retrieve_cert + caclient = Puppet::Network::Client.ca.new() + + while true do + begin + if caclient.request_cert + break if read_new_cert + else + Puppet.notice "Did not receive certificate" + if @one_time + Puppet.notice "Set to run 'one time'; exiting with no certificate" + exit(1) + end + end + rescue StandardError => detail + Puppet.err "Could not request certificate: %s" % detail.to_s + exit(23) if @one_time + end + + sleep @wait_for_cert + end + end + + def read_cert + Puppet::Network::HttpPool.read_cert + end + + def read_new_cert + if Puppet::Network::HttpPool.read_cert + # If we read it in, then we need to get rid of our existing http connection. + # The @new_cert flag will help us do that + @new_cert = true + Puppet.notice "Got signed certificate" + else + Puppet.err "Could not read certificates after retrieving them" + exit(34) if @one_time + end + + return @new_cert + end + end + end + end +end diff --git a/spec/unit/executables/client/certhandler.rb b/spec/unit/executables/client/certhandler.rb new file mode 100755 index 000000000..d12c51c1b --- /dev/null +++ b/spec/unit/executables/client/certhandler.rb @@ -0,0 +1,80 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +require 'puppet/executables/client/certhandler' + +cert_handler = Puppet::Executables::Client::CertHandler + +describe cert_handler, "when handling certificates" do + before do + @caclient = mock('caclient') + caclient_class = mock('caclient_class') + caclient_class.stubs(:new).returns(@caclient) + Puppet::Network::Client.stubs(:ca).returns(caclient_class) + end + + it "should return true if the certificate exists" do + Puppet::Network::HttpPool.expects(:read_cert).returns(true) + cert_handler.new(1,true).read_retrieve.should be_true + end + + it "should return false when getting a new cert" do + Puppet::Network::HttpPool.expects(:read_cert).returns(true) + @caclient.stubs(:request_cert).returns(true) + ch = cert_handler.new(1,true) + ch.stubs(:read_cert).returns(false) + ch.read_retrieve.should be_false + end + + describe "when waiting for cert" do + it "should loop when the cert request fails" do + @caclient.stubs(:request_cert).times(2).returns(false).then.returns(true) + ch = cert_handler.new(1,false) + ch.expects(:sleep) + ch.expects(:read_new_cert).returns(true) + ch.read_retrieve + end + + it "should loop when the cert request raises an Error" do + @caclient.stubs(:request_cert).times(2).raises(StandardError, 'Testing').then.returns(true) + ch = cert_handler.new(1,false) + ch.expects(:sleep) + ch.expects(:read_new_cert).returns(true) + ch.read_retrieve + end + + it "should loop when the new cert can't be read" do + @caclient.stubs(:request_cert).returns(true) + ch = cert_handler.new(1,false) + ch.expects(:sleep) + ch.expects(:read_new_cert).times(2).returns(false).then.returns(true) + ch.read_retrieve + end + end + + describe "when in one time mode" do + it "should exit if the cert request fails" do + @caclient.stubs(:request_cert).returns(false) + ch = cert_handler.new(1,true) + ch.expects(:exit).with(1).raises(SystemExit) + lambda { ch.read_retrieve }.should raise_error(SystemExit) + end + + + it "should exit if the cert request raises an exception" do + @caclient.stubs(:request_cert).raises(StandardError, 'Testing') + ch = cert_handler.new(1,true) + ch.expects(:exit).with(23).raises(SystemExit) + lambda { ch.read_retrieve }.should raise_error(SystemExit) + end + + it "should exit if the new cert can't be read" do + @caclient.stubs(:request_cert).returns(true) + Puppet::Network::HttpPool.stubs(:read_cert).returns(false) + ch = cert_handler.new(1,true) + ch.expects(:exit).with(34).raises(SystemExit) + lambda { ch.read_retrieve }.should raise_error(SystemExit) + end + end +end |