diff --git a/lib/puppet/application.rb b/lib/puppet/application.rb index 2fec38bf2..f0159a65d 100644 --- a/lib/puppet/application.rb +++ b/lib/puppet/application.rb @@ -254,19 +254,6 @@ class Application def preinit end - def option_parser - return @option_parser if defined?(@option_parser) - - @option_parser = OptionParser.new(self.class.banner) - - self.class.option_parser_commands.each do |options, fname| - @option_parser.on(*options) do |value| - self.send(fname, value) - end - end - @option_parser - end - def initialize(command_line = nil) require 'puppet/util/command_line' @command_line = command_line || Puppet::Util::CommandLine.new @@ -323,20 +310,29 @@ class Application end def parse_options - # get all puppet options - optparse_opt = [] - optparse_opt = Puppet.settings.optparse_addargs(optparse_opt) + # Create an option parser + option_parser = OptionParser.new(self.class.banner) - # convert them to OptionParser format - optparse_opt.each do |option| - self.option_parser.on(*option) do |arg| + # Add all global options to it. + Puppet.settings.optparse_addargs([]).each do |option| + option_parser.on(*option) do |arg| handlearg(option[0], arg) end end - # scan command line argument + # Add options that are local to this application, which were + # created using the "option()" metaprogramming method. If there + # are any conflicts, this application's options will be favored. + self.class.option_parser_commands.each do |options, fname| + option_parser.on(*options) do |value| + # Call the method that "option()" created. + self.send(fname, value) + end + end + + # scan command line. begin - self.option_parser.parse!(self.command_line.args) + option_parser.parse!(self.command_line.args) rescue OptionParser::ParseError => detail $stderr.puts detail $stderr.puts "Try 'puppet #{command_line.subcommand_name} --help'" diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 318ff416b..972e9e66c 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -268,7 +268,7 @@ module Puppet setdefaults( :ca, - :ca_name => ["$certname", "The name to use the Certificate Authority certificate."], + :ca_name => ["Puppet CA: $certname", "The name to use the Certificate Authority certificate."], :cadir => { :default => "$ssldir/ca", :owner => "service", :group => "service", diff --git a/lib/puppet/feature/rails.rb b/lib/puppet/feature/rails.rb index e0e14ebeb..74ed09aa6 100644 --- a/lib/puppet/feature/rails.rb +++ b/lib/puppet/feature/rails.rb @@ -24,9 +24,7 @@ Puppet.features.add(:rails) do end end - if ! (defined?(::ActiveRecord) and defined?(::ActiveRecord::VERSION) and defined?(::ActiveRecord::VERSION::MAJOR) and defined?(::ActiveRecord::VERSION::MINOR)) - false - elsif ! (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR >= 1) + unless (Puppet::Util.activerecord_version >= 2.1) Puppet.info "ActiveRecord 2.1 or later required for StoreConfigs" false else diff --git a/lib/puppet/provider/ssh_authorized_key/parsed.rb b/lib/puppet/provider/ssh_authorized_key/parsed.rb index 82f6b8881..6a3855c0e 100644 --- a/lib/puppet/provider/ssh_authorized_key/parsed.rb +++ b/lib/puppet/provider/ssh_authorized_key/parsed.rb @@ -61,6 +61,13 @@ require 'puppet/provider/parsedfile' Dir.mkdir(dir, dir_perm) File.chown(uid, nil, dir) end + + # ParsedFile usually calls backup_target much later in the flush process, + # but our SUID makes that fail to open filebucket files for writing. + # Fortunately, there's already logic to make sure it only ever happens once, + # so calling it here supresses the later attempt by our superclass's flush method. + self.class.backup_target(target) + Puppet::Util::SUIDManager.asuser(@resource.should(:user)) { super } File.chown(uid, nil, target) File.chmod(file_perm, target) diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb index 414b1bc18..c2d492fdd 100644 --- a/lib/puppet/rails.rb +++ b/lib/puppet/rails.rb @@ -2,6 +2,7 @@ require 'facter' require 'puppet' +require 'logger' module Puppet::Rails TIME_DEBUG = true @@ -22,9 +23,8 @@ module Puppet::Rails ActiveRecord::Base.logger.level = Logger::DEBUG end - if (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR <= 1) - ActiveRecord::Base.allow_concurrency = true - end + # As of ActiveRecord 2.2 allow_concurrency has been deprecated and no longer has any effect. + ActiveRecord::Base.allow_concurrency = true if Puppet::Util.activerecord_version < 2.2 ActiveRecord::Base.verify_active_connections! diff --git a/lib/puppet/reference/type.rb b/lib/puppet/reference/type.rb index 847bbc223..b423387e9 100644 --- a/lib/puppet/reference/type.rb +++ b/lib/puppet/reference/type.rb @@ -5,6 +5,7 @@ type = Puppet::Util::Reference.newreference :type, :doc => "All Puppet resource Puppet::Type.eachtype { |type| next if type.name == :puppet next if type.name == :component + next if type.name == :whit types[type.name] = type } diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb index e4d06a039..2f6cae3f5 100644 --- a/lib/puppet/ssl/certificate_request.rb +++ b/lib/puppet/ssl/certificate_request.rb @@ -29,7 +29,7 @@ class Puppet::SSL::CertificateRequest < Puppet::SSL::Base # Support either an actual SSL key, or a Puppet key. key = key.content if key.is_a?(Puppet::SSL::Key) - # If we're a CSR for the CA, then use the real certname, rather than the + # If we're a CSR for the CA, then use the real ca_name, rather than the # fake 'ca' name. This is mostly for backward compatibility with 0.24.x, # but it's also just a good idea. common_name = name == Puppet::SSL::CA_NAME ? Puppet.settings[:ca_name] : name diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb index 63e6b922a..f3321bd29 100644 --- a/lib/puppet/sslcertificates/ca.rb +++ b/lib/puppet/sslcertificates/ca.rb @@ -147,21 +147,19 @@ class Puppet::SSLCertificates::CA # Create the root certificate. def mkrootcert - # Make the root cert's name the FQDN of the host running the CA. - name = Facter["hostname"].value + # Make the root cert's name "Puppet CA: " plus the FQDN of the host running the CA. + name = "Puppet CA: #{Facter["hostname"].value}" if domain = Facter["domain"].value name += ".#{domain}" end - cert = Certificate.new( - + cert = Certificate.new( :name => name, :cert => @config[:cacert], :encrypt => @config[:capass], :key => @config[:cakey], :selfsign => true, :ttl => ttl, - :type => :ca ) @@ -241,19 +239,15 @@ class Puppet::SSLCertificates::CA f << "%04X" % (serial + 1) } - - newcert = Puppet::SSLCertificates.mkcert( - + newcert = Puppet::SSLCertificates.mkcert( :type => :server, :name => csr.subject, :ttl => ttl, :issuer => @cert, :serial => serial, - :publickey => csr.public_key ) - sign_with_key(newcert) self.storeclientcert(newcert) diff --git a/lib/puppet/type/whit.rb b/lib/puppet/type/whit.rb index 6e5ba9eab..55bfcfb46 100644 --- a/lib/puppet/type/whit.rb +++ b/lib/puppet/type/whit.rb @@ -4,4 +4,8 @@ Puppet::Type.newtype(:whit) do newparam :name do desc "The name of the whit, because it must have one." end + + def to_s + "Class[#{name}]" + end end diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index bb4127089..f2eaf0d06 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -20,6 +20,14 @@ module Util # Create a hash to store the different sync objects. @@syncresources = {} + def self.activerecord_version + if (defined?(::ActiveRecord) and defined?(::ActiveRecord::VERSION) and defined?(::ActiveRecord::VERSION::MAJOR) and defined?(::ActiveRecord::VERSION::MINOR)) + ([::ActiveRecord::VERSION::MAJOR, ::ActiveRecord::VERSION::MINOR].join('.').to_f) + else + 0 + end + end + # Return the sync object associated with a given resource. def self.sync(resource) @@syncresources[resource] ||= Sync.new diff --git a/spec/integration/application/doc_spec.rb b/spec/integration/application/doc_spec.rb index cb9f47868..eaf5442a0 100644 --- a/spec/integration/application/doc_spec.rb +++ b/spec/integration/application/doc_spec.rb @@ -45,4 +45,11 @@ describe Puppet::Application::Doc do Dir.chdir(old_dir) end end + + it "should respect the -o option" do + puppetdoc = Puppet::Application[:doc] + puppetdoc.command_line.stubs(:args).returns(['foo', '-o', 'bar']) + puppetdoc.parse_options + puppetdoc.options[:outputdir].should == 'bar' + end end diff --git a/spec/integration/defaults_spec.rb b/spec/integration/defaults_spec.rb index 4ae2983f4..1f90c7cbc 100755 --- a/spec/integration/defaults_spec.rb +++ b/spec/integration/defaults_spec.rb @@ -227,7 +227,7 @@ describe "Puppet defaults" do it "should have a :caname setting that defaults to the cert name" do Puppet.settings[:certname] = "foo" - Puppet.settings[:ca_name].should == "foo" + Puppet.settings[:ca_name].should == "Puppet CA: foo" end it "should have a 'prerun_command' that defaults to the empty string" do diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb index 433809172..be7cda340 100755 --- a/spec/unit/application_spec.rb +++ b/spec/unit/application_spec.rb @@ -191,24 +191,17 @@ describe Puppet::Application do Puppet.settings.stubs(:optparse_addargs).returns([]) end - it "should create a new option parser when needed" do - option_parser = stub "option parser" - option_parser.stubs(:on) - OptionParser.expects(:new).returns(option_parser).once - @app.option_parser.should == option_parser - @app.option_parser.should == option_parser - end - it "should pass the banner to the option parser" do option_parser = stub "option parser" option_parser.stubs(:on) + option_parser.stubs(:parse!) @app.class.instance_eval do banner "banner" end OptionParser.expects(:new).with("banner").returns(option_parser) - @app.option_parser + @app.parse_options end it "should get options from Puppet.settings.optparse_addargs" do @@ -219,15 +212,14 @@ describe Puppet::Application do it "should add Puppet.settings options to OptionParser" do Puppet.settings.stubs(:optparse_addargs).returns( [["--option","-o", "Funny Option"]]) - - @app.option_parser.expects(:on).with { |*arg| arg == ["--option","-o", "Funny Option"] } - + Puppet.settings.expects(:handlearg).with("--option", 'true') + @app.command_line.stubs(:args).returns(["--option"]) @app.parse_options end it "should ask OptionParser to parse the command-line argument" do @app.command_line.stubs(:args).returns(%w{ fake args }) - @app.option_parser.expects(:parse!).with(%w{ fake args }) + OptionParser.any_instance.expects(:parse!).with(%w{ fake args }) @app.parse_options end @@ -258,31 +250,30 @@ describe Puppet::Application do describe "when dealing with an argument not declared directly by the application" do it "should pass it to handle_unknown if this method exists" do - Puppet.settings.stubs(:optparse_addargs).returns([["--not-handled"]]) - @app.option_parser.stubs(:on).yields("value") + Puppet.settings.stubs(:optparse_addargs).returns([["--not-handled", :REQUIRED]]) @app.expects(:handle_unknown).with("--not-handled", "value").returns(true) - + @app.command_line.stubs(:args).returns(["--not-handled", "value"]) @app.parse_options end it "should pass it to Puppet.settings if handle_unknown says so" do - Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet"]]) - @app.option_parser.stubs(:on).yields("value") + Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet", :REQUIRED]]) @app.stubs(:handle_unknown).with("--topuppet", "value").returns(false) Puppet.settings.expects(:handlearg).with("--topuppet", "value") + @app.command_line.stubs(:args).returns(["--topuppet", "value"]) @app.parse_options end it "should pass it to Puppet.settings if there is no handle_unknown method" do - Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet"]]) - @app.option_parser.stubs(:on).yields("value") + Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet", :REQUIRED]]) @app.stubs(:respond_to?).returns(false) Puppet.settings.expects(:handlearg).with("--topuppet", "value") + @app.command_line.stubs(:args).returns(["--topuppet", "value"]) @app.parse_options end @@ -310,7 +301,7 @@ describe Puppet::Application do it "should exit if OptionParser raises an error" do $stderr.stubs(:puts) - @app.option_parser.stubs(:parse!).raises(OptionParser::ParseError.new("blah blah")) + OptionParser.any_instance.stubs(:parse!).raises(OptionParser::ParseError.new("blah blah")) @app.expects(:exit) @@ -478,7 +469,7 @@ describe Puppet::Application do @app.class.option("--[no-]test3","-t") do end - @app.option_parser + @app.parse_options end it "should pass a block that calls our defined method" do @@ -490,7 +481,7 @@ describe Puppet::Application do @app.class.option("--test4","-t") do end - @app.option_parser + @app.parse_options end end @@ -501,7 +492,7 @@ describe Puppet::Application do @app.class.option("--test4","-t") - @app.option_parser + @app.parse_options end it "should give to OptionParser a block that adds the the value to the options array" do @@ -512,7 +503,7 @@ describe Puppet::Application do @app.class.option("--test4","-t") - @app.option_parser + @app.parse_options end end end diff --git a/spec/unit/rails_spec.rb b/spec/unit/rails_spec.rb index eaa968099..01e822ff3 100755 --- a/spec/unit/rails_spec.rb +++ b/spec/unit/rails_spec.rb @@ -47,14 +47,20 @@ describe Puppet::Rails, "when initializing any connection" do Puppet::Rails.connect end - describe "on ActiveRecord 2.1.x" do - confine("ActiveRecord 2.1.x") { ::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR <= 1 } - - it "should set ActiveRecord::Base.allow_concurrency" do + describe "ActiveRecord Version" do + it "should set ActiveRecord::Base.allow_concurrency if ActiveRecord is 2.1" do + Puppet::Util.stubs(:activerecord_version).returns(2.1) ActiveRecord::Base.expects(:allow_concurrency=).with(true) Puppet::Rails.connect end + + it "should not set ActiveRecord::Base.allow_concurrency if ActiveRecord is >= 2.2" do + Puppet::Util.stubs(:activerecord_version).returns(2.2) + ActiveRecord::Base.expects(:allow_concurrency=).never + + Puppet::Rails.connect + end end it "should call ActiveRecord::Base.verify_active_connections!" do diff --git a/spec/unit/sslcertificates/ca_spec.rb b/spec/unit/sslcertificates/ca_spec.rb new file mode 100644 index 000000000..b1393b25d --- /dev/null +++ b/spec/unit/sslcertificates/ca_spec.rb @@ -0,0 +1,110 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet' +require 'puppet/sslcertificates' +require 'puppet/sslcertificates/ca' + +describe Puppet::SSLCertificates::CA do + before :all do + @hosts = %w{host.domain.com Other.Testing.Com} + end + + before :each do + Puppet::Util::SUIDManager.stubs(:asuser).yields + file = Tempfile.new("ca_testing") + @dir = file.path + file.delete + + Puppet.settings[:confdir] = @dir + Puppet.settings[:vardir] = @dir + + @ca = Puppet::SSLCertificates::CA.new + end + + after :each do + system("rm -rf #{@dir}") + end + + describe 'when cleaning' do + it 'should remove associated files' do + dirs = [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir] + + @hosts.each do |host| + files = [] + dirs.each do |dir| + dir = Puppet[dir] + + # Case insensitivity is handled through downcasing + file = File.join(dir, host.downcase + '.pem') + + File.open(file, "w") do |f| + f.puts "testing" + end + + files << file + end + + lambda { @ca.clean(host) }.should_not raise_error + + files.reject {|f| ! File.exists?(f)}.should be_empty + end + end + end + + describe 'when mapping hosts to files' do + it 'should correctly return the certfile' do + @hosts.each do |host| + value = nil + lambda { value = @ca.host2certfile host }.should_not raise_error + + File.join(Puppet[:signeddir], host.downcase + '.pem').should == value + end + end + + it 'should correctly return the csrfile' do + @hosts.each do |host| + value = nil + lambda { value = @ca.host2csrfile host }.should_not raise_error + + File.join(Puppet[:csrdir], host.downcase + '.pem').should == value + end + end + end + + describe 'when listing' do + it 'should find all csr' do + list = [] + + # Make some fake CSRs + @hosts.each do |host| + file = File.join(Puppet[:csrdir], host.downcase + '.pem') + File.open(file, 'w') { |f| f.puts "yay" } + list << host.downcase + end + + @ca.list.sort.should == list.sort + end + end + + describe 'when creating a root certificate' do + before :each do + lambda { @ca.mkrootcert }.should_not raise_exception + end + + it 'should store the public key' do + File.exists?(Puppet[:capub]).should be_true + end + + it 'should prepend "Puppet CA: " to the fqdn as the ca_name by default' do + host_mock_fact = mock() + host_mock_fact.expects(:value).returns('myhost') + domain_mock_fact = mock() + domain_mock_fact.expects(:value).returns('puppetlabs.lan') + Facter.stubs(:[]).with('hostname').returns(host_mock_fact) + Facter.stubs(:[]).with('domain').returns(domain_mock_fact) + + @ca.mkrootcert.name.should == 'Puppet CA: myhost.puppetlabs.lan' + end + end +end diff --git a/spec/unit/type/whit_spec.rb b/spec/unit/type/whit_spec.rb new file mode 100644 index 000000000..998d9df30 --- /dev/null +++ b/spec/unit/type/whit_spec.rb @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +whit = Puppet::Type.type(:whit).new(:name => "Foo::Bar") + +describe whit do + it "should stringify as though it were the class it represents" do + whit.to_s.should == "Class[Foo::Bar]" + end +end diff --git a/test/certmgr/ca.rb b/test/certmgr/ca.rb deleted file mode 100755 index 7e0498dfb..000000000 --- a/test/certmgr/ca.rb +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../lib/puppettest' - -require 'puppet' -require 'puppet/sslcertificates/ca.rb' -require 'puppettest' -require 'puppettest/certificates' -require 'mocha' - -class TestCA < Test::Unit::TestCase - include PuppetTest - - def setup - super - Puppet::Util::SUIDManager.stubs(:asuser).yields - end - - def hosts - %w{host.domain.com Other.Testing.Com} - end - def mkca - Puppet::SSLCertificates::CA.new - end - - def test_clean - dirs = [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir] - ca = mkca - - hosts.each do |host| - files = [] - dirs.each do |dir| - dir = Puppet[dir] - # We handle case insensitivity through downcasing - file = File.join(dir, host.downcase + ".pem") - File.open(file, "w") do |f| - f.puts "testing" - end - files << file - end - assert_nothing_raised do - ca.clean(host) - end - files.each do |f| - assert(! FileTest.exists?(f), "File #{f} was not deleted") - end - end - end - - def test_host2Xfile - ca = mkca - hosts.each do |host| - {:signeddir => :host2certfile, :csrdir => :host2csrfile}.each do |dir, method| - val = nil - assert_nothing_raised do - val = ca.send(method, host) - end - assert_equal(File.join(Puppet[dir], host.downcase + ".pem"), val, - "incorrect response from #{method}") - end - end - end - - def test_list - ca = mkca - # Make a fake csr - dir = Puppet[:csrdir] - list = [] - hosts.each do |host| - file = File.join(dir, host.downcase + ".pem") - File.open(file, "w") { |f| f.puts "yay" } - list << host.downcase - end - - assert_equal(list.sort, ca.list.sort, "list was not correct") - end - - # #142 - test storing the public key - def test_store_public_key - ca = mkca - assert_nothing_raised do - ca.mkrootcert - end - assert(FileTest.exists?(Puppet[:capub]), "did not store public key") - end -end -