Signed-off-by: Brice Figureau <brice-pup...@daysofwonder.com> --- bin/puppetmasterd | 168 +---------------- lib/puppet/application/puppetmasterd.rb | 143 ++++++++++++++ spec/unit/application/puppetmasterd.rb | 323 +++++++++++++++++++++++++++++++ 3 files changed, 468 insertions(+), 166 deletions(-) create mode 100644 lib/puppet/application/puppetmasterd.rb create mode 100644 spec/unit/application/puppetmasterd.rb
diff --git a/bin/puppetmasterd b/bin/puppetmasterd index 3abdb77..9f12f67 100755 --- a/bin/puppetmasterd +++ b/bin/puppetmasterd @@ -62,169 +62,5 @@ # Copyright (c) 2005 Reductive Labs, LLC # Licensed under the GNU Public License -# Do an initial trap, so that cancels don't get a stack trace. -trap(:INT) do - $stderr.puts "Cancelling startup" - exit(0) -end - -require 'getoptlong' -require 'puppet' -require 'puppet/daemon' -require 'puppet/network/server' - -# Create this first-off, so we have ARGV -daemon = Puppet::Daemon.new -daemon.argv = ARGV.dup - -options = [ - [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], - [ "--help", "-h", GetoptLong::NO_ARGUMENT ], - [ "--logdest", "-l", GetoptLong::REQUIRED_ARGUMENT ], - [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], - [ "--version", "-V", GetoptLong::NO_ARGUMENT ] -] - -# Add all of the config parameters as valid options. -Puppet.settings.addargs(options) - -result = GetoptLong.new(*options) - -options = { - :setdest => false, - :verbose => false, - :debug => false -} - -begin - result.each { |opt,arg| - case opt - # First check to see if the argument is a valid configuration parameter; - # if so, set it. NOTE: there is a catch-all at the bottom for defaults.rb - when "--debug" - options[:debug] = true - when "--help" - if Puppet.features.usage? - RDoc::usage && exit - else - puts "No help available unless you have RDoc::usage installed" - exit - end - when "--logdest" - begin - Puppet::Util::Log.newdestination(arg) - options[:setdest] = true - rescue => detail - if Puppet[:debug] - puts detail.backtrace - end - $stderr.puts detail.to_s - end - when "--version" - puts "%s" % Puppet.version - exit - when "--verbose" - options[:verbose] = true - else - Puppet.settings.handlearg(opt, arg) - end - } -rescue GetoptLong::InvalidOption => detail - $stderr.puts "Try '#{$0} --help'" - #$stderr.puts detail - exit(1) -end - -# Now parse the config -Puppet.parse_config - -# Handle the logging settings. -if options[:debug] or options[:verbose] - if options[:debug] - Puppet::Util::Log.level = :debug - else - Puppet::Util::Log.level = :info - end - - unless Puppet[:daemonize] - Puppet::Util::Log.newdestination(:console) - options[:setdest] = true - end -end - -unless options[:setdest] - Puppet::Util::Log.newdestination(:syslog) -end - -if Puppet.settings.print_configs? - exit(Puppet.settings.print_configs ? 0 : 1) -end - -Puppet.settings.use :main, :puppetmasterd, :ssl - -# A temporary solution, to at least make the master work for now. -Puppet::Node::Facts.terminus_class = :yaml - -# Cache our nodes in yaml. Currently not configurable. -Puppet::Node.cache_class = :yaml - -# Configure all of the SSL stuff. -if Puppet::SSL::CertificateAuthority.ca? - Puppet::SSL::Host.ca_location = :local - Puppet.settings.use :ca - Puppet::SSL::CertificateAuthority.instance -else - Puppet::SSL::Host.ca_location = :none -end - -require 'etc' - -if Puppet[:parseonly] - begin - Puppet::Parser::Interpreter.new.parser(Puppet[:environment]) - rescue => detail - Puppet.err detail - exit 1 - end - exit(0) -end - -require 'puppet/file_serving/content' -require 'puppet/file_serving/metadata' -require 'puppet/checksum' - -xmlrpc_handlers = [:Status, :FileServer, :Master, :Report, :Filebucket] - -# Just set up serving to all of the indirected classes. -rest_handlers = Puppet::Indirector::Indirection.instances - -if Puppet[:ca] - xmlrpc_handlers << :CA -end - -daemon.server = Puppet::Network::Server.new(:handlers => rest_handlers, :xmlrpc_handlers => xmlrpc_handlers) - -# Make sure we've got a localhost ssl cert -Puppet::SSL::Host.localhost - -# And now configure our server to *only* hit the CA for data, because that's -# all it will have write access to. -if Puppet::SSL::CertificateAuthority.ca? - Puppet::SSL::Host.ca_location = :only -end - -if Process.uid == 0 - begin - Puppet::Util.chuser - rescue => detail - puts detail.backtrace if Puppet[:trace] - $stderr.puts "Could not change user to %s: %s" % [Puppet[:user], detail] - exit(39) - end -end - -daemon.daemonize if Puppet[:daemonize] - -Puppet.notice "Starting Puppet server version %s" % [Puppet.version] - -daemon.start +require 'puppet/application/puppetmasterd' +Puppet::Application[:puppetmasterd].run diff --git a/lib/puppet/application/puppetmasterd.rb b/lib/puppet/application/puppetmasterd.rb new file mode 100644 index 0000000..e9b2e7f --- /dev/null +++ b/lib/puppet/application/puppetmasterd.rb @@ -0,0 +1,143 @@ +require 'puppet' +require 'puppet/application' +require 'puppet/daemon' +require 'puppet/network/server' + +puppetmasterd_options = [ + [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], + [ "--help", "-h", GetoptLong::NO_ARGUMENT ], + [ "--logdest", "-l", GetoptLong::REQUIRED_ARGUMENT ], + [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], + [ "--version", "-V", GetoptLong::NO_ARGUMENT ] +] + +Puppet::Application.new(:puppetmasterd, puppetmasterd_options) do + + should_parse_config + + dispatch do + return Puppet[:parseonly] ? :parseonly : :main + end + + command(:parseonly) do + begin + Puppet::Parser::Interpreter.new.parser(Puppet[:environment]) + rescue => detail + Puppet.err detail + exit 1 + end + exit(0) + end + + command(:main) do + require 'etc' + require 'puppet/file_serving/content' + require 'puppet/file_serving/metadata' + require 'puppet/checksum' + + xmlrpc_handlers = [:Status, :FileServer, :Master, :Report, :Filebucket] + + # Just set up serving to all of the indirected classes. + rest_handlers = Puppet::Indirector::Indirection.instances + + if Puppet[:ca] + xmlrpc_handlers << :CA + end + + @daemon.server = Puppet::Network::Server.new(:handlers => rest_handlers, :xmlrpc_handlers => xmlrpc_handlers) + + # Make sure we've got a localhost ssl cert + Puppet::SSL::Host.localhost + + # And now configure our server to *only* hit the CA for data, because that's + # all it will have write access to. + if Puppet::SSL::CertificateAuthority.ca? + Puppet::SSL::Host.ca_location = :only + end + + if Process.uid == 0 + begin + Puppet::Util.chuser + rescue => detail + puts detail.backtrace if Puppet[:trace] + $stderr.puts "Could not change user to %s: %s" % [Puppet[:user], detail] + exit(39) + end + end + + @daemon.daemonize if Puppet[:daemonize] + + Puppet.notice "Starting Puppet server version %s" % [Puppet.version] + + @daemon.start + end + + setup do + # Handle the logging settings. + if options[:debug] or options[:verbose] + if options[:debug] + Puppet::Util::Log.level = :debug + else + Puppet::Util::Log.level = :info + end + + unless Puppet[:daemonize] + Puppet::Util::Log.newdestination(:console) + options[:setdest] = true + end + end + + unless options[:setdest] + Puppet::Util::Log.newdestination(:syslog) + end + + if Puppet.settings.print_configs? + exit(Puppet.settings.print_configs ? 0 : 1) + end + + Puppet.settings.use :main, :puppetmasterd, :ssl + + # A temporary solution, to at least make the master work for now. + Puppet::Node::Facts.terminus_class = :yaml + + # Cache our nodes in yaml. Currently not configurable. + Puppet::Node.cache_class = :yaml + + # Configure all of the SSL stuff. + if Puppet::SSL::CertificateAuthority.ca? + Puppet::SSL::Host.ca_location = :local + Puppet.settings.use :ca + Puppet::SSL::CertificateAuthority.instance + else + Puppet::SSL::Host.ca_location = :none + end + end + + preinit do + trap(:INT) do + $stderr.puts "Cancelling startup" + exit(0) + end + + # Create this first-off, so we have ARGV + @daemon = Puppet::Daemon.new + @daemon.argv = ARGV.dup + end + + option(:logdest) do |arg| + begin + Puppet::Util::Log.newdestination(arg) + options[:setdest] = true + rescue => detail + if Puppet[:debug] + puts detail.backtrace + end + $stderr.puts detail.to_s + end + end + + option(:version) do |arg| + puts "%s" % Puppet.version + exit + end +end \ No newline at end of file diff --git a/spec/unit/application/puppetmasterd.rb b/spec/unit/application/puppetmasterd.rb new file mode 100644 index 0000000..f66ec8c --- /dev/null +++ b/spec/unit/application/puppetmasterd.rb @@ -0,0 +1,323 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/application/puppetmasterd' + +describe "PuppetMaster" do + before :each do + @puppetmasterd = Puppet::Application[:puppetmasterd] + @daemon = stub_everything 'daemon' + Puppet::Daemon.stubs(:new).returns(@daemon) + end + + it "should ask Puppet::Application to parse Puppet configuration file" do + @puppetmasterd.should_parse_config?.should be_true + end + + it "should declare a main command" do + @puppetmasterd.should respond_to(:main) + end + + it "should declare a parseonly command" do + @puppetmasterd.should respond_to(:parseonly) + end + + it "should declare a preinit block" do + @puppetmasterd.should respond_to(:run_preinit) + end + + describe "during preinit" do + before :each do + @puppetmasterd.stubs(:trap) + end + + it "should catch INT" do + @puppetmasterd.stubs(:trap).with { |arg,block| arg == :INT } + + @puppetmasterd.run_preinit + end + + it "should create a Puppet Daemon" do + Puppet::Daemon.expects(:new).returns(@daemon) + + @puppetmasterd.run_preinit + end + + it "should give ARGV to the Daemon" do + argv = stub 'argv' + ARGV.stubs(:dup).returns(argv) + @daemon.expects(:argv=).with(argv) + + @puppetmasterd.run_preinit + end + + end + + describe "when applying options" do + it "should exit after printing the version" do + @puppetmasterd.stubs(:puts) + + lambda { @puppetmasterd.handle_version(nil) }.should raise_error(SystemExit) + end + + it "should set the log destination with --logdest" do + Puppet::Log.expects(:newdestination).with("console") + + @puppetmasterd.handle_logdest("console") + end + + it "should put the setdest options to true" do + @puppetmasterd.options.expects(:[]=).with(:setdest,true) + + @puppetmasterd.handle_logdest("console") + end + end + + describe "during setup" do + + before :each do + Puppet::Log.stubs(:newdestination) + Puppet.stubs(:settraps) + Puppet::Log.stubs(:level=) + Puppet::SSL::CertificateAuthority.stubs(:instance) + Puppet::SSL::CertificateAuthority.stubs(:ca?) + Puppet.settings.stubs(:use) + + @puppetmasterd.options.stubs(:[]).with(any_parameters) + end + + it "should set log level to debug if --debug was passed" do + @puppetmasterd.options.stubs(:[]).with(:debug).returns(true) + + Puppet::Log.expects(:level=).with(:debug) + + @puppetmasterd.run_setup + end + + it "should set log level to info if --verbose was passed" do + @puppetmasterd.options.stubs(:[]).with(:verbose).returns(true) + + Puppet::Log.expects(:level=).with(:info) + + @puppetmasterd.run_setup + end + + it "should set console as the log destination if no --logdest and --daemonize" do + @puppetmasterd.stubs(:[]).with(:daemonize).returns(:false) + + Puppet::Log.expects(:newdestination).with(:syslog) + + @puppetmasterd.run_setup + end + + it "should set syslog as the log destination if no --logdest and not --daemonize" do + Puppet::Log.expects(:newdestination).with(:syslog) + + @puppetmasterd.run_setup + end + + it "should print puppet config if asked to in Puppet config" do + @puppetmasterd.stubs(:exit) + Puppet.settings.stubs(:print_configs?).returns(true) + + Puppet.settings.expects(:print_configs) + + @puppetmasterd.run_setup + end + + it "should exit after printing puppet config if asked to in Puppet config" do + Puppet.settings.stubs(:print_configs?).returns(true) + + lambda { @puppetmasterd.run_setup }.should raise_error(SystemExit) + end + + it "should tell Puppet.settings to use :main,:ssl and :puppetmasterd category" do + Puppet.settings.expects(:use).with(:main,:puppetmasterd,:ssl) + + @puppetmasterd.run_setup + end + + it "should set node facst terminus to yaml" do + Puppet::Node::Facts.expects(:terminus_class=).with(:yaml) + + @puppetmasterd.run_setup + end + + it "should cache class in yaml" do + Puppet::Node.expects(:cache_class=).with(:yaml) + + @puppetmasterd.run_setup + end + + describe "with no ca" do + + it "should set the ca_location to none" do + Puppet::SSL::Host.expects(:ca_location=).with(:none) + + @puppetmasterd.run_setup + end + + end + + describe "with a ca configured" do + + before :each do + Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(true) + end + + it "should set the ca_location to local" do + Puppet::SSL::Host.expects(:ca_location=).with(:local) + + @puppetmasterd.run_setup + end + + it "should tell Puppet.settings to use :ca category" do + Puppet.settings.expects(:use).with(:ca) + + @puppetmasterd.run_setup + end + + it "should instantiate the CertificateAuthority singleton" do + Puppet::SSL::CertificateAuthority.expects(:instance) + + @puppetmasterd.run_setup + end + + + end + + end + + describe "when running" do + + it "should dispatch to parseonly if parseonly is set" do + Puppet.stubs(:[]).with(:parseonly).returns(true) + + @puppetmasterd.get_command.should == :parseonly + end + + it "should dispatch to main if parseonly is not set" do + Puppet.stubs(:[]).with(:parseonly).returns(false) + + @puppetmasterd.get_command.should == :main + end + + describe "the parseonly command" do + before :each do + Puppet.stubs(:[]).with(:environment) + Puppet.stubs(:[]).with(:manifest).returns("site.pp") + @interpreter = stub_everything + Puppet.stubs(:err) + @puppetmasterd.stubs(:exit) + Puppet::Parser::Interpreter.stubs(:new).returns(@interpreter) + end + + it "should delegate to the Puppet Parser" do + + @interpreter.expects(:parser) + + @puppetmasterd.parseonly + end + + it "should exit with exit code 0 if no error" do + @puppetmasterd.expects(:exit).with(0) + + @puppetmasterd.parseonly + end + + it "should exit with exit code 1 if error" do + @interpreter.stubs(:parser).raises(Puppet::ParseError) + + @puppetmasterd.expects(:exit).with(1) + + @puppetmasterd.parseonly + end + + end + + describe "the main command" do + before :each do + @puppetmasterd.run_preinit + @server = stub_everything 'server' + Puppet::Network::Server.stubs(:new).returns(@server) + Puppet::SSL::Host.stubs(:localhost) + Puppet::SSL::CertificateAuthority.stubs(:ca?) + Process.stubs(:uid).returns(1000) + Puppet.stubs(:service) + Puppet.stubs(:[]) + Puppet.stubs(:notice) + Puppet.stubs(:start) + end + + it "should create a Server" do + Puppet::Network::Server.expects(:new) + + @puppetmasterd.main + end + + it "should give the server to the daemon" do + @daemon.expects(:server=).with(@server) + + @puppetmasterd.main + end + + it "should create the server with the right XMLRPC handlers" do + Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers] == [:Status, :FileServer, :Master, :Report, :Filebucket]} + + @puppetmasterd.main + end + + it "should create the server with a :ca xmlrpc handler if needed" do + Puppet.stubs(:[]).with(:ca).returns(true) + Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers].include?(:CA) } + + @puppetmasterd.main + end + + it "should create the server with the right REST handlers" do + Puppet::Indirector::Indirection.stubs(:instances).returns("handlers") + Puppet::Network::Server.expects(:new).with { |args| args[:handlers] == "handlers"} + + @puppetmasterd.main + end + + it "should generate a SSL cert for localhost" do + Puppet::SSL::Host.expects(:localhost) + + @puppetmasterd.main + end + + it "should make sure to *only* hit the CA for data" do + Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(true) + + Puppet::SSL::Host.expects(:ca_location=).with(:only) + + @puppetmasterd.main + end + + it "should drop privileges if running as root" do + Process.stubs(:uid).returns(0) + + Puppet::Util.expects(:chuser) + + @puppetmasterd.main + end + + it "should daemonize if needed" do + Puppet.stubs(:[]).with(:daemonize).returns(true) + + @daemon.expects(:daemonize) + + @puppetmasterd.main + end + + it "should start the service" do + @daemon.expects(:start) + + @puppetmasterd.main + end + + end + end +end \ No newline at end of file -- 1.6.0.2 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to puppet-dev@googlegroups.com To unsubscribe from this group, send email to puppet-dev+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en -~----------~----~----~----~------~----~------~--~---