summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG7
-rwxr-xr-xbin/puppetca204
-rwxr-xr-xbin/puppetd14
-rwxr-xr-xbin/puppetmasterd131
-rwxr-xr-xinstall.rb18
-rw-r--r--lib/puppet.rb11
-rw-r--r--lib/puppet/defaults.rb61
-rw-r--r--lib/puppet/file_serving/configuration.rb13
-rw-r--r--lib/puppet/file_serving/mount.rb25
-rw-r--r--lib/puppet/indirector/certificate/ca.rb9
-rw-r--r--lib/puppet/indirector/certificate/file.rb9
-rw-r--r--lib/puppet/indirector/certificate/rest.rb6
-rw-r--r--lib/puppet/indirector/certificate_request/ca.rb14
-rw-r--r--lib/puppet/indirector/certificate_request/file.rb8
-rw-r--r--lib/puppet/indirector/certificate_request/rest.rb6
-rw-r--r--lib/puppet/indirector/certificate_revocation_list/ca.rb8
-rw-r--r--lib/puppet/indirector/certificate_revocation_list/file.rb8
-rw-r--r--lib/puppet/indirector/certificate_revocation_list/rest.rb6
-rw-r--r--lib/puppet/indirector/indirection.rb22
-rw-r--r--lib/puppet/indirector/key/ca.rb20
-rw-r--r--lib/puppet/indirector/key/file.rb42
-rw-r--r--lib/puppet/indirector/rest.rb11
-rw-r--r--lib/puppet/indirector/ssl_file.rb147
-rw-r--r--lib/puppet/indirector/ssl_rsa.rb5
-rw-r--r--lib/puppet/indirector/ssl_rsa/file.rb33
-rw-r--r--lib/puppet/metatype/container.rb1
-rw-r--r--lib/puppet/metatype/instances.rb41
-rw-r--r--lib/puppet/metatype/metaparams.rb4
-rw-r--r--lib/puppet/metatype/relationships.rb7
-rw-r--r--lib/puppet/metatype/schedules.rb6
-rw-r--r--lib/puppet/network/client/ca.rb2
-rw-r--r--lib/puppet/network/client/master.rb1
-rwxr-xr-xlib/puppet/network/handler/fileserver.rb7
-rwxr-xr-xlib/puppet/network/handler/resource.rb14
-rw-r--r--lib/puppet/network/http/handler.rb7
-rw-r--r--lib/puppet/network/http/mongrel.rb11
-rw-r--r--lib/puppet/network/http/mongrel/rest.rb10
-rw-r--r--lib/puppet/network/http/webrick.rb84
-rw-r--r--lib/puppet/network/http_pool.rb49
-rw-r--r--lib/puppet/network/http_server/mongrel.rb4
-rw-r--r--lib/puppet/network/server.rb140
-rw-r--r--lib/puppet/network/xmlrpc/client.rb3
-rw-r--r--lib/puppet/node.rb2
-rw-r--r--lib/puppet/node/catalog.rb6
-rw-r--r--lib/puppet/resource_reference.rb11
-rw-r--r--lib/puppet/ssl.rb6
-rw-r--r--lib/puppet/ssl/base.rb51
-rw-r--r--lib/puppet/ssl/certificate.rb19
-rw-r--r--lib/puppet/ssl/certificate_authority.rb285
-rw-r--r--lib/puppet/ssl/certificate_authority/interface.rb110
-rw-r--r--lib/puppet/ssl/certificate_factory.rb145
-rw-r--r--lib/puppet/ssl/certificate_request.rb36
-rw-r--r--lib/puppet/ssl/certificate_revocation_list.rb72
-rw-r--r--lib/puppet/ssl/host.rb185
-rw-r--r--lib/puppet/ssl/inventory.rb52
-rw-r--r--lib/puppet/ssl/key.rb50
-rw-r--r--lib/puppet/transaction.rb4
-rw-r--r--lib/puppet/type.rb6
-rw-r--r--lib/puppet/type/component.rb4
-rw-r--r--lib/puppet/type/file.rb28
-rwxr-xr-xlib/puppet/type/filebucket.rb14
-rwxr-xr-xlib/puppet/type/schedule.rb16
-rwxr-xr-xlib/puppet/type/user.rb14
-rw-r--r--lib/puppet/type/yumrepo.rb5
-rw-r--r--lib/puppet/util/cacher.rb69
-rwxr-xr-xlib/puppet/util/filetype.rb9
-rwxr-xr-xlib/puppet/util/posix.rb39
-rw-r--r--lib/puppet/util/settings.rb117
-rw-r--r--man/man8/puppet.83
-rwxr-xr-xspec/integration/bin/puppetmasterd.rb109
-rwxr-xr-xspec/integration/defaults.rb13
-rwxr-xr-xspec/integration/file_serving/configuration.rb4
-rwxr-xr-x[-rw-r--r--]spec/integration/indirector/rest.rb832
-rwxr-xr-x[-rw-r--r--]spec/integration/network/server/mongrel.rb4
-rwxr-xr-x[-rw-r--r--]spec/integration/network/server/webrick.rb104
-rwxr-xr-xspec/integration/node/catalog.rb2
-rwxr-xr-xspec/integration/node/facts.rb6
-rwxr-xr-xspec/integration/ssl/certificate_authority.rb137
-rwxr-xr-xspec/integration/ssl/certificate_request.rb57
-rwxr-xr-xspec/integration/ssl/certificate_revocation_list.rb42
-rwxr-xr-xspec/integration/ssl/host.rb90
-rwxr-xr-xspec/integration/transaction/report.rb2
-rw-r--r--spec/shared_behaviours/file_server_terminus.rb2
-rwxr-xr-xspec/unit/file_serving/configuration.rb6
-rwxr-xr-xspec/unit/file_serving/mount.rb8
-rwxr-xr-xspec/unit/indirector/certificate/ca.rb28
-rwxr-xr-xspec/unit/indirector/certificate/file.rb28
-rwxr-xr-xspec/unit/indirector/certificate/rest.rb15
-rwxr-xr-xspec/unit/indirector/certificate_request/ca.rb19
-rwxr-xr-xspec/unit/indirector/certificate_request/file.rb19
-rwxr-xr-xspec/unit/indirector/certificate_request/rest.rb15
-rwxr-xr-xspec/unit/indirector/certificate_revocation_list/ca.rb21
-rwxr-xr-xspec/unit/indirector/certificate_revocation_list/file.rb20
-rwxr-xr-xspec/unit/indirector/certificate_revocation_list/rest.rb15
-rwxr-xr-xspec/unit/indirector/indirection.rb26
-rwxr-xr-xspec/unit/indirector/key/ca.rb34
-rwxr-xr-xspec/unit/indirector/key/file.rb104
-rwxr-xr-xspec/unit/indirector/rest.rb623
-rwxr-xr-xspec/unit/indirector/ssl_file.rb244
-rwxr-xr-xspec/unit/indirector/ssl_rsa/file.rb116
-rw-r--r--spec/unit/network/http/mongrel.rb47
-rw-r--r--spec/unit/network/http/webrick.rb309
-rwxr-xr-xspec/unit/network/http_pool.rb198
-rw-r--r--spec/unit/network/server.rb728
-rwxr-xr-xspec/unit/node.rb18
-rwxr-xr-xspec/unit/node/catalog.rb62
-rwxr-xr-xspec/unit/node/facts.rb8
-rwxr-xr-xspec/unit/other/transbucket.rb4
-rwxr-xr-xspec/unit/provider/mount/parsed.rb4
-rwxr-xr-xspec/unit/rails.rb2
-rwxr-xr-xspec/unit/resource_reference.rb12
-rwxr-xr-xspec/unit/ssl/certificate.rb82
-rwxr-xr-xspec/unit/ssl/certificate_authority.rb737
-rwxr-xr-xspec/unit/ssl/certificate_authority/interface.rb265
-rwxr-xr-xspec/unit/ssl/certificate_factory.rb107
-rwxr-xr-xspec/unit/ssl/certificate_request.rb167
-rwxr-xr-xspec/unit/ssl/certificate_revocation_list.rb166
-rwxr-xr-xspec/unit/ssl/host.rb431
-rwxr-xr-xspec/unit/ssl/inventory.rb180
-rwxr-xr-xspec/unit/ssl/key.rb190
-rwxr-xr-xspec/unit/transaction/report.rb2
-rwxr-xr-xspec/unit/type/file.rb4
-rwxr-xr-xspec/unit/type/interface.rb2
-rwxr-xr-xspec/unit/type/mount.rb8
-rwxr-xr-xspec/unit/type/noop_metaparam.rb2
-rwxr-xr-xspec/unit/type/package.rb10
-rwxr-xr-xspec/unit/type/schedule.rb6
-rwxr-xr-xspec/unit/type/service.rb10
-rwxr-xr-xspec/unit/util/cacher.rb158
-rwxr-xr-xspec/unit/util/settings.rb50
-rwxr-xr-xtest/executables/puppetca.rb115
-rwxr-xr-xtest/executables/puppetmasterd.rb147
-rwxr-xr-xtest/language/parser.rb11
-rwxr-xr-xtest/language/snippets.rb33
-rwxr-xr-xtest/lib/puppettest.rb2
-rw-r--r--test/lib/puppettest/exetest.rb1
-rw-r--r--test/lib/puppettest/support/utils.rb6
-rwxr-xr-xtest/network/client/ca.rb1
-rwxr-xr-xtest/network/client/master.rb18
-rwxr-xr-xtest/network/client/resource.rb5
-rwxr-xr-xtest/network/handler/fileserver.rb4
-rwxr-xr-xtest/network/handler/resource.rb98
-rwxr-xr-xtest/network/server/webrick.rb5
-rwxr-xr-xtest/other/relationships.rb11
-rwxr-xr-xtest/other/transactions.rb30
-rwxr-xr-xtest/ral/manager/instances.rb16
-rwxr-xr-xtest/ral/manager/type.rb161
-rwxr-xr-xtest/ral/providers/group.rb1
-rwxr-xr-xtest/ral/type/basic.rb85
-rwxr-xr-xtest/ral/type/cron.rb13
-rwxr-xr-xtest/ral/type/exec.rb6
-rwxr-xr-xtest/ral/type/file.rb128
-rwxr-xr-xtest/ral/type/file/target.rb24
-rwxr-xr-xtest/ral/type/filebucket.rb51
-rwxr-xr-xtest/ral/type/fileignoresource.rb11
-rwxr-xr-xtest/ral/type/filesources.rb166
-rwxr-xr-xtest/ral/type/group.rb1
-rwxr-xr-xtest/ral/type/host.rb13
-rwxr-xr-xtest/ral/type/parameter.rb2
-rwxr-xr-xtest/ral/type/sshkey.rb53
-rwxr-xr-xtest/ral/type/tidy.rb2
-rwxr-xr-xtest/ral/type/user.rb1
-rwxr-xr-xtest/ral/type/yumrepo.rb17
-rwxr-xr-xtest/util/filetype.rb4
-rwxr-xr-xtest/util/posixtest.rb10
-rwxr-xr-xtest/util/settings.rb63
-rwxr-xr-xtest/util/utiltest.rb19
167 files changed, 7296 insertions, 3339 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5b5148ff4..f0819cefb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+ Added a boolean 'crl' default value. Now we have a location for
+ the CA CRL and the host CRL, and then a setting for configuring
+ whether we should even use a CRL. This way we aren't trying to
+ set file paths to 'false' to disable the CRL.
+
Moving all confine code out of the Provider class, and fixing #1197.
Created a Confiner module for the Provider class methods, enhanced
the interface between it and the Confine class to make sure binary
@@ -198,6 +203,8 @@
permission denied exceptions caught, thus forbidding them
from being replaced with 'nil'.
+ The environment is now available as a variable in the manifests.
+
Fixed #1043 -- autoloading now searches the plugins directory
in each module, in addition to the lib directory. The 'lib'
directory is also deprecated, but supported for now to give
diff --git a/bin/puppetca b/bin/puppetca
index 759b602ac..75988432f 100755
--- a/bin/puppetca
+++ b/bin/puppetca
@@ -97,7 +97,7 @@
# Licensed under the GNU Public License
require 'puppet'
-require 'puppet/sslcertificates'
+require 'puppet/ssl/certificate_authority'
require 'getoptlong'
options = [
@@ -120,22 +120,20 @@ Puppet.settings.addargs(options)
result = GetoptLong.new(*options)
-mode = nil
-all = false
-generate = nil
+modes = Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS
-modes = [:clean, :list, :revoke, :generate, :sign, :print, :verify]
+all = false
+mode = nil
begin
result.each { |opt,arg|
case opt
+ when "--clean"
+ mode = :destroy
when "--all"
all = true
when "--debug"
Puppet::Util::Log.level = :debug
- when "--generate"
- generate = arg
- mode = :generate
when "--help"
if Puppet.features.usage?
RDoc::usage && exit
@@ -143,12 +141,6 @@ begin
puts "No help available unless you have RDoc::usage installed"
exit
end
- when "--list"
- mode = :list
- when "--revoke"
- mode = :revoke
- when "--sign"
- mode = :sign
when "--version"
puts "%s" % Puppet.version
exit
@@ -174,12 +166,14 @@ Puppet.parse_config
Puppet.genconfig
Puppet.genmanifest
+Puppet::Util::Log.newdestination :console
+
+Puppet::SSL::Host.ca_location = :local
+
begin
- ca = Puppet::SSLCertificates::CA.new()
+ ca = Puppet::SSL::CertificateAuthority.new
rescue => detail
- if Puppet[:debug]
- puts detail.backtrace
- end
+ puts detail.backtrace if Puppet[:trace]
puts detail.to_s
exit(23)
end
@@ -189,172 +183,16 @@ unless mode
exit(12)
end
-if [:verify, :print, :generate, :clean, :revoke, :list].include?(mode)
+if all
+ hosts = :all
+else
hosts = ARGV.collect { |h| h.downcase }
end
-if [:sign, :list].include?(mode)
- waiting = ca.list
- unless waiting.length > 0 or (mode == :list and all)
- puts "No certificates to sign"
- if ARGV.length > 0
- exit(17)
- else
- exit(0)
- end
- end
-end
-
-case mode
-when :list
- waiting = ca.list
- if waiting.length > 0
- puts waiting.join("\n")
- end
- if all
- puts ca.list_signed.collect { |cert | cert.sub(/^/,"+ ") }.join("\n")
- end
-when :clean
- if hosts.empty? and all == false
- $stderr.puts "You must specify one or more hosts to clean or --all to clean all host certificates"
- exit(24)
- end
-
- cleaned = false
-
- if all
- certs = ca.list
- if certs.empty?
- $stderr.puts "No certificates to clean"
- exit(24)
- end
- certs.each do |c|
- ca.clean(c)
- end
- cleaned = true
- else
- hosts.each do |host|
- cert = ca.getclientcert(host)[0]
- if cert.nil?
- $stderr.puts "Could not find client certificate for %s" % host
- next
- end
- ca.clean(host)
- cleaned = true
- end
- end
-
- unless cleaned
- exit(27)
- end
-when :sign
- to_sign = ARGV.collect { |h| h.downcase }
- unless to_sign.length > 0 or all
- $stderr.puts(
- "You must specify one or more hosts to sign certificates for or --all to sign all certificates"
- )
- exit(24)
- end
-
- unless all
- to_sign.each { |host|
- unless waiting.include?(host)
- $stderr.puts "No waiting request for %s" % host
- end
- }
- waiting = waiting.find_all { |host|
- to_sign.include?(host)
- }
- end
-
- waiting.each { |host|
- begin
- csr = ca.getclientcsr(host)
- rescue => detail
- $stderr.puts "Could not retrieve request for %s: %s" % [host, detail]
- end
-
- begin
- ca.sign(csr)
- $stderr.puts "Signed %s" % host
- rescue => detail
- $stderr.puts "Could not sign request for %s: %s" % [host, detail]
- end
-
- begin
- ca.removeclientcsr(host)
- rescue => detail
- $stderr.puts "Could not remove request for %s: %s" % [host, detail]
- end
- }
-when :generate
- # we need to generate a certificate for a host
- hosts.each { |host|
- puts "Generating certificate for %s" % host
- cert = Puppet::SSLCertificates::Certificate.new(
- :name => host
- )
- cert.mkcsr
- signedcert, cacert = ca.sign(cert.csr)
-
- cert.cert = signedcert
- cert.cacert = cacert
- cert.write
- }
-when :print
- hosts.each { |h|
- cert = ca.getclientcert(h)[0]
- puts cert.to_text
- }
-when :revoke
- hosts.each { |h|
- serial = nil
- if h =~ /^0x[0-9a-f]+$/
- serial = h.to_i(16)
- elsif h =~ /^[0-9]+$/
- serial = h.to_i
- else
- cert = ca.getclientcert(h)[0]
- if cert.nil?
- $stderr.puts "Could not find client certificate for %s" % h
- else
- serial = cert.serial
- end
- end
- unless serial.nil?
- ca.revoke(serial)
- puts "Revoked certificate with serial #{serial}"
- end
- }
-when :verify
- unless ssl = %x{which openssl}.chomp
- raise "Can't verify certificates without the openssl binary and could not find one"
- end
- success = true
-
- cacert = Puppet[:localcacert]
-
- hosts.each do |host|
- print "%s: " % host
- file = ca.host2certfile(host)
- unless FileTest.exist?(file)
- puts "no certificate found"
- success = false
- next
- end
-
-
- command = %{#{ssl} verify -CAfile #{cacert} #{file}}
- output = %x{#{command}}
- if $? == 0
- puts "valid"
- else
- puts output
- success = false
- end
- end
-else
- $stderr.puts "Invalid mode %s" % mode
- exit(42)
+begin
+ ca.apply(mode, :to => hosts)
+rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ puts detail.to_s
+ exit(24)
end
-
diff --git a/bin/puppetd b/bin/puppetd
index 96d0e5ee8..d408af7d3 100755
--- a/bin/puppetd
+++ b/bin/puppetd
@@ -321,6 +321,11 @@ if options[:centrallogs]
Puppet::Util::Log.newdestination(logdest)
end
+# We need to specify a ca location for things to work, but
+# until the REST cert transfers are working, it needs to
+# be local.
+Puppet::SSL::Host.ca_location = :local
+
# We need tomake the client either way, we just don't start it
# if --no-client is set.
client = Puppet::Network::Client.master.new(args)
@@ -342,10 +347,9 @@ 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()
+caclient = Puppet::Network::Client.ca.new()
+
+unless caclient.read_cert
if options[:waitforcert] > 0
begin
while ! caclient.request_cert do
@@ -364,7 +368,7 @@ unless Puppet::Network::HttpPool.read_cert
end
# Now read the new cert in.
- if Puppet::Network::HttpPool.read_cert
+ if caclient.read_cert
# If we read it in, then get rid of our existing http connection.
client.recycle_connection
Puppet.notice "Got signed certificate"
diff --git a/bin/puppetmasterd b/bin/puppetmasterd
index b4733e604..625b75d52 100755
--- a/bin/puppetmasterd
+++ b/bin/puppetmasterd
@@ -8,8 +8,7 @@
# = Usage
#
# puppetmasterd [-D|--daemonize|--no-daemonize] [-d|--debug] [-h|--help]
-# [-l|--logdest <file>|console|syslog] [--nobucket] [--nonodes]
-# [-v|--verbose] [-V|--version]
+# [-l|--logdest <file>|console|syslog] [-v|--verbose] [-V|--version]
#
# = Description
#
@@ -22,7 +21,7 @@
# parameter, so you can specify '--ssldir <directory>' as an argument.
#
# See the configuration file documentation at
-# http://reductivelabs.com/projects/puppet/reference/configref.html for
+# http://reductivelabs.com/trac/puppet/wiki/ConfigurationReference for
# the full list of acceptable parameters. A commented list of all
# configuration options can also be generated by running puppetmasterdd with
# '--genconfig'.
@@ -44,16 +43,6 @@
# Defaults to sending messages to syslog, or the console
# if debugging or verbosity is enabled.
#
-# nobucket::
-# Do not function as a file bucket.
-#
-# nonodes::
-# Do not use individual node designations; each node will receive the result
-# of evaluating the entire configuration.
-#
-# noreports::
-# Do not start the reports server.
-#
# verbose::
# Enable verbosity.
#
@@ -81,16 +70,12 @@ end
require 'getoptlong'
require 'puppet'
-require 'puppet/network/handler'
-require 'puppet/sslcertificates'
+require 'puppet/network/server'
options = [
[ "--debug", "-d", GetoptLong::NO_ARGUMENT ],
[ "--help", "-h", GetoptLong::NO_ARGUMENT ],
[ "--logdest", "-l", GetoptLong::REQUIRED_ARGUMENT ],
- [ "--nobucket", GetoptLong::NO_ARGUMENT ],
- [ "--noreports", GetoptLong::NO_ARGUMENT ],
- [ "--nonodes", GetoptLong::NO_ARGUMENT ],
[ "--verbose", "-v", GetoptLong::NO_ARGUMENT ],
[ "--version", "-V", GetoptLong::NO_ARGUMENT ]
]
@@ -100,15 +85,7 @@ Puppet.settings.addargs(options)
result = GetoptLong.new(*options)
-master = {}
-ca = {}
-report = {}
-bucket = {}
-
options = {
- :havereport => true,
- :havebucket => true,
- :havemaster => true,
:setdest => false,
:verbose => false,
:debug => false
@@ -128,14 +105,6 @@ begin
puts "No help available unless you have RDoc::usage installed"
exit
end
- when "--noreports"
- options[:havereport] = false
- when "--nomaster"
- options[:havemaster] = false
- when "--nobucket"
- options[:havebucket] = false
- when "--nonodes"
- master[:UseNodes] = false
when "--logdest"
begin
Puppet::Util::Log.newdestination(arg)
@@ -191,87 +160,54 @@ Puppet::Node::Facts.terminus_class = :yaml
# Cache our nodes in yaml. Currently not configurable.
Puppet::Node.cache_class = :yaml
-require 'etc'
-
-handlers = {
- :Status => {},
- :FileServer => {}
-}
-
-if options[:havemaster]
- handlers[:Master] = master
+# Configure all of the SSL stuff.
+if Puppet::SSL::CertificateAuthority.ca?
+ Puppet::SSL::Host.ca_location = :local
+ Puppet.settings.use :main, :ssl, :ca
+ Puppet::SSL::CertificateAuthority.instance
+else
+ Puppet::SSL::Host.ca_location = :none
end
-if options[:havereport]
- handlers[:Report] = report
-end
-
-if Puppet[:ca]
- handlers[:CA] = ca
-end
-
-if options[:havebucket]
- handlers[:FileBucket] = bucket
-end
+require 'etc'
if Puppet[:parseonly]
begin
- Puppet::Network::Handler.master.new(master)
+ Puppet::Parser::Interpreter.new.parser(Puppet[:environment])
rescue => detail
- if Puppet[:trace]
- puts detail.backtrace
- end
- $stderr.puts detail
- exit(32)
+ Puppet.err detail
+ exit 1
end
- # we would have already exited if the file weren't syntactically correct
exit(0)
end
-webserver = server = nil
-begin
- case Puppet[:servertype]
- when "webrick"
- # use the default, um, everything
- require 'puppet/network/http_server/webrick'
- webserver = server = Puppet::Network::HTTPServer::WEBrick.new(:Handlers => handlers)
- when "mongrel":
- require 'puppet/network/http_server/mongrel'
- server = Puppet::Network::HTTPServer::Mongrel.new(handlers)
- addr = Puppet[:bindaddress]
- if addr == ""
- addr = "127.0.0.1"
- end
- webserver = Mongrel::HttpServer.new(addr, Puppet[:masterport])
- webserver.register("/", server)
- else
- Puppet.err "Invalid server type %s" % Puppet[:servertype]
- exit(45)
- end
-rescue => detail
- if Puppet[:trace]
- puts detail.backtrace
- end
- $stderr.puts detail
- exit(1)
+require 'puppet/file_serving/content'
+require 'puppet/file_serving/metadata'
+require 'puppet/checksum'
+
+xmlrpc_handlers = [:Status, :FileServer, :Master, :Report, :Filebucket]
+rest_handlers = [:file_content, :file_metadata, :certificate, :facts, :catalog, :report, :checksum]
+
+if Puppet[:ca]
+ xmlrpc_handlers << :CA
end
+server = Puppet::Network::Server.new(:handlers => rest_handlers, :xmlrpc_handlers => xmlrpc_handlers)
+
if Process.uid == 0
begin
Puppet::Util.chuser
rescue => detail
- if Puppet[:debug]
- puts detail.backtrace
- end
+ puts detail.backtrace if Puppet[:trace]
$stderr.puts "Could not change user to %s: %s" % [Puppet[:user], detail]
exit(39)
end
end
-# Mongrel doesn't shut down like webrick; we really need to write plugins for it.
-if Puppet[:servertype] == "webrick"
- Puppet.newservice(server)
-end
+# Tell Puppet to manage this service for us, which has it starting and stopping
+# as appropriate.
+Puppet.newservice(server)
+
Puppet.settraps
if Puppet[:daemonize]
@@ -279,10 +215,5 @@ if Puppet[:daemonize]
end
Puppet.notice "Starting Puppet server version %s" % [Puppet.version]
-case Puppet[:servertype]
-when "webrick"
- Puppet.start
-when "mongrel":
- webserver.run.join
-end
+Puppet.start
diff --git a/install.rb b/install.rb
index 207f74a0b..c32c24245 100755
--- a/install.rb
+++ b/install.rb
@@ -51,10 +51,10 @@ begin
if $haverdoc
rst2man = %x{which rst2man.py}
$haveman = true
- else
+ else
$haveman = false
end
-rescue
+rescue
puts "Missing rst2man; skipping man page creation"
$haveman = false
end
@@ -151,6 +151,15 @@ def prepare_installation
InstallOptions.tests = true
+ if $haveman
+ InstallOptions.man = true
+ if RUBY_PLATFORM == "i386-mswin32"
+ InstallOptions.man = false
+ end
+ else
+ InstallOptions.man = false
+ end
+
ARGV.options do |opts|
opts.banner = "Usage: #{File.basename($0)} [options]"
opts.separator ""
@@ -173,6 +182,7 @@ def prepare_installation
end
opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full|
InstallOptions.rdoc = true
+ InstallOptions.man = true
InstallOptions.ri = true
InstallOptions.tests = true
end
@@ -277,13 +287,13 @@ def build_man(bins)
File.unlink("./puppet.conf.rst")
# Create binary man pages
- bins.each do |bin|
+ bins.each do |bin|
b = bin.gsub( "bin/", "")
%x{#{bin} --help > ./#{b}.rst}
%x{#{rst2man} ./#{b}.rst ./man/man8/#{b}.8}
File.unlink("./#{b}.rst")
end
- rescue SystemCallError
+ rescue SystemCallError
$stderr.puts "Couldn't build man pages: " + $!
$stderr.puts "Continuing with install..."
end
diff --git a/lib/puppet.rb b/lib/puppet.rb
index 66a52f9e3..cde25721e 100644
--- a/lib/puppet.rb
+++ b/lib/puppet.rb
@@ -205,16 +205,7 @@ module Puppet
end
# Parse the config file for this process.
- def self.parse_config(oldconfig = nil)
- # First look for the old configuration file.
- oldconfig ||= File.join(Puppet[:confdir], Puppet[:name].to_s + ".conf")
- if FileTest.exists?(oldconfig) and Puppet[:name] != "puppet"
- Puppet.warning "Individual config files are deprecated; remove %s and use puppet.conf" % oldconfig
- Puppet.settings.old_parse(oldconfig)
- return
- end
-
- # Now check for the normal config.
+ def self.parse_config
if Puppet[:config] and File.exists? Puppet[:config]
Puppet.debug "Parsing %s" % Puppet[:config]
Puppet.settings.parse(Puppet[:config])
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 57299b7e7..d77ec0486 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -60,12 +60,6 @@ module Puppet
this directory can be removed without causing harm (although it
might result in spurious service restarts)."
},
- :ssldir => {
- :default => "$confdir/ssl",
- :mode => 0771,
- :owner => "root",
- :desc => "Where SSL certificates are kept."
- },
:rundir => {
:default => rundir,
:mode => 01777,
@@ -148,7 +142,20 @@ module Puppet
but then ship with tools that do not know how to handle signed ints, so the UIDs show up as
huge numbers that can then not be fed back into the system. This is a hackish way to fail in a
slightly more useful way when that happens."],
- :node_terminus => ["plain", "Where to find information about nodes."]
+ :node_terminus => ["plain", "Where to find information about nodes."],
+ :httplog => { :default => "$logdir/http.log",
+ :owner => "root",
+ :mode => 0640,
+ :desc => "Where the puppetd web server logs."
+ },
+ :http_proxy_host => ["none",
+ "The HTTP proxy host to use for outgoing connections. Note: You
+ may need to use a FQDN for the server hostname when using a proxy."],
+ :http_proxy_port => [3128,
+ "The HTTP proxy port to use for outgoing connections"],
+ :http_enable_post_connection_check => [true,
+ "Boolean; wheter or not puppetd should validate the server
+ SSL certificate against the request hostname."]
)
hostname = Facter["hostname"].value
@@ -159,14 +166,21 @@ module Puppet
fqdn = hostname
end
- Puppet.setdefaults(:ssl,
+ Puppet.setdefaults(:main,
:certname => [fqdn, "The name to use when handling certificates. Defaults
to the fully qualified domain name."],
:certdnsnames => ['', "The DNS names on the Server certificate as a colon-separated list.
If it's anything other than an empty string, it will be used as an alias in the created
certificate. By default, only the server gets an alias set up, and only for 'puppet'."],
:certdir => ["$ssldir/certs", "The certificate directory."],
+ :ssldir => {
+ :default => "$confdir/ssl",
+ :mode => 0771,
+ :owner => "root",
+ :desc => "Where SSL certificates are kept."
+ },
:publickeydir => ["$ssldir/public_keys", "The public key directory."],
+ :requestdir => ["$ssldir/certificate_requests", "Where host certificate requests are stored."],
:privatekeydir => { :default => "$ssldir/private_keys",
:mode => 0750,
:desc => "The private key directory."
@@ -182,7 +196,7 @@ module Puppet
},
:hostcsr => { :default => "$ssldir/csr_$certname.pem",
:mode => 0644,
- :desc => "Where individual hosts store and look for their certificates."
+ :desc => "Where individual hosts store and look for their certificate requests."
},
:hostcert => { :default => "$certdir/$certname.pem",
:mode => 0644,
@@ -199,6 +213,11 @@ module Puppet
:localcacert => { :default => "$certdir/ca.pem",
:mode => 0644,
:desc => "Where each client stores the CA certificate."
+ },
+ :hostcrl => { :default => "$ssldir/crl.pem",
+ :mode => 0644,
+ :desc => "Where the host's certificate revocation list can be found.
+ This is distinct from the certificate authority's CRL."
}
)
@@ -230,7 +249,12 @@ module Puppet
:owner => "$user",
:group => "$group",
:mode => 0664,
- :desc => "The certificate revocation list (CRL) for the CA. Set this to 'false' if you do not want to use a CRL."
+ :desc => "The certificate revocation list (CRL) for the CA. Will be used if present but otherwise ignored.",
+ :hook => proc do |value|
+ if value == 'false'
+ Puppet.warning "Setting the :cacrl to 'false' is deprecated; Puppet will just ignore the crl if yours is missing"
+ end
+ end
},
:caprivatedir => { :default => "$cadir/private",
:owner => "$user",
@@ -258,7 +282,7 @@ module Puppet
:serial => { :default => "$cadir/serial",
:owner => "$user",
:group => "$group",
- :mode => 0600,
+ :mode => 0644,
:desc => "Where the serial number for certificates is stored."
},
:autosign => { :default => "$confdir/autosign.conf",
@@ -291,7 +315,7 @@ module Puppet
self.setdefaults(self.settings[:name],
:config => ["$confdir/puppet.conf",
"The configuration file for #{Puppet[:name]}."],
- :pidfile => ["", "The pid file"],
+ :pidfile => ["$rundir/$name.pid", "The pid file"],
:bindaddress => ["", "The address to bind to. Mongrel servers
default to 127.0.0.1 and WEBrick defaults to 0.0.0.0."],
:servertype => ["webrick", "The type of server to use. Currently supported
@@ -382,19 +406,6 @@ module Puppet
:mode => 0640,
:desc => "The log file for puppetd. This is generally not used."
},
- :httplog => { :default => "$logdir/http.log",
- :owner => "root",
- :mode => 0640,
- :desc => "Where the puppetd web server logs."
- },
- :http_proxy_host => ["none",
- "The HTTP proxy host to use for outgoing connections. Note: You
- may need to use a FQDN for the server hostname when using a proxy."],
- :http_proxy_port => [3128,
- "The HTTP proxy port to use for outgoing connections"],
- :http_enable_post_connection_check => [true,
- "Boolean; wheter or not puppetd should validate the server
- SSL certificate against the request hostname."],
:server => ["puppet",
"The server to which server puppetd should connect"],
:ignoreschedules => [false,
diff --git a/lib/puppet/file_serving/configuration.rb b/lib/puppet/file_serving/configuration.rb
index ccf0957d1..9c38aaa19 100644
--- a/lib/puppet/file_serving/configuration.rb
+++ b/lib/puppet/file_serving/configuration.rb
@@ -5,25 +5,20 @@
require 'puppet'
require 'puppet/file_serving'
require 'puppet/file_serving/mount'
+require 'puppet/util/cacher'
class Puppet::FileServing::Configuration
require 'puppet/file_serving/configuration/parser'
+ extend Puppet::Util::Cacher
+
@config_fileuration = nil
Mount = Puppet::FileServing::Mount
- # Remove our singleton instance.
- def self.clear_cache
- @config_fileuration = nil
- end
-
# Create our singleton configuration.
def self.create
- unless @config_fileuration
- @config_fileuration = new()
- end
- @config_fileuration
+ attr_cache(:configuration) { new() }
end
private_class_method :new
diff --git a/lib/puppet/file_serving/mount.rb b/lib/puppet/file_serving/mount.rb
index 8e5bd03e8..c52cedbfb 100644
--- a/lib/puppet/file_serving/mount.rb
+++ b/lib/puppet/file_serving/mount.rb
@@ -4,6 +4,7 @@
require 'puppet/network/authstore'
require 'puppet/util/logging'
+require 'puppet/util/cacher'
require 'puppet/file_serving'
require 'puppet/file_serving/metadata'
require 'puppet/file_serving/content'
@@ -12,12 +13,16 @@ require 'puppet/file_serving/content'
# or content objects.
class Puppet::FileServing::Mount < Puppet::Network::AuthStore
include Puppet::Util::Logging
+ extend Puppet::Util::Cacher
- @@localmap = nil
-
- # Clear the cache. This is only ever used for testing.
- def self.clear_cache
- @@localmap = nil
+ def self.localmap
+ attr_cache(:localmap) {
+ { "h" => Facter.value("hostname"),
+ "H" => [Facter.value("hostname"),
+ Facter.value("domain")].join("."),
+ "d" => Facter.value("domain")
+ }
+ }
end
attr_reader :name
@@ -173,14 +178,6 @@ class Puppet::FileServing::Mount < Puppet::Network::AuthStore
# Cache this manufactured map, since if it's used it's likely
# to get used a lot.
def localmap
- unless @@localmap
- @@localmap = {
- "h" => Facter.value("hostname"),
- "H" => [Facter.value("hostname"),
- Facter.value("domain")].join("."),
- "d" => Facter.value("domain")
- }
- end
- @@localmap
+ self.class.localmap
end
end
diff --git a/lib/puppet/indirector/certificate/ca.rb b/lib/puppet/indirector/certificate/ca.rb
new file mode 100644
index 000000000..b64080e16
--- /dev/null
+++ b/lib/puppet/indirector/certificate/ca.rb
@@ -0,0 +1,9 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate'
+
+class Puppet::SSL::Certificate::Ca < Puppet::Indirector::SslFile
+ desc "Manage the CA collection of signed SSL certificates on disk."
+
+ store_in :signeddir
+ store_ca_at :cacert
+end
diff --git a/lib/puppet/indirector/certificate/file.rb b/lib/puppet/indirector/certificate/file.rb
new file mode 100644
index 000000000..c19d001f4
--- /dev/null
+++ b/lib/puppet/indirector/certificate/file.rb
@@ -0,0 +1,9 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate'
+
+class Puppet::SSL::Certificate::File < Puppet::Indirector::SslFile
+ desc "Manage SSL certificates on disk."
+
+ store_in :certdir
+ store_ca_at :localcacert
+end
diff --git a/lib/puppet/indirector/certificate/rest.rb b/lib/puppet/indirector/certificate/rest.rb
new file mode 100644
index 000000000..f88d60d40
--- /dev/null
+++ b/lib/puppet/indirector/certificate/rest.rb
@@ -0,0 +1,6 @@
+require 'puppet/ssl/certificate'
+require 'puppet/indirector/rest'
+
+class Puppet::SSL::Certificate::Rest < Puppet::Indirector::REST
+ desc "Find and save certificates over HTTP via REST."
+end
diff --git a/lib/puppet/indirector/certificate_request/ca.rb b/lib/puppet/indirector/certificate_request/ca.rb
new file mode 100644
index 000000000..e90f43a03
--- /dev/null
+++ b/lib/puppet/indirector/certificate_request/ca.rb
@@ -0,0 +1,14 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_request'
+
+class Puppet::SSL::CertificateRequest::Ca < Puppet::Indirector::SslFile
+ desc "Manage the CA collection of certificate requests on disk."
+
+ store_in :csrdir
+
+ def save(request)
+ result = super
+ Puppet.notice "%s has a waiting certificate request" % request.key
+ result
+ end
+end
diff --git a/lib/puppet/indirector/certificate_request/file.rb b/lib/puppet/indirector/certificate_request/file.rb
new file mode 100644
index 000000000..274311e2c
--- /dev/null
+++ b/lib/puppet/indirector/certificate_request/file.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_request'
+
+class Puppet::SSL::CertificateRequest::File < Puppet::Indirector::SslFile
+ desc "Manage the collection of certificate requests on disk."
+
+ store_in :requestdir
+end
diff --git a/lib/puppet/indirector/certificate_request/rest.rb b/lib/puppet/indirector/certificate_request/rest.rb
new file mode 100644
index 000000000..6df014583
--- /dev/null
+++ b/lib/puppet/indirector/certificate_request/rest.rb
@@ -0,0 +1,6 @@
+require 'puppet/ssl/certificate_request'
+require 'puppet/indirector/rest'
+
+class Puppet::SSL::CertificateRequest::Rest < Puppet::Indirector::REST
+ desc "Find and save certificate requests over HTTP via REST."
+end
diff --git a/lib/puppet/indirector/certificate_revocation_list/ca.rb b/lib/puppet/indirector/certificate_revocation_list/ca.rb
new file mode 100644
index 000000000..66cc23e50
--- /dev/null
+++ b/lib/puppet/indirector/certificate_revocation_list/ca.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_revocation_list'
+
+class Puppet::SSL::CertificateRevocationList::Ca < Puppet::Indirector::SslFile
+ desc "Manage the CA collection of certificate requests on disk."
+
+ store_at :cacrl
+end
diff --git a/lib/puppet/indirector/certificate_revocation_list/file.rb b/lib/puppet/indirector/certificate_revocation_list/file.rb
new file mode 100644
index 000000000..037aa6b8c
--- /dev/null
+++ b/lib/puppet/indirector/certificate_revocation_list/file.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_revocation_list'
+
+class Puppet::SSL::CertificateRevocationList::File < Puppet::Indirector::SslFile
+ desc "Manage the global certificate revocation list."
+
+ store_at :hostcrl
+end
diff --git a/lib/puppet/indirector/certificate_revocation_list/rest.rb b/lib/puppet/indirector/certificate_revocation_list/rest.rb
new file mode 100644
index 000000000..13cc95c87
--- /dev/null
+++ b/lib/puppet/indirector/certificate_revocation_list/rest.rb
@@ -0,0 +1,6 @@
+require 'puppet/ssl/certificate_revocation_list'
+require 'puppet/indirector/rest'
+
+class Puppet::SSL::CertificateRevocationList::Rest < Puppet::Indirector::REST
+ desc "Find and save certificate revocation lists over HTTP via REST."
+end
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
index 05464f8c9..c70259304 100644
--- a/lib/puppet/indirector/indirection.rb
+++ b/lib/puppet/indirector/indirection.rb
@@ -1,20 +1,17 @@
require 'puppet/util/docs'
require 'puppet/indirector/envelope'
require 'puppet/indirector/request'
+require 'puppet/util/cacher'
# The class that connects functional classes with their different collection
# back-ends. Each indirection has a set of associated terminus classes,
# each of which is a subclass of Puppet::Indirector::Terminus.
class Puppet::Indirector::Indirection
+ include Puppet::Util::Cacher
include Puppet::Util::Docs
@@indirections = []
- # Clear all cached termini from all indirections.
- def self.clear_cache
- @@indirections.each { |ind| ind.clear_cache }
- end
-
# Find an indirection by name. This is provided so that Terminus classes
# can specifically hook up with the indirections they are associated with.
def self.instance(name)
@@ -54,13 +51,6 @@ class Puppet::Indirector::Indirection
@cache_class = class_name
end
- # Clear our cached list of termini, and reset the cache name
- # so it's looked up again.
- # This is only used for testing.
- def clear_cache
- @termini.clear
- end
-
# This is only used for testing.
def delete
@@indirections.delete(self) if @@indirections.include?(self)
@@ -104,7 +94,6 @@ class Puppet::Indirector::Indirection
@model = model
@name = name
- @termini = {}
@cache_class = nil
@terminus_class = nil
@@ -138,7 +127,7 @@ class Puppet::Indirector::Indirection
raise Puppet::DevError, "No terminus specified for %s; cannot redirect" % self.name
end
- return @termini[terminus_name] ||= make_terminus(terminus_name)
+ return termini[terminus_name] ||= make_terminus(terminus_name)
end
# This can be used to select the terminus class.
@@ -299,4 +288,9 @@ class Puppet::Indirector::Indirection
end
return klass.new
end
+
+ # Use cached termini.
+ def termini
+ attr_cache(:termini) { Hash.new }
+ end
end
diff --git a/lib/puppet/indirector/key/ca.rb b/lib/puppet/indirector/key/ca.rb
new file mode 100644
index 000000000..3604de22b
--- /dev/null
+++ b/lib/puppet/indirector/key/ca.rb
@@ -0,0 +1,20 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/key'
+
+class Puppet::SSL::Key::Ca < Puppet::Indirector::SslFile
+ desc "Manage the CA's private on disk. This terminus *only* works
+ with the CA key, because that's the only key that the CA ever interacts
+ with."
+
+ # This is just to pass the validation in the base class. Eh.
+ store_at :cakey
+
+ store_ca_at :cakey
+
+ def path(name)
+ unless ca?(name)
+ raise ArgumentError, "The :ca terminus can only handle the CA private key"
+ end
+ super
+ end
+end
diff --git a/lib/puppet/indirector/key/file.rb b/lib/puppet/indirector/key/file.rb
new file mode 100644
index 000000000..4536f8aa7
--- /dev/null
+++ b/lib/puppet/indirector/key/file.rb
@@ -0,0 +1,42 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/key'
+
+class Puppet::SSL::Key::File < Puppet::Indirector::SslFile
+ desc "Manage SSL private and public keys on disk."
+
+ store_in :privatekeydir
+ store_ca_at :cakey
+
+ # Where should we store the public key?
+ def public_key_path(name)
+ if ca?(name)
+ Puppet[:capub]
+ else
+ File.join(Puppet[:publickeydir], name.to_s + ".pem")
+ end
+ end
+
+ # Remove the public key, in addition to the private key
+ def destroy(request)
+ super
+
+ return unless FileTest.exist?(public_key_path(request.key))
+
+ begin
+ File.unlink(public_key_path(request.key))
+ rescue => detail
+ raise Puppet::Error, "Could not remove %s public key: %s" % [request.key, detail]
+ end
+ end
+
+ # Save the public key, in addition to the private key.
+ def save(request)
+ super
+
+ begin
+ File.open(public_key_path(request.key), "w") { |f| f.print request.instance.content.public_key.to_pem }
+ rescue => detail
+ raise Puppet::Error, "Could not write %s: %s" % [key, detail]
+ end
+ end
+end
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb
index d33150fc2..77dd0538b 100644
--- a/lib/puppet/indirector/rest.rb
+++ b/lib/puppet/indirector/rest.rb
@@ -3,21 +3,20 @@ require 'uri'
# Access objects via REST
class Puppet::Indirector::REST < Puppet::Indirector::Terminus
-
def rest_connection_details
{ :host => Puppet[:server], :port => Puppet[:masterport].to_i }
end
def network_fetch(path)
- network {|conn| conn.get("/#{path}").body }
+ network.get("/#{path}").body
end
def network_delete(path)
- network {|conn| conn.delete("/#{path}").body }
+ network.delete("/#{path}").body
end
def network_put(path, data)
- network {|conn| conn.put("/#{path}", data).body }
+ network.put("/#{path}", data).body
end
def find(request)
@@ -46,8 +45,8 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus
private
- def network(&block)
- Net::HTTP.start(rest_connection_details[:host], rest_connection_details[:port]) {|conn| yield(conn) }
+ def network
+ Puppet::Network::HttpPool.http_instance(rest_connection_details[:host], rest_connection_details[:port])
end
def exception?(yaml_string)
diff --git a/lib/puppet/indirector/ssl_file.rb b/lib/puppet/indirector/ssl_file.rb
new file mode 100644
index 000000000..44a66fab2
--- /dev/null
+++ b/lib/puppet/indirector/ssl_file.rb
@@ -0,0 +1,147 @@
+require 'puppet/ssl'
+
+class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
+ # Specify the directory in which multiple files are stored.
+ def self.store_in(setting)
+ @directory_setting = setting
+ end
+
+ # Specify a single file location for storing just one file.
+ # This is used for things like the CRL.
+ def self.store_at(setting)
+ @file_setting = setting
+ end
+
+ # Specify where a specific ca file should be stored.
+ def self.store_ca_at(setting)
+ @ca_setting = setting
+ end
+
+ class << self
+ attr_reader :directory_setting, :file_setting, :ca_setting
+ end
+
+ # The full path to where we should store our files.
+ def self.collection_directory
+ return nil unless directory_setting
+ Puppet.settings[directory_setting]
+ end
+
+ # The full path to an individual file we would be managing.
+ def self.file_location
+ return nil unless file_setting
+ Puppet.settings[file_setting]
+ end
+
+ # The full path to a ca file we would be managing.
+ def self.ca_location
+ return nil unless ca_setting
+ Puppet.settings[ca_setting]
+ end
+
+ # We assume that all files named 'ca' are pointing to individual ca files,
+ # rather than normal host files. It's a bit hackish, but all the other
+ # solutions seemed even more hackish.
+ def ca?(name)
+ name == Puppet::SSL::Host.ca_name
+ end
+
+ def initialize
+ Puppet.settings.use(:main, :ssl)
+
+ (collection_directory || file_location) or raise Puppet::DevError, "No file or directory setting provided; terminus %s cannot function" % self.class.name
+ end
+
+ # Use a setting to determine our path.
+ def path(name)
+ if ca?(name) and ca_location
+ ca_location
+ elsif collection_directory
+ File.join(collection_directory, name.to_s + ".pem")
+ else
+ file_location
+ end
+ end
+
+ # Remove our file.
+ def destroy(request)
+ path = path(request.key)
+ return false unless FileTest.exist?(path)
+
+ begin
+ File.unlink(path)
+ rescue => detail
+ raise Puppet::Error, "Could not remove %s: %s" % [request.key, detail]
+ end
+ end
+
+ # Find the file on disk, returning an instance of the model.
+ def find(request)
+ path = path(request.key)
+
+ return nil unless FileTest.exist?(path)
+
+ result = model.new(request.key)
+ result.read(path)
+ result
+ end
+
+ # Save our file to disk.
+ def save(request)
+ path = path(request.key)
+ dir = File.dirname(path)
+
+ raise Puppet::Error.new("Cannot save %s; parent directory %s does not exist" % [request.key, dir]) unless FileTest.directory?(dir)
+ raise Puppet::Error.new("Cannot save %s; parent directory %s is not writable" % [request.key, dir]) unless FileTest.writable?(dir)
+
+ write(request.key, path) { |f| f.print request.instance.to_s }
+ end
+
+ # Search for more than one file. At this point, it just returns
+ # an instance for every file in the directory.
+ def search(request)
+ dir = collection_directory
+ Dir.entries(dir).reject { |file| file !~ /\.pem$/ }.collect do |file|
+ name = file.sub(/\.pem$/, '')
+ result = model.new(name)
+ result.read(File.join(dir, file))
+ result
+ end
+ end
+
+ private
+
+ # Demeterish pointers to class info.
+ def collection_directory
+ self.class.collection_directory
+ end
+
+ def file_location
+ self.class.file_location
+ end
+
+ def ca_location
+ self.class.ca_location
+ end
+
+ # Yield a filehandle set up appropriately, either with our settings doing
+ # the work or opening a filehandle manually.
+ def write(name, path)
+ if ca?(name) and ca_location
+ Puppet.settings.write(self.class.ca_setting) { |f| yield f }
+ elsif file_location
+ Puppet.settings.write(self.class.file_setting) { |f| yield f }
+ else
+ begin
+ File.open(path, "w") { |f| yield f }
+ rescue => detail
+ raise Puppet::Error, "Could not write %s: %s" % [path, detail]
+ end
+ end
+ end
+end
+
+# LAK:NOTE This has to be at the end, because classes like SSL::Key use this
+# class, and this require statement loads those, which results in a load loop
+# and lots of failures.
+require 'puppet/ssl/host'
diff --git a/lib/puppet/indirector/ssl_rsa.rb b/lib/puppet/indirector/ssl_rsa.rb
deleted file mode 100644
index 162d8200a..000000000
--- a/lib/puppet/indirector/ssl_rsa.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-# This is a stub class
-
-class Puppet::Indirector::SslRsa #:nodoc:
-end
-
diff --git a/lib/puppet/indirector/ssl_rsa/file.rb b/lib/puppet/indirector/ssl_rsa/file.rb
deleted file mode 100644
index 435aa8f86..000000000
--- a/lib/puppet/indirector/ssl_rsa/file.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require 'puppet/indirector/file'
-require 'puppet/indirector/ssl_rsa'
-
-class Puppet::Indirector::SslRsa::File < Puppet::Indirector::File
- desc "Store SSL keys on disk."
-
- def initialize
- Puppet.settings.use(:ssl)
- end
-
- def path(name)
- if name == :ca
- File.join Puppet.settings[:cadir], "ca_key.pem"
- else
- File.join Puppet.settings[:publickeydir], name.to_s + ".pem"
- end
- end
-
- def save(key)
- File.open(path(key.name), "w") { |f| f.print key.to_pem }
- end
-
- def find(name)
- return nil unless FileTest.exists?(path(name))
- OpenSSL::PKey::RSA.new(File.read(path(name)))
- end
-
- def destroy(name)
- return nil unless FileTest.exists?(path(name))
- File.unlink(path(name)) and true
- end
-
-end
diff --git a/lib/puppet/metatype/container.rb b/lib/puppet/metatype/container.rb
index 2bbe3f546..dbc8a3dee 100644
--- a/lib/puppet/metatype/container.rb
+++ b/lib/puppet/metatype/container.rb
@@ -36,7 +36,6 @@ class Puppet::Type
obj.remove
end
@parameters.clear
- self.class.delete(self)
@parent = nil
diff --git a/lib/puppet/metatype/instances.rb b/lib/puppet/metatype/instances.rb
index 3f44413f8..34d542c5d 100644
--- a/lib/puppet/metatype/instances.rb
+++ b/lib/puppet/metatype/instances.rb
@@ -8,11 +8,13 @@ class Puppet::Type
# retrieve a named instance of the current type
def self.[](name)
+ raise "Global resource access is deprecated"
@objects[name] || @aliases[name]
end
# add an instance by name to the class list of instances
def self.[]=(name,object)
+ raise "Global resource storage is deprecated"
newobj = nil
if object.is_a?(Puppet::Type)
newobj = object
@@ -44,6 +46,7 @@ class Puppet::Type
# Create an alias. We keep these in a separate hash so that we don't encounter
# the objects multiple times when iterating over them.
def self.alias(name, obj)
+ raise "Global resource aliasing is deprecated"
if @objects.include?(name)
unless @objects[name] == obj
raise Puppet::Error.new(
@@ -67,6 +70,7 @@ class Puppet::Type
# remove all of the instances of a single type
def self.clear
+ raise "Global resource removal is deprecated"
if defined? @objects
@objects.each do |name, obj|
obj.remove(true)
@@ -126,24 +130,6 @@ class Puppet::Type
# XXX This will have to change when transobjects change to using titles
title = hash.name
- # if the object already exists
- if self.isomorphic? and retobj = self[title]
- # if only one of our objects is implicit, then it's easy to see
- # who wins -- the non-implicit one.
- if retobj.implicit? and ! implicit
- Puppet.notice "Removing implicit %s" % retobj.title
- # Remove all of the objects, but do not remove their subscriptions.
- retobj.remove(false)
-
- # now pass through and create the new object
- elsif implicit
- Puppet.debug "Ignoring implicit %s[%s]" % [self.name, title]
- return nil
- else
- raise Puppet::Error, "%s is already being managed" % retobj.ref
- end
- end
-
# create it anew
# if there's a failure, destroy the object if it got that far, but raise
# the error.
@@ -153,8 +139,6 @@ class Puppet::Type
Puppet.err "Could not create %s: %s" % [title, detail.to_s]
if obj
obj.remove(true)
- elsif obj = self[title]
- obj.remove(true)
end
raise
end
@@ -163,14 +147,12 @@ class Puppet::Type
obj.implicit = true
end
- # Store the object by title
- self[obj.title] = obj
-
return obj
end
# remove a specified object
def self.delete(resource)
+ raise "Global resource removal is deprecated"
return unless defined? @objects
if @objects.include?(resource.title)
@objects.delete(resource.title)
@@ -191,6 +173,7 @@ class Puppet::Type
# iterate across each of the type's instances
def self.each
+ raise "Global resource iteration is deprecated"
return unless defined? @objects
@objects.each { |name,instance|
yield instance
@@ -199,6 +182,7 @@ class Puppet::Type
# does the type have an object with the given name?
def self.has_key?(name)
+ raise "Global resource access is deprecated"
return @objects.has_key?(name)
end
@@ -258,10 +242,6 @@ class Puppet::Type
provider_instances = {}
providers_by_source.collect do |provider|
provider.instances.collect do |instance|
- # First try to get the resource if it already exists
- # Skip instances that map to a managed resource with a different provider
- next if resource = self[instance.name] and resource.provider.class != instance.class
-
# We always want to use the "first" provider instance we find, unless the resource
# is already managed and has a different provider set
if other = provider_instances[instance.name]
@@ -271,12 +251,7 @@ class Puppet::Type
end
provider_instances[instance.name] = instance
- if resource
- resource.provider = instance
- resource
- else
- create(:name => instance.name, :provider => instance, :check => :all)
- end
+ create(:name => instance.name, :provider => instance, :check => :all)
end
end.flatten.compact
end
diff --git a/lib/puppet/metatype/metaparams.rb b/lib/puppet/metatype/metaparams.rb
index edd594114..bf64d3a93 100644
--- a/lib/puppet/metatype/metaparams.rb
+++ b/lib/puppet/metatype/metaparams.rb
@@ -207,9 +207,6 @@ class Puppet::Type
next
end
- # LAK:FIXME Old-school, add the alias to the class.
- @resource.class.alias(other, @resource)
-
# Newschool, add it to the catalog.
@resource.catalog.alias(@resource, other)
end
@@ -277,6 +274,7 @@ class Puppet::Type
# to an object...
tname, name = value
reference = Puppet::ResourceReference.new(tname, name)
+ reference.catalog = resource.catalog
# Either of the two retrieval attempts could have returned
# nil.
diff --git a/lib/puppet/metatype/relationships.rb b/lib/puppet/metatype/relationships.rb
index 4fb78ae56..0070c6efb 100644
--- a/lib/puppet/metatype/relationships.rb
+++ b/lib/puppet/metatype/relationships.rb
@@ -17,7 +17,10 @@ class Puppet::Type
# Figure out of there are any objects we can automatically add as
# dependencies.
- def autorequire
+ def autorequire(rel_catalog = nil)
+ rel_catalog ||= catalog
+ raise(Puppet::DevError, "You cannot add relationships without a catalog") unless rel_catalog
+
reqs = []
self.class.eachautorequire { |type, block|
# Ignore any types we can't find, although that would be a bit odd.
@@ -35,7 +38,7 @@ class Puppet::Type
# Support them passing objects directly, to save some effort.
unless dep.is_a? Puppet::Type
# Skip autorequires that we aren't managing
- unless dep = typeobj[dep]
+ unless dep = rel_catalog.resource(type, dep)
next
end
end
diff --git a/lib/puppet/metatype/schedules.rb b/lib/puppet/metatype/schedules.rb
index 96ebce0ab..b4782f852 100644
--- a/lib/puppet/metatype/schedules.rb
+++ b/lib/puppet/metatype/schedules.rb
@@ -3,9 +3,13 @@ class Puppet::Type
# the instantiation phase, so that the schedule can be anywhere in the
# file.
def schedule
+ unless catalog
+ warning "Cannot schedule without a schedule-containing catalog"
+ return nil
+ end
unless defined? @schedule
if name = self[:schedule]
- if sched = Puppet.type(:schedule)[name]
+ if sched = catalog.resource(:schedule, name)
@schedule = sched
else
self.fail "Could not find schedule %s" % name
diff --git a/lib/puppet/network/client/ca.rb b/lib/puppet/network/client/ca.rb
index a2704e451..5fbdfe9e3 100644
--- a/lib/puppet/network/client/ca.rb
+++ b/lib/puppet/network/client/ca.rb
@@ -45,7 +45,7 @@ class Puppet::Network::Client::CA < Puppet::Network::Client
end
unless @cert.check_private_key(key)
- raise InvalidCertificate, "Certificate does not match private key. Try 'puppetca --clean %s' on the server." % Facter.value(:fqdn)
+ raise InvalidCertificate, "Certificate does not match private key. Try 'puppetca --clean %s' on the server." % Puppet[:certname]
end
# Only write the cert out if it passes validating.
diff --git a/lib/puppet/network/client/master.rb b/lib/puppet/network/client/master.rb
index 22bb3fa4e..a2b6499bb 100644
--- a/lib/puppet/network/client/master.rb
+++ b/lib/puppet/network/client/master.rb
@@ -75,7 +75,6 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
def clear
@catalog.clear(true) if @catalog
- Puppet::Type.allclear
@catalog = nil
end
diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb
index 3e62cdbd9..183979429 100755
--- a/lib/puppet/network/handler/fileserver.rb
+++ b/lib/puppet/network/handler/fileserver.rb
@@ -496,12 +496,14 @@ class Puppet::Network::Handler
@path = nil
end
+ @files = {}
+
super()
end
def fileobj(path, links, client)
obj = nil
- if obj = Puppet.type(:file)[file_path(path, client)]
+ if obj = @files[file_path(path, client)]
# This can only happen in local fileserving, but it's an
# important one. It'd be nice if we didn't just set
# the check params every time, but I'm not sure it's worth
@@ -512,6 +514,7 @@ class Puppet::Network::Handler
:name => file_path(path, client),
:check => CHECKPARAMS
)
+ @files[file_path(path, client)] = obj
end
if links == :manage
@@ -528,7 +531,7 @@ class Puppet::Network::Handler
# Read the contents of the file at the relative path given.
def read_file(relpath, client)
- File.read(file_path(relpath, client))
+ File.read(file_path(relpath, client))
end
# Cache this manufactured map, since if it's used it's likely
diff --git a/lib/puppet/network/handler/resource.rb b/lib/puppet/network/handler/resource.rb
index f2a339751..7ec27b4dc 100755
--- a/lib/puppet/network/handler/resource.rb
+++ b/lib/puppet/network/handler/resource.rb
@@ -68,15 +68,11 @@ class Puppet::Network::Handler
retrieve ||= :all
ignore ||= []
- if obj = typeklass[name]
- obj[:check] = retrieve
- else
- begin
- obj = typeklass.create(:name => name, :check => retrieve)
- rescue Puppet::Error => detail
- raise Puppet::Error, "%s[%s] could not be created: %s" %
- [type, name, detail]
- end
+ begin
+ obj = typeklass.create(:name => name, :check => retrieve)
+ rescue Puppet::Error => detail
+ raise Puppet::Error, "%s[%s] could not be created: %s" %
+ [type, name, detail]
end
unless obj
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb
index 7113c92d3..c05d4907f 100644
--- a/lib/puppet/network/http/handler.rb
+++ b/lib/puppet/network/http/handler.rb
@@ -20,7 +20,7 @@ module Puppet::Network::HTTP::Handler
private
def model
- @model
+ @model
end
def do_find(request, response)
@@ -53,7 +53,7 @@ module Puppet::Network::HTTP::Handler
end
def save_object(obj)
- obj.save
+ obj.save
end
def do_exception(request, response, exception, status=404)
@@ -85,8 +85,7 @@ module Puppet::Network::HTTP::Handler
%r{/#{@handler.to_s}s$}.match(path(request))
end
- # methods to be overridden by the including web server class
-
+ # methods to be overridden by the including web server class
def register_handler
raise NotImplementedError
end
diff --git a/lib/puppet/network/http/mongrel.rb b/lib/puppet/network/http/mongrel.rb
index 9a4531c7a..847781cf2 100644
--- a/lib/puppet/network/http/mongrel.rb
+++ b/lib/puppet/network/http/mongrel.rb
@@ -16,6 +16,7 @@ class Puppet::Network::HTTP::Mongrel
@protocols = args[:protocols]
@handlers = args[:handlers]
+ @xmlrpc_handlers = args[:xmlrpc_handlers]
@server = Mongrel::HttpServer.new(args[:address], args[:port])
setup_handlers
@@ -38,12 +39,22 @@ class Puppet::Network::HTTP::Mongrel
def setup_handlers
@protocols.each do |protocol|
+ next if protocol == :xmlrpc
klass = class_for_protocol(protocol)
@handlers.each do |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
+
+ if @protocols.include?(:xmlrpc) and ! @xmlrpc_handlers.empty?
+ setup_xmlrpc_handlers
+ end
+ end
+
+ # Use our existing code to provide the xmlrpc backward compatibility.
+ def setup_xmlrpc_handlers
+ @server.register('/RPC2', Puppet::Network::HTTPServer::Mongrel.new(@xmlrpc_handlers))
end
def class_for_protocol(protocol)
diff --git a/lib/puppet/network/http/mongrel/rest.rb b/lib/puppet/network/http/mongrel/rest.rb
index 2a3d4f143..a471a62bf 100644
--- a/lib/puppet/network/http/mongrel/rest.rb
+++ b/lib/puppet/network/http/mongrel/rest.rb
@@ -2,12 +2,12 @@ require 'puppet/network/http/handler'
class Puppet::Network::HTTP::MongrelREST < Mongrel::HttpHandler
- include Puppet::Network::HTTP::Handler
+ include Puppet::Network::HTTP::Handler
- def initialize(args={})
- super()
- initialize_for_puppet(args)
- end
+ def initialize(args={})
+ super()
+ initialize_for_puppet(args)
+ end
private
diff --git a/lib/puppet/network/http/webrick.rb b/lib/puppet/network/http/webrick.rb
index 3a37e2071..eacf81ec2 100644
--- a/lib/puppet/network/http/webrick.rb
+++ b/lib/puppet/network/http/webrick.rb
@@ -1,8 +1,12 @@
require 'webrick'
require 'webrick/https'
require 'puppet/network/http/webrick/rest'
+require 'puppet/network/xmlrpc/webrick_servlet'
require 'thread'
+require 'puppet/ssl/certificate'
+require 'puppet/ssl/certificate_revocation_list'
+
class Puppet::Network::HTTP::WEBrick
def initialize(args = {})
@listening = false
@@ -22,7 +26,14 @@ class Puppet::Network::HTTP::WEBrick
@protocols = args[:protocols]
@handlers = args[:handlers]
- @server = WEBrick::HTTPServer.new(:BindAddress => args[:address], :Port => args[:port])
+ @xmlrpc_handlers = args[:xmlrpc_handlers]
+
+ arguments = {:BindAddress => args[:address], :Port => args[:port]}
+ arguments.merge!(setup_logger)
+ arguments.merge!(setup_ssl)
+
+ @server = WEBrick::HTTPServer.new(arguments)
+
setup_handlers
@mutex.synchronize do
@@ -48,15 +59,86 @@ class Puppet::Network::HTTP::WEBrick
end
end
+ # Configure our http log file.
+ def setup_logger
+ # Make sure the settings are all ready for us.
+ Puppet.settings.use(:main, :ssl, Puppet[:name])
+
+ if Puppet[:name] == "puppetmasterd"
+ file = Puppet[:masterhttplog]
+ else
+ file = Puppet[:httplog]
+ end
+
+ # open the log manually to prevent file descriptor leak
+ file_io = ::File.open(file, "a+")
+ file_io.sync
+ file_io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+
+ args = [file_io]
+ args << WEBrick::Log::DEBUG if Puppet::Util::Log.level == :debug
+
+ logger = WEBrick::Log.new(*args)
+ return :Logger => logger, :AccessLog => [
+ [logger, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
+ [logger, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
+ ]
+ end
+
+ # Add all of the ssl cert information.
+ def setup_ssl
+ results = {}
+
+ host = Puppet::SSL::Host.new
+
+ host.generate unless host.certificate
+
+ raise Puppet::Error, "Could not retrieve certificate for %s and not running on a valid certificate authority" % host.name unless host.certificate
+
+ results[:SSLPrivateKey] = host.key.content
+ results[:SSLCertificate] = host.certificate.content
+ results[:SSLStartImmediately] = true
+ results[:SSLEnable] = true
+
+ unless Puppet::SSL::Certificate.find("ca")
+ raise Puppet::Error, "Could not find CA certificate"
+ end
+
+ results[:SSLCACertificateFile] = Puppet[:localcacert]
+ results[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
+
+ results[:SSLCertificateStore] = host.ssl_store
+
+ results
+ end
+
private
def setup_handlers
+ # Set up the new-style protocols.
@protocols.each do |protocol|
+ next if protocol == :xmlrpc
klass = self.class.class_for_protocol(protocol)
@handlers.each do |handler|
@server.mount('/' + handler.to_s, klass, handler)
@server.mount('/' + handler.to_s + 's', klass, handler)
end
end
+
+ # And then set up xmlrpc, if configured.
+ if @protocols.include?(:xmlrpc) and ! @xmlrpc_handlers.empty?
+ @server.mount("/RPC2", xmlrpc_servlet)
+ end
+ end
+
+ # Create our xmlrpc servlet, which provides backward compatibility.
+ def xmlrpc_servlet
+ handlers = @xmlrpc_handlers.collect { |handler|
+ unless hclass = Puppet::Network::Handler.handler(handler)
+ raise "Invalid xmlrpc handler %s" % handler
+ end
+ hclass.new({})
+ }
+ Puppet::Network::XMLRPC::WEBrickServlet.new handlers
end
end
diff --git a/lib/puppet/network/http_pool.rb b/lib/puppet/network/http_pool.rb
index 1227f78dc..78a35cc15 100644
--- a/lib/puppet/network/http_pool.rb
+++ b/lib/puppet/network/http_pool.rb
@@ -1,11 +1,13 @@
-require 'puppet/sslcertificates/support'
+require 'puppet/ssl/host'
require 'net/https'
+require 'puppet/util/cacher'
-module Puppet::Network
-end
+module Puppet::Network; end
# Manage Net::HTTP instances for keep-alive.
module Puppet::Network::HttpPool
+ extend Puppet::Util::Cacher
+
# 2008/03/23
# LAK:WARNING: Enabling this has a high propability of
# causing corrupt files and who knows what else. See #1010.
@@ -15,18 +17,18 @@ module Puppet::Network::HttpPool
HTTP_KEEP_ALIVE
end
- # This handles reading in the key and such-like.
- extend Puppet::SSLCertificates::Support
- @http_cache = {}
+ # Create an ssl host instance for getting certificate
+ # information.
+ def self.ssl_host
+ attr_cache(:ssl_host) { Puppet::SSL::Host.new }
+ end
# Clear our http cache, closing all connections.
def self.clear_http_instances
- @http_cache.each do |name, connection|
+ http_cache.each do |name, connection|
connection.finish if connection.started?
end
- @http_cache.clear
- @cert = nil
- @key = nil
+ Puppet::Util::Cacher.invalidate
end
# Make sure we set the driver up when we read the cert in.
@@ -44,17 +46,13 @@ module Puppet::Network::HttpPool
# Use cert information from a Puppet client to set up the http object.
def self.cert_setup(http)
# Just no-op if we don't have certs.
- return false unless (defined?(@cert) and @cert) or self.read_cert
+ return false unless FileTest.exist?(Puppet[:hostcert]) # ssl_host.certificate
- store = OpenSSL::X509::Store.new
- store.add_file Puppet[:localcacert]
- store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
-
- http.cert_store = store
+ http.cert_store = ssl_host.ssl_store
http.ca_file = Puppet[:localcacert]
- http.cert = self.cert
+ http.cert = ssl_host.certificate.content
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
- http.key = self.key
+ http.key = ssl_host.key.content
end
# Retrieve a cached http instance of caching is enabled, else return
@@ -66,11 +64,11 @@ module Puppet::Network::HttpPool
# Return our cached instance if we've got a cache, as long as we're not
# resetting the instance.
if keep_alive?
- return @http_cache[key] if ! reset and @http_cache[key]
+ return http_cache[key] if ! reset and http_cache[key]
# Clean up old connections if we have them.
- if http = @http_cache[key]
- @http_cache.delete(key)
+ if http = http_cache[key]
+ http_cache.delete(key)
http.finish if http.started?
end
end
@@ -100,8 +98,15 @@ module Puppet::Network::HttpPool
cert_setup(http)
- @http_cache[key] = http if keep_alive?
+ http_cache[key] = http if keep_alive?
return http
end
+
+ private
+
+ def self.http_cache
+ # Default to an empty hash.
+ attr_cache(:http) { Hash.new }
+ end
end
diff --git a/lib/puppet/network/http_server/mongrel.rb b/lib/puppet/network/http_server/mongrel.rb
index 6b2325d29..e9421c781 100644
--- a/lib/puppet/network/http_server/mongrel.rb
+++ b/lib/puppet/network/http_server/mongrel.rb
@@ -64,11 +64,11 @@ module Puppet::Network
# behaviour and we have to subclass Mongrel::HttpHandler so our handler
# works for Mongrel.
@xmlrpc_server = Puppet::Network::XMLRPCServer.new
- handlers.each do |name, args|
+ handlers.each do |name|
unless handler = Puppet::Network::Handler.handler(name)
raise ArgumentError, "Invalid handler %s" % name
end
- @xmlrpc_server.add_handler(handler.interface, handler.new(args))
+ @xmlrpc_server.add_handler(handler.interface, handler.new({}))
end
end
diff --git a/lib/puppet/network/server.rb b/lib/puppet/network/server.rb
index cab14519b..de32db02f 100644
--- a/lib/puppet/network/server.rb
+++ b/lib/puppet/network/server.rb
@@ -1,59 +1,153 @@
require 'puppet/network/http'
+require 'puppet/util/pidlock'
class Puppet::Network::Server
- attr_reader :server_type, :protocols, :address, :port
+ attr_reader :server_type, :protocols, :address, :port
+
+ # Put the daemon into the background.
+ def daemonize
+ if pid = fork()
+ Process.detach(pid)
+ exit(0)
+ end
+
+ # Get rid of console logging
+ Puppet::Util::Log.close(:console)
+
+ Process.setsid
+ Dir.chdir("/")
+ begin
+ $stdin.reopen "/dev/null"
+ $stdout.reopen "/dev/null", "a"
+ $stderr.reopen $stdout
+ Puppet::Util::Log.reopen
+ rescue => detail
+ File.open("/tmp/daemonout", "w") { |f|
+ f.puts "Could not start %s: %s" % [Puppet[:name], detail]
+ }
+ raise "Could not start %s: %s" % [Puppet[:name], detail]
+ end
+ end
+
+ # Create a pidfile for our daemon, so we can be stopped and others
+ # don't try to start.
+ def create_pidfile
+ Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
+ unless Puppet::Util::Pidlock.new(pidfile).lock
+ raise "Could not create PID file: %s" % [pidfile]
+ end
+ end
+ end
+
+ # Remove the pid file for our daemon.
+ def remove_pidfile
+ Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
+ locker = Puppet::Util::Pidlock.new(pidfile)
+ if locker.locked?
+ locker.unlock or Puppet.err "Could not remove PID file %s" % [pidfile]
+ end
+ end
+ end
+
+ # Provide the path to our pidfile.
+ def pidfile
+ Puppet[:pidfile]
+ end
def initialize(args = {})
@server_type = Puppet[:servertype] or raise "No servertype configuration found." # e.g., WEBrick, Mongrel, etc.
http_server_class || raise(ArgumentError, "Could not determine HTTP Server class for server type [#{@server_type}]")
- @address = args[:address] || Puppet[:bindaddress] ||
- raise(ArgumentError, "Must specify :address or configure Puppet :bindaddress.")
- @port = args[:port] || Puppet[:masterport] ||
- raise(ArgumentError, "Must specify :port or configure Puppet :masterport")
- @protocols = [ :rest ]
+
+ @address = args[:address] || Puppet[:bindaddress] || raise(ArgumentError, "Must specify :address or configure Puppet :bindaddress.")
+ @port = args[:port] || Puppet[:masterport] || raise(ArgumentError, "Must specify :port or configure Puppet :masterport")
+
+ @protocols = [ :rest, :xmlrpc ]
@listening = false
@routes = {}
+ @xmlrpc_routes = {}
self.register(args[:handlers]) if args[:handlers]
+ self.register_xmlrpc(args[:xmlrpc_handlers]) if args[:xmlrpc_handlers]
+
+ # Make sure we have all of the directories we need to function.
+ Puppet.settings.use(:main, :ssl, Puppet[:name])
end
+ # Register handlers for REST networking, based on the Indirector.
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 do |name|
+ Puppet::Indirector::Indirection.model(name) || raise(ArgumentError, "Cannot locate indirection '#{name}'.")
+ @routes[name.to_sym] = true
+ end
end
+ # Unregister Indirector handlers.
def unregister(*indirections)
- raise "Cannot unregister indirections while server is listening." if listening?
- indirections = @routes.keys if indirections.empty?
+ 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
+ end
+
+ # Register xmlrpc handlers for backward compatibility.
+ def register_xmlrpc(*namespaces)
+ raise ArgumentError, "XMLRPC namespaces are required." if namespaces.empty?
+ namespaces.flatten.each do |name|
+ Puppet::Network::Handler.handler(name) || raise(ArgumentError, "Cannot locate XMLRPC handler for namespace '#{name}'.")
+ @xmlrpc_routes[name.to_sym] = true
+ end
+ end
+
+ # Unregister xmlrpc handlers.
+ def unregister_xmlrpc(*namespaces)
+ raise "Cannot unregister xmlrpc handlers while server is listening." if listening?
+ namespaces = @xmlrpc_routes.keys if namespaces.empty?
- indirections.flatten.each do |i|
- raise(ArgumentError, "Indirection [%s] is unknown." % i) unless @routes[i.to_sym]
- end
+ namespaces.flatten.each do |i|
+ raise(ArgumentError, "XMLRPC handler '%s' is unknown." % i) unless @xmlrpc_routes[i.to_sym]
+ end
- indirections.flatten.each do |i|
- @routes.delete(i.to_sym)
- end
+ namespaces.flatten.each do |i|
+ @xmlrpc_routes.delete(i.to_sym)
+ end
end
def listening?
- @listening
+ @listening
end
def listen
- raise "Cannot listen -- already listening." if listening?
- @listening = true
- http_server.listen(:address => address, :port => port, :handlers => @routes.keys, :protocols => protocols)
+ raise "Cannot listen -- already listening." if listening?
+ @listening = true
+ http_server.listen(:address => address, :port => port, :handlers => @routes.keys, :xmlrpc_handlers => @xmlrpc_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
http_server_class_by_type(@server_type)
end
+ def start
+ create_pidfile
+ listen
+ end
+
+ def stop
+ unlisten
+ remove_pidfile
+ end
+
private
def http_server
diff --git a/lib/puppet/network/xmlrpc/client.rb b/lib/puppet/network/xmlrpc/client.rb
index e0fb5a0ab..dfd4a95a7 100644
--- a/lib/puppet/network/xmlrpc/client.rb
+++ b/lib/puppet/network/xmlrpc/client.rb
@@ -51,7 +51,8 @@ module Puppet::Network
end
["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
if detail.message.include?(str)
- Puppet.warning "Certificate validation failed; considering using the certname configuration option"
+ Puppet.warning "Certificate validation failed; consider using the certname configuration option"
+ break
end
end
raise XMLRPCClientError,
diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb
index c0628ecdc..252ab961e 100644
--- a/lib/puppet/node.rb
+++ b/lib/puppet/node.rb
@@ -161,5 +161,7 @@ class Puppet::Node
params.each do |name, value|
@parameters[name] = value unless @parameters.include?(name)
end
+
+ @parameters["environment"] ||= self.environment if self.environment
end
end
diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb
index ecda472be..c5e32a032 100644
--- a/lib/puppet/node/catalog.rb
+++ b/lib/puppet/node/catalog.rb
@@ -61,7 +61,7 @@ class Puppet::Node::Catalog < Puppet::PGraph
def add_resource(*resources)
resources.each do |resource|
unless resource.respond_to?(:ref)
- raise ArgumentError, "Can only add objects that respond to :ref"
+ raise ArgumentError, "Can only add objects that respond to :ref, not instances of %s" % resource.class
end
fail_unless_unique(resource)
@@ -309,7 +309,7 @@ class Puppet::Node::Catalog < Puppet::PGraph
# And filebuckets
if bucket = Puppet::Type.type(:filebucket).mkdefaultbucket
- add_resource(bucket)
+ add_resource(bucket) unless resource(bucket.ref)
end
end
@@ -337,7 +337,7 @@ class Puppet::Node::Catalog < Puppet::PGraph
# Lastly, add in any autorequires
@relationship_graph.vertices.each do |vertex|
- vertex.autorequire.each do |edge|
+ vertex.autorequire(self).each do |edge|
unless @relationship_graph.edge?(edge.source, edge.target) # don't let automatic relationships conflict with manual ones.
unless @relationship_graph.edge?(edge.target, edge.source)
vertex.debug "Autorequiring %s" % [edge.source]
diff --git a/lib/puppet/resource_reference.rb b/lib/puppet/resource_reference.rb
index 44b518816..12b9f54a9 100644
--- a/lib/puppet/resource_reference.rb
+++ b/lib/puppet/resource_reference.rb
@@ -22,15 +22,8 @@ class Puppet::ResourceReference
# Find our resource.
def resolve
- if catalog
- return catalog.resource(to_s)
- end
- # If it's builtin, then just ask for it directly from the type.
- if t = builtin_type
- t[@title]
- else # Else, look for a component with the full reference as the name.
- Puppet::Type::Component[to_s]
- end
+ return catalog.resource(to_s) if catalog
+ return nil
end
# If the title has square brackets, treat it like a reference and
diff --git a/lib/puppet/ssl.rb b/lib/puppet/ssl.rb
new file mode 100644
index 000000000..68c65ca80
--- /dev/null
+++ b/lib/puppet/ssl.rb
@@ -0,0 +1,6 @@
+# Just to make the constants work out.
+require 'puppet'
+require 'openssl'
+
+module Puppet::SSL # :nodoc:
+end
diff --git a/lib/puppet/ssl/base.rb b/lib/puppet/ssl/base.rb
new file mode 100644
index 000000000..80bfcae84
--- /dev/null
+++ b/lib/puppet/ssl/base.rb
@@ -0,0 +1,51 @@
+require 'puppet/ssl'
+
+# The base class for wrapping SSL instances.
+class Puppet::SSL::Base
+ def self.wraps(klass)
+ @wrapped_class = klass
+ end
+
+ def self.wrapped_class
+ raise(Puppet::DevError, "%s has not declared what class it wraps" % self) unless defined?(@wrapped_class)
+ @wrapped_class
+ end
+
+ attr_accessor :name, :content
+
+ # Is this file for the CA?
+ def ca?
+ name == Puppet::SSL::Host.ca_name
+ end
+
+ def generate
+ raise Puppet::DevError, "%s did not override 'generate'" % self.class
+ end
+
+ def initialize(name)
+ @name = name
+ end
+
+ # Read content from disk appropriately.
+ def read(path)
+ @content = wrapped_class.new(File.read(path))
+ end
+
+ # Convert our thing to pem.
+ def to_s
+ return "" unless content
+ content.to_pem
+ end
+
+ # Provide the full text of the thing we're dealing with.
+ def to_text
+ return "" unless content
+ content.to_text
+ end
+
+ private
+
+ def wrapped_class
+ self.class.wrapped_class
+ end
+end
diff --git a/lib/puppet/ssl/certificate.rb b/lib/puppet/ssl/certificate.rb
new file mode 100644
index 000000000..16af85d06
--- /dev/null
+++ b/lib/puppet/ssl/certificate.rb
@@ -0,0 +1,19 @@
+require 'puppet/ssl/base'
+
+# Manage certificates themselves. This class has no
+# 'generate' method because the CA is responsible
+# for turning CSRs into certificates; we can only
+# retrieve them from the CA (or not, as is often
+# the case).
+class Puppet::SSL::Certificate < Puppet::SSL::Base
+ # This is defined from the base class
+ wraps OpenSSL::X509::Certificate
+
+ extend Puppet::Indirector
+ indirects :certificate, :terminus_class => :file
+
+ def expiration
+ return nil unless content
+ return content.not_after
+ end
+end
diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb
new file mode 100644
index 000000000..6947af11c
--- /dev/null
+++ b/lib/puppet/ssl/certificate_authority.rb
@@ -0,0 +1,285 @@
+require 'puppet/ssl/host'
+require 'puppet/ssl/certificate_request'
+require 'puppet/util/cacher'
+
+# The class that knows how to sign certificates. It creates
+# a 'special' SSL::Host whose name is 'ca', thus indicating
+# that, well, it's the CA. There's some magic in the
+# indirector/ssl_file terminus base class that does that
+# for us.
+# This class mostly just signs certs for us, but
+# it can also be seen as a general interface into all of the
+# SSL stuff.
+class Puppet::SSL::CertificateAuthority
+ require 'puppet/ssl/certificate_factory'
+ require 'puppet/ssl/inventory'
+ require 'puppet/ssl/certificate_revocation_list'
+
+ require 'puppet/ssl/certificate_authority/interface'
+
+ extend Puppet::Util::Cacher
+
+ def self.ca?
+ return false unless Puppet[:ca]
+ return false unless Puppet[:name] == "puppetmasterd"
+ return true
+ end
+
+ # If this process can function as a CA, then return a singleton
+ # instance.
+ def self.instance
+ return nil unless ca?
+
+ attr_cache(:instance) { new }
+ end
+
+ attr_reader :name, :host
+
+ # Create and run an applicator. I wanted to build an interface where you could do
+ # something like 'ca.apply(:generate).to(:all) but I don't think it's really possible.
+ def apply(method, options)
+ unless options[:to]
+ raise ArgumentError, "You must specify the hosts to apply to; valid values are an array or the symbol :all"
+ end
+ applier = Interface.new(method, options[:to])
+
+ applier.apply(self)
+ end
+
+ # If autosign is configured, then autosign all CSRs that match our configuration.
+ def autosign
+ return unless auto = autosign?
+
+ store = nil
+ if auto != true
+ store = autosign_store(auto)
+ end
+
+ Puppet::SSL::CertificateRequest.search("*").each do |csr|
+ sign(csr.name) if auto == true or store.allowed?(csr.name, "127.1.1.1")
+ end
+ end
+
+ # Do we autosign? This returns true, false, or a filename.
+ def autosign?
+ auto = Puppet[:autosign]
+ return false if ['false', false].include?(auto)
+ return true if ['true', true].include?(auto)
+
+ raise ArgumentError, "The autosign configuration '%s' must be a fully qualified file" % auto unless auto =~ /^\//
+ if FileTest.exist?(auto)
+ return auto
+ else
+ return false
+ end
+ end
+
+ # Create an AuthStore for autosigning.
+ def autosign_store(file)
+ auth = Puppet::Network::AuthStore.new
+ File.readlines(file).each do |line|
+ next if line =~ /^\s*#/
+ next if line =~ /^\s*$/
+ auth.allow(line.chomp)
+ end
+
+ auth
+ end
+
+ # Retrieve (or create, if necessary) the certificate revocation list.
+ def crl
+ unless defined?(@crl)
+ unless @crl = Puppet::SSL::CertificateRevocationList.find("ca")
+ @crl = Puppet::SSL::CertificateRevocationList.new("ca")
+ @crl.generate(host.certificate.content, host.key.content)
+ @crl.save
+ end
+ end
+ @crl
+ end
+
+ # Delegate this to our Host class.
+ def destroy(name)
+ Puppet::SSL::Host.destroy(name)
+ end
+
+ # Generate a new certificate.
+ def generate(name)
+ raise ArgumentError, "A Certificate already exists for %s" % name if Puppet::SSL::Certificate.find(name)
+ host = Puppet::SSL::Host.new(name)
+
+ host.generate_certificate_request
+
+ sign(name)
+ end
+
+ # Generate our CA certificate.
+ def generate_ca_certificate
+ generate_password unless password?
+
+ host.generate_key unless host.key
+
+ # Create a new cert request. We do this
+ # specially, because we don't want to actually
+ # save the request anywhere.
+ request = Puppet::SSL::CertificateRequest.new(host.name)
+ request.generate(host.key)
+
+ # Create a self-signed certificate.
+ @certificate = sign(host.name, :ca, request)
+
+ # And make sure we initialize our CRL.
+ crl()
+ end
+
+ def initialize
+ Puppet.settings.use :main, :ssl, :ca
+
+ @name = Puppet[:certname]
+
+ @host = Puppet::SSL::Host.new(Puppet::SSL::Host.ca_name)
+
+ setup()
+ end
+
+ # Retrieve (or create, if necessary) our inventory manager.
+ def inventory
+ unless defined?(@inventory)
+ @inventory = Puppet::SSL::Inventory.new
+ end
+ @inventory
+ end
+
+ # Generate a new password for the CA.
+ def generate_password
+ pass = ""
+ 20.times { pass += (rand(74) + 48).chr }
+
+ begin
+ Puppet.settings.write(:capass) { |f| f.print pass }
+ rescue Errno::EACCES => detail
+ raise Puppet::Error, "Could not write CA password: %s" % detail.to_s
+ end
+
+ @password = pass
+
+ return pass
+ end
+
+ # List all signed certificates.
+ def list
+ Puppet::SSL::Certificate.search("*").collect { |c| c.name }
+ end
+
+ # Read the next serial from the serial file, and increment the
+ # file so this one is considered used.
+ def next_serial
+ serial = nil
+
+ # This is slightly odd. If the file doesn't exist, our readwritelock creates
+ # it, but with a mode we can't actually read in some cases. So, use
+ # a default before the lock.
+ unless FileTest.exist?(Puppet[:serial])
+ serial = 0x0
+ end
+
+ Puppet.settings.readwritelock(:serial) { |f|
+ if FileTest.exist?(Puppet[:serial])
+ serial ||= File.read(Puppet.settings[:serial]).chomp.hex
+ end
+
+ # We store the next valid serial, not the one we just used.
+ f << "%04X" % (serial + 1)
+ }
+
+ return serial
+ end
+
+ # Does the password file exist?
+ def password?
+ FileTest.exist? Puppet[:capass]
+ end
+
+ # Print a given host's certificate as text.
+ def print(name)
+ if cert = Puppet::SSL::Certificate.find(name)
+ return cert.to_text
+ else
+ return nil
+ end
+ end
+
+ # Revoke a given certificate.
+ def revoke(name)
+ raise ArgumentError, "Cannot revoke certificates when the CRL is disabled" unless crl
+
+ if cert = Puppet::SSL::Certificate.find(name)
+ serial = cert.content.serial
+ elsif ! serial = inventory.serial(name)
+ raise ArgumentError, "Could not find a serial number for %s" % name
+ end
+ crl.revoke(serial, host.key.content)
+ end
+
+ # This initializes our CA so it actually works. This should be a private
+ # method, except that you can't any-instance stub private methods, which is
+ # *awesome*. This method only really exists to provide a stub-point during
+ # testing.
+ def setup
+ generate_ca_certificate unless @host.certificate
+ end
+
+ # Sign a given certificate request.
+ def sign(hostname, cert_type = :server, self_signing_csr = nil)
+ # This is a self-signed certificate
+ if self_signing_csr
+ csr = self_signing_csr
+ issuer = csr.content
+ else
+ unless csr = Puppet::SSL::CertificateRequest.find(hostname)
+ raise ArgumentError, "Could not find certificate request for %s" % hostname
+ end
+ issuer = host.certificate.content
+ end
+
+ cert = Puppet::SSL::Certificate.new(hostname)
+ cert.content = Puppet::SSL::CertificateFactory.new(cert_type, csr.content, issuer, next_serial).result
+ cert.content.sign(host.key.content, OpenSSL::Digest::SHA1.new)
+
+ Puppet.notice "Signed certificate request for %s" % hostname
+
+ # Add the cert to the inventory before we save it, since
+ # otherwise we could end up with it being duplicated, if
+ # this is the first time we build the inventory file.
+ inventory.add(cert)
+
+ # Save the now-signed cert. This should get routed correctly depending
+ # on the certificate type.
+ cert.save
+
+ # And remove the CSR if this wasn't self signed.
+ Puppet::SSL::CertificateRequest.destroy(csr.name) unless self_signing_csr
+
+ return cert
+ end
+
+ # Verify a given host's certificate.
+ def verify(name)
+ unless cert = Puppet::SSL::Certificate.find(name)
+ raise ArgumentError, "Could not find a certificate for %s" % name
+ end
+ store = OpenSSL::X509::Store.new
+ store.add_file Puppet[:cacert]
+ store.add_crl crl.content if self.crl
+ store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
+
+ unless store.verify(cert.content)
+ raise "Certificate for %s failed verification" % name
+ end
+ end
+
+ # List the waiting certificate requests.
+ def waiting?
+ Puppet::SSL::CertificateRequest.search("*").collect { |r| r.name }
+ end
+end
diff --git a/lib/puppet/ssl/certificate_authority/interface.rb b/lib/puppet/ssl/certificate_authority/interface.rb
new file mode 100644
index 000000000..b355e21f0
--- /dev/null
+++ b/lib/puppet/ssl/certificate_authority/interface.rb
@@ -0,0 +1,110 @@
+# This class is basically a hidden class that knows how to act
+# on the CA. It's only used by the 'puppetca' executable, and its
+# job is to provide a CLI-like interface to the CA class.
+class Puppet::SSL::CertificateAuthority::Interface
+ INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify]
+
+ class InterfaceError < ArgumentError; end
+
+ attr_reader :method, :subjects
+
+ # Actually perform the work.
+ def apply(ca)
+ unless subjects or method == :list
+ raise ArgumentError, "You must provide hosts or :all when using %s" % method
+ end
+
+ begin
+ if respond_to?(method)
+ return send(method, ca)
+ end
+
+ (subjects == :all ? ca.list : subjects).each do |host|
+ ca.send(method, host)
+ end
+ rescue InterfaceError
+ raise
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not call %s: %s" % [method, detail]
+ end
+ end
+
+ def generate(ca)
+ raise InterfaceError, "It makes no sense to generate all hosts; you must specify a list" if subjects == :all
+
+ subjects.each do |host|
+ ca.generate(host)
+ end
+ end
+
+ def initialize(method, subjects)
+ self.method = method
+ self.subjects = subjects
+ end
+
+ # List the hosts.
+ def list(ca)
+ unless subjects
+ puts ca.waiting?.join("\n")
+ return nil
+ end
+
+ signed = ca.list
+ requests = ca.waiting?
+
+ if subjects == :all
+ hosts = [signed, requests].flatten
+ else
+ hosts = subjects
+ end
+
+ hosts.uniq.sort.each do |host|
+ if signed.include?(host)
+ puts "+ " + host
+ else
+ puts host
+ end
+ end
+ end
+
+ # Set the method to apply.
+ def method=(method)
+ raise ArgumentError, "Invalid method %s to apply" % method unless INTERFACE_METHODS.include?(method)
+ @method = method
+ end
+
+ # Print certificate information.
+ def print(ca)
+ (subjects == :all ? ca.list : subjects).each do |host|
+ if value = ca.print(host)
+ puts value
+ else
+ Puppet.err "Could not find certificate for %s" % host
+ end
+ end
+ end
+
+ # Sign a given certificate.
+ def sign(ca)
+ list = subjects == :all ? ca.waiting? : subjects
+ raise InterfaceError, "No waiting certificate requests to sign" if list.empty?
+ list.each do |host|
+ ca.sign(host)
+ end
+ end
+
+ # Set the list of hosts we're operating on. Also supports keywords.
+ def subjects=(value)
+ unless value == :all or value.is_a?(Array)
+ raise ArgumentError, "Subjects must be an array or :all; not %s" % value
+ end
+
+ if value.is_a?(Array) and value.empty?
+ value = nil
+ end
+
+ @subjects = value
+ end
+end
+
diff --git a/lib/puppet/ssl/certificate_factory.rb b/lib/puppet/ssl/certificate_factory.rb
new file mode 100644
index 000000000..41155fd41
--- /dev/null
+++ b/lib/puppet/ssl/certificate_factory.rb
@@ -0,0 +1,145 @@
+require 'puppet/ssl'
+
+# The tedious class that does all the manipulations to the
+# certificate to correctly sign it. Yay.
+class Puppet::SSL::CertificateFactory
+ # How we convert from various units to the required seconds.
+ UNITMAP = {
+ "y" => 365 * 24 * 60 * 60,
+ "d" => 24 * 60 * 60,
+ "h" => 60 * 60,
+ "s" => 1
+ }
+
+ attr_reader :name, :cert_type, :csr, :issuer, :serial
+
+ def initialize(cert_type, csr, issuer, serial)
+ @cert_type, @csr, @issuer, @serial = cert_type, csr, issuer, serial
+
+ @name = @csr.subject
+ end
+
+ # Actually generate our certificate.
+ def result
+ @cert = OpenSSL::X509::Certificate.new
+
+ @cert.version = 2 # X509v3
+ @cert.subject = @csr.subject
+ @cert.issuer = @issuer.subject
+ @cert.public_key = @csr.public_key
+ @cert.serial = @serial
+
+ build_extensions()
+
+ set_ttl
+
+ @cert
+ end
+
+ private
+
+ # This is pretty ugly, but I'm not really sure it's even possible to do
+ # it any other way.
+ def build_extensions
+ @ef = OpenSSL::X509::ExtensionFactory.new
+
+ @ef.subject_certificate = @cert
+
+ if @issuer.is_a?(OpenSSL::X509::Request) # It's a self-signed cert
+ @ef.issuer_certificate = @cert
+ else
+ @ef.issuer_certificate = @issuer
+ end
+
+ @subject_alt_name = []
+ @key_usage = nil
+ @ext_key_usage = nil
+ @extensions = []
+
+ method = "add_#{@cert_type.to_s}_extensions"
+
+ begin
+ send(method)
+ rescue NoMethodError
+ raise ArgumentError, "%s is an invalid certificate type" % @cert_type
+ end
+
+ @extensions << @ef.create_extension("nsComment", "Puppet Ruby/OpenSSL Generated Certificate")
+ @extensions << @ef.create_extension("basicConstraints", @basic_constraint, true)
+ @extensions << @ef.create_extension("subjectKeyIdentifier", "hash")
+ @extensions << @ef.create_extension("keyUsage", @key_usage.join(",")) if @key_usage
+ @extensions << @ef.create_extension("extendedKeyUsage", @ext_key_usage.join(",")) if @ext_key_usage
+ @extensions << @ef.create_extension("subjectAltName", @subject_alt_name.join(",")) if ! @subject_alt_name.empty?
+
+ @cert.extensions = @extensions
+
+ # for some reason this _must_ be the last extension added
+ @extensions << @ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if @cert_type == :ca
+ end
+
+ # TTL for new certificates in seconds. If config param :ca_ttl is set,
+ # use that, otherwise use :ca_days for backwards compatibility
+ def ttl
+ ttl = Puppet.settings[:ca_ttl]
+
+ return ttl unless ttl.is_a?(String)
+
+ raise ArgumentError, "Invalid ca_ttl #{ttl}" unless ttl =~ /^(\d+)(y|d|h|s)$/
+
+ return $1.to_i * UNITMAP[$2]
+ end
+
+ def set_ttl
+ # Make the certificate valid as of yesterday, because
+ # so many people's clocks are out of sync.
+ from = Time.now - (60*60*24)
+ @cert.not_before = from
+ @cert.not_after = from + ttl
+ end
+
+ # Woot! We're a CA.
+ def add_ca_extensions
+ @basic_constraint = "CA:TRUE"
+ @key_usage = %w{cRLSign keyCertSign}
+ end
+
+ # We're a terminal CA, probably not self-signed.
+ def add_terminalsubca_extensions
+ @basic_constraint = "CA:TRUE,pathlen:0"
+ @key_usage = %w{cRLSign keyCertSign}
+ end
+
+ # We're a normal server.
+ def add_server_extensions
+ @basic_constraint = "CA:FALSE"
+ dnsnames = Puppet[:certdnsnames]
+ name = @name.to_s.sub(%r{/CN=},'')
+ if dnsnames != ""
+ dnsnames.split(':').each { |d| @subject_alt_name << 'DNS:' + d }
+ @subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
+ elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
+ @subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
+ @subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
+ @subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
+ end
+ @key_usage = %w{digitalSignature keyEncipherment}
+ @ext_key_usage = %w{serverAuth clientAuth emailProtection}
+ end
+
+ # Um, no idea.
+ def add_ocsp_extensions
+ @basic_constraint = "CA:FALSE"
+ @key_usage = %w{nonRepudiation digitalSignature}
+ @ext_key_usage = %w{serverAuth OCSPSigning}
+ end
+
+ # Normal client.
+ def add_client_extensions
+ @basic_constraint = "CA:FALSE"
+ @key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
+ @ext_key_usage = %w{clientAuth emailProtection}
+
+ @extensions << @ef.create_extension("nsCertType", "client,email")
+ end
+end
+
diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb
new file mode 100644
index 000000000..34cae5a3e
--- /dev/null
+++ b/lib/puppet/ssl/certificate_request.rb
@@ -0,0 +1,36 @@
+require 'puppet/ssl/base'
+
+# Manage certificate requests.
+class Puppet::SSL::CertificateRequest < Puppet::SSL::Base
+ wraps OpenSSL::X509::Request
+
+ extend Puppet::Indirector
+ indirects :certificate_request, :terminus_class => :file
+
+ # How to create a certificate request with our system defaults.
+ def generate(key)
+ Puppet.info "Creating a new SSL certificate request for %s" % name
+
+ # Support either an actual SSL key, or a Puppet key.
+ key = key.content if key.is_a?(Puppet::SSL::Key)
+
+ csr = OpenSSL::X509::Request.new
+ csr.version = 0
+ csr.subject = OpenSSL::X509::Name.new([["CN", name]])
+ csr.public_key = key.public_key
+ csr.sign(key, OpenSSL::Digest::MD5.new)
+
+ raise Puppet::Error, "CSR sign verification failed; you need to clean the certificate request for %s on the server" % name unless csr.verify(key.public_key)
+
+ @content = csr
+ end
+
+ def save
+ super()
+
+ # Try to autosign the CSR.
+ if ca = Puppet::SSL::CertificateAuthority.instance
+ ca.autosign
+ end
+ end
+end
diff --git a/lib/puppet/ssl/certificate_revocation_list.rb b/lib/puppet/ssl/certificate_revocation_list.rb
new file mode 100644
index 000000000..3029c14a4
--- /dev/null
+++ b/lib/puppet/ssl/certificate_revocation_list.rb
@@ -0,0 +1,72 @@
+require 'puppet/ssl/base'
+require 'puppet/indirector'
+
+# Manage the CRL.
+class Puppet::SSL::CertificateRevocationList < Puppet::SSL::Base
+ wraps OpenSSL::X509::CRL
+
+ extend Puppet::Indirector
+ indirects :certificate_revocation_list, :terminus_class => :file
+
+ # Knows how to create a CRL with our system defaults.
+ def generate(cert, cakey)
+ Puppet.info "Creating a new certificate revocation list"
+ @content = wrapped_class.new
+ @content.issuer = cert.subject
+ @content.version = 1
+
+ # Init the CRL number.
+ crlNum = OpenSSL::ASN1::Integer(0)
+ @content.extensions = [OpenSSL::X509::Extension.new("crlNumber", crlNum)]
+
+ # Set last/next update
+ @content.last_update = Time.now
+ # Keep CRL valid for 5 years
+ @content.next_update = Time.now + 5 * 365*24*60*60
+
+ @content.sign(cakey, OpenSSL::Digest::SHA1.new)
+
+ @content
+ end
+
+ # The name doesn't actually matter; there's only one CRL.
+ # We just need the name so our Indirector stuff all works more easily.
+ def initialize(fakename)
+ raise Puppet::Error, "Cannot manage the CRL when :cacrl is set to false" if [false, "false"].include?(Puppet[:cacrl])
+
+ @name = "crl"
+ end
+
+ # Revoke the certificate with serial number SERIAL issued by this
+ # CA, then write the CRL back to disk. The REASON must be one of the
+ # OpenSSL::OCSP::REVOKED_* reasons
+ def revoke(serial, cakey, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
+ Puppet.notice "Revoked certificate with serial %s" % serial
+ time = Time.now
+
+ # Add our revocation to the CRL.
+ revoked = OpenSSL::X509::Revoked.new
+ revoked.serial = serial
+ revoked.time = time
+ enum = OpenSSL::ASN1::Enumerated(reason)
+ ext = OpenSSL::X509::Extension.new("CRLReason", enum)
+ revoked.add_extension(ext)
+ @content.add_revoked(revoked)
+
+ # Increment the crlNumber
+ e = @content.extensions.find { |e| e.oid == 'crlNumber' }
+ ext = @content.extensions.reject { |e| e.oid == 'crlNumber' }
+ crlNum = OpenSSL::ASN1::Integer(e ? e.value.to_i + 1 : 0)
+ ext << OpenSSL::X509::Extension.new("crlNumber", crlNum)
+ @content.extensions = ext
+
+ # Set last/next update
+ @content.last_update = time
+ # Keep CRL valid for 5 years
+ @content.next_update = time + 5 * 365*24*60*60
+
+ @content.sign(cakey, OpenSSL::Digest::SHA1.new)
+
+ save
+ end
+end
diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb
new file mode 100644
index 000000000..e366bfbdd
--- /dev/null
+++ b/lib/puppet/ssl/host.rb
@@ -0,0 +1,185 @@
+require 'puppet/ssl'
+require 'puppet/ssl/key'
+require 'puppet/ssl/certificate'
+require 'puppet/ssl/certificate_request'
+require 'puppet/ssl/certificate_revocation_list'
+require 'puppet/util/constant_inflector'
+
+# The class that manages all aspects of our SSL certificates --
+# private keys, public keys, requests, etc.
+class Puppet::SSL::Host
+ # Yay, ruby's strange constant lookups.
+ Key = Puppet::SSL::Key
+ Certificate = Puppet::SSL::Certificate
+ CertificateRequest = Puppet::SSL::CertificateRequest
+ CertificateRevocationList = Puppet::SSL::CertificateRevocationList
+
+ extend Puppet::Util::ConstantInflector
+
+ attr_reader :name
+ attr_accessor :ca
+
+ attr_writer :key, :certificate, :certificate_request
+
+ CA_NAME = "ca"
+
+ # This is the constant that people will use to mark that a given host is
+ # a certificate authority.
+ def self.ca_name
+ CA_NAME
+ end
+
+ class << self
+ attr_reader :ca_location
+ end
+
+ # Configure how our various classes interact with their various terminuses.
+ def self.configure_indirection(terminus, cache = nil)
+ Certificate.terminus_class = terminus
+ CertificateRequest.terminus_class = terminus
+ CertificateRevocationList.terminus_class = terminus
+
+ if cache
+ # This is weird; we don't actually cache our keys or CRL, we
+ # use what would otherwise be the cache as our normal
+ # terminus.
+ Key.terminus_class = cache
+ else
+ Key.terminus_class = terminus
+ end
+
+ if cache
+ Certificate.cache_class = cache
+ CertificateRequest.cache_class = cache
+ CertificateRevocationList.cache_class = cache
+ end
+ end
+
+ # Specify how we expect to interact with our certificate authority.
+ def self.ca_location=(mode)
+ raise ArgumentError, "CA Mode can only be :local, :remote, or :none" unless [:local, :remote, :none].include?(mode)
+
+ @ca_mode = mode
+
+ case @ca_mode
+ when :local:
+ # Our ca is local, so we use it as the ultimate source of information
+ # And we cache files locally.
+ configure_indirection :ca, :file
+ when :remote:
+ configure_indirection :rest, :file
+ when :none:
+ # We have no CA, so we just look in the local file store.
+ configure_indirection :file
+ end
+ end
+
+ # Remove all traces of a given host
+ def self.destroy(name)
+ [Key, Certificate, CertificateRequest].inject(false) do |result, klass|
+ if klass.destroy(name)
+ result = true
+ end
+ result
+ end
+ end
+
+ # Search for more than one host, optionally only specifying
+ # an interest in hosts with a given file type.
+ # This just allows our non-indirected class to have one of
+ # indirection methods.
+ def self.search(options = {})
+ classes = [Key, CertificateRequest, Certificate]
+ if klass = options[:for]
+ classlist = [klass].flatten
+ else
+ classlist = [Key, CertificateRequest, Certificate]
+ end
+
+ # Collect the results from each class, flatten them, collect all of the names, make the name list unique,
+ # then create a Host instance for each one.
+ classlist.collect { |klass| klass.search }.flatten.collect { |r| r.name }.uniq.collect do |name|
+ new(name)
+ end
+ end
+
+ # Is this a ca host, meaning that all of its files go in the CA location?
+ def ca?
+ ca
+ end
+
+ def key
+ return nil unless @key ||= Key.find(name)
+ @key
+ end
+
+ # This is the private key; we can create it from scratch
+ # with no inputs.
+ def generate_key
+ @key = Key.new(name)
+ @key.generate
+ @key.save
+ true
+ end
+
+ def certificate_request
+ return nil unless @certificate_request ||= CertificateRequest.find(name)
+ @certificate_request
+ end
+
+ # Our certificate request requires the key but that's all.
+ def generate_certificate_request
+ generate_key unless key
+ @certificate_request = CertificateRequest.new(name)
+ @certificate_request.generate(key.content)
+ @certificate_request.save
+ return true
+ end
+
+ def certificate
+ return nil unless @certificate ||= Certificate.find(name)
+ @certificate
+ end
+
+ # Generate all necessary parts of our ssl host.
+ def generate
+ generate_key unless key
+ generate_certificate_request unless certificate_request
+
+ # If we can get a CA instance, then we're a valid CA, and we
+ # should use it to sign our request; else, just try to read
+ # the cert.
+ if ! certificate() and ca = Puppet::SSL::CertificateAuthority.instance
+ ca.sign(self.name)
+ end
+ end
+
+ def initialize(name = nil)
+ @name = name || Puppet[:certname]
+ @key = @certificate = @certificate_request = nil
+ @ca = (name == self.class.ca_name)
+ end
+
+ # Extract the public key from the private key.
+ def public_key
+ key.content.public_key
+ end
+
+ # Create/return a store that uses our SSL info to validate
+ # connections.
+ def ssl_store(purpose = OpenSSL::X509::PURPOSE_ANY)
+ store = OpenSSL::X509::Store.new
+ store.purpose = purpose
+
+ store.add_file(Puppet[:localcacert])
+
+ # If there's a CRL, add it to our store.
+ if crl = Puppet::SSL::CertificateRevocationList.find("ca")
+ store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK
+ store.add_crl(crl.content)
+ end
+ return store
+ end
+end
+
+require 'puppet/ssl/certificate_authority'
diff --git a/lib/puppet/ssl/inventory.rb b/lib/puppet/ssl/inventory.rb
new file mode 100644
index 000000000..38cbf46e9
--- /dev/null
+++ b/lib/puppet/ssl/inventory.rb
@@ -0,0 +1,52 @@
+require 'puppet/ssl'
+require 'puppet/ssl/certificate'
+
+# Keep track of all of our known certificates.
+class Puppet::SSL::Inventory
+ attr_reader :path
+
+ # Add a certificate to our inventory.
+ def add(cert)
+ cert = cert.content if cert.is_a?(Puppet::SSL::Certificate)
+
+ # Create our file, if one does not already exist.
+ rebuild unless FileTest.exist?(@path)
+
+ Puppet.settings.write(:cert_inventory, "a") do |f|
+ f.print format(cert)
+ end
+ end
+
+ # Format our certificate for output.
+ def format(cert)
+ iso = '%Y-%m-%dT%H:%M:%S%Z'
+ return "0x%04x %s %s %s\n" % [cert.serial, cert.not_before.strftime(iso), cert.not_after.strftime(iso), cert.subject]
+ end
+
+ def initialize
+ @path = Puppet[:cert_inventory]
+ end
+
+ # Rebuild the inventory from scratch. This should happen if
+ # the file is entirely missing or if it's somehow corrupted.
+ def rebuild
+ Puppet.notice "Rebuilding inventory file"
+
+ Puppet.settings.write(:cert_inventory) do |f|
+ f.print "# Inventory of signed certificates\n# SERIAL NOT_BEFORE NOT_AFTER SUBJECT\n"
+ end
+
+ Puppet::SSL::Certificate.search("*").each { |cert| add(cert) }
+ end
+
+ # Find the serial number for a given certificate.
+ def serial(name)
+ return nil unless FileTest.exist?(@path)
+
+ File.readlines(@path).each do |line|
+ next unless line =~ /^(\S+).+\/CN=#{name}$/
+
+ return Integer($1)
+ end
+ end
+end
diff --git a/lib/puppet/ssl/key.rb b/lib/puppet/ssl/key.rb
new file mode 100644
index 000000000..a1d436090
--- /dev/null
+++ b/lib/puppet/ssl/key.rb
@@ -0,0 +1,50 @@
+require 'puppet/ssl/base'
+require 'puppet/indirector'
+
+# Manage private and public keys as a pair.
+class Puppet::SSL::Key < Puppet::SSL::Base
+ wraps OpenSSL::PKey::RSA
+
+ extend Puppet::Indirector
+ indirects :key, :terminus_class => :file
+
+ attr_accessor :password_file
+
+ # Knows how to create keys with our system defaults.
+ def generate
+ Puppet.info "Creating a new SSL key for %s" % name
+ @content = OpenSSL::PKey::RSA.new(Puppet[:keylength].to_i)
+ end
+
+ def initialize(name)
+ super
+
+ if ca?
+ @password_file = Puppet[:capass]
+ else
+ @password_file = Puppet[:passfile]
+ end
+ end
+
+ def password
+ return nil unless password_file and FileTest.exist?(password_file)
+
+ ::File.read(password_file)
+ end
+
+ # Optionally support specifying a password file.
+ def read(path)
+ return super unless password_file
+
+ #@content = wrapped_class.new(::File.read(path), password)
+ @content = wrapped_class.new(::File.read(path), password)
+ end
+
+ def to_s
+ if pass = password
+ @content.export(OpenSSL::Cipher::DES.new(:EDE3, :CBC), pass)
+ else
+ return super
+ end
+ end
+end
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index 14b2037f4..d4bc42100 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -153,7 +153,7 @@ class Transaction
# contained resources might never get cleaned up.
def cleanup
if defined? @generated
- relationship_graph.remove_resource(*@generated)
+ catalog.remove_resource(*@generated)
end
end
@@ -503,7 +503,7 @@ class Transaction
# Now add any dynamically generated resources
generate()
-
+
# This will throw an error if there are cycles in the graph.
@sorted_resources = relationship_graph.topsort
end
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index f8949ec90..7deb25fff 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -229,14 +229,14 @@ class Type
end
# If the name and title differ, set up an alias
- if self.name != self.title
- if obj = self.class[self.name]
+ if self.name != self.title and self.catalog
+ if obj = catalog.resource(self.class.name, self.name)
if self.class.isomorphic?
raise Puppet::Error, "%s already exists with name %s" %
[obj.title, self.name]
end
else
- self.class.alias(self.name, self)
+ catalog.alias(self, self.name)
end
end
diff --git a/lib/puppet/type/component.rb b/lib/puppet/type/component.rb
index 356205089..1d1bc9ee8 100644
--- a/lib/puppet/type/component.rb
+++ b/lib/puppet/type/component.rb
@@ -88,8 +88,8 @@ Puppet::Type.newtype(:component) do
@reference = Puppet::ResourceReference.new(:component, @title)
- unless self.class[@reference.to_s]
- self.class.alias(@reference.to_s, self)
+ if catalog and ! catalog.resource[@reference.to_s]
+ catalog.alias(self, @reference.to_s)
end
end
diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb
index 3518e8bb3..ef010efda 100644
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@ -78,9 +78,8 @@ module Puppet
munge do |value|
# I don't really know how this is happening.
- if value.is_a?(Array)
- value = value.shift
- end
+ value = value.shift if value.is_a?(Array)
+
case value
when false, "false", :false:
false
@@ -92,7 +91,7 @@ module Puppet
# We can't depend on looking this up right now,
# we have to do it after all of the objects
# have been instantiated.
- if bucketobj = Puppet::Type.type(:filebucket)[value]
+ if resource.catalog and bucketobj = resource.catalog.resource(:filebucket, value)
@resource.bucket = bucketobj.bucket
bucketobj.title
else
@@ -304,30 +303,23 @@ module Puppet
# We have to do some extra finishing, to retrieve our bucket if
# there is one.
def finish
- # Let's cache these values, since there should really only be
- # a couple of these buckets
- @@filebuckets ||= {}
-
# Look up our bucket, if there is one
if bucket = self.bucket
case bucket
when String:
- if obj = @@filebuckets[bucket]
- # This sets the @value on :backup, too
- self.bucket = obj
+ if catalog and obj = catalog.resource(:filebucket, bucket)
+ self.bucket = obj.bucket
elsif bucket == "puppet"
obj = Puppet::Network::Client.client(:Dipper).new(
:Path => Puppet[:clientbucketdir]
)
self.bucket = obj
- @@filebuckets[bucket] = obj
- elsif obj = Puppet::Type.type(:filebucket).bucket(bucket)
- @@filebuckets[bucket] = obj
- self.bucket = obj
else
- self.fail "Could not find filebucket %s" % bucket
+ self.fail "Could not find filebucket '%s'" % bucket
end
when Puppet::Network::Client.client(:Dipper): # things are hunky-dorey
+ when Puppet::Type::Filebucket # things are hunky-dorey
+ self.bucket = bucket.bucket
else
self.fail "Invalid bucket type %s" % bucket.class
end
@@ -432,8 +424,7 @@ module Puppet
end
when "link": return true
else
- self.notice "Cannot backup files of type %s" %
- File.stat(file).ftype
+ self.notice "Cannot backup files of type %s" % File.stat(file).ftype
return false
end
end
@@ -805,7 +796,6 @@ module Puppet
# a wrapper method to make sure the file exists before doing anything
def retrieve
unless stat = self.stat(true)
- self.debug "File does not exist"
# If the file doesn't exist but we have a source, then call
# retrieve on that property
diff --git a/lib/puppet/type/filebucket.rb b/lib/puppet/type/filebucket.rb
index b268610e9..872bded4e 100755
--- a/lib/puppet/type/filebucket.rb
+++ b/lib/puppet/type/filebucket.rb
@@ -54,21 +54,9 @@ module Puppet
defaultto { Puppet[:clientbucketdir] }
end
- # get the actual filebucket object
- def self.bucket(name)
- if object = self[name]
- return object.bucket
- else
- return nil
- end
- end
-
# Create a default filebucket.
def self.mkdefaultbucket
- unless default = self["puppet"]
- return self.create(:name => "puppet", :path => Puppet[:clientbucketdir])
- end
- return nil
+ self.create(:name => "puppet", :path => Puppet[:clientbucketdir])
end
def self.instances
diff --git a/lib/puppet/type/schedule.rb b/lib/puppet/type/schedule.rb
index b8479e01d..ecbf7d49a 100755
--- a/lib/puppet/type/schedule.rb
+++ b/lib/puppet/type/schedule.rb
@@ -241,7 +241,9 @@ module Puppet
:daily => :day,
:monthly => :month,
:weekly => proc do |prev, now|
- prev.strftime("%U") != now.strftime("%U")
+ # Run the resource if the previous day was after this weekday (e.g., prev is wed, current is tue)
+ # or if it's been more than a week since we ran
+ prev.wday > now.wday or (now - prev) > (24 * 3600 * 7)
end
}
@@ -314,8 +316,6 @@ module Puppet
end
def self.mkdefaultschedules
- return [] if self["puppet"]
-
result = []
Puppet.debug "Creating default schedules"
result << self.create(
@@ -326,12 +326,10 @@ module Puppet
# And then one for every period
@parameters.find { |p| p.name == :period }.values.each { |value|
- unless self[value.to_s]
- result << self.create(
- :name => value.to_s,
- :period => value
- )
- end
+ result << self.create(
+ :name => value.to_s,
+ :period => value
+ )
}
result
diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb
index 71507d172..0b668395d 100755
--- a/lib/puppet/type/user.rb
+++ b/lib/puppet/type/user.rb
@@ -302,19 +302,7 @@ module Puppet
group
end
}
- groups.each { |group|
- case group
- when Integer:
- if obj = Puppet.type(:group).find { |gobj|
- gobj.should(:gid) == group
- }
- autos << obj
-
- end
- else
- autos << group
- end
- }
+ autos = groups.reject { |g| g.is_a?(Integer) }
end
if obj = @parameters[:groups] and groups = obj.should
diff --git a/lib/puppet/type/yumrepo.rb b/lib/puppet/type/yumrepo.rb
index acb3b9b83..8800dd71d 100644
--- a/lib/puppet/type/yumrepo.rb
+++ b/lib/puppet/type/yumrepo.rb
@@ -67,8 +67,9 @@ module Puppet
class << self
attr_accessor :filetype
# The writer is only used for testing, there should be no need
- # to change yumconf in any other context
+ # to change yumconf or inifile in any other context
attr_accessor :yumconf
+ attr_writer :inifile
end
self.filetype = Puppet::Util::FileType.filetype(:flat)
@@ -181,11 +182,11 @@ module Puppet
inifile.store
end
+ # This is only used during testing.
def self.clear
@inifile = nil
@yumconf = "/etc/yum.conf"
@defaultrepodir = nil
- super
end
# Return the Puppet::Util::IniConfig::Section for this yumrepo resource
diff --git a/lib/puppet/util/cacher.rb b/lib/puppet/util/cacher.rb
new file mode 100644
index 000000000..7b352c72a
--- /dev/null
+++ b/lib/puppet/util/cacher.rb
@@ -0,0 +1,69 @@
+module Puppet::Util::Cacher
+ # Cause all cached values to be considered invalid.
+ def self.invalidate
+ @timestamp = Time.now
+ end
+
+ def self.valid?(timestamp)
+ unless defined?(@timestamp) and @timestamp
+ @timestamp = Time.now
+ return true
+ end
+ return timestamp >= @timestamp
+ end
+
+ def self.extended(other)
+ other.extend(InstanceMethods)
+ end
+
+ def self.included(other)
+ other.extend(ClassMethods)
+ other.send(:include, InstanceMethods)
+ end
+
+ module ClassMethods
+ private
+
+ def cached_attr(name, &block)
+ define_method(name) do
+ attr_cache(name, &block)
+ end
+ end
+ end
+
+ module InstanceMethods
+ private
+
+ def attr_cache(name, &block)
+ unless defined?(@cacher_caches) and @cacher_caches
+ @cacher_caches = Cache.new
+ end
+
+ @cacher_caches.value(name, &block)
+ end
+ end
+
+ class Cache
+ attr_accessor :caches, :timestamp
+
+ def initialize
+ @caches = {}
+ end
+
+ def value(name)
+ raise ArgumentError, "You must provide a block when using the cache" unless block_given?
+
+ if timestamp.nil? or ! Puppet::Util::Cacher.valid?(timestamp)
+ caches.clear
+ self.timestamp = Time.now
+ end
+
+ # Use 'include?' here rather than testing for truth, so we
+ # can cache false values.
+ unless caches.include?(name)
+ caches[name] = yield
+ end
+ caches[name]
+ end
+ end
+end
diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb
index 8dcb67286..ae078fff4 100755
--- a/lib/puppet/util/filetype.rb
+++ b/lib/puppet/util/filetype.rb
@@ -74,8 +74,10 @@ class Puppet::Util::FileType
# Pick or create a filebucket to use.
def bucket
- filebucket = Puppet::Type.type(:filebucket)
- (filebucket["puppet"] || filebucket.mkdefaultbucket).bucket
+ unless defined?(@bucket)
+ @bucket = Puppet::Type.type(:filebucket).mkdefaultbucket.bucket
+ end
+ @bucket
end
def initialize(path)
@@ -104,6 +106,9 @@ class Puppet::Util::FileType
# Overwrite the file.
def write(text)
backup()
+
+ raise("Cannot create file %s in absent directory" % @path) unless FileTest.exist?(File.dirname(@path))
+
require "tempfile"
tf = Tempfile.new("puppet")
tf.print text; tf.flush
diff --git a/lib/puppet/util/posix.rb b/lib/puppet/util/posix.rb
index cc0340ef7..8228734ef 100755
--- a/lib/puppet/util/posix.rb
+++ b/lib/puppet/util/posix.rb
@@ -63,45 +63,6 @@ module Puppet::Util::POSIX
return nil
end
- # Look in memory for an already-managed type and use its info if available.
- # Currently unused.
- def get_provider_value(type, field, id)
- unless typeklass = Puppet::Type.type(type)
- raise ArgumentError, "Invalid type %s" % type
- end
-
- id = id.to_s
-
- chkfield = idfield(type)
- obj = typeklass.find { |obj|
- if id =~ /^\d+$/
- obj.should(chkfield).to_s == id ||
- obj.provider.send(chkfield) == id
- else
- obj[:name] == id
- end
- }
-
- return nil unless obj
-
- if obj.provider
- begin
- val = obj.provider.send(field)
- if val == :absent
- return nil
- else
- return val
- end
- rescue => detail
- if Puppet[:trace]
- puts detail.backtrace
- Puppet.err detail
- return nil
- end
- end
- end
- end
-
# Determine what the field name is for users and groups.
def idfield(space)
case Puppet::Util.symbolize(space)
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index 0e6f91e48..eec86625d 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -39,6 +39,8 @@ class Puppet::Util::Settings
end
@values[:memory][param] = value
@cache.clear
+
+ clearused
end
return value
@@ -65,7 +67,6 @@ class Puppet::Util::Settings
config = trans.to_catalog
config.store_state = false
config.apply
- config.clear
rescue => detail
if Puppet[:trace]
puts detail.backtrace
@@ -312,94 +313,6 @@ class Puppet::Util::Settings
end
end
- # Parse the configuration file. As of May 2007, this is a backward-compatibility method and
- # will be deprecated soon.
- def old_parse(file)
- text = nil
-
- if file.is_a? Puppet::Util::LoadedFile
- @file = file
- else
- @file = Puppet::Util::LoadedFile.new(file)
- end
-
- # Don't create a timer for the old style parsing.
- # settimer()
-
- begin
- text = File.read(@file.file)
- rescue Errno::ENOENT
- raise Puppet::Error, "No such file %s" % file
- rescue Errno::EACCES
- raise Puppet::Error, "Permission denied to file %s" % file
- end
-
- @values = Hash.new { |names, name|
- names[name] = {}
- }
-
- # Get rid of the values set by the file, keeping cli values.
- self.clear(true)
-
- section = "puppet"
- metas = %w{owner group mode}
- values = Hash.new { |hash, key| hash[key] = {} }
- text.split(/\n/).each { |line|
- case line
- when /^\[(\w+)\]$/: section = $1 # Section names
- when /^\s*#/: next # Skip comments
- when /^\s*$/: next # Skip blanks
- when /^\s*(\w+)\s*=\s*(.+)$/: # settings
- var = $1.intern
- if var == :mode
- value = $2
- else
- value = munge_value($2)
- end
-
- # Only warn if we don't know what this config var is. This
- # prevents exceptions later on.
- unless @config.include?(var) or metas.include?(var.to_s)
- Puppet.warning "Discarded unknown configuration parameter %s" % var.inspect
- next # Skip this line.
- end
-
- # Mmm, "special" attributes
- if metas.include?(var.to_s)
- unless values.include?(section)
- values[section] = {}
- end
- values[section][var.to_s] = value
-
- # If the parameter is valid, then set it.
- if section == Puppet[:name] and @config.include?(var)
- #@config[var].value = value
- @values[:main][var] = value
- end
- next
- end
-
- # Don't override set parameters, since the file is parsed
- # after cli arguments are handled.
- unless @config.include?(var) and @config[var].setbycli
- Puppet.debug "%s: Setting %s to '%s'" % [section, var, value]
- @values[:main][var] = value
- end
- @config[var].section = symbolize(section)
-
- metas.each { |meta|
- if values[section][meta]
- if @config[var].respond_to?(meta + "=")
- @config[var].send(meta + "=", values[section][meta])
- end
- end
- }
- else
- raise Puppet::Error, "Could not match line %s" % line
- end
- }
- end
-
# Create a new element. The value is passed in because it's used to determine
# what kind of element we're creating, but the value itself might be either
# a default or a value, so we can't actually assign it.
@@ -663,7 +576,7 @@ Generated on #{Time.now}.
catalog = bucket.to_catalog
rescue => detail
puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not create resources for managing Puppet's files and directories: %s" % detail
+ Puppet.err "Could not create resources for managing Puppet's files and directories in sections %s: %s" % [sections.inspect, detail]
# We need some way to get rid of any resources created during the catalog creation
# but not cleaned up.
@@ -674,11 +587,14 @@ Generated on #{Time.now}.
catalog.host_config = false
catalog.apply do |transaction|
if failures = transaction.any_failed?
- raise "Could not configure for running; got %s failure(s)" % failures
+ # LAK:NOTE We should do something like this for some cases,
+ # since it can otherwise be hard to know what failed.
+ #transaction.report.logs.find_all { |log| log.level == :err }.each do |log|
+ # puts log.message
+ #end
+ raise "Could not configure myself; got %s failure(s)" % failures
end
end
- ensure
- catalog.clear
end
sections.each { |s| @used << s }
@@ -776,20 +692,26 @@ Generated on #{Time.now}.
end
sync.synchronize(Sync::EX) do
- File.open(file, "r+", 0600) do |rf|
+ File.open(file, ::File::CREAT|::File::RDWR, 0600) do |rf|
rf.lock_exclusive do
if File.exist?(tmpfile)
raise Puppet::Error, ".tmp file already exists for %s; Aborting locked write. Check the .tmp file and delete if appropriate" %
[file]
end
- writesub(default, tmpfile, *args, &bloc)
+ # If there's a failure, remove our tmpfile
+ begin
+ writesub(default, tmpfile, *args, &bloc)
+ rescue
+ File.unlink(tmpfile) if FileTest.exist?(tmpfile)
+ raise
+ end
begin
File.rename(tmpfile, file)
rescue => detail
- Puppet.err "Could not rename %s to %s: %s" %
- [file, tmpfile, detail]
+ Puppet.err "Could not rename %s to %s: %s" % [file, tmpfile, detail]
+ File.unlink(tmpfile) if FileTest.exist?(tmpfile)
end
end
end
@@ -1163,7 +1085,6 @@ Generated on #{Time.now}.
return nil unless path.is_a?(String)
return nil if path =~ /^\/dev/
- return nil if Puppet::Type.type(:file)[path] # skip files that are in our global resource list.
objects = []
diff --git a/man/man8/puppet.8 b/man/man8/puppet.8
index 990b7cee9..8fc24aab2 100644
--- a/man/man8/puppet.8
+++ b/man/man8/puppet.8
@@ -67,8 +67,7 @@ puppet \-l /tmp/script.log script.pp
.SH AUTHOR
Luke Kanies
-
-
+.\" Generated by docutils manpage writer on 2008-01-20 10:28.
.SH COPYRIGHT
Copyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public
License
diff --git a/spec/integration/bin/puppetmasterd.rb b/spec/integration/bin/puppetmasterd.rb
new file mode 100755
index 000000000..447344472
--- /dev/null
+++ b/spec/integration/bin/puppetmasterd.rb
@@ -0,0 +1,109 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+describe "puppetmasterd" do
+ before do
+ # Get a safe temporary file
+ file = Tempfile.new("puppetmaster_integration_testing")
+ @dir = file.path
+ file.delete
+
+ Dir.mkdir(@dir)
+
+ Puppet.settings[:confdir] = @dir
+ Puppet.settings[:vardir] = @dir
+ Puppet[:certdnsnames] = "localhost"
+
+ @@port = 12345
+ end
+
+ after {
+ stop
+
+ Puppet::SSL::Host.ca_location = :none
+
+ system("rm -rf %s" % @dir)
+ Puppet.settings.clear
+ }
+
+ def arguments
+ rundir = File.join(Puppet[:vardir], "run")
+ @pidfile = File.join(rundir, "testing.pid")
+ args = ""
+ args += " --confdir %s" % Puppet[:confdir]
+ args += " --rundir %s" % rundir
+ args += " --pidfile %s" % @pidfile
+ args += " --vardir %s" % Puppet[:vardir]
+ args += " --certdnsnames %s" % Puppet[:certdnsnames]
+ args += " --masterport %s" % @@port
+ args += " --user %s" % Puppet::Util::SUIDManager.uid
+ args += " --group %s" % Puppet::Util::SUIDManager.gid
+ args += " --autosign true"
+ end
+
+ def start(addl_args = "")
+ Puppet.settings.mkdir(:manifestdir)
+ Puppet.settings.write(:manifest) do |f|
+ f.puts { "notify { testing: }" }
+ end
+
+ args = arguments + addl_args
+
+ output = %x{puppetmasterd #{args}}.chomp
+ end
+
+ def stop
+ if @pidfile and FileTest.exist?(@pidfile)
+ pid = File.read(@pidfile).chomp.to_i
+ Process.kill(:TERM, pid)
+ end
+ end
+
+ it "should create a PID file" do
+ start
+
+ FileTest.exist?(@pidfile).should be_true
+ end
+
+ it "should be serving status information over REST"
+
+ it "should be serving status information over xmlrpc" do
+ start
+
+ sleep 0.5
+
+ client = Puppet::Network::Client.status.new(:Server => "localhost", :Port => @@port)
+
+ FileUtils.mkdir_p(File.dirname(Puppet[:autosign]))
+ File.open(Puppet[:autosign], "w") { |f|
+ f.puts Puppet[:certname]
+ }
+
+ client.cert
+ retval = client.status
+
+ retval.should == 1
+ end
+
+ it "should exit with return code 0 after parsing if --parseonly is set and there are no errors" do
+ start(" --parseonly > /dev/null")
+ sleep(1)
+
+ ps = Facter["ps"].value || "ps -ef"
+ pid = nil
+ %x{#{ps}}.chomp.split(/\n/).each { |line|
+ next if line =~ /^puppet/ # skip normal master procs
+ if line =~ /puppetmasterd.+--manifest/
+ ary = line.split(" ")
+ pid = ary[1].to_i
+ end
+ }
+
+ $?.should == 0
+
+ pid.should be_nil
+ end
+
+ it "should exit with return code 1 after parsing if --parseonly is set and there are errors"
+end
diff --git a/spec/integration/defaults.rb b/spec/integration/defaults.rb
index b14a141fb..b6f6bf109 100755
--- a/spec/integration/defaults.rb
+++ b/spec/integration/defaults.rb
@@ -5,13 +5,20 @@ require File.dirname(__FILE__) + '/../spec_helper'
require 'puppet/defaults'
describe "Puppet defaults" do
- describe "when setting the :factpath" do
- after { Puppet.settings.clear }
-
+ after { Puppet.settings.clear }
+ describe "when configuring the :crl" do
it "should add the :factpath to Facter's search paths" do
Facter.expects(:search).with("/my/fact/path")
Puppet.settings[:factpath] = "/my/fact/path"
end
end
+
+ describe "when setting the :factpath" do
+
+ it "should warn if :cacrl is set to false" do
+ Puppet.expects(:warning)
+ Puppet.settings[:cacrl] = 'false'
+ end
+ end
end
diff --git a/spec/integration/file_serving/configuration.rb b/spec/integration/file_serving/configuration.rb
index 6975594a8..cb5a23d3b 100755
--- a/spec/integration/file_serving/configuration.rb
+++ b/spec/integration/file_serving/configuration.rb
@@ -10,7 +10,7 @@ require 'puppet/file_serving/configuration'
describe Puppet::FileServing::Configuration, " when finding files with Puppet::FileServing::Mount" do
before do
# Just in case it already exists.
- Puppet::FileServing::Configuration.clear_cache
+ Puppet::Util::Cacher.invalidate
@mount = Puppet::FileServing::Mount.new("mymount")
FileTest.stubs(:exists?).with("/my/path").returns(true)
@@ -38,6 +38,6 @@ describe Puppet::FileServing::Configuration, " when finding files with Puppet::F
end
after do
- Puppet::FileServing::Configuration.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
diff --git a/spec/integration/indirector/rest.rb b/spec/integration/indirector/rest.rb
index cafcce713..1a9671265 100644..100755
--- a/spec/integration/indirector/rest.rb
+++ b/spec/integration/indirector/rest.rb
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/network/server'
require 'puppet/indirector'
@@ -5,456 +7,476 @@ require 'puppet/indirector/rest'
# a fake class that will be indirected via REST
class Puppet::TestIndirectedFoo
- extend Puppet::Indirector
- indirects :test_indirected_foo, :terminus_setting => :test_indirected_foo_terminus
-
- attr_reader :value
-
- def initialize(value = 0)
- @value = value
- end
-
- def self.from_yaml(yaml)
- YAML.load(yaml)
- end
-
- def name
- "bob"
- end
+ extend Puppet::Indirector
+ indirects :test_indirected_foo, :terminus_setting => :test_indirected_foo_terminus
+
+ attr_reader :value
+
+ def initialize(value = 0)
+ @value = value
+ end
+
+ def self.from_yaml(yaml)
+ YAML.load(yaml)
+ end
+
+ def name
+ "bob"
+ end
end
# empty Terminus class -- this would normally have to be in a directory findable by the autoloader, but we short-circuit that below
class Puppet::TestIndirectedFoo::Rest < Puppet::Indirector::REST
end
+# This way the retrieval of the class by name works.
+Puppet::Indirector::Terminus.register_terminus_class(Puppet::TestIndirectedFoo::Rest)
describe Puppet::Indirector::REST do
- describe "when using webrick" do
- before :each do
- Puppet[:servertype] = 'webrick'
- @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :test_indirected_foo ] }
- @server = Puppet::Network::Server.new(@params)
- @server.listen
+ before do
+ Puppet[:masterport] = 34343
+ Puppet[:server] = "localhost"
+
+ # Get a safe temporary file
+ @tmpfile = Tempfile.new("webrick_integration_testing")
+ @dir = @tmpfile.path + "_dir"
- # the autoloader was clearly not written test-first. We subvert the integration test to get around its bullshit.
- Puppet::Indirector::Terminus.stubs(:terminus_class).returns(Puppet::TestIndirectedFoo::Rest)
- Puppet::TestIndirectedFoo.indirection.stubs(:terminus_class).returns :rest
+ Puppet.settings[:confdir] = @dir
+ Puppet.settings[:vardir] = @dir
+ Puppet.settings[:http_enable_post_connection_check] = false
- # Stub the connection information.
- Puppet::TestIndirectedFoo.indirection.terminus(:rest).stubs(:rest_connection_details).returns(:host => "localhost", :port => 34343)
+ Puppet::SSL::Host.ca_location = :local
+
+ Puppet::TestIndirectedFoo.terminus_class = :rest
+ Puppet::TestIndirectedFoo.indirection.terminus.stubs(:rest_connection_details).returns(:host => "127.0.0.1", :port => "34343")
end
-
- describe "when finding a model instance over REST" do
- describe "when a matching model instance can be found" do
- before :each do
- @model_instance = Puppet::TestIndirectedFoo.new(23)
- @mock_model = stub('faked model', :find => @model_instance)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should not fail" do
- Puppet::TestIndirectedFoo.find('bar')
- lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error
- end
-
- it 'should return an instance of the model class' do
- Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo
- end
-
- it 'should return the instance of the model class associated with the provided lookup key' do
- Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value
- end
-
- it 'should set an expiration on model instance' do
- Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil
- end
- end
-
- describe "when no matching model instance can be found" do
- before :each do
- @mock_model = stub('faked model', :find => nil)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should return nil" do
- Puppet::TestIndirectedFoo.find('bar').should be_nil
- end
- end
-
- describe "when an exception is encountered in looking up a model instance" do
- before :each do
- @mock_model = stub('faked model')
- @mock_model.stubs(:find).raises(RuntimeError)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should raise an exception" do
- lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError)
- end
- end
+
+ after do
+ Puppet::Network::HttpPool.instance_variable_set("@ssl_host", nil)
end
- describe "when searching for model instances over REST" do
- describe "when matching model instances can be found" do
+ describe "when using webrick" do
before :each do
- @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ]
- @mock_model = stub('faked model', :search => @model_instances)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should not fail" do
- lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error
- end
-
- it 'should return all matching results' do
- Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length
- end
-
- it 'should return model instances' do
- Puppet::TestIndirectedFoo.search('bar').each do |result|
- result.class.should == Puppet::TestIndirectedFoo
- end
+ Puppet::Util::Cacher.invalidate
+
+ Puppet[:servertype] = 'webrick'
+ Puppet[:server] = '127.0.0.1'
+ Puppet[:certname] = '127.0.0.1'
+
+ ca = Puppet::SSL::CertificateAuthority.new
+ ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname])
+
+ @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :test_indirected_foo ], :xmlrpc_handlers => [ :status ] }
+ @server = Puppet::Network::Server.new(@params)
+ @server.listen
end
-
- it 'should return the instance of the model class associated with the provided lookup key' do
- Puppet::TestIndirectedFoo.search('bar').collect(&:value).should == @model_instances.collect(&:value)
+
+ after do
+ @server.unlisten
+ @tmpfile.delete
+ Puppet.settings.clear
+ Puppet::Util::Cacher.invalidate
end
-
- it 'should set a version timestamp on model instances' do
- pending("Luke looking at why this version magic might not be working") do
- Puppet::TestIndirectedFoo.search('bar').each do |result|
- result.version.should_not be_nil
+
+ describe "when finding a model instance over REST" do
+ describe "when a matching model instance can be found" do
+ before :each do
+ @model_instance = Puppet::TestIndirectedFoo.new(23)
+ @mock_model = stub('faked model', :find => @model_instance)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should not fail" do
+ Puppet::TestIndirectedFoo.find('bar')
+ lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error
+ end
+
+ it 'should return an instance of the model class' do
+ Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo
+ end
+
+ it 'should return the instance of the model class associated with the provided lookup key' do
+ Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value
+ end
+
+ it 'should set an expiration on model instance' do
+ Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil
+ end
+ end
+
+ describe "when no matching model instance can be found" do
+ before :each do
+ @mock_model = stub('faked model', :find => nil)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should return nil" do
+ Puppet::TestIndirectedFoo.find('bar').should be_nil
+ end
+ end
+
+ describe "when an exception is encountered in looking up a model instance" do
+ before :each do
+ @mock_model = stub('faked model')
+ @mock_model.stubs(:find).raises(RuntimeError)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should raise an exception" do
+ lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError)
+ end
end
- end
end
- end
+
+ describe "when searching for model instances over REST" do
+ describe "when matching model instances can be found" do
+ before :each do
+ @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ]
+ @mock_model = stub('faked model', :search => @model_instances)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should not fail" do
+ lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error
+ end
- describe "when no matching model instance can be found" do
- before :each do
- @mock_model = stub('faked model', :find => nil)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should return nil" do
- Puppet::TestIndirectedFoo.find('bar').should be_nil
- end
- end
+ it 'should return all matching results' do
+ Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length
+ end
- describe "when an exception is encountered in looking up a model instance" do
- before :each do
- @mock_model = stub('faked model')
- @mock_model.stubs(:find).raises(RuntimeError)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should raise an exception" do
- lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError)
+ it 'should return model instances' do
+ Puppet::TestIndirectedFoo.search('bar').each do |result|
+ result.class.should == Puppet::TestIndirectedFoo
+ end
+ end
+
+ it 'should return the instance of the model class associated with the provided lookup key' do
+ Puppet::TestIndirectedFoo.search('bar').collect(&:value).should == @model_instances.collect(&:value)
+ end
+ end
+
+ describe "when no matching model instance can be found" do
+ before :each do
+ @mock_model = stub('faked model', :find => nil)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should return nil" do
+ Puppet::TestIndirectedFoo.find('bar').should be_nil
+ end
+ end
+
+ describe "when an exception is encountered in looking up a model instance" do
+ before :each do
+ @mock_model = stub('faked model')
+ @mock_model.stubs(:find).raises(RuntimeError)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should raise an exception" do
+ lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError)
+ end
+ end
end
- end
- end
- describe "when destroying a model instance over REST" do
- describe "when a matching model instance can be found" do
- before :each do
- @mock_model = stub('faked model', :destroy => true)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should not fail" do
- lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error
- end
-
- it 'should return success' do
- Puppet::TestIndirectedFoo.destroy('bar').should == true
- end
- end
+ describe "when destroying a model instance over REST" do
+ describe "when a matching model instance can be found" do
+ before :each do
+ @mock_model = stub('faked model', :destroy => true)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should not fail" do
+ lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error
+ end
- describe "when no matching model instance can be found" do
- before :each do
- @mock_model = stub('faked model', :destroy => false)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should return failure" do
- Puppet::TestIndirectedFoo.destroy('bar').should == false
+ it 'should return success' do
+ Puppet::TestIndirectedFoo.destroy('bar').should == true
+ end
+ end
+
+ describe "when no matching model instance can be found" do
+ before :each do
+ @mock_model = stub('faked model', :destroy => false)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should return failure" do
+ Puppet::TestIndirectedFoo.destroy('bar').should == false
+ end
+ end
+
+ describe "when an exception is encountered in destroying a model instance" do
+ before :each do
+ @mock_model = stub('faked model')
+ @mock_model.stubs(:destroy).raises(RuntimeError)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should raise an exception" do
+ lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(RuntimeError)
+ end
+ end
end
- end
+
+ describe "when saving a model instance over REST" do
+ before :each do
+ @instance = Puppet::TestIndirectedFoo.new(42)
+ @mock_model = stub('faked model', :from_yaml => @instance)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(@instance)
+ end
+
+ describe "when a successful save can be performed" do
+ before :each do
+ end
+
+ it "should not fail" do
+ lambda { @instance.save }.should_not raise_error
+ end
- describe "when an exception is encountered in destroying a model instance" do
- before :each do
- @mock_model = stub('faked model')
- @mock_model.stubs(:destroy).raises(RuntimeError)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should raise an exception" do
- lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(RuntimeError)
+ it 'should return an instance of the model class' do
+ @instance.save.class.should == Puppet::TestIndirectedFoo
+ end
+
+ it 'should return a matching instance of the model class' do
+ @instance.save.value.should == @instance.value
+ end
+ end
+
+ describe "when a save cannot be completed" do
+ before :each do
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(false)
+ end
+
+ it "should return failure" do
+ @instance.save.should == false
+ end
+ end
+
+ describe "when an exception is encountered in performing a save" do
+ before :each do
+ Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).raises(RuntimeError)
+ end
+
+ it "should raise an exception" do
+ lambda { @instance.save }.should raise_error(RuntimeError)
+ end
+ end
end
- end
end
- describe "when saving a model instance over REST" do
- before :each do
- @instance = Puppet::TestIndirectedFoo.new(42)
- @mock_model = stub('faked model', :from_yaml => @instance)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:model).returns(@mock_model)
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(@instance)
- end
-
- describe "when a successful save can be performed" do
- before :each do
- end
-
- it "should not fail" do
- lambda { @instance.save }.should_not raise_error
- end
-
- it 'should return an instance of the model class' do
- @instance.save.class.should == Puppet::TestIndirectedFoo
- end
-
- it 'should return a matching instance of the model class' do
- @instance.save.value.should == @instance.value
- end
- end
-
- describe "when a save cannot be completed" do
- before :each do
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(false)
- end
-
- it "should return failure" do
- @instance.save.should == false
- end
- end
-
- describe "when an exception is encountered in performing a save" do
+ describe "when using mongrel" do
+ confine "Mongrel is not available" => Puppet.features.mongrel?
+
before :each do
- Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).raises(RuntimeError)
- end
-
- it "should raise an exception" do
- lambda { @instance.save }.should raise_error(RuntimeError)
- end
- end
- end
+ Puppet[:servertype] = 'mongrel'
+ @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :test_indirected_foo ] }
- after :each do
- @server.unlisten
- end
- end
+ # Make sure we never get a cert, since mongrel can't speak ssl
+ Puppet::SSL::Certificate.stubs(:find).returns nil
- describe "when using mongrel" do
- confine "Mongrel is not available" => Puppet.features.mongrel?
-
- before :each do
- Puppet[:servertype] = 'mongrel'
- @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :test_indirected_foo ] }
- @server = Puppet::Network::Server.new(@params)
- @server.listen
+ # We stub ssl to be off, since mongrel can't speak ssl
+ Net::HTTP.any_instance.stubs(:use_ssl?).returns false
- # the autoloader was clearly not written test-first. We subvert the integration test to get around its bullshit.
- Puppet::Indirector::Terminus.stubs(:terminus_class).returns(Puppet::TestIndirectedFoo::Rest)
- Puppet::TestIndirectedFoo.indirection.stubs(:terminus_class).returns :rest
-
- # Stub the connection information.
- Puppet::TestIndirectedFoo.indirection.terminus(:rest).stubs(:rest_connection_details).returns(:host => "localhost", :port => 34343)
- end
-
- describe "when finding a model instance over REST" do
- describe "when a matching model instance can be found" do
- before :each do
- @model_instance = Puppet::TestIndirectedFoo.new(23)
- @mock_model = stub('faked model', :find => @model_instance)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should not fail" do
- lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error
+ @server = Puppet::Network::Server.new(@params)
+ @server.listen
end
-
- it 'should return an instance of the model class' do
- Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo
- end
-
- it 'should return the instance of the model class associated with the provided lookup key' do
- Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value
- end
-
- it 'should set an expiration on model instance' do
- Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil
+
+ after :each do
+ @server.unlisten
end
- end
- describe "when no matching model instance can be found" do
- before :each do
- @mock_model = stub('faked model', :find => nil)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should return nil" do
- Puppet::TestIndirectedFoo.find('bar').should be_nil
- end
- end
+ describe "when finding a model instance over REST" do
+ describe "when a matching model instance can be found" do
+ before :each do
+ @model_instance = Puppet::TestIndirectedFoo.new(23)
+ @mock_model = stub('faked model', :find => @model_instance)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should not fail" do
+ lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error
+ end
- describe "when an exception is encountered in looking up a model instance" do
- before :each do
- @mock_model = stub('faked model')
- @mock_model.stubs(:find).raises(RuntimeError)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should raise an exception" do
- lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError)
- end
- end
- end
-
- describe "when searching for model instances over REST" do
- describe "when matching model instances can be found" do
- before :each do
- @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ]
- @mock_model = stub('faked model', :search => @model_instances)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should not fail" do
- lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error
- end
-
- it 'should return all matching results' do
- Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length
- end
-
- it 'should return model instances' do
- Puppet::TestIndirectedFoo.search('bar').each do |result|
- result.class.should == Puppet::TestIndirectedFoo
- end
- end
-
- it 'should return the instance of the model class associated with the provided lookup key' do
- Puppet::TestIndirectedFoo.search('bar').collect(&:value).should == @model_instances.collect(&:value)
- end
-
- it 'should set an expiration on model instances' do
- Puppet::TestIndirectedFoo.search('bar').each do |result|
- result.expiration.should_not be_nil
- end
- end
- end
+ it 'should return an instance of the model class' do
+ Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo
+ end
- describe "when no matching model instance can be found" do
- before :each do
- @mock_model = stub('faked model', :find => nil)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should return nil" do
- Puppet::TestIndirectedFoo.find('bar').should be_nil
- end
- end
+ it 'should return the instance of the model class associated with the provided lookup key' do
+ Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value
+ end
- describe "when an exception is encountered in looking up a model instance" do
- before :each do
- @mock_model = stub('faked model')
- @mock_model.stubs(:find).raises(RuntimeError)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should raise an exception" do
- lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError)
+ it 'should set an expiration on model instance' do
+ Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil
+ end
+ end
+
+ describe "when no matching model instance can be found" do
+ before :each do
+ @mock_model = stub('faked model', :find => nil)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should return nil" do
+ Puppet::TestIndirectedFoo.find('bar').should be_nil
+ end
+ end
+
+ describe "when an exception is encountered in looking up a model instance" do
+ before :each do
+ @mock_model = stub('faked model')
+ @mock_model.stubs(:find).raises(RuntimeError)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should raise an exception" do
+ lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError)
+ end
+ end
end
- end
- end
- describe "when destroying a model instance over REST" do
- describe "when a matching model instance can be found" do
- before :each do
- @mock_model = stub('faked model', :destroy => true)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should not fail" do
- lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error
- end
-
- it 'should return success' do
- Puppet::TestIndirectedFoo.destroy('bar').should == true
- end
- end
+ describe "when searching for model instances over REST" do
+ describe "when matching model instances can be found" do
+ before :each do
+ @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ]
+ @mock_model = stub('faked model', :search => @model_instances)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should not fail" do
+ lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error
+ end
- describe "when no matching model instance can be found" do
- before :each do
- @mock_model = stub('faked model', :destroy => false)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should return failure" do
- Puppet::TestIndirectedFoo.destroy('bar').should == false
- end
- end
+ it 'should return all matching results' do
+ Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length
+ end
- describe "when an exception is encountered in destroying a model instance" do
- before :each do
- @mock_model = stub('faked model')
- @mock_model.stubs(:destroy).raises(RuntimeError)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- end
-
- it "should raise an exception" do
- lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(RuntimeError)
+ it 'should return model instances' do
+ Puppet::TestIndirectedFoo.search('bar').each do |result|
+ result.class.should == Puppet::TestIndirectedFoo
+ end
+ end
+
+ it 'should return the instance of the model class associated with the provided lookup key' do
+ Puppet::TestIndirectedFoo.search('bar').collect(&:value).should == @model_instances.collect(&:value)
+ end
+
+ it 'should set an expiration on model instances' do
+ Puppet::TestIndirectedFoo.search('bar').each do |result|
+ result.expiration.should_not be_nil
+ end
+ end
+ end
+
+ describe "when no matching model instance can be found" do
+ before :each do
+ @mock_model = stub('faked model', :find => nil)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should return nil" do
+ Puppet::TestIndirectedFoo.find('bar').should be_nil
+ end
+ end
+
+ describe "when an exception is encountered in looking up a model instance" do
+ before :each do
+ @mock_model = stub('faked model')
+ @mock_model.stubs(:find).raises(RuntimeError)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should raise an exception" do
+ lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(RuntimeError)
+ end
+ end
end
- end
- end
- describe "when saving a model instance over REST" do
- before :each do
- @instance = Puppet::TestIndirectedFoo.new(42)
- @mock_model = stub('faked model', :from_yaml => @instance)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(@instance)
- end
-
- describe "when a successful save can be performed" do
- before :each do
- end
-
- it "should not fail" do
- lambda { @instance.save }.should_not raise_error
- end
-
- it 'should return an instance of the model class' do
- @instance.save.class.should == Puppet::TestIndirectedFoo
- end
-
- it 'should return a matching instance of the model class' do
- @instance.save.value.should == @instance.value
- end
- end
-
- describe "when a save cannot be completed" do
- before :each do
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(false)
- end
-
- it "should return failure" do
- @instance.save.should == false
- end
- end
-
- describe "when an exception is encountered in performing a save" do
- before :each do
- Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).raises(RuntimeError)
- end
-
- it "should raise an exception" do
- lambda { @instance.save }.should raise_error(RuntimeError)
+ describe "when destroying a model instance over REST" do
+ describe "when a matching model instance can be found" do
+ before :each do
+ @mock_model = stub('faked model', :destroy => true)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should not fail" do
+ lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error
+ end
+
+ it 'should return success' do
+ Puppet::TestIndirectedFoo.destroy('bar').should == true
+ end
+ end
+
+ describe "when no matching model instance can be found" do
+ before :each do
+ @mock_model = stub('faked model', :destroy => false)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should return failure" do
+ Puppet::TestIndirectedFoo.destroy('bar').should == false
+ end
+ end
+
+ describe "when an exception is encountered in destroying a model instance" do
+ before :each do
+ @mock_model = stub('faked model')
+ @mock_model.stubs(:destroy).raises(RuntimeError)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ end
+
+ it "should raise an exception" do
+ lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(RuntimeError)
+ end
+ end
end
- end
- end
- after :each do
- @server.unlisten
+ describe "when saving a model instance over REST" do
+ before :each do
+ @instance = Puppet::TestIndirectedFoo.new(42)
+ @mock_model = stub('faked model', :from_yaml => @instance)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:model).returns(@mock_model)
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(@instance)
+ end
+
+ describe "when a successful save can be performed" do
+ before :each do
+ end
+
+ it "should not fail" do
+ lambda { @instance.save }.should_not raise_error
+ end
+
+ it 'should return an instance of the model class' do
+ @instance.save.class.should == Puppet::TestIndirectedFoo
+ end
+
+ it 'should return a matching instance of the model class' do
+ @instance.save.value.should == @instance.value
+ end
+ end
+
+ describe "when a save cannot be completed" do
+ before :each do
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(false)
+ end
+
+ it "should return failure" do
+ @instance.save.should == false
+ end
+ end
+
+ describe "when an exception is encountered in performing a save" do
+ before :each do
+ Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).raises(RuntimeError)
+ end
+
+ it "should raise an exception" do
+ lambda { @instance.save }.should raise_error(RuntimeError)
+ end
+ end
+ end
end
- end
end
diff --git a/spec/integration/network/server/mongrel.rb b/spec/integration/network/server/mongrel.rb
index 65caf78c9..08fd49b17 100644..100755
--- a/spec/integration/network/server/mongrel.rb
+++ b/spec/integration/network/server/mongrel.rb
@@ -8,7 +8,7 @@ describe Puppet::Network::Server do
before :each do
Puppet[:servertype] = 'mongrel'
- @params = { :address => "127.0.0.1", :port => 34346, :handlers => [ :node ] }
+ @params = { :address => "127.0.0.1", :port => 34346, :handlers => [ :node ], :xmlrpc_handlers => [ :status ] }
@server = Puppet::Network::Server.new(@params)
end
@@ -43,4 +43,4 @@ describe Puppet::Network::Server do
@server.unlisten if @server.listening?
end
end
-end \ No newline at end of file
+end
diff --git a/spec/integration/network/server/webrick.rb b/spec/integration/network/server/webrick.rb
index 0ab8d89e4..0e66ee955 100644..100755
--- a/spec/integration/network/server/webrick.rb
+++ b/spec/integration/network/server/webrick.rb
@@ -1,46 +1,70 @@
+#!/usr/bin/env ruby
+
require File.dirname(__FILE__) + '/../../../spec_helper'
require 'puppet/network/server'
+require 'puppet/ssl/certificate_authority'
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
+ describe "when using webrick" do
+ before :each do
+ Puppet[:servertype] = 'webrick'
+ @params = { :address => "127.0.0.1", :port => 34343, :handlers => [ :node ], :xmlrpc_handlers => [ :status ] }
+
+ # Get a safe temporary file
+ @tmpfile = Tempfile.new("webrick_integration_testing")
+ @dir = @tmpfile.path + "_dir"
+
+ Puppet.settings[:confdir] = @dir
+ Puppet.settings[:vardir] = @dir
+
+ Puppet::SSL::Host.ca_location = :local
+
+ ca = Puppet::SSL::CertificateAuthority.new
+ ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname])
+ end
+
+ after do
+ @tmpfile.delete
+ Puppet.settings.clear
+
+ system("rm -rf %s" % @dir)
+
+ Puppet::Util::Cacher.invalidate
+ 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
- end
-end \ No newline at end of file
+end
diff --git a/spec/integration/node/catalog.rb b/spec/integration/node/catalog.rb
index 941d2cc6c..285b85869 100755
--- a/spec/integration/node/catalog.rb
+++ b/spec/integration/node/catalog.rb
@@ -7,13 +7,13 @@ require File.dirname(__FILE__) + '/../../spec_helper'
describe Puppet::Node::Catalog do
describe "when using the indirector" do
+ after { Puppet::Util::Cacher.invalidate }
before do
# This is so the tests work w/out networking.
Facter.stubs(:to_hash).returns({"hostname" => "foo.domain.com"})
Facter.stubs(:value).returns("eh")
end
- after { Puppet::Node::Catalog.indirection.clear_cache }
it "should be able to delegate to the :yaml terminus" do
Puppet::Node::Catalog.indirection.stubs(:terminus_class).returns :yaml
diff --git a/spec/integration/node/facts.rb b/spec/integration/node/facts.rb
index c2f876578..cef3d79d4 100755
--- a/spec/integration/node/facts.rb
+++ b/spec/integration/node/facts.rb
@@ -7,13 +7,15 @@ require File.dirname(__FILE__) + '/../../spec_helper'
describe Puppet::Node::Facts do
describe "when using the indirector" do
- after { Puppet::Node::Facts.indirection.clear_cache }
+ after { Puppet::Util::Cacher.invalidate }
it "should expire any cached node instances when it is saved" do
Puppet::Node::Facts.indirection.stubs(:terminus_class).returns :yaml
+
+ Puppet::Node::Facts.indirection.terminus(:yaml).should equal(Puppet::Node::Facts.indirection.terminus(:yaml))
terminus = Puppet::Node::Facts.indirection.terminus(:yaml)
+ terminus.stubs :save
- terminus.expects(:save)
Puppet::Node.expects(:expire).with("me")
facts = Puppet::Node::Facts.new("me")
diff --git a/spec/integration/ssl/certificate_authority.rb b/spec/integration/ssl/certificate_authority.rb
new file mode 100755
index 000000000..d838bc586
--- /dev/null
+++ b/spec/integration/ssl/certificate_authority.rb
@@ -0,0 +1,137 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-4-17.
+# Copyright (c) 2008. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_authority'
+require 'tempfile'
+
+describe Puppet::SSL::CertificateAuthority do
+ before do
+ # Get a safe temporary file
+ file = Tempfile.new("ca_integration_testing")
+ @dir = file.path
+ file.delete
+
+ Puppet.settings[:confdir] = @dir
+ Puppet.settings[:vardir] = @dir
+
+ Puppet::SSL::Host.ca_location = :local
+ @ca = Puppet::SSL::CertificateAuthority.new
+ end
+
+ after {
+ Puppet::SSL::Host.ca_location = :none
+
+ system("rm -rf %s" % @dir)
+ Puppet.settings.clear
+
+ Puppet::Util::Cacher.invalidate
+
+ Puppet::SSL::CertificateAuthority.instance_variable_set("@instance", nil)
+ }
+
+ it "should create a CA host" do
+ @ca.host.should be_ca
+ end
+
+ it "should be able to generate a certificate" do
+ @ca.generate_ca_certificate
+
+ @ca.host.certificate.should be_instance_of(Puppet::SSL::Certificate)
+ end
+
+ it "should be able to generate a new host certificate" do
+ @ca.generate("newhost")
+
+ Puppet::SSL::Certificate.find("newhost").should be_instance_of(Puppet::SSL::Certificate)
+ end
+
+ it "should be able to revoke a host certificate" do
+ pending("This test doesn't actually work yet") do
+ @ca.generate("newhost")
+
+ @ca.revoke("newhost")
+
+ lambda { @ca.verify("newhost") }.should raise_error
+ end
+ end
+
+ it "should have a CRL" do
+ @ca.generate_ca_certificate
+ @ca.crl.should_not be_nil
+ end
+
+ it "should be able to read in a previously created CRL" do
+ @ca.generate_ca_certificate
+
+ # Create it to start with.
+ @ca.crl
+
+ Puppet::SSL::CertificateAuthority.new.crl.should_not be_nil
+ end
+
+ describe "when signing certificates" do
+ before do
+ @host = Puppet::SSL::Host.new("luke.madstop.com")
+
+ # We have to provide the key, since when we're in :ca_only mode, we can only interact
+ # with the CA key.
+ key = Puppet::SSL::Key.new(@host.name)
+ key.generate
+
+ @host.key = key
+ @host.generate_certificate_request
+
+ path = File.join(Puppet[:requestdir], "luke.madstop.com.pem")
+ end
+
+ it "should be able to sign certificates" do
+ @ca.sign("luke.madstop.com")
+ end
+
+ it "should save the signed certificate" do
+ @ca.sign("luke.madstop.com")
+
+ Puppet::SSL::Certificate.find("luke.madstop.com").should be_instance_of(Puppet::SSL::Certificate)
+ end
+
+ it "should be able to sign multiple certificates" do
+ @other = Puppet::SSL::Host.new("other.madstop.com")
+ okey = Puppet::SSL::Key.new(@other.name)
+ okey.generate
+ @other.key = okey
+ @other.generate_certificate_request
+
+ @ca.sign("luke.madstop.com")
+ @ca.sign("other.madstop.com")
+
+ Puppet::SSL::Certificate.find("other.madstop.com").should be_instance_of(Puppet::SSL::Certificate)
+ Puppet::SSL::Certificate.find("luke.madstop.com").should be_instance_of(Puppet::SSL::Certificate)
+ end
+
+ it "should save the signed certificate to the :signeddir" do
+ @ca.sign("luke.madstop.com")
+
+ client_cert = File.join(Puppet[:signeddir], "luke.madstop.com.pem")
+ File.read(client_cert).should == Puppet::SSL::Certificate.find("luke.madstop.com").content.to_s
+ end
+
+ it "should save valid certificates" do
+ @ca.sign("luke.madstop.com")
+
+ ssl = %x{which openssl}
+
+ unless ssl
+ pending "No ssl available"
+ else
+ ca_cert = Puppet[:cacert]
+ client_cert = File.join(Puppet[:signeddir], "luke.madstop.com.pem")
+ output = %x{openssl verify -CAfile #{ca_cert} #{client_cert}}
+ $?.should == 0
+ end
+ end
+ end
+end
diff --git a/spec/integration/ssl/certificate_request.rb b/spec/integration/ssl/certificate_request.rb
new file mode 100755
index 000000000..f428718e7
--- /dev/null
+++ b/spec/integration/ssl/certificate_request.rb
@@ -0,0 +1,57 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-4-17.
+# Copyright (c) 2008. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_request'
+require 'tempfile'
+
+describe Puppet::SSL::CertificateRequest do
+ before do
+ # Get a safe temporary file
+ file = Tempfile.new("csr_integration_testing")
+ @dir = file.path
+ file.delete
+
+ Puppet.settings.clear
+
+ Puppet.settings[:confdir] = @dir
+ Puppet.settings[:vardir] = @dir
+
+ @csr = Puppet::SSL::CertificateRequest.new("luke.madstop.com")
+
+ @key = OpenSSL::PKey::RSA.new(512)
+ end
+
+ after do
+ system("rm -rf %s" % @dir)
+ Puppet.settings.clear
+
+ # This is necessary so the terminus instances don't lie around.
+ Puppet::Util::Cacher.invalidate
+ end
+
+ it "should be able to generate CSRs" do
+ @csr.generate(@key)
+ end
+
+ it "should be able to save CSRs" do
+ @csr.save
+ end
+
+ it "should be able to find saved certificate requests via the Indirector" do
+ @csr.generate(@key)
+ @csr.save
+
+ Puppet::SSL::CertificateRequest.find("luke.madstop.com").should be_instance_of(Puppet::SSL::CertificateRequest)
+ end
+
+ it "should save the completely CSR when saving" do
+ @csr.generate(@key)
+ @csr.save
+
+ Puppet::SSL::CertificateRequest.find("luke.madstop.com").content.to_s.should == @csr.content.to_s
+ end
+end
diff --git a/spec/integration/ssl/certificate_revocation_list.rb b/spec/integration/ssl/certificate_revocation_list.rb
new file mode 100755
index 000000000..246654816
--- /dev/null
+++ b/spec/integration/ssl/certificate_revocation_list.rb
@@ -0,0 +1,42 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-5-5.
+# Copyright (c) 2008. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_revocation_list'
+require 'tempfile'
+
+describe Puppet::SSL::CertificateRevocationList do
+ before do
+ # Get a safe temporary file
+ file = Tempfile.new("ca_integration_testing")
+ @dir = file.path
+ file.delete
+
+ Puppet.settings[:confdir] = @dir
+ Puppet.settings[:vardir] = @dir
+
+ Puppet::SSL::Host.ca_location = :local
+ end
+
+ after {
+ Puppet::SSL::Host.ca_location = :none
+
+ system("rm -rf %s" % @dir)
+ Puppet.settings.clear
+
+ # This is necessary so the terminus instances don't lie around.
+ Puppet::Util::Cacher.invalidate
+ }
+
+ it "should be able to read in written out CRLs with no revoked certificates" do
+ ca = Puppet::SSL::CertificateAuthority.new
+
+ raise "CRL not created" unless FileTest.exist?(Puppet[:hostcrl])
+
+ crl = Puppet::SSL::CertificateRevocationList.new("crl_int_testing")
+ crl.read(Puppet[:hostcrl])
+ end
+end
diff --git a/spec/integration/ssl/host.rb b/spec/integration/ssl/host.rb
new file mode 100755
index 000000000..65f10cef3
--- /dev/null
+++ b/spec/integration/ssl/host.rb
@@ -0,0 +1,90 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-4-17.
+# Copyright (c) 2008. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/host'
+require 'tempfile'
+
+describe Puppet::SSL::Host do
+ before do
+ # Get a safe temporary file
+ file = Tempfile.new("host_integration_testing")
+ @dir = file.path
+ file.delete
+
+ Puppet.settings[:confdir] = @dir
+ Puppet.settings[:vardir] = @dir
+
+ Puppet::SSL::Host.ca_location = :local
+
+ @host = Puppet::SSL::Host.new("luke.madstop.com")
+ @ca = Puppet::SSL::CertificateAuthority.new
+ end
+
+ after {
+ Puppet::SSL::Host.ca_location = :none
+
+ system("rm -rf %s" % @dir)
+ Puppet.settings.clear
+ Puppet::Util::Cacher.invalidate
+ }
+
+ it "should be considered a CA host if its name is equal to 'ca'" do
+ Puppet::SSL::Host.new("ca").should be_ca
+ end
+
+ describe "when managing its key" do
+ it "should be able to generate and save a key" do
+ @host.generate_key
+ end
+
+ it "should save the key such that the Indirector can find it" do
+ @host.generate_key
+
+ Puppet::SSL::Key.find(@host.name).content.to_s.should == @host.key.to_s
+ end
+
+ it "should save the private key into the :privatekeydir" do
+ @host.generate_key
+ File.read(File.join(Puppet.settings[:privatekeydir], "luke.madstop.com.pem")).should == @host.key.to_s
+ end
+ end
+
+ describe "when managing its certificate request" do
+ it "should be able to generate and save a certificate request" do
+ @host.generate_certificate_request
+ end
+
+ it "should save the certificate request such that the Indirector can find it" do
+ @host.generate_certificate_request
+
+ Puppet::SSL::CertificateRequest.find(@host.name).content.to_s.should == @host.certificate_request.to_s
+ end
+
+ it "should save the private certificate request into the :privatekeydir" do
+ @host.generate_certificate_request
+ File.read(File.join(Puppet.settings[:requestdir], "luke.madstop.com.pem")).should == @host.certificate_request.to_s
+ end
+ end
+
+ describe "when the CA host" do
+ it "should never store its key in the :privatekeydir" do
+ Puppet.settings.use(:main, :ssl, :ca)
+ @ca = Puppet::SSL::Host.new(Puppet::SSL::Host.ca_name)
+ @ca.generate_key
+
+ FileTest.should_not be_exist(File.join(Puppet[:privatekeydir], "ca.pem"))
+ end
+ end
+
+ it "should pass the verification of its own SSL store" do
+ @host.generate
+ @ca = Puppet::SSL::CertificateAuthority.new
+ @ca.sign(@host.name)
+
+ @host.ssl_store.verify(@host.certificate.content).should be_true
+ end
+end
diff --git a/spec/integration/transaction/report.rb b/spec/integration/transaction/report.rb
index 48e59f203..6bbd5eb10 100755
--- a/spec/integration/transaction/report.rb
+++ b/spec/integration/transaction/report.rb
@@ -7,7 +7,7 @@ require File.dirname(__FILE__) + '/../../spec_helper'
describe Puppet::Transaction::Report do
describe "when using the indirector" do
- after { Puppet::Transaction::Report.indirection.clear_cache }
+ after { Puppet::Util::Cacher.invalidate }
it "should be able to delegate to the :processor terminus" do
Puppet::Transaction::Report.indirection.stubs(:terminus_class).returns :processor
diff --git a/spec/shared_behaviours/file_server_terminus.rb b/spec/shared_behaviours/file_server_terminus.rb
index de08f29fc..883db58f5 100644
--- a/spec/shared_behaviours/file_server_terminus.rb
+++ b/spec/shared_behaviours/file_server_terminus.rb
@@ -7,7 +7,7 @@ describe "Puppet::Indirector::FileServerTerminus", :shared => true do
# This only works if the shared behaviour is included before
# the 'before' block in the including context.
before do
- Puppet::FileServing::Configuration.clear_cache
+ Puppet::Util::Cacher.invalidate
FileTest.stubs(:exists?).with(Puppet[:fileserverconfig]).returns(true)
FileTest.stubs(:exists?).with("/my/mount/path").returns(true)
FileTest.stubs(:directory?).with("/my/mount/path").returns(true)
diff --git a/spec/unit/file_serving/configuration.rb b/spec/unit/file_serving/configuration.rb
index a0710e20d..d51fa70b2 100755
--- a/spec/unit/file_serving/configuration.rb
+++ b/spec/unit/file_serving/configuration.rb
@@ -15,12 +15,12 @@ describe Puppet::FileServing::Configuration do
it "should have a method for removing the current configuration instance" do
old = Puppet::FileServing::Configuration.create
- Puppet::FileServing::Configuration.clear_cache
+ Puppet::Util::Cacher.invalidate
Puppet::FileServing::Configuration.create.should_not equal(old)
end
after do
- Puppet::FileServing::Configuration.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
@@ -32,7 +32,7 @@ describe Puppet::FileServing::Configuration do
end
after :each do
- Puppet::FileServing::Configuration.clear_cache
+ Puppet::Util::Cacher.invalidate
end
describe Puppet::FileServing::Configuration, " when initializing" do
diff --git a/spec/unit/file_serving/mount.rb b/spec/unit/file_serving/mount.rb
index ebe058301..6f491e3b2 100755
--- a/spec/unit/file_serving/mount.rb
+++ b/spec/unit/file_serving/mount.rb
@@ -12,9 +12,9 @@ end
describe Puppet::FileServing::Mount do
it "should provide a method for clearing its cached host information" do
- Puppet::FileServing::Mount.new("whatever").send(:localmap)
- Puppet::FileServing::Mount.clear_cache
- Puppet::FileServing::Mount.send(:class_variable_get, "@@localmap").should be_nil
+ old = Puppet::FileServing::Mount.localmap
+ Puppet::Util::Cacher.invalidate
+ Puppet::FileServing::Mount.localmap.should_not equal(old)
end
end
@@ -106,7 +106,7 @@ describe Puppet::FileServing::Mount, " when finding files" do
end
after do
- Puppet::FileServing::Mount.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
diff --git a/spec/unit/indirector/certificate/ca.rb b/spec/unit/indirector/certificate/ca.rb
new file mode 100755
index 000000000..0158a8d90
--- /dev/null
+++ b/spec/unit/indirector/certificate/ca.rb
@@ -0,0 +1,28 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate/ca'
+
+describe Puppet::SSL::Certificate::Ca do
+ it "should have documentation" do
+ Puppet::SSL::Certificate::Ca.doc.should be_instance_of(String)
+ end
+
+ it "should use the :signeddir as the collection directory" do
+ Puppet.settings.expects(:value).with(:signeddir).returns "/cert/dir"
+ Puppet::SSL::Certificate::Ca.collection_directory.should == "/cert/dir"
+ end
+
+ it "should store the ca certificate at the :cacert location" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
+ file = Puppet::SSL::Certificate::Ca.new
+ file.stubs(:ca?).returns true
+ file.path("whatever").should == "/ca/cert"
+ end
+end
diff --git a/spec/unit/indirector/certificate/file.rb b/spec/unit/indirector/certificate/file.rb
new file mode 100755
index 000000000..6fb00f1ca
--- /dev/null
+++ b/spec/unit/indirector/certificate/file.rb
@@ -0,0 +1,28 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate/file'
+
+describe Puppet::SSL::Certificate::File do
+ it "should have documentation" do
+ Puppet::SSL::Certificate::File.doc.should be_instance_of(String)
+ end
+
+ it "should use the :certdir as the collection directory" do
+ Puppet.settings.expects(:value).with(:certdir).returns "/cert/dir"
+ Puppet::SSL::Certificate::File.collection_directory.should == "/cert/dir"
+ end
+
+ it "should store the ca certificate at the :localcacert location" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert"
+ file = Puppet::SSL::Certificate::File.new
+ file.stubs(:ca?).returns true
+ file.path("whatever").should == "/ca/cert"
+ end
+end
diff --git a/spec/unit/indirector/certificate/rest.rb b/spec/unit/indirector/certificate/rest.rb
new file mode 100755
index 000000000..62b1ef543
--- /dev/null
+++ b/spec/unit/indirector/certificate/rest.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate/rest'
+
+describe Puppet::SSL::Certificate::Rest do
+ before do
+ @searcher = Puppet::SSL::Certificate::Rest.new
+ end
+
+ it "should be a sublcass of Puppet::Indirector::REST" do
+ Puppet::SSL::Certificate::Rest.superclass.should equal(Puppet::Indirector::REST)
+ end
+end
diff --git a/spec/unit/indirector/certificate_request/ca.rb b/spec/unit/indirector/certificate_request/ca.rb
new file mode 100755
index 000000000..b35d8b474
--- /dev/null
+++ b/spec/unit/indirector/certificate_request/ca.rb
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_request/ca'
+
+describe Puppet::SSL::CertificateRequest::Ca do
+ it "should have documentation" do
+ Puppet::SSL::CertificateRequest::Ca.doc.should be_instance_of(String)
+ end
+
+ it "should use the :csrdir as the collection directory" do
+ Puppet.settings.expects(:value).with(:csrdir).returns "/request/dir"
+ Puppet::SSL::CertificateRequest::Ca.collection_directory.should == "/request/dir"
+ end
+end
diff --git a/spec/unit/indirector/certificate_request/file.rb b/spec/unit/indirector/certificate_request/file.rb
new file mode 100755
index 000000000..e1f442e2a
--- /dev/null
+++ b/spec/unit/indirector/certificate_request/file.rb
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_request/file'
+
+describe Puppet::SSL::CertificateRequest::File do
+ it "should have documentation" do
+ Puppet::SSL::CertificateRequest::File.doc.should be_instance_of(String)
+ end
+
+ it "should use the :requestdir as the collection directory" do
+ Puppet.settings.expects(:value).with(:requestdir).returns "/request/dir"
+ Puppet::SSL::CertificateRequest::File.collection_directory.should == "/request/dir"
+ end
+end
diff --git a/spec/unit/indirector/certificate_request/rest.rb b/spec/unit/indirector/certificate_request/rest.rb
new file mode 100755
index 000000000..cbd525f17
--- /dev/null
+++ b/spec/unit/indirector/certificate_request/rest.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_request/rest'
+
+describe Puppet::SSL::CertificateRequest::Rest do
+ before do
+ @searcher = Puppet::SSL::CertificateRequest::Rest.new
+ end
+
+ it "should be a sublcass of Puppet::Indirector::REST" do
+ Puppet::SSL::CertificateRequest::Rest.superclass.should equal(Puppet::Indirector::REST)
+ end
+end
diff --git a/spec/unit/indirector/certificate_revocation_list/ca.rb b/spec/unit/indirector/certificate_revocation_list/ca.rb
new file mode 100755
index 000000000..f6da86861
--- /dev/null
+++ b/spec/unit/indirector/certificate_revocation_list/ca.rb
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_revocation_list/ca'
+
+describe Puppet::SSL::CertificateRevocationList::Ca do
+ it "should have documentation" do
+ Puppet::SSL::CertificateRevocationList::Ca.doc.should be_instance_of(String)
+ end
+
+ it "should use the :cacrl setting as the crl location" do
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).with(:cacrl).returns "/request/dir"
+ Puppet::SSL::CertificateRevocationList::Ca.new.path("whatever").should == "/request/dir"
+ end
+end
diff --git a/spec/unit/indirector/certificate_revocation_list/file.rb b/spec/unit/indirector/certificate_revocation_list/file.rb
new file mode 100755
index 000000000..5db4f8c06
--- /dev/null
+++ b/spec/unit/indirector/certificate_revocation_list/file.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_revocation_list/file'
+
+describe Puppet::SSL::CertificateRevocationList::File do
+ it "should have documentation" do
+ Puppet::SSL::CertificateRevocationList::File.doc.should be_instance_of(String)
+ end
+
+ it "should always store the file to :hostcrl location" do
+ Puppet.settings.expects(:value).with(:hostcrl).returns "/host/crl"
+ Puppet.settings.stubs(:use)
+ Puppet::SSL::CertificateRevocationList::File.file_location.should == "/host/crl"
+ end
+end
diff --git a/spec/unit/indirector/certificate_revocation_list/rest.rb b/spec/unit/indirector/certificate_revocation_list/rest.rb
new file mode 100755
index 000000000..f6f493c37
--- /dev/null
+++ b/spec/unit/indirector/certificate_revocation_list/rest.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/certificate_revocation_list/rest'
+
+describe Puppet::SSL::CertificateRevocationList::Rest do
+ before do
+ @searcher = Puppet::SSL::CertificateRevocationList::Rest.new
+ end
+
+ it "should be a sublcass of Puppet::Indirector::REST" do
+ Puppet::SSL::CertificateRevocationList::Rest.superclass.should equal(Puppet::Indirector::REST)
+ end
+end
diff --git a/spec/unit/indirector/indirection.rb b/spec/unit/indirector/indirection.rb
index cefd0557e..e4799d3ff 100755
--- a/spec/unit/indirector/indirection.rb
+++ b/spec/unit/indirector/indirection.rb
@@ -87,6 +87,9 @@ describe "Delegation Authorizer", :shared => true do
end
describe Puppet::Indirector::Indirection do
+ after do
+ Puppet::Util::Cacher.invalidate
+ end
describe "when initializing" do
# (LAK) I've no idea how to test this, really.
it "should store a reference to itself before it consumes its options" do
@@ -494,7 +497,7 @@ describe Puppet::Indirector::Indirection do
after :each do
@indirection.delete
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
@@ -615,15 +618,6 @@ describe Puppet::Indirector::Indirection do
@indirection.terminus(:foo).should equal(@terminus)
end
- it "should allow the clearance of cached terminus instances" do
- terminus1 = mock 'terminus1'
- terminus2 = mock 'terminus2'
- @terminus_class.stubs(:new).returns(terminus1, terminus2, ArgumentError)
- @indirection.terminus(:foo).should equal(terminus1)
- @indirection.class.clear_cache
- @indirection.terminus(:foo).should equal(terminus2)
- end
-
# Make sure it caches the terminus.
it "should return the same terminus instance each time for a given name" do
@terminus_class.stubs(:new).returns(@terminus)
@@ -638,7 +632,6 @@ describe Puppet::Indirector::Indirection do
after do
@indirection.delete
- Puppet::Indirector::Indirection.clear_cache
end
end
@@ -675,7 +668,6 @@ describe Puppet::Indirector::Indirection do
after do
@indirection.delete
- Puppet::Indirector::Indirection.clear_cache
end
end
@@ -706,15 +698,6 @@ describe Puppet::Indirector::Indirection do
@indirection.cache.should equal(@cache)
@indirection.cache.should equal(@cache)
end
-
- it "should remove the cache terminus when all other terminus instances are cleared" do
- cache2 = mock 'cache2'
- @cache_class.stubs(:new).returns(@cache, cache2)
- @indirection.cache_class = :cache_terminus
- @indirection.cache.should equal(@cache)
- @indirection.clear_cache
- @indirection.cache.should equal(cache2)
- end
end
describe "and saving" do
@@ -725,7 +708,6 @@ describe Puppet::Indirector::Indirection do
after :each do
@indirection.delete
- Puppet::Indirector::Indirection.clear_cache
end
end
end
diff --git a/spec/unit/indirector/key/ca.rb b/spec/unit/indirector/key/ca.rb
new file mode 100755
index 000000000..579617f71
--- /dev/null
+++ b/spec/unit/indirector/key/ca.rb
@@ -0,0 +1,34 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/key/ca'
+
+describe Puppet::SSL::Key::Ca do
+ it "should have documentation" do
+ Puppet::SSL::Key::Ca.doc.should be_instance_of(String)
+ end
+
+ it "should store the ca key at the :cakey location" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:cakey).returns "/ca/key"
+ file = Puppet::SSL::Key::Ca.new
+ file.stubs(:ca?).returns true
+ file.path("whatever").should == "/ca/key"
+ end
+
+ describe "when choosing the path for the public key" do
+ it "should fail if the key is not for the CA" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:cakey).returns "/ca/key"
+ file = Puppet::SSL::Key::Ca.new
+ file.stubs(:ca?).returns false
+ lambda { file.path("whatever") }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/unit/indirector/key/file.rb b/spec/unit/indirector/key/file.rb
new file mode 100755
index 000000000..8a1cb04bd
--- /dev/null
+++ b/spec/unit/indirector/key/file.rb
@@ -0,0 +1,104 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-7.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/key/file'
+
+describe Puppet::SSL::Key::File do
+ it "should have documentation" do
+ Puppet::SSL::Key::File.doc.should be_instance_of(String)
+ end
+
+ it "should use the :privatekeydir as the collection directory" do
+ Puppet.settings.expects(:value).with(:privatekeydir).returns "/key/dir"
+ Puppet::SSL::Key::File.collection_directory.should == "/key/dir"
+ end
+
+ it "should store the ca key at the :cakey location" do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:cakey).returns "/ca/key"
+ file = Puppet::SSL::Key::File.new
+ file.stubs(:ca?).returns true
+ file.path("whatever").should == "/ca/key"
+ end
+
+ describe "when choosing the path for the public key" do
+ it "should use the :capub setting location if the key is for the certificate authority" do
+ Puppet.settings.stubs(:value).returns "/fake/dir"
+ Puppet.settings.stubs(:value).with(:capub).returns "/ca/pubkey"
+ Puppet.settings.stubs(:use)
+
+ @searcher = Puppet::SSL::Key::File.new
+ @searcher.stubs(:ca?).returns true
+ @searcher.public_key_path("whatever").should == "/ca/pubkey"
+ end
+
+ it "should use the host name plus '.pem' in :publickeydir for normal hosts" do
+ Puppet.settings.stubs(:value).with(:privatekeydir).returns "/private/key/dir"
+ Puppet.settings.stubs(:value).with(:publickeydir).returns "/public/key/dir"
+ Puppet.settings.stubs(:use)
+
+ @searcher = Puppet::SSL::Key::File.new
+ @searcher.stubs(:ca?).returns false
+ @searcher.public_key_path("whatever").should == "/public/key/dir/whatever.pem"
+ end
+ end
+
+ describe "when managing private keys" do
+ before do
+ @searcher = Puppet::SSL::Key::File.new
+
+ @private_key_path = File.join("/fake/key/path")
+ @public_key_path = File.join("/other/fake/key/path")
+
+ @searcher.stubs(:public_key_path).returns @public_key_path
+ @searcher.stubs(:path).returns @private_key_path
+
+ FileTest.stubs(:directory?).returns true
+ FileTest.stubs(:writable?).returns true
+
+ @public_key = stub 'public_key'
+ @real_key = stub 'sslkey', :public_key => @public_key
+
+ @key = stub 'key', :name => "myname", :content => @real_key
+
+ @request = stub 'request', :key => "myname", :instance => @key
+ end
+
+ it "should save the public key when saving the private key" do
+ File.stubs(:open).with(@private_key_path, "w")
+
+ fh = mock 'filehandle'
+
+ File.expects(:open).with(@public_key_path, "w").yields fh
+ @public_key.expects(:to_pem).returns "my pem"
+
+ fh.expects(:print).with "my pem"
+
+ @searcher.save(@request)
+ end
+
+ it "should destroy the public key when destroying the private key" do
+ File.stubs(:unlink).with(@private_key_path)
+ FileTest.stubs(:exist?).with(@private_key_path).returns true
+ FileTest.expects(:exist?).with(@public_key_path).returns true
+ File.expects(:unlink).with(@public_key_path)
+
+ @searcher.destroy(@request)
+ end
+
+ it "should not fail if the public key does not exist when deleting the private key" do
+ File.stubs(:unlink).with(@private_key_path)
+
+ FileTest.stubs(:exist?).with(@private_key_path).returns true
+ FileTest.expects(:exist?).with(@public_key_path).returns false
+ File.expects(:unlink).with(@public_key_path).never
+
+ @searcher.destroy(@request)
+ end
+ end
+end
diff --git a/spec/unit/indirector/rest.rb b/spec/unit/indirector/rest.rb
index 1a1064491..1f802b603 100755
--- a/spec/unit/indirector/rest.rb
+++ b/spec/unit/indirector/rest.rb
@@ -3,6 +3,39 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/indirector/rest'
+describe "a REST http call", :shared => true do
+ it "should accept a path" do
+ lambda { @search.send(@method, *@arguments) }.should_not raise_error(ArgumentError)
+ end
+
+ it "should require a path" do
+ lambda { @searcher.send(@method) }.should raise_error(ArgumentError)
+ end
+
+ it "should use the Http Pool with the remote server and port looked up from the REST terminus" do
+ @searcher.expects(:rest_connection_details).returns(@details)
+
+ conn = mock 'connection'
+ result = stub 'result', :body => "body"
+ conn.stubs(:put).returns result
+ conn.stubs(:delete).returns result
+ conn.stubs(:get).returns result
+ Puppet::Network::HttpPool.expects(:http_instance).with(@details[:host], @details[:port]).returns conn
+ @searcher.send(@method, *@arguments)
+ end
+
+ it "should return the results of the request" do
+ conn = mock 'connection'
+ result = stub 'result', :body => "result"
+ conn.stubs(:put).returns result
+ conn.stubs(:delete).returns result
+ conn.stubs(:get).returns result
+ Puppet::Network::HttpPool.stubs(:http_instance).returns conn
+
+ @searcher.send(@method, *@arguments).should == 'result'
+ end
+end
+
describe Puppet::Indirector::REST do
before do
Puppet::Indirector::Terminus.stubs(:register_terminus_class)
@@ -19,354 +52,280 @@ describe Puppet::Indirector::REST do
@searcher = @rest_class.new
end
-
- describe "when locating the REST connection" do
- before do
- Puppet.settings.stubs(:value).returns("whatever")
- end
-
- it "should return the :server setting as the host" do
- Puppet.settings.expects(:value).with(:server).returns "myserver"
- @searcher.rest_connection_details[:host].should == "myserver"
- end
-
- it "should return the :masterport (as an Integer) as the port" do
- Puppet.settings.expects(:value).with(:masterport).returns "1234"
- @searcher.rest_connection_details[:port].should == 1234
- end
+
+ describe "when configuring the REST http call" do
+ before do
+ Puppet.settings.stubs(:value).returns("rest_testing")
+ end
+
+ it "should return the :server setting as the host" do
+ Puppet.settings.expects(:value).with(:server).returns "myserver"
+ @searcher.rest_connection_details[:host].should == "myserver"
+ end
+
+ it "should return the :masterport (as an Integer) as the port" do
+ Puppet.settings.expects(:value).with(:masterport).returns "1234"
+ @searcher.rest_connection_details[:port].should == 1234
+ end
end
-
+
describe "when doing a network fetch" do
- before :each do
- Net::HTTP.stubs(:start).returns('result')
- @details = { :host => '127.0.0.1', :port => 34343 }
- @searcher.stubs(:rest_connection_details).returns(@details)
- end
-
- it "should accept a path" do
- lambda { @search.network_fetch('foo') }.should_not raise_error(ArgumentError)
- end
-
- it "should require a path" do
- lambda { @searcher.network_fetch }.should raise_error(ArgumentError)
- end
-
- it "should look up connection details" do
- @searcher.expects(:rest_connection_details).returns(@details)
- @searcher.network_fetch('foo')
- end
-
- it "should use the GET http method" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = mock('mock http connection', :get => @mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_fetch('foo')
- end
-
- it "should use the appropriate remote server" do
- Net::HTTP.expects(:start).with {|host, port| host == @details[:host] }
- @searcher.network_fetch('foo')
- end
-
- it "should use the appropriate remote port" do
- Net::HTTP.expects(:start).with {|host, port| port == @details[:port] }
- @searcher.network_fetch('foo')
- end
-
- it "should use the provided path" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = stub('mock http connection')
- @mock_connection.expects(:get).with('/foo').returns(@mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_fetch('foo')
- end
-
- it "should return the results of the GET request" do
- @searcher.network_fetch('foo').should == 'result'
- end
+ before :each do
+ Net::HTTP.stubs(:start).returns('result')
+ @details = { :host => '127.0.0.1', :port => 34343 }
+ @searcher.stubs(:rest_connection_details).returns(@details)
+
+ @method = :network_fetch
+ @arguments = "foo"
+ end
+
+ it_should_behave_like "a REST http call"
+
+ it "should use the GET http method" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = mock('mock http connection', :get => @mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_fetch('foo')
+ end
+
+ it "should use the provided path" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = stub('mock http connection')
+ @mock_connection.expects(:get).with('/foo').returns(@mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_fetch('foo')
+ end
end
describe "when doing a network delete" do
- before :each do
- Net::HTTP.stubs(:start).returns('result')
- @details = { :host => '127.0.0.1', :port => 34343 }
- @searcher.stubs(:rest_connection_details).returns(@details)
- end
-
- it "should accept a path" do
- lambda { @search.network_delete('foo') }.should_not raise_error(ArgumentError)
- end
-
- it "should require a path" do
- lambda { @searcher.network_delete }.should raise_error(ArgumentError)
- end
-
- it "should look up connection details" do
- @searcher.expects(:rest_connection_details).returns(@details)
- @searcher.network_delete('foo')
- end
-
- it "should use the DELETE http method" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = mock('mock http connection', :delete => @mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_delete('foo')
- end
-
- it "should use the appropriate remote server" do
- Net::HTTP.expects(:start).with {|host, port| host == @details[:host] }
- @searcher.network_delete('foo')
- end
-
- it "should use the appropriate remote port" do
- Net::HTTP.expects(:start).with {|host, port| port == @details[:port] }
- @searcher.network_delete('foo')
- end
-
- it "should use the provided path" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = stub('mock http connection')
- @mock_connection.expects(:delete).with('/foo').returns(@mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_delete('foo')
- end
-
- it "should return the results of the DELETE request" do
- @searcher.network_delete('foo').should == 'result'
- end
+ before :each do
+ Net::HTTP.stubs(:start).returns('result')
+ @details = { :host => '127.0.0.1', :port => 34343 }
+ @searcher.stubs(:rest_connection_details).returns(@details)
+
+ @method = :network_delete
+ @arguments = "foo"
+ end
+
+ it_should_behave_like "a REST http call"
+
+ it "should use the DELETE http method" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = mock('mock http connection', :delete => @mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_delete('foo')
+ end
end
-
+
describe "when doing a network put" do
- before :each do
- Net::HTTP.stubs(:start).returns('result')
- @details = { :host => '127.0.0.1', :port => 34343 }
- @data = { :foo => 'bar' }
- @searcher.stubs(:rest_connection_details).returns(@details)
- end
-
- it "should accept a path and data" do
- lambda { @search.network_put('foo', @data) }.should_not raise_error(ArgumentError)
- end
-
- it "should require a path and data" do
- lambda { @searcher.network_put('foo') }.should raise_error(ArgumentError)
- end
-
- it "should look up connection details" do
- @searcher.expects(:rest_connection_details).returns(@details)
- @searcher.network_put('foo', @data)
- end
-
- it "should use the appropriate remote server" do
- Net::HTTP.expects(:start).with {|host, port| host == @details[:host] }
- @searcher.network_put('foo', @data)
- end
-
- it "should use the appropriate remote port" do
- Net::HTTP.expects(:start).with {|host, port| port == @details[:port] }
- @searcher.network_put('foo', @data)
- end
-
- it "should use the PUT http method" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = mock('mock http connection', :put => @mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_put('foo', @data)
- end
-
- it "should use the provided path" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = stub('mock http connection')
- @mock_connection.expects(:put).with {|path, data| path == '/foo' }.returns(@mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_put('foo', @data)
- end
-
- it "should use the provided data" do
- @mock_result = stub('mock result', :body => 'result')
- @mock_connection = stub('mock http connection')
- @mock_connection.expects(:put).with {|path, data| data == @data }.returns(@mock_result)
- @searcher.stubs(:network).yields(@mock_connection)
- @searcher.network_put('foo', @data)
- end
-
- it "should return the results of the PUT request" do
- @searcher.network_put('foo', @data).should == 'result'
- end
+ before :each do
+ Net::HTTP.stubs(:start).returns('result')
+ @details = { :host => '127.0.0.1', :port => 34343 }
+ @data = { :foo => 'bar' }
+ @searcher.stubs(:rest_connection_details).returns(@details)
+
+ @method = :network_put
+ @arguments = ["foo", @data]
+ end
+
+ it_should_behave_like "a REST http call"
+
+ it "should use the PUT http method" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = mock('mock http connection', :put => @mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_put('foo', @data)
+ end
+
+ it "should use the provided path" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = stub('mock http connection')
+ @mock_connection.expects(:put).with {|path, data| path == '/foo' }.returns(@mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_put('foo', @data)
+ end
+
+ it "should use the provided data" do
+ @mock_result = stub('mock result', :body => 'result')
+ @mock_connection = stub('mock http connection')
+ @mock_connection.expects(:put).with {|path, data| data == @data }.returns(@mock_result)
+ @searcher.stubs(:network).returns(@mock_connection)
+ @searcher.network_put('foo', @data)
+ end
end
describe "when doing a find" do
- before :each do
- @result = { :foo => 'bar'}.to_yaml
- @searcher.stubs(:network_fetch).returns(@result) # neuter the network connection
- @model.stubs(:from_yaml).returns(@instance)
-
- @request = stub 'request', :key => 'foo'
- end
-
- it "should look up the model instance over the network" do
- @searcher.expects(:network_fetch).returns(@result)
- @searcher.find(@request)
- end
-
- it "should look up the model instance using the named indirection" do
- @searcher.expects(:network_fetch).with {|path| path =~ %r{^#{@indirection.name.to_s}/} }.returns(@result)
- @searcher.find(@request)
- end
-
- it "should look up the model instance using the provided key" do
- @searcher.expects(:network_fetch).with {|path| path =~ %r{/foo$} }.returns(@result)
- @searcher.find(@request)
- end
-
- it "should deserialize result data to a Model instance" do
- @model.expects(:from_yaml)
- @searcher.find(@request)
- end
-
- it "should return the deserialized Model instance" do
- @searcher.find(@request).should == @instance
- end
-
- it "should return nil when deserialized model instance is nil" do
- @model.stubs(:from_yaml).returns(nil)
- @searcher.find(@request).should be_nil
- end
-
- it "should generate an error when result data deserializes improperly" do
- @model.stubs(:from_yaml).raises(ArgumentError)
- lambda { @searcher.find(@request) }.should raise_error(ArgumentError)
- end
-
- it "should generate an error when result data specifies an error" do
- @searcher.stubs(:network_fetch).returns(RuntimeError.new("bogus").to_yaml)
- lambda { @searcher.find(@request) }.should raise_error(RuntimeError)
- end
+ before :each do
+ @result = { :foo => 'bar'}.to_yaml
+ @searcher.stubs(:network_fetch).returns(@result) # neuter the network connection
+ @model.stubs(:from_yaml).returns(@instance)
+
+ @request = stub 'request', :key => 'foo'
+ end
+
+ it "should look up the model instance over the network" do
+ @searcher.expects(:network_fetch).returns(@result)
+ @searcher.find(@request)
+ end
+
+ it "should look up the model instance using the named indirection" do
+ @searcher.expects(:network_fetch).with {|path| path =~ %r{^#{@indirection.name.to_s}/} }.returns(@result)
+ @searcher.find(@request)
+ end
+
+ it "should look up the model instance using the provided key" do
+ @searcher.expects(:network_fetch).with {|path| path =~ %r{/foo$} }.returns(@result)
+ @searcher.find(@request)
+ end
+
+ it "should deserialize result data to a Model instance" do
+ @model.expects(:from_yaml)
+ @searcher.find(@request)
+ end
+
+ it "should return the deserialized Model instance" do
+ @searcher.find(@request).should == @instance
+ end
+
+ it "should return nil when deserialized model instance is nil" do
+ @model.stubs(:from_yaml).returns(nil)
+ @searcher.find(@request).should be_nil
+ end
+
+ it "should generate an error when result data deserializes improperly" do
+ @model.stubs(:from_yaml).raises(ArgumentError)
+ lambda { @searcher.find(@request) }.should raise_error(ArgumentError)
+ end
+
+ it "should generate an error when result data specifies an error" do
+ @searcher.stubs(:network_fetch).returns(RuntimeError.new("bogus").to_yaml)
+ lambda { @searcher.find(@request) }.should raise_error(RuntimeError)
+ end
end
describe "when doing a search" do
- before :each do
- @result = [1, 2].to_yaml
- @searcher.stubs(:network_fetch).returns(@result)
- @model.stubs(:from_yaml).returns(@instance)
-
- @request = stub 'request', :key => 'foo'
- end
-
- it "should look up the model data over the network" do
- @searcher.expects(:network_fetch).returns(@result)
- @searcher.search(@request)
- end
-
- it "should look up the model instance using the named indirection" do
- @searcher.expects(:network_fetch).with {|path| path =~ %r{^#{@indirection.name.to_s}s/} }.returns(@result)
- @searcher.search(@request)
- end
-
- it "should look up the model instance using the provided key" do
- @searcher.expects(:network_fetch).with {|path| path =~ %r{/foo$} }.returns(@result)
- @searcher.search(@request)
- end
-
- it "should deserialize result data into a list of Model instances" do
- @model.expects(:from_yaml).at_least(2)
- @searcher.search(@request)
- end
-
- it "should generate an error when result data deserializes improperly" do
- @model.stubs(:from_yaml).raises(ArgumentError)
- lambda { @searcher.search(@request) }.should raise_error(ArgumentError)
- end
-
- it "should generate an error when result data specifies an error" do
- @searcher.stubs(:network_fetch).returns(RuntimeError.new("bogus").to_yaml)
- lambda { @searcher.search(@request) }.should raise_error(RuntimeError)
- end
- end
-
+ before :each do
+ @result = [1, 2].to_yaml
+ @searcher.stubs(:network_fetch).returns(@result)
+ @model.stubs(:from_yaml).returns(@instance)
+
+ @request = stub 'request', :key => 'foo'
+ end
+
+ it "should look up the model data over the network" do
+ @searcher.expects(:network_fetch).returns(@result)
+ @searcher.search(@request)
+ end
+
+ it "should look up the model instance using the plural of the named indirection" do
+ @searcher.expects(:network_fetch).with {|path| path =~ %r{^#{@indirection.name.to_s}s/} }.returns(@result)
+ @searcher.search(@request)
+ end
+
+ it "should look up the model instance using the provided key" do
+ @searcher.expects(:network_fetch).with {|path| path =~ %r{/foo$} }.returns(@result)
+ @searcher.search(@request)
+ end
+
+ it "should deserialize result data into a list of Model instances" do
+ @model.expects(:from_yaml).at_least(2)
+ @searcher.search(@request)
+ end
+
+ it "should generate an error when result data deserializes improperly" do
+ @model.stubs(:from_yaml).raises(ArgumentError)
+ lambda { @searcher.search(@request) }.should raise_error(ArgumentError)
+ end
+
+ it "should generate an error when result data specifies an error" do
+ @searcher.stubs(:network_fetch).returns(RuntimeError.new("bogus").to_yaml)
+ lambda { @searcher.search(@request) }.should raise_error(RuntimeError)
+ end
+ end
+
describe "when doing a destroy" do
- before :each do
- @result = true.to_yaml
- @searcher.stubs(:network_delete).returns(@result) # neuter the network connection
- @model.stubs(:from_yaml).returns(@instance)
-
- @request = stub 'request', :key => 'foo'
- end
-
- it "should look up the model instance over the network" do
- @searcher.expects(:network_delete).returns(@result)
- @searcher.destroy(@request)
- end
-
- it "should look up the model instance using the named indirection" do
- @searcher.expects(:network_delete).with {|path| path =~ %r{^#{@indirection.name.to_s}/} }.returns(@result)
- @searcher.destroy(@request)
- end
-
- it "should look up the model instance using the provided key" do
- @searcher.expects(:network_delete).with {|path| path =~ %r{/foo$} }.returns(@result)
- @searcher.destroy(@request)
- end
-
- it "should deserialize result data" do
- YAML.expects(:load).with(@result)
- @searcher.destroy(@request)
- end
-
- it "should return deserialized result data" do
- @searcher.destroy(@request).should == true
- end
-
- it "should generate an error when result data specifies an error" do
- @searcher.stubs(:network_delete).returns(RuntimeError.new("bogus").to_yaml)
- lambda { @searcher.destroy(@request) }.should raise_error(RuntimeError)
- end
+ before :each do
+ @result = true.to_yaml
+ @searcher.stubs(:network_delete).returns(@result) # neuter the network connection
+ @model.stubs(:from_yaml).returns(@instance)
+
+ @request = stub 'request', :key => 'foo'
+ end
+
+ it "should look up the model instance over the network" do
+ @searcher.expects(:network_delete).returns(@result)
+ @searcher.destroy(@request)
+ end
+
+ it "should look up the model instance using the named indirection" do
+ @searcher.expects(:network_delete).with {|path| path =~ %r{^#{@indirection.name.to_s}/} }.returns(@result)
+ @searcher.destroy(@request)
+ end
+
+ it "should look up the model instance using the provided key" do
+ @searcher.expects(:network_delete).with {|path| path =~ %r{/foo$} }.returns(@result)
+ @searcher.destroy(@request)
+ end
+
+ it "should deserialize result data" do
+ YAML.expects(:load).with(@result)
+ @searcher.destroy(@request)
+ end
+
+ it "should return deserialized result data" do
+ @searcher.destroy(@request).should == true
+ end
+
+ it "should generate an error when result data specifies an error" do
+ @searcher.stubs(:network_delete).returns(RuntimeError.new("bogus").to_yaml)
+ lambda { @searcher.destroy(@request) }.should raise_error(RuntimeError)
+ end
end
describe "when doing a save" do
- before :each do
- @result = { :foo => 'bar'}.to_yaml
- @searcher.stubs(:network_put).returns(@result) # neuter the network connection
- @model.stubs(:from_yaml).returns(@instance)
-
- @request = stub 'request', :instance => @instance
- end
-
- it "should save the model instance over the network" do
- @searcher.expects(:network_put).returns(@result)
- @searcher.save(@request)
- end
-
- it "should save the model instance using the named indirection" do
- @searcher.expects(:network_put).with do |path, data|
- path =~ %r{^#{@indirection.name.to_s}/} and
- data == @instance.to_yaml
- end.returns(@result)
- @searcher.save(@request)
- end
-
- it "should deserialize result data to a Model instance" do
- @model.expects(:from_yaml)
- @searcher.save(@request)
- end
-
- it "should return the resulting deserialized Model instance" do
- @searcher.save(@request).should == @instance
- end
-
- it "should return nil when deserialized model instance is nil" do
- @model.stubs(:from_yaml).returns(nil)
- @searcher.save(@request).should be_nil
- end
-
- it "should generate an error when result data deserializes improperly" do
- @model.stubs(:from_yaml).raises(ArgumentError)
- lambda { @searcher.save(@request) }.should raise_error(ArgumentError)
- end
-
- it "should generate an error when result data specifies an error" do
- @searcher.stubs(:network_put).returns(RuntimeError.new("bogus").to_yaml)
- lambda { @searcher.save(@request) }.should raise_error(RuntimeError)
- end
+ before :each do
+ @result = { :foo => 'bar'}.to_yaml
+ @searcher.stubs(:network_put).returns(@result) # neuter the network connection
+ @model.stubs(:from_yaml).returns(@instance)
+
+ @request = stub 'request', :instance => @instance
+ end
+
+ it "should save the model instance over the network" do
+ @searcher.expects(:network_put).returns(@result)
+ @searcher.save(@request)
+ end
+
+ it "should save the model instance using the named indirection" do
+ @searcher.expects(:network_put).with do |path, data|
+ path =~ %r{^#{@indirection.name.to_s}/} and
+ data == @instance.to_yaml
+ end.returns(@result)
+ @searcher.save(@request)
+ end
+
+ it "should deserialize result data to a Model instance" do
+ @model.expects(:from_yaml)
+ @searcher.save(@request)
+ end
+
+ it "should return the resulting deserialized Model instance" do
+ @searcher.save(@request).should == @instance
+ end
+
+ it "should return nil when deserialized model instance is nil" do
+ @model.stubs(:from_yaml).returns(nil)
+ @searcher.save(@request).should be_nil
+ end
+
+ it "should generate an error when result data deserializes improperly" do
+ @model.stubs(:from_yaml).raises(ArgumentError)
+ lambda { @searcher.save(@request) }.should raise_error(ArgumentError)
+ end
+
+ it "should generate an error when result data specifies an error" do
+ @searcher.stubs(:network_put).returns(RuntimeError.new("bogus").to_yaml)
+ lambda { @searcher.save(@request) }.should raise_error(RuntimeError)
+ end
end
end
diff --git a/spec/unit/indirector/ssl_file.rb b/spec/unit/indirector/ssl_file.rb
new file mode 100755
index 000000000..864ba1420
--- /dev/null
+++ b/spec/unit/indirector/ssl_file.rb
@@ -0,0 +1,244 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-10.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/indirector/ssl_file'
+
+describe Puppet::Indirector::SslFile do
+ before do
+ @indirection = stub 'indirection', :name => :testing
+ Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection)
+ @file_class = Class.new(Puppet::Indirector::SslFile) do
+ def self.to_s
+ "Testing::Mytype"
+ end
+ end
+
+ @setting = :mydir
+ @file_class.store_in @setting
+ @path = "/my/directory"
+ Puppet.settings.stubs(:value).returns "stubbed_setting"
+ Puppet.settings.stubs(:value).with(@setting).returns(@path)
+ Puppet.settings.stubs(:value).with(:trace).returns(false)
+ end
+
+ it "should use :main and :ssl upon initialization" do
+ Puppet.settings.expects(:use).with(:main, :ssl)
+ @file_class.new
+ end
+
+ it "should return a nil collection directory if no directory setting has been provided" do
+ @file_class.store_in nil
+ @file_class.collection_directory.should be_nil
+ end
+
+ it "should return a nil file location if no location has been provided" do
+ @file_class.store_at nil
+ @file_class.file_location.should be_nil
+ end
+
+ it "should fail if no store directory or file location has been set" do
+ @file_class.store_in nil
+ @file_class.store_at nil
+ lambda { @file_class.new }.should raise_error(Puppet::DevError)
+ end
+
+ describe "when managing ssl files" do
+ before do
+ Puppet.settings.stubs(:use)
+ @searcher = @file_class.new
+
+ @cert = stub 'certificate', :name => "myname"
+ @certpath = File.join(@path, "myname" + ".pem")
+
+ @request = stub 'request', :key => @cert.name, :instance => @cert
+ end
+
+ it "should consider the file a ca file if the name is equal to what the SSL::Host class says is the CA name" do
+ Puppet::SSL::Host.expects(:ca_name).returns "amaca"
+ @searcher.should be_ca("amaca")
+ end
+
+ describe "when choosing the location for certificates" do
+ it "should set them at the ca setting's path if a ca setting is available and the name resolves to the CA name" do
+ @file_class.store_in nil
+ @file_class.store_at :mysetting
+ @file_class.store_ca_at :casetting
+
+ Puppet.settings.stubs(:value).with(:casetting).returns "/ca/file"
+
+ @searcher.expects(:ca?).with(@cert.name).returns true
+ @searcher.path(@cert.name).should == "/ca/file"
+ end
+
+ it "should set them at the file location if a file setting is available" do
+ @file_class.store_in nil
+ @file_class.store_at :mysetting
+
+ Puppet.settings.stubs(:value).with(:mysetting).returns "/some/file"
+
+ @searcher.path(@cert.name).should == "/some/file"
+ end
+
+ it "should set them in the setting directory, with the certificate name plus '.pem', if a directory setting is available" do
+ @searcher.path(@cert.name).should == @certpath
+ end
+ end
+
+ describe "when finding certificates on disk" do
+ describe "and no certificate is present" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns false
+ end
+
+ it "should return nil" do
+ @searcher.find(@request).should be_nil
+ end
+ end
+
+ describe "and a certificate is present" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns true
+ end
+
+ it "should return an instance of the model, which it should use to read the certificate" do
+ cert = mock 'cert'
+ model = mock 'model'
+ @file_class.stubs(:model).returns model
+
+ model.expects(:new).with("myname").returns cert
+ cert.expects(:read).with(@certpath)
+ @searcher.find(@request).should equal(cert)
+ end
+ end
+ end
+
+ describe "when saving certificates to disk" do
+ before do
+ FileTest.stubs(:directory?).returns true
+ FileTest.stubs(:writable?).returns true
+ end
+
+ it "should fail if the directory is absent" do
+ FileTest.expects(:directory?).with(File.dirname(@certpath)).returns false
+ lambda { @searcher.save(@request) }.should raise_error(Puppet::Error)
+ end
+
+ it "should fail if the directory is not writeable" do
+ FileTest.stubs(:directory?).returns true
+ FileTest.expects(:writable?).with(File.dirname(@certpath)).returns false
+ lambda { @searcher.save(@request) }.should raise_error(Puppet::Error)
+ end
+
+ it "should save to the path the output of converting the certificate to a string" do
+ fh = mock 'filehandle'
+ fh.expects(:print).with("mycert")
+
+ @searcher.stubs(:write).yields fh
+ @cert.expects(:to_s).returns "mycert"
+
+ @searcher.save(@request)
+ end
+
+ describe "and a directory setting is set" do
+ it "should open the file in write mode" do
+ @searcher.class.store_in @setting
+ fh = mock 'filehandle'
+ fh.stubs :print
+ File.expects(:open).with(@certpath, "w").yields(fh)
+
+ @searcher.save(@request)
+ end
+ end
+
+ describe "and a file location is set" do
+ it "should use the filehandle provided by the Settings" do
+ @searcher.class.store_at @setting
+
+ fh = mock 'filehandle'
+ fh.stubs :print
+ Puppet.settings.expects(:write).with(@setting).yields fh
+ @searcher.save(@request)
+ end
+ end
+
+ describe "and the name is the CA name and a ca setting is set" do
+ it "should use the filehandle provided by the Settings" do
+ @searcher.class.store_at @setting
+ @searcher.class.store_ca_at :castuff
+
+ fh = mock 'filehandle'
+ fh.stubs :print
+ Puppet.settings.expects(:write).with(:castuff).yields fh
+ @searcher.stubs(:ca?).returns true
+ @searcher.save(@request)
+ end
+ end
+ end
+
+ describe "when destroying certificates" do
+ describe "that do not exist" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns false
+ end
+
+ it "should return false" do
+ @searcher.destroy(@request).should be_false
+ end
+ end
+
+ describe "that exist" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns true
+ end
+
+ it "should unlink the certificate file" do
+ File.expects(:unlink).with(@certpath)
+ @searcher.destroy(@request)
+ end
+ end
+ end
+
+ describe "when searching for certificates" do
+ before do
+ @model = mock 'model'
+ @file_class.stubs(:model).returns @model
+ end
+ it "should return a certificate instance for all files that exist" do
+ Dir.expects(:entries).with(@path).returns %w{one.pem two.pem}
+
+ one = stub 'one', :read => nil
+ two = stub 'two', :read => nil
+
+ @model.expects(:new).with("one").returns one
+ @model.expects(:new).with("two").returns two
+
+ @searcher.search(@request).should == [one, two]
+ end
+
+ it "should read each certificate in using the model's :read method" do
+ Dir.expects(:entries).with(@path).returns %w{one.pem}
+
+ one = stub 'one'
+ one.expects(:read).with(File.join(@path, "one.pem"))
+
+ @model.expects(:new).with("one").returns one
+
+ @searcher.search(@request)
+ end
+
+ it "should skip any files that do not match /\.pem$/" do
+ Dir.expects(:entries).with(@path).returns %w{. .. one.pem}
+
+ one = stub 'one', :read => nil
+
+ @model.expects(:new).with("one").returns one
+
+ @searcher.search(@request)
+ end
+ end
+ end
+end
diff --git a/spec/unit/indirector/ssl_rsa/file.rb b/spec/unit/indirector/ssl_rsa/file.rb
deleted file mode 100755
index 76e5e3a94..000000000
--- a/spec/unit/indirector/ssl_rsa/file.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/env ruby
-#
-# Created by Luke Kanies on 2007-9-22.
-# Copyright (c) 2007. All rights reserved.
-
-require File.dirname(__FILE__) + '/../../../spec_helper'
-
-require 'puppet/sslcertificates/monkey_patch'
-require 'puppet/indirector/ssl_rsa/file'
-
-
-describe Puppet::Indirector::SslRsa::File do
-
- it "should be a subclass of the File terminus class" do
- Puppet::Indirector::SslRsa::File.superclass.should equal(Puppet::Indirector::File)
- end
-
- it "should have documentation" do
- Puppet::Indirector::SslRsa::File.doc.should be_instance_of(String)
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when choosing a path for a ca key" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
- @name = :ca
- end
-
- it "should use the cadir" do
- Puppet.settings.stubs(:value).with(:cadir).returns("/dir")
- @file.path(@name).should =~ /^\/dir/
- end
-
- it "should use 'ca_key.pem' as the file name" do
- @file.path(@name).should =~ /ca_key\.pem$/
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when choosing a path for a non-ca key" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
- @name = :publickey
- end
-
- it "should use the publickeydir" do
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @file.path(@name).should =~ /^\/dir/
- end
-
- it "should use the key name with the pem file extension" do
- @file.path(@name).should =~ /#{@name}\.pem$/
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when saving" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
-
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @key = stub "key", :name => "foo"
- end
-
- it "should store the rsa key to disk in pem format" do
- @key.expects(:to_pem).returns(:data)
- @path = "/dir/foo.pem"
- filehandle = mock "filehandle"
- File.expects(:open).with(@path, "w").yields(filehandle)
- filehandle.expects(:print).with(:data)
- @file.save(@key)
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when finding a key by name" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
-
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @name = "foo"
- end
-
- it "should return the key as a key object on success" do
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(true)
- File.stubs(:read).with(@path).returns(:data)
- OpenSSL::PKey::RSA.expects(:new).with(:data).returns(:mykey)
- @file.find(@name).should == :mykey
- end
-
- it "should return 'nil' on failure" do
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(false)
- @file.find(@name).should == nil
- end
-end
-
-describe Puppet::Indirector::SslRsa::File, " when removing a key" do
- before do
- @file = Puppet::Indirector::SslRsa::File.new
-
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @name = "foo"
- end
-
- it "should remove the key from disk and return true" do
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(true)
- File.stubs(:unlink).with(@path).returns(true)
- @file.destroy(@name).should == true
- end
-
- it "should return an exception on failure" do
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(false)
- @file.destroy(@name).should == nil
- end
-end
diff --git a/spec/unit/network/http/mongrel.rb b/spec/unit/network/http/mongrel.rb
index ccfca2f55..1f87fd943 100644
--- a/spec/unit/network/http/mongrel.rb
+++ b/spec/unit/network/http/mongrel.rb
@@ -23,7 +23,14 @@ describe Puppet::Network::HTTP::Mongrel, "when turning on listening" do
@mock_mongrel.stubs(:run)
@mock_mongrel.stubs(:register)
Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel)
- @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] }
+
+ @mock_puppet_mongrel = mock('puppet_mongrel')
+ Puppet::Network::HTTPServer::Mongrel.stubs(:new).returns(@mock_puppet_mongrel)
+
+ @listen_params = { :address => "127.0.0.1", :port => 31337,
+ :handlers => [ :node, :catalog ], :protocols => [ :rest, :xmlrpc ],
+ :xmlrpc_handlers => [ :status, :fileserver ]
+ }
end
it "should fail if already listening" do
@@ -63,18 +70,38 @@ describe Puppet::Network::HTTP::Mongrel, "when turning on listening" do
@server.should be_listening
end
- it "should instantiate a handler for each protocol+handler pair to configure web server routing" do
- @listen_params[:protocols].each do |protocol|
- @listen_params[:handlers].each do |handler|
- @mock_mongrel.expects(:register)
+ describe "when providing REST services" do
+ it "should instantiate a handler for each protocol+handler pair to configure web server routing" do
+ @listen_params[:protocols].each do |protocol|
+ @listen_params[:handlers].each do |handler|
+ @mock_mongrel.expects(:register)
+ end
end
+ @server.listen(@listen_params)
+ end
+
+ it "should use a Mongrel + REST class to configure Mongrel when REST services are requested" do
+ @server.expects(:class_for_protocol).with(:rest).at_least_once.returns(Puppet::Network::HTTP::MongrelREST)
+ @server.listen(@listen_params)
end
- @server.listen(@listen_params)
end
-
- it "should use a Mongrel + REST class to configure Mongrel when REST services are requested" do
- @server.expects(:class_for_protocol).with(:rest).at_least_once.returns(Puppet::Network::HTTP::MongrelREST)
- @server.listen(@listen_params)
+
+ describe "when providing XMLRPC services" do
+ it "should do nothing if no xmlrpc handlers have been provided" do
+ Puppet::Network::HTTPServer::Mongrel.expects(:new).never
+ @server.listen(@listen_params.merge(:xmlrpc_handlers => []))
+ end
+
+ it "should create an instance of the existing Mongrel http server with the right handlers" do
+ Puppet::Network::HTTPServer::Mongrel.expects(:new).with([:status, :master]).returns(@mock_puppet_mongrel)
+ @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master]))
+ end
+
+ it "should register the Mongrel server instance at /RPC2" do
+ @mock_mongrel.expects(:register).with("/RPC2", @mock_puppet_mongrel)
+
+ @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master]))
+ end
end
it "should fail if services from an unknown protocol are requested" do
diff --git a/spec/unit/network/http/webrick.rb b/spec/unit/network/http/webrick.rb
index 05ed2f0e2..6d006992c 100644
--- a/spec/unit/network/http/webrick.rb
+++ b/spec/unit/network/http/webrick.rb
@@ -18,18 +18,21 @@ describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do
[:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)}
WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick)
@server = Puppet::Network::HTTP::WEBrick.new
- @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] }
+ [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging
+ @listen_params = { :address => "127.0.0.1", :port => 31337,
+ :handlers => [ :node, :catalog ], :xmlrpc_handlers => [], :protocols => [ :rest ]
+ }
end
-
+
it "should fail if already listening" do
@server.listen(@listen_params)
Proc.new { @server.listen(@listen_params) }.should raise_error(RuntimeError)
end
-
+
it "should require at least one handler" do
Proc.new { @server.listen(@listen_params.delete_if {|k,v| :handlers == k}) }.should raise_error(ArgumentError)
end
-
+
it "should require at least one protocol" do
Proc.new { @server.listen(@listen_params.delete_if {|k,v| :protocols == k}) }.should raise_error(ArgumentError)
end
@@ -37,7 +40,7 @@ describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do
it "should require a listening address to be specified" do
Proc.new { @server.listen(@listen_params.delete_if {|k,v| :address == k})}.should raise_error(ArgumentError)
end
-
+
it "should require a listening port to be specified" do
Proc.new { @server.listen(@listen_params.delete_if {|k,v| :port == k})}.should raise_error(ArgumentError)
end
@@ -46,35 +49,107 @@ describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do
@mock_webrick.expects(:start)
@server.listen(@listen_params)
end
-
+
it "should tell webrick to listen on the specified address and port" do
WEBrick::HTTPServer.expects(:new).with {|args|
args[:Port] == 31337 and args[:BindAddress] == "127.0.0.1"
}.returns(@mock_webrick)
@server.listen(@listen_params)
end
-
+
+ it "should configure a logger for webrick" do
+ @server.expects(:setup_logger).returns(:Logger => :mylogger)
+
+ WEBrick::HTTPServer.expects(:new).with {|args|
+ args[:Logger] == :mylogger
+ }.returns(@mock_webrick)
+
+ @server.listen(@listen_params)
+ end
+
+ it "should configure SSL for webrick" do
+ @server.expects(:setup_ssl).returns(:Ssl => :testing, :Other => :yay)
+
+ WEBrick::HTTPServer.expects(:new).with {|args|
+ args[:Ssl] == :testing and args[:Other] == :yay
+ }.returns(@mock_webrick)
+
+ @server.listen(@listen_params)
+ end
+
it "should be listening" do
@server.listen(@listen_params)
@server.should be_listening
end
-
- it "should instantiate a handler for each protocol+handler pair to configure web server routing" do
- @listen_params[:protocols].each do |protocol|
- mock_handler = mock("handler instance for [#{protocol}]")
- mock_handler_class = mock("handler class for [#{protocol}]")
- @listen_params[:handlers].each do |handler|
- @mock_webrick.expects(:mount)
+
+ describe "when the REST protocol is requested" do
+ it "should use a WEBrick + REST class to configure WEBrick" do
+ Puppet::Network::HTTP::WEBrick.expects(:class_for_protocol).with(:rest).at_least_once
+ @server.listen(@listen_params.merge(:protocols => [:rest]))
+ end
+
+ it "should instantiate a handler for each protocol+handler pair to configure web server routing" do
+ @listen_params[:protocols].each do |protocol|
+ @listen_params[:handlers].each do |handler|
+ @mock_webrick.expects(:mount)
+ end
end
+ @server.listen(@listen_params)
end
- @server.listen(@listen_params)
end
- it "should use a WEBrick + REST class to configure WEBrick when REST services are requested" do
- Puppet::Network::HTTP::WEBrick.expects(:class_for_protocol).with(:rest).at_least_once
- @server.listen(@listen_params.merge(:protocols => [:rest]))
+ describe "when the XMLRPC protocol is requested" do
+ before do
+ @servlet = mock 'servlet'
+
+ Puppet::Network::XMLRPC::WEBrickServlet.stubs(:new).returns @servlet
+
+ @master_handler = mock('master_handler')
+ @file_handler = mock('file_handler')
+
+ @master = mock 'master'
+ @file = mock 'file'
+ @master_handler.stubs(:new).returns @master
+ @file_handler.stubs(:new).returns @file
+
+ Puppet::Network::Handler.stubs(:handler).with(:master).returns @master_handler
+ Puppet::Network::Handler.stubs(:handler).with(:fileserver).returns @file_handler
+ end
+
+ it "should do nothing if no xmlrpc handlers have been specified" do
+ Puppet::Network::Handler.expects(:handler).never
+
+ @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => []))
+ end
+
+ it "should look the handler classes up via their base class" do
+ Puppet::Network::Handler.expects(:handler).with(:master).returns @master_handler
+ Puppet::Network::Handler.expects(:handler).with(:fileserver).returns @file_handler
+
+ @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver]))
+ end
+
+ it "should create an instance for each requested xmlrpc handler" do
+ @master_handler.expects(:new).returns @master
+ @file_handler.expects(:new).returns @file
+
+ @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver]))
+ end
+
+ it "should create a webrick servlet with the xmlrpc handler instances" do
+ Puppet::Network::XMLRPC::WEBrickServlet.expects(:new).with([@master, @file]).returns @servlet
+
+ @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver]))
+ end
+
+ it "should mount the webrick servlet at /RPC2" do
+ @mock_webrick.stubs(:mount)
+ @mock_webrick.expects(:mount).with("/RPC2", @servlet)
+
+ @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver]))
+ end
end
-
+
it "should fail if services from an unknown protocol are requested" do
Proc.new { @server.listen(@listen_params.merge(:protocols => [ :foo ]))}.should raise_error
end
@@ -82,21 +157,21 @@ end
describe Puppet::Network::HTTP::WEBrick, "when looking up the class to handle a protocol" do
- it "should require a protocol" do
- lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol }.should raise_error(ArgumentError)
- end
-
- it "should accept a protocol" do
- lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("bob") }.should_not raise_error(ArgumentError)
- end
-
- it "should use a WEBrick + REST class when a REST protocol is specified" do
- Puppet::Network::HTTP::WEBrick.class_for_protocol("rest").should == Puppet::Network::HTTP::WEBrickREST
- end
-
- it "should fail when an unknown protocol is specified" do
- lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("abcdefg") }.should raise_error
- end
+ it "should require a protocol" do
+ lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol }.should raise_error(ArgumentError)
+ end
+
+ it "should accept a protocol" do
+ lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("bob") }.should_not raise_error(ArgumentError)
+ end
+
+ it "should use a WEBrick + REST class when a REST protocol is specified" do
+ Puppet::Network::HTTP::WEBrick.class_for_protocol("rest").should == Puppet::Network::HTTP::WEBrickREST
+ end
+
+ it "should fail when an unknown protocol is specified" do
+ lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("abcdefg") }.should raise_error
+ end
end
describe Puppet::Network::HTTP::WEBrick, "when turning off listening" do
@@ -105,22 +180,182 @@ describe Puppet::Network::HTTP::WEBrick, "when turning off listening" do
[:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)}
WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick)
@server = Puppet::Network::HTTP::WEBrick.new
+ [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging
@listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] }
end
-
+
it "should fail unless listening" do
Proc.new { @server.unlisten }.should raise_error(RuntimeError)
end
-
+
it "should order webrick server to stop" do
@mock_webrick.expects(:shutdown)
@server.listen(@listen_params)
@server.unlisten
end
-
+
it "should no longer be listening" do
@server.listen(@listen_params)
@server.unlisten
@server.should_not be_listening
end
end
+
+describe Puppet::Network::HTTP::WEBrick do
+ before do
+ @mock_webrick = stub('webrick', :[] => {})
+ [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)}
+ WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick)
+ @server = Puppet::Network::HTTP::WEBrick.new
+ end
+
+ describe "when configuring an http logger" do
+ before do
+ Puppet.settings.stubs(:value).returns "something"
+ Puppet.settings.stubs(:use)
+ @filehandle = stub 'handle', :fcntl => nil, :sync => nil
+
+ File.stubs(:open).returns @filehandle
+ end
+
+ it "should use the settings for :main, :ssl, and the process name" do
+ Puppet.settings.stubs(:value).with(:name).returns "myname"
+ Puppet.settings.expects(:use).with(:main, :ssl, "myname")
+
+ @server.setup_logger
+ end
+
+ it "should use the masterlog if the process name is 'puppetmasterd'" do
+ Puppet.settings.stubs(:value).with(:name).returns "puppetmasterd"
+ Puppet.settings.expects(:value).with(:masterhttplog).returns "/master/log"
+
+ File.expects(:open).with("/master/log", "a+").returns @filehandle
+
+ @server.setup_logger
+ end
+
+ it "should use the httplog if the process name is not 'puppetmasterd'" do
+ Puppet.settings.stubs(:value).with(:name).returns "other"
+ Puppet.settings.expects(:value).with(:httplog).returns "/other/log"
+
+ File.expects(:open).with("/other/log", "a+").returns @filehandle
+
+ @server.setup_logger
+ end
+
+ describe "and creating the logging filehandle" do
+ it "should set fcntl to 'Fcntl::F_SETFD, Fcntl::FD_CLOEXEC'" do
+ @filehandle.expects(:fcntl).with(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+
+ @server.setup_logger
+ end
+
+ it "should sync the filehandle" do
+ @filehandle.expects(:sync)
+
+ @server.setup_logger
+ end
+ end
+
+ it "should create a new WEBrick::Log instance with the open filehandle" do
+ WEBrick::Log.expects(:new).with(@filehandle)
+
+ @server.setup_logger
+ end
+
+ it "should set debugging if the current loglevel is :debug" do
+ Puppet::Util::Log.expects(:level).returns :debug
+
+ WEBrick::Log.expects(:new).with { |handle, debug| debug == WEBrick::Log::DEBUG }
+
+ @server.setup_logger
+ end
+
+ it "should return the logger as the main log" do
+ logger = mock 'logger'
+ WEBrick::Log.expects(:new).returns logger
+
+ @server.setup_logger[:Logger].should == logger
+ end
+
+ it "should return the logger as the access log using both the Common and Referer log format" do
+ logger = mock 'logger'
+ WEBrick::Log.expects(:new).returns logger
+
+ @server.setup_logger[:AccessLog].should == [
+ [logger, WEBrick::AccessLog::COMMON_LOG_FORMAT],
+ [logger, WEBrick::AccessLog::REFERER_LOG_FORMAT]
+ ]
+ end
+ end
+
+ describe "when configuring ssl" do
+ before do
+ @key = stub 'key', :content => "mykey"
+ @cert = stub 'cert', :content => "mycert"
+ @host = stub 'host', :key => @key, :certificate => @cert, :name => "yay", :ssl_store => "mystore"
+
+ Puppet::SSL::Certificate.stubs(:find).with('ca').returns @cert
+
+ Puppet::SSL::Host.stubs(:new).returns @host
+ end
+
+ it "should use the key from an SSL::Host instance created with the default name" do
+ Puppet::SSL::Host.expects(:new).returns @host
+ @host.expects(:key).returns @key
+
+ @server.setup_ssl[:SSLPrivateKey].should == "mykey"
+ end
+
+ it "should generate its files if no certificate can be found" do
+ @host.expects(:certificate).times(2).returns(nil).then.returns(@cert)
+
+ @host.expects(:generate)
+
+ @server.setup_ssl
+ end
+
+ it "should configure the certificate" do
+ @server.setup_ssl[:SSLCertificate].should == "mycert"
+ end
+
+ it "should fail if no CA certificate can be found" do
+ Puppet::SSL::Certificate.stubs(:find).with('ca').returns nil
+
+ lambda { @server.setup_ssl }.should raise_error(Puppet::Error)
+ end
+
+ it "should specify the path to the CA certificate" do
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:hostcrl).returns 'false'
+ Puppet.settings.stubs(:value).with(:localcacert).returns '/ca/crt'
+
+ @server.setup_ssl[:SSLCACertificateFile].should == "/ca/crt"
+ end
+
+ it "should start ssl immediately" do
+ @server.setup_ssl[:SSLStartImmediately].should be_true
+ end
+
+ it "should enable ssl" do
+ @server.setup_ssl[:SSLEnable].should be_true
+ end
+
+ it "should configure the verification method as 'OpenSSL::SSL::VERIFY_PEER'" do
+ @server.setup_ssl[:SSLVerifyClient].should == OpenSSL::SSL::VERIFY_PEER
+ end
+
+ it "should add an x509 store" do
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:hostcrl).returns '/my/crl'
+
+ @host.expects(:ssl_store).returns "mystore"
+
+ @server.setup_ssl[:SSLCertificateStore].should == "mystore"
+ end
+
+ it "should set the certificate name to 'nil'" do
+ @server.setup_ssl[:SSLCertName].should be_nil
+ end
+ end
+end
diff --git a/spec/unit/network/http_pool.rb b/spec/unit/network/http_pool.rb
index 3c52c8613..dd8bed54c 100755
--- a/spec/unit/network/http_pool.rb
+++ b/spec/unit/network/http_pool.rb
@@ -6,105 +6,28 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/network/http_pool'
-describe Puppet::Network::HttpPool, " when adding certificate information to http instances" do
- before do
- @http = mock 'http'
- [:cert_store=, :verify_mode=, :ca_file=, :cert=, :key=].each { |m| @http.stubs(m) }
- @store = stub 'store'
- [:add_file,:purpose=].each { |m| @store.stubs(m) }
+describe Puppet::Network::HttpPool do
+ after do
+ Puppet::Util::Cacher.invalidate
+ Puppet::Network::HttpPool.clear_http_instances
+ Puppet::Network::HttpPool.instance_variable_set("@ssl_host", nil)
end
it "should have keep-alive disabled" do
Puppet::Network::HttpPool::HTTP_KEEP_ALIVE.should be_false
end
- it "should do nothing if no certificate is available" do
- Puppet::Network::HttpPool.expects(:read_cert).returns(false)
- @http.expects(:cert=).never
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should add a certificate store" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
- @http.expects(:cert_store=).with(@store)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should add the local CA cert to the certificate store" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- OpenSSL::X509::Store.expects(:new).returns(@store)
- Puppet.settings.stubs(:value).with(:localcacert).returns("/some/file")
- Puppet.settings.stubs(:value).with(:localcacert).returns("/some/file")
- @store.expects(:add_file).with("/some/file")
-
- Puppet::Network::HttpPool.stubs(:key).returns(:whatever)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should set the purpose of the cert store to OpenSSL::X509::PURPOSE_SSL_CLIENT" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @store.expects(:purpose=).with(OpenSSL::X509::PURPOSE_SSL_CLIENT)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should add the client certificate" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:cert).returns(:mycert)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @http.expects(:cert=).with(:mycert)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should add the client key" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @http.expects(:key=).with(:mykey)
-
- Puppet::Network::HttpPool.cert_setup(@http)
+ it "should use an SSL::Host instance to get its certificate information" do
+ host = mock 'host'
+ Puppet::SSL::Host.expects(:new).with().returns host
+ Puppet::Network::HttpPool.ssl_host.should equal(host)
end
- it "should set the verify mode to OpenSSL::SSL::VERIFY_PEER" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet::Network::HttpPool.stubs(:key).returns(:mykey)
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @http.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should set the ca file" do
- Puppet::Network::HttpPool.stubs(:read_cert).returns(true)
- Puppet.settings.stubs(:value).with(:localcacert).returns("/some/file")
- OpenSSL::X509::Store.expects(:new).returns(@store)
-
- @http.expects(:ca_file=).with("/some/file")
-
- Puppet::Network::HttpPool.stubs(:key).returns(:whatever)
-
- Puppet::Network::HttpPool.cert_setup(@http)
- end
-
- it "should set up certificate information when creating http instances" do
- Puppet::Network::HttpPool.expects(:cert_setup).with { |i| i.is_a?(Net::HTTP) }
- Puppet::Network::HttpPool.http_instance("one", "two")
- end
-
- after do
- Puppet::Network::HttpPool.clear_http_instances
+ it "should reuse the same host instance" do
+ host = mock 'host'
+ Puppet::SSL::Host.expects(:new).with().once.returns host
+ Puppet::Network::HttpPool.ssl_host.should equal(host)
+ Puppet::Network::HttpPool.ssl_host.should equal(host)
end
describe "when managing http instances" do
@@ -115,7 +38,7 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt
end
before do
- # All of hte cert stuff is tested elsewhere
+ # All of the cert stuff is tested elsewhere
Puppet::Network::HttpPool.stubs(:cert_setup)
end
@@ -152,7 +75,7 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt
Puppet::Network::HttpPool.http_instance("me", 54321).open_timeout.should == 120
end
- describe "when http keep-alive is enabled" do
+ describe "and http keep-alive is enabled" do
before do
Puppet::Network::HttpPool.stubs(:keep_alive?).returns true
end
@@ -201,9 +124,19 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt
one.expects(:finish).never
Puppet::Network::HttpPool.clear_http_instances
end
+
+ it "should reset its ssl host when clearing the cache" do
+ stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120, :http_enable_post_connection_check => true, :certname => "a"
+ one = Puppet::Network::HttpPool.http_instance("me", 54321)
+ one.expects(:started?).returns(false)
+ one.expects(:finish).never
+ id = Puppet::Network::HttpPool.ssl_host.object_id
+ Puppet::Network::HttpPool.clear_http_instances
+ Puppet::Network::HttpPool.ssl_host.object_id.should_not == id
+ end
end
- describe "when http keep-alive is disabled" do
+ describe "and http keep-alive is disabled" do
before do
Puppet::Network::HttpPool.stubs(:keep_alive?).returns false
end
@@ -215,26 +148,73 @@ describe Puppet::Network::HttpPool, " when adding certificate information to htt
end
end
- # We mostly have to do this for testing, since in real life people
- # won't change certs within a single process.
- it "should remove its loaded certificate when clearing the cache" do
- Puppet::Network::HttpPool.instance_variable_set("@cert", :yay)
+ after do
Puppet::Network::HttpPool.clear_http_instances
- # Can't use the accessor, because it will read the cert in
- Puppet::Network::HttpPool.instance_variable_get("@cert").should be_nil
end
+ end
- # We mostly have to do this for testing, since in real life people
- # won't change certs within a single process.
- it "should remove its loaded key when clearing the cache" do
- Puppet::Network::HttpPool.instance_variable_set("@key", :yay)
- Puppet::Network::HttpPool.clear_http_instances
- # Can't use the accessor, because it will read the cert in
- Puppet::Network::HttpPool.instance_variable_get("@key").should be_nil
+ describe "when adding certificate information to http instances" do
+ before do
+ @http = mock 'http'
+ [:cert_store=, :verify_mode=, :ca_file=, :cert=, :key=].each { |m| @http.stubs(m) }
+ @store = stub 'store'
+
+ @cert = stub 'cert', :content => "real_cert"
+ @key = stub 'key', :content => "real_key"
+ @host = stub 'host', :certificate => @cert, :key => @key, :ssl_store => @store
+
+ Puppet[:confdir] = "/sometthing/else"
+ Puppet.settings.stubs(:value).returns "/some/file"
+ Puppet.settings.stubs(:value).with(:hostcert).returns "/host/cert"
+
+ FileTest.stubs(:exist?).with("/host/cert").returns true
+
+ Puppet::Network::HttpPool.stubs(:ssl_host).returns @host
end
- after do
- Puppet::Network::HttpPool.clear_http_instances
+ it "should do nothing if no certificate is on disk" do
+ FileTest.expects(:exist?).with("/host/cert").returns false
+ @http.expects(:cert=).never
+ Puppet::Network::HttpPool.cert_setup(@http)
+ end
+
+ it "should add a certificate store from the ssl host" do
+ @http.expects(:cert_store=).with(@store)
+
+ Puppet::Network::HttpPool.cert_setup(@http)
+ end
+
+ it "should add the client certificate" do
+ @http.expects(:cert=).with("real_cert")
+
+ Puppet::Network::HttpPool.cert_setup(@http)
+ end
+
+ it "should add the client key" do
+ @http.expects(:key=).with("real_key")
+
+ Puppet::Network::HttpPool.cert_setup(@http)
+ end
+
+ it "should set the verify mode to OpenSSL::SSL::VERIFY_PEER" do
+ @http.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
+
+ Puppet::Network::HttpPool.cert_setup(@http)
+ end
+
+ it "should set the ca file" do
+ Puppet.settings.stubs(:value).returns "/some/file"
+ FileTest.stubs(:exist?).with(Puppet[:hostcert]).returns true
+
+ Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert/file"
+ @http.expects(:ca_file=).with("/ca/cert/file")
+
+ Puppet::Network::HttpPool.cert_setup(@http)
+ end
+
+ it "should set up certificate information when creating http instances" do
+ Puppet::Network::HttpPool.expects(:cert_setup).with { |i| i.is_a?(Net::HTTP) }
+ Puppet::Network::HttpPool.http_instance("one", "two")
end
end
end
diff --git a/spec/unit/network/server.rb b/spec/unit/network/server.rb
index 4e47c22fd..5332964c6 100644
--- a/spec/unit/network/server.rb
+++ b/spec/unit/network/server.rb
@@ -6,311 +6,527 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/network/server'
-describe Puppet::Network::Server, "when initializing" do
+describe Puppet::Network::Server do
before do
@mock_http_server_class = mock('http server class')
- Puppet.stubs(:[]).with(:servertype).returns(:suparserver)
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).with(:name).returns("me")
+ Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver)
Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class)
- end
-
- it "should allow specifying a listening address" do
- Puppet.stubs(:[]).with(:masterport).returns('')
- @server = Puppet::Network::Server.new(:address => "127.0.0.1")
- @server.address.should == "127.0.0.1"
+ Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver)
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
end
- it "should allow specifying a listening port" do
- Puppet.stubs(:[]).with(:bindaddress).returns('')
- @server = Puppet::Network::Server.new(:port => 31337)
- @server.port.should == 31337
- end
-
- it "should use the Puppet configurator to find a default listening address" do
- Puppet.stubs(:[]).with(:masterport).returns('')
- Puppet.expects(:[]).with(:bindaddress).returns("10.0.0.1")
- @server = Puppet::Network::Server.new
- @server.address.should == "10.0.0.1"
- end
+ describe "when initializing" do
+ before do
+ Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
+ Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler')
+ end
- it "should use the Puppet configurator to find a default listening port" do
- Puppet.stubs(:[]).with(:bindaddress).returns('')
- Puppet.expects(:[]).with(:masterport).returns(6667)
- @server = Puppet::Network::Server.new
- @server.port.should == 6667
- end
+ it "should allow specifying a listening address" do
+ Puppet.settings.stubs(:value).with(:masterport).returns('')
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1")
+ @server.address.should == "127.0.0.1"
+ end
- it "should fail to initialize if no listening address can be found" do
- Puppet.stubs(:[]).with(:masterport).returns(6667)
- Puppet.stubs(:[]).with(:bindaddress).returns(nil)
- Proc.new { Puppet::Network::Server.new }.should raise_error(ArgumentError)
- end
-
- it "should fail to initialize if no listening port can be found" do
- Puppet.stubs(:[]).with(:bindaddress).returns("127.0.0.1")
- Puppet.stubs(:[]).with(:masterport).returns(nil)
- Proc.new { Puppet::Network::Server.new }.should raise_error(ArgumentError)
- end
+ it "should allow specifying a listening port" do
+ Puppet.settings.stubs(:value).with(:bindaddress).returns('')
+ @server = Puppet::Network::Server.new(:port => 31337)
+ @server.port.should == 31337
+ end
- it "should use the Puppet configurator to determine which HTTP server will be used to provide access to clients" do
- Puppet.expects(:[]).with(:servertype).returns(:suparserver)
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
- @server.server_type.should == :suparserver
- end
-
- it "should fail to initialize if there is no HTTP server known to the Puppet configurator" do
- Puppet.expects(:[]).with(:servertype).returns(nil)
- Proc.new { Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337) }.should raise_error
- end
-
- it "should ask the Puppet::Network::HTTP class to fetch the proper HTTP server class" do
- Puppet::Network::HTTP.expects(:server_class_by_type).with(:suparserver).returns(@mock_http_server_class)
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
- end
-
- it "should fail if the HTTP server class is unknown" do
- Puppet::Network::HTTP.stubs(:server_class_by_type).returns(nil)
- Proc.new { Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337) }.should raise_error(ArgumentError)
- end
-
- it "should allow registering indirections" do
- @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337, :handlers => [ :foo, :bar, :baz])
- Proc.new { @server.unregister(:foo, :bar, :baz) }.should_not raise_error
- end
-
- it "should not be listening after initialization" do
- Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337).should_not be_listening
- end
-end
+ it "should use the Puppet configurator to find a default listening address" do
+ Puppet.settings.stubs(:value).with(:masterport).returns('')
+ Puppet.settings.expects(:value).with(:bindaddress).returns("10.0.0.1")
+ @server = Puppet::Network::Server.new
+ @server.address.should == "10.0.0.1"
+ end
-describe Puppet::Network::Server, "in general" do
- before 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)
- end
-
- it "should allow registering an indirection for client access by specifying its indirection name" do
- Proc.new { @server.register(:foo) }.should_not raise_error
- end
-
- it "should require at least one indirection name when registering indirections for client access" do
- Proc.new { @server.register }.should raise_error(ArgumentError)
- end
-
- it "should allow for numerous indirections to be registered at once for client access" do
- Proc.new { @server.register(:foo, :bar, :baz) }.should_not raise_error
- end
+ it "should use the Puppet configurator to find a default listening port" do
+ Puppet.settings.stubs(:value).with(:bindaddress).returns('')
+ Puppet.settings.expects(:value).with(:masterport).returns(6667)
+ @server = Puppet::Network::Server.new
+ @server.port.should == 6667
+ end
+
+ it "should fail to initialize if no listening address can be found" do
+ Puppet.settings.stubs(:value).with(:masterport).returns(6667)
+ Puppet.settings.stubs(:value).with(:bindaddress).returns(nil)
+ lambda { Puppet::Network::Server.new }.should raise_error(ArgumentError)
+ end
+
+ it "should fail to initialize if no listening port can be found" do
+ Puppet.settings.stubs(:value).with(:bindaddress).returns("127.0.0.1")
+ Puppet.settings.stubs(:value).with(:masterport).returns(nil)
+ lambda { Puppet::Network::Server.new }.should raise_error(ArgumentError)
+ end
+
+ it "should use the Puppet configurator to determine which HTTP server will be used to provide access to clients" do
+ Puppet.settings.expects(:value).with(:servertype).returns(:suparserver)
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
+ @server.server_type.should == :suparserver
+ end
- it "should allow the use of indirection names to specify which indirections are to be no longer accessible to clients" do
- @server.register(:foo)
- Proc.new { @server.unregister(:foo) }.should_not raise_error
+ it "should fail to initialize if there is no HTTP server known to the Puppet configurator" do
+ Puppet.settings.expects(:value).with(:servertype).returns(nil)
+ lambda { Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337) }.should raise_error
+ end
+
+ it "should ask the Puppet::Network::HTTP class to fetch the proper HTTP server class" do
+ Puppet::Network::HTTP.expects(:server_class_by_type).with(:suparserver).returns(@mock_http_server_class)
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
+ end
+
+ it "should fail if the HTTP server class is unknown" do
+ Puppet::Network::HTTP.stubs(:server_class_by_type).returns(nil)
+ lambda { Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337) }.should raise_error(ArgumentError)
+ end
+
+ it "should allow registering REST handlers" do
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337, :handlers => [ :foo, :bar, :baz])
+ lambda { @server.unregister(:foo, :bar, :baz) }.should_not raise_error
+ end
+
+ it "should allow registering XMLRPC handlers" do
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz])
+ lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should_not raise_error
+ end
+
+ it "should not be listening after initialization" do
+ Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337).should_not be_listening
+ end
+
+ it "should use the :main setting section" do
+ Puppet.settings.expects(:use).with { |args| args.include?(:main) }
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz])
+ end
+
+ it "should use the Puppet[:name] setting section" do
+ Puppet.settings.expects(:value).with(:name).returns "me"
+ Puppet.settings.expects(:use).with { |args| args.include?("me") }
+
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz])
+ end
end
- it "should leave other indirections accessible to clients when turning off indirections" do
- @server.register(:foo, :bar)
- @server.unregister(:foo)
- Proc.new { @server.unregister(:bar)}.should_not raise_error
+ # We don't test the method, because it's too much of a Unix-y pain.
+ it "should be able to daemonize" do
+ @server.should respond_to(:daemonize)
end
-
- it "should allow specifying numerous indirections which are to be no longer accessible to clients" do
- @server.register(:foo, :bar)
- Proc.new { @server.unregister(:foo, :bar) }.should_not raise_error
+
+ describe "when being started" do
+ before do
+ @server.stubs(:listen)
+ @server.stubs(:create_pidfile)
+ end
+
+ it "should listen" do
+ @server.expects(:listen)
+ @server.start
+ end
+
+ it "should create its PID file" do
+ @server.expects(:create_pidfile)
+ @server.start
+ end
end
-
- it "should not turn off any indirections if given unknown indirection names to turn off" do
- @server.register(:foo, :bar)
- Proc.new { @server.unregister(:foo, :bar, :baz) }.should raise_error(ArgumentError)
- Proc.new { @server.unregister(:foo, :bar) }.should_not raise_error
+
+ describe "when being stopped" do
+ before do
+ @server.stubs(:unlisten)
+ @server.stubs(:remove_pidfile)
+ end
+
+ it "should unlisten" do
+ @server.expects(:unlisten)
+ @server.stop
+ end
+
+ it "should remove its PID file" do
+ @server.expects(:remove_pidfile)
+ @server.stop
+ end
end
-
- it "should not allow turning off unknown indirection names" do
- @server.register(:foo, :bar)
- Proc.new { @server.unregister(:baz) }.should raise_error(ArgumentError)
+
+ describe "when creating its pidfile" do
+ it "should use an exclusive mutex" do
+ Puppet.settings.expects(:value).with(:name).returns "me"
+
+ sync = mock 'sync'
+ Puppet::Util.expects(:sync).with("me").returns sync
+
+ sync.expects(:synchronize).with(Sync::EX)
+ @server.create_pidfile
+ end
+
+ it "should lock the pidfile using the Pidlock class" do
+ pidfile = mock 'pidfile'
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.expects(:value).with(:pidfile).returns "/my/file"
+
+ Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile
+
+ pidfile.expects(:lock).returns true
+ @server.create_pidfile
+ end
+
+ it "should fail if it cannot lock" do
+ pidfile = mock 'pidfile'
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file"
+
+ Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile
+
+ pidfile.expects(:lock).returns false
+
+ lambda { @server.create_pidfile }.should raise_error
+ end
end
-
- it "should disable client access immediately when turning off indirections" do
- @server.register(:foo, :bar)
- @server.unregister(:foo)
- Proc.new { @server.unregister(:foo) }.should raise_error(ArgumentError)
+
+ describe "when removing its pidfile" do
+ it "should use an exclusive mutex" do
+ Puppet.settings.expects(:value).with(:name).returns "me"
+
+ sync = mock 'sync'
+ Puppet::Util.expects(:sync).with("me").returns sync
+
+ sync.expects(:synchronize).with(Sync::EX)
+ @server.remove_pidfile
+ end
+
+ it "should do nothing if the pidfile is not present" do
+ pidfile = mock 'pidfile', :locked? => false
+ Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file"
+
+ pidfile.expects(:unlock).never
+ @server.remove_pidfile
+ end
+
+ it "should unlock the pidfile using the Pidlock class" do
+ pidfile = mock 'pidfile', :locked? => true
+ Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile
+ pidfile.expects(:unlock).returns true
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file"
+
+ @server.remove_pidfile
+ end
+
+ it "should warn if it cannot remove the pidfile" do
+ pidfile = mock 'pidfile', :locked? => true
+ Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile
+ pidfile.expects(:unlock).returns false
+
+ Puppet.settings.stubs(:value).with(:name).returns "eh"
+ Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file"
+
+ Puppet.expects :err
+ @server.remove_pidfile
+ end
end
-
- it "should allow turning off all indirections at once" do
- @server.register(:foo, :bar)
- @server.unregister
- [ :foo, :bar, :baz].each do |indirection|
- Proc.new { @server.unregister(indirection) }.should raise_error(ArgumentError)
+
+ describe "when managing indirection registrations" do
+ before do
+ Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
+ end
+
+ it "should allow registering an indirection for client access by specifying its indirection name" do
+ lambda { @server.register(:foo) }.should_not raise_error
+ end
+
+ it "should require that the indirection be valid" do
+ Puppet::Indirector::Indirection.expects(:model).with(:foo).returns nil
+ lambda { @server.register(:foo) }.should raise_error(ArgumentError)
+ end
+
+ it "should require at least one indirection name when registering indirections for client access" do
+ lambda { @server.register }.should raise_error(ArgumentError)
+ end
+
+ it "should allow for numerous indirections to be registered at once for client access" do
+ lambda { @server.register(:foo, :bar, :baz) }.should_not raise_error
+ end
+
+ it "should allow the use of indirection names to specify which indirections are to be no longer accessible to clients" do
+ @server.register(:foo)
+ lambda { @server.unregister(:foo) }.should_not raise_error
+ end
+
+ it "should leave other indirections accessible to clients when turning off indirections" do
+ @server.register(:foo, :bar)
+ @server.unregister(:foo)
+ lambda { @server.unregister(:bar)}.should_not raise_error
+ end
+
+ it "should allow specifying numerous indirections which are to be no longer accessible to clients" do
+ @server.register(:foo, :bar)
+ lambda { @server.unregister(:foo, :bar) }.should_not raise_error
+ end
+
+ it "should not turn off any indirections if given unknown indirection names to turn off" do
+ @server.register(:foo, :bar)
+ lambda { @server.unregister(:foo, :bar, :baz) }.should raise_error(ArgumentError)
+ lambda { @server.unregister(:foo, :bar) }.should_not raise_error
+ end
+
+ it "should not allow turning off unknown indirection names" do
+ @server.register(:foo, :bar)
+ lambda { @server.unregister(:baz) }.should raise_error(ArgumentError)
+ end
+
+ it "should disable client access immediately when turning off indirections" do
+ @server.register(:foo, :bar)
+ @server.unregister(:foo)
+ lambda { @server.unregister(:foo) }.should raise_error(ArgumentError)
+ end
+
+ it "should allow turning off all indirections at once" do
+ @server.register(:foo, :bar)
+ @server.unregister
+ [ :foo, :bar, :baz].each do |indirection|
+ lambda { @server.unregister(indirection) }.should raise_error(ArgumentError)
+ end
end
end
-
+
it "should provide a means of determining whether it is listening" do
@server.should respond_to(:listening?)
end
-
+
it "should provide a means of determining which HTTP server will be used to provide access to clients" do
@server.server_type.should == :suparserver
end
-
- it "should allow for multiple configurations, each handling different indirections" do
- @server2 = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
- @server.register(:foo, :bar)
- @server2.register(:foo, :xyzzy)
- @server.unregister(:foo, :bar)
- @server2.unregister(:foo, :xyzzy)
- Proc.new { @server.unregister(:xyzzy) }.should raise_error(ArgumentError)
- Proc.new { @server2.unregister(:bar) }.should raise_error(ArgumentError)
- end
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 ]
+
+ it "should set the protocols to :rest and :xmlrpc" do
+ @server.protocols.should == [ :rest, :xmlrpc ]
end
-
+
it "should provide a means of determining the listening address" do
@server.address.should == "127.0.0.1"
end
-
+
it "should provide a means of determining the listening port" do
@server.port.should == 31337
end
-end
-describe Puppet::Network::Server, "when listening is off" do
- before 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)
- @mock_http_server = mock('http server')
- @mock_http_server.stubs(:listen)
- @server.stubs(:http_server).returns(@mock_http_server)
- end
+ it "should allow for multiple configurations, each handling different indirections" do
+ Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
- it "should indicate that it is not listening" do
- @server.should_not be_listening
+ @server2 = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337)
+ @server.register(:foo, :bar)
+ @server2.register(:foo, :xyzzy)
+ @server.unregister(:foo, :bar)
+ @server2.unregister(:foo, :xyzzy)
+ lambda { @server.unregister(:xyzzy) }.should raise_error(ArgumentError)
+ lambda { @server2.unregister(:bar) }.should raise_error(ArgumentError)
end
-
- it "should not allow listening to be turned off" do
- Proc.new { @server.unlisten }.should raise_error(RuntimeError)
- end
-
- it "should allow listening to be turned on" do
- Proc.new { @server.listen }.should_not raise_error
- end
-
-end
-describe Puppet::Network::Server, "when listening is on" do
- before 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)
- @mock_http_server = mock('http server')
- @mock_http_server.stubs(:listen)
- @mock_http_server.stubs(:unlisten)
- @server.stubs(:http_server).returns(@mock_http_server)
- @server.listen
- end
-
- it "should indicate that listening is turned off" do
- @server.should be_listening
- end
-
- it "should not allow listening to be turned on" do
- Proc.new { @server.listen }.should raise_error(RuntimeError)
- end
-
- it "should allow listening to be turned off" do
- Proc.new { @server.unlisten }.should_not raise_error
- end
-end
-
-describe Puppet::Network::Server, "when listening is being turned on" do
- before 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, :handlers => [:node])
- @mock_http_server = mock('http server')
- @mock_http_server.stubs(:listen)
- end
+ describe "when managing xmlrpc registrations" do
+ before do
+ Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler')
+ end
- 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 allow registering an xmlrpc handler by specifying its namespace" do
+ lambda { @server.register_xmlrpc(:foo) }.should_not raise_error
+ end
- it "should cause the HTTP server to listen" do
- @server.stubs(:http_server).returns(@mock_http_server)
- @mock_http_server.expects(:listen)
- @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
+ it "should require that the xmlrpc namespace be valid" do
+ Puppet::Network::Handler.stubs(:handler).returns nil
+
+ lambda { @server.register_xmlrpc(:foo) }.should raise_error(ArgumentError)
+ end
+
+ it "should require at least one namespace" do
+ lambda { @server.register_xmlrpc() }.should raise_error(ArgumentError)
+ end
+
+ it "should allow multiple namespaces to be registered at once" do
+ lambda { @server.register_xmlrpc(:foo, :bar) }.should_not raise_error
+ end
+
+ it "should allow the use of namespaces to specify which are no longer accessible to clients" do
+ @server.register_xmlrpc(:foo, :bar)
+ end
+
+ it "should leave other namespaces accessible to clients when turning off xmlrpc namespaces" do
+ @server.register_xmlrpc(:foo, :bar)
+ @server.unregister_xmlrpc(:foo)
+ lambda { @server.unregister_xmlrpc(:bar)}.should_not raise_error
+ end
+
+ it "should allow specifying numerous namespaces which are to be no longer accessible to clients" do
+ @server.register_xmlrpc(:foo, :bar)
+ lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error
+ end
+
+ it "should not turn off any indirections if given unknown namespaces to turn off" do
+ @server.register_xmlrpc(:foo, :bar)
+ lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should raise_error(ArgumentError)
+ lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error
+ end
+
+ it "should not allow turning off unknown namespaces" do
+ @server.register_xmlrpc(:foo, :bar)
+ lambda { @server.unregister_xmlrpc(:baz) }.should raise_error(ArgumentError)
+ end
+
+ it "should disable client access immediately when turning off namespaces" do
+ @server.register_xmlrpc(:foo, :bar)
+ @server.unregister_xmlrpc(:foo)
+ lambda { @server.unregister_xmlrpc(:foo) }.should raise_error(ArgumentError)
+ end
+
+ it "should allow turning off all namespaces at once" do
+ @server.register_xmlrpc(:foo, :bar)
+ @server.unregister_xmlrpc
+ [ :foo, :bar, :baz].each do |indirection|
+ lambda { @server.unregister_xmlrpc(indirection) }.should raise_error(ArgumentError)
+ end
+ end
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
+
+ describe "when listening is off" do
+ before do
+ @mock_http_server = mock('http server')
+ @mock_http_server.stubs(:listen)
+ @server.stubs(:http_server).returns(@mock_http_server)
+ end
+
+ it "should indicate that it is not listening" do
+ @server.should_not be_listening
+ end
+
+ it "should not allow listening to be turned off" do
+ lambda { @server.unlisten }.should raise_error(RuntimeError)
+ end
+
+ it "should allow listening to be turned on" do
+ lambda { @server.listen }.should_not raise_error
+ end
+
end
-end
-describe Puppet::Network::Server, "when listening is being turned off" do
- before 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)
- @mock_http_server = mock('http server')
- @mock_http_server.stubs(:listen)
- @server.stubs(:http_server).returns(@mock_http_server)
- @server.listen
+ describe "when listening is on" do
+ before do
+ @mock_http_server = mock('http server')
+ @mock_http_server.stubs(:listen)
+ @mock_http_server.stubs(:unlisten)
+ @server.stubs(:http_server).returns(@mock_http_server)
+ @server.listen
+ end
+
+ it "should indicate that it is listening" do
+ @server.should be_listening
+ end
+
+ it "should not allow listening to be turned on" do
+ lambda { @server.listen }.should raise_error(RuntimeError)
+ end
+
+ it "should allow listening to be turned off" do
+ lambda { @server.unlisten }.should_not raise_error
+ end
end
- it "should cause the HTTP server to stop listening when listening is turned off" do
- @mock_http_server.expects(:unlisten)
- @server.unlisten
+ describe "when listening is being turned on" do
+ before do
+ Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
+ Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler')
+
+ @server = Puppet::Network::Server.new(:address => "127.0.0.1", :port => 31337, :handlers => [:node], :xmlrpc_handlers => [:master])
+ @mock_http_server = mock('http server')
+ @mock_http_server.stubs(:listen)
+ end
+
+ 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" do
+ @server.stubs(:http_server).returns(@mock_http_server)
+ @mock_http_server.expects(:listen)
+ @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 REST 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 XMLRPC handlers to the HTTP server" do
+ @server.stubs(:http_server).returns(@mock_http_server)
+ @mock_http_server.expects(:listen).with do |args|
+ args[:xmlrpc_handlers] == [ :master ]
+ 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, :xmlrpc ]
+ end
+ @server.listen
+ end
end
- it "should not allow for indirections to be turned off" do
- @server.register(:foo)
- Proc.new { @server.unregister(:foo) }.should raise_error(RuntimeError)
+ describe "when listening is being turned off" do
+ before do
+ @mock_http_server = mock('http server')
+ @mock_http_server.stubs(:listen)
+ @server.stubs(:http_server).returns(@mock_http_server)
+ @server.listen
+ end
+
+ it "should cause the HTTP server to stop listening" do
+ @mock_http_server.expects(:unlisten)
+ @server.unlisten
+ end
+
+ it "should not allow for indirections to be turned off" do
+ Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
+
+ @server.register(:foo)
+ lambda { @server.unregister(:foo) }.should raise_error(RuntimeError)
+ end
end
-end
-
-describe Class.new, "put these somewhere" do
- it "should have the ability to use a class-level from_ hook (from_yaml, from_text, etc.) that can be called, based on content-type header, to allow for different deserializations of an object"
- it "should allow from_* on the inbound :data packet (look at its content_type) when doing a PUT/.new.save"
- it "should prepend a rest version number on the path (w00t)"
- it "should ... on server side, .save should from_yaml, then foo.save(args) instead of just Foo.new.save(args)"
+
+ describe Class.new, "put these somewhere" do
+ it "should have the ability to use a class-level from_ hook (from_yaml, from_text, etc.) that can be called, based on content-type header, to allow for different deserializations of an object"
+ it "should allow from_* on the inbound :data packet (look at its content_type) when doing a PUT/.new.save"
+ it "should prepend a rest version number on the path (w00t)"
+ it "should ... on server side, .save should from_yaml, then foo.save(args) instead of just Foo.new.save(args)"
+ end
end
diff --git a/spec/unit/node.rb b/spec/unit/node.rb
index 421fcd635..08afc5183 100755
--- a/spec/unit/node.rb
+++ b/spec/unit/node.rb
@@ -113,6 +113,22 @@ describe Puppet::Node, " when merging facts" do
@node.merge "two" => "three"
@node.parameters["two"].should == "three"
end
+
+ it "should add the environment to the list of parameters" do
+ Puppet.settings.stubs(:value).with(:environments).returns("one,two")
+ Puppet.settings.stubs(:value).with(:environment).returns("one")
+ @node = Puppet::Node.new("testnode", :environment => "one")
+ @node.merge "two" => "three"
+ @node.parameters["environment"].should == "one"
+ end
+
+ it "should not set the environment if it is already set in the parameters" do
+ Puppet.settings.stubs(:value).with(:environments).returns("one,two")
+ Puppet.settings.stubs(:value).with(:environment).returns("one")
+ @node = Puppet::Node.new("testnode", :environment => "one")
+ @node.merge "environment" => "two"
+ @node.parameters["environment"].should == "two"
+ end
end
describe Puppet::Node, " when indirecting" do
@@ -132,7 +148,7 @@ describe Puppet::Node, " when indirecting" do
end
after do
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
diff --git a/spec/unit/node/catalog.rb b/spec/unit/node/catalog.rb
index 8178f953a..59c70b45e 100755
--- a/spec/unit/node/catalog.rb
+++ b/spec/unit/node/catalog.rb
@@ -310,8 +310,6 @@ describe Puppet::Node::Catalog, " when converting to a RAL catalog" do
newconfig = nil
- Puppet::Type.allclear
-
proc { @catalog = config.to_ral }.should_not raise_error
@catalog.resource("Test[changer2]").should equal(resource)
end
@@ -325,9 +323,9 @@ end
describe Puppet::Node::Catalog, " when functioning as a resource container" do
before do
@catalog = Puppet::Node::Catalog.new("host")
- @one = stub 'resource1', :ref => "Me[one]", :catalog= => nil
- @two = stub 'resource2', :ref => "Me[two]", :catalog= => nil
- @dupe = stub 'resource3', :ref => "Me[one]", :catalog= => nil
+ @one = stub 'resource1', :ref => "Me[one]", :catalog= => nil, :title => "one", :[] => "one"
+ @two = stub 'resource2', :ref => "Me[two]", :catalog= => nil, :title => "two", :[] => "two"
+ @dupe = stub 'resource3', :ref => "Me[one]", :catalog= => nil, :title => "one", :[] => "one"
end
it "should provide a method to add one or more resources" do
@@ -445,6 +443,28 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do
@catalog.resource("me", "other").should equal(@one)
end
+ it "should ignore conflicting aliases that point to the aliased resource" do
+ @catalog.alias(@one, "other")
+ lambda { @catalog.alias(@one, "other") }.should_not raise_error
+ end
+
+ it "should create aliases for resources isomorphic resources whose names do not match their titles" do
+ resource = Puppet::Type::File.create(:title => "testing", :path => "/something")
+
+ @catalog.add_resource(resource)
+
+ @catalog.resource(:file, "/something").should equal(resource)
+ end
+
+ it "should not create aliases for resources non-isomorphic resources whose names do not match their titles" do
+ resource = Puppet::Type.type(:exec).create(:title => "testing", :command => "echo", :path => %w{/bin /usr/bin /usr/local/bin})
+
+ @catalog.add_resource(resource)
+
+ # Yay, I've already got a 'should' method
+ @catalog.resource(:exec, "echo").object_id.should == nil.object_id
+ end
+
# This test is the same as the previous, but the behaviour should be explicit.
it "should alias using the class name from the resource reference, not the resource class name" do
@catalog.add_resource @one
@@ -452,7 +472,7 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do
@catalog.resource("me", "other").should equal(@one)
end
- it "should fail to add an alias if the aliased name already exists" do
+ it "should fail to add an alias if the aliased name already exists as a resource" do
@catalog.add_resource @one
proc { @catalog.alias @two, "one" }.should raise_error(ArgumentError)
end
@@ -494,10 +514,6 @@ describe Puppet::Node::Catalog, " when functioning as a resource container" do
raise "Aliased non-isomorphic resource"
end
end
-
- after do
- Puppet::Type.allclear
- end
end
describe Puppet::Node::Catalog do
@@ -628,13 +644,14 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
@file = Puppet::Type.type(:file)
@one = @file.create :path => "/one"
@two = @file.create :path => "/two"
+ @sub = @file.create :path => "/two/subdir"
@catalog.add_edge @compone, @one
@catalog.add_edge @comptwo, @two
@three = @file.create :path => "/three"
@four = @file.create :path => "/four", :require => ["file", "/three"]
@five = @file.create :path => "/five"
- @catalog.add_resource @compone, @comptwo, @one, @two, @three, @four, @five
+ @catalog.add_resource @compone, @comptwo, @one, @two, @three, @four, @five, @sub
@relationships = @catalog.relationship_graph
end
@@ -669,6 +686,10 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
@relationships.edge?(@one, @two).should be_true
end
+ it "should add automatic relationships to the relationship graph" do
+ @relationships.edge?(@two, @sub).should be_true
+ end
+
it "should get removed when the catalog is cleaned up" do
@relationships.expects(:clear).with(false)
@catalog.clear
@@ -682,14 +703,14 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
end
it "should look up resources in the relationship graph if not found in the main catalog" do
- five = stub 'five', :ref => "File[five]", :catalog= => nil
+ five = stub 'five', :ref => "File[five]", :catalog= => nil, :title => "five", :[] => "five"
@relationships.add_resource five
@catalog.resource(five.ref).should equal(five)
end
it "should provide a method to create additional resources that also registers the resource" do
args = {:name => "/yay", :ensure => :file}
- resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog
+ resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog, :title => "/yay", :[] => "/yay"
Puppet::Type.type(:file).expects(:create).with(args).returns(resource)
@catalog.create_resource :file, args
@catalog.resource("File[/yay]").should equal(resource)
@@ -697,7 +718,7 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
it "should provide a mechanism for creating implicit resources" do
args = {:name => "/yay", :ensure => :file}
- resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog
+ resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog, :title => "/yay", :[] => "/yay"
Puppet::Type.type(:file).expects(:create).with(args).returns(resource)
resource.expects(:implicit=).with(true)
@catalog.create_implicit_resource :file, args
@@ -706,7 +727,7 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
it "should add implicit resources to the relationship graph if there is one" do
args = {:name => "/yay", :ensure => :file}
- resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog
+ resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog, :title => "/yay", :[] => "/yay"
resource.expects(:implicit=).with(true)
Puppet::Type.type(:file).expects(:create).with(args).returns(resource)
# build the graph
@@ -718,7 +739,7 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
it "should remove resources created mid-transaction" do
args = {:name => "/yay", :ensure => :file}
- resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog
+ resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog, :title => "/yay", :[] => "/yay"
@transaction = mock 'transaction'
Puppet::Transaction.stubs(:new).returns(@transaction)
@transaction.stubs(:evaluate)
@@ -737,10 +758,6 @@ describe Puppet::Node::Catalog, " when creating a relationship graph" do
@catalog.remove_resource(@one)
@catalog.relationship_graph.vertex?(@one).should be_false
end
-
- after do
- Puppet::Type.allclear
- end
end
describe Puppet::Node::Catalog, " when writing dot files" do
@@ -780,7 +797,7 @@ describe Puppet::Node::Catalog, " when indirecting" do
before do
@indirection = stub 'indirection', :name => :catalog
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
it "should redirect to the indirection for retrieval" do
@@ -794,8 +811,7 @@ describe Puppet::Node::Catalog, " when indirecting" do
end
after do
- mocha_verify
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
diff --git a/spec/unit/node/facts.rb b/spec/unit/node/facts.rb
index 1bfccd32e..69b8e4483 100755
--- a/spec/unit/node/facts.rb
+++ b/spec/unit/node/facts.rb
@@ -10,7 +10,8 @@ describe Puppet::Node::Facts, " when indirecting" do
# We have to clear the cache so that the facts ask for our indirection stub,
# instead of anything that might be cached.
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
+
@facts = Puppet::Node::Facts.new("me", "one" => "two")
end
@@ -29,11 +30,6 @@ describe Puppet::Node::Facts, " when indirecting" do
it "should default to the 'facter' terminus" do
Puppet::Node::Facts.indirection.terminus_class.should == :facter
end
-
- after do
- mocha_verify
- Puppet::Indirector::Indirection.clear_cache
- end
end
describe Puppet::Node::Facts, " when storing and retrieving" do
diff --git a/spec/unit/other/transbucket.rb b/spec/unit/other/transbucket.rb
index 4494f2abb..e447c78a2 100755
--- a/spec/unit/other/transbucket.rb
+++ b/spec/unit/other/transbucket.rb
@@ -91,10 +91,6 @@ describe Puppet::TransBucket, " when generating a catalog" do
@fakes = %w{Fake[bottom] Fake[middle] Fake[top]}
end
- after do
- Puppet::Type.allclear
- end
-
it "should convert all transportable objects to RAL resources" do
@catalog = @top.to_catalog
@users.each do |name|
diff --git a/spec/unit/provider/mount/parsed.rb b/spec/unit/provider/mount/parsed.rb
index ba65b70a4..8d043f97f 100755
--- a/spec/unit/provider/mount/parsed.rb
+++ b/spec/unit/provider/mount/parsed.rb
@@ -167,10 +167,6 @@ describe provider_class do
@provider_class.prefetch("/" => @mount)
@mount.provider.should be_mounted
end
-
- after do
- Puppet::Type.allclear
- end
end
describe provider_class, " when mounting and unmounting" do
diff --git a/spec/unit/rails.rb b/spec/unit/rails.rb
index bb2f991ca..4a4667543 100755
--- a/spec/unit/rails.rb
+++ b/spec/unit/rails.rb
@@ -7,7 +7,7 @@ describe Puppet::Rails, "when initializing any connection" do
confine Puppet.features.rails? => "Cannot test without ActiveRecord"
before do
- @logger = mock 'logger'
+ @logger = stub 'logger', :level= => nil
@logger.stub_everything
Logger.stubs(:new).returns(@logger)
diff --git a/spec/unit/resource_reference.rb b/spec/unit/resource_reference.rb
index cbbd6ef51..ee71a5077 100755
--- a/spec/unit/resource_reference.rb
+++ b/spec/unit/resource_reference.rb
@@ -48,18 +48,6 @@ describe Puppet::ResourceReference do
end
end
-describe Puppet::ResourceReference, "when resolving resources without a catalog" do
- it "should be able to resolve builtin resources from their types" do
- Puppet::Type.type(:file).expects(:[]).with("myfile").returns(:myfile)
- Puppet::ResourceReference.new(:file, "myfile").resolve.should == :myfile
- end
-
- it "should be able to resolve defined resources from Components" do
- Puppet::Type.type(:component).expects(:[]).with("Foo::Bar[yay]").returns(:mything)
- Puppet::ResourceReference.new("foo::bar", "yay").resolve.should == :mything
- end
-end
-
describe Puppet::ResourceReference, "when resolving resources with a catalog" do
it "should resolve all resources using the catalog" do
config = mock 'catalog'
diff --git a/spec/unit/ssl/certificate.rb b/spec/unit/ssl/certificate.rb
new file mode 100755
index 000000000..1cb164d3f
--- /dev/null
+++ b/spec/unit/ssl/certificate.rb
@@ -0,0 +1,82 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate'
+
+describe Puppet::SSL::Certificate do
+ before do
+ @class = Puppet::SSL::Certificate
+ end
+
+ after do
+ @class.instance_variable_set("@ca_location", nil)
+ end
+
+ it "should be extended with the Indirector module" do
+ @class.metaclass.should be_include(Puppet::Indirector)
+ end
+
+ it "should indirect certificate" do
+ @class.indirection.name.should == :certificate
+ end
+
+ it "should default to the :file terminus" do
+ @class.indirection.terminus_class.should == :file
+ end
+
+ describe "when managing instances" do
+ before do
+ @certificate = @class.new("myname")
+ end
+
+ it "should have a name attribute" do
+ @certificate.name.should == "myname"
+ end
+
+ it "should have a content attribute" do
+ @certificate.should respond_to(:content)
+ end
+
+ it "should return a nil expiration if there is no actual certificate" do
+ @certificate.stubs(:content).returns nil
+
+ @certificate.expiration.should be_nil
+ end
+
+ it "should use the expiration of the certificate as its expiration date" do
+ cert = stub 'cert'
+ @certificate.stubs(:content).returns cert
+
+ cert.expects(:not_after).returns "sometime"
+
+ @certificate.expiration.should == "sometime"
+ end
+
+ it "should be able to read certificates from disk" do
+ path = "/my/path"
+ File.expects(:read).with(path).returns("my certificate")
+ certificate = mock 'certificate'
+ OpenSSL::X509::Certificate.expects(:new).with("my certificate").returns(certificate)
+ @certificate.read(path).should equal(certificate)
+ @certificate.content.should equal(certificate)
+ end
+
+ it "should return an empty string when converted to a string with no certificate" do
+ @certificate.to_s.should == ""
+ end
+
+ it "should convert the certificate to pem format when converted to a string" do
+ certificate = mock 'certificate', :to_pem => "pem"
+ @certificate.content = certificate
+ @certificate.to_s.should == "pem"
+ end
+
+ it "should have a :to_text method that it delegates to the actual key" do
+ real_certificate = mock 'certificate'
+ real_certificate.expects(:to_text).returns "certificatetext"
+ @certificate.content = real_certificate
+ @certificate.to_text.should == "certificatetext"
+ end
+ end
+end
diff --git a/spec/unit/ssl/certificate_authority.rb b/spec/unit/ssl/certificate_authority.rb
new file mode 100755
index 000000000..ff629fec1
--- /dev/null
+++ b/spec/unit/ssl/certificate_authority.rb
@@ -0,0 +1,737 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_authority'
+
+describe Puppet::SSL::CertificateAuthority do
+ after do
+ # Clear out the var, yay unit tests.
+ Puppet::SSL::CertificateAuthority.instance_variable_set("@instance", nil)
+ Puppet.settings.clearused
+ end
+
+ it "should have a class method for returning a singleton instance" do
+ Puppet::SSL::CertificateAuthority.should respond_to(:instance)
+ end
+
+ describe "when finding an existing instance" do
+ describe "and the host is a CA host and the proces name is 'puppetmasterd'" do
+ before do
+ Puppet.settings.stubs(:value).with(:ca).returns true
+ Puppet.settings.stubs(:value).with(:name).returns "puppetmasterd"
+
+ @ca = mock('ca')
+ Puppet::SSL::CertificateAuthority.stubs(:new).returns @ca
+ end
+
+ after do
+ # Clear out the var, yay unit tests.
+ Puppet::SSL::CertificateAuthority.instance_variable_set("@instance", nil)
+ end
+
+ it "should return an instance" do
+ Puppet::SSL::CertificateAuthority.instance.should equal(@ca)
+ end
+
+ it "should always return the same instance" do
+ Puppet::SSL::CertificateAuthority.instance.should equal(Puppet::SSL::CertificateAuthority.instance)
+ end
+ end
+
+ describe "and the host is not a CA host" do
+ it "should return nil" do
+ Puppet.settings.stubs(:value).with(:ca).returns false
+ Puppet.settings.stubs(:value).with(:name).returns "puppetmasterd"
+
+ ca = mock('ca')
+ Puppet::SSL::CertificateAuthority.expects(:new).never
+ Puppet::SSL::CertificateAuthority.instance.should be_nil
+ end
+ end
+
+ describe "and the process name is not 'puppetmasterd'" do
+ it "should return nil" do
+ Puppet.settings.stubs(:value).with(:ca).returns true
+ Puppet.settings.stubs(:value).with(:name).returns "puppetd"
+
+ ca = mock('ca')
+ Puppet::SSL::CertificateAuthority.expects(:new).never
+ Puppet::SSL::CertificateAuthority.instance.should be_nil
+ end
+ end
+ end
+
+ describe "when initializing" do
+ before do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "ca_testing"
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
+ end
+
+ it "should always set its name to the value of :certname" do
+ Puppet.settings.expects(:value).with(:certname).returns "ca_testing"
+
+ Puppet::SSL::CertificateAuthority.new.name.should == "ca_testing"
+ end
+
+ it "should create an SSL::Host instance whose name is the 'ca_name'" do
+ Puppet::SSL::Host.expects(:ca_name).returns "caname"
+
+ host = stub 'host'
+ Puppet::SSL::Host.expects(:new).with("caname").returns host
+
+ Puppet::SSL::CertificateAuthority.new
+ end
+
+ it "should use the :main, :ca, and :ssl settings sections" do
+ Puppet.settings.expects(:use).with(:main, :ssl, :ca)
+ Puppet::SSL::CertificateAuthority.new
+ end
+
+ it "should create an inventory instance" do
+ Puppet::SSL::Inventory.expects(:new).returns "inventory"
+
+ Puppet::SSL::CertificateAuthority.new.inventory.should == "inventory"
+ end
+
+ it "should make sure the CA is set up" do
+ Puppet::SSL::CertificateAuthority.any_instance.expects(:setup)
+
+ Puppet::SSL::CertificateAuthority.new
+ end
+ end
+
+ describe "when setting itself up" do
+ it "should generate the CA certificate if it does not have one" do
+ Puppet.settings.stubs :use
+
+ host = stub 'host'
+ Puppet::SSL::Host.stubs(:new).returns host
+
+ host.expects(:certificate).returns nil
+
+ Puppet::SSL::CertificateAuthority.any_instance.expects(:generate_ca_certificate)
+ Puppet::SSL::CertificateAuthority.new
+ end
+ end
+
+ describe "when retrieving the certificate revocation list" do
+ before do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "ca_testing"
+ Puppet.settings.stubs(:value).with(:cacrl).returns "/my/crl"
+
+ cert = stub("certificate", :content => "real_cert")
+ key = stub("key", :content => "real_key")
+ @host = stub 'host', :certificate => cert, :name => "hostname", :key => key
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
+ @ca = Puppet::SSL::CertificateAuthority.new
+
+ @ca.stubs(:host).returns @host
+ end
+
+ it "should return any found CRL instance" do
+ crl = mock 'crl'
+ Puppet::SSL::CertificateRevocationList.expects(:find).returns crl
+ @ca.crl.should equal(crl)
+ end
+
+ it "should create, generate, and save a new CRL instance of no CRL can be found" do
+ crl = mock 'crl'
+ Puppet::SSL::CertificateRevocationList.expects(:find).returns nil
+
+ Puppet::SSL::CertificateRevocationList.expects(:new).returns crl
+
+ crl.expects(:generate).with(@ca.host.certificate.content, @ca.host.key.content)
+ crl.expects(:save)
+
+ @ca.crl.should equal(crl)
+ end
+ end
+
+ describe "when generating a self-signed CA certificate" do
+ before do
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).returns "ca_testing"
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:crl)
+ @ca = Puppet::SSL::CertificateAuthority.new
+
+ @host = stub 'host', :key => mock("key"), :name => "hostname", :certificate => mock('certificate')
+
+ Puppet::SSL::CertificateRequest.any_instance.stubs(:generate)
+
+ @ca.stubs(:host).returns @host
+ end
+
+ it "should create and store a password at :capass" do
+ Puppet.settings.expects(:value).with(:capass).returns "/path/to/pass"
+
+ FileTest.expects(:exist?).with("/path/to/pass").returns false
+
+ fh = mock 'filehandle'
+ Puppet.settings.expects(:write).with(:capass).yields fh
+
+ fh.expects(:print).with { |s| s.length > 18 }
+
+ @ca.stubs(:sign)
+
+ @ca.generate_ca_certificate
+ end
+
+ it "should generate a key if one does not exist" do
+ @ca.stubs :generate_password
+ @ca.stubs :sign
+
+ @ca.host.expects(:key).returns nil
+ @ca.host.expects(:generate_key)
+
+ @ca.generate_ca_certificate
+ end
+
+ it "should create and sign a self-signed cert using the CA name" do
+ request = mock 'request'
+ Puppet::SSL::CertificateRequest.expects(:new).with(@ca.host.name).returns request
+ request.expects(:generate).with(@ca.host.key)
+
+ @ca.expects(:sign).with(@host.name, :ca, request)
+
+ @ca.stubs :generate_password
+
+ @ca.generate_ca_certificate
+ end
+
+ it "should generate its CRL" do
+ @ca.stubs :generate_password
+ @ca.stubs :sign
+
+ @ca.host.expects(:key).returns nil
+ @ca.host.expects(:generate_key)
+
+ @ca.expects(:crl)
+
+ @ca.generate_ca_certificate
+ end
+ end
+
+ describe "when signing" do
+ before do
+ Puppet.settings.stubs(:use)
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true
+
+ # Set up the CA
+ @key = mock 'key'
+ @key.stubs(:content).returns "cakey"
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:key).returns @key
+ @cacert = mock 'certificate'
+ @cacert.stubs(:content).returns "cacertificate"
+ @ca = Puppet::SSL::CertificateAuthority.new
+
+ @ca.host.stubs(:certificate).returns @cacert
+ @ca.host.stubs(:key).returns @key
+
+ @name = "myhost"
+ @real_cert = stub 'realcert', :sign => nil
+ @cert = stub 'certificate', :content => @real_cert
+ Puppet::SSL::Certificate.stubs(:new).returns @cert
+
+ @cert.stubs(:content=)
+ @cert.stubs(:save)
+
+ # Stub out the factory
+ @factory = stub 'factory', :result => "my real cert"
+ Puppet::SSL::CertificateFactory.stubs(:new).returns @factory
+
+ @request = stub 'request', :content => "myrequest", :name => @name
+
+ # And the inventory
+ @inventory = stub 'inventory', :add => nil
+ @ca.stubs(:inventory).returns @inventory
+
+ Puppet::SSL::CertificateRequest.stubs(:destroy)
+ end
+
+ describe "and calculating the next certificate serial number" do
+ before do
+ @path = "/path/to/serial"
+ Puppet.settings.stubs(:value).with(:serial).returns @path
+
+ @filehandle = stub 'filehandle', :<< => @filehandle
+ Puppet.settings.stubs(:readwritelock).with(:serial).yields @filehandle
+ end
+
+ it "should default to 0x0 for the first serial number" do
+ @ca.next_serial.should == 0x0
+ end
+
+ it "should return the current content of the serial file" do
+ FileTest.stubs(:exist?).with(@path).returns true
+ File.expects(:read).with(@path).returns "0002"
+
+ @ca.next_serial.should == 2
+ end
+
+ it "should write the next serial number to the serial file as hex" do
+ @filehandle.expects(:<<).with("0001")
+
+ @ca.next_serial
+ end
+
+ it "should lock the serial file while writing" do
+ Puppet.settings.expects(:readwritelock).with(:serial)
+
+ @ca.next_serial
+ end
+ end
+
+ describe "its own certificate" do
+ before do
+ @serial = 10
+ @ca.stubs(:next_serial).returns @serial
+ end
+
+ it "should not look up a certificate request for the host" do
+ Puppet::SSL::CertificateRequest.expects(:find).never
+
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should use a certificate type of :ca" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[0] == :ca
+ end.returns @factory
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should pass the provided CSR as the CSR" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[1] == "myrequest"
+ end.returns @factory
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should use the provided CSR's content as the issuer" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[2] == "myrequest"
+ end.returns @factory
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should pass the next serial as the serial number" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[3] == @serial
+ end.returns @factory
+ @ca.sign(@name, :ca, @request)
+ end
+
+ it "should save the resulting certificate" do
+ @cert.expects(:save)
+
+ @ca.sign(@name, :ca, @request)
+ end
+ end
+
+ describe "another host's certificate" do
+ before do
+ @serial = 10
+ @ca.stubs(:next_serial).returns @serial
+
+ Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request
+ @cert.stubs :save
+ end
+
+ it "should use a certificate type of :server" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[0] == :server
+ end.returns @factory
+
+ @ca.sign(@name)
+ end
+
+ it "should use look up a CSR for the host in the :ca_file terminus" do
+ Puppet::SSL::CertificateRequest.expects(:find).with(@name).returns @request
+
+ @ca.sign(@name)
+ end
+
+ it "should fail if no CSR can be found for the host" do
+ Puppet::SSL::CertificateRequest.expects(:find).with(@name).returns nil
+
+ lambda { @ca.sign(@name) }.should raise_error(ArgumentError)
+ end
+
+ it "should use the CA certificate as the issuer" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[2] == @cacert.content
+ end.returns @factory
+ @ca.sign(@name)
+ end
+
+ it "should pass the next serial as the serial number" do
+ Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ args[3] == @serial
+ end.returns @factory
+ @ca.sign(@name)
+ end
+
+ it "should sign the resulting certificate using its real key and a digest" do
+ digest = mock 'digest'
+ OpenSSL::Digest::SHA1.expects(:new).returns digest
+
+ key = stub 'key', :content => "real_key"
+ @ca.host.stubs(:key).returns key
+
+ @cert.content.expects(:sign).with("real_key", digest)
+ @ca.sign(@name)
+ end
+
+ it "should save the resulting certificate" do
+ @cert.expects(:save)
+ @ca.sign(@name)
+ end
+
+ it "should remove the host's certificate request" do
+ Puppet::SSL::CertificateRequest.expects(:destroy).with(@name)
+
+ @ca.sign(@name)
+ end
+ end
+
+ it "should create a certificate instance with the content set to the newly signed x509 certificate" do
+ @serial = 10
+ @ca.stubs(:next_serial).returns @serial
+
+ Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request
+ @cert.stubs :save
+ Puppet::SSL::Certificate.expects(:new).with(@name).returns @cert
+
+ @ca.sign(@name)
+ end
+
+ it "should return the certificate instance" do
+ @ca.stubs(:next_serial).returns @serial
+ Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request
+ @cert.stubs :save
+ @ca.sign(@name).should equal(@cert)
+ end
+
+ it "should add the certificate to its inventory" do
+ @ca.stubs(:next_serial).returns @serial
+ @inventory.expects(:add).with(@cert)
+
+ Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request
+ @cert.stubs :save
+ @ca.sign(@name)
+ end
+
+ it "should have a method for triggering autosigning of available CSRs" do
+ @ca.should respond_to(:autosign)
+ end
+
+ describe "when autosigning certificates" do
+ it "should do nothing if autosign is disabled" do
+ Puppet.settings.expects(:value).with(:autosign).returns 'false'
+
+ Puppet::SSL::CertificateRequest.expects(:search).never
+ @ca.autosign
+ end
+
+ it "should do nothing if no autosign.conf exists" do
+ Puppet.settings.expects(:value).with(:autosign).returns '/auto/sign'
+ FileTest.expects(:exist?).with("/auto/sign").returns false
+
+ Puppet::SSL::CertificateRequest.expects(:search).never
+ @ca.autosign
+ end
+
+ describe "and autosign is enabled and the autosign.conf file exists" do
+ before do
+ Puppet.settings.stubs(:value).with(:autosign).returns '/auto/sign'
+ FileTest.stubs(:exist?).with("/auto/sign").returns true
+ File.stubs(:readlines).with("/auto/sign").returns ["one\n", "two\n"]
+
+ Puppet::SSL::CertificateRequest.stubs(:search).returns []
+
+ @store = stub 'store', :allow => nil
+ Puppet::Network::AuthStore.stubs(:new).returns @store
+ end
+
+ describe "when creating the AuthStore instance to verify autosigning" do
+ it "should create an AuthStore with each line in the configuration file allowed to be autosigned" do
+ Puppet::Network::AuthStore.expects(:new).returns @store
+
+ @store.expects(:allow).with("one")
+ @store.expects(:allow).with("two")
+
+ @ca.autosign
+ end
+
+ it "should reparse the autosign configuration on each call" do
+ Puppet::Network::AuthStore.expects(:new).times(2).returns @store
+
+ @ca.autosign
+ @ca.autosign
+ end
+
+ it "should ignore comments" do
+ File.stubs(:readlines).with("/auto/sign").returns ["one\n", "#two\n"]
+
+ @store.expects(:allow).with("one")
+ @ca.autosign
+ end
+
+ it "should ignore blank lines" do
+ File.stubs(:readlines).with("/auto/sign").returns ["one\n", "\n"]
+
+ @store.expects(:allow).with("one")
+ @ca.autosign
+ end
+ end
+
+ it "should sign all CSRs whose hostname matches the autosign configuration" do
+ csr1 = mock 'csr1'
+ csr2 = mock 'csr2'
+ Puppet::SSL::CertificateRequest.stubs(:search).returns [csr1, csr2]
+ end
+
+ it "should not sign CSRs whose hostname does not match the autosign configuration" do
+ csr1 = mock 'csr1'
+ csr2 = mock 'csr2'
+ Puppet::SSL::CertificateRequest.stubs(:search).returns [csr1, csr2]
+ end
+ end
+ end
+ end
+
+ describe "when managing certificate clients" do
+ before do
+ Puppet.settings.stubs(:use)
+
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true
+
+ # Set up the CA
+ @key = mock 'key'
+ @key.stubs(:content).returns "cakey"
+ @host = stub 'host', :key => @key
+ Puppet::SSL::CertificateAuthority.any_instance.stubs(:host).returns @host
+
+ @cacert = mock 'certificate'
+ @cacert.stubs(:content).returns "cacertificate"
+ @ca = Puppet::SSL::CertificateAuthority.new
+ end
+
+ it "should have a method for acting on the SSL files" do
+ @ca.should respond_to(:apply)
+ end
+
+ describe "when applying a method to a set of hosts" do
+ it "should fail if no subjects have been specified" do
+ lambda { @ca.apply(:generate) }.should raise_error(ArgumentError)
+ end
+
+ it "should create an Interface instance with the specified method and the subjects" do
+ Puppet::SSL::CertificateAuthority::Interface.expects(:new).with(:generate, :hosts).returns(stub('applier', :apply => nil))
+ @ca.apply(:generate, :to => :hosts)
+ end
+
+ it "should apply the Interface with itself as the argument" do
+ applier = stub('applier')
+ applier.expects(:apply).with(@ca)
+ Puppet::SSL::CertificateAuthority::Interface.expects(:new).returns applier
+ @ca.apply(:generate, :to => :ca_testing)
+ end
+ end
+
+ it "should be able to list waiting certificate requests" do
+ req1 = stub 'req1', :name => "one"
+ req2 = stub 'req2', :name => "two"
+ Puppet::SSL::CertificateRequest.expects(:search).with("*").returns [req1, req2]
+
+ @ca.waiting?.should == %w{one two}
+ end
+
+ it "should delegate removing hosts to the Host class" do
+ Puppet::SSL::Host.expects(:destroy).with("myhost")
+
+ @ca.destroy("myhost")
+ end
+
+ it "should be able to verify certificates" do
+ @ca.should respond_to(:verify)
+ end
+
+ it "should list certificates as the sorted list of all existing signed certificates" do
+ cert1 = stub 'cert1', :name => "cert1"
+ cert2 = stub 'cert2', :name => "cert2"
+ Puppet::SSL::Certificate.expects(:search).with("*").returns [cert1, cert2]
+ @ca.list.should == %w{cert1 cert2}
+ end
+
+ describe "and printing certificates" do
+ it "should return nil if the certificate cannot be found" do
+ Puppet::SSL::Certificate.expects(:find).with("myhost").returns nil
+ @ca.print("myhost").should be_nil
+ end
+
+ it "should print certificates by calling :to_text on the host's certificate" do
+ cert1 = stub 'cert1', :name => "cert1", :to_text => "mytext"
+ Puppet::SSL::Certificate.expects(:find).with("myhost").returns cert1
+ @ca.print("myhost").should == "mytext"
+ end
+ end
+
+ describe "and verifying certificates" do
+ before do
+ @store = stub 'store', :verify => true, :add_file => nil, :purpose= => nil, :add_crl => true
+
+ OpenSSL::X509::Store.stubs(:new).returns @store
+
+ Puppet.settings.stubs(:value).returns "crtstuff"
+
+ @cert = stub 'cert', :content => "mycert"
+ Puppet::SSL::Certificate.stubs(:find).returns @cert
+
+ @crl = stub('crl', :content => "mycrl")
+
+ @ca.stubs(:crl).returns @crl
+ end
+
+ it "should fail if the host's certificate cannot be found" do
+ Puppet::SSL::Certificate.expects(:find).with("me").returns(nil)
+
+ lambda { @ca.verify("me") }.should raise_error(ArgumentError)
+ end
+
+ it "should create an SSL Store to verify" do
+ OpenSSL::X509::Store.expects(:new).returns @store
+
+ @ca.verify("me")
+ end
+
+ it "should add the CA Certificate to the store" do
+ Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
+ @store.expects(:add_file).with "/ca/cert"
+
+ @ca.verify("me")
+ end
+
+ it "should add the CRL to the store if the crl is enabled" do
+ @store.expects(:add_crl).with "mycrl"
+
+ @ca.verify("me")
+ end
+
+ it "should set the store purpose to OpenSSL::X509::PURPOSE_SSL_CLIENT" do
+ Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
+ @store.expects(:add_file).with "/ca/cert"
+
+ @ca.verify("me")
+ end
+
+ it "should use the store to verify the certificate" do
+ @cert.expects(:content).returns "mycert"
+
+ @store.expects(:verify).with("mycert").returns true
+
+ @ca.verify("me")
+ end
+
+ it "should fail if the verification returns false" do
+ @cert.expects(:content).returns "mycert"
+
+ @store.expects(:verify).with("mycert").returns false
+
+ lambda { @ca.verify("me") }.should raise_error
+ end
+ end
+
+ describe "and revoking certificates" do
+ before do
+ @crl = mock 'crl'
+ @ca.stubs(:crl).returns @crl
+
+ @ca.stubs(:next_serial).returns 10
+
+ @real_cert = stub 'real_cert', :serial => 15
+ @cert = stub 'cert', :content => @real_cert
+ Puppet::SSL::Certificate.stubs(:find).returns @cert
+
+ end
+
+ it "should fail if the certificate revocation list is disabled" do
+ @ca.stubs(:crl).returns false
+
+ lambda { @ca.revoke('ca_testing') }.should raise_error(ArgumentError)
+
+ end
+
+ it "should delegate the revocation to its CRL" do
+ @ca.crl.expects(:revoke)
+
+ @ca.revoke('host')
+ end
+
+ it "should get the serial number from the local certificate if it exists" do
+ @ca.crl.expects(:revoke).with { |serial, key| serial == 15 }
+
+ Puppet::SSL::Certificate.expects(:find).with("host").returns @cert
+
+ @ca.revoke('host')
+ end
+
+ it "should get the serial number from inventory if no local certificate exists" do
+ real_cert = stub 'real_cert', :serial => 15
+ cert = stub 'cert', :content => real_cert
+ Puppet::SSL::Certificate.expects(:find).with("host").returns nil
+
+ @ca.inventory.expects(:serial).with("host").returns 16
+
+ @ca.crl.expects(:revoke).with { |serial, key| serial == 16 }
+ @ca.revoke('host')
+ end
+ end
+
+ it "should be able to generate a complete new SSL host" do
+ @ca.should respond_to(:generate)
+ end
+
+ describe "and generating certificates" do
+ before do
+ @host = stub 'host', :generate_certificate_request => nil
+ Puppet::SSL::Host.stubs(:new).returns @host
+ Puppet::SSL::Certificate.stubs(:find).returns nil
+
+ @ca.stubs(:sign)
+ end
+
+ it "should fail if a certificate already exists for the host" do
+ Puppet::SSL::Certificate.expects(:find).with("him").returns "something"
+
+ lambda { @ca.generate("him") }.should raise_error(ArgumentError)
+ end
+
+ it "should create a new Host instance with the correct name" do
+ Puppet::SSL::Host.expects(:new).with("him").returns @host
+
+ @ca.generate("him")
+ end
+
+ it "should use the Host to generate the certificate request" do
+ @host.expects :generate_certificate_request
+
+ @ca.generate("him")
+ end
+
+ it "should sign the generated request" do
+ @ca.expects(:sign).with("him")
+
+ @ca.generate("him")
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/certificate_authority/interface.rb b/spec/unit/ssl/certificate_authority/interface.rb
new file mode 100755
index 000000000..617cfa6ba
--- /dev/null
+++ b/spec/unit/ssl/certificate_authority/interface.rb
@@ -0,0 +1,265 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/ssl/certificate_authority'
+
+describe "a normal interface method", :shared => true do
+ it "should call the method on the CA for each host specified if an array was provided" do
+ @ca.expects(@method).with("host1")
+ @ca.expects(@method).with("host2")
+
+ @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, %w{host1 host2})
+
+ @applier.apply(@ca)
+ end
+
+ it "should call the method on the CA for all existing certificates if :all was provided" do
+ @ca.expects(:list).returns %w{host1 host2}
+
+ @ca.expects(@method).with("host1")
+ @ca.expects(@method).with("host2")
+
+ @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, :all)
+
+ @applier.apply(@ca)
+ end
+end
+
+describe Puppet::SSL::CertificateAuthority::Interface do
+ before do
+ @class = Puppet::SSL::CertificateAuthority::Interface
+ end
+ describe "when initializing" do
+ it "should set its method using its settor" do
+ @class.any_instance.expects(:method=).with(:generate)
+ @class.new(:generate, :all)
+ end
+
+ it "should set its subjects using the settor" do
+ @class.any_instance.expects(:subjects=).with(:all)
+ @class.new(:generate, :all)
+ end
+ end
+
+ describe "when setting the method" do
+ it "should set the method" do
+ @class.new(:generate, :all).method.should == :generate
+ end
+
+ it "should fail if the method isn't a member of the INTERFACE_METHODS array" do
+ Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.expects(:include?).with(:thing).returns false
+
+ lambda { @class.new(:thing, :all) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "when setting the subjects" do
+ it "should set the subjects" do
+ @class.new(:generate, :all).subjects.should == :all
+ end
+
+ it "should fail if the subjects setting isn't :all or an array" do
+ lambda { @class.new(:generate, "other") }.should raise_error(ArgumentError)
+ end
+ end
+
+ it "should have a method for triggering the application" do
+ @class.new(:generate, :all).should respond_to(:apply)
+ end
+
+ describe "when applying" do
+ before do
+ # We use a real object here, because :verify can't be stubbed, apparently.
+ @ca = Object.new
+ end
+
+ it "should raise InterfaceErrors" do
+ @applier = @class.new(:revoke, :all)
+
+ @ca.expects(:list).raises Puppet::SSL::CertificateAuthority::Interface::InterfaceError
+
+ lambda { @applier.apply(@ca) }.should raise_error(Puppet::SSL::CertificateAuthority::Interface::InterfaceError)
+ end
+
+ it "should log non-Interface failures rather than failing" do
+ @applier = @class.new(:revoke, :all)
+
+ @ca.expects(:list).raises ArgumentError
+
+ Puppet.expects(:err)
+
+ lambda { @applier.apply(@ca) }.should_not raise_error
+ end
+
+ describe "with an empty array specified and the method is not list" do
+ it "should fail" do
+ @applier = @class.new(:sign, [])
+ lambda { @applier.apply(@ca) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe ":generate" do
+ it "should fail if :all was specified" do
+ @applier = @class.new(:generate, :all)
+ lambda { @applier.apply(@ca) }.should raise_error(ArgumentError)
+ end
+
+ it "should call :generate on the CA for each host specified" do
+ @applier = @class.new(:generate, %w{host1 host2})
+
+ @ca.expects(:generate).with("host1")
+ @ca.expects(:generate).with("host2")
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe ":verify" do
+ before { @method = :verify }
+ #it_should_behave_like "a normal interface method"
+
+ it "should call the method on the CA for each host specified if an array was provided" do
+ # LAK:NOTE Mocha apparently doesn't allow you to mock :verify, but I'm confident this works in real life.
+ end
+
+ it "should call the method on the CA for all existing certificates if :all was provided" do
+ # LAK:NOTE Mocha apparently doesn't allow you to mock :verify, but I'm confident this works in real life.
+ end
+ end
+
+ describe ":destroy" do
+ before { @method = :destroy }
+ it_should_behave_like "a normal interface method"
+ end
+
+ describe ":revoke" do
+ before { @method = :revoke }
+ it_should_behave_like "a normal interface method"
+ end
+
+ describe ":sign" do
+ describe "and an array of names was provided" do
+ before do
+ @applier = @class.new(:sign, %w{host1 host2})
+ end
+
+ it "should sign the specified waiting certificate requests" do
+ @ca.expects(:sign).with("host1")
+ @ca.expects(:sign).with("host2")
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe "and :all was provided" do
+ it "should sign all waiting certificate requests" do
+ @ca.stubs(:waiting?).returns(%w{cert1 cert2})
+
+ @ca.expects(:sign).with("cert1")
+ @ca.expects(:sign).with("cert2")
+
+ @applier = @class.new(:sign, :all)
+ @applier.apply(@ca)
+ end
+
+ it "should fail if there are no waiting certificate requests" do
+ @ca.stubs(:waiting?).returns([])
+
+ @applier = @class.new(:sign, :all)
+ lambda { @applier.apply(@ca) }.should raise_error(Puppet::SSL::CertificateAuthority::Interface::InterfaceError)
+ end
+ end
+ end
+
+ describe ":list" do
+ describe "and an empty array was provided" do
+ it "should print a string containing all certificate requests" do
+ @ca.expects(:waiting?).returns %w{host1 host2}
+
+ @applier = @class.new(:list, [])
+
+ @applier.expects(:puts).with "host1\nhost2"
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe "and :all was provided" do
+ it "should print a string containing all certificate requests and certificates" do
+ @ca.expects(:waiting?).returns %w{host1 host2}
+ @ca.expects(:list).returns %w{host3 host4}
+
+ @applier = @class.new(:list, :all)
+
+ @applier.expects(:puts).with "host1"
+ @applier.expects(:puts).with "host2"
+ @applier.expects(:puts).with "+ host3"
+ @applier.expects(:puts).with "+ host4"
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe "and an array of names was provided" do
+ it "should print a string of all named hosts that have a waiting request" do
+ @ca.expects(:waiting?).returns %w{host1 host2}
+ @ca.expects(:list).returns %w{host3 host4}
+
+ @applier = @class.new(:list, %w{host1 host2 host3 host4})
+
+ @applier.expects(:puts).with "host1"
+ @applier.expects(:puts).with "host2"
+ @applier.expects(:puts).with "+ host3"
+ @applier.expects(:puts).with "+ host4"
+
+ @applier.apply(@ca)
+ end
+ end
+ end
+
+ describe ":print" do
+ describe "and :all was provided" do
+ it "should print all certificates" do
+ @ca.expects(:list).returns %w{host1 host2}
+
+ @applier = @class.new(:print, :all)
+
+ @ca.expects(:print).with("host1").returns "h1"
+ @applier.expects(:puts).with "h1"
+
+ @ca.expects(:print).with("host2").returns "h2"
+ @applier.expects(:puts).with "h2"
+
+ @applier.apply(@ca)
+ end
+ end
+
+ describe "and an array of names was provided" do
+ it "should print each named certificate if found" do
+ @applier = @class.new(:print, %w{host1 host2})
+
+ @ca.expects(:print).with("host1").returns "h1"
+ @applier.expects(:puts).with "h1"
+
+ @ca.expects(:print).with("host2").returns "h2"
+ @applier.expects(:puts).with "h2"
+
+ @applier.apply(@ca)
+ end
+
+ it "should log any named but not found certificates" do
+ @applier = @class.new(:print, %w{host1 host2})
+
+ @ca.expects(:print).with("host1").returns "h1"
+ @applier.expects(:puts).with "h1"
+
+ @ca.expects(:print).with("host2").returns nil
+ Puppet.expects(:err).with { |msg| msg.include?("host2") }
+
+ @applier.apply(@ca)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/certificate_factory.rb b/spec/unit/ssl/certificate_factory.rb
new file mode 100755
index 000000000..822b330f2
--- /dev/null
+++ b/spec/unit/ssl/certificate_factory.rb
@@ -0,0 +1,107 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_factory'
+
+describe Puppet::SSL::CertificateFactory do
+ before do
+ @cert_type = mock 'cert_type'
+ @name = mock 'name'
+ @csr = stub 'csr', :subject => @name
+ @issuer = mock 'issuer'
+ @serial = mock 'serial'
+
+ @factory = Puppet::SSL::CertificateFactory.new(@cert_type, @csr, @issuer, @serial)
+ end
+
+ describe "when initializing" do
+ it "should set its :cert_type to its first argument" do
+ @factory.cert_type.should equal(@cert_type)
+ end
+
+ it "should set its :csr to its second argument" do
+ @factory.csr.should equal(@csr)
+ end
+
+ it "should set its :issuer to its third argument" do
+ @factory.issuer.should equal(@issuer)
+ end
+
+ it "should set its :serial to its fourth argument" do
+ @factory.serial.should equal(@serial)
+ end
+
+ it "should set its name to the subject of the csr" do
+ @factory.name.should equal(@name)
+ end
+ end
+
+ describe "when generating the certificate" do
+ before do
+ @cert = mock 'cert'
+
+ @cert.stub_everything
+
+ @factory.stubs :build_extensions
+
+ @factory.stubs :set_ttl
+
+ @issuer_name = mock 'issuer_name'
+ @issuer.stubs(:subject).returns @issuer_name
+
+ @public_key = mock 'public_key'
+ @csr.stubs(:public_key).returns @public_key
+
+ OpenSSL::X509::Certificate.stubs(:new).returns @cert
+ end
+
+ it "should return a new X509 certificate" do
+ OpenSSL::X509::Certificate.expects(:new).returns @cert
+ @factory.result.should equal(@cert)
+ end
+
+ it "should set the certificate's version to 2" do
+ @cert.expects(:version=).with 2
+ @factory.result
+ end
+
+ it "should set the certificate's subject to the CSR's subject" do
+ @cert.expects(:subject=).with @name
+ @factory.result
+ end
+
+ it "should set the certificate's issuer to the Issuer's subject" do
+ @cert.expects(:issuer=).with @issuer_name
+ @factory.result
+ end
+
+ it "should set the certificate's public key to the CSR's public key" do
+ @cert.expects(:public_key=).with @public_key
+ @factory.result
+ end
+
+ it "should set the certificate's serial number to the provided serial number" do
+ @cert.expects(:serial=).with @serial
+ @factory.result
+ end
+
+ it "should build extensions for the certificate" do
+ @factory.expects(:build_extensions)
+ @factory.result
+ end
+
+ it "should set the ttl of the certificate" do
+ @factory.expects(:set_ttl)
+ @factory.result
+ end
+ end
+
+ describe "when building extensions" do
+ it "should have tests"
+ end
+
+ describe "when setting the ttl" do
+ it "should have tests"
+ end
+end
diff --git a/spec/unit/ssl/certificate_request.rb b/spec/unit/ssl/certificate_request.rb
new file mode 100755
index 000000000..351e5bbd5
--- /dev/null
+++ b/spec/unit/ssl/certificate_request.rb
@@ -0,0 +1,167 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_request'
+require 'puppet/ssl/key'
+
+describe Puppet::SSL::CertificateRequest do
+ before do
+ @class = Puppet::SSL::CertificateRequest
+ end
+
+ it "should be extended with the Indirector module" do
+ @class.metaclass.should be_include(Puppet::Indirector)
+ end
+
+ it "should indirect certificate_request" do
+ @class.indirection.name.should == :certificate_request
+ end
+
+ it "should use any provided name as its name" do
+ @class.new("myname").name.should == "myname"
+ end
+
+ it "should default to the :file terminus" do
+ @class.indirection.terminus_class.should == :file
+ end
+
+ describe "when managing instances" do
+ before do
+ @request = @class.new("myname")
+ end
+
+ it "should have a name attribute" do
+ @request.name.should == "myname"
+ end
+
+ it "should have a content attribute" do
+ @request.should respond_to(:content)
+ end
+
+ it "should be able to read requests from disk" do
+ path = "/my/path"
+ File.expects(:read).with(path).returns("my request")
+ request = mock 'request'
+ OpenSSL::X509::Request.expects(:new).with("my request").returns(request)
+ @request.read(path).should equal(request)
+ @request.content.should equal(request)
+ end
+
+ it "should return an empty string when converted to a string with no request" do
+ @request.to_s.should == ""
+ end
+
+ it "should convert the request to pem format when converted to a string" do
+ request = mock 'request', :to_pem => "pem"
+ @request.content = request
+ @request.to_s.should == "pem"
+ end
+
+ it "should have a :to_text method that it delegates to the actual key" do
+ real_request = mock 'request'
+ real_request.expects(:to_text).returns "requesttext"
+ @request.content = real_request
+ @request.to_text.should == "requesttext"
+ end
+ end
+
+ describe "when generating" do
+ before do
+ @instance = @class.new("myname")
+
+ key = Puppet::SSL::Key.new("myname")
+ @key = key.generate
+
+ @request = OpenSSL::X509::Request.new
+ OpenSSL::X509::Request.expects(:new).returns(@request)
+
+ @request.stubs(:verify).returns(true)
+ end
+
+ it "should use the content of the provided key if the key is a Puppet::SSL::Key instance" do
+ key = Puppet::SSL::Key.new("test")
+ key.expects(:content).returns @key
+
+ @request.expects(:sign).with{ |key, digest| key == @key }
+ @instance.generate(key)
+ end
+
+ it "should log that it is creating a new certificate request" do
+ Puppet.expects(:info)
+ @instance.generate(@key)
+ end
+
+ it "should set the subject to [CN, name]" do
+ subject = mock 'subject'
+ OpenSSL::X509::Name.expects(:new).with([["CN", @instance.name]]).returns(subject)
+ @request.expects(:subject=).with(subject)
+ @instance.generate(@key)
+ end
+
+ it "should set the version to 0" do
+ @request.expects(:version=).with(0)
+ @instance.generate(@key)
+ end
+
+ it "should set the public key to the provided key's public key" do
+ # Yay, the private key extracts a new key each time.
+ pubkey = @key.public_key
+ @key.stubs(:public_key).returns pubkey
+ @request.expects(:public_key=).with(@key.public_key)
+ @instance.generate(@key)
+ end
+
+ it "should sign the csr with the provided key and a digest" do
+ digest = mock 'digest'
+ OpenSSL::Digest::MD5.expects(:new).returns(digest)
+ @request.expects(:sign).with(@key, digest)
+ @instance.generate(@key)
+ end
+
+ it "should verify the generated request using the public key" do
+ @request.expects(:verify).with(@key.public_key)
+ @instance.generate(@key)
+ end
+
+ it "should fail if verification fails" do
+ @request.expects(:verify).returns false
+
+ lambda { @instance.generate(@key) }.should raise_error(Puppet::Error)
+ end
+
+ it "should return the generated request" do
+ @instance.generate(@key).should equal(@request)
+ end
+
+ it "should set its content to the generated request" do
+ @instance.generate(@key)
+ @instance.content.should equal(@request)
+ end
+ end
+
+ describe "when a CSR is saved" do
+ describe "and a CA is available" do
+ it "should save the CSR and trigger autosigning" do
+ ca = mock 'ca', :autosign
+ Puppet::SSL::CertificateAuthority.expects(:instance).returns ca
+
+ csr = Puppet::SSL::CertificateRequest.new("me")
+ Puppet::SSL::CertificateRequest.indirection.expects(:save).with(csr)
+
+ csr.save
+ end
+ end
+
+ describe "and a CA is not available" do
+ it "should save the CSR" do
+ Puppet::SSL::CertificateAuthority.expects(:instance).returns nil
+
+ csr = Puppet::SSL::CertificateRequest.new("me")
+ Puppet::SSL::CertificateRequest.indirection.expects(:save).with(csr)
+
+ csr.save
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/certificate_revocation_list.rb b/spec/unit/ssl/certificate_revocation_list.rb
new file mode 100755
index 000000000..13febf744
--- /dev/null
+++ b/spec/unit/ssl/certificate_revocation_list.rb
@@ -0,0 +1,166 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate_revocation_list'
+
+describe Puppet::SSL::CertificateRevocationList do
+ before do
+ @cert = stub 'cert', :subject => "mysubject"
+ @key = stub 'key', :private? => true
+
+ @class = Puppet::SSL::CertificateRevocationList
+ end
+
+ it "should default to the :file terminus" do
+ @class.indirection.terminus_class.should == :file
+ end
+
+ describe "when an instance" do
+ before do
+ @class.any_instance.stubs(:read_or_generate)
+
+ @crl = @class.new("whatever")
+ end
+
+ it "should always use 'crl' for its name" do
+ @crl.name.should == "crl"
+ end
+
+ it "should have a content attribute" do
+ @crl.should respond_to(:content)
+ end
+ end
+
+ describe "when initializing" do
+ it "should fail if :cacrl is set to false" do
+ Puppet.settings.expects(:value).with(:cacrl).returns false
+ lambda { @class.new("crl") }.should raise_error(Puppet::Error)
+ end
+
+ it "should fail if :cacrl is set to the string 'false'" do
+ Puppet.settings.expects(:value).with(:cacrl).returns "false"
+ lambda { @class.new("crl") }.should raise_error(Puppet::Error)
+ end
+ end
+
+ describe "when generating the crl" do
+ before do
+ @real_crl = mock 'crl'
+ @real_crl.stub_everything
+
+ OpenSSL::X509::CRL.stubs(:new).returns(@real_crl)
+
+ @class.any_instance.stubs(:read_or_generate)
+
+ @crl = @class.new("crl")
+ end
+
+ it "should set its issuer to the subject of the passed certificate" do
+ @real_crl.expects(:issuer=).with(@cert.subject)
+
+ @crl.generate(@cert, @key)
+ end
+
+ it "should set its version to 1" do
+ @real_crl.expects(:version=).with(1)
+
+ @crl.generate(@cert, @key)
+ end
+
+ it "should create an instance of OpenSSL::X509::CRL" do
+ OpenSSL::X509::CRL.expects(:new).returns(@real_crl)
+
+ @crl.generate(@cert, @key)
+ end
+
+ # The next three tests aren't good, but at least they
+ # specify the behaviour.
+ it "should add an extension for the CRL number" do
+ @real_crl.expects(:extensions=)
+ @crl.generate(@cert, @key)
+ end
+
+ it "should set the last update time" do
+ @real_crl.expects(:last_update=)
+ @crl.generate(@cert, @key)
+ end
+
+ it "should set the next update time" do
+ @real_crl.expects(:next_update=)
+ @crl.generate(@cert, @key)
+ end
+
+ it "should sign the CRL" do
+ @real_crl.expects(:sign).with { |key, digest| key == @key }
+ @crl.generate(@cert, @key)
+ end
+
+ it "should set the content to the generated crl" do
+ @crl.generate(@cert, @key)
+ @crl.content.should equal(@real_crl)
+ end
+
+ it "should return the generated crl" do
+ @crl.generate(@cert, @key).should equal(@real_crl)
+ end
+ end
+
+ # This test suite isn't exactly complete, because the
+ # SSL stuff is very complicated. It just hits the high points.
+ describe "when revoking a certificate" do
+ before do
+ @class.wrapped_class.any_instance.stubs(:issuer=)
+ @class.wrapped_class.any_instance.stubs(:sign)
+
+ @crl = @class.new("crl")
+ @crl.generate(@cert, @key)
+ @crl.content.stubs(:sign)
+
+ @crl.stubs :save
+
+ @key = mock 'key'
+ end
+
+ it "should require a serial number and the CA's private key" do
+ lambda { @crl.revoke }.should raise_error(ArgumentError)
+ end
+
+ it "should default to OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE as the revocation reason" do
+ # This makes it a bit more of an integration test than we'd normally like, but that's life
+ # with openssl.
+ reason = OpenSSL::ASN1::Enumerated(OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
+ OpenSSL::ASN1.expects(:Enumerated).with(OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE).returns reason
+
+ @crl.revoke(1, @key)
+ end
+
+ it "should mark the CRL as updated" do
+ time = Time.now
+ Time.stubs(:now).returns time
+
+ @crl.content.expects(:last_update=).with(time)
+
+ @crl.revoke(1, @key)
+ end
+
+ it "should mark the CRL valid for five years" do
+ time = Time.now
+ Time.stubs(:now).returns time
+
+ @crl.content.expects(:next_update=).with(time + (5 * 365*24*60*60))
+
+ @crl.revoke(1, @key)
+ end
+
+ it "should sign the CRL with the CA's private key and a digest instance" do
+ @crl.content.expects(:sign).with { |key, digest| key == @key and digest.is_a?(OpenSSL::Digest::SHA1) }
+ @crl.revoke(1, @key)
+ end
+
+ it "should save the CRL" do
+ @crl.expects :save
+ @crl.revoke(1, @key)
+ end
+ end
+end
diff --git a/spec/unit/ssl/host.rb b/spec/unit/ssl/host.rb
new file mode 100755
index 000000000..b717da80e
--- /dev/null
+++ b/spec/unit/ssl/host.rb
@@ -0,0 +1,431 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/host'
+
+describe Puppet::SSL::Host do
+ before do
+ @class = Puppet::SSL::Host
+ @host = @class.new("myname")
+ end
+
+ it "should use any provided name as its name" do
+ @host.name.should == "myname"
+ end
+
+ it "should retrieve its public key from its private key" do
+ realkey = mock 'realkey'
+ key = stub 'key', :content => realkey
+ Puppet::SSL::Key.stubs(:find).returns(key)
+ pubkey = mock 'public_key'
+ realkey.expects(:public_key).returns pubkey
+
+ @host.public_key.should equal(pubkey)
+ end
+
+ it "should default to being a non-ca host" do
+ @host.ca?.should be_false
+ end
+
+ it "should be a ca host if its name matches the CA_NAME" do
+ Puppet::SSL::Host.stubs(:ca_name).returns "yayca"
+ Puppet::SSL::Host.new("yayca").should be_ca
+ end
+
+ it "should have a method for determining the CA location" do
+ Puppet::SSL::Host.should respond_to(:ca_location)
+ end
+
+ it "should have a method for specifying the CA location" do
+ Puppet::SSL::Host.should respond_to(:ca_location=)
+ end
+
+ describe "when specifying the CA location" do
+ before do
+ [Puppet::SSL::Key, Puppet::SSL::Certificate, Puppet::SSL::CertificateRequest, Puppet::SSL::CertificateRevocationList].each do |klass|
+ klass.stubs(:terminus_class=)
+ klass.stubs(:cache_class=)
+ end
+ end
+
+ it "should support the location ':local'" do
+ lambda { Puppet::SSL::Host.ca_location = :local }.should_not raise_error
+ end
+
+ it "should support the location ':remote'" do
+ lambda { Puppet::SSL::Host.ca_location = :remote }.should_not raise_error
+ end
+
+ it "should support the location ':none'" do
+ lambda { Puppet::SSL::Host.ca_location = :none }.should_not raise_error
+ end
+
+ it "should not support other modes" do
+ lambda { Puppet::SSL::Host.ca_location = :whatever }.should raise_error(ArgumentError)
+ end
+
+ describe "as 'local'" do
+ it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do
+ Puppet::SSL::Certificate.expects(:cache_class=).with :file
+ Puppet::SSL::CertificateRequest.expects(:cache_class=).with :file
+ Puppet::SSL::CertificateRevocationList.expects(:cache_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :local
+ end
+
+ it "should set the terminus class for Key as :file" do
+ Puppet::SSL::Key.expects(:terminus_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :local
+ end
+
+ it "should set the terminus class for Certificate, CertificateRevocationList, and CertificateRequest as :ca" do
+ Puppet::SSL::Certificate.expects(:terminus_class=).with :ca
+ Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :ca
+ Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :ca
+
+ Puppet::SSL::Host.ca_location = :local
+ end
+ end
+
+ describe "as 'remote'" do
+ it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do
+ Puppet::SSL::Certificate.expects(:cache_class=).with :file
+ Puppet::SSL::CertificateRequest.expects(:cache_class=).with :file
+ Puppet::SSL::CertificateRevocationList.expects(:cache_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :remote
+ end
+
+ it "should set the terminus class for Key as :file" do
+ Puppet::SSL::Key.expects(:terminus_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :remote
+ end
+
+ it "should set the terminus class for Certificate, CertificateRevocationList, and CertificateRequest as :rest" do
+ Puppet::SSL::Certificate.expects(:terminus_class=).with :rest
+ Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :rest
+ Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :rest
+
+ Puppet::SSL::Host.ca_location = :remote
+ end
+ end
+
+ describe "as 'none'" do
+ it "should set the terminus class for Key, Certificate, CertificateRevocationList, and CertificateRequest as :file" do
+ Puppet::SSL::Key.expects(:terminus_class=).with :file
+ Puppet::SSL::Certificate.expects(:terminus_class=).with :file
+ Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :file
+ Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :file
+
+ Puppet::SSL::Host.ca_location = :none
+ end
+ end
+ end
+
+ it "should have a class method for destroying all files related to a given host" do
+ Puppet::SSL::Host.should respond_to(:destroy)
+ end
+
+ describe "when destroying a host's SSL files" do
+ before do
+ Puppet::SSL::Key.stubs(:destroy).returns false
+ Puppet::SSL::Certificate.stubs(:destroy).returns false
+ Puppet::SSL::CertificateRequest.stubs(:destroy).returns false
+ end
+
+ it "should destroy its certificate, certificate request, and key" do
+ Puppet::SSL::Key.expects(:destroy).with("myhost")
+ Puppet::SSL::Certificate.expects(:destroy).with("myhost")
+ Puppet::SSL::CertificateRequest.expects(:destroy).with("myhost")
+
+ Puppet::SSL::Host.destroy("myhost")
+ end
+
+ it "should return true if any of the classes returned true" do
+ Puppet::SSL::Certificate.expects(:destroy).with("myhost").returns true
+
+ Puppet::SSL::Host.destroy("myhost").should be_true
+ end
+
+ it "should return false if none of the classes returned true" do
+ Puppet::SSL::Host.destroy("myhost").should be_false
+ end
+ end
+
+ describe "when initializing" do
+ it "should default its name to the :certname setting" do
+ Puppet.settings.expects(:value).with(:certname).returns "myname"
+
+ Puppet::SSL::Host.new.name.should == "myname"
+ end
+
+ it "should indicate that it is a CA host if its name matches the ca_name constant" do
+ Puppet::SSL::Host.stubs(:ca_name).returns "myca"
+ Puppet::SSL::Host.new("myca").should be_ca
+ end
+ end
+
+ describe "when managing its private key" do
+ before do
+ @realkey = "mykey"
+ @key = stub 'key', :content => @realkey
+ end
+
+ it "should return nil if the key is not set and cannot be found" do
+ Puppet::SSL::Key.expects(:find).with("myname").returns(nil)
+ @host.key.should be_nil
+ end
+
+ it "should find the key in the Key class and return the Puppet instance" do
+ Puppet::SSL::Key.expects(:find).with("myname").returns(@key)
+ @host.key.should equal(@key)
+ end
+
+ it "should be able to generate and save a new key" do
+ Puppet::SSL::Key.expects(:new).with("myname").returns(@key)
+
+ @key.expects(:generate)
+ @key.expects(:save)
+
+ @host.generate_key.should be_true
+ @host.key.should equal(@key)
+ end
+
+ it "should return any previously found key without requerying" do
+ Puppet::SSL::Key.expects(:find).with("myname").returns(@key).once
+ @host.key.should equal(@key)
+ @host.key.should equal(@key)
+ end
+ end
+
+ describe "when managing its certificate request" do
+ before do
+ @realrequest = "real request"
+ @request = stub 'request', :content => @realrequest
+ end
+
+ it "should return nil if the key is not set and cannot be found" do
+ Puppet::SSL::CertificateRequest.expects(:find).with("myname").returns(nil)
+ @host.certificate_request.should be_nil
+ end
+
+ it "should find the request in the Key class and return it and return the Puppet SSL request" do
+ Puppet::SSL::CertificateRequest.expects(:find).with("myname").returns @request
+
+ @host.certificate_request.should equal(@request)
+ end
+
+ it "should generate a new key when generating the cert request if no key exists" do
+ Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request
+
+ key = stub 'key', :public_key => mock("public_key"), :content => "mycontent"
+
+ @host.expects(:key).times(2).returns(nil).then.returns(key)
+ @host.expects(:generate_key).returns(key)
+
+ @request.stubs(:generate)
+ @request.stubs(:save)
+
+ @host.generate_certificate_request
+ end
+
+ it "should be able to generate and save a new request using the private key" do
+ Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request
+
+ key = stub 'key', :public_key => mock("public_key"), :content => "mycontent"
+ @host.stubs(:key).returns(key)
+ @request.expects(:generate).with("mycontent")
+ @request.expects(:save)
+
+ @host.generate_certificate_request.should be_true
+ @host.certificate_request.should equal(@request)
+ end
+
+ it "should return any previously found request without requerying" do
+ Puppet::SSL::CertificateRequest.expects(:find).with("myname").returns(@request).once
+
+ @host.certificate_request.should equal(@request)
+ @host.certificate_request.should equal(@request)
+ end
+ end
+
+ describe "when managing its certificate" do
+ before do
+ @realcert = mock 'certificate'
+ @cert = stub 'cert', :content => @realcert
+ end
+
+ it "should find the certificate in the Certificate class and return the Puppet certificate instance" do
+ Puppet::SSL::Certificate.expects(:find).with("myname").returns @cert
+
+ @host.certificate.should equal(@cert)
+ end
+
+ it "should return any previously found certificate" do
+ Puppet::SSL::Certificate.expects(:find).with("myname").returns(@cert).once
+
+ @host.certificate.should equal(@cert)
+ @host.certificate.should equal(@cert)
+ end
+ end
+
+ it "should have a method for listing certificate hosts" do
+ Puppet::SSL::Host.should respond_to(:search)
+ end
+
+ describe "when listing certificate hosts" do
+ it "should default to listing all clients with any file types" do
+ Puppet::SSL::Key.expects(:search).returns []
+ Puppet::SSL::Certificate.expects(:search).returns []
+ Puppet::SSL::CertificateRequest.expects(:search).returns []
+ Puppet::SSL::Host.search
+ end
+
+ it "should be able to list only clients with a key" do
+ Puppet::SSL::Key.expects(:search).returns []
+ Puppet::SSL::Certificate.expects(:search).never
+ Puppet::SSL::CertificateRequest.expects(:search).never
+ Puppet::SSL::Host.search :for => Puppet::SSL::Key
+ end
+
+ it "should be able to list only clients with a certificate" do
+ Puppet::SSL::Key.expects(:search).never
+ Puppet::SSL::Certificate.expects(:search).returns []
+ Puppet::SSL::CertificateRequest.expects(:search).never
+ Puppet::SSL::Host.search :for => Puppet::SSL::Certificate
+ end
+
+ it "should be able to list only clients with a certificate request" do
+ Puppet::SSL::Key.expects(:search).never
+ Puppet::SSL::Certificate.expects(:search).never
+ Puppet::SSL::CertificateRequest.expects(:search).returns []
+ Puppet::SSL::Host.search :for => Puppet::SSL::CertificateRequest
+ end
+
+ it "should return a Host instance created with the name of each found instance" do
+ key = stub 'key', :name => "key"
+ cert = stub 'cert', :name => "cert"
+ csr = stub 'csr', :name => "csr"
+
+ Puppet::SSL::Key.expects(:search).returns [key]
+ Puppet::SSL::Certificate.expects(:search).returns [cert]
+ Puppet::SSL::CertificateRequest.expects(:search).returns [csr]
+
+ returned = []
+ %w{key cert csr}.each do |name|
+ result = mock(name)
+ returned << result
+ Puppet::SSL::Host.expects(:new).with(name).returns result
+ end
+
+ result = Puppet::SSL::Host.search
+ returned.each do |r|
+ result.should be_include(r)
+ end
+ end
+ end
+
+ it "should have a method for generating all necessary files" do
+ Puppet::SSL::Host.new("me").should respond_to(:generate)
+ end
+
+ describe "when generating files" do
+ before do
+ @host = Puppet::SSL::Host.new("me")
+ @host.stubs(:generate_key)
+ @host.stubs(:generate_certificate_request)
+ end
+
+ it "should generate a key if one is not present" do
+ @host.expects(:key).returns nil
+ @host.expects(:generate_key)
+
+ @host.generate
+ end
+
+ it "should generate a certificate request if one is not present" do
+ @host.expects(:certificate_request).returns nil
+ @host.expects(:generate_certificate_request)
+
+ @host.generate
+ end
+
+ describe "and it can create a certificate authority" do
+ before do
+ @ca = mock 'ca'
+ Puppet::SSL::CertificateAuthority.stubs(:instance).returns @ca
+ end
+
+ it "should use the CA to sign its certificate request if it does not have a certificate" do
+ @host.expects(:certificate).returns nil
+
+ @ca.expects(:sign).with(@host.name)
+
+ @host.generate
+ end
+ end
+
+ describe "and it cannot create a certificate authority" do
+ before do
+ Puppet::SSL::CertificateAuthority.stubs(:instance).returns nil
+ end
+
+ it "should seek its certificate" do
+ @host.expects(:certificate)
+
+ @host.generate
+ end
+ end
+ end
+
+ it "should have a method for creating an SSL store" do
+ Puppet::SSL::Host.new("me").should respond_to(:ssl_store)
+ end
+
+ describe "when creating an SSL store" do
+ before do
+ @host = Puppet::SSL::Host.new("me")
+ @store = mock 'store'
+ @store.stub_everything
+ OpenSSL::X509::Store.stubs(:new).returns @store
+
+ Puppet.settings.stubs(:value).returns "ssl_host_testing"
+ end
+
+ it "should accept a purpose" do
+ @store.expects(:purpose=).with "my special purpose"
+ @host.ssl_store("my special purpose")
+ end
+
+ it "should default to OpenSSL::X509::PURPOSE_ANY as the purpose" do
+ @store.expects(:purpose=).with OpenSSL::X509::PURPOSE_ANY
+ @host.ssl_store
+ end
+
+ it "should add the local CA cert file" do
+ Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert/file"
+ @store.expects(:add_file).with "/ca/cert/file"
+ @host.ssl_store
+ end
+
+ describe "and a CRL is available" do
+ before do
+ @crl = stub 'crl', :content => "real_crl"
+ Puppet::SSL::CertificateRevocationList.stubs(:find).returns @crl
+ end
+
+ it "should add the CRL" do
+ @store.expects(:add_crl).with "real_crl"
+ @host.ssl_store
+ end
+
+ it "should set the flags to OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK" do
+ @store.expects(:flags=).with OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK
+ @host.ssl_store
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/inventory.rb b/spec/unit/ssl/inventory.rb
new file mode 100755
index 000000000..bf1dbfb48
--- /dev/null
+++ b/spec/unit/ssl/inventory.rb
@@ -0,0 +1,180 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/inventory'
+
+describe Puppet::SSL::Inventory do
+ before do
+ @class = Puppet::SSL::Inventory
+ end
+
+ it "should use the :certinventory setting for the path to the inventory file" do
+ Puppet.settings.expects(:value).with(:cert_inventory).returns "/inven/tory"
+
+ @class.any_instance.stubs(:rebuild)
+
+ @class.new.path.should == "/inven/tory"
+ end
+
+ describe "when initializing" do
+ it "should set its path to the inventory file" do
+ Puppet.settings.stubs(:value).with(:cert_inventory).returns "/inven/tory"
+ @class.new.path.should == "/inven/tory"
+ end
+ end
+
+ describe "when managing an inventory" do
+ before do
+ Puppet.settings.stubs(:value).with(:cert_inventory).returns "/inven/tory"
+
+ FileTest.stubs(:exist?).with("/inven/tory").returns true
+
+ @inventory = @class.new
+
+ @cert = mock 'cert'
+ end
+
+ describe "and creating the inventory file" do
+ before do
+ Puppet.settings.stubs(:write)
+ FileTest.stubs(:exist?).with("/inven/tory").returns false
+
+ Puppet::SSL::Certificate.stubs(:search).returns []
+ end
+
+ it "should log that it is building a new inventory file" do
+ Puppet.expects(:notice)
+
+ @inventory.rebuild
+ end
+
+ it "should use the Settings to write to the file" do
+ Puppet.settings.expects(:write).with(:cert_inventory)
+
+ @inventory.rebuild
+ end
+
+ it "should add a header to the file" do
+ fh = mock 'filehandle'
+ Puppet.settings.stubs(:write).yields fh
+ fh.expects(:print).with { |str| str =~ /^#/ }
+
+ @inventory.rebuild
+ end
+
+ it "should add formatted information on all existing certificates" do
+ cert1 = mock 'cert1'
+ cert2 = mock 'cert2'
+
+ Puppet::SSL::Certificate.expects(:search).with("*").returns [cert1, cert2]
+
+ @class.any_instance.expects(:add).with(cert1)
+ @class.any_instance.expects(:add).with(cert2)
+
+ @inventory.rebuild
+ end
+ end
+
+ describe "and adding a certificate" do
+ it "should build the inventory file if one does not exist" do
+ Puppet.settings.stubs(:value).with(:cert_inventory).returns "/inven/tory"
+ Puppet.settings.stubs(:write)
+
+ FileTest.expects(:exist?).with("/inven/tory").returns false
+
+ @inventory.expects(:rebuild)
+
+ @inventory.add(@cert)
+ end
+
+ it "should use the Settings to write to the file" do
+ Puppet.settings.expects(:write).with(:cert_inventory, "a")
+
+ @inventory.add(@cert)
+ end
+
+ it "should use the actual certificate if it was passed a Puppet certificate" do
+ cert = Puppet::SSL::Certificate.new("mycert")
+ cert.content = @cert
+
+ fh = stub 'filehandle', :print => nil
+ Puppet.settings.stubs(:write).yields fh
+
+ @inventory.expects(:format).with(@cert)
+
+ @inventory.add(@cert)
+ end
+
+ it "should add formatted certificate information to the end of the file" do
+ fh = mock 'filehandle'
+
+ Puppet.settings.stubs(:write).yields fh
+
+ @inventory.expects(:format).with(@cert).returns "myformat"
+
+ fh.expects(:print).with("myformat")
+
+ @inventory.add(@cert)
+ end
+ end
+
+ describe "and formatting a certificate" do
+ before do
+ @cert = stub 'cert', :not_before => Time.now, :not_after => Time.now, :subject => "mycert", :serial => 15
+ end
+
+ it "should print the serial number as a 4 digit hex number in the first field" do
+ @inventory.format(@cert).split[0].should == "0x000f" # 15 in hex
+ end
+
+ it "should print the not_before date in '%Y-%m-%dT%H:%M:%S%Z' format in the second field" do
+ @cert.not_before.expects(:strftime).with('%Y-%m-%dT%H:%M:%S%Z').returns "before_time"
+
+ @inventory.format(@cert).split[1].should == "before_time"
+ end
+
+ it "should print the not_after date in '%Y-%m-%dT%H:%M:%S%Z' format in the third field" do
+ @cert.not_after.expects(:strftime).with('%Y-%m-%dT%H:%M:%S%Z').returns "after_time"
+
+ @inventory.format(@cert).split[2].should == "after_time"
+ end
+
+ it "should print the subject in the fourth field" do
+ @inventory.format(@cert).split[3].should == "mycert"
+ end
+
+ it "should add a carriage return" do
+ @inventory.format(@cert).should =~ /\n$/
+ end
+
+ it "should produce a line consisting of the serial number, start date, expiration date, and subject" do
+ # Just make sure our serial and subject bracket the lines.
+ @inventory.format(@cert).should =~ /^0x.+mycert$/
+ end
+ end
+
+ it "should be able to find a given host's serial number" do
+ @inventory.should respond_to(:serial)
+ end
+
+ describe "and finding a serial number" do
+ it "should return nil if the inventory file is missing" do
+ FileTest.expects(:exist?).with("/inven/tory").returns false
+ @inventory.serial(:whatever).should be_nil
+ end
+
+ it "should return the serial number from the line matching the provided name" do
+ File.expects(:readlines).with("/inven/tory").returns ["0x00f blah blah /CN=me\n", "0x001 blah blah /CN=you\n"]
+
+ @inventory.serial("me").should == 15
+ end
+
+ it "should return the number as an integer" do
+ File.expects(:readlines).with("/inven/tory").returns ["0x00f blah blah /CN=me\n", "0x001 blah blah /CN=you\n"]
+
+ @inventory.serial("me").should == 15
+ end
+ end
+ end
+end
diff --git a/spec/unit/ssl/key.rb b/spec/unit/ssl/key.rb
new file mode 100755
index 000000000..4cd8e856d
--- /dev/null
+++ b/spec/unit/ssl/key.rb
@@ -0,0 +1,190 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/key'
+
+describe Puppet::SSL::Key do
+ before do
+ @class = Puppet::SSL::Key
+ end
+
+ it "should be extended with the Indirector module" do
+ @class.metaclass.should be_include(Puppet::Indirector)
+ end
+
+ it "should indirect key" do
+ @class.indirection.name.should == :key
+ end
+
+ it "should default to the :file terminus" do
+ @class.indirection.terminus_class.should == :file
+ end
+
+ it "should have a method for determining whether it's a CA key" do
+ @class.new("test").should respond_to(:ca?)
+ end
+
+ it "should consider itself a ca key if its name matches the CA_NAME" do
+ @class.new(Puppet::SSL::Host.ca_name).should be_ca
+ end
+
+ describe "when initializing" do
+ it "should set its password file to the :capass if it's a CA key" do
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:capass).returns "/ca/pass"
+
+ key = Puppet::SSL::Key.new(Puppet::SSL::Host.ca_name)
+ key.password_file.should == "/ca/pass"
+ end
+
+ it "should set its password file to the default password file if it is not the CA key" do
+ Puppet.settings.stubs(:value).returns "whatever"
+ Puppet.settings.stubs(:value).with(:passfile).returns "/normal/pass"
+
+ key = Puppet::SSL::Key.new("notca")
+ key.password_file.should == "/normal/pass"
+ end
+ end
+
+ describe "when managing instances" do
+ before do
+ @key = @class.new("myname")
+ end
+
+ it "should have a name attribute" do
+ @key.name.should == "myname"
+ end
+
+ it "should have a content attribute" do
+ @key.should respond_to(:content)
+ end
+
+ it "should be able to read keys from disk" do
+ path = "/my/path"
+ File.expects(:read).with(path).returns("my key")
+ key = mock 'key'
+ OpenSSL::PKey::RSA.expects(:new).returns(key)
+ @key.read(path).should equal(key)
+ @key.content.should equal(key)
+ end
+
+ it "should not try to use the provided password file if the file does not exist" do
+ FileTest.stubs(:exist?).returns false
+ @key.password_file = "/path/to/password"
+
+ path = "/my/path"
+
+ File.stubs(:read).with(path).returns("my key")
+ OpenSSL::PKey::RSA.expects(:new).with("my key", nil).returns(mock('key'))
+ File.expects(:read).with("/path/to/password").never
+
+ @key.read(path)
+ end
+
+ it "should read the key with the password retrieved from the password file if one is provided" do
+ FileTest.stubs(:exist?).returns true
+ @key.password_file = "/path/to/password"
+
+ path = "/my/path"
+ File.expects(:read).with(path).returns("my key")
+ File.expects(:read).with("/path/to/password").returns("my password")
+
+ key = mock 'key'
+ OpenSSL::PKey::RSA.expects(:new).with("my key", "my password").returns(key)
+ @key.read(path).should equal(key)
+ @key.content.should equal(key)
+ end
+
+ it "should return an empty string when converted to a string with no key" do
+ @key.to_s.should == ""
+ end
+
+ it "should convert the key to pem format when converted to a string" do
+ key = mock 'key', :to_pem => "pem"
+ @key.content = key
+ @key.to_s.should == "pem"
+ end
+
+ it "should have a :to_text method that it delegates to the actual key" do
+ real_key = mock 'key'
+ real_key.expects(:to_text).returns "keytext"
+ @key.content = real_key
+ @key.to_text.should == "keytext"
+ end
+ end
+
+ describe "when generating the private key" do
+ before do
+ @instance = @class.new("test")
+
+ @key = mock 'key'
+ end
+
+ it "should create an instance of OpenSSL::PKey::RSA" do
+ OpenSSL::PKey::RSA.expects(:new).returns(@key)
+
+ @instance.generate
+ end
+
+ it "should create the private key with the keylength specified in the settings" do
+ Puppet.settings.expects(:value).with(:keylength).returns("50")
+ OpenSSL::PKey::RSA.expects(:new).with(50).returns(@key)
+
+ @instance.generate
+ end
+
+ it "should set the content to the generated key" do
+ OpenSSL::PKey::RSA.stubs(:new).returns(@key)
+ @instance.generate
+ @instance.content.should equal(@key)
+ end
+
+ it "should return the generated key" do
+ OpenSSL::PKey::RSA.stubs(:new).returns(@key)
+ @instance.generate.should equal(@key)
+ end
+
+ it "should return the key in pem format" do
+ @instance.generate
+ @instance.content.expects(:to_pem).returns "my normal key"
+ @instance.to_s.should == "my normal key"
+ end
+
+ describe "with a password file set" do
+ it "should return a nil password if the password file does not exist" do
+ FileTest.expects(:exist?).with("/path/to/pass").returns false
+ File.expects(:read).with("/path/to/pass").never
+
+ @instance.password_file = "/path/to/pass"
+
+ @instance.password.should be_nil
+ end
+
+ it "should return the contents of the password file as its password" do
+ FileTest.expects(:exist?).with("/path/to/pass").returns true
+ File.expects(:read).with("/path/to/pass").returns "my password"
+
+ @instance.password_file = "/path/to/pass"
+
+ @instance.password.should == "my password"
+ end
+
+ it "should export the private key to text using the password" do
+ Puppet.settings.stubs(:value).with(:keylength).returns("50")
+
+ @instance.password_file = "/path/to/pass"
+ @instance.stubs(:password).returns "my password"
+
+ OpenSSL::PKey::RSA.expects(:new).returns(@key)
+ @instance.generate
+
+ cipher = mock 'cipher'
+ OpenSSL::Cipher::DES.expects(:new).with(:EDE3, :CBC).returns cipher
+ @key.expects(:export).with(cipher, "my password").returns "my encrypted key"
+
+ @instance.to_s.should == "my encrypted key"
+ end
+ end
+ end
+end
diff --git a/spec/unit/transaction/report.rb b/spec/unit/transaction/report.rb
index 644f8d709..8d49b16a0 100755
--- a/spec/unit/transaction/report.rb
+++ b/spec/unit/transaction/report.rb
@@ -35,6 +35,6 @@ describe Puppet::Transaction::Report, " when being indirect" do
end
after do
- Puppet::Indirector::Indirection.clear_cache
+ Puppet::Util::Cacher.invalidate
end
end
diff --git a/spec/unit/type/file.rb b/spec/unit/type/file.rb
index 12b806d88..d6add8609 100755
--- a/spec/unit/type/file.rb
+++ b/spec/unit/type/file.rb
@@ -93,8 +93,4 @@ describe Puppet::Type.type(:file) do
("%o" % (File.stat(@file).mode & 007777)).should == "%o" % 0755
end
end
-
- after do
- Puppet::Type::File.clear
- end
end
diff --git a/spec/unit/type/interface.rb b/spec/unit/type/interface.rb
index 27f34b7e0..4e27e35ea 100755
--- a/spec/unit/type/interface.rb
+++ b/spec/unit/type/interface.rb
@@ -90,6 +90,4 @@ describe interface do
it "should have a target parameter" do
@class.attrtype(:target).should == :param
end
-
- after { @class.clear }
end
diff --git a/spec/unit/type/mount.rb b/spec/unit/type/mount.rb
index a9b78672e..9d09225cc 100755
--- a/spec/unit/type/mount.rb
+++ b/spec/unit/type/mount.rb
@@ -11,8 +11,6 @@ describe Puppet::Type.type(:mount) do
mount = Puppet::Type.type(:mount).create(:name => "yay")
mount.should(:ensure).should be_nil
end
-
- after { Puppet::Type.type(:mount).clear }
end
describe Puppet::Type.type(:mount), "when validating attributes" do
@@ -51,8 +49,6 @@ describe Puppet::Type.type(:mount)::Ensure, "when validating values" do
it "should support :mounted as a value to :ensure" do
Puppet::Type.type(:mount).create(:name => "yay", :ensure => :mounted)
end
-
- after { Puppet::Type.type(:mount).clear }
end
describe Puppet::Type.type(:mount)::Ensure do
@@ -64,10 +60,6 @@ describe Puppet::Type.type(:mount)::Ensure do
@ensure = @mount.property(:ensure)
end
- after :each do
- Puppet::Type.type(:mount).clear
- end
-
def mount_stub(params)
Puppet::Type.type(:mount).validproperties.each do |prop|
unless params[prop]
diff --git a/spec/unit/type/noop_metaparam.rb b/spec/unit/type/noop_metaparam.rb
index 2a3e0160d..540603ef9 100755
--- a/spec/unit/type/noop_metaparam.rb
+++ b/spec/unit/type/noop_metaparam.rb
@@ -9,8 +9,6 @@ describe Puppet::Type.type(:file).attrclass(:noop) do
@file = Puppet::Type.newfile :path => "/what/ever"
end
- after { Puppet::Type::File.clear }
-
it "should accept true as a value" do
lambda { @file[:noop] = true }.should_not raise_error
end
diff --git a/spec/unit/type/package.rb b/spec/unit/type/package.rb
index 335910c63..d2fc85ed1 100755
--- a/spec/unit/type/package.rb
+++ b/spec/unit/type/package.rb
@@ -29,8 +29,6 @@ describe Puppet::Type::Package do
pkg = Puppet::Type::Package.create(:name => "yay")
pkg.should(:ensure).should == :present
end
-
- after { Puppet::Type::Package.clear }
end
describe Puppet::Type::Package, "when validating attributes" do
@@ -97,8 +95,6 @@ describe Puppet::Type::Package, "when validating attribute values" do
it "should accept any string as an argument to :source" do
proc { Puppet::Type::Package.create(:name => "yay", :source => "stuff") }.should_not raise_error(Puppet::Error)
end
-
- after { Puppet::Type::Package.clear }
end
module PackageEvaluationTesting
@@ -116,12 +112,6 @@ describe Puppet::Type::Package do
@catalog = Puppet::Node::Catalog.new
@catalog.add_resource(@package)
end
-
- after :each do
- @catalog.clear(true)
- Puppet::Type::Package.clear
- end
-
describe Puppet::Type::Package, "when it should be purged" do
include PackageEvaluationTesting
diff --git a/spec/unit/type/schedule.rb b/spec/unit/type/schedule.rb
index da38f68a9..b533d17e4 100755
--- a/spec/unit/type/schedule.rb
+++ b/spec/unit/type/schedule.rb
@@ -42,18 +42,12 @@ module ScheduleTesting
end
describe Puppet::Type::Schedule do
-
before :each do
Puppet.settings.stubs(:value).with(:ignoreschedules).returns(false)
@schedule = Puppet::Type::Schedule.create(:name => "testing")
end
- after :each do
- Puppet::Type::Schedule.clear
- end
-
-
describe Puppet::Type::Schedule do
include ScheduleTesting
diff --git a/spec/unit/type/service.rb b/spec/unit/type/service.rb
index e8358cb22..1a57bdd41 100755
--- a/spec/unit/type/service.rb
+++ b/spec/unit/type/service.rb
@@ -117,8 +117,6 @@ describe Puppet::Type::Service, "when validating attribute values" do
svc = Puppet::Type::Service.create(:name => "yay", :path => ["/one:/two", "/three:/four"])
svc[:path].should == %w{/one /two /three /four}
end
-
- after { Puppet::Type::Service.clear }
end
describe Puppet::Type::Service, "when setting default attribute values" do
@@ -148,8 +146,6 @@ describe Puppet::Type::Service, "when setting default attribute values" do
svc = Puppet::Type::Service.create(:name => "nfs.client")
svc[:control].should == "NFS_CLIENT_START"
end
-
- after { Puppet::Type::Service.clear }
end
describe Puppet::Type::Service, "when retrieving the host's current state" do
@@ -169,8 +165,6 @@ describe Puppet::Type::Service, "when retrieving the host's current state" do
@service[:enable] = true
@service.property(:enable).retrieve.should == :yepper
end
-
- after { Puppet::Type::Service.clear }
end
describe Puppet::Type::Service, "when changing the host" do
@@ -217,8 +211,6 @@ describe Puppet::Type::Service, "when changing the host" do
@service.property(:ensure).sync
end
-
- after { Puppet::Type::Service.clear }
end
describe Puppet::Type::Service, "when refreshing the service" do
@@ -251,6 +243,4 @@ describe Puppet::Type::Service, "when refreshing the service" do
@service.provider.expects(:restart)
@service.refresh
end
-
- after { Puppet::Type::Service.clear }
end
diff --git a/spec/unit/util/cacher.rb b/spec/unit/util/cacher.rb
new file mode 100755
index 000000000..73e449588
--- /dev/null
+++ b/spec/unit/util/cacher.rb
@@ -0,0 +1,158 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/util/cacher'
+
+class CacheClassTest
+ include Puppet::Util::Cacher
+
+ cached_attr(:testing) { Time.now }
+
+ def sa_cache
+ attr_cache(:ca_cache) { Time.now }
+ end
+end
+
+class CacheInstanceTest
+ extend Puppet::Util::Cacher
+
+ def self.sa_cache
+ attr_cache(:ca_cache) { Time.now }
+ end
+end
+
+describe "a cacher user using cached values", :shared => true do
+ it "should use the block to generate a new value if none is present" do
+ now = Time.now
+ Time.stubs(:now).returns now
+ @object.sa_cache.should equal(now)
+ end
+
+ it "should not test for validity if it is creating the value" do
+ # This is only necessary in the class, since it has this value kicking
+ # around.
+ @object.instance_variable_set("@cacher_caches", nil)
+ Puppet::Util::Cacher.expects(:valid?).never
+ @object.sa_cache
+ end
+
+ it "should not consider cached false values to be missing values" do
+ Puppet::Util::Cacher.stubs(:valid?).returns true
+
+ # This is only necessary in the class, since it has this value kicking
+ # around.
+ @object.instance_variable_set("@cacher_caches", nil)
+ Time.stubs(:now).returns false
+ @object.sa_cache
+ @object.sa_cache.should be_false
+ end
+
+ it "should return cached values if they are still valid" do
+ Puppet::Util::Cacher.stubs(:valid?).returns true
+
+ @object.sa_cache.should equal(@object.sa_cache)
+ end
+
+ it "should use the block to generate new values if the cached values are invalid" do
+ Puppet::Util::Cacher.stubs(:valid?).returns false
+
+ @object.sa_cache.should_not equal(@object.sa_cache)
+ end
+
+ it "should still cache values after an invalidation" do
+ # Load the cache
+ @object.sa_cache
+
+ Puppet::Util::Cacher.invalidate
+ @object.sa_cache.should equal(@object.sa_cache)
+ end
+end
+
+describe Puppet::Util::Cacher do
+ before do
+ Puppet::Util::Cacher.invalidate
+ end
+ after do
+ Puppet::Util::Cacher.invalidate
+ end
+
+ it "should have a method for invalidating caches" do
+ Puppet::Util::Cacher.should respond_to(:invalidate)
+ end
+
+ it "should have a method for determining whether a cached value is valid" do
+ Puppet::Util::Cacher.should respond_to(:valid?)
+ end
+
+ it "should consider cached values valid if the cached value was created and there was never an invalidation" do
+ Puppet::Util::Cacher.instance_variable_set("@timestamp", nil)
+
+ Puppet::Util::Cacher.should be_valid(Time.now)
+ end
+
+ it "should consider cached values valid if the cached value was created since the last invalidation" do
+ Puppet::Util::Cacher.invalidate
+
+ Puppet::Util::Cacher.should be_valid(Time.now + 1)
+ end
+
+ it "should consider cached values invalid if the cache was invalidated after the cached value was created" do
+ Puppet::Util::Cacher.invalidate
+
+ Puppet::Util::Cacher.should_not be_valid(Time.now - 1)
+ end
+
+ describe "when used to extend a class" do
+ before do
+ @object = CacheClassTest.new
+ end
+
+ it_should_behave_like "a cacher user using cached values"
+
+ it "should provide a class method for defining cached attributes" do
+ CacheClassTest.private_methods.should be_include("cached_attr")
+ end
+
+ describe "and defining cached attributes" do
+ it "should create an accessor for the cached attribute" do
+ @object.should respond_to(:testing)
+ end
+
+ it "should return a value calculated from the provided block" do
+ time = Time.now
+ Time.stubs(:now).returns time
+ @object.testing.should equal(time)
+ end
+
+ it "should return the cached value from the getter if the value is still valid" do
+ value = @object.testing
+ Puppet::Util::Cacher.expects(:valid?).returns true
+ @object.testing.should equal(value)
+ end
+
+ it "should regenerate and return a new value using the provided block if the value is no longer valid" do
+ value = @object.testing
+ Puppet::Util::Cacher.expects(:valid?).returns false
+ @object.testing.should_not equal(value)
+ end
+ end
+
+ it "should provide a private instance method for caching values" do
+ @object.private_methods.should be_include("attr_cache")
+ end
+
+ end
+
+ describe "when included in a class" do
+ before do
+ @object = CacheInstanceTest
+ end
+
+ it "should provide a private instance method for caching values" do
+ CacheInstanceTest.private_methods.should be_include("attr_cache")
+ end
+
+ it_should_behave_like "a cacher user using cached values"
+ end
+end
diff --git a/spec/unit/util/settings.rb b/spec/unit/util/settings.rb
index a6b358462..ca533ef9a 100755
--- a/spec/unit/util/settings.rb
+++ b/spec/unit/util/settings.rb
@@ -93,6 +93,11 @@ describe Puppet::Util::Settings, " when setting values" do
@settings[:myval].should == "yay"
end
+ it "should clear the list of used sections" do
+ @settings.expects(:clearused)
+ @settings[:myval] = "yay"
+ end
+
it "should call passed blocks when values are set" do
values = []
@settings.setdefaults(:section, :hooker => {:default => "yay", :desc => "boo", :hook => lambda { |v| values << v }})
@@ -284,11 +289,6 @@ describe Puppet::Util::Settings, " when parsing its configuration" do
lambda { @settings.parse(file) }.should_not raise_error
end
- it "should support an old parse method when per-executable configuration files still exist" do
- # I'm not going to bother testing this method.
- @settings.should respond_to(:old_parse)
- end
-
it "should convert booleans in the configuration file into Ruby booleans" do
text = "[main]
one = true
@@ -481,7 +481,7 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
def stub_transaction
@bucket = mock 'bucket'
- @config = mock 'config', :clear => nil
+ @config = mock 'config'
@trans = mock 'transaction'
@settings.expects(:to_transportable).with(:whatever).returns(@bucket)
@@ -597,14 +597,6 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
file.should be_nil
end
- it "should not try to manage files in memory" do
- main = Puppet::Type.type(:file).create(:path => "/maindir")
-
- trans = @settings.to_transportable
-
- lambda { trans.to_catalog }.should_not raise_error
- end
-
it "should do nothing if a catalog cannot be created" do
bucket = mock 'bucket'
catalog = mock 'catalog'
@@ -616,34 +608,6 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
@settings.use(:mysection)
end
- it "should clear the catalog after applying" do
- bucket = mock 'bucket'
- catalog = mock 'catalog'
-
- @settings.expects(:to_transportable).returns bucket
- bucket.expects(:to_catalog).returns catalog
- catalog.stubs(:host_config=)
- catalog.stubs(:apply)
- catalog.expects(:clear)
-
- @settings.use(:mysection)
- end
-
- it "should clear the catalog even if there is an exception during applying" do
- bucket = mock 'bucket'
- catalog = mock 'catalog'
-
- @settings.expects(:to_transportable).returns bucket
- bucket.expects(:to_catalog).returns catalog
- catalog.stubs(:host_config=)
- catalog.expects(:apply).raises(ArgumentError)
- catalog.expects(:clear)
-
- # We don't care about the raised exception, we just care that
- # we clear the catalog even with the exception
- lambda { @settings.use(:mysection) }.should raise_error
- end
-
it "should do nothing if all specified sections have already been used" do
bucket = mock 'bucket'
catalog = mock 'catalog'
@@ -701,6 +665,4 @@ describe Puppet::Util::Settings, " when being used to manage the host machine" d
proc { @settings.use(:whatever) }.should raise_error(RuntimeError)
end
-
- after { Puppet::Type.allclear }
end
diff --git a/test/executables/puppetca.rb b/test/executables/puppetca.rb
deleted file mode 100755
index cdc827079..000000000
--- a/test/executables/puppetca.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../lib/puppettest'
-
-require 'puppettest'
-require 'mocha'
-
-class TestPuppetCA < Test::Unit::TestCase
- include PuppetTest::ExeTest
-
- def setup
- super
- Puppet::Util::SUIDManager.stubs(:asuser).yields
- end
-
- def gen_cert(ca, host)
- runca("-g #{host}")
- ca.getclientcert(host)[0]
- end
-
- def mkca
- Puppet::Network::Handler.ca.new()
- end
-
- def mkcert(hostname)
- cert = nil
- assert_nothing_raised {
- cert = Puppet::SSLCertificates::Certificate.new(
- :name => hostname
- )
- cert.mkcsr
- }
-
- return cert
- end
-
- def runca(args)
- debug = ""
- if Puppet[:debug]
- debug = "-d "
- end
- return %x{puppetca --user=#{Puppet[:user]} #{debug} --group=#{Puppet[:group]} --confdir=#{Puppet[:confdir]} --vardir=#{Puppet[:vardir]} #{args} 2>&1}
- end
-
- def test_signing
- ca = mkca
- Puppet[:autosign] = false
-
- %w{host.test.com Other.Testing.Com}.each do |host|
- cert = mkcert(host)
- resp = nil
- assert_nothing_raised {
- # We need to use a fake name so it doesn't think the cert is from
- # itself. Strangely, getcert stores the csr, because it's a server-side
- # method, not client.
- resp = ca.getcert(cert.csr.to_pem, host, "127.0.0.1")
- }
- assert_equal(["",""], resp)
-
- output = nil
- assert_nothing_raised {
- output = runca("--list").chomp.split("\n").reject { |line| line =~ /warning:/ } # stupid ssl.rb
- }
- assert_equal($?,0)
- assert_equal([host.downcase], output)
- assert_nothing_raised {
- output = runca("--sign -a").chomp.split("\n")
- }
-
-
- assert_equal($?,0)
- assert_equal(["Signed #{host.downcase}"], output)
-
-
- signedfile = ca.ca.host2certfile(host)
- assert(FileTest.exists?(signedfile), "cert does not exist")
- assert(! FileTest.executable?(signedfile), "cert is executable")
-
- uid = Puppet::Util.uid(Puppet[:user])
-
- if Puppet::Util::SUIDManager.uid == 0
- assert(! FileTest.owned?(signedfile), "cert is owned by root")
- end
- assert_nothing_raised {
- output = runca("--list").chomp.split("\n")
- }
- assert_equal($?,0)
- assert_equal(["No certificates to sign"], output)
- end
- end
-
- # This method takes a long time to run because of all of the external
- # executable calls.
- def test_revocation
- ca = Puppet::SSLCertificates::CA.new()
- host1 = gen_cert(ca, "host1.example.com")
- host2 = gen_cert(ca, "host2.example.com")
- host3 = gen_cert(ca, "host3.example.com")
- runca("-r host1.example.com")
- runca("-r #{host2.serial}")
- runca("-r 0x#{host3.serial.to_s(16)}")
- runca("-r 0xff")
-
- # Recreate CA to force reading of CRL
- ca = Puppet::SSLCertificates::CA.new()
- crl = ca.crl
- revoked = crl.revoked.collect { |r| r.serial }
- exp = [host1.serial, host2.serial, host3.serial, 255]
- assert_equal(exp, revoked)
- end
-
- def test_case_insensitive_sign
- end
-end
-
diff --git a/test/executables/puppetmasterd.rb b/test/executables/puppetmasterd.rb
deleted file mode 100755
index 6d4ddf56f..000000000
--- a/test/executables/puppetmasterd.rb
+++ /dev/null
@@ -1,147 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../lib/puppettest'
-
-require 'puppet'
-require 'puppet/network/client'
-require 'puppettest'
-require 'socket'
-
-class TestPuppetMasterD < Test::Unit::TestCase
- include PuppetTest::ExeTest
- def setup
- super
- Puppet[:certdnsnames] = "localhost"
- end
-
- def getcerts
- include Puppet::Daemon
- if self.readcerts
- return [@cert, @key, @cacert, @cacertfile]
- else
- raise "Couldn't read certs"
- end
- end
-
- # start the daemon and verify it responds and such
- def test_normalstart
- startmasterd
-
- pidfile = File.join(Puppet[:vardir], "run", "puppetmasterd.pid")
- assert(FileTest.exists?(pidfile), "PID file does not exist")
-
- sleep(1)
- assert_nothing_raised {
- socket = TCPSocket.new("127.0.0.1", @@port)
- socket.close
- }
-
- client = nil
- assert_nothing_raised() {
- client = Puppet::Network::Client.status.new(
- :Server => "localhost",
- :Port => @@port
- )
- }
-
- # set our client up to auto-sign
- assert(Puppet[:autosign] =~ /^#{File::SEPARATOR}/,
- "Autosign is set to %s, not a file" % Puppet[:autosign])
-
- FileUtils.mkdir_p(File.dirname(Puppet[:autosign]))
- File.open(Puppet[:autosign], "w") { |f|
- f.puts Puppet[:certname]
- }
-
- retval = nil
-
- # init the client certs
- assert_nothing_raised() {
- client.cert
- }
-
- # call status
- assert_nothing_raised() {
- retval = client.status
- }
- assert_equal(1, retval, "Status.status return value was %s" % retval)
-
- # this client shoulduse the same certs
- assert_nothing_raised() {
- client = Puppet::Network::Client.master.new(
- :Server => "localhost",
- :Port => @@port
- )
- }
- assert_nothing_raised() {
- retval = client.getconfig
- }
-
- objects = nil
- end
-
- # verify that we can run puppetmasterd in parse-only mode
- def test_parseonly
- startmasterd("--parseonly > /dev/null")
- sleep(1)
-
- pid = nil
- ps = Facter["ps"].value || "ps -ef"
- %x{#{ps}}.chomp.split(/\n/).each { |line|
- next if line =~ /^puppet/ # skip normal master procs
- if line =~ /puppetmasterd.+--manifest/
- ary = line.split(" ")
- pid = ary[1].to_i
- end
- }
-
- assert($? == 0, "Puppetmasterd ended with non-zero exit status")
-
- assert_nil(pid, "Puppetmasterd is still running after parseonly")
- end
-
- def disabled_test_sslconnection
- #file = File.join(exampledir, "code", "head")
- #startmasterd("--manifest #{file}")
-
- #assert_nothing_raised {
- # socket = TCPSocket.new("127.0.0.1", Puppet[:masterport])
- # socket.close
- #}
-
- client = nil
- cert, key, cacert, cacertfile = getcerts()
-
- assert_nothing_raised() {
- client = Net::HTTP.new("localhost", Puppet[:masterport])
- client.cert = cert
- client.key = key
- client.ca_file = cacertfile
- client.use_ssl = true
- client.start_immediately = true
- }
- retval = nil
-
- assert_nothing_raised() {
- retval = client.nothing
- }
- assert_equal(1, retval, "return value was %s" % retval)
- facts = {}
- Facter.each { |p,v|
- facts[p] = v
- }
- textfacts = CGI.escape(YAML.dump(facts))
- assert_nothing_raised() {
- #Puppet.notice "calling status"
- #retval = client.call("status.status", "")
- retval = client.call("puppetmaster.getconfig", textfacts, "yaml")
- }
-
- objects = nil
- assert_nothing_raised {
- YAML.load(CGI.unescape(retval))
- }
- #stopmasterd
- end
-end
-
diff --git a/test/language/parser.rb b/test/language/parser.rb
index cdd13297a..effb2d40c 100755
--- a/test/language/parser.rb
+++ b/test/language/parser.rb
@@ -26,15 +26,6 @@ class TestParser < Test::Unit::TestCase
parser.file = file
parser.parse
}
-
- Puppet::Type.eachtype { |type|
- type.each { |obj|
- assert(obj.file, "File is not set on %s" % obj.ref)
- assert(obj.name, "Name is not set on %s" % obj.ref)
- assert(obj.line, "Line is not set on %s" % obj.ref)
- }
- }
- Puppet::Type.allclear
}
end
@@ -49,7 +40,6 @@ class TestParser < Test::Unit::TestCase
config.compile
#ast.classes[""].evaluate config.topscope
}
- Puppet::Type.allclear
}
end
@@ -680,7 +670,6 @@ file { "/tmp/yayness":
manifest = File.join(modpath, "manifest.pp")
manifest_texts.each do |txt|
- Puppet::Type.allclear
File.open(manifest, "w") { |f| f.puts txt }
assert_nothing_raised {
diff --git a/test/language/snippets.rb b/test/language/snippets.rb
index 982ddfec4..95a518388 100755
--- a/test/language/snippets.rb
+++ b/test/language/snippets.rb
@@ -24,14 +24,14 @@ class TestSnippets < Test::Unit::TestCase
end
def assert_file(path, msg = nil)
- unless file = @file[path]
+ unless file = @catalog.resource(:file, path)
msg ||= "Could not find file %s" % path
raise msg
end
end
def assert_mode_equal(mode, path)
- unless file = @file[path]
+ unless file = @catalog.resource(:file, path)
raise "Could not find file %s" % path
end
@@ -213,8 +213,8 @@ class TestSnippets < Test::Unit::TestCase
path1 = "/tmp/argumenttest1"
path2 = "/tmp/argumenttest2"
- file1 = @file[path1]
- file2 = @file[path2]
+ file1 = @catalog.resource(:file, path1)
+ file2 = @catalog.resource(:file, path2)
assert_file(path1)
assert_mode_equal(0755, path1)
@@ -233,7 +233,7 @@ class TestSnippets < Test::Unit::TestCase
}
paths.each { |path|
- file = @file[path]
+ file = @catalog.resource(:file, path)
assert(file, "File %s is missing" % path)
assert_mode_equal(0755, path)
}
@@ -243,7 +243,7 @@ class TestSnippets < Test::Unit::TestCase
paths = %w{a b c d e f g h}.collect { |l| "/tmp/iteration%stest" % l }
paths.each { |path|
- file = @file[path]
+ file = @catalog.resource(:file, path)
assert_file(path)
assert_mode_equal(0755, path)
}
@@ -264,7 +264,7 @@ class TestSnippets < Test::Unit::TestCase
dir = "/tmp/testdirtest"
assert_file(file)
assert_file(dir)
- assert_equal(:directory, @file[dir].should(:ensure), "Directory is not set to be a directory")
+ assert_equal(:directory, @catalog.resource(:file, dir).should(:ensure), "Directory is not set to be a directory")
end
def snippet_scopetest
@@ -351,7 +351,7 @@ class TestSnippets < Test::Unit::TestCase
}.each { |count, str|
path = "/tmp/singlequote%s" % count
assert_file(path)
- assert_equal(str, @file[path].should(:content))
+ assert_equal(str, @catalog.resource(:file, path).should(:content))
}
end
@@ -389,21 +389,20 @@ class TestSnippets < Test::Unit::TestCase
end
def snippet_emptyexec
- assert(Puppet::Type.type(:exec)["touch /tmp/emptyexectest"],
- "Did not create exec")
+ assert(@catalog.resource(:exec, "touch /tmp/emptyexectest"), "Did not create exec")
end
def snippet_multisubs
path = "/tmp/multisubtest"
assert_file(path)
- file = @file[path]
+ file = @catalog.resource(:file, path)
assert_equal("sub2", file.should(:content), "sub2 did not override content")
assert_mode_equal(0755, path)
end
def snippet_collection
assert_file("/tmp/colltest1")
- assert_nil(@file["/tmp/colltest2"], "Incorrectly collected file")
+ assert_nil(@catalog.resource(:file, "/tmp/colltest2"), "Incorrectly collected file")
end
def snippet_virtualresources
@@ -476,16 +475,6 @@ class TestSnippets < Test::Unit::TestCase
catalog = catalog.to_ral
}
- Puppet::Type.eachtype { |type|
- type.each { |obj|
- # don't worry about this for now
- #unless obj.name == "puppet[top]" or
- # obj.is_a?(Puppet.type(:schedule))
- # assert(obj.parent, "%s has no parent" % obj.name)
- #end
- assert(obj.name)
- }
- }
@catalog = catalog
assert_nothing_raised {
self.send(mname)
diff --git a/test/lib/puppettest.rb b/test/lib/puppettest.rb
index 63f8121b5..6c1e059b8 100755
--- a/test/lib/puppettest.rb
+++ b/test/lib/puppettest.rb
@@ -233,6 +233,7 @@ module PuppetTest
end
f = File.join(self.tmpdir(), "tempfile_" + @@tmpfilenum.to_s)
+ @@tmpfiles ||= []
@@tmpfiles << f
return f
end
@@ -298,7 +299,6 @@ module PuppetTest
@@tmppids.clear
- Puppet::Type.allclear
Puppet::Util::Storage.clear
Puppet.clear
Puppet.settings.clear
diff --git a/test/lib/puppettest/exetest.rb b/test/lib/puppettest/exetest.rb
index 05de56c0f..0d66c5a07 100644
--- a/test/lib/puppettest/exetest.rb
+++ b/test/lib/puppettest/exetest.rb
@@ -58,7 +58,6 @@ module PuppetTest::ExeTest
args += " --masterport %s" % @@port
args += " --user %s" % Puppet::Util::SUIDManager.uid
args += " --group %s" % Puppet::Util::SUIDManager.gid
- args += " --nonodes"
args += " --autosign true"
#if Puppet[:debug]
diff --git a/test/lib/puppettest/support/utils.rb b/test/lib/puppettest/support/utils.rb
index cb4a6924c..b749c7931 100644
--- a/test/lib/puppettest/support/utils.rb
+++ b/test/lib/puppettest/support/utils.rb
@@ -42,12 +42,6 @@ module PuppetTest::Support::Utils
# stop any services that might be hanging around
def stopservices
- if stype = Puppet::Type.type(:service)
- stype.each { |service|
- service[:ensure] = :stopped
- service.evaluate
- }
- end
end
# TODO: rewrite this to use the 'etc' module.
diff --git a/test/network/client/ca.rb b/test/network/client/ca.rb
index 9781e9589..2546642cd 100755
--- a/test/network/client/ca.rb
+++ b/test/network/client/ca.rb
@@ -35,6 +35,7 @@ class TestClientCA < Test::Unit::TestCase
Puppet.settings.stubs(:value).with(:http_proxy_host).returns(nil)
Puppet.settings.stubs(:value).with(:http_proxy_port).returns(nil)
Puppet.settings.stubs(:value).with(:http_keepalive).returns(false)
+ Puppet.settings.stubs(:value).with(:configtimeout).returns(180)
# Just throw an error; the important thing is the values, not what happens next.
Net::HTTP.stubs(:new).with("myca", 321, nil, nil).raises(ArgumentError)
diff --git a/test/network/client/master.rb b/test/network/client/master.rb
index dc2140e62..c0d14ccee 100755
--- a/test/network/client/master.rb
+++ b/test/network/client/master.rb
@@ -421,24 +421,6 @@ end
assert_equal(facts["environment"], Puppet[:environment], "Did not add environment to client facts")
end
- # This is partially to fix #532, but also to save on memory.
- def test_remove_objects_after_every_run
- client = mkclient
-
- ftype = Puppet::Type.type(:file)
- file = ftype.create :title => "/what/ever", :ensure => :present
- config = Puppet::Node::Catalog.new
- config.add_resource(file)
-
- config.expects :apply
-
- client.catalog = config
- client.expects(:getconfig)
- client.run
-
- assert_nil(ftype[@createdfile], "file object was not removed from memory")
- end
-
# #685
def test_http_failures_do_not_kill_puppetd
client = mkclient
diff --git a/test/network/client/resource.rb b/test/network/client/resource.rb
index eb8e829eb..f3c564d9d 100755
--- a/test/network/client/resource.rb
+++ b/test/network/client/resource.rb
@@ -38,7 +38,6 @@ class TestResourceClient < Test::Unit::TestCase
assert_instance_of(Puppet::TransObject, tobj)
- Puppet::Type.allclear
obj = nil
assert_nothing_raised {
obj = tobj.to_type
@@ -49,7 +48,6 @@ class TestResourceClient < Test::Unit::TestCase
File.unlink(file)
# Now test applying
- Puppet::Type.allclear
result = nil
assert_nothing_raised {
result = client.apply(tobj)
@@ -57,7 +55,6 @@ class TestResourceClient < Test::Unit::TestCase
assert(FileTest.exists?(file), "File was not created on apply")
# Lastly, test "list"
- Puppet::Type.allclear
list = nil
assert_nothing_raised {
list = client.list("user")
@@ -70,14 +67,12 @@ class TestResourceClient < Test::Unit::TestCase
break if count > 3
assert_instance_of(Puppet::TransObject, tobj)
- Puppet::Type.allclear
tobj2 = nil
assert_nothing_raised {
tobj2 = client.describe(tobj.type, tobj.name)
}
obj = nil
- Puppet::Type.allclear
assert_nothing_raised {
obj = tobj2.to_type
}
diff --git a/test/network/handler/fileserver.rb b/test/network/handler/fileserver.rb
index a705dbf4b..b3a9aef2b 100755
--- a/test/network/handler/fileserver.rb
+++ b/test/network/handler/fileserver.rb
@@ -146,10 +146,6 @@ class TestFileServer < Test::Unit::TestCase
list = server.list(sfile, :manage, true, false)
}
- assert_nothing_raised {
- file = Puppet.type(:file)[tmpfile]
- }
-
output = "/\tfile"
# verify it got listed as a file
diff --git a/test/network/handler/resource.rb b/test/network/handler/resource.rb
index 00a88b57f..269c9571c 100755
--- a/test/network/handler/resource.rb
+++ b/test/network/handler/resource.rb
@@ -13,7 +13,6 @@ class TestResourceServer < Test::Unit::TestCase
def verify_described(type, described)
described.each do |name, trans|
- type.clear
obj = nil
assert_nothing_raised do
obj = trans.to_type
@@ -28,7 +27,6 @@ class TestResourceServer < Test::Unit::TestCase
assert_equal(Puppet::Type.type(:package).defaultprovider.name, obj[:provider])
end
end
- type.clear
end
def test_describe_file
@@ -42,71 +40,38 @@ class TestResourceServer < Test::Unit::TestCase
server = Puppet::Network::Handler.resource.new()
end
- # The first run we create the file on the copy, the second run
- # the file is already there so the object should be in sync
- 2.times do |i|
- [ [nil],
- [[:content, :mode], []],
- [[], [:content]],
- [[:content], [:mode]]
- ].each do |ary|
- retrieve = ary[0] || []
- ignore = ary[1] || []
-
- File.open(file, "w") { |f| f.print str }
-
- result = nil
- assert_nothing_raised do
- result = server.describe("file", file, *ary)
- end
-
- assert(result, "Could not retrieve file information")
-
- assert_instance_of(Puppet::TransObject, result)
+ [ [nil],
+ [[:content, :mode], []],
+ [[], [:content]],
+ [[:content], [:mode]]
+ ].each do |ary|
+ retrieve = ary[0] || []
+ ignore = ary[1] || []
- # Now we have to clear, so that the server's object gets removed
- Puppet::Type.type(:file).clear
+ File.open(file, "w") { |f| f.print str }
- # And remove the file, so we can verify it gets recreated
- if i == 0
- File.unlink(file)
- end
-
- object = nil
- assert_nothing_raised do
- object = result.to_type
- end
+ result = nil
+ assert_nothing_raised do
+ result = server.describe("file", file, *ary)
+ end
- assert(object, "Could not create type")
+ assert(result, "Could not retrieve file information")
- retrieve.each do |property|
- assert(object.should(property), "Did not retrieve %s" % property)
- end
+ assert_instance_of(Puppet::TransObject, result)
- ignore.each do |property|
- assert(! object.should(property), "Incorrectly retrieved %s" % property)
- end
+ object = nil
+ assert_nothing_raised do
+ object = result.to_type
+ end
- if i == 0
- assert_events([:file_created], object)
- else
- assert_nothing_raised {
- assert(object.insync?(object.retrieve), "Object was not in sync")
- }
- end
+ assert(object, "Could not create type")
- assert(FileTest.exists?(file), "File did not get recreated")
+ retrieve.each do |property|
+ assert(object.should(property), "Did not retrieve %s" % property)
+ end
- if i == 0
- if object.should(:content)
- assert_equal(str, File.read(file), "File contents are not the same")
- else
- assert_equal("", File.read(file), "File content was incorrectly made")
- end
- end
- if FileTest.exists? file
- File.unlink(file)
- end
+ ignore.each do |property|
+ assert(! object.should(property), "Incorrectly retrieved %s" % property)
end
end
end
@@ -140,9 +105,6 @@ class TestResourceServer < Test::Unit::TestCase
assert_instance_of(Puppet::TransObject, result)
- # Now we have to clear, so that the server's object gets removed
- Puppet::Type.type(:file).clear
-
# And remove the file, so we can verify it gets recreated
Dir.rmdir(file)
@@ -151,6 +113,8 @@ class TestResourceServer < Test::Unit::TestCase
object = result.to_type
end
+ catalog = mk_catalog(object)
+
assert(object, "Could not create type")
retrieve.each do |property|
@@ -160,11 +124,6 @@ class TestResourceServer < Test::Unit::TestCase
ignore.each do |property|
assert(! object.should(property), "Incorrectly retrieved %s" % property)
end
-
- #assert_apply(object)
- assert_events([:directory_created], object)
- assert(FileTest.directory?(file), "Directory did not get recreated")
- Dir.rmdir(file)
end
end
@@ -198,8 +157,6 @@ class TestResourceServer < Test::Unit::TestCase
bucket = server.list(type.name)
}
- #type.clear
-
count = 0
described = {}
bucket.each do |obj|
@@ -251,8 +208,6 @@ class TestResourceServer < Test::Unit::TestCase
filetrans = server.describe("file", file)
}
- Puppet::Type.type(:file).clear
-
bucket = Puppet::TransBucket.new
bucket.type = "file"
bucket.name = "test"
@@ -273,7 +228,6 @@ class TestResourceServer < Test::Unit::TestCase
yaml = Base64.encode64(YAML::dump(bucket))
}
- Puppet::Type.type(:file).clear
File.unlink(file)
if Base64.decode64(yaml) =~ /(.{20}Loglevel.{20})/
diff --git a/test/network/server/webrick.rb b/test/network/server/webrick.rb
index fe6d69ade..0cdade4ba 100755
--- a/test/network/server/webrick.rb
+++ b/test/network/server/webrick.rb
@@ -67,7 +67,7 @@ class TestWebrickServer < Test::Unit::TestCase
end
# Test that a client whose cert has been revoked really can't connect
- def test_certificate_revocation
+ def test_xcertificate_revocation
Puppet[:autosign] = true
serverpid, server = mk_status_server
@@ -101,9 +101,6 @@ class TestWebrickServer < Test::Unit::TestCase
def mk_status_client
client = nil
- # Otherwise, the client initalization will trip over itself
- # since elements created in the last run are still around
- Puppet::Type::allclear
assert_nothing_raised() {
client = Puppet::Network::Client.status.new(
diff --git a/test/other/relationships.rb b/test/other/relationships.rb
index bf83caf4a..4e666450e 100755
--- a/test/other/relationships.rb
+++ b/test/other/relationships.rb
@@ -81,6 +81,9 @@ class TestRelationships < Test::Unit::TestCase
)
end
+ catalog = mk_catalog(*files)
+ catalog.add_resource(*execs)
+
# Add our first relationship
if out[param]
files[0][param] = execs[0]
@@ -106,8 +109,6 @@ class TestRelationships < Test::Unit::TestCase
execs[0][param], "Incorrect source list")
end
check_relationship(sources, targets, out[param], refreshers.include?(param))
-
- Puppet::Type.allclear
end
end
@@ -166,6 +167,7 @@ class TestRelationships < Test::Unit::TestCase
exec = Puppet::Type.newexec(:title => "myexec", :cwd => path,
:command => "/bin/echo")
+ catalog = mk_catalog(file, exec)
reqs = nil
assert_nothing_raised do
reqs = exec.autorequire
@@ -176,9 +178,8 @@ class TestRelationships < Test::Unit::TestCase
# Now make sure that these relationships are added to the
# relationship graph
- config = mk_catalog(file, exec)
- config.apply do |trans|
- assert(config.relationship_graph.edge?(file, exec), "autorequire edge was not created")
+ catalog.apply do |trans|
+ assert(catalog.relationship_graph.edge?(file, exec), "autorequire edge was not created")
end
end
diff --git a/test/other/transactions.rb b/test/other/transactions.rb
index ce2d0d52b..8cae3388b 100755
--- a/test/other/transactions.rb
+++ b/test/other/transactions.rb
@@ -598,15 +598,15 @@ class TestTransactions < Test::Unit::TestCase
yay = Puppet::Type.newgenerator :title => "yay"
rah = Puppet::Type.newgenerator :title => "rah"
- config = mk_catalog(yay, rah)
- trans = Puppet::Transaction.new(config)
+ catalog = mk_catalog(yay, rah)
+ trans = Puppet::Transaction.new(catalog)
assert_nothing_raised do
trans.generate
end
%w{ya ra y r}.each do |name|
- assert(trans.catalog.vertex?(Puppet::Type.type(:generator)[name]),
+ assert(catalog.resource(:generator, name),
"Generated %s was not a vertex" % name)
assert($finished.include?(name), "%s was not finished" % name)
end
@@ -617,10 +617,8 @@ class TestTransactions < Test::Unit::TestCase
end
%w{ya ra y r}.each do |name|
- assert(!trans.catalog.vertex?(Puppet::Type.type(:generator)[name]),
+ assert(! catalog.resource(:generator, name),
"Generated vertex %s was not removed from graph" % name)
- assert_nil(Puppet::Type.type(:generator)[name],
- "Generated vertex %s was not removed from class" % name)
end
end
@@ -637,8 +635,8 @@ class TestTransactions < Test::Unit::TestCase
yay = Puppet::Type.newgenerator :title => "yay"
rah = Puppet::Type.newgenerator :title => "rah", :subscribe => yay
- config = mk_catalog(yay, rah)
- trans = Puppet::Transaction.new(config)
+ catalog = mk_catalog(yay, rah)
+ trans = Puppet::Transaction.new(catalog)
trans.prepare
@@ -647,7 +645,7 @@ class TestTransactions < Test::Unit::TestCase
assert_nothing_raised("failed to apply yay") do
trans.eval_resource(yay)
end
- ya = type["ya"]
+ ya = catalog.resource(type.name, "ya")
assert(ya, "Did not generate ya")
assert(trans.relationship_graph.vertex?(ya),
"Did not add ya to rel_graph")
@@ -660,11 +658,11 @@ class TestTransactions < Test::Unit::TestCase
# Now make sure it in turn eval_generates appropriately
assert_nothing_raised("failed to apply yay") do
- trans.eval_resource(type["ya"])
+ trans.eval_resource(catalog.resource(type.name, "ya"))
end
%w{y}.each do |name|
- res = type[name]
+ res = catalog.resource(type.name, "ya")
assert(res, "Did not generate %s" % name)
assert(trans.relationship_graph.vertex?(res),
"Did not add %s to rel_graph" % name)
@@ -672,7 +670,7 @@ class TestTransactions < Test::Unit::TestCase
end
assert_nothing_raised("failed to eval_generate with nil response") do
- trans.eval_resource(type["y"])
+ trans.eval_resource(catalog.resource(type.name, "y"))
end
assert(trans.relationship_graph.edge?(yay, ya), "no edge was created for ya => yay")
@@ -680,7 +678,7 @@ class TestTransactions < Test::Unit::TestCase
trans.eval_resource(rah)
end
- ra = type["ra"]
+ ra = catalog.resource(type.name, "ra")
assert(ra, "Did not generate ra")
assert(trans.relationship_graph.vertex?(ra),
"Did not add ra to rel_graph" % name)
@@ -699,14 +697,12 @@ class TestTransactions < Test::Unit::TestCase
end
%w{ya ra y r}.each do |name|
- assert(!trans.relationship_graph.vertex?(type[name]),
+ assert(!trans.relationship_graph.vertex?(catalog.resource(type.name, name)),
"Generated vertex %s was not removed from graph" % name)
- assert_nil(type[name],
- "Generated vertex %s was not removed from class" % name)
end
# Now, start over and make sure that everything gets evaluated.
- trans = Puppet::Transaction.new(config)
+ trans = Puppet::Transaction.new(catalog)
$evaluated.clear
assert_nothing_raised do
trans.evaluate
diff --git a/test/ral/manager/instances.rb b/test/ral/manager/instances.rb
index a50ecb213..5305b3ff3 100755
--- a/test/ral/manager/instances.rb
+++ b/test/ral/manager/instances.rb
@@ -89,21 +89,5 @@ class TestTypeInstances < Test::Unit::TestCase
# Now make sure the resources have an 'ensure' property to go with the value in the provider
assert(resources[:one].send(:instance_variable_get, "@parameters").include?(:ensure), "Did not create ensure property")
end
-
- # Make sure resources are entirely deleted.
- def test_delete
- aliases = %w{one}
- catalog = mk_catalog
- obj = @type.create(:name => "testing", :alias => "two", :catalog => catalog)
- aliases << "two"
-
- @type.alias("two", obj)
-
- obj.remove
- assert_nil(@type["testing"], "Object was not removed from objects hash")
- assert_nil(@type["one"], "Object's alias was not removed")
- assert_nil(@type["two"], "Object's second alias was not removed")
-
- end
end
diff --git a/test/ral/manager/type.rb b/test/ral/manager/type.rb
index c6efe4f00..f3a116f6f 100755
--- a/test/ral/manager/type.rb
+++ b/test/ral/manager/type.rb
@@ -65,7 +65,6 @@ class TestType < Test::Unit::TestCase
assert_nothing_raised() {
file.evaluate
}
- Puppet.type(:file).clear
assert_nothing_raised() {
system("rm -f %s" % path)
file = Puppet.type(:file).create(
@@ -110,47 +109,7 @@ class TestType < Test::Unit::TestCase
assert_equal("testing", group.name, "Could not retrieve name")
end
- # Verify that values get merged correctly
- def test_mergepropertyvalues
- file = tempfile()
-
- # Create the first version
- assert_nothing_raised {
- Puppet.type(:file).create(
- :path => file,
- :owner => ["root", "bin"]
- )
- }
-
- # Make sure no other statements are allowed
- assert_raise(Puppet::Error) {
- Puppet.type(:file).create(
- :path => file,
- :group => "root"
- )
- }
- end
-
- def test_aliases_to_self_are_not_failures
- resource = Puppet.type(:file).create(
- :name => "/path/to/some/missing/file",
- :ensure => "file"
- )
- resource.stubs(:path).returns("")
-
- catalog = stub 'catalog'
- catalog.expects(:resource).with(:file, "/path/to/some/missing/file").returns(resource)
- resource.catalog = catalog
-
- # Verify our adding ourselves as an alias isn't an error.
- assert_nothing_raised("Could not add alias") {
- resource[:alias] = "/path/to/some/missing/file"
- }
-
- assert_equal(resource.object_id, Puppet.type(:file)["/path/to/some/missing/file"].object_id, "Could not retrieve alias to self")
- end
-
- def test_aliases_are_added_to_class_and_catalog
+ def test_aliases_are_added_to_catalog
resource = Puppet.type(:file).create(
:name => "/path/to/some/missing/file",
:ensure => "file"
@@ -165,8 +124,6 @@ class TestType < Test::Unit::TestCase
assert_nothing_raised("Could not add alias") {
resource[:alias] = "funtest"
}
-
- assert_equal(resource.object_id, Puppet.type(:file)["funtest"].object_id, "Could not retrieve alias")
end
def test_aliasing_fails_without_a_catalog
@@ -182,7 +139,7 @@ class TestType < Test::Unit::TestCase
def test_catalogs_are_set_during_initialization_if_present_on_the_transobject
trans = Puppet::TransObject.new("/path/to/some/file", :file)
- trans.catalog = :my_config
+ trans.catalog = stub 'catalog', :resource => nil
resource = trans.to_type
assert_equal(resource.catalog, trans.catalog, "Did not set catalog on initialization")
end
@@ -217,37 +174,6 @@ class TestType < Test::Unit::TestCase
assert(twoobj.requires?(oneobj), "Requirement was not created")
end
- # Verify that names are aliases, not equivalents
- def test_nameasalias
- file = nil
- # Create the parent dir, so we make sure autorequiring the parent dir works
- parentdir = tempfile()
- dir = Puppet.type(:file).create(
- :name => parentdir,
- :ensure => "directory"
- )
- assert_apply(dir)
- path = File.join(parentdir, "subdir")
- name = "a test file"
- transport = Puppet::TransObject.new(name, "file")
- transport[:path] = path
- transport[:ensure] = "file"
- assert_nothing_raised {
- file = transport.to_type
- }
-
- assert_equal(path, file[:path])
- assert_equal(name, file.title)
-
- assert_nothing_raised {
- file.retrieve
- }
-
- assert_apply(file)
-
- assert(Puppet.type(:file)[name], "Could not look up object by name")
- end
-
def test_ensuredefault
user = nil
assert_nothing_raised {
@@ -434,7 +360,6 @@ class TestType < Test::Unit::TestCase
assert_equal(path, file[:name], "Did not get correct name")
file = nil
- Puppet::Type.type(:file).clear
# Now make sure we can specify both and still get the right answers
assert_nothing_raised do
@@ -475,7 +400,6 @@ class TestType < Test::Unit::TestCase
# Now try it using the class method on Type
oldid = obj.object_id
obj = nil
- Puppet::Type.type(:file).clear
assert_nothing_raised {
obj = Puppet::Type.create(trans)
@@ -487,7 +411,6 @@ class TestType < Test::Unit::TestCase
# Now try the same things with hashes instead of a transobject
oldid = obj.object_id
obj = nil
- Puppet::Type.type(:file).clear
hash = {
:type => :file,
:title => "Myfile",
@@ -510,7 +433,6 @@ class TestType < Test::Unit::TestCase
# Now try it using the class method on Type
oldid = obj.object_id
obj = nil
- Puppet::Type.type(:file).clear
assert_nothing_raised {
obj = Puppet::Type.create(hash)
@@ -533,25 +455,6 @@ class TestType < Test::Unit::TestCase
end
end
- def test_title_and_name
- obj = nil
- path = tempfile()
- fileobj = Puppet::Type.type(:file)
-
- assert_nothing_raised do
- obj = fileobj.create(
- :title => "myfile",
- :path => path
- )
- end
-
- assert_equal(obj, fileobj["myfile"],
- "Could not retrieve obj by title")
-
- assert_equal(obj, fileobj[path],
- "Could not retrieve obj by name")
- end
-
# Make sure default providers behave correctly
def test_defaultproviders
# Make a fake type
@@ -577,6 +480,7 @@ class TestType < Test::Unit::TestCase
# Make sure that we can have multiple non-isomorphic objects with the same name,
# but not with isomorphic objects.
def test_isomorphic_names
+ catalog = mk_catalog
# First do execs, since they're not isomorphic.
echo = Puppet::Util.binary "echo"
exec1 = exec2 = nil
@@ -586,37 +490,31 @@ class TestType < Test::Unit::TestCase
:command => "#{echo} funtest"
)
end
+ catalog.add_resource(exec1)
assert_nothing_raised do
exec2 = Puppet::Type.type(:exec).create(
:title => "exec2",
:command => "#{echo} funtest"
)
end
-
- assert_apply(exec1, exec2)
+ catalog.add_resource(exec2)
# Now do files, since they are. This should fail.
file1 = file2 = nil
path = tempfile()
- assert_nothing_raised do
- file1 = Puppet::Type.type(:file).create(
- :title => "file1",
- :path => path,
- :content => "yayness"
- )
- end
-
- # This will fail, but earlier systems will catch it.
- assert_raise(Puppet::Error) do
- file2 = Puppet::Type.type(:file).create(
- :title => "file2",
- :path => path,
- :content => "rahness"
- )
- end
+ file1 = Puppet::Type.type(:file).create(
+ :title => "file1",
+ :path => path,
+ :content => "yayness"
+ )
+ catalog.add_resource(file1)
- assert(file1, "Did not create first file")
- assert_nil(file2, "Incorrectly created second file")
+ file2 = Puppet::Type.type(:file).create(
+ :title => "file2",
+ :path => path,
+ :content => "rahness"
+ )
+ assert_raise(ArgumentError) { catalog.add_resource(file2) }
end
def test_tags
@@ -654,20 +552,6 @@ class TestType < Test::Unit::TestCase
end
end
- # Make sure that classes behave like hashes.
- def test_class_hash_behaviour
- path = tempfile()
-
- filetype = Puppet::Type.type(:file)
- one = Puppet::Type.newfile :path => path
-
- assert_equal(one, filetype[path], "Did not get file back")
-
- assert_raise(Puppet::Error) do
- filetype[path] = one
- end
- end
-
def test_ref
path = tempfile()
Puppet::Type.type(:exec) # uggh, the methods need to load the types
@@ -685,7 +569,7 @@ class TestType < Test::Unit::TestCase
type = Puppet::Type.type(:exec)
mk = Proc.new do |i, hash|
hash[:title] = "exec%s" % i
- hash[:command] = "/bin/echo"
+ hash[:command] = "/bin/echo %s" % i
if parent = hash[:parent]
hash.delete(:parent)
end
@@ -753,7 +637,8 @@ class TestType < Test::Unit::TestCase
# Partially test #704, but also cover the rest of the schedule management bases.
def test_schedule
- Puppet::Type.type(:schedule).create(:name => "maint")
+ schedule = Puppet::Type.type(:schedule).create(:name => "maint")
+ catalog = mk_catalog(schedule)
{"maint" => true, nil => false, :fail => :fail}.each do |name, should|
args = {:name => tempfile, :ensure => :file}
@@ -761,21 +646,27 @@ class TestType < Test::Unit::TestCase
args[:schedule] = name
end
resource = Puppet::Type.type(:file).create(args)
+ catalog.add_resource(resource)
if should == :fail
assert_raise(Puppet::Error, "Did not fail on missing schedule") do
resource.schedule
end
+ elsif should == false
+ assert_nil(resource.schedule, "Set the schedule tho it is set to nil")
else
sched = nil
assert_nothing_raised("Failed when schedule was %s" % sched) do
sched = resource.schedule
end
+ assert(sched, "Did not find schedule %s" % sched.inspect)
+
if should
assert_equal(name, sched.name, "did not get correct schedule back")
end
end
+ catalog.remove_resource(resource)
end
end
diff --git a/test/ral/providers/group.rb b/test/ral/providers/group.rb
index 18b0866b9..f912ec51a 100755
--- a/test/ral/providers/group.rb
+++ b/test/ral/providers/group.rb
@@ -21,7 +21,6 @@ class TestGroupProvider < Test::Unit::TestCase
def teardown
super
- Puppet.type(:group).clear
@@tmpgroups.each { |group|
unless missing?(group)
remove(group)
diff --git a/test/ral/type/basic.rb b/test/ral/type/basic.rb
deleted file mode 100755
index 3c5faeee0..000000000
--- a/test/ral/type/basic.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'puppettest'
-
-class TestBasic < Test::Unit::TestCase
- include PuppetTest
-
- def setup
- super
- @component = nil
- @configfile = nil
- @command = nil
-
- assert_nothing_raised() {
- @component = Puppet.type(:component).create(
- :name => "yaytest",
- :type => "testing"
- )
- }
-
- assert_nothing_raised() {
- @filepath = tempfile()
- @configfile = Puppet.type(:file).create(
- :path => @filepath,
- :ensure => "file",
- :checksum => "md5"
- )
- }
- assert_nothing_raised() {
- @command = Puppet.type(:exec).create(
- :title => "echo",
- :command => "echo yay",
- :path => ENV["PATH"]
- )
- }
- @config = mk_catalog(@component, @configfile, @command)
- @config.add_edge @component, @configfile
- @config.add_edge @component, @command
- end
-
- def teardown
- super
- stopservices
- end
-
- def test_values
- [:ensure, :checksum].each do |param|
- prop = @configfile.property(param)
- assert(prop, "got no property for %s" % param)
- assert(prop.value, "got no value for %s" % param)
- end
- end
-
- def test_name_calls
- [@command, @configfile].each { |obj|
- Puppet.debug "obj is %s" % obj
- assert_nothing_raised(){
- obj.name
- }
- }
- end
-
- def test_name_equality
- assert_equal(@filepath, @configfile.title)
-
- assert_equal("echo", @command.title)
- end
-
- def test_object_retrieval
- [@command, @configfile].each { |obj|
- assert_equal(obj.class[obj.name].object_id, obj.object_id,
- "%s did not match class version" % obj.ref)
- }
- end
-
- def test_paths
- [@configfile, @command, @component].each { |obj|
- assert_nothing_raised {
- assert_instance_of(String, obj.path)
- }
- }
- end
-end
diff --git a/test/ral/type/cron.rb b/test/ral/type/cron.rb
index 73e941894..8e3d25350 100755
--- a/test/ral/type/cron.rb
+++ b/test/ral/type/cron.rb
@@ -25,7 +25,6 @@ class TestCron < Test::Unit::TestCase
def teardown
super
@crontype.defaultprovider = nil
- Puppet::Util::FileType.filetype(:ram).clear
end
def eachprovider
@@ -145,21 +144,19 @@ class TestCron < Test::Unit::TestCase
next unless prop.name.to_s == "command"
assert(prop.insync?(value), "Property %s is not considered in sync with value %s" % [prop.name, value.inspect])
end
-
- @crontype.clear
end
end
def test_makeandretrievecron
%w{storeandretrieve a-name another-name more_naming SomeName}.each do |name|
cron = mkcron(name)
- comp = mk_catalog(name, cron)
- trans = assert_events([:cron_created], comp, name)
+ catalog = mk_catalog(name, cron)
+ trans = assert_events([:cron_created], catalog, name)
cron.provider.class.prefetch
cron = nil
- assert(cron = Puppet.type(:cron)[name], "Could not retrieve named cron")
+ assert(cron = catalog.resource(:cron, name), "Could not retrieve named cron")
assert_instance_of(Puppet.type(:cron), cron)
end
end
@@ -247,7 +244,6 @@ class TestCron < Test::Unit::TestCase
next unless prop.name.to_s == "minute"
assert(prop.insync?(value), "Property %s is not considered in sync with value %s" % [prop.name, value.inspect])
end
- @crontype.clear
end
end
@@ -294,8 +290,6 @@ class TestCron < Test::Unit::TestCase
# Write it to our file
assert_apply(cron)
- @crontype.clear
-
crons = []
assert_nothing_raised {
@crontype.instances.each do |cron|
@@ -484,7 +478,6 @@ class TestCron < Test::Unit::TestCase
cron = @crontype.create(:name => "space testing", :command => string)
assert_apply(cron)
- cron.class.clear
cron = @crontype.create(:name => "space testing", :command => string)
# Now make sure that it's correctly in sync
diff --git a/test/ral/type/exec.rb b/test/ral/type/exec.rb
index e2a3dd9ed..8c7c3f69b 100755
--- a/test/ral/type/exec.rb
+++ b/test/ral/type/exec.rb
@@ -22,8 +22,6 @@ class TestExec < Test::Unit::TestCase
def test_numvsstring
[0, "0"].each { |val|
- Puppet.type(:exec).clear
- Puppet.type(:component).clear
command = nil
output = nil
assert_nothing_raised {
@@ -50,13 +48,11 @@ class TestExec < Test::Unit::TestCase
:path => "/usr/bin:/bin:/usr/sbin:/sbin"
)
}
- Puppet.type(:exec).clear
assert_nothing_raised {
command = Puppet.type(:exec).create(
:command => "/bin/echo"
)
}
- Puppet.type(:exec).clear
assert_nothing_raised {
command = Puppet.type(:exec).create(
:command => "/bin/echo",
@@ -242,6 +238,8 @@ class TestExec < Test::Unit::TestCase
:command => "cat %s %s" % [exe, oexe],
:path => ENV["PATH"]
)
+
+ catalog = mk_catalog(file, baseobj, ofile, exec, cat)
rels = nil
assert_nothing_raised do
diff --git a/test/ral/type/file.rb b/test/ral/type/file.rb
index 5cf989aa3..fc7c39796 100755
--- a/test/ral/type/file.rb
+++ b/test/ral/type/file.rb
@@ -30,10 +30,10 @@ class TestFile < Test::Unit::TestCase
@file = Puppet::Type.type(:file)
$method = @method_name
Puppet[:filetimeout] = -1
+ Facter.stubs(:to_hash).returns({})
end
def teardown
- Puppet::Util::Storage.clear
system("rm -rf %s" % Puppet[:statefile])
super
end
@@ -409,7 +409,6 @@ class TestFile < Test::Unit::TestCase
of.puts "some more text, yo"
}
}
- Puppet.type(:file).clear
# now recreate the file
assert_nothing_raised() {
@@ -445,11 +444,6 @@ class TestFile < Test::Unit::TestCase
}
assert_events([:file_changed], file)
- # verify that we're actually getting notified when a file changes
- assert_nothing_raised() {
- Puppet.type(:file).clear
- }
-
if path =~ /nonexists/
File.unlink(path)
end
@@ -492,7 +486,7 @@ class TestFile < Test::Unit::TestCase
# Create a test directory
path = tempfile()
dir = @file.create :path => path, :mode => 0755, :recurse => true
- config = mk_catalog(dir)
+ catalog = mk_catalog(dir)
Dir.mkdir(path)
@@ -505,7 +499,7 @@ class TestFile < Test::Unit::TestCase
test = File.join(path, "file")
File.open(test, "w") { |f| f.puts "yay" }
assert_nothing_raised() { ret = dir.localrecurse(true) }
- fileobj = @file[test]
+ fileobj = catalog.resource(:file, test)
assert(fileobj, "child object was not created")
assert_equal([fileobj], ret, "child object was not returned")
@@ -549,7 +543,7 @@ class TestFile < Test::Unit::TestCase
assert_nothing_raised() { ret = dir.localrecurse(true) }
assert_equal([bad], ret.collect { |f| f.title }, "purge failed")
- badobj = @file[bad]
+ badobj = catalog.resource(:file, bad)
assert(badobj, "did not create bad object")
end
@@ -700,7 +694,6 @@ class TestFile < Test::Unit::TestCase
"Incorrect generated children when recurse == %s" % value.inspect)
File.unlink(tmpfile)
- Puppet.type(:file).clear
end
end
@@ -745,43 +738,6 @@ class TestFile < Test::Unit::TestCase
assert(file.insync?(currentvalues))
end
- def test_remove
- basedir = tempfile()
- subdir = File.join(basedir, "this")
- FileUtils.mkdir_p(subdir)
-
- dir = nil
- assert_nothing_raised {
- dir = Puppet.type(:file).create(
- :path => basedir,
- :recurse => true,
- :check => %w{owner mode group}
- )
- }
- mk_catalog dir
-
- assert_nothing_raised {
- dir.eval_generate
- }
-
- obj = nil
- assert_nothing_raised {
- obj = Puppet.type(:file)[subdir]
- }
-
- assert(obj, "Could not retrieve subdir object")
-
- assert_nothing_raised {
- obj.remove(true)
- }
-
- assert_nothing_raised {
- obj = Puppet.type(:file)[subdir]
- }
-
- assert_nil(obj, "Retrieved removed object")
- end
-
def test_path
dir = tempfile()
@@ -801,15 +757,13 @@ class TestFile < Test::Unit::TestCase
:check => %w{mode owner group}
)
}
- mk_catalog dirobj
+ catalog = mk_catalog dirobj
assert_nothing_raised {
dirobj.eval_generate
}
- assert_nothing_raised {
- file = dirobj.class[path]
- }
+ file = catalog.resource(:file, path)
assert(file, "Could not retrieve file object")
@@ -829,6 +783,7 @@ class TestFile < Test::Unit::TestCase
:name => subfile,
:ensure => "file"
)
+ catalog = mk_catalog(baseobj, subobj)
edge = nil
assert_nothing_raised do
edge = subobj.autorequire.shift
@@ -1062,14 +1017,11 @@ class TestFile < Test::Unit::TestCase
File.open(file, "w", 0411) { |f| f.puts "yayness" }
- obj = nil
- assert_nothing_raised {
- obj = Puppet::Type.type(:file).create(
- :path => file, :content => "rahness\n", :backup => ".puppet-bak"
- )
- }
-
- assert_apply(obj)
+ obj = Puppet::Type.type(:file).create(
+ :path => file, :content => "rahness\n", :backup => ".puppet-bak"
+ )
+ catalog = mk_catalog(obj)
+ catalog.apply
backupfile = file + obj[:backup]
@@tmpfiles << backupfile
@@ -1079,16 +1031,16 @@ class TestFile < Test::Unit::TestCase
assert_equal(0411, filemode(backupfile),
"File mode is wrong for backupfile")
- bucket = "bucket"
+ name = "bucket"
bpath = tempfile()
Dir.mkdir(bpath)
- Puppet::Type.type(:filebucket).create(
- :title => bucket, :path => bpath
- )
+ bucket = Puppet::Type.type(:filebucket).create(:title => name, :path => bpath)
+ catalog.add_resource(bucket)
- obj[:backup] = bucket
+ obj[:backup] = name
obj[:content] = "New content"
- assert_apply(obj)
+ catalog.finalize
+ catalog.apply
md5 = "18cc17fa3047fcc691fdf49c0a7f539a"
dir, file, pathfile = Puppet::Network::Handler.filebucket.paths(bpath, md5)
@@ -1301,8 +1253,6 @@ class TestFile < Test::Unit::TestCase
end
assert_equal("/my/file/for/testing", file.title)
- assert_equal(file, Puppet::Type.type(:file)["/my/file/for/testing"])
- Puppet::Type.type(:file).clear
end
end
@@ -1319,7 +1269,9 @@ class TestFile < Test::Unit::TestCase
assert_equal(dir, File.readlink(link))
obj = Puppet::Type.newfile :path => link, :ensure => :link, :target => file, :recurse => false, :backup => "main"
- assert_apply(obj)
+ catalog = mk_catalog(bucket, obj)
+
+ catalog.apply
assert_equal(file, File.readlink(link))
end
@@ -1367,6 +1319,8 @@ class TestFile < Test::Unit::TestCase
obj = Puppet::Type.newfile :path => path, :force => true,
:links => :manage
+ catalog = mk_catalog(obj, bucket)
+
Puppet[:trace] = true
["main", false].each do |backup|
obj[:backup] = backup
@@ -1495,8 +1449,11 @@ class TestFile < Test::Unit::TestCase
)
assert(dipper, "did not receive bucket client")
file = Puppet::Type.newfile :path => dest, :source => source, :recurse => true, :backup => "rtest"
+
+ catalog = mk_catalog(bucket, file)
- assert_apply(file)
+ catalog.apply
+
dfiles.each do |f|
assert(FileTest.exists?(f), "destfile %s was not created" % f)
end
@@ -1506,7 +1463,7 @@ class TestFile < Test::Unit::TestCase
f.puts "boo: %s" % File.basename(sf)
} }
- assert_apply(file)
+ catalog.apply
dfiles.each do |f|
assert_equal("boo: %s\n" % File.basename(f), File.read(f),
"file was not copied correctly")
@@ -1532,6 +1489,9 @@ class TestFile < Test::Unit::TestCase
def test_backup
path = tempfile()
file = Puppet::Type.newfile :path => path, :content => "yay"
+
+ catalog = mk_catalog(file)
+ catalog.finalize # adds the default resources.
[false, :false, "false"].each do |val|
assert_nothing_raised do
@@ -1561,6 +1521,7 @@ class TestFile < Test::Unit::TestCase
# And then an existing bucket
obj = Puppet::Type.type(:filebucket).create :name => "testing"
+ catalog.add_resource(obj)
bucket = obj.bucket
assert_nothing_raised do
@@ -1576,12 +1537,12 @@ class TestFile < Test::Unit::TestCase
file = File.join(dir, "file")
File.open(file, "w") { |f| f.puts "" }
obj = Puppet::Type.newfile :path => dir, :recurse => true, :mode => 0755
- mk_catalog obj
+ catalog = mk_catalog obj
assert_equal("/%s" % obj.ref, obj.path)
list = obj.eval_generate
- fileobj = obj.class[file]
+ fileobj = catalog.resource(:file, file)
assert(fileobj, "did not generate file object")
assert_equal("/%s" % fileobj.ref, fileobj.path, "did not generate correct subfile path")
end
@@ -1596,14 +1557,6 @@ class TestFile < Test::Unit::TestCase
assert(! FileTest.exists?(path), "File was not removed")
end
- # Testing #434
- def test_stripping_extra_slashes_during_lookup
- file = Puppet::Type.newfile(:path => "/one/two")
- %w{/one/two/ /one/two /one//two //one//two//}.each do |path|
- assert(Puppet::Type.type(:file)[path], "could not look up file via path %s" % path)
- end
- end
-
# Testing #438
def test_creating_properties_conflict
file = tempfile()
@@ -1614,7 +1567,6 @@ class TestFile < Test::Unit::TestCase
assert_nothing_raised("%s conflicted with ensure" % [param]) do
Puppet::Type.newfile(:path => file, param => first, :ensure => :file)
end
- Puppet::Type.type(:file).clear
params.each do |other|
next if other == param
assert_raise(Puppet::Error, "%s and %s did not conflict" % [param, other]) do
@@ -1687,20 +1639,20 @@ class TestFile < Test::Unit::TestCase
File.open(file, "w") { |f| f.puts "yay" }
File.chmod(0644, file)
obj = Puppet::Type.newfile(:path => dir, :mode => 0750, :recurse => "2")
- config = mk_catalog(obj)
+ catalog = mk_catalog(obj)
children = nil
assert_nothing_raised("Failure when recursing") do
children = obj.eval_generate
end
- assert(obj.class[subdir], "did not create subdir object")
+ assert(catalog.resource(:file, subdir), "did not create subdir object")
children.each do |c|
assert_nothing_raised("Failure when recursing on %s" % c) do
- c.catalog = config
+ c.catalog = catalog
others = c.eval_generate
end
end
- oobj = obj.class[other]
+ oobj = catalog.resource(:file, other)
assert(oobj, "did not create other object")
assert_nothing_raised do
@@ -1728,12 +1680,12 @@ class TestFile < Test::Unit::TestCase
obj = Puppet::Type.newfile(:path => dir, :ensure => :directory,
:recurse => true)
- config = mk_catalog(obj)
+ catalog = mk_catalog(obj)
children = nil
assert_nothing_raised do
children = obj.eval_generate
end
- fobj = obj.class[file]
+ fobj = catalog.resource(:file, file)
assert(fobj, "did not create file object")
assert(fobj.should(:ensure) != :directory, "ensure was passed to child")
end
diff --git a/test/ral/type/file/target.rb b/test/ral/type/file/target.rb
index 035ea905b..b6c84df99 100755
--- a/test/ral/type/file/target.rb
+++ b/test/ral/type/file/target.rb
@@ -46,7 +46,7 @@ class TestFileTarget < Test::Unit::TestCase
def test_linkrecurse
dest = tempfile()
link = @file.create :path => tempfile(), :recurse => true, :ensure => dest
- mk_catalog link
+ catalog = mk_catalog(link)
ret = nil
@@ -64,7 +64,7 @@ class TestFileTarget < Test::Unit::TestCase
assert_equal(:directory, link.should(:ensure), "ensure was not set to directory")
assert_equal([File.join(link.title, "one")], ret.collect { |f| f.title },
"Did not get linked file")
- oneobj = @file[File.join(link.title, "one")]
+ oneobj = catalog.resource(:file, File.join(link.title, "one"))
assert_equal(one, oneobj.should(:target), "target was not set correctly")
oneobj.remove
@@ -83,7 +83,7 @@ class TestFileTarget < Test::Unit::TestCase
"Did not get links back")
returns.each do |path|
- obj = @file[path]
+ obj = catalog.resource(:file, path)
assert(path, "did not get obj for %s" % path)
sdest = File.join(dest, File.basename(path))
assert_equal(sdest, obj.should(:target),
@@ -100,16 +100,14 @@ class TestFileTarget < Test::Unit::TestCase
system("mkdir -p %s" % subdir)
system("touch %s" % file)
- link = nil
- assert_nothing_raised {
- link = Puppet.type(:file).create(
- :ensure => source,
- :path => path,
- :recurse => true
- )
- }
+ link = Puppet.type(:file).create(
+ :ensure => source,
+ :path => path,
+ :recurse => true
+ )
- assert_apply(link)
+ catalog = mk_catalog(link)
+ catalog.apply
sublink = File.join(path, "subdir")
linkpath = File.join(sublink, "file")
@@ -118,7 +116,7 @@ class TestFileTarget < Test::Unit::TestCase
assert(File.symlink?(linkpath), "path is not a link")
assert_equal(file, File.readlink(linkpath))
- assert_nil(@file[sublink], "objects were not removed")
+ assert_nil(catalog.resource(:file, sublink), "objects were not removed")
assert_equal([], link.evaluate, "Link is not in sync")
end
diff --git a/test/ral/type/filebucket.rb b/test/ral/type/filebucket.rb
index f9706663b..28be67b0c 100755
--- a/test/ral/type/filebucket.rb
+++ b/test/ral/type/filebucket.rb
@@ -65,12 +65,9 @@ class TestFileBucket < Test::Unit::TestCase
def test_simplebucket
name = "yayness"
bucketpath = tempfile()
- mkbucket(name, bucketpath)
+ resource = mkbucket(name, bucketpath)
- bucket = nil
- assert_nothing_raised {
- bucket = Puppet.type(:filebucket).bucket(name)
- }
+ bucket = resource.bucket
assert_instance_of(Puppet::Network::Client.dipper, bucket)
@@ -109,49 +106,5 @@ class TestFileBucket < Test::Unit::TestCase
assert_equal(md5, newmd5)
end
-
- def test_fileswithbuckets
- name = "yayness"
- mkbucket(name, tempfile())
-
- bucket = nil
- assert_nothing_raised {
- bucket = Puppet.type(:filebucket).bucket(name)
- }
-
- file = mktestfile()
- assert_nothing_raised {
- file[:backup] = name
- }
-
- opath = tempfile()
- @@tmpfiles << opath
- File.open(opath, "w") { |f| f.puts "yaytest" }
-
- origmd5 = File.open(file.name) { |f| newmd5 = Digest::MD5.hexdigest(f.read) }
-
- file[:source] = opath
- #assert_nothing_raised {
- # file[:backup] = true
- #}
-
- assert_apply(file)
-
- # so, we've now replaced the file with the opath file
- assert_equal(
- File.open(opath) { |f| newmd5 = Digest::MD5.hexdigest(f.read) },
- File.open(file.name) { |f| newmd5 = Digest::MD5.hexdigest(f.read) }
- )
-
- #File.chmod(0644, file.name)
- assert_nothing_raised {
- bucket.restore(file.name, origmd5)
- }
-
- assert_equal(
- origmd5,
- File.open(file.name) { |f| newmd5 = Digest::MD5.hexdigest(f.read) }
- )
- end
end
diff --git a/test/ral/type/fileignoresource.rb b/test/ral/type/fileignoresource.rb
index ff867c879..996bca424 100755
--- a/test/ral/type/fileignoresource.rb
+++ b/test/ral/type/fileignoresource.rb
@@ -18,6 +18,8 @@ class TestFileIgnoreSources < Test::Unit::TestCase
rescue
system("rm -rf %s" % Puppet[:statefile])
end
+
+ Facter.stubs(:to_hash).returns({})
end
#This is not needed unless using md5 (correct me if I'm wrong)
@@ -86,8 +88,6 @@ class TestFileIgnoreSources < Test::Unit::TestCase
#This file should not
assert(!(FileTest.exists?(File.join(topath,sourcefile2))))
-
- Puppet::Type.allclear
end
def test_ignore_with_wildcard
@@ -155,8 +155,6 @@ class TestFileIgnoreSources < Test::Unit::TestCase
assert(!(FileTest.exists?(File.join(topath,sourcefile2))))
assert(!(FileTest.exists?(File.join(topath,subdir2))))
assert(!(FileTest.exists?(File.join(File.join(topath,subdir),sourcefile2))))
- Puppet::Type.allclear
-
end
def test_ignore_array
@@ -236,10 +234,5 @@ class TestFileIgnoreSources < Test::Unit::TestCase
assert(!(FileTest.exists?(File.join(topath,subdir2))), "subdir2 in dest")
assert(!(FileTest.exists?(File.join(topath,subdir3))), "anotherdir in dest")
assert(!(FileTest.exists?(File.join(File.join(topath,subdir),sourcefile2))), "file2 in dest/sub")
-
-
- Puppet::Type.allclear
-
end
-
end
diff --git a/test/ral/type/filesources.rb b/test/ral/type/filesources.rb
index a7bb6fefa..653db5c7d 100755
--- a/test/ral/type/filesources.rb
+++ b/test/ral/type/filesources.rb
@@ -21,6 +21,7 @@ class TestFileSources < Test::Unit::TestCase
@file = Puppet::Type.type(:file)
Puppet[:filetimeout] = -1
Puppet::Util::SUIDManager.stubs(:asuser).yields
+ Facter.stubs(:to_hash).returns({})
end
def teardown
@@ -69,7 +70,7 @@ class TestFileSources < Test::Unit::TestCase
:name => path
)
}
- config = mk_catalog(file)
+ catalog = mk_catalog(file)
child = nil
assert_nothing_raised {
child = file.newchild("childtest", true)
@@ -84,7 +85,8 @@ class TestFileSources < Test::Unit::TestCase
source = tempfile()
dest = tempfile()
- file = Puppet::Type.newfile :path => dest, :source => source, :title => "copier"
+ file = Puppet::Type.newfile :path => dest, :source => source,
+ :title => "copier"
property = file.property(:source)
@@ -123,10 +125,7 @@ class TestFileSources < Test::Unit::TestCase
File.open(target, "w") { |f| f.puts "yay" }
File.symlink(target, source)
- file[:links] = :manage
- assert_equal("link", property.describe(source)[:type])
-
- # And then make sure links get followed
+ # And then make sure links get followed, otherwise
file[:links] = :follow
assert_equal("file", property.describe(source)[:type])
end
@@ -275,7 +274,7 @@ class TestFileSources < Test::Unit::TestCase
# The sourcerecurse method will only ever get called when we're
# recursing, so we go ahead and set it.
obj = Puppet::Type.newfile :source => source, :path => dest, :recurse => true
- config = mk_catalog(obj)
+ catalog = mk_catalog(obj)
result = nil
sourced = nil
@@ -284,12 +283,12 @@ class TestFileSources < Test::Unit::TestCase
end
assert_equal([destfile], sourced, "Did not get correct list of sourced objects")
- dfileobj = @file[destfile]
+ dfileobj = catalog.resource(:file, destfile)
assert(dfileobj, "Did not create destfile object")
assert_equal([dfileobj], result)
# Clean this up so it can be recreated
- config.remove_resource(dfileobj)
+ catalog.remove_resource(dfileobj)
# Make sure we correctly iterate over the sources
nosource = tempfile()
@@ -300,7 +299,7 @@ class TestFileSources < Test::Unit::TestCase
result, sourced = obj.sourcerecurse(true)
end
assert_equal([destfile], sourced, "Did not get correct list of sourced objects")
- dfileobj = @file[destfile]
+ dfileobj = catalog.resource(:file, destfile)
assert(dfileobj, "Did not create destfile object with a missing source")
assert_equal([dfileobj], result)
dfileobj.remove
@@ -356,23 +355,20 @@ class TestFileSources < Test::Unit::TestCase
end
def recursive_source_test(fromdir, todir)
- Puppet::Type.allclear
initstorage
tofile = nil
trans = nil
- assert_nothing_raised {
- tofile = Puppet.type(:file).create(
- :path => todir,
- :recurse => true,
- :backup => false,
- :source => fromdir
- )
- }
- assert_apply(tofile)
+ tofile = Puppet.type(:file).create(
+ :path => todir,
+ :recurse => true,
+ :backup => false,
+ :source => fromdir
+ )
+ catalog = mk_catalog(tofile)
+ catalog.apply
assert(FileTest.exists?(todir), "Created dir %s does not exist" % todir)
- Puppet::Type.allclear
end
def run_complex_sources(networked = false)
@@ -414,9 +410,6 @@ class TestFileSources < Test::Unit::TestCase
def test_sources_with_deleted_destfiles
fromdir, todir, one, two = run_complex_sources
assert(FileTest.exists?(todir))
-
- # We shouldn't have a 'two' file object in memory
- assert_nil(@file[two], "object for 'two' is still in memory")
# then delete a file
File.unlink(two)
@@ -532,107 +525,6 @@ class TestFileSources < Test::Unit::TestCase
return file
end
- def test_NetworkSources
- server = nil
- mounts = {
- "/" => "root"
- }
-
- fileserverconf = mkfileserverconf(mounts)
-
- Puppet[:autosign] = true
-
- Puppet[:masterport] = 8762
- Puppet[:name] = "puppetmasterd"
- Puppet[:certdnsnames] = "localhost"
-
- serverpid = nil
- assert_nothing_raised() {
- server = Puppet::Network::HTTPServer::WEBrick.new(
- :Handlers => {
- :CA => {}, # so that certs autogenerate
- :FileServer => {
- :Config => fileserverconf
- }
- }
- )
-
- }
- serverpid = fork {
- assert_nothing_raised() {
- #trap(:INT) { server.shutdown; Kernel.exit! }
- trap(:INT) { server.shutdown }
- server.start
- }
- }
- @@tmppids << serverpid
-
- sleep(1)
-
- fromdir, todir = run_complex_sources("root")
- assert_trees_equal(fromdir,todir)
- recursive_source_test(fromdir, todir)
- assert_trees_equal(fromdir,todir)
-
- assert_nothing_raised {
- system("kill -INT %s" % serverpid)
- }
- end
-
- def test_unmountedNetworkSources
- server = nil
- mounts = {
- "/" => "root",
- "/noexistokay" => "noexist"
- }
-
- fileserverconf = mkfileserverconf(mounts)
-
- Puppet[:autosign] = true
- Puppet[:masterport] = @port
- Puppet[:certdnsnames] = "localhost"
-
- serverpid = nil
- assert_nothing_raised("Could not start on port %s" % @port) {
- server = Puppet::Network::HTTPServer::WEBrick.new(
- :Port => @port,
- :Handlers => {
- :CA => {}, # so that certs autogenerate
- :FileServer => {
- :Config => fileserverconf
- }
- }
- )
-
- }
-
- serverpid = fork {
- assert_nothing_raised() {
- #trap(:INT) { server.shutdown; Kernel.exit! }
- trap(:INT) { server.shutdown }
- server.start
- }
- }
- @@tmppids << serverpid
-
- sleep(1)
-
- name = File.join(tmpdir(), "nosourcefile")
- file = Puppet.type(:file).create(
- :source => "puppet://localhost/noexist/file",
- :name => name
- )
-
- assert_nothing_raised {
- file.retrieve
- }
-
- comp = mk_catalog(file)
- comp.apply
-
- assert(!FileTest.exists?(name), "File with no source exists anyway")
- end
-
def test_alwayschecksum
from = tempfile()
to = tempfile()
@@ -741,22 +633,18 @@ class TestFileSources < Test::Unit::TestCase
File.open(source, "w") { |f| f.puts "yay" }
File.symlink(source, link)
- file = nil
- assert_nothing_raised {
- file = Puppet.type(:file).create(
- :name => dest,
- :source => link,
- :links => :follow
- )
- }
+ file = Puppet.type(:file).create(:name => dest, :source => link)
- assert_events([:file_created], file)
- assert(FileTest.file?(dest), "Destination is not a file")
+ catalog = mk_catalog(file)
- # Now copy the links
- file[:links] = :manage
- assert_events([:link_created], file)
- assert(FileTest.symlink?(dest), "Destination is not a link")
+ # Default to managing links
+ catalog.apply
+ assert(FileTest.symlink?(dest), "Did not create link")
+
+ # Now follow the links
+ file[:links] = :follow
+ catalog.apply
+ assert(FileTest.file?(dest), "Destination is not a file")
end
def test_changes
diff --git a/test/ral/type/group.rb b/test/ral/type/group.rb
index d28c8eea5..3c29fe505 100755
--- a/test/ral/type/group.rb
+++ b/test/ral/type/group.rb
@@ -39,7 +39,6 @@ class TestGroup < Test::Unit::TestCase
end
def teardown
- Puppet.type(:group).clear
Puppet::Type.type(:group).defaultprovider = nil
super
end
diff --git a/test/ral/type/host.rb b/test/ral/type/host.rb
index 9b744eeec..df7cc508f 100755
--- a/test/ral/type/host.rb
+++ b/test/ral/type/host.rb
@@ -55,16 +55,12 @@ class TestHost < Test::Unit::TestCase
end
def test_list
+ list = nil
assert_nothing_raised do
- @hosttype.defaultprovider.prefetch
+ list = @hosttype.defaultprovider.instances
end
- count = 0
- @hosttype.each do |h|
- count += 1
- end
-
- assert_equal(0, count, "Found hosts in empty file somehow")
+ assert_equal(0, list.length, "Found hosts in empty file somehow")
end
# Darwin will actually write to netinfo here.
@@ -213,12 +209,13 @@ class TestHost < Test::Unit::TestCase
def test_puppetalias
host = mkhost()
+ catalog = mk_catalog(host)
assert_nothing_raised {
host[:alias] = "testing"
}
- same = host.class["testing"]
+ same = catalog.resource(:host, "testing")
assert(same, "Could not retrieve by alias")
end
end
diff --git a/test/ral/type/parameter.rb b/test/ral/type/parameter.rb
index e1b8e00b3..04c4b0ce1 100755
--- a/test/ral/type/parameter.rb
+++ b/test/ral/type/parameter.rb
@@ -131,7 +131,7 @@ class TestParameter < Test::Unit::TestCase
assert_instance_of(param, obj, "alias is an instance of the wrong class")
# Make sure the alias got created
- assert(type["foo"], "Did not retrieve object by its alias")
+ assert(config.resource(type.name, "foo"), "Did not retrieve object by its alias")
# Now try it during initialization
other = nil
diff --git a/test/ral/type/sshkey.rb b/test/ral/type/sshkey.rb
index b9aed20e8..333bc377d 100755
--- a/test/ral/type/sshkey.rb
+++ b/test/ral/type/sshkey.rb
@@ -49,26 +49,27 @@ class TestSSHKey < Test::Unit::TestCase
@catalog ||= mk_catalog
- assert_nothing_raised {
- key = @sshkeytype.create(
- :name => "host%s.madstop.com" % @kcount,
- :key => "%sAAAAB3NzaC1kc3MAAACBAMnhSiku76y3EGkNCDsUlvpO8tRgS9wL4Eh54WZfQ2lkxqfd2uT/RTT9igJYDtm/+UHuBRdNGpJYW1Nw2i2JUQgQEEuitx4QKALJrBotejGOAWxxVk6xsh9xA0OW8Q3ZfuX2DDitfeC8ZTCl4xodUMD8feLtP+zEf8hxaNamLlt/AAAAFQDYJyf3vMCWRLjTWnlxLtOyj/bFpwAAAIEAmRxxXb4jjbbui9GYlZAHK00689DZuX0EabHNTl2yGO5KKxGC6Esm7AtjBd+onfu4Rduxut3jdI8GyQCIW8WypwpJofCIyDbTUY4ql0AQUr3JpyVytpnMijlEyr41FfIb4tnDqnRWEsh2H7N7peW+8DWZHDFnYopYZJ9Yu4/jHRYAAACAERG50e6aRRb43biDr7Ab9NUCgM9bC0SQscI/xdlFjac0B/kSWJYTGVARWBDWug705hTnlitY9cLC5Ey/t/OYOjylTavTEfd/bh/8FkAYO+pWdW3hx6p97TBffK0b6nrc6OORT2uKySbbKOn0681nNQh4a6ueR3JRppNkRPnTk5c=" % @kcount,
- :type => "ssh-dss",
- :alias => ["192.168.0.%s" % @kcount],
- :catalog => @catalog
- )
- }
+ key = @sshkeytype.create(
+ :name => "host%s.madstop.com" % @kcount,
+ :key => "%sAAAAB3NzaC1kc3MAAACBAMnhSiku76y3EGkNCDsUlvpO8tRgS9wL4Eh54WZfQ2lkxqfd2uT/RTT9igJYDtm/+UHuBRdNGpJYW1Nw2i2JUQgQEEuitx4QKALJrBotejGOAWxxVk6xsh9xA0OW8Q3ZfuX2DDitfeC8ZTCl4xodUMD8feLtP+zEf8hxaNamLlt/AAAAFQDYJyf3vMCWRLjTWnlxLtOyj/bFpwAAAIEAmRxxXb4jjbbui9GYlZAHK00689DZuX0EabHNTl2yGO5KKxGC6Esm7AtjBd+onfu4Rduxut3jdI8GyQCIW8WypwpJofCIyDbTUY4ql0AQUr3JpyVytpnMijlEyr41FfIb4tnDqnRWEsh2H7N7peW+8DWZHDFnYopYZJ9Yu4/jHRYAAACAERG50e6aRRb43biDr7Ab9NUCgM9bC0SQscI/xdlFjac0B/kSWJYTGVARWBDWug705hTnlitY9cLC5Ey/t/OYOjylTavTEfd/bh/8FkAYO+pWdW3hx6p97TBffK0b6nrc6OORT2uKySbbKOn0681nNQh4a6ueR3JRppNkRPnTk5c=" % @kcount,
+ :type => "ssh-dss",
+ :alias => ["192.168.0.%s" % @kcount],
+ :catalog => @catalog
+ )
+
+ @catalog.add_resource(key)
return key
end
def test_instances
+ list = nil
assert_nothing_raised {
- Puppet.type(:sshkey).instances
+ list = Puppet.type(:sshkey).instances
}
count = 0
- @sshkeytype.each do |h|
+ list.each do |h|
count += 1
end
@@ -90,7 +91,6 @@ class TestSSHKey < Test::Unit::TestCase
# Now create a new key object
name = key.name
key = nil
- @sshkeytype.clear
key = @sshkeytype.create :name => name, :target => file, :provider => :parsed
key.retrieve
@@ -102,19 +102,17 @@ class TestSSHKey < Test::Unit::TestCase
def test_moddingkey
key = mkkey()
- assert_events([:sshkey_created], key)
+ @catalog.apply
key.retrieve
aliases = %w{madstop kirby yayness}
key[:alias] = aliases
- params = key.instance_variable_get("@parameters")
- assert_events([:sshkey_changed], key)
+ @catalog.apply
aliases.each do |name|
- assert_equal(key, key.class[name],
- "alias was not set")
+ assert_equal(key.object_id, @catalog.resource(:sshkey, name).object_id, "alias %s was not set" % name)
end
end
@@ -136,7 +134,9 @@ class TestSSHKey < Test::Unit::TestCase
key[:alias] = "testing"
}
- same = key.class["testing"]
+ key.finish
+
+ same = @catalog.resource(:sshkey, "testing")
assert(same, "Could not retrieve by alias")
end
@@ -170,7 +170,10 @@ class TestSSHKey < Test::Unit::TestCase
}
assert_apply(*keys)
keys.clear
- Puppet.type(:sshkey).clear
+
+ @catalog.clear(true)
+ @catalog = nil
+
newkey = mkkey()
#newkey[:ensure] = :present
names << newkey.name
@@ -178,17 +181,9 @@ class TestSSHKey < Test::Unit::TestCase
# Verify we can retrieve that info
assert_nothing_raised("Could not retrieve after second write") {
- newkey.provider.class.prefetch
- newkey.retrieve
+ newkey.provider.prefetch
}
- # And verify that we have data for everything
- names.each { |name|
- key = Puppet.type(:sshkey)[name] ||
- Puppet.type(:sshkey).create(:name => name)
- assert(key, "Could not retrieve key for %s" % name)
- assert(key.provider.exists?, "key %s is missing" % name)
- }
+ assert(newkey.provider.exists?, "Did not see key in file")
end
end
-
diff --git a/test/ral/type/tidy.rb b/test/ral/type/tidy.rb
index 657ca6e93..a3a3b4b01 100755
--- a/test/ral/type/tidy.rb
+++ b/test/ral/type/tidy.rb
@@ -207,8 +207,6 @@ class TestTidy < Test::Unit::TestCase
assert_apply(tidy)
assert(! FileTest.exists?(path), "file did not get tidied")
- tidy.class.clear
-
# Now try one with just an age attribute.
time = Time.now - 10
stat = stub 'stat', :mtime => time, :atime => time, :ftype => "file"
diff --git a/test/ral/type/user.rb b/test/ral/type/user.rb
index 87d5b6075..1a2de2649 100755
--- a/test/ral/type/user.rb
+++ b/test/ral/type/user.rb
@@ -455,6 +455,7 @@ class TestUser < Test::Unit::TestCase
# Testing #455
def test_autorequire_with_no_group_should
user = Puppet::Type.type(:user).create(:name => "yaytest", :check => :all)
+ catalog = mk_catalog(user)
assert_nothing_raised do
user.autorequire
diff --git a/test/ral/type/yumrepo.rb b/test/ral/type/yumrepo.rb
index 899a02135..273179bc4 100755
--- a/test/ral/type/yumrepo.rb
+++ b/test/ral/type/yumrepo.rb
@@ -17,6 +17,9 @@ class TestYumRepo < Test::Unit::TestCase
f.print "[main]\nreposdir=#{@yumdir} /no/such/dir\n"
end
Puppet.type(:yumrepo).yumconf = @yumconf
+
+ # It needs to be reset each time, otherwise the cache is used.
+ Puppet.type(:yumrepo).inifile = nil
end
# Modify one existing section
@@ -24,19 +27,17 @@ class TestYumRepo < Test::Unit::TestCase
copy_datafiles
devel = make_repo("development", { :descr => "New description" })
current_values = devel.retrieve
+
assert_equal("development", devel[:name])
- assert_equal('Fedora Core $releasever - Development Tree',
- current_values[devel.property(:descr)])
- assert_equal('New description',
- devel.property(:descr).should)
+ assert_equal('Fedora Core $releasever - Development Tree', current_values[devel.property(:descr)])
+ assert_equal('New description', devel.property(:descr).should)
assert_apply(devel)
+
inifile = Puppet.type(:yumrepo).read()
assert_equal('New description', inifile['development']['name'])
- assert_equal('Fedora Core $releasever - $basearch - Base',
- inifile['base']['name'])
+ assert_equal('Fedora Core $releasever - $basearch - Base', inifile['base']['name'])
assert_equal("foo\n bar\n baz", inifile['base']['exclude'])
- assert_equal(['base', 'development', 'main'],
- all_sections(inifile))
+ assert_equal(['base', 'development', 'main'], all_sections(inifile))
end
# Create a new section
diff --git a/test/util/filetype.rb b/test/util/filetype.rb
index 6c7ede07b..24a968552 100755
--- a/test/util/filetype.rb
+++ b/test/util/filetype.rb
@@ -85,7 +85,7 @@ class TestFileType < Test::Unit::TestCase
assert_nothing_raised("Could not call backup with no buckets") do
obj.backup
end
- puppet = type["puppet"]
+ puppet = type.mkdefaultbucket
assert(puppet, "Did not create default filebucket")
assert_equal("one", puppet.bucket.getfile(Digest::MD5.hexdigest(File.read(path))), "Could not get file from backup")
@@ -99,7 +99,7 @@ class TestFileType < Test::Unit::TestCase
assert_equal("two", puppet.bucket.getfile(Digest::MD5.hexdigest(File.read(path))), "Could not get file from backup")
end
- if Facter["operatingsystem"].value == "Darwin"
+ if Facter["operatingsystem"].value == "Darwin" and Facter["operatingsystemrelease"] != "9.1.0"
def test_ninfotoarray
obj = nil
type = nil
diff --git a/test/util/posixtest.rb b/test/util/posixtest.rb
index 34d68e3a2..8fd11b086 100755
--- a/test/util/posixtest.rb
+++ b/test/util/posixtest.rb
@@ -35,16 +35,6 @@ class TestPosixUtil < Test::Unit::TestCase
end
end
- def test_get_provider_value
- user = nonrootuser
- obj = mk_posix_resource(:user, user)
-
- assert_nothing_raised do
- assert_equal(user.uid, get_provider_value(:user, :uid, user.uid))
- assert_equal(user.name, get_provider_value(:user, :name, user.name))
- end
- end
-
def test_gid_and_uid
{:user => nonrootuser, :group => nonrootgroup}.each do |type, obj|
method = idfield(type)
diff --git a/test/util/settings.rb b/test/util/settings.rb
index cf5dca76d..de6fff946 100755
--- a/test/util/settings.rb
+++ b/test/util/settings.rb
@@ -256,69 +256,6 @@ yay = /a/path
end
end
- def test_old_parse
- text = %{
-one = this is a test
-two = another test
-owner = root
-group = root
-yay = /a/path
-
-[section1]
- attr = value
- owner = puppet
- group = puppet
- attrdir = /some/dir
- attr3 = $attrdir/other
- }
-
- file = tempfile()
- File.open(file, "w") { |f| f.puts text }
-
- assert_nothing_raised {
- @config.setdefaults("puppet",
- :one => ["a", "one"],
- :two => ["a", "two"],
- :yay => ["/default/path", "boo"],
- :mkusers => [true, "uh, yeah"]
- )
- }
-
- assert_nothing_raised {
- @config.setdefaults("section1",
- :attr => ["a", "one"],
- :attrdir => ["/another/dir", "two"],
- :attr3 => ["$attrdir/maybe", "boo"]
- )
- }
-
- assert_nothing_raised {
- @config.old_parse(file)
- }
-
- assert_equal("value", @config[:attr])
- assert_equal("/some/dir", @config[:attrdir])
- assert_equal(:directory, @config.element(:attrdir).type)
- assert_equal("/some/dir/other", @config[:attr3])
-
- elem = nil
- assert_nothing_raised {
- elem = @config.element(:attr3)
- }
-
- assert(elem)
- assert_equal("puppet", elem.owner)
-
- config = nil
- assert_nothing_raised {
- config = @config.to_config
- }
-
- assert_nothing_raised("Could not create transportable config") {
- @config.to_transportable
- }
- end
-
def test_parse
result = {
:main => {:main => "main", :bad => "invalid", :cliparam => "reset"},
diff --git a/test/util/utiltest.rb b/test/util/utiltest.rb
index 35e1446a1..a8dfca9c2 100755
--- a/test/util/utiltest.rb
+++ b/test/util/utiltest.rb
@@ -264,24 +264,5 @@ class TestPuppetUtil < Test::Unit::TestCase
# Puppet::Util.execute(cmd, 0, 0)
#}
end
-
- # This is mostly to test #380.
- def test_get_provider_value
- group = Puppet::Type.type(:group).create :name => "yayness", :ensure => :present
-
- root = Puppet::Type.type(:user).create :name => "root", :ensure => :present
-
- val = nil
- assert_nothing_raised do
- val = Puppet::Util.get_provider_value(:group, :gid, "yayness")
- end
- assert_nil(val, "returned a value on a missing group")
-
- # Now make sure we get a value for one we know exists
- assert_nothing_raised do
- val = Puppet::Util.get_provider_value(:user, :uid, "root")
- end
- assert_equal(0, val, "got invalid uid for root")
- end
end