summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael V. O'Brien <michael@reductivelabs.com>2007-09-25 12:00:07 -0500
committerMichael V. O'Brien <michael@reductivelabs.com>2007-09-25 12:00:07 -0500
commitff2828f5dbe68ff1cb06a3503590a3e4bd1b59e3 (patch)
tree8c8960cac1d7b3e8b48e44163062be3b3f4c201f
parentf8ab62b212788a4591276c95b5f67217f7517e4e (diff)
parentffaa8ce07979f4db860950fa9be08ca37964206f (diff)
downloadpuppet-ff2828f5dbe68ff1cb06a3503590a3e4bd1b59e3.tar.gz
puppet-ff2828f5dbe68ff1cb06a3503590a3e4bd1b59e3.tar.xz
puppet-ff2828f5dbe68ff1cb06a3503590a3e4bd1b59e3.zip
Merge branch 'master' of git://reductivelabs.com/puppet
-rwxr-xr-xbin/filebucket4
-rwxr-xr-xbin/puppet10
-rwxr-xr-xbin/puppetca4
-rwxr-xr-xbin/puppetd12
-rwxr-xr-xbin/puppetmasterd4
-rwxr-xr-xbin/puppetrun6
-rwxr-xr-xbin/ralsh4
-rwxr-xr-xext/module_puppet10
-rwxr-xr-xext/tools/passwd2puppet45
-rw-r--r--lib/puppet.rb30
-rw-r--r--lib/puppet/checksum.rb64
-rw-r--r--lib/puppet/config_stores/rest.rb2
-rw-r--r--lib/puppet/defaults.rb20
-rw-r--r--lib/puppet/dsl.rb10
-rw-r--r--lib/puppet/fact_stores/yaml.rb2
-rw-r--r--lib/puppet/indirector.rb91
-rw-r--r--lib/puppet/indirector/code.rb6
-rw-r--r--lib/puppet/indirector/code/configuration.rb171
-rw-r--r--lib/puppet/indirector/exec.rb57
-rw-r--r--lib/puppet/indirector/exec/node.rb50
-rw-r--r--lib/puppet/indirector/file.rb54
-rw-r--r--lib/puppet/indirector/file/checksum.rb33
-rw-r--r--lib/puppet/indirector/indirection.rb91
-rw-r--r--lib/puppet/indirector/ldap.rb90
-rw-r--r--lib/puppet/indirector/ldap/node.rb115
-rw-r--r--lib/puppet/indirector/memory.rb21
-rw-r--r--lib/puppet/indirector/memory/node.rb8
-rw-r--r--lib/puppet/indirector/null.rb9
-rw-r--r--lib/puppet/indirector/null/node.rb14
-rw-r--r--lib/puppet/indirector/terminus.rb117
-rw-r--r--lib/puppet/indirector/yaml.rb45
-rw-r--r--lib/puppet/indirector/yaml/facts.rb5
-rw-r--r--lib/puppet/metatype/closure.rb13
-rw-r--r--lib/puppet/metatype/container.rb8
-rw-r--r--lib/puppet/metatype/instances.rb12
-rw-r--r--lib/puppet/module.rb4
-rw-r--r--lib/puppet/network/client/ca.rb8
-rw-r--r--lib/puppet/network/client/master.rb180
-rw-r--r--lib/puppet/network/handler/ca.rb2
-rw-r--r--lib/puppet/network/handler/configuration.rb14
-rwxr-xr-xlib/puppet/network/handler/facts.rb68
-rwxr-xr-xlib/puppet/network/handler/filebucket.rb2
-rwxr-xr-xlib/puppet/network/handler/fileserver.rb15
-rw-r--r--lib/puppet/network/handler/master.rb9
-rw-r--r--lib/puppet/network/handler/node.rb242
-rwxr-xr-xlib/puppet/network/handler/report.rb4
-rwxr-xr-xlib/puppet/network/handler/resource.rb13
-rwxr-xr-xlib/puppet/network/handler/runner.rb4
-rw-r--r--lib/puppet/network/server/webrick.rb2
-rw-r--r--lib/puppet/node.rb34
-rw-r--r--lib/puppet/node/configuration.rb266
-rwxr-xr-xlib/puppet/node/facts.rb36
-rw-r--r--lib/puppet/node/searching.rb106
-rw-r--r--lib/puppet/parser/ast/component.rb224
-rw-r--r--lib/puppet/parser/interpreter.rb2
-rw-r--r--lib/puppet/pgraph.rb6
-rwxr-xr-xlib/puppet/provider/maillist/mailman.rb4
-rw-r--r--lib/puppet/provider/mount.rb2
-rw-r--r--lib/puppet/rails.rb4
-rw-r--r--lib/puppet/reference/configuration.rb2
-rw-r--r--lib/puppet/reports/rrdgraph.rb2
-rw-r--r--lib/puppet/reports/store.rb6
-rw-r--r--lib/puppet/reports/tagmail.rb2
-rw-r--r--lib/puppet/sslcertificates/ca.rb18
-rw-r--r--lib/puppet/sslcertificates/inventory.rb2
-rw-r--r--lib/puppet/sslcertificates/support.rb8
-rw-r--r--lib/puppet/transaction.rb171
-rw-r--r--lib/puppet/transportable.rb94
-rw-r--r--lib/puppet/type.rb23
-rw-r--r--lib/puppet/type/component.rb67
-rw-r--r--lib/puppet/type/pfile.rb53
-rw-r--r--lib/puppet/util/feature.rb53
-rwxr-xr-xlib/puppet/util/instance_loader.rb10
-rw-r--r--lib/puppet/util/metric.rb2
-rw-r--r--lib/puppet/util/settings.rb (renamed from lib/puppet/util/config.rb)221
-rw-r--r--lib/puppet/util/storage.rb4
-rw-r--r--spec/Rakefile6
-rwxr-xr-xspec/bin/spec1
-rwxr-xr-xspec/integration/checksum.rb48
-rwxr-xr-xspec/integration/node.rb46
-rw-r--r--spec/lib/spec/dsl/behaviour.rb6
-rw-r--r--spec/lib/spec/runner/behaviour_runner.rb2
-rw-r--r--spec/spec_helper.rb14
-rwxr-xr-xspec/unit/indirector/code.rb33
-rwxr-xr-xspec/unit/indirector/code/configuration.rb158
-rwxr-xr-xspec/unit/indirector/exec.rb49
-rwxr-xr-xspec/unit/indirector/exec/node.rb62
-rwxr-xr-xspec/unit/indirector/file.rb160
-rwxr-xr-xspec/unit/indirector/file/checksum.rb142
-rwxr-xr-xspec/unit/indirector/indirection.rb160
-rwxr-xr-xspec/unit/indirector/indirector.rb86
-rwxr-xr-xspec/unit/indirector/ldap.rb147
-rwxr-xr-xspec/unit/indirector/ldap/node.rb240
-rwxr-xr-xspec/unit/indirector/memory.rb53
-rwxr-xr-xspec/unit/indirector/memory/node.rb19
-rwxr-xr-xspec/unit/indirector/null.rb27
-rwxr-xr-xspec/unit/indirector/null/node.rb18
-rwxr-xr-xspec/unit/indirector/terminus.rb226
-rwxr-xr-xspec/unit/indirector/yaml.rb104
-rwxr-xr-xspec/unit/indirector/yaml/facts.rb26
-rwxr-xr-xspec/unit/node/configuration.rb337
-rwxr-xr-xspec/unit/node/facts.rb39
-rwxr-xr-xspec/unit/node/node.rb (renamed from spec/unit/other/node.rb)42
-rwxr-xr-xspec/unit/node/searching.rb79
-rwxr-xr-xspec/unit/other/checksum.rb92
-rwxr-xr-xspec/unit/other/modules.rb24
-rwxr-xr-xspec/unit/other/pgraph.rb285
-rwxr-xr-xspec/unit/other/transaction.rb26
-rwxr-xr-xspec/unit/other/transbucket.rb133
-rwxr-xr-xspec/unit/other/transobject.rb116
-rwxr-xr-xspec/unit/parser/interpreter.rb4
-rwxr-xr-xspec/unit/ral/type.rb25
-rwxr-xr-xspec/unit/util/config.rb408
-rwxr-xr-xspec/unit/util/settings.rb535
-rwxr-xr-xtest/certmgr/certmgr.rb8
-rwxr-xr-xtest/certmgr/inventory.rb4
-rw-r--r--test/data/snippets/failmissingexecpath.pp14
-rwxr-xr-xtest/language/snippets.rb18
-rwxr-xr-xtest/lib/puppettest.rb20
-rw-r--r--test/lib/puppettest/graph.rb41
-rw-r--r--test/lib/puppettest/parsertesting.rb11
-rw-r--r--test/lib/puppettest/runnable_test.rb30
-rw-r--r--test/lib/puppettest/support/assertions.rb52
-rwxr-xr-xtest/lib/puppettest/support/resources.rb34
-rw-r--r--test/lib/puppettest/support/utils.rb38
-rw-r--r--test/lib/puppettest/testcase.rb23
-rwxr-xr-xtest/network/client/ca.rb2
-rwxr-xr-xtest/network/client/client.rb6
-rwxr-xr-xtest/network/client/master.rb54
-rwxr-xr-xtest/network/handler/configuration.rb26
-rwxr-xr-xtest/network/handler/facts.rb112
-rwxr-xr-xtest/network/handler/master.rb16
-rwxr-xr-xtest/network/handler/node.rb640
-rwxr-xr-xtest/other/dsl.rb2
-rwxr-xr-xtest/other/events.rb67
-rwxr-xr-xtest/other/overrides.rb6
-rwxr-xr-xtest/other/pgraph.rb290
-rwxr-xr-xtest/other/relationships.rb13
-rwxr-xr-xtest/other/report.rb18
-rwxr-xr-xtest/other/transactions.rb270
-rwxr-xr-xtest/puppet/conffiles.rb5
-rwxr-xr-xtest/ral/manager/type.rb94
-rwxr-xr-xtest/ral/providers/service.rb4
-rwxr-xr-xtest/ral/types/basic.rb11
-rwxr-xr-xtest/ral/types/component.rb113
-rwxr-xr-xtest/ral/types/cron.rb4
-rwxr-xr-xtest/ral/types/exec.rb10
-rwxr-xr-xtest/ral/types/file.rb38
-rwxr-xr-xtest/ral/types/file/target.rb6
-rwxr-xr-xtest/ral/types/fileignoresource.rb48
-rwxr-xr-xtest/ral/types/filesources.rb63
-rwxr-xr-xtest/ral/types/group.rb4
-rwxr-xr-xtest/ral/types/tidy.rb2
-rwxr-xr-xtest/ral/types/user.rb18
-rwxr-xr-xtest/util/fact_store.rb67
-rwxr-xr-xtest/util/features.rb2
-rwxr-xr-xtest/util/graph.rb108
-rwxr-xr-xtest/util/settings.rb (renamed from test/util/config.rb)166
158 files changed, 5845 insertions, 3937 deletions
diff --git a/bin/filebucket b/bin/filebucket
index 2001eaf63..22580cbe3 100755
--- a/bin/filebucket
+++ b/bin/filebucket
@@ -109,7 +109,7 @@ options = [
]
# Add all of the config parameters as valid options.
-Puppet.config.addargs(options)
+Puppet.settings.addargs(options)
result = GetoptLong.new(*options)
@@ -139,7 +139,7 @@ begin
when "--remote"
options[:remote] = true
else
- Puppet.config.handlearg(opt, arg)
+ Puppet.settings.handlearg(opt, arg)
end
}
rescue GetoptLong::InvalidOption => detail
diff --git a/bin/puppet b/bin/puppet
index 36f0fcd62..deeb65c42 100755
--- a/bin/puppet
+++ b/bin/puppet
@@ -76,7 +76,7 @@ options = [
]
# Add all of the config parameters as valid options.
-Puppet.config.addargs(options)
+Puppet.settings.addargs(options)
result = GetoptLong.new(*options)
@@ -124,7 +124,7 @@ begin
$stderr.puts detail.to_s
end
else
- Puppet.config.handlearg(opt, arg)
+ Puppet.settings.handlearg(opt, arg)
end
}
rescue GetoptLong::InvalidOption => detail
@@ -156,7 +156,7 @@ end
# Now parse the config
if Puppet[:config] and File.exists? Puppet[:config]
- Puppet.config.parse(Puppet[:config])
+ Puppet.settings.parse(Puppet[:config])
end
Puppet.genconfig
@@ -194,8 +194,8 @@ begin
if Puppet[:parseonly]
exit(0)
end
- client.getconfig
- client.apply
+ config = client.getconfig
+ config.apply
rescue => detail
if detail.is_a?(XMLRPC::FaultException)
$stderr.puts detail.message
diff --git a/bin/puppetca b/bin/puppetca
index 3dbd87b89..72b2640a3 100755
--- a/bin/puppetca
+++ b/bin/puppetca
@@ -104,7 +104,7 @@ options = [
]
# Add all of the config parameters as valid options.
-Puppet.config.addargs(options)
+Puppet.settings.addargs(options)
result = GetoptLong.new(*options)
@@ -143,7 +143,7 @@ begin
when "--verbose"
Puppet::Util::Log.level = :info
else
- Puppet.config.handlearg(opt, arg)
+ Puppet.settings.handlearg(opt, arg)
end
}
rescue GetoptLong::InvalidOption => detail
diff --git a/bin/puppetd b/bin/puppetd
index a03ed8f10..8d112ca3a 100755
--- a/bin/puppetd
+++ b/bin/puppetd
@@ -178,7 +178,7 @@ options = [
]
# Add all of the config parameters as valid options.
-Puppet.config.addargs(options)
+Puppet.settings.addargs(options)
result = GetoptLong.new(*options)
@@ -216,10 +216,10 @@ begin
options[:enable] = true
when "--test"
# Enable all of the most common test options.
- Puppet.config.handlearg("--ignorecache")
- Puppet.config.handlearg("--no-usecacheonfailure")
- Puppet.config.handlearg("--no-splay")
- Puppet.config.handlearg("--show_diff")
+ Puppet.settings.handlearg("--ignorecache")
+ Puppet.settings.handlearg("--no-usecacheonfailure")
+ Puppet.settings.handlearg("--no-splay")
+ Puppet.settings.handlearg("--show_diff")
options[:onetime] = true
options[:waitforcert] = 0
unless Puppet::Util::Log.level == :debug
@@ -264,7 +264,7 @@ begin
options[:waitforcert] = arg.to_i
explicit_waitforcert = true
else
- Puppet.config.handlearg(opt, arg)
+ Puppet.settings.handlearg(opt, arg)
end
}
rescue GetoptLong::InvalidOption => detail
diff --git a/bin/puppetmasterd b/bin/puppetmasterd
index 4552fd0b8..51c714b15 100755
--- a/bin/puppetmasterd
+++ b/bin/puppetmasterd
@@ -95,7 +95,7 @@ options = [
]
# Add all of the config parameters as valid options.
-Puppet.config.addargs(options)
+Puppet.settings.addargs(options)
result = GetoptLong.new(*options)
@@ -152,7 +152,7 @@ begin
when "--verbose"
options[:verbose] = true
else
- Puppet.config.handlearg(opt, arg)
+ Puppet.settings.handlearg(opt, arg)
end
}
rescue GetoptLong::InvalidOption => detail
diff --git a/bin/puppetrun b/bin/puppetrun
index cd6b493b9..1aa0b295b 100755
--- a/bin/puppetrun
+++ b/bin/puppetrun
@@ -199,7 +199,7 @@ flags = [
]
# Add all of the config parameters as valid options.
-Puppet.config.addargs(flags)
+Puppet.settings.addargs(flags)
result = GetoptLong.new(*flags)
@@ -259,7 +259,7 @@ begin
when "--debug"
options[:debug] = true
else
- Puppet.config.handlearg(opt, arg)
+ Puppet.settings.handlearg(opt, arg)
end
}
rescue GetoptLong::InvalidOption => detail
@@ -278,7 +278,7 @@ config = File.join(Puppet[:confdir], "puppetmasterd.conf")
Puppet.parse_config(config)
if File.exists? config
- Puppet.config.parse(config)
+ Puppet.settings.parse(config)
end
if Puppet[:ldapnodes]
diff --git a/bin/ralsh b/bin/ralsh
index 7985f3995..7bf0bd3d7 100755
--- a/bin/ralsh
+++ b/bin/ralsh
@@ -99,7 +99,7 @@ options = [
]
# Add all of the config parameters as valid options.
-Puppet.config.addargs(options)
+Puppet.settings.addargs(options)
result = GetoptLong.new(*options)
@@ -139,7 +139,7 @@ result.each { |opt,arg|
debug = true
else
# Anything else is handled by the config stuff
- Puppet.config.handlearg(opt, arg)
+ Puppet.settings.handlearg(opt, arg)
end
}
diff --git a/ext/module_puppet b/ext/module_puppet
index cb03b6ef2..52f65b094 100755
--- a/ext/module_puppet
+++ b/ext/module_puppet
@@ -61,7 +61,7 @@ options = [
]
# Add all of the config parameters as valid options.
-Puppet.config.addargs(options)
+Puppet.settings.addargs(options)
result = GetoptLong.new(*options)
@@ -108,7 +108,7 @@ begin
$stderr.puts detail.to_s
end
else
- Puppet.config.handlearg(opt, arg)
+ Puppet.settings.handlearg(opt, arg)
end
}
rescue GetoptLong::InvalidOption => detail
@@ -121,7 +121,7 @@ end
# Now parse the config
if Puppet[:config] and File.exists? Puppet[:config]
- Puppet.config.parse(Puppet[:config])
+ Puppet.settings.parse(Puppet[:config])
end
client = nil
@@ -191,8 +191,8 @@ if parseonly
end
begin
- client.getconfig
- client.apply
+ config = client.getconfig
+ config.apply
rescue => detail
Puppet.err detail
exit(1)
diff --git a/ext/tools/passwd2puppet b/ext/tools/passwd2puppet
deleted file mode 100755
index 29ffdbf95..000000000
--- a/ext/tools/passwd2puppet
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/ruby -w
-
-#--------------------
-# Convert a passwd-format file to Puppet users
-#
-
-require 'getoptlong'
-
-result = GetoptLong.new(
- [ "--help", "-h", GetoptLong::NO_ARGUMENT ]
-)
-
-result.each { |opt,arg|
- case opt
- when "--help"
- puts "There is no help yet"
- exit
- else
- raise "Invalid option '#{opt}'"
- end
-}
-
-fields = %w{uid gid comment home shell}
-
-puts "user {"
-ARGV.each do |file|
- File.open(file) do |of|
- of.sort.each do |line|
- next if line =~ /^\s*#/
- next if line =~ /^\s*$/
-
- ary = line.chomp.split(":")
- puts " " + ary.shift + ":"
- ary.shift # get rid of that password field
-
- puts fields.zip(ary).collect { |field, val|
- " %s => \"%s\"" % [field, val]
- }.join(",\n") + ";"
-
- end
- end
-end
-puts "}"
-
-# $Id$
diff --git a/lib/puppet.rb b/lib/puppet.rb
index 20d879fdf..c1f31e467 100644
--- a/lib/puppet.rb
+++ b/lib/puppet.rb
@@ -12,7 +12,7 @@ require 'puppet/external/event-loop'
require 'puppet/util'
require 'puppet/util/log'
require 'puppet/util/autoload'
-require 'puppet/util/config'
+require 'puppet/util/settings'
require 'puppet/util/feature'
require 'puppet/util/suidmanager'
@@ -45,7 +45,7 @@ module Puppet
end
# the hash that determines how our system behaves
- @@config = Puppet::Util::Config.new
+ @@settings = Puppet::Util::Settings.new
# The services running in this process.
@services ||= []
@@ -76,7 +76,7 @@ module Puppet
# Store a new default value.
def self.setdefaults(section, hash)
- @@config.setdefaults(section, hash)
+ @@settings.setdefaults(section, hash)
end
# configuration parameter access and stuff
@@ -89,17 +89,17 @@ module Puppet
return false
end
else
- return @@config[param]
+ return @@settings[param]
end
end
# configuration parameter access and stuff
def self.[]=(param,value)
- @@config[param] = value
+ @@settings[param] = value
end
def self.clear
- @@config.clear
+ @@settings.clear
end
def self.debug=(value)
@@ -110,8 +110,8 @@ module Puppet
end
end
- def self.config
- @@config
+ def self.settings
+ @@settings
end
# Load all of the configuration parameters.
@@ -122,7 +122,7 @@ module Puppet
val = Puppet[:configprint]
if val == "all"
hash = {}
- Puppet.config.each do |name, obj|
+ Puppet.settings.each do |name, obj|
val = obj.value
case val
when true, false, "": val = val.inspect
@@ -134,7 +134,7 @@ module Puppet
end
elsif val =~ /,/
val.split(/\s*,\s*/).sort.each do |v|
- if Puppet.config.include?(v)
+ if Puppet.settings.include?(v)
puts "%s = %s" % [v, Puppet[v]]
else
puts "invalid parameter: %s" % v
@@ -143,7 +143,7 @@ module Puppet
end
else
val.split(/\s*,\s*/).sort.each do |v|
- if Puppet.config.include?(v)
+ if Puppet.settings.include?(v)
puts Puppet[val]
else
puts "invalid parameter: %s" % v
@@ -154,14 +154,14 @@ module Puppet
exit(0)
end
if Puppet[:genconfig]
- puts Puppet.config.to_config
+ puts Puppet.settings.to_config
exit(0)
end
end
def self.genmanifest
if Puppet[:genmanifest]
- puts Puppet.config.to_manifest
+ puts Puppet.settings.to_manifest
exit(0)
end
end
@@ -208,14 +208,14 @@ module Puppet
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.config.old_parse(oldconfig)
+ Puppet.settings.old_parse(oldconfig)
return
end
# Now check for the normal config.
if Puppet[:config] and File.exists? Puppet[:config]
Puppet.debug "Parsing %s" % Puppet[:config]
- Puppet.config.parse(Puppet[:config])
+ Puppet.settings.parse(Puppet[:config])
end
end
diff --git a/lib/puppet/checksum.rb b/lib/puppet/checksum.rb
new file mode 100644
index 000000000..c607953c1
--- /dev/null
+++ b/lib/puppet/checksum.rb
@@ -0,0 +1,64 @@
+#
+# Created by Luke Kanies on 2007-9-22.
+# Copyright (c) 2007. All rights reserved.
+
+require 'puppet'
+require 'puppet/indirector'
+
+# A checksum class to model translating checksums to file paths. This
+# is the new filebucket.
+class Puppet::Checksum
+ extend Puppet::Indirector
+
+ indirects :checksum
+
+ attr_reader :algorithm, :content
+
+ def algorithm=(value)
+ unless respond_to?(value)
+ raise ArgumentError, "Checksum algorithm %s is not supported" % value
+ end
+ value = value.intern if value.is_a?(String)
+ @algorithm = value
+ # Reset the checksum so it's forced to be recalculated.
+ @checksum = nil
+ end
+
+ # Calculate (if necessary) and return the checksum
+ def checksum
+ unless @checksum
+ @checksum = send(algorithm)
+ end
+ @checksum
+ end
+
+ def initialize(content, algorithm = nil)
+ raise ArgumentError.new("You must specify the content") unless content
+
+ @content = content
+ self.algorithm = algorithm || "md5"
+
+ # Init to avoid warnings.
+ @checksum = nil
+ end
+
+ # This can't be private, else respond_to? returns false.
+ def md5
+ require 'digest/md5'
+ Digest::MD5.hexdigest(content)
+ end
+
+ # This is here so the Indirector::File terminus works correctly.
+ def name
+ checksum
+ end
+
+ def sha1
+ require 'digest/sha1'
+ Digest::SHA1.hexdigest(content)
+ end
+
+ def to_s
+ "Checksum<{%s}%s>" % [algorithm, checksum]
+ end
+end
diff --git a/lib/puppet/config_stores/rest.rb b/lib/puppet/config_stores/rest.rb
index 980968bd8..bb3d937ac 100644
--- a/lib/puppet/config_stores/rest.rb
+++ b/lib/puppet/config_stores/rest.rb
@@ -1,4 +1,4 @@
-Puppet::Util::ConfigStore.newstore(:rest) do
+Puppet::Util::SettingsStore.newstore(:rest) do
desc "Store client configurations via a REST web service."
require 'net/http'
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 78364e786..f76ae9b84 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -267,7 +267,7 @@ module Puppet
)
# Define the config default.
- self.setdefaults(self.config[:name],
+ self.setdefaults(self.settings[:name],
:config => ["$confdir/puppet.conf",
"The configuration file for #{Puppet[:name]}."],
:pidfile => ["", "The pid file"],
@@ -494,14 +494,18 @@ module Puppet
"The server through which to send email reports."]
)
- self.setdefaults(:facts,
- :factstore => ["yaml",
- "The backend store to use for client facts."]
+ # This needs to be in main because it's used too early in the system, such that
+ # we get an infinite loop otherwise.
+ self.setdefaults(:main,
+ :facts_terminus => ["yaml",
+ "The backend store to use for client facts."],
+ :checksum_terminus => ["file",
+ "The backend store to use for storing files by checksum (i.e., filebuckets)."]
)
- self.setdefaults(:yamlfacts,
- :yamlfactdir => ["$vardir/facts",
- "The directory in which client facts are stored when the yaml fact store is used."]
+ self.setdefaults(:yaml,
+ :yamldir => ["$vardir/yaml",
+ "The directory in which YAML data is stored, usually in a subdirectory."]
)
self.setdefaults(:rails,
@@ -554,7 +558,7 @@ module Puppet
setdefaults(:parser,
:typecheck => [true, "Whether to validate types during parsing."],
:paramcheck => [true, "Whether to validate parameters during parsing."],
- :node_source => ["none", "Where to look for node configuration information.
+ :node_terminus => ["null", "Where to look for node configuration information.
The default node source, ``none``, just returns a node with its facts
filled in, which is required for normal functionality.
See the `NodeSourceReference`:trac: for more information."]
diff --git a/lib/puppet/dsl.rb b/lib/puppet/dsl.rb
index 793578bca..3696cd9ee 100644
--- a/lib/puppet/dsl.rb
+++ b/lib/puppet/dsl.rb
@@ -67,11 +67,8 @@ module Puppet
def apply
bucket = export()
- objects = bucket.to_type
- master = Puppet::Network::Client.master.new :Master => "whatever"
- master.objects = objects
-
- master.apply
+ configuration = bucket.to_configuration
+ configuration.apply
end
def export
@@ -255,8 +252,7 @@ module Puppet
def scope
unless defined?(@scope)
@interp = Puppet::Parser::Interpreter.new :Code => ""
- # Load the class, so the node object class is available.
- require 'puppet/network/handler/node'
+ require 'puppet/node'
@node = Puppet::Node.new(Facter.value(:hostname))
@node.parameters = Facter.to_hash
@interp = Puppet::Parser::Interpreter.new :Code => ""
diff --git a/lib/puppet/fact_stores/yaml.rb b/lib/puppet/fact_stores/yaml.rb
index a4b12a2e5..b33e162ba 100644
--- a/lib/puppet/fact_stores/yaml.rb
+++ b/lib/puppet/fact_stores/yaml.rb
@@ -16,7 +16,7 @@ Puppet::Util::FactStore.newstore(:yaml) do
end
def initialize
- Puppet.config.use(:yamlfacts)
+ Puppet.settings.use(:yamlfacts)
end
# Store the facts to disk.
diff --git a/lib/puppet/indirector.rb b/lib/puppet/indirector.rb
index 0ba538355..6ff2de1b4 100644
--- a/lib/puppet/indirector.rb
+++ b/lib/puppet/indirector.rb
@@ -1,76 +1,51 @@
# Manage indirections to termini. They are organized in terms of indirections -
# - e.g., configuration, node, file, certificate -- and each indirection has one
-# or more terminus types defined. The indirection must have its preferred terminus
-# configured via a 'default' in the form of '<indirection>_terminus'; e.g.,
-# 'node_terminus = ldap'.
+# or more terminus types defined. The indirection is configured via the
+# +indirects+ method, which will be called by the class extending itself
+# with this module.
module Puppet::Indirector
- # This manages reading in all of our files for us and then retrieving
- # loaded instances. We still have to define the 'newX' method, but this
- # does all of the rest -- loading, storing, and retrieving by name.
- require 'puppet/util/instance_loader'
- include Puppet::Util::InstanceLoader
+ # LAK:FIXME We need to figure out how to handle documentation for the
+ # different indirection types.
- # Define a new indirection terminus. This method is used by the individual
- # termini in their separate files. Again, the autoloader takes care of
- # actually loading these files.
- def register_terminus(name, options = {}, &block)
- genclass(name, :hash => instance_hash(indirection.name), :attributes => options, :block => block)
- end
-
- # Retrieve a terminus class by indirection and name.
- def terminus(name)
- loaded_instance(name)
- end
+ require 'puppet/indirector/indirection'
+ require 'puppet/indirector/terminus'
# Declare that the including class indirects its methods to
# this terminus. The terminus name must be the name of a Puppet
# default, not the value -- if it's the value, then it gets
# evaluated at parse time, which is before the user has had a chance
# to override it.
- def indirects(indirection, options)
- @indirection = indirection
- @indirect_terminus = options[:to]
-
- # Set up autoloading of the appropriate termini.
- autoload "puppet/indirector/%s" % indirection
+ def indirects(indirection)
+ raise(ArgumentError, "Already handling indirection for %s; cannot also handle %s" % [@indirection.name, indirection]) if defined?(@indirection) and @indirection
+ # populate this class with the various new methods
+ extend ClassMethods
+ include InstanceMethods
+
+ # instantiate the actual Terminus for that type and this name (:ldap, w/ args :node)
+ # & hook the instantiated Terminus into this class (Node: @indirection = terminus)
+ @indirection = Puppet::Indirector::Indirection.new(self, indirection)
end
- # Define methods for each of the HTTP methods. These just point to the
- # termini, with consistent error-handling. Each method is called with
- # the first argument being the indirection type and the rest of the
- # arguments passed directly on to the indirection terminus. There is
- # currently no attempt to standardize around what the rest of the arguments
- # should allow or include or whatever.
- # There is also no attempt to pre-validate that a given indirection supports
- # the method in question. We should probably require that indirections
- # declare supported methods, and then verify that termini implement all of
- # those methods.
- [:get, :post, :put, :delete].each do |method_name|
- define_method(method_name) do |*args|
- begin
- terminus.send(method_name, *args)
- rescue NoMethodError
- raise ArgumentError, "Indirection category %s does not respond to REST method %s" % [indirection, method_name]
- end
- end
- end
+ module ClassMethods
+ attr_reader :indirection
+
+ def find(*args)
+ indirection.find(*args)
+ end
- private
+ def destroy(*args)
+ indirection.destroy(*args)
+ end
- # Create a new terminus instance.
- def make_terminus(indirection)
- # Load our terminus class.
- unless klass = self.class.terminus(indirection, indirection.default)
- raise ArgumentError, "Could not find terminus %s for indirection %s" % [indirection.default, indirection]
- end
- return klass.new
+ def search(*args)
+ indirection.search(*args)
+ end
end
- # Return the singleton terminus for this indirection.
- def terminus
- unless terminus = @termini[indirection.name]
- terminus = @termini[indirection.name] = make_terminus(indirection)
- end
- terminus
+ module InstanceMethods
+ # these become instance methods
+ def save(*args)
+ self.class.indirection.save(self, *args)
+ end
end
end
diff --git a/lib/puppet/indirector/code.rb b/lib/puppet/indirector/code.rb
new file mode 100644
index 000000000..0c0ee146b
--- /dev/null
+++ b/lib/puppet/indirector/code.rb
@@ -0,0 +1,6 @@
+require 'puppet/indirector/terminus'
+
+# Do nothing, requiring that the back-end terminus do all
+# of the work.
+class Puppet::Indirector::Code < Puppet::Indirector::Terminus
+end
diff --git a/lib/puppet/indirector/code/configuration.rb b/lib/puppet/indirector/code/configuration.rb
new file mode 100644
index 000000000..6d0317204
--- /dev/null
+++ b/lib/puppet/indirector/code/configuration.rb
@@ -0,0 +1,171 @@
+require 'puppet/node'
+require 'puppet/node/configuration'
+require 'puppet/indirector/code'
+require 'puppet/parser/interpreter'
+require 'yaml'
+
+class Puppet::Indirector::Code::Configuration < Puppet::Indirector::Code
+ desc "Puppet's configuration compilation interface. Passed a node name
+ or other key, retrieves information about the node (using the ``node_source``)
+ and returns a compiled configuration."
+
+ include Puppet::Util
+
+ attr_accessor :code
+
+ # Compile a node's configuration.
+ def find(key, client = nil, clientip = nil)
+ # If we want to use the cert name as our key
+ if Puppet[:node_name] == 'cert' and client
+ key = client
+ end
+
+ # Note that this is reasonable, because either their node source should actually
+ # know about the node, or they should be using the ``none`` node source, which
+ # will always return data.
+ unless node = Puppet::Node.search(key)
+ raise Puppet::Error, "Could not find node '%s'" % key
+ end
+
+ # Add any external data to the node.
+ add_node_data(node)
+
+ configuration = compile(node)
+
+ return configuration
+ end
+
+ def initialize
+ set_server_facts
+ end
+
+ # Create/return our interpreter.
+ def interpreter
+ unless defined?(@interpreter) and @interpreter
+ @interpreter = create_interpreter
+ end
+ @interpreter
+ end
+
+ # Return the configuration version.
+ def version(client = nil, clientip = nil)
+ if client and node = Puppet::Node.search(client)
+ update_node_check(node)
+ return interpreter.configuration_version(node)
+ else
+ # Just return something that will always result in a recompile, because
+ # this is local.
+ return (Time.now + 1000).to_i
+ end
+ end
+
+ private
+
+ # Add any extra data necessary to the node.
+ def add_node_data(node)
+ # Merge in our server-side facts, so they can be used during compilation.
+ node.merge(@server_facts)
+ end
+
+ # Compile the actual configuration.
+ def compile(node)
+ # Ask the interpreter to compile the configuration.
+ str = "Compiled configuration for %s" % node.name
+ if node.environment
+ str += " in environment %s" % node.environment
+ end
+ config = nil
+
+ # LAK:FIXME This should log at :none when our client is
+ # local, since we don't want 'puppet' (vs. puppetmasterd) to
+ # log compile times.
+ benchmark(:notice, "Compiled configuration for %s" % node.name) do
+ begin
+ config = interpreter.compile(node)
+ rescue Puppet::Error => detail
+ if Puppet[:trace]
+ puts detail.backtrace
+ end
+ unless local?
+ Puppet.err detail.to_s
+ end
+ raise XMLRPC::FaultException.new(
+ 1, detail.to_s
+ )
+ end
+ end
+
+ return config
+ end
+
+ # Create our interpreter object.
+ def create_interpreter
+ args = {}
+
+ # Allow specification of a code snippet or of a file
+ if self.code
+ args[:Code] = self.code
+ end
+
+ # LAK:FIXME This needs to be handled somehow.
+ #if options.include?(:UseNodes)
+ # args[:UseNodes] = options[:UseNodes]
+ #elsif @local
+ # args[:UseNodes] = false
+ #end
+
+ return Puppet::Parser::Interpreter.new(args)
+ end
+
+ # Initialize our server fact hash; we add these to each client, and they
+ # won't change while we're running, so it's safe to cache the values.
+ def set_server_facts
+ @server_facts = {}
+
+ # Add our server version to the fact list
+ @server_facts["serverversion"] = Puppet.version.to_s
+
+ # And then add the server name and IP
+ {"servername" => "fqdn",
+ "serverip" => "ipaddress"
+ }.each do |var, fact|
+ if value = Facter.value(fact)
+ @server_facts[var] = value
+ else
+ Puppet.warning "Could not retrieve fact %s" % fact
+ end
+ end
+
+ if @server_facts["servername"].nil?
+ host = Facter.value(:hostname)
+ if domain = Facter.value(:domain)
+ @server_facts["servername"] = [host, domain].join(".")
+ else
+ @server_facts["servername"] = host
+ end
+ end
+ end
+
+ # Translate our configuration appropriately for sending back to a client.
+ # LAK:FIXME This method should probably be part of the protocol, but it
+ # shouldn't be here.
+ def translate(config)
+ if local?
+ config
+ else
+ CGI.escape(config.to_yaml(:UseBlock => true))
+ end
+ end
+
+ # Mark that the node has checked in. LAK:FIXME this needs to be moved into
+ # the Node class, or somewhere that's got abstract backends.
+ def update_node_check(node)
+ if Puppet.features.rails? and Puppet[:storeconfigs]
+ Puppet::Rails.connect
+
+ host = Puppet::Rails::Host.find_or_create_by_name(node.name)
+ host.last_freshcheck = Time.now
+ host.save
+ end
+ end
+end
diff --git a/lib/puppet/indirector/exec.rb b/lib/puppet/indirector/exec.rb
new file mode 100644
index 000000000..7e4ac8d18
--- /dev/null
+++ b/lib/puppet/indirector/exec.rb
@@ -0,0 +1,57 @@
+require 'puppet/indirector/terminus'
+require 'puppet/util'
+
+class Puppet::Indirector::Exec < Puppet::Indirector::Terminus
+ # Look for external node definitions.
+ def find(name)
+ # Run the command.
+ unless output = query(name)
+ return nil
+ end
+
+ # Translate the output to ruby.
+ return output
+ end
+
+ private
+
+ # Proxy the execution, so it's easier to test.
+ def execute(command)
+ Puppet::Util.execute(command)
+ end
+
+ # Call the external command and see if it returns our output.
+ def query(name)
+ external_command = command
+
+ # Make sure it's an arry
+ unless external_command.is_a?(Array)
+ raise Puppet::DevError, "Exec commands must be an array"
+ end
+
+ # Make sure it's fully qualified.
+ unless external_command[0][0] == File::SEPARATOR[0]
+ raise ArgumentError, "You must set the exec parameter to a fully qualified command"
+ end
+
+ # Add our name to it.
+ external_command << name
+ begin
+ output = execute(external_command)
+ rescue Puppet::ExecutionFailure => detail
+ if $?.exitstatus == 1
+ return nil
+ else
+ Puppet.err "Could not retrieve external node information for %s: %s" % [name, detail]
+ end
+ return nil
+ end
+
+ if output =~ /\A\s*\Z/ # all whitespace
+ Puppet.debug "Empty response for %s from exec %s terminus" % [name, self.name]
+ return nil
+ else
+ return output
+ end
+ end
+end
diff --git a/lib/puppet/indirector/exec/node.rb b/lib/puppet/indirector/exec/node.rb
new file mode 100644
index 000000000..033afe3f0
--- /dev/null
+++ b/lib/puppet/indirector/exec/node.rb
@@ -0,0 +1,50 @@
+require 'puppet/indirector/exec'
+
+class Puppet::Indirector::Exec::Node < Puppet::Indirector::Exec
+ desc "Call an external program to get node information."
+ include Puppet::Util
+
+ def command
+ command = Puppet[:external_nodes]
+ unless command != "none"
+ raise ArgumentError, "You must set the 'external_nodes' parameter to use the external node terminus"
+ end
+ command.split
+ end
+
+ # Look for external node definitions.
+ def find(name)
+ output = super or return nil
+
+ # Translate the output to ruby.
+ result = translate(name, output)
+
+ return create_node(name, result)
+ end
+
+ private
+
+ # Turn our outputted objects into a Puppet::Node instance.
+ def create_node(name, result)
+ node = Puppet::Node.new(name)
+ set = false
+ [:parameters, :classes].each do |param|
+ if value = result[param]
+ node.send(param.to_s + "=", value)
+ set = true
+ end
+ end
+
+ node.fact_merge
+ return node
+ end
+
+ # Translate the yaml string into Ruby objects.
+ def translate(name, output)
+ begin
+ YAML.load(output).inject({}) { |hash, data| hash[symbolize(data[0])] = data[1]; hash }
+ rescue => detail
+ raise Puppet::Error, "Could not load external node results for %s: %s" % [name, detail]
+ end
+ end
+end
diff --git a/lib/puppet/indirector/file.rb b/lib/puppet/indirector/file.rb
new file mode 100644
index 000000000..c2d36c46b
--- /dev/null
+++ b/lib/puppet/indirector/file.rb
@@ -0,0 +1,54 @@
+require 'puppet/indirector/terminus'
+
+# An empty terminus type, meant to just return empty objects.
+class Puppet::Indirector::File < Puppet::Indirector::Terminus
+ def destroy(file)
+ if respond_to?(:path)
+ path = path(file.name)
+ else
+ path = file.path
+ end
+ raise Puppet::Error.new("File %s does not exist; cannot destroy" % [file]) unless File.exist?(path)
+
+ begin
+ File.unlink(path)
+ rescue => detail
+ raise Puppet::Error, "Could not remove %s: %s" % [file, detail]
+ end
+ end
+
+ def find(name)
+ if respond_to?(:path)
+ path = path(name)
+ else
+ path = name
+ end
+
+ return nil unless File.exist?(path)
+
+ begin
+ content = File.read(path)
+ rescue => detail
+ raise Puppet::Error, "Could not retrieve path %s: %s" % [path, detail]
+ end
+
+ return model.new(content)
+ end
+
+ def save(file)
+ if respond_to?(:path)
+ path = path(file.name)
+ else
+ path = file.path
+ end
+ dir = File.dirname(path)
+
+ raise Puppet::Error.new("Cannot save %s; parent directory %s does not exist" % [file, dir]) unless File.directory?(dir)
+
+ begin
+ File.open(path, "w") { |f| f.print file.content }
+ rescue => detail
+ raise Puppet::Error, "Could not write %s: %s" % [file, detail]
+ end
+ end
+end
diff --git a/lib/puppet/indirector/file/checksum.rb b/lib/puppet/indirector/file/checksum.rb
new file mode 100644
index 000000000..2f0974ced
--- /dev/null
+++ b/lib/puppet/indirector/file/checksum.rb
@@ -0,0 +1,33 @@
+require 'puppet/checksum'
+require 'puppet/indirector/file'
+
+class Puppet::Indirector::File::Checksum < Puppet::Indirector::File
+ desc "Store files in a directory set based on their checksums."
+
+ def initialize
+ Puppet.settings.use(:filebucket)
+ end
+
+ def path(checksum)
+ path = []
+ path << Puppet[:bucketdir] # Start with the base directory
+ path << checksum[0..7].split("").join(File::SEPARATOR) # Add sets of directories based on the checksum
+ path << checksum # And the full checksum name itself
+ path << "contents" # And the actual file name
+
+ path.join(File::SEPARATOR)
+ end
+
+ def save(file)
+ path = File.dirname(path(file.name))
+
+ # Make the directories if necessary.
+ unless FileTest.directory?(path)
+ Puppet::Util.withumask(0007) do
+ FileUtils.mkdir_p(path)
+ end
+ end
+
+ super
+ end
+end
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
new file mode 100644
index 000000000..8afe0012d
--- /dev/null
+++ b/lib/puppet/indirector/indirection.rb
@@ -0,0 +1,91 @@
+# An actual indirection.
+class Puppet::Indirector::Indirection
+ @@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)
+ @@indirections.find { |i| i.name == name }
+ end
+
+ attr_accessor :name, :model
+
+ # Clear our cached list of termini.
+ # 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)
+ end
+
+ def initialize(model, name, options = {})
+ @model = model
+ @name = name
+ options.each do |name, value|
+ begin
+ send(name.to_s + "=", value)
+ rescue NoMethodError
+ raise ArgumentError, "%s is not a valid Indirection parameter" % name
+ end
+ end
+ @termini = {}
+ @terminus_types = {}
+ raise(ArgumentError, "Indirection %s is already defined" % @name) if @@indirections.find { |i| i.name == @name }
+ @@indirections << self
+ end
+
+ # Return the singleton terminus for this indirection.
+ def terminus(terminus_name = nil)
+ # Get the name of the terminus.
+ unless terminus_name
+ param_name = "%s_terminus" % self.name
+ if Puppet.settings.valid?(param_name)
+ terminus_name = Puppet.settings[param_name]
+ else
+ terminus_name = Puppet[:default_terminus]
+ end
+ unless terminus_name and terminus_name.to_s != ""
+ raise ArgumentError, "Invalid terminus name %s" % terminus_name.inspect
+ end
+ terminus_name = terminus_name.intern if terminus_name.is_a?(String)
+ end
+
+ return @termini[terminus_name] ||= make_terminus(terminus_name)
+ end
+
+ def find(*args)
+ terminus.find(*args)
+ end
+
+ def destroy(*args)
+ terminus.destroy(*args)
+ end
+
+ def search(*args)
+ terminus.search(*args)
+ end
+
+ # these become instance methods
+ def save(*args)
+ terminus.save(*args)
+ end
+
+ private
+
+ # Create a new terminus instance.
+ def make_terminus(name)
+ # Load our terminus class.
+ unless klass = Puppet::Indirector::Terminus.terminus_class(name, self.name)
+ raise ArgumentError, "Could not find terminus %s for indirection %s" % [name, self.name]
+ end
+ return klass.new
+ end
+end
diff --git a/lib/puppet/indirector/ldap.rb b/lib/puppet/indirector/ldap.rb
new file mode 100644
index 000000000..fb883def6
--- /dev/null
+++ b/lib/puppet/indirector/ldap.rb
@@ -0,0 +1,90 @@
+require 'puppet/indirector/terminus'
+
+class Puppet::Indirector::Ldap < Puppet::Indirector::Terminus
+ # Perform our ldap search and process the result.
+ def find(name)
+ # We have to use 'yield' here because the LDAP::Entry objects
+ # get destroyed outside the scope of the search, strangely.
+ ldapsearch(name) { |entry| return process(name, entry) }
+
+ # Return nil if we haven't found something.
+ return nil
+ end
+
+ # Process the found entry. We assume that we don't just want the
+ # ldap object.
+ def process(name, entry)
+ raise Puppet::DevError, "The 'process' method has not been overridden for the LDAP terminus for %s" % self.name
+ end
+
+ # Default to all attributes.
+ def search_attributes
+ nil
+ end
+
+ def search_base
+ Puppet[:ldapbase]
+ end
+
+ # The ldap search filter to use.
+ def search_filter(name)
+ raise Puppet::DevError, "No search string set for LDAP terminus for %s" % self.name
+ end
+
+ # Find the ldap node, return the class list and parent node specially,
+ # and everything else in a parameter hash.
+ def ldapsearch(node)
+ raise ArgumentError.new("You must pass a block to ldapsearch") unless block_given?
+
+ found = false
+ count = 0
+
+ begin
+ connection.search(search_base, 2, search_filter(node), search_attributes) do |entry|
+ found = true
+ yield entry
+ end
+ rescue => detail
+ if count == 0
+ # Try reconnecting to ldap if we get an exception and we haven't yet retried.
+ count += 1
+ @connection = nil
+ Puppet.warning "Retrying LDAP connection"
+ retry
+ else
+ raise Puppet::Error, "LDAP Search failed: %s" % detail
+ end
+ end
+
+ return found
+ end
+
+ private
+
+ # Create an ldap connection.
+ def connection
+ unless defined? @connection and @connection
+ unless Puppet.features.ldap?
+ raise Puppet::Error, "Could not set up LDAP Connection: Missing ruby/ldap libraries"
+ end
+ begin
+ if Puppet[:ldapssl]
+ @connection = LDAP::SSLConn.new(Puppet[:ldapserver], Puppet[:ldapport])
+ elsif Puppet[:ldaptls]
+ @connection = LDAP::SSLConn.new(
+ Puppet[:ldapserver], Puppet[:ldapport], true
+ )
+ else
+ @connection = LDAP::Conn.new(Puppet[:ldapserver], Puppet[:ldapport])
+ end
+ @connection.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
+ @connection.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON)
+ @connection.simple_bind(Puppet[:ldapuser], Puppet[:ldappassword])
+ rescue => detail
+ raise Puppet::Error, "Could not connect to LDAP: %s" % detail
+ end
+ end
+
+ return @connection
+ end
+end
diff --git a/lib/puppet/indirector/ldap/node.rb b/lib/puppet/indirector/ldap/node.rb
new file mode 100644
index 000000000..6f35b575c
--- /dev/null
+++ b/lib/puppet/indirector/ldap/node.rb
@@ -0,0 +1,115 @@
+require 'puppet/indirector/ldap'
+
+class Puppet::Indirector::Ldap::Node < Puppet::Indirector::Ldap
+ desc "Search in LDAP for node configuration information."
+
+ # The attributes that Puppet class information is stored in.
+ def class_attributes
+ Puppet[:ldapclassattrs].split(/\s*,\s*/)
+ end
+
+ # Look for our node in ldap.
+ def find(name)
+ return nil unless information = super
+ node = Puppet::Node.new(name)
+
+ parent_info = nil
+ parent = information[:parent]
+ parents = [name]
+ while parent
+ if parents.include?(parent)
+ raise ArgumentError, "Found loop in LDAP node parents; %s appears twice" % parent
+ end
+ parents << parent
+ ldapsearch(parent) do |entry|
+ parent_info = process(parent, entry)
+ end
+ information[:classes] += parent_info[:classes]
+ parent_info[:parameters].each do |param, value|
+ # Specifically test for whether it's set, so false values are handled
+ # correctly.
+ information[:parameters][param] = value unless information[:parameters].include?(param)
+ end
+
+ parent = parent_info[:parent]
+ end
+
+ node.classes = information[:classes].uniq unless information[:classes].empty?
+ node.parameters = information[:parameters] unless information[:parameters].empty?
+ node.fact_merge
+
+ return node
+ end
+
+ # The parent attribute, if we have one.
+ def parent_attribute
+ if pattr = Puppet[:ldapparentattr] and ! pattr.empty?
+ pattr
+ else
+ nil
+ end
+ end
+
+ # Process the found entry. We assume that we don't just want the
+ # ldap object.
+ def process(name, entry)
+ result = {}
+ if pattr = parent_attribute
+ if values = entry.vals(pattr)
+ if values.length > 1
+ raise Puppet::Error,
+ "Node %s has more than one parent: %s" % [name, values.inspect]
+ end
+ unless values.empty?
+ result[:parent] = values.shift
+ end
+ end
+ end
+
+ result[:classes] = []
+ class_attributes.each { |attr|
+ if values = entry.vals(attr)
+ values.each do |v| result[:classes] << v end
+ end
+ }
+
+ result[:parameters] = entry.to_hash.inject({}) do |hash, ary|
+ if ary[1].length == 1
+ hash[ary[0]] = ary[1].shift
+ else
+ hash[ary[0]] = ary[1]
+ end
+ hash
+ end
+
+ return result
+ end
+
+ # Default to all attributes.
+ def search_attributes
+ ldapattrs = Puppet[:ldapattrs]
+
+ # results in everything getting returned
+ return nil if ldapattrs == "all"
+
+ search_attrs = class_attributes + ldapattrs.split(/\s*,\s*/)
+
+ if pattr = parent_attribute
+ search_attrs << pattr
+ end
+
+ search_attrs
+ end
+
+ # The ldap search filter to use.
+ def search_filter(name)
+ filter = Puppet[:ldapstring]
+
+ if filter.include? "%s"
+ # Don't replace the string in-line, since that would hard-code our node
+ # info.
+ filter = filter.gsub('%s', name)
+ end
+ filter
+ end
+end
diff --git a/lib/puppet/indirector/memory.rb b/lib/puppet/indirector/memory.rb
new file mode 100644
index 000000000..5bfcec95d
--- /dev/null
+++ b/lib/puppet/indirector/memory.rb
@@ -0,0 +1,21 @@
+require 'puppet/indirector/terminus'
+
+# Manage a memory-cached list of instances.
+class Puppet::Indirector::Memory < Puppet::Indirector::Terminus
+ def initialize
+ @instances = {}
+ end
+
+ def destroy(instance)
+ raise ArgumentError.new("Could not find %s to destroy" % instance) unless @instances.include?(instance.name)
+ @instances.delete(instance.name)
+ end
+
+ def find(name)
+ @instances[name]
+ end
+
+ def save(instance)
+ @instances[instance.name] = instance
+ end
+end
diff --git a/lib/puppet/indirector/memory/node.rb b/lib/puppet/indirector/memory/node.rb
new file mode 100644
index 000000000..c5000b879
--- /dev/null
+++ b/lib/puppet/indirector/memory/node.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/memory'
+
+class Puppet::Indirector::Memory::Node < Puppet::Indirector::Memory
+ desc "Keep track of nodes in memory but nowhere else. This is used for
+ one-time compiles, such as what the stand-alone ``puppet`` does.
+ To use this terminus, you must load it with the data you want it
+ to contain."
+end
diff --git a/lib/puppet/indirector/null.rb b/lib/puppet/indirector/null.rb
new file mode 100644
index 000000000..db2b1db1c
--- /dev/null
+++ b/lib/puppet/indirector/null.rb
@@ -0,0 +1,9 @@
+require 'puppet/indirector/terminus'
+
+# An empty terminus type, meant to just return empty objects.
+class Puppet::Indirector::Null < Puppet::Indirector::Terminus
+ # Just return nothing.
+ def find(name)
+ indirection.model.new(name)
+ end
+end
diff --git a/lib/puppet/indirector/null/node.rb b/lib/puppet/indirector/null/node.rb
new file mode 100644
index 000000000..eb08f5697
--- /dev/null
+++ b/lib/puppet/indirector/null/node.rb
@@ -0,0 +1,14 @@
+require 'puppet/indirector/null'
+
+class Puppet::Indirector::Null::Node < Puppet::Indirector::Null
+ desc "Always return an empty node object. This is the node source you should
+ use when you don't have some other, functional source you want to use,
+ as the compiler will not work without this node information."
+
+ # Just return an empty node.
+ def find(name)
+ node = super
+ node.fact_merge
+ node
+ end
+end
diff --git a/lib/puppet/indirector/terminus.rb b/lib/puppet/indirector/terminus.rb
new file mode 100644
index 000000000..bcff08d79
--- /dev/null
+++ b/lib/puppet/indirector/terminus.rb
@@ -0,0 +1,117 @@
+require 'puppet/indirector'
+require 'puppet/indirector/indirection'
+require 'puppet/util/instance_loader'
+
+# A simple class that can function as the base class for indirected types.
+class Puppet::Indirector::Terminus
+ require 'puppet/util/docs'
+ extend Puppet::Util::Docs
+
+ class << self
+ include Puppet::Util::InstanceLoader
+
+ attr_accessor :name, :terminus_type
+ attr_reader :abstract_terminus, :indirection
+
+ # Are we an abstract terminus type, rather than an instance with an
+ # associated indirection?
+ def abstract_terminus?
+ abstract_terminus
+ end
+
+ # Look up the indirection if we were only provided a name.
+ def indirection=(name)
+ if name.is_a?(Puppet::Indirector::Indirection)
+ @indirection = name
+ elsif ind = Puppet::Indirector::Indirection.instance(name)
+ @indirection = ind
+ else
+ raise ArgumentError, "Could not find indirection instance %s" % name
+ end
+ end
+
+ # Register our subclass with the appropriate indirection.
+ # This follows the convention that our terminus is named after the
+ # indirection.
+ def inherited(subclass)
+ longname = subclass.to_s
+ if longname =~ /#<Class/
+ raise ArgumentError, "Terminus subclasses must have associated constants"
+ end
+ names = longname.split("::")
+ name = names.pop.downcase.intern
+
+ subclass.name = name
+
+ # Short-circuit the abstract types, which are those that directly subclass
+ # the Terminus class.
+ if self == Puppet::Indirector::Terminus
+ subclass.mark_as_abstract_terminus
+ return
+ end
+
+ # Set the terminus type to be the name of the abstract terminus type.
+ # Yay, class/instance confusion.
+ subclass.terminus_type = self.name
+
+ # This will throw an exception if the indirection instance cannot be found.
+ # Do this last, because it also registers the terminus type with the indirection,
+ # which needs the above information.
+ subclass.indirection = name
+
+ # And add this instance to the instance hash.
+ Puppet::Indirector::Terminus.register_terminus_class(subclass)
+ end
+
+ # Mark that this instance is abstract.
+ def mark_as_abstract_terminus
+ @abstract_terminus = true
+ end
+
+ def model
+ indirection.model
+ end
+
+ # Register a class, probably autoloaded.
+ def register_terminus_class(klass)
+ setup_instance_loading klass.terminus_type
+ instance_hash(klass.terminus_type)[klass.name] = klass
+ end
+
+ # Return a terminus by name, using the autoloader.
+ def terminus_class(type, name)
+ setup_instance_loading type
+ loaded_instance(type, name)
+ end
+
+ private
+
+ def setup_instance_loading(type)
+ unless instance_loading?(type)
+ instance_load type, "puppet/indirector/%s" % type
+ end
+ end
+ end
+
+ def initialize
+ if self.class.abstract_terminus?
+ raise Puppet::DevError, "Cannot create instances of abstract terminus types"
+ end
+ end
+
+ def terminus_type
+ self.class.terminus_type
+ end
+
+ def name
+ self.class.name
+ end
+
+ def model
+ self.class.model
+ end
+
+ def indirection
+ self.class.indirection
+ end
+end
diff --git a/lib/puppet/indirector/yaml.rb b/lib/puppet/indirector/yaml.rb
new file mode 100644
index 000000000..b9ea54f39
--- /dev/null
+++ b/lib/puppet/indirector/yaml.rb
@@ -0,0 +1,45 @@
+require 'puppet/indirector/terminus'
+
+# The base class for YAML indirection termini.
+class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
+ def initialize
+ # Make sure our base directory exists.
+ Puppet.settings.use(:yaml)
+ end
+
+ # Read a given name's file in and convert it from YAML.
+ def find(name)
+ raise ArgumentError.new("You must specify the name of the object to retrieve") unless name
+ file = path(name)
+ return nil unless FileTest.exist?(file)
+
+ begin
+ return YAML.load(File.read(file))
+ rescue => detail
+ raise Puppet::Error, "Could not read YAML data for %s(%s): %s" % [indirection.name, name, detail]
+ end
+ end
+
+ # Convert our object to YAML and store it to the disk.
+ def save(object)
+ raise ArgumentError.new("You can only save objects that respond to :name") unless object.respond_to?(:name)
+
+ file = path(object.name)
+
+ basedir = File.dirname(file)
+
+ # This is quite likely a bad idea, since we're not managing ownership or modes.
+ unless FileTest.exist?(basedir)
+ Dir.mkdir(basedir)
+ end
+
+ File.open(file, "w", 0660) { |f| f.print YAML.dump(object) }
+ end
+
+ private
+
+ # Return the path to a given node's file.
+ def path(name)
+ File.join(Puppet[:yamldir], self.name.to_s, name.to_s + ".yaml")
+ end
+end
diff --git a/lib/puppet/indirector/yaml/facts.rb b/lib/puppet/indirector/yaml/facts.rb
new file mode 100644
index 000000000..754b0d5a6
--- /dev/null
+++ b/lib/puppet/indirector/yaml/facts.rb
@@ -0,0 +1,5 @@
+require 'puppet/indirector/yaml'
+
+class Puppet::Indirector::Yaml::Facts < Puppet::Indirector::Yaml
+ desc "Store client facts as flat files, serialized using YAML."
+end
diff --git a/lib/puppet/metatype/closure.rb b/lib/puppet/metatype/closure.rb
index efb4712c6..727bc6884 100644
--- a/lib/puppet/metatype/closure.rb
+++ b/lib/puppet/metatype/closure.rb
@@ -1,19 +1,6 @@
class Puppet::Type
attr_writer :implicit
- def self.implicitcreate(hash)
- unless hash.include?(:implicit)
- hash[:implicit] = true
- end
- if obj = self.create(hash)
- obj.implicit = true
-
- return obj
- else
- return nil
- end
- end
-
# Is this type's name isomorphic with the object? That is, if the
# name conflicts, does it necessarily mean that the objects conflict?
# Defaults to true.
diff --git a/lib/puppet/metatype/container.rb b/lib/puppet/metatype/container.rb
index 7c44a7def..7bbccf8a0 100644
--- a/lib/puppet/metatype/container.rb
+++ b/lib/puppet/metatype/container.rb
@@ -14,14 +14,6 @@ class Puppet::Type
self.class.depthfirst?
end
- def parent=(parent)
- if self.parentof?(parent)
- devfail "%s[%s] is already the parent of %s[%s]" %
- [self.class.name, self.title, parent.class.name, parent.title]
- end
- @parent = parent
- end
-
# Add a hook for testing for recursion.
def parentof?(child)
if (self == child)
diff --git a/lib/puppet/metatype/instances.rb b/lib/puppet/metatype/instances.rb
index f6c2fdd34..4af230b28 100644
--- a/lib/puppet/metatype/instances.rb
+++ b/lib/puppet/metatype/instances.rb
@@ -79,8 +79,7 @@ class Puppet::Type
end
# Force users to call this, so that we can merge objects if
- # necessary. FIXME This method should be responsible for most of the
- # error handling.
+ # necessary.
def self.create(args)
# Don't modify the original hash; instead, create a duplicate and modify it.
# We have to dup and use the ! so that it stays a TransObject if it is
@@ -138,9 +137,8 @@ class Puppet::Type
# now pass through and create the new object
elsif implicit
- Puppet.notice "Ignoring implicit %s" % title
-
- return retobj
+ Puppet.debug "Ignoring implicit %s[%s]" % [self.name, title]
+ return nil
else
# If only one of the objects is being managed, then merge them
if retobj.managed?
@@ -308,8 +306,8 @@ class Puppet::Type
# Create the path for logging and such.
def pathbuilder
- if defined? @parent and @parent
- [@parent.pathbuilder, self.ref].flatten
+ if p = parent
+ [p.pathbuilder, self.ref].flatten
else
[self.ref]
end
diff --git a/lib/puppet/module.rb b/lib/puppet/module.rb
index 924958bbe..dc30d8167 100644
--- a/lib/puppet/module.rb
+++ b/lib/puppet/module.rb
@@ -9,7 +9,7 @@ class Puppet::Module
# parameter. Only consider paths that are absolute and existing
# directories
def self.modulepath(environment = nil)
- dirs = Puppet.config.value(:modulepath, environment).split(":")
+ dirs = Puppet.settings.value(:modulepath, environment).split(":")
if ENV["PUPPETLIB"]
dirs = ENV["PUPPETLIB"].split(":") + dirs
else
@@ -61,7 +61,7 @@ class Puppet::Module
if mod
return mod.template(file)
else
- return File.join(Puppet.config.value(:templatedir, environment), template)
+ return File.join(Puppet.settings.value(:templatedir, environment), template)
end
end
diff --git a/lib/puppet/network/client/ca.rb b/lib/puppet/network/client/ca.rb
index 412c9c59f..46fb9f51f 100644
--- a/lib/puppet/network/client/ca.rb
+++ b/lib/puppet/network/client/ca.rb
@@ -14,9 +14,9 @@ class Puppet::Network::Client::CA < Puppet::Network::Client
end
# This client is really only able to request certificates for the
- # current host. It uses the Puppet.config settings to figure everything out.
+ # current host. It uses the Puppet.settings settings to figure everything out.
def request_cert
- Puppet.config.use(:main, :ssl)
+ Puppet.settings.use(:main, :ssl)
if cert = read_cert
return cert
@@ -49,8 +49,8 @@ class Puppet::Network::Client::CA < Puppet::Network::Client
end
# Only write the cert out if it passes validating.
- Puppet.config.write(:hostcert) do |f| f.print cert end
- Puppet.config.write(:localcacert) do |f| f.print cacert end
+ Puppet.settings.write(:hostcert) do |f| f.print cert end
+ Puppet.settings.write(:localcacert) do |f| f.print cacert end
return @cert
end
diff --git a/lib/puppet/network/client/master.rb b/lib/puppet/network/client/master.rb
index c6d7cd75d..f950a6059 100644
--- a/lib/puppet/network/client/master.rb
+++ b/lib/puppet/network/client/master.rb
@@ -7,7 +7,7 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
@@sync = Sync.new
end
- attr_accessor :objects
+ attr_accessor :configuration
attr_reader :compile_time
class << self
@@ -46,51 +46,7 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
# Return the list of dynamic facts as an array of symbols
def self.dynamic_facts
- Puppet.config[:dynamicfacts].split(/\s*,\s*/).collect { |fact| fact.downcase }
- end
-
- # This method actually applies the configuration.
- def apply(tags = nil, ignoreschedules = false)
- unless defined? @objects
- raise Puppet::Error, "Cannot apply; objects not defined"
- end
-
- transaction = @objects.evaluate
-
- if tags
- transaction.tags = tags
- end
-
- if ignoreschedules
- transaction.ignoreschedules = true
- end
-
- transaction.addtimes :config_retrieval => @configtime
-
- begin
- transaction.evaluate
- rescue Puppet::Error => detail
- Puppet.err "Could not apply complete configuration: %s" %
- detail
- rescue => detail
- Puppet.err "Got an uncaught exception of type %s: %s" %
- [detail.class, detail]
- if Puppet[:trace]
- puts detail.backtrace
- end
- ensure
- Puppet::Util::Storage.store
- end
-
- if Puppet[:report] or Puppet[:summarize]
- report(transaction)
- end
-
- return transaction
- ensure
- if defined? transaction and transaction
- transaction.cleanup
- end
+ Puppet.settings[:dynamicfacts].split(/\s*,\s*/).collect { |fact| fact.downcase }
end
# Cache the config
@@ -111,10 +67,10 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
end
def clear
- @objects.remove(true) if @objects
+ @configuration.clear(true) if @configuration
Puppet::Type.allclear
mkdefault_objects
- @objects = nil
+ @configuration = nil
end
# Initialize and load storage
@@ -183,15 +139,15 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
facts = self.class.facts
end
- if self.objects or FileTest.exists?(self.cachefile)
+ if self.configuration or FileTest.exists?(self.cachefile)
if self.fresh?(facts)
Puppet.info "Config is up to date"
- if self.objects
+ if self.configuration
return
end
if oldtext = self.retrievecache
begin
- @objects = YAML.load(oldtext).to_type
+ @configuration = YAML.load(oldtext).to_configuration
rescue => detail
Puppet.warning "Could not load cached configuration: %s" % detail
end
@@ -213,7 +169,7 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
end
unless objects = get_actual_config(facts)
- @objects = nil
+ @configuration = nil
return
end
@@ -225,21 +181,21 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
self.setclasses(objects.classes)
# Clear all existing objects, so we can recreate our stack.
- if self.objects
+ if self.configuration
clear()
end
- # Now convert the objects to real Puppet objects
- @objects = objects.to_type
+ # Now convert the objects to a puppet configuration graph.
+ @configuration = objects.to_configuration
- if @objects.nil?
+ if @configuration.nil?
raise Puppet::Error, "Configuration could not be processed"
end
- # and perform any necessary final actions before we evaluate.
- @objects.finalize
+ # Keep the state database up to date.
+ @configuration.host_config = true
- return @objects
+ return @configuration
end
# A simple proxy method, so it's easy to test.
@@ -249,12 +205,9 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
# Just so we can specify that we are "the" instance.
def initialize(*args)
- Puppet.config.use(:main, :ssl, :puppetd)
+ Puppet.settings.use(:main, :ssl, :puppetd)
super
- # This might be nil
- @configtime = 0
-
self.class.instance = self
@running = false
@@ -297,7 +250,9 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
end
# The code that actually runs the configuration.
- def run(tags = nil, ignoreschedules = false)
+ # This just passes any options on to the configuration,
+ # which accepts :tags and :ignoreschedules.
+ def run(options = {})
got_lock = false
splay
Puppet::Util.sync(:puppetrun).synchronize(Sync::EX) do
@@ -307,19 +262,20 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
else
got_lock = true
begin
- @configtime = thinmark do
+ duration = thinmark do
self.getconfig
end
rescue => detail
Puppet.err "Could not retrieve configuration: %s" % detail
end
- if defined? @objects and @objects
+ if defined? @configuration and @configuration
+ @configuration.retrieval_duration = duration
unless @local
Puppet.notice "Starting configuration run"
end
benchmark(:notice, "Finished configuration run") do
- self.apply(tags, ignoreschedules)
+ @configuration.apply(options)
end
end
end
@@ -366,9 +322,6 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
# Download files from the remote server, returning a list of all
# changed files.
def self.download(args)
- objects = Puppet::Type.type(:component).create(
- :name => "#{args[:name]}_collector"
- )
hash = {
:path => args[:dest],
:recurse => true,
@@ -383,18 +336,23 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
if args[:ignore]
hash[:ignore] = args[:ignore].split(/\s+/)
end
- objects.push Puppet::Type.type(:file).create(hash)
+ downconfig = Puppet::Node::Configuration.new("downloading")
+ downconfig.add_resource Puppet::Type.type(:file).create(hash)
Puppet.info "Retrieving #{args[:name]}s"
noop = Puppet[:noop]
Puppet[:noop] = false
+ files = []
begin
- trans = objects.evaluate
- trans.ignoretags = true
Timeout::timeout(self.timeout) do
- trans.evaluate
+ downconfig.apply do |trans|
+ trans.changed?.find_all do |resource|
+ yield resource if block_given?
+ files << resource[:path]
+ end
+ end
end
rescue Puppet::Error, Timeout::Error => detail
if Puppet[:debug]
@@ -403,18 +361,10 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
Puppet.err "Could not retrieve #{args[:name]}s: %s" % detail
end
- # Now source all of the changed objects, but only source those
- # that are top-level.
- files = []
- trans.changed?.find_all do |object|
- yield object if block_given?
- files << object[:path]
- end
- trans.cleanup
-
# Now clean up after ourselves
- objects.remove
- files
+ downconfig.clear
+
+ return files
ensure
# I can't imagine why this is necessary, but apparently at last one person has had problems with noop
# being nil here.
@@ -427,21 +377,21 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
# Retrieve facts from the central server.
def self.getfacts
- # Clear all existing definitions.
- Facter.clear
# Download the new facts
path = Puppet[:factpath].split(":")
files = []
download(:dest => Puppet[:factdest], :source => Puppet[:factsource],
- :ignore => Puppet[:factsignore], :name => "fact") do |object|
-
- next unless path.include?(::File.dirname(object[:path]))
+ :ignore => Puppet[:factsignore], :name => "fact") do |resource|
- files << object[:path]
+ next unless path.include?(::File.dirname(resource[:path]))
+ files << resource[:path]
end
ensure
+ # Clear all existing definitions.
+ Facter.clear
+
# Reload everything.
if Facter.respond_to? :loadfacts
Facter.loadfacts
@@ -461,20 +411,20 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
# changed plugins, because Puppet::Type loads plugins on demand.
def self.getplugins
download(:dest => Puppet[:plugindest], :source => Puppet[:pluginsource],
- :ignore => Puppet[:pluginsignore], :name => "plugin") do |object|
+ :ignore => Puppet[:pluginsignore], :name => "plugin") do |resource|
- next if FileTest.directory?(object[:path])
- path = object[:path].sub(Puppet[:plugindest], '').sub(/^\/+/, '')
+ next if FileTest.directory?(resource[:path])
+ path = resource[:path].sub(Puppet[:plugindest], '').sub(/^\/+/, '')
unless Puppet::Util::Autoload.loaded?(path)
next
end
begin
Puppet.info "Reloading downloaded file %s" % path
- load object[:path]
+ load resource[:path]
rescue => detail
Puppet.warning "Could not reload downloaded file %s: %s" %
- [object[:path], detail]
+ [resource[:path], detail]
end
end
end
@@ -517,42 +467,6 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
return timeout
end
-
- # Send off the transaction report.
- def report(transaction)
- begin
- report = transaction.generate_report()
- rescue => detail
- Puppet.err "Could not generate report: %s" % detail
- return
- end
-
- if Puppet[:rrdgraph] == true
- report.graph()
- end
-
- if Puppet[:summarize]
- puts report.summary
- end
-
- if Puppet[:report]
- begin
- reportclient().report(report)
- rescue => detail
- Puppet.err "Reporting failed: %s" % detail
- end
- end
- end
-
- def reportclient
- unless defined? @reportclient
- @reportclient = Puppet::Network::Client.report.new(
- :Server => Puppet[:reportserver]
- )
- end
-
- @reportclient
- end
loadfacts()
@@ -633,7 +547,7 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
Puppet.err "Could not retrieve configuration: %s" % detail
unless Puppet[:usecacheonfailure]
- @objects = nil
+ @configuration = nil
Puppet.warning "Not using cache on failed configuration"
return
end
diff --git a/lib/puppet/network/handler/ca.rb b/lib/puppet/network/handler/ca.rb
index 422b21ae1..052eb5c19 100644
--- a/lib/puppet/network/handler/ca.rb
+++ b/lib/puppet/network/handler/ca.rb
@@ -60,7 +60,7 @@ class Puppet::Network::Handler
end
def initialize(hash = {})
- Puppet.config.use(:main, :ssl, :ca)
+ Puppet.settings.use(:main, :ssl, :ca)
if hash.include? :autosign
@autosign = hash[:autosign]
end
diff --git a/lib/puppet/network/handler/configuration.rb b/lib/puppet/network/handler/configuration.rb
index 2c72d3d2b..2df1b3ab4 100644
--- a/lib/puppet/network/handler/configuration.rb
+++ b/lib/puppet/network/handler/configuration.rb
@@ -30,7 +30,7 @@ class Puppet::Network::Handler
# Note that this is reasonable, because either their node source should actually
# know about the node, or they should be using the ``none`` node source, which
# will always return data.
- unless node = node_handler.details(key)
+ unless node = Puppet::Node.search(key)
raise Puppet::Error, "Could not find node '%s'" % key
end
@@ -64,7 +64,7 @@ class Puppet::Network::Handler
# Return the configuration version.
def version(client = nil, clientip = nil)
- if client and node = node_handler.details(client)
+ if client and node = Puppet::Node.search(client)
update_node_check(node)
return interpreter.configuration_version(node)
else
@@ -79,7 +79,7 @@ class Puppet::Network::Handler
# Add any extra data necessary to the node.
def add_node_data(node)
# Merge in our server-side facts, so they can be used during compilation.
- node.fact_merge(@server_facts)
+ node.merge(@server_facts)
# Add any specified classes to the node's class list.
if classes = @options[:Classes]
@@ -159,14 +159,6 @@ class Puppet::Network::Handler
@interpreter
end
- # Create a node handler instance for looking up our nodes.
- def node_handler
- unless defined?(@node_handler)
- @node_handler = Puppet::Network::Handler.handler(:node).create
- end
- @node_handler
- end
-
# Initialize our server fact hash; we add these to each client, and they
# won't change while we're running, so it's safe to cache the values.
def set_server_facts
diff --git a/lib/puppet/network/handler/facts.rb b/lib/puppet/network/handler/facts.rb
deleted file mode 100755
index 4767e8be4..000000000
--- a/lib/puppet/network/handler/facts.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require 'yaml'
-require 'puppet/util/fact_store'
-
-class Puppet::Network::Handler
- # Receive logs from remote hosts.
- class Facts < Handler
- desc "An interface for storing and retrieving client facts. Currently only
- used internally by Puppet."
-
- @interface = XMLRPC::Service::Interface.new("facts") { |iface|
- iface.add_method("void set(string, string)")
- iface.add_method("string get(string)")
- iface.add_method("integer store_date(string)")
- }
-
- def initialize(hash = {})
- super
-
- backend = Puppet[:factstore]
-
- unless klass = Puppet::Util::FactStore.store(backend)
- raise Puppet::Error, "Could not find fact store %s" % backend
- end
-
- @backend = klass.new
- end
-
- # Get the facts from our back end.
- def get(node)
- if facts = @backend.get(node)
- return strip_internal(facts)
- else
- return nil
- end
- end
-
- # Set the facts in the backend.
- def set(node, facts)
- @backend.set(node, add_internal(facts))
- nil
- end
-
- # Retrieve a client's storage date.
- def store_date(node)
- if facts = get(node)
- facts[:_puppet_timestamp].to_i
- else
- nil
- end
- end
-
- private
-
- # Add internal data to the facts for storage.
- def add_internal(facts)
- facts = facts.dup
- facts[:_puppet_timestamp] = Time.now
- facts
- end
-
- # Strip out that internal data.
- def strip_internal(facts)
- facts = facts.dup
- facts.find_all { |name, value| name.to_s =~ /^_puppet_/ }.each { |name, value| facts.delete(name) }
- facts
- end
- end
-end
diff --git a/lib/puppet/network/handler/filebucket.rb b/lib/puppet/network/handler/filebucket.rb
index bb6a0e6d3..1bf8da854 100755
--- a/lib/puppet/network/handler/filebucket.rb
+++ b/lib/puppet/network/handler/filebucket.rb
@@ -64,7 +64,7 @@ class Puppet::Network::Handler # :nodoc:
end
end
- Puppet.config.use(:filebucket)
+ Puppet.settings.use(:filebucket)
@name = "Filebucket[#{@path}]"
end
diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb
index a429412d2..ae0e6553d 100755
--- a/lib/puppet/network/handler/fileserver.rb
+++ b/lib/puppet/network/handler/fileserver.rb
@@ -243,7 +243,10 @@ class Puppet::Network::Handler
# the modules.
def modules_mount(module_name, client)
# Find our environment, if we have one.
- if node = node_handler.details(client || Facter.value("hostname"))
+ unless hostname = (client || Facter.value("hostname"))
+ raise ArgumentError, "Could not find hostname"
+ end
+ if node = Puppet::Node.find(hostname)
env = node.environment
else
env = nil
@@ -258,14 +261,6 @@ class Puppet::Network::Handler
end
end
- # Create a node handler instance for looking up our nodes.
- def node_handler
- unless defined?(@node_handler)
- @node_handler = Puppet::Network::Handler.handler(:node).create
- end
- @node_handler
- end
-
# Read the configuration file.
def readconfig(check = true)
return if @noreadconfig
@@ -455,7 +450,7 @@ class Puppet::Network::Handler
def getfileobject(dir, links)
unless FileTest.exists?(dir)
- self.notice "File source %s does not exist" % dir
+ self.debug "File source %s does not exist" % dir
return nil
end
diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb
index c8db277ba..030950c61 100644
--- a/lib/puppet/network/handler/master.rb
+++ b/lib/puppet/network/handler/master.rb
@@ -74,7 +74,7 @@ class Puppet::Network::Handler
client, clientip = clientname(client, clientip, facts)
# Pass the facts to the fact handler
- fact_handler.set(client, facts)
+ Puppet::Node::Facts.new(client, facts).save
# And get the configuration from the config handler
begin
@@ -134,13 +134,6 @@ class Puppet::Network::Handler
return facts
end
- def fact_handler
- unless defined? @fact_handler
- @fact_handler = Puppet::Network::Handler.handler(:facts).new :local => local?
- end
- @fact_handler
- end
-
# Translate our configuration appropriately for sending back to a client.
def translate(config)
if local?
diff --git a/lib/puppet/network/handler/node.rb b/lib/puppet/network/handler/node.rb
deleted file mode 100644
index c6ccc2eb6..000000000
--- a/lib/puppet/network/handler/node.rb
+++ /dev/null
@@ -1,242 +0,0 @@
-# Created by Luke A. Kanies on 2007-08-13.
-# Copyright (c) 2007. All rights reserved.
-
-require 'puppet/util'
-require 'puppet/node'
-require 'puppet/util/classgen'
-require 'puppet/util/instance_loader'
-
-# Look up a node, along with all the details about it.
-class Puppet::Network::Handler::Node < Puppet::Network::Handler
- desc "Retrieve information about nodes."
-
- # Create a singleton node handler
- def self.create
- unless @handler
- @handler = new
- end
- @handler
- end
-
- # Add a new node source.
- def self.newnode_source(name, options = {}, &block)
- name = symbolize(name)
-
- fact_merge = options[:fact_merge]
- mod = genmodule(name, :extend => SourceBase, :hash => instance_hash(:node_source), :block => block)
- mod.send(:define_method, :fact_merge?) do
- fact_merge
- end
- mod
- end
-
- # Collect the docs for all of our node sources.
- def self.node_source_docs
- docs = ""
-
- # Use this method so they all get loaded
- instance_loader(:node_source).loadall
- loaded_instances(:node_source).sort { |a,b| a.to_s <=> b.to_s }.each do |name|
- mod = self.node_source(name)
- docs += "%s\n%s\n" % [name, "-" * name.to_s.length]
-
- docs += Puppet::Util::Docs.scrub(mod.doc) + "\n\n"
- end
-
- docs
- end
-
- # List each of the node sources.
- def self.node_sources
- instance_loader(:node_source).loadall
- loaded_instances(:node_source)
- end
-
- # Remove a defined node source; basically only used for testing.
- def self.rm_node_source(name)
- rmclass(name, :hash => instance_hash(:node_source))
- end
-
- extend Puppet::Util::ClassGen
- extend Puppet::Util::InstanceLoader
-
- # A simple base module we can use for modifying how our node sources work.
- module SourceBase
- include Puppet::Util::Docs
- end
-
- @interface = XMLRPC::Service::Interface.new("nodes") { |iface|
- iface.add_method("string details(key)")
- iface.add_method("string parameters(key)")
- iface.add_method("string environment(key)")
- iface.add_method("string classes(key)")
- }
-
- # Set up autoloading and retrieving of reports.
- instance_load :node_source, 'puppet/node_source'
-
- attr_reader :source
-
- # Return a given node's classes.
- def classes(key)
- if node = details(key)
- node.classes
- else
- nil
- end
- end
-
- # Return an entire node configuration. This uses the 'nodesearch' method
- # defined in the node_source to look for the node.
- def details(key, client = nil, clientip = nil)
- return nil unless key
- if node = cached?(key)
- return node
- end
- facts = node_facts(key)
- node = nil
- names = node_names(key, facts)
- names.each do |name|
- name = name.to_s if name.is_a?(Symbol)
- if node = nodesearch(name) and @source != "none"
- Puppet.info "Found %s in %s" % [name, @source]
- break
- end
- end
-
- # If they made it this far, we haven't found anything, so look for a
- # default node.
- unless node or names.include?("default")
- if node = nodesearch("default")
- Puppet.notice "Using default node for %s" % key
- end
- end
-
- if node
- node.source = @source
- node.names = names
-
- # Merge the facts into the parameters.
- if fact_merge?
- node.fact_merge(facts)
- end
-
- cache(node)
-
- return node
- else
- return nil
- end
- end
-
- # Return a given node's environment.
- def environment(key, client = nil, clientip = nil)
- if node = details(key)
- node.environment
- else
- nil
- end
- end
-
- # Create our node lookup tool.
- def initialize(hash = {})
- @source = hash[:Source] || Puppet[:node_source]
-
- unless mod = self.class.node_source(@source)
- raise ArgumentError, "Unknown node source '%s'" % @source
- end
-
- extend(mod)
-
- super
-
- # We cache node info for speed
- @node_cache = {}
- end
-
- # Try to retrieve a given node's parameters.
- def parameters(key, client = nil, clientip = nil)
- if node = details(key)
- node.parameters
- else
- nil
- end
- end
-
- private
-
- # Store the node to make things a bit faster.
- def cache(node)
- @node_cache[node.name] = node
- end
-
- # If the node is cached, return it.
- def cached?(name)
- # Don't use cache when the filetimeout is set to 0
- return false if [0, "0"].include?(Puppet[:filetimeout])
-
- if node = @node_cache[name] and Time.now - node.time < Puppet[:filetimeout]
- return node
- else
- return false
- end
- end
-
- # Create/cache a fact handler.
- def fact_handler
- unless defined?(@fact_handler)
- @fact_handler = Puppet::Network::Handler.handler(:facts).new
- end
- @fact_handler
- end
-
- # Short-hand for creating a new node, so the node sources don't need to
- # specify the constant.
- def newnode(options)
- Puppet::Node.new(options)
- end
-
- # Look up the node facts from our fact handler.
- def node_facts(key)
- if facts = fact_handler.get(key)
- facts
- else
- {}
- end
- end
-
- # Calculate the list of node names we should use for looking
- # up our node.
- def node_names(key, facts = nil)
- facts ||= node_facts(key)
- names = []
-
- if hostname = facts["hostname"]
- unless hostname == key
- names << hostname
- end
- else
- hostname = key
- end
-
- if fqdn = facts["fqdn"]
- hostname = fqdn
- names << fqdn
- end
-
- # Make sure both the fqdn and the short name of the
- # host can be used in the manifest
- if hostname =~ /\./
- names << hostname.sub(/\..+/,'')
- elsif domain = facts['domain']
- names << hostname + "." + domain
- end
-
- # Sort the names inversely by name length.
- names.sort! { |a,b| b.length <=> a.length }
-
- # And make sure the key is first, since that's the most
- # likely usage.
- ([key] + names).uniq
- end
-end
diff --git a/lib/puppet/network/handler/report.rb b/lib/puppet/network/handler/report.rb
index 81aee6a3c..62e9cfdec 100755
--- a/lib/puppet/network/handler/report.rb
+++ b/lib/puppet/network/handler/report.rb
@@ -71,8 +71,8 @@ class Puppet::Network::Handler
def initialize(*args)
super
- Puppet.config.use(:reporting)
- Puppet.config.use(:metrics)
+ Puppet.settings.use(:reporting)
+ Puppet.settings.use(:metrics)
end
# Accept a report from a client.
diff --git a/lib/puppet/network/handler/resource.rb b/lib/puppet/network/handler/resource.rb
index ac29dce53..7709b85fe 100755
--- a/lib/puppet/network/handler/resource.rb
+++ b/lib/puppet/network/handler/resource.rb
@@ -39,21 +39,14 @@ class Puppet::Network::Handler
end
end
- component = bucket.to_type
-
- # Create a client, but specify the remote machine as the server
- # because the class requires it, even though it's unused
- client = Puppet::Network::Client.client(:Master).new(:Master => client||"localhost")
-
- # Set the objects
- client.objects = component
+ config = bucket.to_configuration
# And then apply the configuration. This way we're reusing all
# the code in there. It should probably just be separated out, though.
- transaction = client.apply
+ transaction = config.apply
# And then clean up
- component.remove
+ config.clear(true)
# It'd be nice to return some kind of report, but... at this point
# we have no such facility.
diff --git a/lib/puppet/network/handler/runner.rb b/lib/puppet/network/handler/runner.rb
index c41e83608..4b9ccab75 100755
--- a/lib/puppet/network/handler/runner.rb
+++ b/lib/puppet/network/handler/runner.rb
@@ -50,10 +50,10 @@ class Puppet::Network::Handler
# And then we need to tell it to run, with this extra info.
if fg
- master.run(tags, ignoreschedules)
+ master.run(:tags => tags, :ignoreschedules => ignoreschedules)
else
Puppet.newthread do
- master.run(tags, ignoreschedules)
+ master.run(:tags => tags, :ignoreschedules => ignoreschedules)
end
end
diff --git a/lib/puppet/network/server/webrick.rb b/lib/puppet/network/server/webrick.rb
index 3af0cfd3f..f24411ab3 100644
--- a/lib/puppet/network/server/webrick.rb
+++ b/lib/puppet/network/server/webrick.rb
@@ -48,7 +48,7 @@ module Puppet
# yuck; separate http logs
file = nil
- Puppet.config.use(:main, :ssl, Puppet[:name])
+ Puppet.settings.use(:main, :ssl, Puppet[:name])
if Puppet[:name] == "puppetmasterd"
file = Puppet[:masterhttplog]
else
diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb
index 2d3ac712e..d71bd507e 100644
--- a/lib/puppet/node.rb
+++ b/lib/puppet/node.rb
@@ -1,10 +1,27 @@
+require 'puppet/indirector'
+
# A simplistic class for managing the node information itself.
class Puppet::Node
+ require 'puppet/node/facts'
+
+ # Set up indirection, so that nodes can be looked for in
+ # the node sources.
+ extend Puppet::Indirector
+
+ # Use the node source as the indirection terminus.
+ indirects :node
+
+ # Add the node-searching methods. This is what people will actually
+ # interact with that will find the node with the list of names or
+ # will search for a default node.
+ require 'puppet/node/searching'
+ extend Puppet::Node::Searching
+
attr_accessor :name, :classes, :parameters, :source, :ipaddress, :names
attr_reader :time
attr_writer :environment
- # Do not return environments tha are empty string, and use
+ # Do not return environments that are the empty string, and use
# explicitly set environments, then facts, then a central env
# value.
def environment
@@ -21,6 +38,9 @@ class Puppet::Node
end
def initialize(name, options = {})
+ unless name
+ raise ArgumentError, "Node names cannot be nil"
+ end
@name = name
# Provide a default value.
@@ -52,9 +72,15 @@ class Puppet::Node
end
# Merge the node facts with parameters from the node source.
- # This is only called if the node source has 'fact_merge' set to true.
- def fact_merge(facts)
- facts.each do |name, value|
+ def fact_merge
+ if facts = Puppet::Node::Facts.find(name)
+ merge(facts.values)
+ end
+ end
+
+ # Merge any random parameters into our parameter list.
+ def merge(params)
+ params.each do |name, value|
@parameters[name] = value unless @parameters.include?(name)
end
end
diff --git a/lib/puppet/node/configuration.rb b/lib/puppet/node/configuration.rb
index 4f93fdbe5..53f63d003 100644
--- a/lib/puppet/node/configuration.rb
+++ b/lib/puppet/node/configuration.rb
@@ -1,13 +1,34 @@
+require 'puppet/indirector'
require 'puppet/external/gratr/digraph'
# This class models a node configuration. It is the thing
# meant to be passed from server to client, and it contains all
# of the information in the configuration, including the resources
# and the relationships between them.
-class Puppet::Node::Configuration < GRATR::Digraph
- attr_accessor :name, :version
+class Puppet::Node::Configuration < Puppet::PGraph
+ extend Puppet::Indirector
+ indirects :configuration
+
+ # The host name this is a configuration for.
+ attr_accessor :name
+
+ # The configuration version. Used for testing whether a configuration
+ # is up to date.
+ attr_accessor :version
+
+ # How long this configuration took to retrieve. Used for reporting stats.
+ attr_accessor :retrieval_duration
+
+ # How we should extract the configuration for sending to the client.
attr_reader :extraction_format
+ # Whether this is a host configuration, which behaves very differently.
+ # In particular, reports are sent, graphs are made, and state is
+ # stored in the state database. If this is set incorrectly, then you often
+ # end up in infinite loops, because configurations are used to make things
+ # that the host configuration needs.
+ attr_accessor :host_config
+
# Add classes to our class list.
def add_class(*classes)
classes.each do |klass|
@@ -18,10 +39,133 @@ class Puppet::Node::Configuration < GRATR::Digraph
tag(*classes)
end
+ # Add one or more resources to our graph and to our resource table.
+ def add_resource(*resources)
+ resources.each do |resource|
+ unless resource.respond_to?(:ref)
+ raise ArgumentError, "Can only add objects that respond to :ref"
+ end
+
+ ref = resource.ref
+ if @resource_table.include?(ref)
+ raise ArgumentError, "Resource %s is already defined" % ref
+ else
+ @resource_table[ref] = resource
+ end
+ resource.configuration = self
+ add_vertex!(resource)
+ end
+ end
+
+ # Apply our configuration to the local host. Valid options
+ # are:
+ # :tags - set the tags that restrict what resources run
+ # during the transaction
+ # :ignoreschedules - tell the transaction to ignore schedules
+ # when determining the resources to run
+ def apply(options = {})
+ @applying = true
+
+ Puppet::Util::Storage.load if host_config?
+ transaction = Puppet::Transaction.new(self)
+
+ transaction.tags = options[:tags] if options[:tags]
+ transaction.ignoreschedules = true if options[:ignoreschedules]
+
+ transaction.addtimes :config_retrieval => @retrieval_duration
+
+ begin
+ transaction.evaluate
+ rescue Puppet::Error => detail
+ Puppet.err "Could not apply complete configuration: %s" % detail
+ rescue => detail
+ if Puppet[:trace]
+ puts detail.backtrace
+ end
+ Puppet.err "Got an uncaught exception of type %s: %s" % [detail.class, detail]
+ ensure
+ # Don't try to store state unless we're a host config
+ # too recursive.
+ Puppet::Util::Storage.store if host_config?
+ end
+
+ if block_given?
+ yield transaction
+ end
+
+ if host_config and (Puppet[:report] or Puppet[:summarize])
+ transaction.send_report
+ end
+
+ return transaction
+ ensure
+ @applying = false
+ cleanup()
+ if defined? transaction and transaction
+ transaction.cleanup
+ end
+ end
+
+ # Are we in the middle of applying the configuration?
+ def applying?
+ @applying
+ end
+
+ def clear(remove_resources = true)
+ super()
+ # We have to do this so that the resources clean themselves up.
+ @resource_table.values.each { |resource| resource.remove } if remove_resources
+ @resource_table.clear
+
+ if defined?(@relationship_graph) and @relationship_graph
+ @relationship_graph.clear(false)
+ @relationship_graph = nil
+ end
+ end
+
def classes
@classes.dup
end
+ # Create an implicit resource, meaning that it will lose out
+ # to any explicitly defined resources. This method often returns
+ # nil.
+ # The quirk of this method is that it's not possible to create
+ # an implicit resource before an explicit resource of the same name,
+ # because all explicit resources are created before any generate()
+ # methods are called on the individual resources. Thus, this
+ # method can safely just check if an explicit resource already exists
+ # and toss this implicit resource if so.
+ def create_implicit_resource(type, options)
+ unless options.include?(:implicit)
+ options[:implicit] = true
+ end
+
+ # This will return nil if an equivalent explicit resource already exists.
+ # When resource classes no longer retain references to resource instances,
+ # this will need to be modified to catch that conflict and discard
+ # implicit resources.
+ if resource = create_resource(type, options)
+ resource.implicit = true
+
+ return resource
+ else
+ return nil
+ end
+ end
+
+ # Create a new resource and register it in the configuration.
+ def create_resource(type, options)
+ unless klass = Puppet::Type.type(type)
+ raise ArgumentError, "Unknown resource type %s" % type
+ end
+ return unless resource = klass.create(options)
+
+ @transient_resources << resource if applying?
+ add_resource(resource)
+ resource
+ end
+
# Make sure we support the requested extraction format.
def extraction_format=(value)
unless respond_to?("extract_to_%s" % value)
@@ -94,12 +238,101 @@ class Puppet::Node::Configuration < GRATR::Digraph
return result
end
- def initialize(name)
+ # Make sure all of our resources are "finished".
+ def finalize
+ @resource_table.values.each { |resource| resource.finish }
+
+ write_graph(:resources)
+ end
+
+ def host_config?
+ host_config || false
+ end
+
+ def initialize(name = nil)
super()
- @name = name
+ @name = name if name
@extraction_format ||= :transportable
@tags = []
@classes = []
+ @resource_table = {}
+ @transient_resources = []
+ @applying = false
+ @relationship_graph = nil
+
+ if block_given?
+ yield(self)
+ finalize()
+ end
+ end
+
+ # Create a graph of all of the relationships in our configuration.
+ def relationship_graph
+ unless defined? @relationship_graph and @relationship_graph
+ # It's important that we assign the graph immediately, because
+ # the debug messages below use the relationships in the
+ # relationship graph to determine the path to the resources
+ # spitting out the messages. If this is not set,
+ # then we get into an infinite loop.
+ @relationship_graph = Puppet::Node::Configuration.new
+ @relationship_graph.host_config = host_config?
+
+ # First create the dependency graph
+ self.vertices.each do |vertex|
+ @relationship_graph.add_vertex! vertex
+ vertex.builddepends.each do |edge|
+ @relationship_graph.add_edge!(edge)
+ end
+ end
+
+ # Lastly, add in any autorequires
+ @relationship_graph.vertices.each do |vertex|
+ vertex.autorequire.each do |edge|
+ unless @relationship_graph.edge?(edge)
+ unless @relationship_graph.edge?(edge.target, edge.source)
+ vertex.debug "Autorequiring %s" % [edge.source]
+ @relationship_graph.add_edge!(edge)
+ else
+ vertex.debug "Skipping automatic relationship with %s" % (edge.source == vertex ? edge.target : edge.source)
+ end
+ end
+ end
+ end
+
+ @relationship_graph.write_graph(:relationships)
+
+ # Then splice in the container information
+ @relationship_graph.splice!(self, Puppet::Type::Component)
+
+ @relationship_graph.write_graph(:expanded_relationships)
+ end
+ @relationship_graph
+ end
+
+ # Remove the resource from our configuration. Notice that we also call
+ # 'remove' on the resource, at least until resource classes no longer maintain
+ # references to the resource instances.
+ def remove_resource(*resources)
+ resources.each do |resource|
+ @resource_table.delete(resource.ref) if @resource_table.include?(resource.ref)
+ remove_vertex!(resource) if vertex?(resource)
+ @relationship_graph.remove_vertex!(resource) if @relationship_graph and @relationship_graph.vertex?(resource)
+ resource.remove
+ end
+ end
+
+ # Look a resource up by its reference (e.g., File[/etc/passwd]).
+ def resource(type, title = nil)
+ if title
+ ref = "%s[%s]" % [type.to_s.capitalize, title]
+ else
+ ref = type
+ end
+ if resource = @resource_table[ref]
+ return resource
+ elsif defined?(@relationship_graph) and @relationship_graph
+ @relationship_graph.resource(ref)
+ end
end
# Add a tag.
@@ -120,4 +353,29 @@ class Puppet::Node::Configuration < GRATR::Digraph
def tags
@tags.dup
end
+
+ # Produce the graph files if requested.
+ def write_graph(name)
+ # We only want to graph the main host configuration.
+ return unless host_config?
+
+ return unless Puppet[:graph]
+
+ Puppet.settings.use(:graphing)
+
+ file = File.join(Puppet[:graphdir], "%s.dot" % name.to_s)
+ File.open(file, "w") { |f|
+ f.puts to_dot("name" => name.to_s.capitalize)
+ }
+ end
+
+ private
+
+ def cleanup
+ unless @transient_resources.empty?
+ remove_resource(*@transient_resources)
+ @transient_resources.clear
+ @relationship_graph = nil
+ end
+ end
end
diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb
new file mode 100755
index 000000000..a2e6d9c04
--- /dev/null
+++ b/lib/puppet/node/facts.rb
@@ -0,0 +1,36 @@
+require 'puppet/node'
+require 'puppet/indirector'
+
+# Manage a given node's facts. This either accepts facts and stores them, or
+# returns facts for a given node.
+class Puppet::Node::Facts
+ # Set up indirection, so that nodes can be looked for in
+ # the node sources.
+ extend Puppet::Indirector
+
+ # Use the node source as the indirection terminus.
+ indirects :facts
+
+ attr_accessor :name, :values
+
+ def initialize(name, values = {})
+ @name = name
+ @values = values
+
+ add_internal
+ end
+
+ private
+
+ # Add internal data to the facts for storage.
+ def add_internal
+ self.values[:_timestamp] = Time.now
+ end
+
+ # Strip out that internal data.
+ def strip_internal
+ newvals = values.dup
+ newvals.find_all { |name, value| name.to_s =~ /^_/ }.each { |name, value| newvals.delete(name) }
+ newvals
+ end
+end
diff --git a/lib/puppet/node/searching.rb b/lib/puppet/node/searching.rb
new file mode 100644
index 000000000..10dd588ab
--- /dev/null
+++ b/lib/puppet/node/searching.rb
@@ -0,0 +1,106 @@
+# The module that handles actually searching for nodes. This is only included
+# in the Node class, but it's completely stand-alone functionality, so it's
+# worth making it a separate module to simplify testing.
+module Puppet::Node::Searching
+ # Retrieve a node from the node source, with some additional munging
+ # thrown in for kicks.
+ def search(key)
+ return nil unless key
+ if node = cached?(key)
+ return node
+ end
+ facts = node_facts(key)
+ node = nil
+ names = node_names(key, facts)
+ names.each do |name|
+ name = name.to_s if name.is_a?(Symbol)
+ if node = find(name)
+ #Puppet.info "Found %s in %s" % [name, @source]
+ break
+ end
+ end
+
+ # If they made it this far, we haven't found anything, so look for a
+ # default node.
+ unless node or names.include?("default")
+ if node = find("default")
+ Puppet.notice "Using default node for %s" % key
+ end
+ end
+
+ if node
+ node.names = names
+
+ cache(node)
+
+ return node
+ else
+ return nil
+ end
+ end
+
+ private
+
+ # Store the node to make things a bit faster.
+ def cache(node)
+ @node_cache ||= {}
+ @node_cache[node.name] = node
+ end
+
+ # If the node is cached, return it.
+ def cached?(name)
+ # Don't use cache when the filetimeout is set to 0
+ return false if [0, "0"].include?(Puppet[:filetimeout])
+ @node_cache ||= {}
+
+ if node = @node_cache[name] and Time.now - node.time < Puppet[:filetimeout]
+ return node
+ else
+ return false
+ end
+ end
+
+ # Look up the node facts from our fact handler.
+ def node_facts(key)
+ if facts = Puppet::Node::Facts.find(key)
+ facts.values
+ else
+ {}
+ end
+ end
+
+ # Calculate the list of node names we should use for looking
+ # up our node.
+ def node_names(key, facts = nil)
+ facts ||= node_facts(key)
+ names = []
+
+ if hostname = facts["hostname"]
+ unless hostname == key
+ names << hostname
+ end
+ else
+ hostname = key
+ end
+
+ if fqdn = facts["fqdn"]
+ hostname = fqdn
+ names << fqdn
+ end
+
+ # Make sure both the fqdn and the short name of the
+ # host can be used in the manifest
+ if hostname =~ /\./
+ names << hostname.sub(/\..+/,'')
+ elsif domain = facts['domain']
+ names << hostname + "." + domain
+ end
+
+ # Sort the names inversely by name length.
+ names.sort! { |a,b| b.length <=> a.length }
+
+ # And make sure the key is first, since that's the most
+ # likely usage.
+ ([key] + names).uniq
+ end
+end
diff --git a/lib/puppet/parser/ast/component.rb b/lib/puppet/parser/ast/component.rb
deleted file mode 100644
index 1d7fe9cdd..000000000
--- a/lib/puppet/parser/ast/component.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-require 'puppet/parser/ast/branch'
-
-class Puppet::Parser::AST
- # Evaluate the stored parse tree for a given component. This will
- # receive the arguments passed to the component and also the type and
- # name of the component.
- class Component < AST::Branch
- include Puppet::Util
- include Puppet::Util::Warnings
- include Puppet::Util::MethodHelper
- class << self
- attr_accessor :name
- end
-
- # The class name
- @name = :definition
-
- attr_accessor :classname, :arguments, :code, :scope, :keyword
- attr_accessor :exported, :namespace, :parser, :virtual
-
- # These are retrieved when looking up the superclass
- attr_accessor :name
-
- attr_reader :parentclass
-
- def child_of?(klass)
- false
- end
-
- def evaluate_resource(hash)
- origscope = hash[:scope]
- title = hash[:title]
- args = symbolize_options(hash[:arguments] || {})
-
- name = args[:name] || title
-
- exported = hash[:exported]
- virtual = hash[:virtual]
-
- pscope = origscope
- scope = subscope(pscope, title)
-
- if virtual or origscope.virtual?
- scope.virtual = true
- end
-
- if exported or origscope.exported?
- scope.exported = true
- end
-
- # Additionally, add a tag for whatever kind of class
- # we are
- if @classname != "" and ! @classname.nil?
- @classname.split(/::/).each { |tag| scope.tag(tag) }
- end
-
- [name, title].each do |str|
- unless str.nil? or str =~ /[^\w]/ or str == ""
- scope.tag(str)
- end
- end
-
- # define all of the arguments in our local scope
- if self.arguments
- # Verify that all required arguments are either present or
- # have been provided with defaults.
- self.arguments.each { |arg, default|
- arg = symbolize(arg)
- unless args.include?(arg)
- if defined? default and ! default.nil?
- default = default.safeevaluate :scope => scope
- args[arg] = default
- #Puppet.debug "Got default %s for %s in %s" %
- # [default.inspect, arg.inspect, @name.inspect]
- else
- parsefail "Must pass %s to %s of type %s" %
- [arg,title,@classname]
- end
- end
- }
- end
-
- # Set each of the provided arguments as variables in the
- # component's scope.
- args.each { |arg,value|
- unless validattr?(arg)
- parsefail "%s does not accept attribute %s" % [@classname, arg]
- end
-
- exceptwrap do
- scope.setvar(arg.to_s,args[arg])
- end
- }
-
- unless args.include? :title
- scope.setvar("title",title)
- end
-
- unless args.include? :name
- scope.setvar("name",name)
- end
-
- if self.code
- return self.code.safeevaluate(:scope => scope)
- else
- return nil
- end
- end
-
- def initialize(hash = {})
- @arguments = nil
- @parentclass = nil
- super
-
- # Convert the arguments to a hash for ease of later use.
- if @arguments
- unless @arguments.is_a? Array
- @arguments = [@arguments]
- end
- oldargs = @arguments
- @arguments = {}
- oldargs.each do |arg, val|
- @arguments[arg] = val
- end
- else
- @arguments = {}
- end
-
- # Deal with metaparams in the argument list.
- @arguments.each do |arg, defvalue|
- next unless Puppet::Type.metaparamclass(arg)
- if defvalue
- warnonce "%s is a metaparam; this value will inherit to all contained elements" % arg
- else
- raise Puppet::ParseError,
- "%s is a metaparameter; please choose another name" %
- name
- end
- end
- end
-
- def find_parentclass
- @parser.findclass(namespace, parentclass)
- end
-
- # Set our parent class, with a little check to avoid some potential
- # weirdness.
- def parentclass=(name)
- if name == self.classname
- parsefail "Parent classes must have dissimilar names"
- end
-
- @parentclass = name
- end
-
- # Hunt down our class object.
- def parentobj
- if @parentclass
- # Cache our result, since it should never change.
- unless defined?(@parentobj)
- unless tmp = find_parentclass
- parsefail "Could not find %s %s" % [self.class.name, @parentclass]
- end
-
- if tmp == self
- parsefail "Parent classes must have dissimilar names"
- end
-
- @parentobj = tmp
- end
- @parentobj
- else
- nil
- end
- end
-
- # Create a new subscope in which to evaluate our code.
- def subscope(scope, name = nil)
- args = {
- :type => self.classname,
- :keyword => self.keyword,
- :namespace => self.namespace
- }
-
- args[:name] = name if name
- scope = scope.newscope(args)
- scope.source = self
-
- return scope
- end
-
- def to_s
- classname
- end
-
- # Check whether a given argument is valid. Searches up through
- # any parent classes that might exist.
- def validattr?(param)
- param = param.to_s
-
- if @arguments.include?(param)
- # It's a valid arg for us
- return true
- elsif param == "name"
- return true
-# elsif defined? @parentclass and @parentclass
-# # Else, check any existing parent
-# if parent = @scope.lookuptype(@parentclass) and parent != []
-# return parent.validarg?(param)
-# elsif builtin = Puppet::Type.type(@parentclass)
-# return builtin.validattr?(param)
-# else
-# raise Puppet::Error, "Could not find parent class %s" %
-# @parentclass
-# end
- elsif Puppet::Type.metaparam?(param)
- return true
- else
- # Or just return false
- return false
- end
- end
- end
-end
diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb
index a4ea26572..81867c84b 100644
--- a/lib/puppet/parser/interpreter.rb
+++ b/lib/puppet/parser/interpreter.rb
@@ -68,7 +68,7 @@ class Puppet::Parser::Interpreter
elsif self.file
parser.file = self.file
else
- file = Puppet.config.value(:manifest, environment)
+ file = Puppet.settings.value(:manifest, environment)
parser.file = file
end
parser.parse
diff --git a/lib/puppet/pgraph.rb b/lib/puppet/pgraph.rb
index 07bdff4bb..2399d1651 100644
--- a/lib/puppet/pgraph.rb
+++ b/lib/puppet/pgraph.rb
@@ -84,7 +84,7 @@ class Puppet::PGraph < GRATR::Digraph
def matching_edges(events, base = nil)
events.collect do |event|
source = base || event.source
-
+
unless vertex?(source)
Puppet.warning "Got an event from invalid vertex %s" % source.ref
next
@@ -95,7 +95,7 @@ class Puppet::PGraph < GRATR::Digraph
adjacent(source, :direction => :out, :type => :edges).find_all do |edge|
edge.match?(event.event)
end
- end.flatten
+ end.compact.flatten
end
# Take container information from another graph and use it
@@ -209,5 +209,3 @@ class Puppet::PGraph < GRATR::Digraph
end
end
end
-
-# $Id$
diff --git a/lib/puppet/provider/maillist/mailman.rb b/lib/puppet/provider/maillist/mailman.rb
index b556eecd7..903689178 100755
--- a/lib/puppet/provider/maillist/mailman.rb
+++ b/lib/puppet/provider/maillist/mailman.rb
@@ -101,9 +101,9 @@ Puppet::Type.type(:maillist).provide(:mailman) do
# Pull the current state of the list from the full list. We're
# getting some double entendre here....
def query
- provider.class.instances.each do |list|
+ self.class.instances.each do |list|
if list.name == self.name or list.name.downcase == self.name
- return list.property_hash
+ return list.properties
end
end
nil
diff --git a/lib/puppet/provider/mount.rb b/lib/puppet/provider/mount.rb
index 446ed641c..6a05d9826 100644
--- a/lib/puppet/provider/mount.rb
+++ b/lib/puppet/provider/mount.rb
@@ -50,5 +50,3 @@ module Puppet::Provider::Mount
end
end
end
-
-# $Id$
diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb
index 670c622eb..53dafce79 100644
--- a/lib/puppet/rails.rb
+++ b/lib/puppet/rails.rb
@@ -9,7 +9,7 @@ module Puppet::Rails
# This global init does not work for testing, because we remove
# the state dir on every test.
unless ActiveRecord::Base.connected?
- Puppet.config.use(:main, :rails, :puppetmasterd)
+ Puppet.settings.use(:main, :rails, :puppetmasterd)
ActiveRecord::Base.logger = Logger.new(Puppet[:railslog])
begin
@@ -103,7 +103,7 @@ module Puppet::Rails
raise Puppet::DevError, "No activerecord, cannot init Puppet::Rails"
end
- Puppet.config.use(:puppetmasterd, :rails)
+ Puppet.settings.use(:puppetmasterd, :rails)
begin
ActiveRecord::Base.establish_connection(database_arguments())
diff --git a/lib/puppet/reference/configuration.rb b/lib/puppet/reference/configuration.rb
index 65fdbeb7d..4b09002b8 100644
--- a/lib/puppet/reference/configuration.rb
+++ b/lib/puppet/reference/configuration.rb
@@ -1,6 +1,6 @@
config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc => "A reference for all configuration parameters") do
docs = {}
- Puppet.config.each do |name, object|
+ Puppet.settings.each do |name, object|
docs[name] = object
end
diff --git a/lib/puppet/reports/rrdgraph.rb b/lib/puppet/reports/rrdgraph.rb
index 7209a8401..1516d331a 100644
--- a/lib/puppet/reports/rrdgraph.rb
+++ b/lib/puppet/reports/rrdgraph.rb
@@ -102,7 +102,7 @@ Puppet::Network::Handler.report.newreport(:rrdgraph) do
unless File.directory?(hostdir) and FileTest.writable?(hostdir)
# Some hackishness to create the dir with all of the right modes and ownership
- config = Puppet::Util::Config.new
+ config = Puppet::Util::Settings.new
config.setdefaults(:reports, :hostdir => {:default => hostdir, :owner => Puppet[:user], :mode => 0755, :group => Puppet[:group], :desc => "eh"})
# This creates the dir.
diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb
index 8d6e11379..389de4e6e 100644
--- a/lib/puppet/reports/store.rb
+++ b/lib/puppet/reports/store.rb
@@ -1,7 +1,7 @@
require 'puppet'
Puppet::Network::Handler.report.newreport(:store, :useyaml => true) do
- Puppet.config.use(:reporting)
+ Puppet.settings.use(:reporting)
desc "Store the yaml report on disk. Each host sends its report as a YAML dump
and this just stores the file on disk, in the ``reportdir`` directory.
@@ -11,9 +11,9 @@ Puppet::Network::Handler.report.newreport(:store, :useyaml => true) do
default report)."
def mkclientdir(client, dir)
- config = Puppet::Util::Config.new
+ config = Puppet::Util::Settings.new
config.setdefaults("reportclient-#{client}",
- "clientdir-#{client}" => { :default => dir,
+ "client-#{client}-dir" => { :default => dir,
:mode => 0750,
:desc => "Client dir for %s" % client,
:owner => Puppet[:user],
diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb
index b62a6d2d3..8c65524ee 100644
--- a/lib/puppet/reports/tagmail.rb
+++ b/lib/puppet/reports/tagmail.rb
@@ -31,7 +31,7 @@ Puppet::Network::Handler.report.newreport(:tagmail) do
"
- Puppet.config.use(:tagmail)
+ Puppet.settings.use(:tagmail)
# Find all matching messages.
def match(taglists)
diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb
index 5e355f7fe..fd416dd5e 100644
--- a/lib/puppet/sslcertificates/ca.rb
+++ b/lib/puppet/sslcertificates/ca.rb
@@ -53,7 +53,7 @@ class Puppet::SSLCertificates::CA
end
def initialize(hash = {})
- Puppet.config.use(:main, :ca, :ssl)
+ Puppet.settings.use(:main, :ca, :ssl)
self.setconfig(hash)
if Puppet[:capass]
@@ -73,7 +73,7 @@ class Puppet::SSLCertificates::CA
self.getcert
init_crl
unless FileTest.exists?(@config[:serial])
- Puppet.config.write(:serial) do |f|
+ Puppet.settings.write(:serial) do |f|
f << "%04X" % 1
end
end
@@ -85,7 +85,7 @@ class Puppet::SSLCertificates::CA
20.times { pass += (rand(74) + 48).chr }
begin
- Puppet.config.write(:capass) { |f| f.print pass }
+ Puppet.settings.write(:capass) { |f| f.print pass }
rescue Errno::EACCES => detail
raise Puppet::Error, detail.to_s
end
@@ -163,10 +163,10 @@ class Puppet::SSLCertificates::CA
Puppet::Util::SUIDManager.asuser(Puppet[:user], Puppet[:group]) do
@cert = cert.mkselfsigned
end
- Puppet.config.write(:cacert) do |f|
+ Puppet.settings.write(:cacert) do |f|
f.puts @cert.to_pem
end
- Puppet.config.write(:capub) do |f|
+ Puppet.settings.write(:capub) do |f|
f.puts @cert.public_key
end
return cert
@@ -201,7 +201,7 @@ class Puppet::SSLCertificates::CA
# Take the Puppet config and store it locally.
def setconfig(hash)
@config = {}
- Puppet.config.params("ca").each { |param|
+ Puppet.settings.params("ca").each { |param|
param = param.intern if param.is_a? String
if hash.include?(param)
@config[param] = hash[param]
@@ -303,7 +303,7 @@ class Puppet::SSLCertificates::CA
raise Puppet::Error, "Certificate request for %s already exists" % host
end
- Puppet.config.writesub(:csrdir, csrfile) do |f|
+ Puppet.settings.writesub(:csrdir, csrfile) do |f|
f.print csr.to_pem
end
end
@@ -319,7 +319,7 @@ class Puppet::SSLCertificates::CA
end
Puppet::SSLCertificates::Inventory::add(cert)
- Puppet.config.writesub(:signeddir, certfile) do |f|
+ Puppet.settings.writesub(:signeddir, certfile) do |f|
f.print cert.to_pem
end
end
@@ -389,7 +389,7 @@ class Puppet::SSLCertificates::CA
@crl.next_update = now + 5 * 365*24*60*60
sign_with_key(@crl)
- Puppet.config.write(:cacrl) do |f|
+ Puppet.settings.write(:cacrl) do |f|
f.puts @crl.to_pem
end
end
diff --git a/lib/puppet/sslcertificates/inventory.rb b/lib/puppet/sslcertificates/inventory.rb
index d475c1c86..14d2155a8 100644
--- a/lib/puppet/sslcertificates/inventory.rb
+++ b/lib/puppet/sslcertificates/inventory.rb
@@ -11,7 +11,7 @@ module Puppet::SSLCertificates
inited = false
end
- Puppet.config.write(:cert_inventory, "a") do |f|
+ Puppet.settings.write(:cert_inventory, "a") do |f|
f.puts((inited ? nil : self.init).to_s + format(cert))
end
end
diff --git a/lib/puppet/sslcertificates/support.rb b/lib/puppet/sslcertificates/support.rb
index e37a52038..c8d2e846b 100644
--- a/lib/puppet/sslcertificates/support.rb
+++ b/lib/puppet/sslcertificates/support.rb
@@ -44,7 +44,7 @@ module Puppet::SSLCertificates::Support
unless instance_variable_get(var)
unless cert = send(reader)
cert = send(maker)
- Puppet.config.write(param) { |f| f.puts cert.to_pem }
+ Puppet.settings.write(param) { |f| f.puts cert.to_pem }
end
instance_variable_set(var, cert)
end
@@ -59,7 +59,7 @@ module Puppet::SSLCertificates::Support
# Our key meta programming can only handle one file, so we have
# to separately write out the public key.
- Puppet.config.write(:hostpubkey) do |f|
+ Puppet.settings.write(:hostpubkey) do |f|
f.print key.public_key.to_pem
end
return key
@@ -104,8 +104,8 @@ module Puppet::SSLCertificates::Support
if cert.nil? or cert == ""
return nil
end
- Puppet.config.write(:hostcert) do |f| f.print cert end
- Puppet.config.write(:localcacert) do |f| f.print cacert end
+ Puppet.settings.write(:hostcert) do |f| f.print cert end
+ Puppet.settings.write(:localcacert) do |f| f.print cacert end
#File.open(@certfile, "w", 0644) { |f| f.print cert }
#File.open(@cacertfile, "w", 0644) { |f| f.print cacert }
begin
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index 46bac3058..4e2ab702f 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -6,10 +6,14 @@ require 'puppet/propertychange'
module Puppet
class Transaction
- attr_accessor :component, :resources, :ignoreschedules, :ignoretags
- attr_accessor :relgraph, :sorted_resources, :configurator
+ attr_accessor :component, :configuration, :ignoreschedules
+ attr_accessor :sorted_resources, :configurator
+ # The report, once generated.
attr_reader :report
+
+ # The list of events generated in this transaction.
+ attr_reader :events
attr_writer :tags
@@ -22,13 +26,14 @@ class Transaction
end
end
- # Check to see if we should actually allow deleition.
+ # Check to see if we should actually allow processing, but this really only
+ # matters when a resource is getting deleted.
def allow_processing?(resource, changes)
# If a resource is going to be deleted but it still has
# dependencies, then don't delete it unless it's implicit or the
# dependency is itself being deleted.
if resource.purging? and resource.deleting?
- if deps = @relgraph.dependents(resource) and ! deps.empty? and deps.detect { |d| ! d.deleting? }
+ if deps = relationship_graph.dependents(resource) and ! deps.empty? and deps.detect { |d| ! d.deleting? }
resource.warning "%s still depend%s on me -- not purging" %
[deps.collect { |r| r.ref }.join(","), deps.length > 1 ? "":"s"]
return false
@@ -129,6 +134,9 @@ class Transaction
# Find all of the changed resources.
def changed?
@changes.find_all { |change| change.changed }.collect { |change|
+ unless change.property.resource
+ raise "No resource for %s" % change.inspect
+ end
change.property.resource
}.uniq
end
@@ -137,14 +145,8 @@ class Transaction
# contained resources might never get cleaned up.
def cleanup
if defined? @generated
- @generated.each do |resource|
- resource.remove
- end
+ relationship_graph.remove_resource(*@generated)
end
- if defined? @relgraph
- @relgraph.clear
- end
- @resources.clear
end
# Copy an important relationships from the parent to the newly-generated
@@ -158,10 +160,11 @@ class Transaction
else
edge = [resource, gen_child]
end
- unless @relgraph.edge?(edge[1], edge[0])
- @relgraph.add_edge!(*edge)
+ relationship_graph.add_resource(gen_child) unless relationship_graph.resource(gen_child.ref)
+
+ unless relationship_graph.edge?(edge[1], edge[0])
+ relationship_graph.add_edge!(*edge)
else
- @relgraph.add_vertex!(gen_child)
resource.debug "Skipping automatic relationship to %s" % gen_child
end
end
@@ -192,7 +195,8 @@ class Transaction
children.each do |child|
child.finish
# Make sure that the vertex is in the relationship graph.
- @relgraph.add_vertex!(child)
+ relationship_graph.add_resource(child) unless relationship_graph.resource(child.ref)
+ child.configuration = relationship_graph
end
@generated += children
return children
@@ -265,9 +269,12 @@ class Transaction
# Collect the targets of any subscriptions to those events. We pass
# the parent resource in so it will override the source in the events,
# since eval_generated children can't have direct relationships.
- @relgraph.matching_edges(events, resource).each do |edge|
- edge = edge.dup
- label = edge.label
+ relationship_graph.matching_edges(events, resource).each do |orig_edge|
+ # We have to dup the label here, else we modify the original edge label,
+ # which affects whether a given event will match on the next run, which is,
+ # of course, bad.
+ edge = orig_edge.class.new(orig_edge.source, orig_edge.target)
+ label = orig_edge.label.dup
label[:event] = events.collect { |e| e.event }
edge.label = label
set_trigger(edge)
@@ -283,8 +290,6 @@ class Transaction
def evaluate
@count = 0
- graph(@resources, :resources)
-
# Start logging.
Puppet::Util::Log.newdestination(@report)
@@ -314,6 +319,7 @@ class Transaction
Puppet.debug "Finishing transaction %s with %s changes" %
[self.object_id, @count]
+ @events = allevents
allevents
end
@@ -333,7 +339,7 @@ class Transaction
# enough to check the immediate dependencies, which is why we use
# a tree from the reversed graph.
skip = false
- deps = @relgraph.dependencies(resource)
+ deps = relationship_graph.dependencies(resource)
deps.each do |dep|
if fails = failed?(dep)
resource.notice "Dependency %s[%s] has %s failures" %
@@ -347,7 +353,7 @@ class Transaction
# Collect any dynamically generated resources.
def generate
- list = @resources.vertices
+ list = @configuration.vertices
# Store a list of all generated resources, so that we can clean them up
# after the transaction closes.
@@ -369,7 +375,8 @@ class Transaction
end
made.uniq!
made.each do |res|
- @resources.add_vertex!(res)
+ @configuration.add_resource(res)
+ res.configuration = configuration
newlist << res
@generated << res
res.finish
@@ -410,32 +417,24 @@ class Transaction
return @report
end
- # Produce the graph files if requested.
- def graph(gr, name)
- # We don't want to graph the configuration process.
- return if self.configurator
-
- return unless Puppet[:graph]
-
- Puppet.config.use(:graphing)
-
- file = File.join(Puppet[:graphdir], "%s.dot" % name.to_s)
- File.open(file, "w") { |f|
- f.puts gr.to_dot("name" => name.to_s.capitalize)
- }
+ # Should we ignore tags?
+ def ignore_tags?
+ ! @configuration.host_config?
end
# this should only be called by a Puppet::Type::Component resource now
# and it should only receive an array
def initialize(resources)
- if resources.is_a?(Puppet::PGraph)
- @resources = resources
+ if resources.is_a?(Puppet::Node::Configuration)
+ @configuration = resources
+ elsif resources.is_a?(Puppet::PGraph)
+ raise "Transactions should get configurations now, not PGraph"
else
- @resources = resources.to_graph
+ raise "Transactions require configurations"
end
@resourcemetrics = {
- :total => @resources.vertices.length,
+ :total => @configuration.vertices.length,
:out_of_sync => 0, # The number of resources that had changes
:applied => 0, # The number of resources fixed
:skipped => 0, # The number of resources skipped
@@ -474,7 +473,7 @@ class Transaction
# types, just providers.
def prefetch
prefetchers = {}
- @resources.each do |resource|
+ @configuration.each do |resource|
if provider = resource.provider and provider.class.respond_to?(:prefetch)
prefetchers[provider.class] ||= {}
prefetchers[provider.class][resource.title] = resource
@@ -501,48 +500,49 @@ class Transaction
# Now add any dynamically generated resources
generate()
-
- # Create a relationship graph from our resource graph
- @relgraph = relationship_graph
# This will throw an error if there are cycles in the graph.
- @sorted_resources = @relgraph.topsort
+ @sorted_resources = relationship_graph.topsort
end
-
- # Create a graph of all of the relationships in our resource graph.
+
def relationship_graph
- graph = Puppet::PGraph.new
-
- # First create the dependency graph
- @resources.vertices.each do |vertex|
- graph.add_vertex!(vertex)
- vertex.builddepends.each do |edge|
- graph.add_edge!(edge)
- end
+ configuration.relationship_graph
+ end
+
+ # Send off the transaction report.
+ def send_report
+ begin
+ report = generate_report()
+ rescue => detail
+ Puppet.err "Could not generate report: %s" % detail
+ return
+ end
+
+ if Puppet[:rrdgraph] == true
+ report.graph()
+ end
+
+ if Puppet[:summarize]
+ puts report.summary
end
- # Lastly, add in any autorequires
- graph.vertices.each do |vertex|
- vertex.autorequire.each do |edge|
- unless graph.edge?(edge)
- unless graph.edge?(edge.target, edge.source)
- vertex.debug "Autorequiring %s" % [edge.source]
- graph.add_edge!(edge)
- else
- vertex.debug "Skipping automatic relationship with %s" % (edge.source == vertex ? edge.target : edge.source)
- end
- end
+ if Puppet[:report]
+ begin
+ reportclient().report(report)
+ rescue => detail
+ Puppet.err "Reporting failed: %s" % detail
end
end
-
- graph(graph, :relationships)
-
- # Then splice in the container information
- graph.splice!(@resources, Puppet::Type::Component)
+ end
- graph(graph, :expanded_relationships)
-
- return graph
+ def reportclient
+ unless defined? @reportclient
+ @reportclient = Puppet::Network::Client.report.new(
+ :Server => Puppet[:reportserver]
+ )
+ end
+
+ @reportclient
end
# Roll all completed changes back.
@@ -572,7 +572,7 @@ class Transaction
end
# FIXME This won't work right now.
- @relgraph.matching_edges(events).each do |edge|
+ relationship_graph.matching_edges(events).each do |edge|
@targets[edge.target] << edge
end
@@ -606,7 +606,7 @@ class Transaction
# Should this resource be skipped?
def skip?(resource)
skip = false
- if ! tagged?(resource)
+ if missing_tags?(resource)
resource.debug "Not tagged with %s" % tags.join(", ")
elsif ! scheduled?(resource)
resource.debug "Not scheduled"
@@ -620,29 +620,22 @@ class Transaction
# The tags we should be checking.
def tags
- # Allow the tags to be overridden
unless defined? @tags
- @tags = Puppet[:tags]
- end
-
- unless defined? @processed_tags
- if @tags.nil? or @tags == ""
+ tags = Puppet[:tags]
+ if tags.nil? or tags == ""
@tags = []
else
- @tags = [@tags] unless @tags.is_a? Array
- @tags = @tags.collect do |tag|
- tag.split(/\s*,\s*/)
- end.flatten
+ @tags = tags.split(/\s*,\s*/)
end
- @processed_tags = true
end
@tags
end
# Is this resource tagged appropriately?
- def tagged?(resource)
- self.ignoretags or tags.empty? or resource.tagged?(tags)
+ def missing_tags?(resource)
+ return false if self.ignore_tags? or tags.empty?
+ return true unless resource.tagged?(tags)
end
# Are there any edges that target this resource?
diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb
index aa7eb92f7..ecd179ed7 100644
--- a/lib/puppet/transportable.rb
+++ b/lib/puppet/transportable.rb
@@ -60,7 +60,18 @@ module Puppet
instance_variables
end
- def to_type(parent = nil)
+ def to_ref
+ unless defined? @ref
+ if self.type and self.name
+ @ref = "%s[%s]" % [self.type, self.name]
+ else
+ @ref = nil
+ end
+ end
+ @ref
+ end
+
+ def to_type
retobj = nil
if typeklass = Puppet::Type.type(self.type)
# FIXME This should really be done differently, but...
@@ -77,10 +88,6 @@ module Puppet
raise Puppet::Error.new("Could not find object type %s" % self.type)
end
- if parent
- parent.push retobj
- end
-
return retobj
end
end
@@ -167,12 +174,7 @@ module Puppet
end
end
- str = nil
- if self.top
- str = "%s"
- else
- str = "#{@keyword} #{@type} {\n%s\n}"
- end
+ str = "#{@keyword} #{@name} {\n%s\n}"
str % @children.collect { |child|
child.to_manifest
}.collect { |str|
@@ -188,7 +190,44 @@ module Puppet
instance_variables
end
- def to_type(parent = nil)
+ # Create a resource graph from our structure.
+ def to_configuration
+ configuration = Puppet::Node::Configuration.new(Facter.value("hostname")) do |config|
+ delver = proc do |obj|
+ unless container = config.resource(obj.to_ref)
+ container = obj.to_type
+ config.add_resource container
+ end
+ obj.each do |child|
+ unless resource = config.resource(child.to_ref)
+ next unless resource = child.to_type
+ config.add_resource resource
+ end
+ config.add_edge!(container, resource)
+ if child.is_a?(self.class)
+ delver.call(child)
+ end
+ end
+ end
+
+ delver.call(self)
+ end
+
+ return configuration
+ end
+
+ def to_ref
+ unless defined? @ref
+ if self.type and self.name
+ @ref = "%s[%s]" % [self.type, self.name]
+ else
+ @ref = nil
+ end
+ end
+ @ref
+ end
+
+ def to_type
# this container will contain the equivalent of all objects at
# this level
#container = Puppet::Component.new(:name => @name, :type => @type)
@@ -235,45 +274,16 @@ module Puppet
#Puppet.debug "%s[%s] has no parameters" % [@type, @name]
end
- #if parent
- # hash[:parent] = parent
- #end
container = Puppet::Type::Component.create(hash)
end
#Puppet.info container.inspect
- if parent
- parent.push container
- end
-
# unless we successfully created the container, return an error
unless container
Puppet.warning "Got no container back"
return nil
end
- self.each { |child|
- # the fact that we descend here means that we are
- # always going to execute depth-first
- # which is _probably_ a good thing, but one never knows...
- unless child.is_a?(Puppet::TransBucket) or
- child.is_a?(Puppet::TransObject)
- raise Puppet::DevError,
- "TransBucket#to_type cannot handle objects of type %s" %
- child.class
- end
-
- # Now just call to_type on them with the container as a parent
- begin
- child.to_type(container)
- rescue => detail
- if Puppet[:trace] and ! detail.is_a?(Puppet::Error)
- puts detail.backtrace
- end
- Puppet.err detail.to_s
- end
- }
-
# at this point, no objects at are level are still Transportable
# objects
return container
@@ -287,7 +297,5 @@ module Puppet
end
end
- #------------------------------------------------------------
end
-# $Id$
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index b4b6e3b18..19f676ff4 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -44,7 +44,9 @@ class Type
# that it is clear whether it operates on all attributes (thus has 'attr' in
# the method name, or whether it operates on a specific type of attributes.
attr_accessor :file, :line
- attr_reader :parent
+
+ # The configuration that this resource is stored in.
+ attr_accessor :configuration
attr_writer :title
attr_writer :noop
@@ -310,6 +312,25 @@ class Type
return self[:name]
end
+ # Look up our parent in the configuration, if we have one.
+ def parent
+ return nil unless configuration
+
+ # This is kinda weird.
+ if implicit?
+ parents = configuration.relationship_graph.adjacent(self, :direction => :in)
+ else
+ parents = configuration.adjacent(self, :direction => :in)
+ end
+ if parents
+ # We should never have more than one parent, so let's just ignore
+ # it if we happen to.
+ return parents.shift
+ else
+ return nil
+ end
+ end
+
# Return the "type[name]" style reference.
def ref
"%s[%s]" % [self.class.name.to_s.capitalize, self.title]
diff --git a/lib/puppet/type/component.rb b/lib/puppet/type/component.rb
index 5905d85ab..c5842e0e7 100644
--- a/lib/puppet/type/component.rb
+++ b/lib/puppet/type/component.rb
@@ -52,6 +52,7 @@ Puppet::Type.newtype(:component) do
# this is only called on one component over the whole system
# this also won't work with scheduling, but eh
def evaluate
+ raise "Component#evaluate is deprecated"
self.finalize unless self.finalized?
transaction = Puppet::Transaction.new(self)
transaction.component = self
@@ -127,27 +128,6 @@ Puppet::Type.newtype(:component) do
return false
end
end
-
- def push(*childs)
- unless defined? @children
- @children = []
- end
- childs.each { |child|
- # Make sure we don't have any loops here.
- if parentof?(child)
- devfail "Already the parent of %s[%s]" % [child.class.name, child.title]
- end
- unless child.is_a?(Puppet::Type)
- self.debug "Got object of type %s" % child.class
- self.devfail(
- "Containers can only contain Puppet resources, not %s" %
- child.class
- )
- end
- @children.push(child)
- child.parent = self
- }
- end
# Component paths are special because they function as containers.
def pathbuilder
@@ -162,30 +142,15 @@ Puppet::Type.newtype(:component) do
else
myname = self.title
end
- if self.parent
- return [@parent.pathbuilder, myname]
+ if p = self.parent
+ return [p.pathbuilder, myname]
else
return [myname]
end
end
- # Remove an object. The argument determines whether the object's
- # subscriptions get eliminated, too.
- def remove(rmdeps = true)
- # Our children remove themselves from our @children array (else the object
- # we called this on at the top would not be removed), so we duplicate the
- # array and iterate over that. If we don't do this, only half of the
- # objects get removed.
- @children.dup.each { |child|
- child.remove(rmdeps)
- }
-
- @children.clear
-
- # Get rid of params and provider, too.
- super
-
- @parent = nil
+ def ref
+ title
end
# We have a different way of setting the title
@@ -203,30 +168,12 @@ Puppet::Type.newtype(:component) do
end
def refresh
- @children.collect { |child|
+ configuration.adjacent(self).each do |child|
if child.respond_to?(:refresh)
child.refresh
child.log "triggering %s" % :refresh
end
- }
- end
-
- # Convert to a graph object with all of the container info.
- def to_graph
- graph = Puppet::PGraph.new
-
- delver = proc do |obj|
- obj.each do |child|
- graph.add_edge!(obj, child)
- if child.is_a?(self.class)
- delver.call(child)
- end
- end
end
-
- delver.call(self)
-
- return graph
end
def to_s
@@ -237,5 +184,3 @@ Puppet::Type.newtype(:component) do
end
end
end
-
-# $Id$
diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb
index 99b5a7435..5bf9fef78 100644
--- a/lib/puppet/type/pfile.rb
+++ b/lib/puppet/type/pfile.rb
@@ -574,6 +574,9 @@ module Puppet
# Create a new file or directory object as a child to the current
# object.
def newchild(path, local, hash = {})
+ unless configuration
+ raise Puppet::DevError, "File recursion cannot happen without a configuration"
+ end
# make local copy of arguments
args = symbolize_options(@arghash)
@@ -608,14 +611,14 @@ module Puppet
}
child = nil
- klass = self.class
-
+
# The child might already exist because 'localrecurse' runs
# before 'sourcerecurse'. I could push the override stuff into
# a separate method or something, but the work is the same other
# than this last bit, so it doesn't really make sense.
- if child = klass[path]
+ if child = configuration.resource(:file, path)
unless child.parent.object_id == self.object_id
+ puts("Parent is %s, I am %s" % [child.parent.ref, self.ref]) if child.parent
self.debug "Not managing more explicit file %s" %
path
return nil
@@ -640,28 +643,22 @@ module Puppet
#notice "Creating new file with args %s" % args.inspect
args[:parent] = self
begin
- child = klass.implicitcreate(args)
-
- # implicit creation can return nil
- if child.nil?
- return nil
- end
- rescue Puppet::Error => detail
- self.notice(
- "Cannot manage: %s" %
- [detail.message]
- )
- self.debug args.inspect
- child = nil
+ # This method is used by subclasses of :file, so use the class name rather than hard-coding
+ # :file.
+ return nil unless child = configuration.create_implicit_resource(self.class.name, args)
rescue => detail
- self.notice(
- "Cannot manage: %s" %
- [detail]
- )
- self.debug args.inspect
- child = nil
+ puts detail.backtrace
+ self.notice "Cannot manage: %s" % [detail]
+ return nil
end
end
+
+ # LAK:FIXME This shouldn't be necessary, but as long as we're
+ # modeling the relationship graph specifically, it is.
+ configuration.relationship_graph.add_edge! self, child
+ unless child.parent
+ raise "Did not set parent of %s" % child.ref
+ end
return child
end
@@ -669,12 +666,14 @@ module Puppet
# path names, rather than including the full parent's title each
# time.
def pathbuilder
- if defined? @parent
+ # We specifically need to call the method here, so it looks
+ # up our parent in the configuration graph.
+ if parent = parent()
# We only need to behave specially when our parent is also
# a file
- if @parent.is_a?(self.class)
+ if parent.is_a?(self.class)
# Remove the parent file name
- list = @parent.pathbuilder
+ list = parent.pathbuilder
list.pop # remove the parent's path info
return list << self.ref
else
@@ -695,9 +694,7 @@ module Puppet
# files.
def recurse
# are we at the end of the recursion?
- unless self.recurse?
- return
- end
+ return unless self.recurse?
recurse = self[:recurse]
# we might have a string, rather than a number
diff --git a/lib/puppet/util/feature.rb b/lib/puppet/util/feature.rb
index 30c38e286..2669d1ab1 100644
--- a/lib/puppet/util/feature.rb
+++ b/lib/puppet/util/feature.rb
@@ -16,8 +16,7 @@ class Puppet::Util::Feature
if self.class.respond_to?(method)
raise ArgumentError, "Feature %s is already defined" % name
end
-
- result = true
+
if block_given?
begin
result = yield
@@ -25,33 +24,21 @@ class Puppet::Util::Feature
warn "Failed to load feature test for %s: %s" % [name, detail]
result = false
end
- end
-
- if ary = options[:libs]
- ary = [ary] unless ary.is_a?(Array)
-
- ary.each do |lib|
- unless lib.is_a?(String)
- raise ArgumentError, "Libraries must be passed as strings not %s" % lib.class
- end
-
- begin
- require lib
- rescue Exception
- Puppet.debug "Failed to load library '%s' for feature '%s'" % [lib, name]
- result = false
- end
- end
+ @results[name] = result
end
meta_def(method) do
- result
+ unless @results.include?(name)
+ @results[name] = test(name, options)
+ end
+ @results[name]
end
end
# Create a new feature collection.
def initialize(path)
@path = path
+ @results = {}
@loader = Puppet::Util::Autoload.new(self, @path)
end
@@ -71,6 +58,28 @@ class Puppet::Util::Feature
return false
end
end
-end
-# $Id$
+ # Actually test whether the feature is present. We only want to test when
+ # someone asks for the feature, so we don't unnecessarily load
+ # files.
+ def test(name, options)
+ result = true
+ if ary = options[:libs]
+ ary = [ary] unless ary.is_a?(Array)
+
+ ary.each do |lib|
+ unless lib.is_a?(String)
+ raise ArgumentError, "Libraries must be passed as strings not %s" % lib.class
+ end
+
+ begin
+ require lib
+ rescue Exception
+ Puppet.debug "Failed to load library '%s' for feature '%s'" % [lib, name]
+ result = false
+ end
+ end
+ end
+ result
+ end
+end
diff --git a/lib/puppet/util/instance_loader.rb b/lib/puppet/util/instance_loader.rb
index 1a64c9c69..f280014eb 100755
--- a/lib/puppet/util/instance_loader.rb
+++ b/lib/puppet/util/instance_loader.rb
@@ -5,6 +5,12 @@ require 'puppet/util'
# of Puppet::Util::Autoload
module Puppet::Util::InstanceLoader
include Puppet::Util
+
+ # Are we instance-loading this type?
+ def instance_loading?(type)
+ defined?(@autoloaders) and @autoloaders.include?(symbolize(type))
+ end
+
# Define a new type of autoloading.
def instance_load(type, path, options = {})
@autoloaders ||= {}
@@ -54,7 +60,7 @@ module Puppet::Util::InstanceLoader
# Retrieve an alread-loaded instance, or attempt to load our instance.
def loaded_instance(type, name)
name = symbolize(name)
- instances = instance_hash(type)
+ return nil unless instances = instance_hash(type)
unless instances.include? name
if instance_loader(type).load(name)
unless instances.include? name
@@ -70,5 +76,3 @@ module Puppet::Util::InstanceLoader
instances[name]
end
end
-
-# $Id$
diff --git a/lib/puppet/util/metric.rb b/lib/puppet/util/metric.rb
index 13bbc2af1..133aa9c2a 100644
--- a/lib/puppet/util/metric.rb
+++ b/lib/puppet/util/metric.rb
@@ -21,7 +21,7 @@ class Puppet::Util::Metric
end
def create(start = nil)
- Puppet.config.use(:metrics)
+ Puppet.settings.use(:metrics)
start ||= Time.now.to_i - 5
diff --git a/lib/puppet/util/config.rb b/lib/puppet/util/settings.rb
index 9cdb4cfe3..1478cd8a5 100644
--- a/lib/puppet/util/config.rb
+++ b/lib/puppet/util/settings.rb
@@ -5,7 +5,7 @@ require 'getoptlong'
# The class for handling configuration files.
-class Puppet::Util::Config
+class Puppet::Util::Settings
include Enumerable
include Puppet::Util
@@ -45,15 +45,17 @@ class Puppet::Util::Config
end
# A simplified equality operator.
- def ==(other)
- self.each { |myname, myobj|
- unless other[myname] == value(myname)
- return false
- end
- }
-
- return true
- end
+ # LAK: For some reason, this causes mocha to not be able to mock
+ # the 'value' method, and it's not used anywhere.
+# def ==(other)
+# self.each { |myname, myobj|
+# unless other[myname] == value(myname)
+# return false
+# end
+# }
+#
+# return true
+# end
# Generate the list of valid arguments, in a format that GetoptLong can
# understand, and add them to the passed option list.
@@ -69,14 +71,14 @@ class Puppet::Util::Config
return options
end
- # Turn the config into a transaction and apply it
+ # Turn the config into a Puppet configuration and apply it
def apply
trans = self.to_transportable
begin
- comp = trans.to_type
- trans = comp.evaluate
- trans.evaluate
- comp.remove
+ config = trans.to_configuration
+ config.store_state = false
+ config.apply
+ config.clear
rescue => detail
if Puppet[:trace]
puts detail.backtrace
@@ -476,57 +478,15 @@ class Puppet::Util::Config
end
# Convert a single section into transportable objects.
- def section_to_transportable(section, done = nil, includefiles = true)
+ def section_to_transportable(section, done = nil)
done ||= Hash.new { |hash, key| hash[key] = {} }
objects = []
persection(section) do |obj|
if @config[:mkusers] and value(:mkusers)
- [:owner, :group].each do |attr|
- type = nil
- if attr == :owner
- type = :user
- else
- type = attr
- end
- # If a user and/or group is set, then make sure we're
- # managing that object
- if obj.respond_to? attr and name = obj.send(attr)
- # Skip root or wheel
- next if %w{root wheel}.include?(name.to_s)
-
- # Skip owners and groups we've already done, but tag
- # them with our section if necessary
- if done[type].include?(name)
- tags = done[type][name].tags
- unless tags.include?(section)
- done[type][name].tags = tags << section
- end
- elsif newobj = Puppet::Type.type(type)[name]
- unless newobj.property(:ensure)
- newobj[:ensure] = "present"
- end
- newobj.tag(section)
- if type == :user
- newobj[:comment] ||= "%s user" % name
- end
- else
- newobj = Puppet::TransObject.new(name, type.to_s)
- newobj.tags = ["puppet", "configuration", section]
- newobj[:ensure] = "present"
- if type == :user
- newobj[:comment] ||= "%s user" % name
- end
- # Set the group appropriately for the user
- if type == :user
- newobj[:gid] = Puppet[:group]
- end
- done[type][name] = newobj
- objects << newobj
- end
- end
- end
+ objects += add_user_resources(section, obj, done)
end
+ # Only files are convertable to transportable resources.
if obj.respond_to? :to_transportable
next if value(obj.name) =~ /^\/dev/
transobjects = obj.to_transportable
@@ -544,7 +504,8 @@ class Puppet::Util::Config
end
bucket = Puppet::TransBucket.new
- bucket.type = section
+ bucket.type = "Settings"
+ bucket.name = section
bucket.push(*objects)
bucket.keyword = "class"
@@ -596,9 +557,9 @@ class Puppet::Util::Config
end
# Convert our list of objects into a component that can be applied.
- def to_component
+ def to_configuration
transport = self.to_transportable
- return transport.to_type
+ return transport.to_configuration
end
# Convert our list of objects into a configuration file.
@@ -634,7 +595,7 @@ Generated on #{Time.now}.
end
# Convert our configuration into a list of transportable objects.
- def to_transportable
+ def to_transportable(*sections)
done = Hash.new { |hash, key|
hash[key] = {}
}
@@ -643,14 +604,20 @@ Generated on #{Time.now}.
if defined? @file.file and @file.file
topbucket.name = @file.file
else
- topbucket.name = "configtop"
+ topbucket.name = "top"
end
- topbucket.type = "puppetconfig"
+ topbucket.type = "Settings"
topbucket.top = true
# Now iterate over each section
- eachsection do |section|
- topbucket.push section_to_transportable(section, done)
+ if sections.empty?
+ eachsection do |section|
+ sections << section
+ end
+ end
+ sections.each do |section|
+ obj = section_to_transportable(section, done)
+ topbucket.push obj
end
topbucket
@@ -683,37 +650,31 @@ Generated on #{Time.now}.
}
return if runners.empty?
- bucket = Puppet::TransBucket.new
- bucket.type = "puppetconfig"
- bucket.top = true
-
- # Create a hash to keep track of what we've done so far.
- @done = Hash.new { |hash, key| hash[key] = {} }
- runners.each do |section|
- bucket.push section_to_transportable(section, @done, false)
- end
-
- objects = bucket.to_type
-
- objects.finalize
- tags = nil
- if Puppet[:tags]
- tags = Puppet[:tags]
- Puppet[:tags] = ""
- end
- trans = objects.evaluate
- trans.ignoretags = true
- trans.configurator = true
- trans.evaluate
- if tags
- Puppet[:tags] = tags
- end
-
- # Remove is a recursive process, so it's sufficient to just call
- # it on the component.
- objects.remove(true)
-
- objects = nil
+ bucket = to_transportable(*sections)
+
+ config = bucket.to_configuration
+ config.host_config = false
+ config.apply
+ config.clear
+
+# tags = nil
+# if Puppet[:tags]
+# tags = Puppet[:tags]
+# Puppet[:tags] = ""
+# end
+# trans = objects.evaluate
+# trans.ignoretags = true
+# trans.configurator = true
+# trans.evaluate
+# if tags
+# Puppet[:tags] = tags
+# end
+#
+# # Remove is a recursive process, so it's sufficient to just call
+# # it on the component.
+# objects.remove(true)
+#
+# objects = nil
runners.each { |s| @used << s }
end
@@ -845,6 +806,48 @@ Generated on #{Time.now}.
private
+ # Create the transportable objects for users and groups.
+ def add_user_resources(section, obj, done)
+ resources = []
+ [:owner, :group].each do |attr|
+ type = nil
+ if attr == :owner
+ type = :user
+ else
+ type = attr
+ end
+ # If a user and/or group is set, then make sure we're
+ # managing that object
+ if obj.respond_to? attr and name = obj.send(attr)
+ # Skip root or wheel
+ next if %w{root wheel}.include?(name.to_s)
+
+ # Skip owners and groups we've already done, but tag
+ # them with our section if necessary
+ if done[type].include?(name)
+ tags = done[type][name].tags
+ unless tags.include?(section)
+ done[type][name].tags = tags << section
+ end
+ else
+ newobj = Puppet::TransObject.new(name, type.to_s)
+ newobj.tags = ["puppet", "configuration", section]
+ newobj[:ensure] = :present
+ if type == :user
+ newobj[:comment] ||= "%s user" % name
+ end
+ # Set the group appropriately for the user
+ if type == :user
+ newobj[:gid] = Puppet[:group]
+ end
+ done[type][name] = newobj
+ resources << newobj
+ end
+ end
+ end
+ resources
+ end
+
# Extract extra setting information for files.
def extract_fileinfo(string)
result = {}
@@ -1105,6 +1108,11 @@ Generated on #{Time.now}.
# Set the type appropriately. Yep, a hack. This supports either naming
# the variable 'dir', or adding a slash at the end.
def munge(value)
+ # If it's not a fully qualified path...
+ if value.is_a?(String) and value !~ /^\$/ and value !~ /^\//
+ # Make it one
+ value = File.join(Dir.getwd, value)
+ end
if value.to_s =~ /\/$/
@type = :directory
return value.sub(/\/$/, '')
@@ -1127,9 +1135,6 @@ Generated on #{Time.now}.
end
# Convert the object to a TransObject instance.
- # FIXME There's no dependency system in place right now; if you use
- # a section that requires another section, there's nothing done to
- # correct that for you, at the moment.
def to_transportable
type = self.type
return nil unless type
@@ -1138,9 +1143,9 @@ Generated on #{Time.now}.
objects = []
path = self.value
- unless path =~ /^#{File::SEPARATOR}/
- path = File.join(Dir.getwd, path)
- end
+
+ # Skip plain files that don't exist, since we won't be managing them anyway.
+ return nil unless self.name.to_s =~ /dir$/ or File.exist?(path) or self.create
obj = Puppet::TransObject.new(path, "file")
# Only create directories, or files that are specifically marked to
@@ -1157,7 +1162,7 @@ Generated on #{Time.now}.
}
# Only chown or chgrp when root
- if Puppet::Util::SUIDManager.uid == 0
+ if Puppet.features.root?
[:group, :owner].each { |var|
if value = self.send(var)
obj[var] = value
@@ -1187,7 +1192,7 @@ Generated on #{Time.now}.
name = $1
unless @parent.include?(name)
raise ArgumentError,
- "Configuration parameter '%s' is undefined" %
+ "Settings parameter '%s' is undefined" %
name
end
}
@@ -1218,5 +1223,3 @@ Generated on #{Time.now}.
end
end
end
-
-# $Id$
diff --git a/lib/puppet/util/storage.rb b/lib/puppet/util/storage.rb
index a10183615..9e99057d9 100644
--- a/lib/puppet/util/storage.rb
+++ b/lib/puppet/util/storage.rb
@@ -46,7 +46,7 @@ class Puppet::Util::Storage
self.init
def self.load
- Puppet.config.use(:main)
+ Puppet.settings.use(:main)
unless File.exists?(Puppet[:statefile])
unless defined? @@state and ! @@state.nil?
@@ -99,5 +99,3 @@ class Puppet::Util::Storage
end
end
end
-
-# $Id$
diff --git a/spec/Rakefile b/spec/Rakefile
index 40d107312..bb2a75de5 100644
--- a/spec/Rakefile
+++ b/spec/Rakefile
@@ -2,9 +2,15 @@ require File.join(File.dirname(__FILE__), "spec_helper.rb")
require 'rake'
require 'spec/rake/spectask'
+basedir = File.dirname(__FILE__)
+puppetlibdir = File.join(basedir, "../lib")
+puppettestlibdir = File.join(basedir, "../test/lib")
+speclibdir = File.join(basedir, "lib")
+
desc "Run all spec unit tests"
Spec::Rake::SpecTask.new('unit') do |t|
t.spec_files = FileList['unit/**/*.rb']
+ t.libs = [puppetlibdir, puppettestlibdir, speclibdir]
end
task :default => [:unit]
diff --git a/spec/bin/spec b/spec/bin/spec
index a7e6ce0cb..aaf320f34 100755
--- a/spec/bin/spec
+++ b/spec/bin/spec
@@ -1,3 +1,4 @@
+#!/usr/bin/env ruby
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
require 'spec'
::Spec::Runner::CommandLine.run(ARGV, STDERR, STDOUT, true, true)
diff --git a/spec/integration/checksum.rb b/spec/integration/checksum.rb
new file mode 100755
index 000000000..f112f7502
--- /dev/null
+++ b/spec/integration/checksum.rb
@@ -0,0 +1,48 @@
+#!/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/checksum'
+
+describe Puppet::Checksum, " when using the file terminus" do
+ before do
+ Puppet[:checksum_terminus] = "file"
+
+ @content = "this is some content"
+ @sum = Puppet::Checksum.new(@content)
+
+ @file = Puppet::Checksum.indirection.terminus.path(@sum.checksum)
+ end
+
+ it "should store content at a path determined by its checksum" do
+ File.stubs(:directory?).returns(true)
+ filehandle = mock 'filehandle'
+ filehandle.expects(:print).with(@content)
+ File.expects(:open).with(@file, "w").yields(filehandle)
+
+ @sum.save
+ end
+
+ it "should retrieve stored content when the checksum is provided as the key" do
+ File.stubs(:exist?).returns(true)
+ File.expects(:read).with(@file).returns(@content)
+
+ newsum = Puppet::Checksum.find(@sum.checksum)
+
+ newsum.content.should == @content
+ end
+
+ it "should remove specified files when asked" do
+ File.stubs(:exist?).returns(true)
+ File.expects(:unlink).with(@file)
+
+ Puppet::Checksum.destroy(@sum)
+ end
+
+ after do
+ Puppet.settings.clear
+ end
+end
diff --git a/spec/integration/node.rb b/spec/integration/node.rb
new file mode 100755
index 000000000..8bc641bae
--- /dev/null
+++ b/spec/integration/node.rb
@@ -0,0 +1,46 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2007-9-23.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../spec_helper'
+
+require 'puppet/node'
+
+describe Puppet::Node, " when using the memory terminus" do
+ before do
+ @name = "me"
+ @node = Puppet::Node.new(@name)
+ Puppet[:node_terminus] = "memory"
+ end
+
+ it "should find no nodes by default" do
+ Puppet::Node.find(@name).should be_nil
+ end
+
+ it "should be able to find nodes that were previously saved" do
+ @node.save
+ Puppet::Node.find(@name).should equal(@node)
+ end
+
+ it "should replace existing saved nodes when a new node with the same name is saved" do
+ @node.save
+ two = Puppet::Node.new(@name)
+ two.save
+ Puppet::Node.find(@name).should equal(two)
+ end
+
+ it "should be able to remove previously saved nodes" do
+ @node.save
+ Puppet::Node.destroy(@node)
+ Puppet::Node.find(@name).should be_nil
+ end
+
+ it "should fail when asked to destroy a node that does not exist" do
+ proc { Puppet::Node.destroy(@node) }.should raise_error(ArgumentError)
+ end
+
+ after do
+ Puppet.settings.clear
+ end
+end
diff --git a/spec/lib/spec/dsl/behaviour.rb b/spec/lib/spec/dsl/behaviour.rb
index 5158bb673..159a0ba7e 100644
--- a/spec/lib/spec/dsl/behaviour.rb
+++ b/spec/lib/spec/dsl/behaviour.rb
@@ -1,6 +1,10 @@
+require(File.expand_path(File.dirname(__FILE__) + '../../../../../test/lib/puppettest/runnable_test.rb'))
+
module Spec
module DSL
- class EvalModule < Module; end
+ class EvalModule < Module;
+ include PuppetTest::RunnableTest
+ end
class Behaviour
extend BehaviourCallbacks
diff --git a/spec/lib/spec/runner/behaviour_runner.rb b/spec/lib/spec/runner/behaviour_runner.rb
index 1ac891f3c..078490e92 100644
--- a/spec/lib/spec/runner/behaviour_runner.rb
+++ b/spec/lib/spec/runner/behaviour_runner.rb
@@ -55,6 +55,8 @@ module Spec
def run_behaviours
@behaviours.each do |behaviour|
+ # LAK:NOTE: this 'runnable' test is Puppet-specific.
+ next unless behaviour.runnable?
behaviour.run(@options.reporter, @options.dry_run, @options.reverse, @options.timeout)
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index aa56fd93e..3017f272a 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,13 +1,21 @@
-dir = File.dirname(__FILE__)
-$:.unshift("#{dir}/lib").unshift("#{dir}/../lib")
+dir = File.expand_path(File.dirname(__FILE__))
+$:.unshift("#{dir}/lib")
+$:.unshift("#{dir}/../lib")
# Add the old test dir, so that we can still find mocha and spec
$:.unshift("#{dir}/../test/lib")
require 'mocha'
-require 'spec'
require 'puppettest'
+require 'spec'
Spec::Runner.configure do |config|
config.mock_with :mocha
+ config.prepend_before :each do
+ setup() if respond_to? :setup
+ end
+
+ config.prepend_after :each do
+ teardown() if respond_to? :teardown
+ end
end
diff --git a/spec/unit/indirector/code.rb b/spec/unit/indirector/code.rb
new file mode 100755
index 000000000..f34dcf402
--- /dev/null
+++ b/spec/unit/indirector/code.rb
@@ -0,0 +1,33 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'puppet/indirector/code'
+
+describe Puppet::Indirector::Code do
+ before do
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
+ @model = mock 'model'
+ @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
+ Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
+
+ @code_class = Class.new(Puppet::Indirector::Code) do
+ def self.to_s
+ "Testing"
+ end
+ end
+
+ @searcher = @code_class.new
+ end
+
+ it "should not have a find() method defined" do
+ @searcher.should_not respond_to(:find)
+ end
+
+ it "should not have a save() method defined" do
+ @searcher.should_not respond_to(:save)
+ end
+
+ it "should not have a destroy() method defined" do
+ @searcher.should_not respond_to(:destroy)
+ end
+end
diff --git a/spec/unit/indirector/code/configuration.rb b/spec/unit/indirector/code/configuration.rb
new file mode 100755
index 000000000..8652f342d
--- /dev/null
+++ b/spec/unit/indirector/code/configuration.rb
@@ -0,0 +1,158 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2007-9-23.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/code/configuration'
+
+describe Puppet::Indirector::Code::Configuration do
+ # LAK:TODO I have no idea how to do this, or even if it should be in this class or test or what.
+ # This is used for determining if the client should recompile its configuration, so it's not sufficient
+ # to recompile and compare versions.
+ # It might be that the right solution is to require configuration caching, and then compare the cached
+ # configuration version to the current version, via some querying mechanism (i.e., the client asks for just
+ # the configuration's 'up-to-date' attribute, rather than the whole configuration).
+ it "should provide a mechanism for determining if the client's configuration is up to date"
+end
+
+describe Puppet::Indirector::Code::Configuration do
+ before do
+ Puppet.expects(:version).returns(1)
+ Facter.expects(:value).with('fqdn').returns("my.server.com")
+ Facter.expects(:value).with('ipaddress').returns("my.ip.address")
+ end
+
+ it "should gather data about itself" do
+ Puppet::Indirector::Code::Configuration.new
+ end
+
+ it "should cache the server metadata and reuse it" do
+ compiler = Puppet::Indirector::Code::Configuration.new
+ node1 = stub 'node1', :merge => nil
+ node2 = stub 'node2', :merge => nil
+ compiler.stubs(:compile)
+ Puppet::Node.stubs(:search).with('node1').returns(node1)
+ Puppet::Node.stubs(:search).with('node2').returns(node2)
+
+ compiler.find('node1')
+ compiler.find('node2')
+ end
+end
+
+describe Puppet::Indirector::Code::Configuration, " when creating the interpreter" do
+ before do
+ @compiler = Puppet::Indirector::Code::Configuration.new
+ end
+
+ it "should not create the interpreter until it is asked for the first time" do
+ interp = mock 'interp'
+ Puppet::Parser::Interpreter.expects(:new).with({}).returns(interp)
+ @compiler.interpreter.should equal(interp)
+ end
+
+ it "should use the same interpreter for all compiles" do
+ interp = mock 'interp'
+ Puppet::Parser::Interpreter.expects(:new).with({}).returns(interp)
+ @compiler.interpreter.should equal(interp)
+ @compiler.interpreter.should equal(interp)
+ end
+
+ it "should provide a mechanism for setting the code to pass to the interpreter" do
+ @compiler.should respond_to(:code=)
+ end
+
+ it "should pass any specified code on to the interpreter when it is being initialized" do
+ code = "some code"
+ @compiler.code = code
+ interp = mock 'interp'
+ Puppet::Parser::Interpreter.expects(:new).with(:Code => code).returns(interp)
+ @compiler.send(:interpreter).should equal(interp)
+ end
+
+end
+
+describe Puppet::Indirector::Code::Configuration, " when finding nodes" do
+ before do
+ @compiler = Puppet::Indirector::Code::Configuration.new
+ @name = "me"
+ @node = mock 'node'
+ @compiler.stubs(:compile)
+ end
+
+ it "should look node information up via the Node class with the provided key" do
+ @node.stubs :merge
+ Puppet::Node.expects(:search).with(@name).returns(@node)
+ @compiler.find(@name)
+ end
+
+ it "should fail if it cannot find the node" do
+ @node.stubs :merge
+ Puppet::Node.expects(:search).with(@name).returns(nil)
+ proc { @compiler.find(@name) }.should raise_error(Puppet::Error)
+ end
+end
+
+describe Puppet::Indirector::Code::Configuration, " after finding nodes" do
+ before do
+ Puppet.expects(:version).returns(1)
+ Puppet.settings.stubs(:value).with(:node_name).returns("cert")
+ Facter.expects(:value).with('fqdn').returns("my.server.com")
+ Facter.expects(:value).with('ipaddress').returns("my.ip.address")
+ @compiler = Puppet::Indirector::Code::Configuration.new
+ @name = "me"
+ @node = mock 'node'
+ @compiler.stubs(:compile)
+ Puppet::Node.stubs(:search).with(@name).returns(@node)
+ end
+
+ it "should add the server's Puppet version to the node's parameters as 'serverversion'" do
+ @node.expects(:merge).with { |args| args["serverversion"] == "1" }
+ @compiler.find(@name)
+ end
+
+ it "should add the server's fqdn to the node's parameters as 'servername'" do
+ @node.expects(:merge).with { |args| args["servername"] == "my.server.com" }
+ @compiler.find(@name)
+ end
+
+ it "should add the server's IP address to the node's parameters as 'serverip'" do
+ @node.expects(:merge).with { |args| args["serverip"] == "my.ip.address" }
+ @compiler.find(@name)
+ end
+
+ # LAK:TODO This is going to be difficult, because this whole process is so
+ # far removed from the actual connection that the certificate information
+ # will be quite hard to come by, dum by, gum by.
+ it "should search for the name using the client certificate's DN if the :node_name setting is set to 'cert'"
+end
+
+describe Puppet::Indirector::Code::Configuration, " when creating configurations" do
+ before do
+ @compiler = Puppet::Indirector::Code::Configuration.new
+ @name = "me"
+ @node = stub 'node', :merge => nil, :name => @name, :environment => "yay"
+ Puppet::Node.stubs(:search).with(@name).returns(@node)
+ end
+
+ it "should pass the found node to the interpreter for compiling" do
+ config = mock 'config'
+ @compiler.interpreter.expects(:compile).with(@node)
+ @compiler.find(@name)
+ end
+
+ it "should return the results of compiling as the configuration" do
+ config = mock 'config'
+ @compiler.interpreter.expects(:compile).with(@node).returns(:configuration)
+ @compiler.find(@name).should == :configuration
+ end
+
+ it "should benchmark the compile process" do
+ @compiler.expects(:benchmark).with do |level, message|
+ level == :notice and message =~ /^Compiled configuration/
+ end
+ @compiler.interpreter.stubs(:compile).with(@node)
+ @compiler.find(@name)
+ end
+end
diff --git a/spec/unit/indirector/exec.rb b/spec/unit/indirector/exec.rb
new file mode 100755
index 000000000..42fbe0955
--- /dev/null
+++ b/spec/unit/indirector/exec.rb
@@ -0,0 +1,49 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/indirector/exec'
+
+describe Puppet::Indirector::Exec do
+ before do
+ @indirection = mock 'indirection'
+ Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection)
+ @exec_class = Class.new(Puppet::Indirector::Exec) do
+ def self.to_s
+ "Testing"
+ end
+
+ attr_accessor :command
+ end
+
+ @searcher = @exec_class.new
+ @searcher.command = ["/echo"]
+ end
+
+ it "should throw an exception if the command is not an array" do
+ @searcher.command = "/usr/bin/echo"
+ proc { @searcher.find("foo") }.should raise_error(Puppet::DevError)
+ end
+
+ it "should throw an exception if the command is not fully qualified" do
+ @searcher.command = ["mycommand"]
+ proc { @searcher.find("foo") }.should raise_error(ArgumentError)
+ end
+
+ it "should execute the command with the object name as the only argument" do
+ @searcher.expects(:execute).with(%w{/echo yay})
+ @searcher.find("yay")
+ end
+
+ it "should return the output of the script" do
+ @searcher.expects(:execute).with(%w{/echo yay}).returns("whatever")
+ @searcher.find("yay").should == "whatever"
+ end
+
+ it "should return nil when the command produces no output" do
+ @searcher.expects(:execute).with(%w{/echo yay}).returns(nil)
+ @searcher.find("yay").should be_nil
+ end
+
+ it "should be able to execute commands with multiple arguments"
+end
diff --git a/spec/unit/indirector/exec/node.rb b/spec/unit/indirector/exec/node.rb
new file mode 100755
index 000000000..47f4ce7a5
--- /dev/null
+++ b/spec/unit/indirector/exec/node.rb
@@ -0,0 +1,62 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/exec/node'
+
+describe Puppet::Indirector::Exec::Node, " when constructing the command to run" do
+ before do
+ @indirection = mock 'indirection'
+ Puppet.settings.stubs(:value).with(:external_nodes).returns("/echo")
+ @searcher = Puppet::Indirector::Exec::Node.new
+ end
+
+ it "should use the external_node script as the command" do
+ Puppet.expects(:[]).with(:external_nodes).returns("/bin/echo")
+ @searcher.command.should == %w{/bin/echo}
+ end
+
+ it "should throw an exception if no external node command is set" do
+ Puppet.expects(:[]).with(:external_nodes).returns("none")
+ proc { @searcher.find("foo") }.should raise_error(ArgumentError)
+ end
+end
+
+describe Puppet::Indirector::Exec::Node, " when handling the results of the command" do
+ before do
+ @indirection = mock 'indirection'
+ Puppet.settings.stubs(:value).with(:external_nodes).returns("/echo")
+ @searcher = Puppet::Indirector::Exec::Node.new
+ @node = stub 'node', :fact_merge => nil
+ @name = "yay"
+ Puppet::Node.expects(:new).with(@name).returns(@node)
+ @result = {}
+ # Use a local variable so the reference is usable in the execute() definition.
+ result = @result
+ @searcher.meta_def(:execute) do |command|
+ return YAML.dump(result)
+ end
+ end
+
+ it "should translate the YAML into a Node instance" do
+ # Use an empty hash
+ @searcher.find(@name).should equal(@node)
+ end
+
+ it "should set the resulting parameters as the node parameters" do
+ @result[:parameters] = {"a" => "b", "c" => "d"}
+ @node.expects(:parameters=).with "a" => "b", "c" => "d"
+ @searcher.find(@name)
+ end
+
+ it "should set the resulting classes as the node classes" do
+ @result[:classes] = %w{one two}
+ @node.expects(:classes=).with %w{one two}
+ @searcher.find(@name)
+ end
+
+ it "should merge the node's facts with its parameters" do
+ @node.expects(:fact_merge)
+ @searcher.find(@name)
+ end
+end
diff --git a/spec/unit/indirector/file.rb b/spec/unit/indirector/file.rb
new file mode 100755
index 000000000..cc86f9fa9
--- /dev/null
+++ b/spec/unit/indirector/file.rb
@@ -0,0 +1,160 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'puppet/indirector/file'
+
+module FileTerminusTesting
+ def setup
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
+ @model = mock 'model'
+ @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
+ Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
+
+ @file_class = Class.new(Puppet::Indirector::File) do
+ def self.to_s
+ "Testing"
+ end
+ end
+
+ @searcher = @file_class.new
+
+ @path = "/my/file"
+ @dir = "/my"
+ end
+end
+
+describe Puppet::Indirector::File, " when finding files" do
+ include FileTerminusTesting
+
+ it "should provide a method to return file contents at a specified path" do
+ @searcher.should respond_to(:find)
+ end
+
+ it "should return file contents as an instance of the model" do
+ content = "my content"
+
+ file = mock 'file'
+ @model.expects(:new).with(content).returns(file)
+
+ File.expects(:exist?).with(@path).returns(true)
+ File.expects(:read).with(@path).returns(content)
+ @searcher.find(@path)
+ end
+
+ it "should create the model instance with the content as the only argument to initialization" do
+ content = "my content"
+
+ file = mock 'file'
+ @model.expects(:new).with(content).returns(file)
+
+ File.expects(:exist?).with(@path).returns(true)
+ File.expects(:read).with(@path).returns(content)
+ @searcher.find(@path).should equal(file)
+ end
+
+ it "should return nil if no file is found" do
+ File.expects(:exist?).with(@path).returns(false)
+ @searcher.find(@path).should be_nil
+ end
+
+ it "should fail intelligently if a found file cannot be read" do
+ File.expects(:exist?).with(@path).returns(true)
+ File.expects(:read).with(@path).raises(RuntimeError)
+ proc { @searcher.find(@path) }.should raise_error(Puppet::Error)
+ end
+
+ it "should use the path() method to calculate the path if it exists" do
+ @searcher.meta_def(:path) do |name|
+ name.upcase
+ end
+
+ File.expects(:exist?).with(@path.upcase).returns(false)
+ @searcher.find(@path)
+ end
+end
+
+describe Puppet::Indirector::File, " when saving files" do
+ include FileTerminusTesting
+
+ it "should provide a method to save file contents at a specified path" do
+ filehandle = mock 'file'
+ content = "my content"
+ File.expects(:directory?).with(@dir).returns(true)
+ File.expects(:open).with(@path, "w").yields(filehandle)
+ filehandle.expects(:print).with(content)
+
+ file = stub 'file', :content => content, :path => @path, :name => @path
+
+ @searcher.save(file)
+ end
+
+ it "should fail intelligently if the file's parent directory does not exist" do
+ File.expects(:directory?).with(@dir).returns(false)
+
+ file = stub 'file', :path => @path, :name => @path
+
+ proc { @searcher.save(file) }.should raise_error(Puppet::Error)
+ end
+
+ it "should fail intelligently if a file cannot be written" do
+ filehandle = mock 'file'
+ content = "my content"
+ File.expects(:directory?).with(@dir).returns(true)
+ File.expects(:open).with(@path, "w").yields(filehandle)
+ filehandle.expects(:print).with(content).raises(ArgumentError)
+
+ file = stub 'file', :content => content, :path => @path, :name => @path
+
+ proc { @searcher.save(file) }.should raise_error(Puppet::Error)
+ end
+
+ it "should use the path() method to calculate the path if it exists" do
+ @searcher.meta_def(:path) do |name|
+ name.upcase
+ end
+
+ file = stub 'file', :name => "/yay"
+
+ File.expects(:open).with("/YAY", "w")
+ @searcher.save(file)
+ end
+end
+
+describe Puppet::Indirector::File, " when removing files" do
+ include FileTerminusTesting
+
+ it "should provide a method to remove files at a specified path" do
+ file = stub 'file', :path => @path, :name => @path
+ File.expects(:exist?).with(@path).returns(true)
+ File.expects(:unlink).with(@path)
+
+ @searcher.destroy(file)
+ end
+
+ it "should throw an exception if the file is not found" do
+ file = stub 'file', :path => @path, :name => @path
+ File.expects(:exist?).with(@path).returns(false)
+
+ proc { @searcher.destroy(file) }.should raise_error(Puppet::Error)
+ end
+
+ it "should fail intelligently if the file cannot be removed" do
+ file = stub 'file', :path => @path, :name => @path
+ File.expects(:exist?).with(@path).returns(true)
+ File.expects(:unlink).with(@path).raises(ArgumentError)
+
+ proc { @searcher.destroy(file) }.should raise_error(Puppet::Error)
+ end
+
+ it "should use the path() method to calculate the path if it exists" do
+ @searcher.meta_def(:path) do |name|
+ name.upcase
+ end
+
+ file = stub 'file', :name => "/yay"
+ File.expects(:exist?).with("/YAY").returns(true)
+ File.expects(:unlink).with("/YAY")
+
+ @searcher.destroy(file)
+ end
+end
diff --git a/spec/unit/indirector/file/checksum.rb b/spec/unit/indirector/file/checksum.rb
new file mode 100755
index 000000000..539bb973c
--- /dev/null
+++ b/spec/unit/indirector/file/checksum.rb
@@ -0,0 +1,142 @@
+#!/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/indirector/file/checksum'
+
+module FileChecksumTesting
+ def setup
+ Puppet.settings.stubs(:use)
+ @store = Puppet::Indirector::File::Checksum.new
+
+ @value = "70924d6fa4b2d745185fa4660703a5c0"
+ @sum = stub 'sum', :name => @value
+
+ @dir = "/what/ever"
+
+ Puppet.stubs(:[]).with(:bucketdir).returns(@dir)
+
+ @path = @store.path(@value)
+ end
+end
+
+describe Puppet::Indirector::File::Checksum do
+ it "should be a subclass of the File terminus class" do
+ Puppet::Indirector::File::Checksum.superclass.should equal(Puppet::Indirector::File)
+ end
+
+ it "should have documentation" do
+ Puppet::Indirector::File::Checksum.doc.should be_instance_of(String)
+ end
+end
+
+describe Puppet::Indirector::File::Checksum, " when initializing" do
+ it "should use the filebucket settings section" do
+ Puppet.settings.expects(:use).with(:filebucket)
+ Puppet::Indirector::File::Checksum.new
+ end
+end
+
+describe Puppet::Indirector::File::Checksum, " when determining file paths" do
+ include FileChecksumTesting
+
+ # I was previously passing the object in.
+ it "should use the value passed in to path() as the checksum" do
+ @value.expects(:name).never
+ @store.path(@value)
+ end
+
+ it "should use the value of the :bucketdir setting as the root directory" do
+ @path.should =~ %r{^#{@dir}}
+ end
+
+ it "should choose a path 8 directories deep with each directory name being the respective character in the checksum" do
+ dirs = @value[0..7].split("").join(File::SEPARATOR)
+ @path.should be_include(dirs)
+ end
+
+ it "should use the full checksum as the final directory name" do
+ File.basename(File.dirname(@path)).should == @value
+ end
+
+ it "should use 'contents' as the actual file name" do
+ File.basename(@path).should == "contents"
+ end
+
+ it "should use the bucketdir, the 8 sum character directories, the full checksum, and 'contents' as the full file name" do
+ @path.should == [@dir, @value[0..7].split(""), @value, "contents"].flatten.join(File::SEPARATOR)
+ end
+end
+
+describe Puppet::Indirector::File::Checksum, " when retrieving files" do
+ include FileChecksumTesting
+
+ # The smallest test that will use the calculated path
+ it "should look for the calculated path" do
+ File.expects(:exist?).with(@path).returns(false)
+ @store.find(@value)
+ end
+
+ it "should return an instance of Puppet::Checksum created with the content if the file exists" do
+ content = "my content"
+ sum = stub 'file'
+ Puppet::Checksum.expects(:new).with(content).returns(sum)
+
+ File.expects(:exist?).with(@path).returns(true)
+ File.expects(:read).with(@path).returns(content)
+
+ @store.find(@value).should equal(sum)
+ end
+
+ it "should return nil if no file is found" do
+ File.expects(:exist?).with(@path).returns(false)
+ @store.find(@value).should be_nil
+ end
+
+ it "should fail intelligently if a found file cannot be read" do
+ File.expects(:exist?).with(@path).returns(true)
+ File.expects(:read).with(@path).raises(RuntimeError)
+ proc { @store.find(@value) }.should raise_error(Puppet::Error)
+ end
+end
+
+describe Puppet::Indirector::File::Checksum, " when saving files" do
+ include FileChecksumTesting
+
+ # LAK:FIXME I don't know how to include in the spec the fact that we're
+ # using the superclass's save() method and thus are acquiring all of
+ # it's behaviours.
+ it "should save the content to the calculated path" do
+ File.stubs(:directory?).with(File.dirname(@path)).returns(true)
+ File.expects(:open).with(@path, "w")
+
+ file = stub 'file', :name => @value
+ @store.save(file)
+ end
+
+ it "should make any directories necessary for storage" do
+ FileUtils.expects(:mkdir_p).with do |arg|
+ File.umask == 0007 and arg == File.dirname(@path)
+ end
+ File.expects(:directory?).with(File.dirname(@path)).returns(true)
+ File.expects(:open).with(@path, "w")
+
+ file = stub 'file', :name => @value
+ @store.save(file)
+ end
+end
+
+describe Puppet::Indirector::File::Checksum, " when deleting files" do
+ include FileChecksumTesting
+
+ it "should remove the file at the calculated path" do
+ File.expects(:exist?).with(@path).returns(true)
+ File.expects(:unlink).with(@path)
+
+ file = stub 'file', :name => @value
+ @store.destroy(file)
+ end
+end
diff --git a/spec/unit/indirector/indirection.rb b/spec/unit/indirector/indirection.rb
new file mode 100755
index 000000000..326b6b470
--- /dev/null
+++ b/spec/unit/indirector/indirection.rb
@@ -0,0 +1,160 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/indirector'
+
+describe Puppet::Indirector::Indirection, " when initializing" do
+ it "should keep a reference to the indirecting model" do
+ model = mock 'model'
+ @indirection = Puppet::Indirector::Indirection.new(model, :myind)
+ @indirection.model.should equal(model)
+ end
+
+ it "should set the name" do
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :myind)
+ @indirection.name.should == :myind
+ end
+
+ it "should require indirections to have unique names" do
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test)
+ proc { Puppet::Indirector::Indirection.new(:test) }.should raise_error(ArgumentError)
+ end
+
+ after do
+ @indirection.delete if defined? @indirection
+ end
+end
+
+describe Puppet::Indirector::Indirection, " when managing indirection instances" do
+ it "should allow an indirection to be retrieved by name" do
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test)
+ Puppet::Indirector::Indirection.instance(:test).should equal(@indirection)
+ end
+
+ it "should return nil when the named indirection has not been created" do
+ Puppet::Indirector::Indirection.instance(:test).should be_nil
+ end
+
+ after do
+ @indirection.delete if defined? @indirection
+ end
+end
+
+describe Puppet::Indirector::Indirection, " when choosing terminus types" do
+ before do
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test)
+ @terminus = mock 'terminus'
+ @terminus_class = stub 'terminus class', :new => @terminus
+ end
+
+ it "should follow a convention on using per-model configuration parameters to determine the terminus class" do
+ Puppet.settings.expects(:valid?).with('test_terminus').returns(true)
+ Puppet.settings.expects(:value).with('test_terminus').returns(:foo)
+ Puppet::Indirector::Terminus.expects(:terminus_class).with(:foo, :test).returns(@terminus_class)
+ @indirection.terminus.should equal(@terminus)
+ end
+
+ it "should use a default system-wide configuration parameter parameter to determine the terminus class when no
+ per-model configuration parameter is available" do
+ Puppet.settings.expects(:valid?).with('test_terminus').returns(false)
+ Puppet.settings.expects(:value).with(:default_terminus).returns(:foo)
+ Puppet::Indirector::Terminus.expects(:terminus_class).with(:foo, :test).returns(@terminus_class)
+ @indirection.terminus.should equal(@terminus)
+ end
+
+ it "should select the specified terminus class if a name is provided" do
+ Puppet::Indirector::Terminus.expects(:terminus_class).with(:foo, :test).returns(@terminus_class)
+ @indirection.terminus(:foo).should equal(@terminus)
+ end
+
+ it "should fail when the terminus class name is an empty string" do
+ proc { @indirection.terminus("") }.should raise_error(ArgumentError)
+ end
+
+ it "should fail when the terminus class name is nil" do
+ proc { @indirection.terminus(nil) }.should raise_error(ArgumentError)
+ end
+
+ it "should fail when the specified terminus class cannot be found" do
+ Puppet::Indirector::Terminus.expects(:terminus_class).with(:foo, :test).returns(nil)
+ proc { @indirection.terminus(:foo) }.should raise_error(ArgumentError)
+ end
+
+ after do
+ @indirection.delete if defined? @indirection
+ end
+end
+
+describe Puppet::Indirector::Indirection, " when managing terminus instances" do
+ before do
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test)
+ @terminus = mock 'terminus'
+ @terminus_class = mock 'terminus class'
+ Puppet::Indirector::Terminus.stubs(:terminus_class).with(:foo, :test).returns(@terminus_class)
+ end
+
+ it "should create an instance of the chosen terminus class" do
+ @terminus_class.stubs(:new).returns(@terminus)
+ @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)
+ @indirection.terminus(:foo).should equal(@terminus)
+ @indirection.terminus(:foo).should equal(@terminus)
+ end
+
+ it "should not create a terminus instance until one is actually needed" do
+ Puppet::Indirector.expects(:terminus).never
+ indirection = Puppet::Indirector::Indirection.new(mock('model'), :lazytest)
+ end
+
+ after do
+ @indirection.delete
+ Puppet::Indirector::Indirection.clear_cache
+ end
+end
+
+describe Puppet::Indirector::Indirection do
+ before do
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test)
+ @terminus = mock 'terminus'
+ @indirection.stubs(:terminus).returns(@terminus)
+ end
+
+ it "should handle lookups of a model instance by letting the appropriate terminus perform the lookup" do
+ @terminus.expects(:find).with(:mything).returns(:whev)
+ @indirection.find(:mything).should == :whev
+ end
+
+ it "should handle removing model instances from a terminus letting the appropriate terminus remove the instance" do
+ @terminus.expects(:destroy).with(:mything).returns(:whev)
+ @indirection.destroy(:mything).should == :whev
+ end
+
+ it "should handle searching for model instances by letting the appropriate terminus find the matching instances" do
+ @terminus.expects(:search).with(:mything).returns(:whev)
+ @indirection.search(:mything).should == :whev
+ end
+
+ it "should handle storing a model instance by letting the appropriate terminus store the instance" do
+ @terminus.expects(:save).with(:mything).returns(:whev)
+ @indirection.save(:mything).should == :whev
+ end
+
+ after do
+ @indirection.delete
+ Puppet::Indirector::Indirection.clear_cache
+ end
+end
diff --git a/spec/unit/indirector/indirector.rb b/spec/unit/indirector/indirector.rb
new file mode 100755
index 000000000..1702bf51f
--- /dev/null
+++ b/spec/unit/indirector/indirector.rb
@@ -0,0 +1,86 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/defaults'
+require 'puppet/indirector'
+
+describe Puppet::Indirector, " when available to a model" do
+ before do
+ @thingie = Class.new do
+ extend Puppet::Indirector
+ end
+ end
+
+ it "should provide a way for the model to register an indirection under a name" do
+ @thingie.should respond_to(:indirects)
+ end
+end
+
+describe Puppet::Indirector, "when registering an indirection" do
+ before do
+ @thingie = Class.new do
+ extend Puppet::Indirector
+ end
+ end
+
+ it "should require a name when registering a model" do
+ Proc.new {@thingie.send(:indirects) }.should raise_error(ArgumentError)
+ end
+
+ it "should create an indirection instance to manage each indirecting model" do
+ @indirection = @thingie.indirects(:test)
+ @indirection.should be_instance_of(Puppet::Indirector::Indirection)
+ end
+
+ it "should not allow a model to register under multiple names" do
+ # Keep track of the indirection instance so we can delete it on cleanup
+ @indirection = @thingie.indirects :first
+ Proc.new { @thingie.indirects :second }.should raise_error(ArgumentError)
+ end
+
+ it "should make the indirection available via an accessor" do
+ @indirection = @thingie.indirects :first
+ @thingie.indirection.should equal(@indirection)
+ end
+
+ after do
+ @indirection.delete if @indirection
+ end
+end
+
+describe Puppet::Indirector, " when redirecting a model" do
+ before do
+ @thingie = Class.new do
+ extend Puppet::Indirector
+ end
+ @mock_terminus = mock('Terminus')
+ @indirection = @thingie.send(:indirects, :test)
+ @thingie.expects(:indirection).returns(@mock_terminus)
+ end
+
+ it "should give the model the ability to lookup a model instance by letting the indirection perform the lookup" do
+ @mock_terminus.expects(:find)
+ @thingie.find
+ end
+
+ it "should give the model the ability to remove model instances from a terminus by letting the indirection remove the instance" do
+ @mock_terminus.expects(:destroy)
+ @thingie.destroy
+ end
+
+ it "should give the model the ability to search for model instances by letting the indirection find the matching instances" do
+ @mock_terminus.expects(:search)
+ @thingie.search
+ end
+
+ it "should give the model the ability to store a model instance by letting the indirection store the instance" do
+ thing = @thingie.new
+ @mock_terminus.expects(:save).with(thing)
+ thing.save
+ end
+
+ after do
+ @indirection.delete
+ end
+end
diff --git a/spec/unit/indirector/ldap.rb b/spec/unit/indirector/ldap.rb
new file mode 100755
index 000000000..fe9408986
--- /dev/null
+++ b/spec/unit/indirector/ldap.rb
@@ -0,0 +1,147 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/indirector/ldap'
+
+describe Puppet::Indirector::Ldap, " when searching ldap" do
+ before do
+ @indirection = mock 'indirection'
+ Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
+ @ldap_class = Class.new(Puppet::Indirector::Ldap) do
+ def self.to_s
+ "Testing"
+ end
+ end
+
+ @connection = mock 'ldap'
+
+ @searcher = @ldap_class.new
+
+ # Stub everything, and we can selectively replace with an expect as
+ # we need to for testing.
+ @searcher.stubs(:connection).returns(@connection)
+ @searcher.stubs(:search_filter).returns(:filter)
+ @searcher.stubs(:search_base).returns(:base)
+ @searcher.stubs(:process)
+ end
+
+ it "should call the ldapsearch method with the name being searched for" do
+ @searcher.expects(:ldapsearch).with("yay")
+ @searcher.find "yay"
+ end
+
+ it "should fail if no block is passed to the ldapsearch method" do
+ proc { @searcher.ldapsearch("blah") }.should raise_error(ArgumentError)
+ end
+
+ it "should use the results of the ldapbase method as the ldap search base" do
+ @searcher.stubs(:search_base).returns("mybase")
+ @connection.expects(:search).with do |*args|
+ args[0].should == "mybase"
+ true
+ end
+ @searcher.find "yay"
+ end
+
+ it "should default to the value of the :search_base setting as the result of the ldapbase method" do
+ Puppet.expects(:[]).with(:ldapbase).returns("myldapbase")
+ searcher = @ldap_class.new
+ searcher.search_base.should == "myldapbase"
+ end
+
+ it "should use the results of the :search_attributes method as the list of attributes to return" do
+ @searcher.stubs(:search_attributes).returns(:myattrs)
+ @connection.expects(:search).with do |*args|
+ args[3].should == :myattrs
+ true
+ end
+ @searcher.find "yay"
+ end
+
+ it "should use the results of the :search_filter method as the search filter" do
+ @searcher.stubs(:search_filter).with("yay").returns("yay's filter")
+ @connection.expects(:search).with do |*args|
+ args[2].should == "yay's filter"
+ true
+ end
+ @searcher.find "yay"
+ end
+
+ it "should use depth 2 when searching" do
+ @connection.expects(:search).with do |*args|
+ args[1].should == 2
+ true
+ end
+ @searcher.find "yay"
+ end
+
+ it "should call process() on the first found entry" do
+ @connection.expects(:search).yields("myresult")
+ @searcher.expects(:process).with("yay", "myresult")
+ @searcher.find "yay"
+ end
+
+ it "should reconnect and retry the search if there is a failure" do
+ run = false
+ @connection.stubs(:search).with do |*args|
+ if run
+ true
+ else
+ run = true
+ raise "failed"
+ end
+ end.yields("myresult")
+ @searcher.expects(:process).with("yay", "myresult")
+
+ @searcher.find "yay"
+ end
+
+ it "should not reconnect on failure more than once" do
+ count = 0
+ @connection.stubs(:search).with do |*args|
+ count += 1
+ raise ArgumentError, "yay"
+ end
+ proc { @searcher.find("whatever") }.should raise_error(Puppet::Error)
+ count.should == 2
+ end
+
+ it "should return true if an entry is found" do
+ @connection.expects(:search).yields("result")
+ @searcher.ldapsearch("whatever") { |r| }.should be_true
+ end
+end
+
+describe Puppet::Indirector::Ldap, " when connecting to ldap" do
+ confine "LDAP is not available" => Puppet.features.ldap?
+ confine "No LDAP test data for networks other than Luke's" => Facter.value(:domain) == "madstop.com"
+
+ it "should only create the ldap connection when asked for it the first time"
+
+ it "should throw an exception if it cannot connect to LDAP"
+
+ it "should use SSL when the :ldapssl setting is true"
+
+ it "should connect to the server specified in the :ldapserver setting"
+
+ it "should use the port specified in the :ldapport setting"
+
+ it "should use protocol version 3"
+
+ it "should follow referrals"
+
+ it "should use the user specified in the :ldapuser setting"
+
+ it "should use the password specified in the :ldappassord setting"
+
+ it "should have an ldap method that returns an LDAP connection object"
+
+ it "should fail when LDAP support is missing"
+end
+
+describe Puppet::Indirector::Ldap, " when reconnecting to ldap" do
+ confine "Not running on culain as root" => (Puppet::Util::SUIDManager.uid == 0 and Facter.value("hostname") == "culain")
+
+ it "should reconnect to ldap when connections are lost"
+end
diff --git a/spec/unit/indirector/ldap/node.rb b/spec/unit/indirector/ldap/node.rb
new file mode 100755
index 000000000..37953db19
--- /dev/null
+++ b/spec/unit/indirector/ldap/node.rb
@@ -0,0 +1,240 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/ldap/node'
+
+module LdapNodeSearching
+ def setup
+ @searcher = Puppet::Indirector::Ldap::Node.new
+ @entries = {}
+ entries = @entries
+
+ @connection = mock 'connection'
+ @entry = mock 'entry'
+ @connection.stubs(:search).yields(@entry)
+ @searcher.stubs(:connection).returns(@connection)
+ @searcher.stubs(:class_attributes).returns([])
+ @searcher.stubs(:parent_attribute).returns(nil)
+ @searcher.stubs(:search_base).returns(:yay)
+ @searcher.stubs(:search_filter).returns(:filter)
+
+ @node = mock 'node'
+ @node.stubs(:fact_merge)
+ @name = "mynode"
+ Puppet::Node.stubs(:new).with(@name).returns(@node)
+ end
+end
+
+describe Puppet::Indirector::Ldap::Node, " when searching for nodes" do
+ include LdapNodeSearching
+
+ it "should return nil if no results are found in ldap" do
+ @connection.stubs(:search)
+ @searcher.find("mynode").should be_nil
+ end
+
+ it "should return a node object if results are found in ldap" do
+ @entry.stubs(:to_hash).returns({})
+ @searcher.find("mynode").should equal(@node)
+ end
+
+ it "should deduplicate class values" do
+ @entry.stubs(:to_hash).returns({})
+ @searcher.stubs(:class_attributes).returns(%w{one two})
+ @entry.stubs(:vals).with("one").returns(%w{a b})
+ @entry.stubs(:vals).with("two").returns(%w{b c})
+ @node.expects(:classes=).with(%w{a b c})
+ @searcher.find("mynode")
+ end
+
+ it "should add any values stored in the class_attributes attributes to the node classes" do
+ @entry.stubs(:to_hash).returns({})
+ @searcher.stubs(:class_attributes).returns(%w{one two})
+ @entry.stubs(:vals).with("one").returns(%w{a b})
+ @entry.stubs(:vals).with("two").returns(%w{c d})
+ @node.expects(:classes=).with(%w{a b c d})
+ @searcher.find("mynode")
+ end
+
+ it "should add all entry attributes as node parameters" do
+ @entry.stubs(:to_hash).returns("one" => ["two"], "three" => ["four"])
+ @node.expects(:parameters=).with("one" => "two", "three" => "four")
+ @searcher.find("mynode")
+ end
+
+ it "should retain false parameter values" do
+ @entry.stubs(:to_hash).returns("one" => [false])
+ @node.expects(:parameters=).with("one" => false)
+ @searcher.find("mynode")
+ end
+
+ it "should turn single-value parameter value arrays into single non-arrays" do
+ @entry.stubs(:to_hash).returns("one" => ["a"])
+ @node.expects(:parameters=).with("one" => "a")
+ @searcher.find("mynode")
+ end
+
+ it "should keep multi-valued parametes as arrays" do
+ @entry.stubs(:to_hash).returns("one" => ["a", "b"])
+ @node.expects(:parameters=).with("one" => ["a", "b"])
+ @searcher.find("mynode")
+ end
+end
+
+describe Puppet::Indirector::Ldap::Node, " when a parent node exists" do
+ include LdapNodeSearching
+
+ before do
+ @parent = mock 'parent'
+ @parent_parent = mock 'parent_parent'
+
+ @searcher.meta_def(:search_filter) do |name|
+ return name
+ end
+ @connection.stubs(:search).with { |*args| args[2] == @name }.yields(@entry)
+ @connection.stubs(:search).with { |*args| args[2] == 'parent' }.yields(@parent)
+ @connection.stubs(:search).with { |*args| args[2] == 'parent_parent' }.yields(@parent_parent)
+
+ @searcher.stubs(:parent_attribute).returns(:parent)
+ end
+
+ it "should add any parent classes to the node's classes" do
+ @entry.stubs(:to_hash).returns({})
+ @entry.stubs(:vals).with(:parent).returns(%w{parent})
+ @entry.stubs(:vals).with("one").returns(%w{a b})
+
+ @parent.stubs(:to_hash).returns({})
+ @parent.stubs(:vals).with("one").returns(%w{c d})
+ @parent.stubs(:vals).with(:parent).returns(nil)
+
+ @searcher.stubs(:class_attributes).returns(%w{one})
+ @node.expects(:classes=).with(%w{a b c d})
+ @searcher.find("mynode")
+ end
+
+ it "should add any parent parameters to the node's parameters" do
+ @entry.stubs(:to_hash).returns("one" => "two")
+ @entry.stubs(:vals).with(:parent).returns(%w{parent})
+
+ @parent.stubs(:to_hash).returns("three" => "four")
+ @parent.stubs(:vals).with(:parent).returns(nil)
+
+ @node.expects(:parameters=).with("one" => "two", "three" => "four")
+ @searcher.find("mynode")
+ end
+
+ it "should prefer node parameters over parent parameters" do
+ @entry.stubs(:to_hash).returns("one" => "two")
+ @entry.stubs(:vals).with(:parent).returns(%w{parent})
+
+ @parent.stubs(:to_hash).returns("one" => "three")
+ @parent.stubs(:vals).with(:parent).returns(nil)
+
+ @node.expects(:parameters=).with("one" => "two")
+ @searcher.find("mynode")
+ end
+
+ it "should recursively look up parent information" do
+ @entry.stubs(:to_hash).returns("one" => "two")
+ @entry.stubs(:vals).with(:parent).returns(%w{parent})
+
+ @parent.stubs(:to_hash).returns("three" => "four")
+ @parent.stubs(:vals).with(:parent).returns(['parent_parent'])
+
+ @parent_parent.stubs(:to_hash).returns("five" => "six")
+ @parent_parent.stubs(:vals).with(:parent).returns(nil)
+ @parent_parent.stubs(:vals).with(:parent).returns(nil)
+
+ @node.expects(:parameters=).with("one" => "two", "three" => "four", "five" => "six")
+ @searcher.find("mynode")
+ end
+
+ it "should not allow loops in parent declarations" do
+ @entry.stubs(:to_hash).returns("one" => "two")
+ @entry.stubs(:vals).with(:parent).returns(%w{parent})
+
+ @parent.stubs(:to_hash).returns("three" => "four")
+ @parent.stubs(:vals).with(:parent).returns([@name])
+ proc { @searcher.find("mynode") }.should raise_error(ArgumentError)
+ end
+end
+
+describe Puppet::Indirector::Ldap::Node, " when developing the search query" do
+ before do
+ @searcher = Puppet::Indirector::Ldap::Node.new
+ end
+
+ it "should return the value of the :ldapclassattrs split on commas as the class attributes" do
+ Puppet.stubs(:[]).with(:ldapclassattrs).returns("one,two")
+ @searcher.class_attributes.should == %w{one two}
+ end
+
+ it "should return nil as the parent attribute if the :ldapparentattr is set to an empty string" do
+ Puppet.stubs(:[]).with(:ldapparentattr).returns("")
+ @searcher.parent_attribute.should be_nil
+ end
+
+ it "should return the value of the :ldapparentattr as the parent attribute" do
+ Puppet.stubs(:[]).with(:ldapparentattr).returns("pere")
+ @searcher.parent_attribute.should == "pere"
+ end
+
+ it "should use the value of the :ldapstring as the search filter" do
+ Puppet.stubs(:[]).with(:ldapstring).returns("mystring")
+ @searcher.search_filter("testing").should == "mystring"
+ end
+
+ it "should replace '%s' with the node name in the search filter if it is present" do
+ Puppet.stubs(:[]).with(:ldapstring).returns("my%sstring")
+ @searcher.search_filter("testing").should == "mytestingstring"
+ end
+
+ it "should not modify the global :ldapstring when replacing '%s' in the search filter" do
+ filter = mock 'filter'
+ filter.expects(:include?).with("%s").returns(true)
+ filter.expects(:gsub).with("%s", "testing").returns("mynewstring")
+ Puppet.stubs(:[]).with(:ldapstring).returns(filter)
+ @searcher.search_filter("testing").should == "mynewstring"
+ end
+end
+
+describe Puppet::Indirector::Ldap::Node, " when deciding attributes to search for" do
+ before do
+ @searcher = Puppet::Indirector::Ldap::Node.new
+ end
+
+ it "should use 'nil' if the :ldapattrs setting is 'all'" do
+ Puppet.stubs(:[]).with(:ldapattrs).returns("all")
+ @searcher.search_attributes.should be_nil
+ end
+
+ it "should split the value of :ldapattrs on commas and use the result as the attribute list" do
+ Puppet.stubs(:[]).with(:ldapattrs).returns("one,two")
+ @searcher.stubs(:class_attributes).returns([])
+ @searcher.stubs(:parent_attribute).returns(nil)
+ @searcher.search_attributes.should == %w{one two}
+ end
+
+ it "should add the class attributes to the search attributes if not returning all attributes" do
+ Puppet.stubs(:[]).with(:ldapattrs).returns("one,two")
+ @searcher.stubs(:class_attributes).returns(%w{three four})
+ @searcher.stubs(:parent_attribute).returns(nil)
+ # Sort them so i don't have to care about return order
+ @searcher.search_attributes.sort.should == %w{one two three four}.sort
+ end
+
+ it "should add the parent attribute to the search attributes if not returning all attributes" do
+ Puppet.stubs(:[]).with(:ldapattrs).returns("one,two")
+ @searcher.stubs(:class_attributes).returns([])
+ @searcher.stubs(:parent_attribute).returns("parent")
+ @searcher.search_attributes.sort.should == %w{one two parent}.sort
+ end
+
+ it "should not add nil parent attributes to the search attributes" do
+ Puppet.stubs(:[]).with(:ldapattrs).returns("one,two")
+ @searcher.stubs(:class_attributes).returns([])
+ @searcher.stubs(:parent_attribute).returns(nil)
+ @searcher.search_attributes.should == %w{one two}
+ end
+end
diff --git a/spec/unit/indirector/memory.rb b/spec/unit/indirector/memory.rb
new file mode 100755
index 000000000..ac6f055ce
--- /dev/null
+++ b/spec/unit/indirector/memory.rb
@@ -0,0 +1,53 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'puppet/indirector/memory'
+
+describe "A Memory Terminus", :shared => true do
+ it "should find no instances by default" do
+ @searcher.find(@name).should be_nil
+ end
+
+ it "should be able to find instances that were previously saved" do
+ @searcher.save(@instance)
+ @searcher.find(@name).should equal(@instance)
+ end
+
+ it "should replace existing saved instances when a new instance with the same name is saved" do
+ @searcher.save(@instance)
+ two = stub 'second', :name => @name
+ @searcher.save(two)
+ @searcher.find(@name).should equal(two)
+ end
+
+ it "should be able to remove previously saved instances" do
+ @searcher.save(@instance)
+ @searcher.destroy(@instance)
+ @searcher.find(@name).should be_nil
+ end
+
+ it "should fail when asked to destroy an instance that does not exist" do
+ proc { @searcher.destroy(@instance) }.should raise_error(ArgumentError)
+ end
+end
+
+describe Puppet::Indirector::Memory do
+ it_should_behave_like "A Memory Terminus"
+
+ before do
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
+ @model = mock 'model'
+ @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
+ Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
+
+ @memory_class = Class.new(Puppet::Indirector::Memory) do
+ def self.to_s
+ "Testing"
+ end
+ end
+
+ @searcher = @memory_class.new
+ @name = "me"
+ @instance = stub 'instance', :name => @name
+ end
+end
diff --git a/spec/unit/indirector/memory/node.rb b/spec/unit/indirector/memory/node.rb
new file mode 100755
index 000000000..cba4af53a
--- /dev/null
+++ b/spec/unit/indirector/memory/node.rb
@@ -0,0 +1,19 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/memory/node'
+
+# All of our behaviour is described here, so we always have to
+# include it.
+require 'unit/indirector/memory'
+
+describe Puppet::Indirector::Memory::Node do
+ before do
+ @name = "me"
+ @searcher = Puppet::Indirector::Memory::Node.new
+ @instance = stub 'instance', :name => @name
+ end
+
+ it_should_behave_like "A Memory Terminus"
+end
diff --git a/spec/unit/indirector/null.rb b/spec/unit/indirector/null.rb
new file mode 100755
index 000000000..9e1dcb07c
--- /dev/null
+++ b/spec/unit/indirector/null.rb
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'puppet/indirector/null'
+
+describe Puppet::Indirector::Null do
+ before do
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
+ @model = mock 'model'
+ @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
+ Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
+
+ @null_class = Class.new(Puppet::Indirector::Null) do
+ def self.to_s
+ "Testing"
+ end
+ end
+
+ @searcher = @null_class.new
+ end
+
+ it "should return return an instance of the indirected model" do
+ object = mock 'object'
+ @model.expects(:new).with("yay").returns object
+ @searcher.find("yay").should equal(object)
+ end
+end
diff --git a/spec/unit/indirector/null/node.rb b/spec/unit/indirector/null/node.rb
new file mode 100755
index 000000000..c589e5820
--- /dev/null
+++ b/spec/unit/indirector/null/node.rb
@@ -0,0 +1,18 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/indirector/null/node'
+
+describe Puppet::Indirector::Null::Node do
+ before do
+ @searcher = Puppet::Indirector::Null::Node.new
+ end
+
+ it "should call node_merge() on the returned node" do
+ node = mock 'node'
+ Puppet::Node.expects(:new).with("mynode").returns(node)
+ node.expects(:fact_merge)
+ @searcher.find("mynode")
+ end
+end
diff --git a/spec/unit/indirector/terminus.rb b/spec/unit/indirector/terminus.rb
new file mode 100755
index 000000000..dc86cf315
--- /dev/null
+++ b/spec/unit/indirector/terminus.rb
@@ -0,0 +1,226 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'puppet/defaults'
+require 'puppet/indirector'
+
+describe Puppet::Indirector::Terminus do
+ before do
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
+
+ @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil
+ Puppet::Indirector::Indirection.stubs(:instance).with(:mystuff).returns(@indirection)
+ @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do
+ def self.to_s
+ "Abstract"
+ end
+ end
+ @terminus = Class.new(@abstract_terminus) do
+ def self.to_s
+ "Terminus::Type::MyStuff"
+ end
+ end
+ end
+
+ it "should provide a method for setting terminus class documentation" do
+ @terminus.should respond_to(:desc)
+ end
+
+ it "should support a class-level name attribute" do
+ @terminus.should respond_to(:name)
+ end
+
+ it "should support a class-level indirection attribute" do
+ @terminus.should respond_to(:indirection)
+ end
+
+ it "should support a class-level terminus-type attribute" do
+ @terminus.should respond_to(:terminus_type)
+ end
+
+ it "should support a class-level model attribute" do
+ @terminus.should respond_to(:model)
+ end
+
+ it "should accept indirection instances as its indirection" do
+ indirection = stub 'indirection', :is_a? => true, :register_terminus_type => nil
+ proc { @terminus.indirection = indirection }.should_not raise_error
+ @terminus.indirection.should equal(indirection)
+ end
+
+ it "should look up indirection instances when only a name has been provided" do
+ indirection = mock 'indirection'
+ Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns(indirection)
+ @terminus.indirection = :myind
+ @terminus.indirection.should equal(indirection)
+ end
+
+ it "should fail when provided a name that does not resolve to an indirection" do
+ Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns(nil)
+ proc { @terminus.indirection = :myind }.should raise_error(ArgumentError)
+
+ # It shouldn't overwrite our existing one (or, more normally, it shouldn't set
+ # anything).
+ @terminus.indirection.should equal(@indirection)
+ end
+end
+
+# LAK: This could reasonably be in the Indirection instances, too. It doesn't make
+# a whole heckuva lot of difference, except that with the instance loading in
+# the Terminus base class, we have to have a check to see if we're already
+# instance-loading a given terminus class type.
+describe Puppet::Indirector::Terminus, " when managing terminus classes" do
+ it "should provide a method for registering terminus classes" do
+ Puppet::Indirector::Terminus.should respond_to(:register_terminus_class)
+ end
+
+ it "should provide a method for returning terminus classes by name and type" do
+ terminus = stub 'terminus_type', :terminus_type => :abstract, :name => :whatever
+ Puppet::Indirector::Terminus.register_terminus_class(terminus)
+ Puppet::Indirector::Terminus.terminus_class(:abstract, :whatever).should equal(terminus)
+ end
+
+ it "should set up autoloading for any terminus class types requested" do
+ Puppet::Indirector::Terminus.expects(:instance_load).with(:test2, "puppet/indirector/test2")
+ Puppet::Indirector::Terminus.terminus_class(:test2, :whatever)
+ end
+
+ it "should load terminus classes that are not found" do
+ # Set up instance loading; it would normally happen automatically
+ Puppet::Indirector::Terminus.instance_load :test1, "puppet/indirector/test1"
+ Puppet::Indirector::Terminus.instance_loader(:test1).expects(:load).with(:yay)
+ Puppet::Indirector::Terminus.terminus_class(:test1, :yay)
+ end
+
+ it "should fail when no indirection can be found" do
+ Puppet::Indirector::Indirection.expects(:instance).with(:myindirection).returns(nil)
+
+ @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do
+ def self.to_s
+ "Abstract"
+ end
+ end
+ proc {
+ @terminus = Class.new(@abstract_terminus) do
+ def self.to_s
+ "MyIndirection"
+ end
+ end
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should register the terminus class with the terminus base class" do
+ Puppet::Indirector::Terminus.expects(:register_terminus_class).with do |type|
+ type.terminus_type == :abstract and type.name == :myindirection
+ end
+ @indirection = stub 'indirection', :name => :myind, :register_terminus_type => nil
+ Puppet::Indirector::Indirection.expects(:instance).with(:myindirection).returns(@indirection)
+
+ @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do
+ def self.to_s
+ "Abstract"
+ end
+ end
+
+ @terminus = Class.new(@abstract_terminus) do
+ def self.to_s
+ "MyIndirection"
+ end
+ end
+ end
+end
+
+describe Puppet::Indirector::Terminus, " when creating terminus class types" do
+ before do
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
+ @subclass = Class.new(Puppet::Indirector::Terminus) do
+ def self.to_s
+ "Puppet::Indirector::Terminus::MyTermType"
+ end
+ end
+ end
+
+ it "should set the name of the abstract subclass to be its class constant" do
+ @subclass.name.should equal(:mytermtype)
+ end
+
+ it "should mark abstract terminus types as such" do
+ @subclass.should be_abstract_terminus
+ end
+
+ it "should not allow instances of abstract subclasses to be created" do
+ proc { @subclass.new }.should raise_error(Puppet::DevError)
+ end
+end
+
+describe Puppet::Indirector::Terminus, " when creating terminus classes" do
+ before do
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
+
+ @indirection = stub 'indirection', :name => :myind, :register_terminus_type => nil
+ Puppet::Indirector::Indirection.expects(:instance).with(:myindirection).returns(@indirection)
+
+ @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do
+ def self.to_s
+ "Abstract"
+ end
+ end
+ @terminus = Class.new(@abstract_terminus) do
+ def self.to_s
+ "MyIndirection"
+ end
+ end
+ end
+
+ it "should associate the subclass with an indirection based on the subclass constant" do
+ @terminus.indirection.should equal(@indirection)
+ end
+
+ it "should set the subclass's type to the abstract terminus name" do
+ @terminus.terminus_type.should == :abstract
+ end
+
+ it "should set the subclass's name to the indirection name" do
+ @terminus.name.should == :myindirection
+ end
+
+ it "should set the subclass's model to the indirection model" do
+ @indirection.expects(:model).returns :yay
+ @terminus.model.should == :yay
+ end
+end
+
+describe Puppet::Indirector::Terminus, " when a terminus instance" do
+ before do
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
+ @indirection = stub 'indirection', :name => :myyaml, :register_terminus_type => nil
+ Puppet::Indirector::Indirection.stubs(:instance).with(:mystuff).returns(@indirection)
+ @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do
+ def self.to_s
+ "Abstract"
+ end
+ end
+ @terminus_class = Class.new(@abstract_terminus) do
+ def self.to_s
+ "MyStuff"
+ end
+ end
+ @terminus_class.name = :test
+ @terminus = @terminus_class.new
+ end
+
+ it "should return the class's name as its name" do
+ @terminus.name.should == :test
+ end
+
+ it "should return the class's indirection as its indirection" do
+ @terminus.indirection.should equal(@indirection)
+ end
+
+ it "should set the instances's type to the abstract terminus type's name" do
+ @terminus.terminus_type.should == :abstract
+ end
+
+ it "should set the instances's model to the indirection's model" do
+ @indirection.expects(:model).returns :yay
+ @terminus.model.should == :yay
+ end
+end
diff --git a/spec/unit/indirector/yaml.rb b/spec/unit/indirector/yaml.rb
new file mode 100755
index 000000000..9e1d65e49
--- /dev/null
+++ b/spec/unit/indirector/yaml.rb
@@ -0,0 +1,104 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/indirector/yaml'
+
+module YamlTesting
+ def setup
+ @indirection = stub 'indirection', :name => :myyaml, :register_terminus_type => nil
+ Puppet::Indirector::Indirection.stubs(:instance).with(:myyaml).returns(@indirection)
+ @store_class = Class.new(Puppet::Indirector::Yaml) do
+ def self.to_s
+ "MyYaml"
+ end
+ end
+ @store = @store_class.new
+
+ @subject = Object.new
+ @subject.metaclass.send(:attr_accessor, :name)
+ @subject.name = :me
+
+ @dir = "/what/ever"
+ Puppet.settings.stubs(:use)
+ Puppet.settings.stubs(:value).with(:yamldir).returns(@dir)
+ end
+end
+
+describe Puppet::Indirector::Yaml, " when choosing file location" do
+ include YamlTesting
+
+ it "should store all files in a single file root set in the Puppet defaults" do
+ @store.send(:path, :me).should =~ %r{^#{@dir}}
+ end
+
+ it "should use the terminus name for choosing the subdirectory" do
+ @store.send(:path, :me).should =~ %r{^#{@dir}/myyaml}
+ end
+
+ it "should use the object's name to determine the file name" do
+ @store.send(:path, :me).should =~ %r{me.yaml$}
+ end
+end
+
+describe Puppet::Indirector::Yaml, " when storing objects as YAML" do
+ include YamlTesting
+
+ it "should only store objects that respond to :name" do
+ proc { @store.save(Object.new) }.should raise_error(ArgumentError)
+ end
+
+ it "should convert Ruby objects to YAML and write them to disk" do
+ yaml = @subject.to_yaml
+ file = mock 'file'
+ path = @store.send(:path, @subject.name)
+ FileTest.expects(:exist?).with(File.dirname(path)).returns(true)
+ File.expects(:open).with(path, "w", 0660).yields(file)
+ file.expects(:print).with(yaml)
+
+ @store.save(@subject)
+ end
+
+ it "should create the indirection subdirectory if it does not exist" do
+ yaml = @subject.to_yaml
+ file = mock 'file'
+ path = @store.send(:path, @subject.name)
+ dir = File.dirname(path)
+ FileTest.expects(:exist?).with(dir).returns(false)
+ Dir.expects(:mkdir).with(dir)
+ File.expects(:open).with(path, "w", 0660).yields(file)
+ file.expects(:print).with(yaml)
+
+ @store.save(@subject)
+ end
+end
+
+describe Puppet::Indirector::Yaml, " when retrieving YAML" do
+ include YamlTesting
+
+ it "should require the name of the object to retrieve" do
+ proc { @store.find(nil) }.should raise_error(ArgumentError)
+ end
+
+ it "should read YAML in from disk and convert it to Ruby objects" do
+ path = @store.send(:path, @subject.name)
+
+ yaml = @subject.to_yaml
+ FileTest.expects(:exist?).with(path).returns(true)
+ File.expects(:read).with(path).returns(yaml)
+
+ @store.find(@subject.name).instance_variable_get("@name").should == :me
+ end
+
+ it "should fail coherently when the stored YAML is invalid" do
+ path = @store.send(:path, @subject.name)
+
+ # Something that will fail in yaml
+ yaml = "--- !ruby/object:Hash"
+
+ FileTest.expects(:exist?).with(path).returns(true)
+ File.expects(:read).with(path).returns(yaml)
+
+ proc { @store.find(@subject.name) }.should raise_error(Puppet::Error)
+ end
+end
diff --git a/spec/unit/indirector/yaml/facts.rb b/spec/unit/indirector/yaml/facts.rb
new file mode 100755
index 000000000..f1256cfa4
--- /dev/null
+++ b/spec/unit/indirector/yaml/facts.rb
@@ -0,0 +1,26 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/node/facts'
+require 'puppet/indirector/yaml/facts'
+
+describe Puppet::Indirector::Yaml::Facts do
+ it "should be a subclass of the Yaml terminus" do
+ Puppet::Indirector::Yaml::Facts.superclass.should equal(Puppet::Indirector::Yaml)
+ end
+
+
+ it "should have documentation" do
+ Puppet::Indirector::Yaml::Facts.doc.should_not be_nil
+ end
+
+ it "should be registered with the facts indirection" do
+ indirection = Puppet::Indirector::Indirection.instance(:facts)
+ Puppet::Indirector::Yaml::Facts.indirection.should equal(indirection)
+ end
+
+ it "should have its name set to :facts" do
+ Puppet::Indirector::Yaml::Facts.name.should == :facts
+ end
+end
diff --git a/spec/unit/node/configuration.rb b/spec/unit/node/configuration.rb
index 4429fe3a3..8ba55f50c 100755
--- a/spec/unit/node/configuration.rb
+++ b/spec/unit/node/configuration.rb
@@ -133,3 +133,340 @@ describe Puppet::Node::Configuration, " when extracting transobjects" do
botarray.include?(:botres).should be_true
end
end
+
+describe Puppet::Node::Configuration, " when functioning as a resource container" do
+ before do
+ @config = Puppet::Node::Configuration.new("host")
+ @one = stub 'resource1', :ref => "Me[you]", :configuration= => nil
+ @two = stub 'resource2', :ref => "Me[him]", :configuration= => nil
+ @dupe = stub 'resource3', :ref => "Me[you]", :configuration= => nil
+ end
+
+ it "should provide a method to add one or more resources" do
+ @config.add_resource @one, @two
+ @config.resource(@one.ref).should equal(@one)
+ @config.resource(@two.ref).should equal(@two)
+ end
+
+ it "should make all vertices available by resource reference" do
+ @config.add_resource(@one)
+ @config.resource(@one.ref).should equal(@one)
+ @config.vertices.find { |r| r.ref == @one.ref }.should equal(@one)
+ end
+
+ it "should not allow two resources with the same resource reference" do
+ @config.add_resource(@one)
+ proc { @config.add_resource(@dupe) }.should raise_error(ArgumentError)
+ end
+
+ it "should not store objects that do not respond to :ref" do
+ proc { @config.add_resource("thing") }.should raise_error(ArgumentError)
+ end
+
+ it "should remove all resources when asked" do
+ @config.add_resource @one
+ @config.add_resource @two
+ @one.expects :remove
+ @two.expects :remove
+ @config.clear(true)
+ end
+
+ it "should support a mechanism for finishing resources" do
+ @one.expects :finish
+ @two.expects :finish
+ @config.add_resource @one
+ @config.add_resource @two
+
+ @config.finalize
+ end
+
+ it "should optionally support an initialization block and should finalize after such blocks" do
+ @one.expects :finish
+ @two.expects :finish
+ config = Puppet::Node::Configuration.new("host") do |conf|
+ conf.add_resource @one
+ conf.add_resource @two
+ end
+ end
+
+ it "should inform the resource that it is the resource's configuration" do
+ @one.expects(:configuration=).with(@config)
+ @config.add_resource @one
+ end
+
+ it "should be able to find resources by reference" do
+ @config.add_resource @one
+ @config.resource(@one.ref).should equal(@one)
+ end
+
+ it "should be able to find resources by reference or by type/title tuple" do
+ @config.add_resource @one
+ @config.resource("me", "you").should equal(@one)
+ end
+
+ it "should have a mechanism for removing resources" do
+ @config.add_resource @one
+ @one.expects :remove
+ @config.remove_resource(@one)
+ @config.resource(@one.ref).should be_nil
+ @config.vertex?(@one).should be_false
+ end
+end
+
+module ApplyingConfigurations
+ def setup
+ @config = Puppet::Node::Configuration.new("host")
+
+ @config.retrieval_duration = Time.now
+ @transaction = mock 'transaction'
+ Puppet::Transaction.stubs(:new).returns(@transaction)
+ @transaction.stubs(:evaluate)
+ @transaction.stubs(:cleanup)
+ @transaction.stubs(:addtimes)
+ end
+end
+
+describe Puppet::Node::Configuration, " when applying" do
+ include ApplyingConfigurations
+
+ it "should create and evaluate a transaction" do
+ @transaction.expects(:evaluate)
+ @config.apply
+ end
+
+ it "should provide the configuration time to the transaction" do
+ @transaction.expects(:addtimes).with do |arg|
+ arg[:config_retrieval].should be_instance_of(Time)
+ true
+ end
+ @config.apply
+ end
+
+ it "should clean up the transaction" do
+ @transaction.expects :cleanup
+ @config.apply
+ end
+
+ it "should return the transaction" do
+ @config.apply.should equal(@transaction)
+ end
+
+ it "should yield the transaction if a block is provided" do
+ @config.apply do |trans|
+ trans.should equal(@transaction)
+ end
+ end
+
+ it "should default to not being a host configuration" do
+ @config.host_config.should be_nil
+ end
+
+ it "should pass supplied tags on to the transaction" do
+ @transaction.expects(:tags=).with(%w{one two})
+ @config.apply(:tags => %w{one two})
+ end
+
+ it "should set ignoreschedules on the transaction if specified in apply()" do
+ @transaction.expects(:ignoreschedules=).with(true)
+ @config.apply(:ignoreschedules => true)
+ end
+end
+
+describe Puppet::Node::Configuration, " when applying host configurations" do
+ include ApplyingConfigurations
+
+ # super() doesn't work in the setup method for some reason
+ before do
+ @config.host_config = true
+ end
+
+ it "should send a report if reporting is enabled" do
+ Puppet[:report] = true
+ @transaction.expects :send_report
+ @config.apply
+ end
+
+ it "should send a report if report summaries are enabled" do
+ Puppet[:summarize] = true
+ @transaction.expects :send_report
+ @config.apply
+ end
+
+ it "should initialize the state database before applying a configuration" do
+ Puppet::Util::Storage.expects(:load)
+
+ # Short-circuit the apply, so we know we're loading before the transaction
+ Puppet::Transaction.expects(:new).raises ArgumentError
+ proc { @config.apply }.should raise_error(ArgumentError)
+ end
+
+ it "should sync the state database after applying" do
+ Puppet::Util::Storage.expects(:store)
+ @config.apply
+ end
+
+ after { Puppet.settings.clear }
+end
+
+describe Puppet::Node::Configuration, " when applying non-host configurations" do
+ include ApplyingConfigurations
+
+ before do
+ @config.host_config = false
+ end
+
+ it "should never send reports" do
+ Puppet[:report] = true
+ Puppet[:summarize] = true
+ @transaction.expects(:send_report).never
+ @config.apply
+ end
+
+ it "should never modify the state database" do
+ Puppet::Util::Storage.expects(:load).never
+ Puppet::Util::Storage.expects(:store).never
+ @config.apply
+ end
+
+ after { Puppet.settings.clear }
+end
+
+describe Puppet::Node::Configuration, " when creating a relationship graph" do
+ before do
+ @config = Puppet::Node::Configuration.new("host")
+ @compone = Puppet::Type::Component.create :name => "one"
+ @comptwo = Puppet::Type::Component.create :name => "two", :require => ["class", "one"]
+ @file = Puppet::Type.type(:file)
+ @one = @file.create :path => "/one"
+ @two = @file.create :path => "/two"
+ @config.add_edge! @compone, @one
+ @config.add_edge! @comptwo, @two
+
+ @three = @file.create :path => "/three"
+ @four = @file.create :path => "/four", :require => ["file", "/three"]
+ @five = @file.create :path => "/five"
+ @config.add_resource @compone, @comptwo, @one, @two, @three, @four, @five
+ @relationships = @config.relationship_graph
+ end
+
+ it "should be able to create a relationship graph" do
+ @relationships.should be_instance_of(Puppet::Node::Configuration)
+ end
+
+ it "should copy its host_config setting to the relationship graph" do
+ config = Puppet::Node::Configuration.new
+ config.host_config = true
+ config.relationship_graph.host_config.should be_true
+ end
+
+ it "should not have any components" do
+ @relationships.vertices.find { |r| r.instance_of?(Puppet::Type::Component) }.should be_nil
+ end
+
+ it "should have all non-component resources from the configuration" do
+ # The failures print out too much info, so i just do a class comparison
+ @relationships.vertex?(@five).should be_true
+ end
+
+ it "should have all resource relationships set as edges" do
+ @relationships.edge?(@three, @four).should be_true
+ end
+
+ it "should copy component relationships to all contained resources" do
+ @relationships.edge?(@one, @two).should be_true
+ end
+
+ it "should get removed when the configuration is cleaned up" do
+ @relationships.expects(:clear).with(false)
+ @config.clear
+ @config.instance_variable_get("@relationship_graph").should be_nil
+ end
+
+ it "should create a new relationship graph after clearing the old one" do
+ @relationships.expects(:clear).with(false)
+ @config.clear
+ @config.relationship_graph.should be_instance_of(Puppet::Node::Configuration)
+ end
+
+ it "should look up resources in the relationship graph if not found in the main configuration" do
+ five = stub 'five', :ref => "File[five]", :configuration= => nil
+ @relationships.add_resource five
+ @config.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]", :configuration= => @config
+ Puppet::Type.type(:file).expects(:create).with(args).returns(resource)
+ @config.create_resource :file, args
+ @config.resource("File[/yay]").should equal(resource)
+ end
+
+ it "should provide a mechanism for creating implicit resources" do
+ args = {:name => "/yay", :ensure => :file}
+ resource = stub 'file', :ref => "File[/yay]", :configuration= => @config
+ Puppet::Type.type(:file).expects(:create).with(args).returns(resource)
+ resource.expects(:implicit=).with(true)
+ @config.create_implicit_resource :file, args
+ @config.resource("File[/yay]").should equal(resource)
+ end
+
+ it "should remove resources created mid-transaction" do
+ args = {:name => "/yay", :ensure => :file}
+ resource = stub 'file', :ref => "File[/yay]", :configuration= => @config
+ @transaction = mock 'transaction'
+ Puppet::Transaction.stubs(:new).returns(@transaction)
+ @transaction.stubs(:evaluate)
+ @transaction.stubs(:cleanup)
+ @transaction.stubs(:addtimes)
+ Puppet::Type.type(:file).expects(:create).with(args).returns(resource)
+ resource.expects :remove
+ @config.apply do |trans|
+ @config.create_resource :file, args
+ @config.resource("File[/yay]").should equal(resource)
+ end
+ @config.resource("File[/yay]").should be_nil
+ end
+
+ it "should remove resources from the relationship graph if it exists" do
+ @config.remove_resource(@one)
+ @config.relationship_graph.vertex?(@one).should be_false
+ end
+
+ after do
+ Puppet::Type.allclear
+ end
+end
+
+describe Puppet::Node::Configuration, " when writing dot files" do
+ before do
+ @config = Puppet::Node::Configuration.new("host")
+ @name = :test
+ @file = File.join(Puppet[:graphdir], @name.to_s + ".dot")
+ end
+ it "should only write when it is a host configuration" do
+ File.expects(:open).with(@file).never
+ @config.host_config = false
+ Puppet[:graph] = true
+ @config.write_graph(@name)
+ end
+
+ it "should only write when graphing is enabled" do
+ File.expects(:open).with(@file).never
+ @config.host_config = true
+ Puppet[:graph] = false
+ @config.write_graph(@name)
+ end
+
+ it "should write a dot file based on the passed name" do
+ File.expects(:open).with(@file, "w").yields(stub("file", :puts => nil))
+ @config.expects(:to_dot).with("name" => @name.to_s.capitalize)
+ @config.host_config = true
+ Puppet[:graph] = true
+ @config.write_graph(@name)
+ end
+
+ after do
+ Puppet.settings.clear
+ end
+end
diff --git a/spec/unit/node/facts.rb b/spec/unit/node/facts.rb
new file mode 100755
index 000000000..61f05a2b2
--- /dev/null
+++ b/spec/unit/node/facts.rb
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/node/facts'
+
+describe Puppet::Node::Facts, " when indirecting" do
+ before do
+ @terminus = mock 'terminus'
+ Puppet::Node::Facts.stubs(:indirection).returns(@terminus)
+
+ # We have to clear the cache so that the facts ask for our terminus stub,
+ # instead of anything that might be cached.
+ Puppet::Indirector::Indirection.clear_cache
+ @facts = Puppet::Node::Facts.new("me", "one" => "two")
+ end
+
+ it "should redirect to the specified fact store for retrieval" do
+ @terminus.expects(:find).with(:my_facts)
+ Puppet::Node::Facts.find(:my_facts)
+ end
+
+ it "should redirect to the specified fact store for storage" do
+ @terminus.expects(:save).with(@facts)
+ @facts.save
+ end
+
+ after do
+ mocha_verify
+ Puppet::Indirector::Indirection.clear_cache
+ end
+end
+
+describe Puppet::Node::Facts, " when storing and retrieving" do
+ it "should add metadata to the facts" do
+ facts = Puppet::Node::Facts.new("me", "one" => "two", "three" => "four")
+ facts.values[:_timestamp].should be_instance_of(Time)
+ end
+end
diff --git a/spec/unit/other/node.rb b/spec/unit/node/node.rb
index 66d5ba9d7..fe5d2be8b 100755
--- a/spec/unit/other/node.rb
+++ b/spec/unit/node/node.rb
@@ -11,6 +11,10 @@ describe Puppet::Node, " when initializing" do
@node.name.should == "testnode"
end
+ it "should not allow nil node names" do
+ proc { Puppet::Node.new(nil) }.should raise_error(ArgumentError)
+ end
+
it "should default to an empty parameter hash" do
@node.parameters.should == {}
end
@@ -62,7 +66,7 @@ describe Puppet::Node, " when returning the environment" do
end
it "should return the central environment if there is no environment fact nor explicit environment" do
- Puppet.config.expects(:[]).with(:environment).returns(:centralenv)
+ Puppet.settings.expects(:[]).with(:environment).returns(:centralenv)
@node.environment.should == :centralenv
end
@@ -77,7 +81,7 @@ describe Puppet::Node, " when returning the environment" do
end
it "should not use an explicit environment that is an empty string" do
- Puppet.config.expects(:[]).with(:environment).returns(nil)
+ Puppet.settings.expects(:[]).with(:environment).returns(nil)
@node.environment.should be_nil
end
end
@@ -85,17 +89,47 @@ end
describe Puppet::Node, " when merging facts" do
before do
@node = Puppet::Node.new("testnode")
+ Puppet::Node::Facts.stubs(:find).with(@node.name).returns(Puppet::Node::Facts.new(@node.name, "one" => "c", "two" => "b"))
end
it "should prefer parameters already set on the node over facts from the node" do
@node.parameters = {"one" => "a"}
- @node.fact_merge("one" => "c")
+ @node.fact_merge
@node.parameters["one"].should == "a"
end
it "should add passed parameters to the parameter list" do
@node.parameters = {"one" => "a"}
- @node.fact_merge("two" => "b")
+ @node.fact_merge
@node.parameters["two"].should == "b"
end
+
+ it "should accept arbitrary parameters to merge into its parameters" do
+ @node.parameters = {"one" => "a"}
+ @node.merge "two" => "three"
+ @node.parameters["two"].should == "three"
+ end
+end
+
+describe Puppet::Node, " when indirecting" do
+ before do
+ @terminus = mock 'terminus'
+ Puppet::Node.stubs(:indirection).returns(@terminus)
+ end
+
+ it "should redirect to the specified node source" do
+ @terminus.expects(:find).with(:my_node.to_s)
+ Puppet::Node.find(:my_node.to_s)
+ end
+
+ after do
+ Puppet::Indirector::Indirection.clear_cache
+ end
+end
+
+describe Puppet::Node do
+ # LAK:NOTE This is used to keep track of when a given node has connected,
+ # so we can report on nodes that do not appear to connecting to the
+ # central server.
+ it "should provide a method for noting that the node has connected"
end
diff --git a/spec/unit/node/searching.rb b/spec/unit/node/searching.rb
new file mode 100755
index 000000000..e747996e4
--- /dev/null
+++ b/spec/unit/node/searching.rb
@@ -0,0 +1,79 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'puppet/node/searching'
+require 'puppet/node/facts'
+
+describe Puppet::Node::Searching, " when searching for nodes" do
+ before do
+ @searcher = Object.new
+ @searcher.extend(Puppet::Node::Searching)
+ @facts = Puppet::Node::Facts.new("foo", "hostname" => "yay", "domain" => "domain.com")
+ @node = Puppet::Node.new("foo")
+ Puppet::Node::Facts.stubs(:find).with("foo").returns(@facts)
+ end
+
+ it "should search for the node by its key first" do
+ names = []
+ @searcher.expects(:find).with do |name|
+ names << name
+ names == %w{foo}
+ end.returns(@node)
+ @searcher.search("foo").should equal(@node)
+ end
+
+ it "should return the first node found using the generated list of names" do
+ names = []
+ @searcher.expects(:find).with("foo").returns(nil)
+ @searcher.expects(:find).with("yay.domain.com").returns(@node)
+ @searcher.search("foo").should equal(@node)
+ end
+
+ it "should search for the rest of the names inversely by length" do
+ names = []
+ @facts.values["fqdn"] = "longer.than.the.normal.fqdn.com"
+ @searcher.stubs(:find).with do |name|
+ names << name
+ end
+ @searcher.search("foo")
+ # Strip off the key
+ names.shift
+
+ # And the 'default'
+ names.pop
+
+ length = 100
+ names.each do |name|
+ (name.length < length).should be_true
+ length = name.length
+ end
+ end
+
+ it "should attempt to find a default node if no names are found" do
+ names = []
+ @searcher.stubs(:find).with do |name|
+ names << name
+ end.returns(nil)
+ @searcher.search("foo")
+ names[-1].should == "default"
+ end
+
+ it "should cache the nodes" do
+ @searcher.expects(:find).with("foo").returns(@node)
+ @searcher.search("foo").should equal(@node)
+ @searcher.search("foo").should equal(@node)
+ end
+
+ it "should flush the node cache using the :filetimeout parameter" do
+ node2 = Puppet::Node.new("foo2")
+ Puppet[:filetimeout] = -1
+ # I couldn't get this to work with :expects
+ @searcher.stubs(:find).returns(@node, node2).then.raises(ArgumentError)
+ @searcher.search("foo").should equal(@node)
+ @searcher.search("foo").should equal(node2)
+ end
+
+ after do
+ Puppet.settings.clear
+ end
+end
diff --git a/spec/unit/other/checksum.rb b/spec/unit/other/checksum.rb
new file mode 100755
index 000000000..6a63e833d
--- /dev/null
+++ b/spec/unit/other/checksum.rb
@@ -0,0 +1,92 @@
+#!/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/checksum'
+
+describe Puppet::Checksum do
+ it "should have 'Checksum' and the checksum algorithm when converted to a string" do
+ inst = Puppet::Checksum.new("whatever", "md5")
+ inst.to_s.should == "Checksum<{md5}#{inst.checksum}>"
+ end
+
+ it "should convert algorithm names to symbols when they are set after checksum creation" do
+ sum = Puppet::Checksum.new("whatever")
+ sum.algorithm = "md5"
+ sum.algorithm.should == :md5
+ end
+
+ it "should return the checksum as the name" do
+ sum = Puppet::Checksum.new("whatever")
+ sum.checksum.should == sum.name
+ end
+end
+
+describe Puppet::Checksum, " when initializing" do
+ before do
+ @content = "this is some content"
+ @sum = Puppet::Checksum.new(@content)
+ end
+
+ it "should require content" do
+ proc { Puppet::Checksum.new(nil) }.should raise_error(ArgumentError)
+ end
+
+ it "should set the content appropriately" do
+ @sum.content.should == @content
+ end
+
+ it "should calculate the checksum" do
+ require 'digest/md5'
+ Digest::MD5.expects(:hexdigest).with(@content).returns(:mychecksum)
+ @sum.checksum.should == :mychecksum
+ end
+
+ it "should not calculate the checksum until it is asked for" do
+ require 'digest/md5'
+ Digest::MD5.expects(:hexdigest).never
+ sum = Puppet::Checksum.new(@content, :md5)
+ end
+
+ it "should remove the old checksum value if the algorithm is changed" do
+ Digest::MD5.expects(:hexdigest).with(@content).returns(:oldsum)
+ oldsum = @sum.checksum
+ @sum.algorithm = :sha1
+ Digest::SHA1.expects(:hexdigest).with(@content).returns(:newsum)
+ @sum.checksum.should == :newsum
+ end
+
+ it "should default to 'md5' as the checksum algorithm if the algorithm is not in the name" do
+ @sum.algorithm.should == :md5
+ end
+
+ it "should support specifying the algorithm during initialization" do
+ sum = Puppet::Checksum.new(@content, :sha1)
+ sum.algorithm.should == :sha1
+ end
+
+ it "should fail when an unsupported algorithm is used" do
+ proc { Puppet::Checksum.new(@content, :nope) }.should raise_error(ArgumentError)
+ end
+end
+
+describe Puppet::Checksum, " when using back-ends" do
+ it "should redirect using Puppet::Indirector" do
+ Puppet::Indirector::Indirection.instance(:checksum).model.should equal(Puppet::Checksum)
+ end
+
+ it "should have a :save instance method" do
+ Puppet::Checksum.new("mysum").should respond_to(:save)
+ end
+
+ it "should respond to :find" do
+ Puppet::Checksum.should respond_to(:find)
+ end
+
+ it "should respond to :destroy" do
+ Puppet::Checksum.should respond_to(:destroy)
+ end
+end
diff --git a/spec/unit/other/modules.rb b/spec/unit/other/modules.rb
index 0ab37aa9e..f53c43e89 100755
--- a/spec/unit/other/modules.rb
+++ b/spec/unit/other/modules.rb
@@ -5,10 +5,10 @@ require File.dirname(__FILE__) + '/../../spec_helper'
describe Puppet::Module, " when building its search path" do
include PuppetTest
- it "should ignore unqualified paths in the search path" do
+ it "should fully qualify unqualified paths in the search path" do
Puppet[:modulepath] = "something:/my/something"
File.stubs(:directory?).returns(true)
- Puppet::Module.modulepath.should == %w{/my/something}
+ Puppet::Module.modulepath.should == [File.join(Dir.getwd, 'something'), "/my/something"]
end
it "should ignore paths that do not exist" do
@@ -26,7 +26,7 @@ describe Puppet::Module, " when building its search path" do
end
it "should use the environment-specific search path when a node environment is provided" do
- Puppet.config.expects(:value).with(:modulepath, "myenv").returns("/mone:/mtwo")
+ Puppet.settings.expects(:value).with(:modulepath, "myenv").returns("/mone:/mtwo")
File.stubs(:directory?).returns(true)
Puppet::Module.modulepath("myenv").should == %w{/mone /mtwo}
end
@@ -82,30 +82,30 @@ describe Puppet::Module, " when searching for templates" do
end
it "should use the main templatedir if no module is found" do
- Puppet.config.expects(:value).with(:templatedir, nil).returns("/my/templates")
+ Puppet.settings.expects(:value).with(:templatedir, nil).returns("/my/templates")
Puppet::Module.expects(:find).with("mymod", nil).returns(nil)
Puppet::Module.find_template("mymod/mytemplate").should == "/my/templates/mymod/mytemplate"
end
it "should return unqualified templates directly in the template dir" do
- Puppet.config.expects(:value).with(:templatedir, nil).returns("/my/templates")
+ Puppet.settings.expects(:value).with(:templatedir, nil).returns("/my/templates")
Puppet::Module.expects(:find).never
Puppet::Module.find_template("mytemplate").should == "/my/templates/mytemplate"
end
it "should use the environment templatedir if no module is found and an environment is specified" do
- Puppet.config.expects(:value).with(:templatedir, "myenv").returns("/myenv/templates")
+ Puppet.settings.expects(:value).with(:templatedir, "myenv").returns("/myenv/templates")
Puppet::Module.expects(:find).with("mymod", "myenv").returns(nil)
Puppet::Module.find_template("mymod/mytemplate", "myenv").should == "/myenv/templates/mymod/mytemplate"
end
it "should use the node environment if specified" do
- Puppet.config.expects(:value).with(:modulepath, "myenv").returns("/my/templates")
+ Puppet.settings.expects(:value).with(:modulepath, "myenv").returns("/my/templates")
File.stubs(:directory?).returns(true)
Puppet::Module.find_template("mymod/envtemplate", "myenv").should == "/my/templates/mymod/templates/envtemplate"
end
- after { Puppet.config.clear }
+ after { Puppet.settings.clear }
end
describe Puppet::Module, " when searching for manifests" do
@@ -125,27 +125,27 @@ describe Puppet::Module, " when searching for manifests" do
end
it "should use the node environment if specified" do
- Puppet.config.expects(:value).with(:modulepath, "myenv").returns("/env/modules")
+ Puppet.settings.expects(:value).with(:modulepath, "myenv").returns("/env/modules")
File.stubs(:directory?).returns(true)
Dir.expects(:glob).with("/env/modules/mymod/manifests/envmanifest.pp").returns(%w{/env/modules/mymod/manifests/envmanifest.pp})
Puppet::Module.find_manifests("mymod/envmanifest.pp", :environment => "myenv").should == ["/env/modules/mymod/manifests/envmanifest.pp"]
end
it "should return all manifests matching the glob pattern" do
- Puppet.config.expects(:value).with(:modulepath, nil).returns("/my/modules")
+ Puppet.settings.expects(:value).with(:modulepath, nil).returns("/my/modules")
File.stubs(:directory?).returns(true)
Dir.expects(:glob).with("/my/modules/mymod/manifests/yay/*.pp").returns(%w{/one /two})
Puppet::Module.find_manifests("mymod/yay/*.pp").should == %w{/one /two}
end
it "should default to the 'init.pp' file in the manifests directory" do
- Puppet.config.expects(:value).with(:modulepath, nil).returns("/my/modules")
+ Puppet.settings.expects(:value).with(:modulepath, nil).returns("/my/modules")
File.stubs(:directory?).returns(true)
Dir.expects(:glob).with("/my/modules/mymod/manifests/init.pp").returns(%w{my manifest})
Puppet::Module.find_manifests("mymod").should == %w{my manifest}
end
- after { Puppet.config.clear }
+ after { Puppet.settings.clear }
end
describe Puppet::Module, " when returning files" do
diff --git a/spec/unit/other/pgraph.rb b/spec/unit/other/pgraph.rb
new file mode 100755
index 000000000..19809ac1e
--- /dev/null
+++ b/spec/unit/other/pgraph.rb
@@ -0,0 +1,285 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2007-9-12.
+# Copyright (c) 2006. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/util/graph'
+
+class Container
+ include Puppet::Util::Graph
+ include Enumerable
+ attr_accessor :name
+ def each
+ @children.each do |c| yield c end
+ end
+
+ def initialize(name, ary)
+ @name = name
+ @children = ary
+ end
+
+ def push(*ary)
+ ary.each { |c| @children.push(c)}
+ end
+
+ def to_s
+ @name
+ end
+end
+
+describe Puppet::PGraph do
+ before do
+ @graph = Puppet::PGraph.new
+ end
+
+ it "should correctly clear vertices and edges when asked" do
+ @graph.add_edge!("a", "b")
+ @graph.add_vertex! "c"
+ @graph.clear
+ @graph.vertices.should be_empty
+ @graph.edges.should be_empty
+ end
+end
+
+describe Puppet::PGraph, " when matching edges" do
+ before do
+ @graph = Puppet::PGraph.new
+ @event = Puppet::Event.new(:source => "a", :event => :yay)
+ @none = Puppet::Event.new(:source => "a", :event => :NONE)
+
+ @edges = {}
+ @edges["a/b"] = Puppet::Relationship["a", "b", {:event => :yay, :callback => :refresh}]
+ @edges["a/c"] = Puppet::Relationship["a", "c", {:event => :yay, :callback => :refresh}]
+ @graph.add_edge!(@edges["a/b"])
+ end
+
+ it "should match edges whose source matches the source of the event" do
+ @graph.matching_edges([@event]).should == [@edges["a/b"]]
+ end
+
+ it "should match always match nothing when the event is :NONE" do
+ @graph.matching_edges([@none]).should be_empty
+ end
+
+ it "should match multiple edges" do
+ @graph.add_edge!(@edges["a/c"])
+ @graph.matching_edges([@event]).sort.should == [@edges["a/b"], @edges["a/c"]].sort
+ end
+end
+
+describe Puppet::PGraph, " when determining dependencies" do
+ before do
+ @graph = Puppet::PGraph.new
+
+ @graph.add_edge!("a", "b")
+ @graph.add_edge!("a", "c")
+ @graph.add_edge!("b", "d")
+ end
+
+ it "should find all dependents when they are on multiple levels" do
+ @graph.dependents("a").sort.should == %w{b c d}.sort
+ end
+
+ it "should find single dependents" do
+ @graph.dependents("b").sort.should == %w{d}.sort
+ end
+
+ it "should return an empty array when there are no dependents" do
+ @graph.dependents("c").sort.should == [].sort
+ end
+
+ it "should find all dependencies when they are on multiple levels" do
+ @graph.dependencies("d").sort.should == %w{a b}
+ end
+
+ it "should find single dependencies" do
+ @graph.dependencies("c").sort.should == %w{a}
+ end
+
+ it "should return an empty array when there are no dependencies" do
+ @graph.dependencies("a").sort.should == []
+ end
+end
+
+describe Puppet::PGraph, " when splicing the relationship graph" do
+ def container_graph
+ @one = Container.new("one", %w{a b})
+ @two = Container.new("two", ["c", "d"])
+ @three = Container.new("three", ["i", "j"])
+ @middle = Container.new("middle", ["e", "f", @two])
+ @top = Container.new("top", ["g", "h", @middle, @one, @three])
+ @empty = Container.new("empty", [])
+
+ @contgraph = @top.to_graph
+
+ # We have to add the container to the main graph, else it won't
+ # be spliced in the dependency graph.
+ @contgraph.add_vertex!(@empty)
+ end
+
+ def dependency_graph
+ @depgraph = Puppet::PGraph.new
+ @contgraph.vertices.each do |v|
+ @depgraph.add_vertex(v)
+ end
+
+ # We have to specify a relationship to our empty container, else it
+ # never makes it into the dep graph in the first place.
+ {@one => @two, "f" => "c", "h" => @middle, "c" => @empty}.each do |source, target|
+ @depgraph.add_edge!(source, target, :callback => :refresh)
+ end
+ end
+
+ def splice
+ @depgraph.splice!(@contgraph, Container)
+ end
+
+ before do
+ container_graph
+ dependency_graph
+ splice
+ end
+
+ it "should not create a cyclic graph" do
+ @depgraph.should_not be_cyclic
+ end
+
+ # This is the real heart of splicing -- replacing all containers in
+ # our relationship and exploding their relationships so that each
+ # relationship to a container gets copied to all of its children.
+ it "should remove all Container objects from the dependency graph" do
+ @depgraph.vertices.find_all { |v| v.is_a?(Container) }.should be_empty
+ end
+
+ it "should add container relationships to contained objects" do
+ @contgraph.leaves(@middle).each do |leaf|
+ @depgraph.should be_edge("h", leaf)
+ end
+ end
+
+ it "should explode container-to-container relationships, making edges between all respective contained objects" do
+ @one.each do |oobj|
+ @two.each do |tobj|
+ @depgraph.should be_edge(oobj, tobj)
+ end
+ end
+ end
+
+ it "should no longer contain anything but the non-container objects" do
+ @depgraph.vertices.find_all { |v| ! v.is_a?(String) }.should be_empty
+ end
+
+ it "should copy labels" do
+ @depgraph.edges.each do |edge|
+ edge.label.should == {:callback => :refresh}
+ end
+ end
+
+ it "should not add labels to edges that have none" do
+ @depgraph.add_edge!(@two, @three)
+ splice
+ @depgraph.edge_label("c", "i").should == {}
+ end
+
+ it "should copy labels over edges that have none" do
+ @depgraph.add_edge!("c", @three, {:callback => :refresh})
+ splice
+ # And make sure the label got copied.
+ @depgraph.edge_label("c", "i").should == {:callback => :refresh}
+ end
+
+ it "should not replace a label with a nil label" do
+ # Lastly, add some new label-less edges and make sure the label stays.
+ @depgraph.add_edge!(@middle, @three)
+ @depgraph.add_edge!("c", @three, {:callback => :refresh})
+ splice
+ @depgraph.edge_label("c", "i").should == {:callback => :refresh}
+ end
+
+ it "should copy labels to all created edges" do
+ @depgraph.add_edge!(@middle, @three)
+ @depgraph.add_edge!("c", @three, {:callback => :refresh})
+ splice
+ @three.each do |child|
+ edge = @depgraph.edge_class.new("c", child)
+ @depgraph.should be_edge(edge)
+ @depgraph[edge].should == {:callback => :refresh}
+ end
+ end
+end
+
+# Labels in this graph are used for managing relationships,
+# including callbacks, so they're quite important.
+describe Puppet::PGraph, " when managing labels" do
+ before do
+ @graph = Puppet::PGraph.new
+ @label = {:callback => :yay}
+ end
+
+ it "should return nil for edges with no label" do
+ @graph.add_edge!(:a, :b)
+ @graph.edge_label(:a, :b).should be_nil
+ end
+
+ it "should just return empty label hashes" do
+ @graph.add_edge!(:a, :b, {})
+ @graph.edge_label(:a, :b).should == {}
+ end
+
+ it "should consider empty label hashes to be nil when copying" do
+ @graph.add_edge!(:a, :b)
+ @graph.copy_label(:a, :b, {})
+ @graph.edge_label(:a, :b).should be_nil
+ end
+
+ it "should return label hashes" do
+ @graph.add_edge!(:a, :b, @label)
+ @graph.edge_label(:a, :b).should == @label
+ end
+
+ it "should replace nil labels with real labels" do
+ @graph.add_edge!(:a, :b)
+ @graph.copy_label(:a, :b, @label)
+ @graph.edge_label(:a, :b).should == @label
+ end
+
+ it "should not replace labels with nil labels" do
+ @graph.add_edge!(:a, :b, @label)
+ @graph.copy_label(:a, :b, {})
+ @graph.edge_label(:a, :b).should == @label
+ end
+end
+
+describe Puppet::PGraph, " when sorting the graph" do
+ before do
+ @graph = Puppet::PGraph.new
+ end
+
+ def add_edges(hash)
+ hash.each do |a,b|
+ @graph.add_edge!(a, b)
+ end
+ end
+
+ it "should fail on two-vertex loops" do
+ add_edges :a => :b, :b => :a
+ proc { @graph.topsort }.should raise_error(Puppet::Error)
+ end
+
+ it "should fail on multi-vertex loops" do
+ add_edges :a => :b, :b => :c, :c => :a
+ proc { @graph.topsort }.should raise_error(Puppet::Error)
+ end
+
+ it "should fail when a larger tree contains a small cycle" do
+ add_edges :a => :b, :b => :a, :c => :a, :d => :c
+ proc { @graph.topsort }.should raise_error(Puppet::Error)
+ end
+
+ it "should succeed on trees with no cycles" do
+ add_edges :a => :b, :b => :e, :c => :a, :d => :c
+ proc { @graph.topsort }.should_not raise_error
+ end
+end
diff --git a/spec/unit/other/transaction.rb b/spec/unit/other/transaction.rb
new file mode 100755
index 000000000..7990d2eef
--- /dev/null
+++ b/spec/unit/other/transaction.rb
@@ -0,0 +1,26 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+describe Puppet::Transaction, " when determining tags" do
+ before do
+ @config = Puppet::Node::Configuration.new
+ @transaction = Puppet::Transaction.new(@config)
+ end
+
+ it "should default to the tags specified in the :tags setting" do
+ Puppet.expects(:[]).with(:tags).returns("one")
+ @transaction.tags.should == %w{one}
+ end
+
+ it "should split tags based on ','" do
+ Puppet.expects(:[]).with(:tags).returns("one,two")
+ @transaction.tags.should == %w{one two}
+ end
+
+ it "should use any tags set after creation" do
+ Puppet.expects(:[]).with(:tags).never
+ @transaction.tags = %w{one two}
+ @transaction.tags.should == %w{one two}
+ end
+end
diff --git a/spec/unit/other/transbucket.rb b/spec/unit/other/transbucket.rb
new file mode 100755
index 000000000..8cb9abaa4
--- /dev/null
+++ b/spec/unit/other/transbucket.rb
@@ -0,0 +1,133 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+describe Puppet::TransBucket do
+ before do
+ @bucket = Puppet::TransBucket.new
+ end
+
+ it "should be able to produce a RAL component" do
+ @bucket.name = "luke"
+ @bucket.type = "user"
+
+ resource = nil
+ proc { resource = @bucket.to_type }.should_not raise_error
+ resource.should be_instance_of(Puppet::Type::Component)
+ resource.title.should == "user[luke]"
+ end
+
+ it "should accept TransObjects into its children list" do
+ object = Puppet::TransObject.new("luke", "user")
+ proc { @bucket.push(object) }.should_not raise_error
+ @bucket.each do |o|
+ o.should equal(object)
+ end
+ end
+
+ it "should accept TransBuckets into its children list" do
+ object = Puppet::TransBucket.new()
+ proc { @bucket.push(object) }.should_not raise_error
+ @bucket.each do |o|
+ o.should equal(object)
+ end
+ end
+
+ it "should refuse to accept any children that are not TransObjects or TransBuckets" do
+ proc { @bucket.push "a test" }.should raise_error
+ end
+
+ it "should return nil as its reference when type or name is missing" do
+ @bucket.to_ref.should be_nil
+ end
+
+ it "should return the title as its reference" do
+ @bucket.name = "luke"
+ @bucket.type = "user"
+ @bucket.to_ref.should == "user[luke]"
+ end
+end
+
+describe Puppet::TransBucket, " when generating a configuration" do
+ before do
+ @bottom = Puppet::TransBucket.new
+ @bottom.type = "fake"
+ @bottom.name = "bottom"
+ @bottomobj = Puppet::TransObject.new("bottom", "user")
+ @bottom.push @bottomobj
+
+ @middle = Puppet::TransBucket.new
+ @middle.type = "fake"
+ @middle.name = "middle"
+ @middleobj = Puppet::TransObject.new("middle", "user")
+ @middle.push(@middleobj)
+ @middle.push(@bottom)
+
+ @top = Puppet::TransBucket.new
+ @top.type = "fake"
+ @top.name = "top"
+ @topobj = Puppet::TransObject.new("top", "user")
+ @top.push(@topobj)
+ @top.push(@middle)
+
+ @config = @top.to_configuration
+
+ @users = %w{top middle bottom}
+ @fakes = %w{fake[bottom] fake[middle] fake[top]}
+ end
+
+ it "should convert all transportable objects to RAL resources" do
+ @users.each do |name|
+ @config.vertices.find { |r| r.class.name == :user and r.title == name }.should be_instance_of(Puppet::Type.type(:user))
+ end
+ end
+
+ it "should convert all transportable buckets to RAL components" do
+ @fakes.each do |name|
+ @config.vertices.find { |r| r.class.name == :component and r.title == name }.should be_instance_of(Puppet::Type.type(:component))
+ end
+ end
+
+ it "should add all resources to the graph's resource table" do
+ @config.resource("fake[top]").should equal(@top)
+ end
+
+ it "should finalize all resources" do
+ @config.vertices.each do |vertex| vertex.should be_finalized end
+ end
+
+ it "should only call to_type on each resource once" do
+ @topobj.expects(:to_type)
+ @bottomobj.expects(:to_type)
+ @top.to_configuration
+ end
+
+ after do
+ Puppet::Type.allclear
+ end
+end
+
+describe Puppet::TransBucket, " when serializing" do
+ before do
+ @bucket = Puppet::TransBucket.new(%w{one two})
+ @bucket.name = "one"
+ @bucket.type = "two"
+ end
+
+ it "should be able to be dumped to yaml" do
+ proc { YAML.dump(@bucket) }.should_not raise_error
+ end
+
+ it "should dump YAML that produces an equivalent object" do
+ result = YAML.dump(@bucket)
+
+ newobj = YAML.load(result)
+ newobj.name.should == "one"
+ newobj.type.should == "two"
+ children = []
+ newobj.each do |o|
+ children << o
+ end
+ children.should == %w{one two}
+ end
+end
diff --git a/spec/unit/other/transobject.rb b/spec/unit/other/transobject.rb
new file mode 100755
index 000000000..07c9dc761
--- /dev/null
+++ b/spec/unit/other/transobject.rb
@@ -0,0 +1,116 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+describe Puppet::TransObject, " when building its search path" do
+end
+
+describe Puppet::TransObject, " when building its search path" do
+end
+#!/usr/bin/env ruby
+
+$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
+
+require 'puppet'
+require 'puppet/transportable'
+require 'puppettest'
+require 'puppettest/parsertesting'
+require 'yaml'
+
+class TestTransportable < Test::Unit::TestCase
+ include PuppetTest::ParserTesting
+
+ def test_yamldumpobject
+ obj = mk_transobject
+ obj.to_yaml_properties
+ str = nil
+ assert_nothing_raised {
+ str = YAML.dump(obj)
+ }
+
+ newobj = nil
+ assert_nothing_raised {
+ newobj = YAML.load(str)
+ }
+
+ assert(newobj.name, "Object has no name")
+ assert(newobj.type, "Object has no type")
+ end
+
+ def test_yamldumpbucket
+ objects = %w{/etc/passwd /etc /tmp /var /dev}.collect { |d|
+ mk_transobject(d)
+ }
+ bucket = mk_transbucket(*objects)
+ str = nil
+ assert_nothing_raised {
+ str = YAML.dump(bucket)
+ }
+
+ newobj = nil
+ assert_nothing_raised {
+ newobj = YAML.load(str)
+ }
+
+ assert(newobj.name, "Bucket has no name")
+ assert(newobj.type, "Bucket has no type")
+ end
+
+ # Verify that we correctly strip out collectable objects, since they should
+ # not be sent to the client.
+ def test_collectstrip
+ top = mk_transtree do |object, depth, width|
+ if width % 2 == 1
+ object.collectable = true
+ end
+ end
+
+ assert(top.flatten.find_all { |o| o.collectable }.length > 0,
+ "Could not find any collectable objects")
+
+ # Now strip out the collectable objects
+ top.collectstrip!
+
+ # And make sure they're actually gone
+ assert_equal(0, top.flatten.find_all { |o| o.collectable }.length,
+ "Still found collectable objects")
+ end
+
+ # Make sure our 'delve' command is working
+ def test_delve
+ top = mk_transtree do |object, depth, width|
+ if width % 2 == 1
+ object.collectable = true
+ end
+ end
+
+ objects = []
+ buckets = []
+ collectable = []
+
+ count = 0
+ assert_nothing_raised {
+ top.delve do |object|
+ count += 1
+ if object.is_a? Puppet::TransBucket
+ buckets << object
+ else
+ objects << object
+ if object.collectable
+ collectable << object
+ end
+ end
+ end
+ }
+
+ top.flatten.each do |obj|
+ assert(objects.include?(obj), "Missing obj %s[%s]" % [obj.type, obj.name])
+ end
+
+ assert_equal(collectable.length,
+ top.flatten.find_all { |o| o.collectable }.length,
+ "Found incorrect number of collectable objects")
+ end
+end
+
+# $Id$
diff --git a/spec/unit/parser/interpreter.rb b/spec/unit/parser/interpreter.rb
index c0f9d54b3..a79267b52 100755
--- a/spec/unit/parser/interpreter.rb
+++ b/spec/unit/parser/interpreter.rb
@@ -77,8 +77,8 @@ describe Puppet::Parser::Interpreter, " when creating parser instances" do
file = mock 'file'
file.stubs(:changed?).returns(true)
file.stubs(:file).returns("/whatever")
- Puppet.config.stubs(:read_file).with(file).returns(text)
- Puppet.config.parse(file)
+ Puppet.settings.stubs(:read_file).with(file).returns(text)
+ Puppet.settings.parse(file)
parser1 = mock 'parser1'
Puppet::Parser::Parser.expects(:new).with(:environment => :env1).returns(parser1)
diff --git a/spec/unit/ral/type.rb b/spec/unit/ral/type.rb
new file mode 100755
index 000000000..c8bf8c9b4
--- /dev/null
+++ b/spec/unit/ral/type.rb
@@ -0,0 +1,25 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+describe Puppet::Type, " when in a configuration" do
+ before do
+ @configuration = Puppet::Node::Configuration.new
+ @container = Puppet::Type.type(:component).create(:name => "container")
+ @one = Puppet::Type.type(:file).create(:path => "/file/one")
+ @two = Puppet::Type.type(:file).create(:path => "/file/two")
+ @configuration.add_resource @container
+ @configuration.add_resource @one
+ @configuration.add_resource @two
+ @configuration.add_edge! @container, @one
+ @configuration.add_edge! @container, @two
+ end
+
+ it "should have no parent if there is no in edge" do
+ @container.parent.should be_nil
+ end
+
+ it "should set its parent to its in edge" do
+ @one.parent.ref.should equal(@container.ref)
+ end
+end
diff --git a/spec/unit/util/config.rb b/spec/unit/util/config.rb
deleted file mode 100755
index 348a54893..000000000
--- a/spec/unit/util/config.rb
+++ /dev/null
@@ -1,408 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../spec_helper'
-
-describe Puppet::Util::Config, " when specifying defaults" do
- before do
- @config = Puppet::Util::Config.new
- end
-
- it "should start with no defined parameters" do
- @config.params.length.should == 0
- end
-
- it "should allow specification of default values associated with a section as an array" do
- @config.setdefaults(:section, :myvalue => ["defaultval", "my description"])
- end
-
- it "should not allow duplicate parameter specifications" do
- @config.setdefaults(:section, :myvalue => ["a", "b"])
- lambda { @config.setdefaults(:section, :myvalue => ["c", "d"]) }.should raise_error(ArgumentError)
- end
-
- it "should allow specification of default values associated with a section as a hash" do
- @config.setdefaults(:section, :myvalue => {:default => "defaultval", :desc => "my description"})
- end
-
- it "should consider defined parameters to be valid" do
- @config.setdefaults(:section, :myvalue => ["defaultval", "my description"])
- @config.valid?(:myvalue).should be_true
- end
-
- it "should require a description when defaults are specified with an array" do
- lambda { @config.setdefaults(:section, :myvalue => ["a value"]) }.should raise_error(ArgumentError)
- end
-
- it "should require a description when defaults are specified with a hash" do
- lambda { @config.setdefaults(:section, :myvalue => {:default => "a value"}) }.should raise_error(ArgumentError)
- end
-
- it "should support specifying owner, group, and mode when specifying files" do
- @config.setdefaults(:section, :myvalue => {:default => "/some/file", :owner => "blah", :mode => "boo", :group => "yay", :desc => "whatever"})
- end
-
- it "should support specifying a short name" do
- @config.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"})
- end
-
- it "should fail when short names conflict" do
- @config.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"})
- lambda { @config.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"}) }.should raise_error(ArgumentError)
- end
-end
-
-describe Puppet::Util::Config, " when setting values" do
- before do
- @config = Puppet::Util::Config.new
- @config.setdefaults :main, :myval => ["val", "desc"]
- @config.setdefaults :main, :bool => [true, "desc"]
- end
-
- it "should provide a method for setting values from other objects" do
- @config[:myval] = "something else"
- @config[:myval].should == "something else"
- end
-
- it "should support a getopt-specific mechanism for setting values" do
- @config.handlearg("--myval", "newval")
- @config[:myval].should == "newval"
- end
-
- it "should support a getopt-specific mechanism for turning booleans off" do
- @config.handlearg("--no-bool")
- @config[:bool].should == false
- end
-
- it "should support a getopt-specific mechanism for turning booleans on" do
- # Turn it off first
- @config[:bool] = false
- @config.handlearg("--bool")
- @config[:bool].should == true
- end
-
- it "should clear the cache when setting getopt-specific values" do
- @config.setdefaults :mysection, :one => ["whah", "yay"], :two => ["$one yay", "bah"]
- @config[:two].should == "whah yay"
- @config.handlearg("--one", "else")
- @config[:two].should == "else yay"
- end
-
- it "should not clear other values when setting getopt-specific values" do
- @config[:myval] = "yay"
- @config.handlearg("--no-bool")
- @config[:myval].should == "yay"
- end
-
- it "should call passed blocks when values are set" do
- values = []
- @config.setdefaults(:section, :hooker => {:default => "yay", :desc => "boo", :hook => lambda { |v| values << v }})
- values.should == []
-
- @config[:hooker] = "something"
- values.should == %w{something}
- end
-
- it "should munge values using the element-specific methods" do
- @config[:bool] = "false"
- @config[:bool].should == false
- end
-
- it "should prefer cli values to values set in Ruby code" do
- @config.handlearg("--myval", "cliarg")
- @config[:myval] = "memarg"
- @config[:myval].should == "cliarg"
- end
-end
-
-describe Puppet::Util::Config, " when returning values" do
- before do
- @config = Puppet::Util::Config.new
- @config.setdefaults :section, :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"], :four => ["$two $three FOUR", "d"]
- end
-
- it "should provide a mechanism for returning set values" do
- @config[:one] = "other"
- @config[:one].should == "other"
- end
-
- it "should interpolate default values for other parameters into returned parameter values" do
- @config[:one].should == "ONE"
- @config[:two].should == "ONE TWO"
- @config[:three].should == "ONE ONE TWO THREE"
- end
-
- it "should interpolate default values that themselves need to be interpolated" do
- @config[:four].should == "ONE TWO ONE ONE TWO THREE FOUR"
- end
-
- it "should interpolate set values for other parameters into returned parameter values" do
- @config[:one] = "on3"
- @config[:two] = "$one tw0"
- @config[:three] = "$one $two thr33"
- @config[:four] = "$one $two $three f0ur"
- @config[:one].should == "on3"
- @config[:two].should == "on3 tw0"
- @config[:three].should == "on3 on3 tw0 thr33"
- @config[:four].should == "on3 on3 tw0 on3 on3 tw0 thr33 f0ur"
- end
-
- it "should not cache interpolated values such that stale information is returned" do
- @config[:two].should == "ONE TWO"
- @config[:one] = "one"
- @config[:two].should == "one TWO"
- end
-
- it "should not cache values such that information from one environment is returned for another environment" do
- text = "[env1]\none = oneval\n[env2]\none = twoval\n"
- file = mock 'file'
- file.stubs(:changed?).returns(true)
- file.stubs(:file).returns("/whatever")
- @config.stubs(:read_file).with(file).returns(text)
- @config.parse(file)
-
- @config.value(:one, "env1").should == "oneval"
- @config.value(:one, "env2").should == "twoval"
- end
-
- it "should have a name determined by the 'name' parameter" do
- @config.setdefaults(:whatever, :name => ["something", "yayness"])
- @config.name.should == :something
- @config[:name] = :other
- @config.name.should == :other
- end
-end
-
-describe Puppet::Util::Config, " when choosing which value to return" do
- before do
- @config = Puppet::Util::Config.new
- @config.setdefaults :section,
- :one => ["ONE", "a"],
- :name => ["myname", "w"]
- end
-
- it "should return default values if no values have been set" do
- @config[:one].should == "ONE"
- end
-
- it "should return values set on the cli before values set in the configuration file" do
- text = "[main]\none = fileval\n"
- file = mock 'file'
- file.stubs(:changed?).returns(true)
- file.stubs(:file).returns("/whatever")
- @config.stubs(:parse_file).returns(text)
- @config.handlearg("--one", "clival")
- @config.parse(file)
-
- @config[:one].should == "clival"
- end
-
- it "should return values set on the cli before values set in Ruby" do
- @config[:one] = "rubyval"
- @config.handlearg("--one", "clival")
- @config[:one].should == "clival"
- end
-
- it "should return values set in the executable-specific section before values set in the main section" do
- text = "[main]\none = mainval\n[myname]\none = nameval\n"
- file = mock 'file'
- file.stubs(:changed?).returns(true)
- file.stubs(:file).returns("/whatever")
- @config.stubs(:read_file).with(file).returns(text)
- @config.parse(file)
-
- @config[:one].should == "nameval"
- end
-
- it "should not return values outside of its search path" do
- text = "[other]\none = oval\n"
- file = "/some/file"
- file = mock 'file'
- file.stubs(:changed?).returns(true)
- file.stubs(:file).returns("/whatever")
- @config.stubs(:read_file).with(file).returns(text)
- @config.parse(file)
- @config[:one].should == "ONE"
- end
-
- it "should return values in a specified environment" do
- text = "[env]\none = envval\n"
- file = "/some/file"
- file = mock 'file'
- file.stubs(:changed?).returns(true)
- file.stubs(:file).returns("/whatever")
- @config.stubs(:read_file).with(file).returns(text)
- @config.parse(file)
- @config.value(:one, "env").should == "envval"
- end
-
- it "should return values in a specified environment before values in the main or name sections" do
- text = "[env]\none = envval\n[main]\none = mainval\n[myname]\none = nameval\n"
- file = "/some/file"
- file = mock 'file'
- file.stubs(:changed?).returns(true)
- file.stubs(:file).returns("/whatever")
- @config.stubs(:read_file).with(file).returns(text)
- @config.parse(file)
- @config.value(:one, "env").should == "envval"
- end
-end
-
-describe Puppet::Util::Config, " when parsing its configuration" do
- before do
- @config = Puppet::Util::Config.new
- @config.setdefaults :section, :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"]
- end
-
- it "should return values set in the configuration file" do
- text = "[main]
- one = fileval
- "
- file = "/some/file"
- @config.expects(:read_file).with(file).returns(text)
- @config.parse(file)
- @config[:one].should == "fileval"
- end
-
- #484 - this should probably be in the regression area
- it "should not throw an exception on unknown parameters" do
- text = "[main]\nnosuchparam = mval\n"
- file = "/some/file"
- @config.expects(:read_file).with(file).returns(text)
- lambda { @config.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.
- @config.should respond_to(:old_parse)
- end
-
- it "should convert booleans in the configuration file into Ruby booleans" do
- text = "[main]
- one = true
- two = false
- "
- file = "/some/file"
- @config.expects(:read_file).with(file).returns(text)
- @config.parse(file)
- @config[:one].should == true
- @config[:two].should == false
- end
-
- it "should convert integers in the configuration file into Ruby Integers" do
- text = "[main]
- one = 65
- "
- file = "/some/file"
- @config.expects(:read_file).with(file).returns(text)
- @config.parse(file)
- @config[:one].should == 65
- end
-
- it "should support specifying file all metadata (owner, group, mode) in the configuration file" do
- @config.setdefaults :section, :myfile => ["/my/file", "a"]
-
- text = "[main]
- myfile = /other/file {owner = luke, group = luke, mode = 644}
- "
- file = "/some/file"
- @config.expects(:read_file).with(file).returns(text)
- @config.parse(file)
- @config[:myfile].should == "/other/file"
- @config.metadata(:myfile).should == {:owner => "luke", :group => "luke", :mode => "644"}
- end
-
- it "should support specifying file a single piece of metadata (owner, group, or mode) in the configuration file" do
- @config.setdefaults :section, :myfile => ["/my/file", "a"]
-
- text = "[main]
- myfile = /other/file {owner = luke}
- "
- file = "/some/file"
- @config.expects(:read_file).with(file).returns(text)
- @config.parse(file)
- @config[:myfile].should == "/other/file"
- @config.metadata(:myfile).should == {:owner => "luke"}
- end
-end
-
-describe Puppet::Util::Config, " when reparsing its configuration" do
- before do
- @config = Puppet::Util::Config.new
- @config.setdefaults :section, :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"]
- end
-
- it "should replace in-memory values with on-file values" do
- # Init the value
- text = "[main]\none = disk-init\n"
- file = mock 'file'
- file.stubs(:changed?).returns(true)
- file.stubs(:file).returns("/test/file")
- @config[:one] = "init"
- @config.file = file
-
- # Now replace the value
- text = "[main]\none = disk-replace\n"
-
- # This is kinda ridiculous - the reason it parses twice is that
- # it goes to parse again when we ask for the value, because the
- # mock always says it should get reparsed.
- @config.expects(:read_file).with(file).returns(text).times(2)
- @config.reparse
- @config[:one].should == "disk-replace"
- end
-
- it "should retain parameters set by cli when configuration files are reparsed" do
- @config.handlearg("--one", "clival")
-
- text = "[main]\none = on-disk\n"
- file = mock 'file'
- file.stubs(:file).returns("/test/file")
- @config.stubs(:read_file).with(file).returns(text)
- @config.parse(file)
-
- @config[:one].should == "clival"
- end
-
- it "should remove in-memory values that are no longer set in the file" do
- # Init the value
- text = "[main]\none = disk-init\n"
- file = mock 'file'
- file.stubs(:changed?).returns(true)
- file.stubs(:file).returns("/test/file")
- @config.expects(:read_file).with(file).returns(text)
- @config.parse(file)
- @config[:one].should == "disk-init"
-
- # Now replace the value
- text = "[main]\ntwo = disk-replace\n"
- @config.expects(:read_file).with(file).returns(text)
- @config.parse(file)
- #@config.reparse
-
- # The originally-overridden value should be replaced with the default
- @config[:one].should == "ONE"
-
- # and we should now have the new value in memory
- @config[:two].should == "disk-replace"
- end
-end
-
-#describe Puppet::Util::Config, " when being used to manage the host machine" do
-# it "should provide a method that writes files with the correct modes"
-#
-# it "should provide a method that creates directories with the correct modes"
-#
-# it "should provide a method to declare what directories should exist"
-#
-# it "should provide a method to trigger enforcing of file modes on existing files and directories"
-#
-# it "should provide a method to convert the file mode enforcement into a Puppet manifest"
-#
-# it "should provide an option to create needed users and groups"
-#
-# it "should provide a method to print out the current configuration"
-#
-# it "should be able to provide all of its parameters in a format compatible with GetOpt::Long"
-#
-# it "should not attempt to manage files within /dev"
-#end
diff --git a/spec/unit/util/settings.rb b/spec/unit/util/settings.rb
new file mode 100755
index 000000000..8d11737b3
--- /dev/null
+++ b/spec/unit/util/settings.rb
@@ -0,0 +1,535 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+describe Puppet::Util::Settings, " when specifying defaults" do
+ before do
+ @settings = Puppet::Util::Settings.new
+ end
+
+ it "should start with no defined parameters" do
+ @settings.params.length.should == 0
+ end
+
+ it "should allow specification of default values associated with a section as an array" do
+ @settings.setdefaults(:section, :myvalue => ["defaultval", "my description"])
+ end
+
+ it "should not allow duplicate parameter specifications" do
+ @settings.setdefaults(:section, :myvalue => ["a", "b"])
+ lambda { @settings.setdefaults(:section, :myvalue => ["c", "d"]) }.should raise_error(ArgumentError)
+ end
+
+ it "should allow specification of default values associated with a section as a hash" do
+ @settings.setdefaults(:section, :myvalue => {:default => "defaultval", :desc => "my description"})
+ end
+
+ it "should consider defined parameters to be valid" do
+ @settings.setdefaults(:section, :myvalue => ["defaultval", "my description"])
+ @settings.valid?(:myvalue).should be_true
+ end
+
+ it "should require a description when defaults are specified with an array" do
+ lambda { @settings.setdefaults(:section, :myvalue => ["a value"]) }.should raise_error(ArgumentError)
+ end
+
+ it "should require a description when defaults are specified with a hash" do
+ lambda { @settings.setdefaults(:section, :myvalue => {:default => "a value"}) }.should raise_error(ArgumentError)
+ end
+
+ it "should support specifying owner, group, and mode when specifying files" do
+ @settings.setdefaults(:section, :myvalue => {:default => "/some/file", :owner => "blah", :mode => "boo", :group => "yay", :desc => "whatever"})
+ end
+
+ it "should support specifying a short name" do
+ @settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"})
+ end
+
+ it "should fail when short names conflict" do
+ @settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"})
+ lambda { @settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"}) }.should raise_error(ArgumentError)
+ end
+end
+
+describe Puppet::Util::Settings, " when setting values" do
+ before do
+ @settings = Puppet::Util::Settings.new
+ @settings.setdefaults :main, :myval => ["val", "desc"]
+ @settings.setdefaults :main, :bool => [true, "desc"]
+ end
+
+ it "should provide a method for setting values from other objects" do
+ @settings[:myval] = "something else"
+ @settings[:myval].should == "something else"
+ end
+
+ it "should support a getopt-specific mechanism for setting values" do
+ @settings.handlearg("--myval", "newval")
+ @settings[:myval].should == "newval"
+ end
+
+ it "should support a getopt-specific mechanism for turning booleans off" do
+ @settings.handlearg("--no-bool")
+ @settings[:bool].should == false
+ end
+
+ it "should support a getopt-specific mechanism for turning booleans on" do
+ # Turn it off first
+ @settings[:bool] = false
+ @settings.handlearg("--bool")
+ @settings[:bool].should == true
+ end
+
+ it "should clear the cache when setting getopt-specific values" do
+ @settings.setdefaults :mysection, :one => ["whah", "yay"], :two => ["$one yay", "bah"]
+ @settings[:two].should == "whah yay"
+ @settings.handlearg("--one", "else")
+ @settings[:two].should == "else yay"
+ end
+
+ it "should not clear other values when setting getopt-specific values" do
+ @settings[:myval] = "yay"
+ @settings.handlearg("--no-bool")
+ @settings[:myval].should == "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 }})
+ values.should == []
+
+ @settings[:hooker] = "something"
+ values.should == %w{something}
+ end
+
+ it "should munge values using the element-specific methods" do
+ @settings[:bool] = "false"
+ @settings[:bool].should == false
+ end
+
+ it "should prefer cli values to values set in Ruby code" do
+ @settings.handlearg("--myval", "cliarg")
+ @settings[:myval] = "memarg"
+ @settings[:myval].should == "cliarg"
+ end
+end
+
+describe Puppet::Util::Settings, " when returning values" do
+ before do
+ @settings = Puppet::Util::Settings.new
+ @settings.setdefaults :section, :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"], :four => ["$two $three FOUR", "d"]
+ end
+
+ it "should provide a mechanism for returning set values" do
+ @settings[:one] = "other"
+ @settings[:one].should == "other"
+ end
+
+ it "should interpolate default values for other parameters into returned parameter values" do
+ @settings[:one].should == "ONE"
+ @settings[:two].should == "ONE TWO"
+ @settings[:three].should == "ONE ONE TWO THREE"
+ end
+
+ it "should interpolate default values that themselves need to be interpolated" do
+ @settings[:four].should == "ONE TWO ONE ONE TWO THREE FOUR"
+ end
+
+ it "should interpolate set values for other parameters into returned parameter values" do
+ @settings[:one] = "on3"
+ @settings[:two] = "$one tw0"
+ @settings[:three] = "$one $two thr33"
+ @settings[:four] = "$one $two $three f0ur"
+ @settings[:one].should == "on3"
+ @settings[:two].should == "on3 tw0"
+ @settings[:three].should == "on3 on3 tw0 thr33"
+ @settings[:four].should == "on3 on3 tw0 on3 on3 tw0 thr33 f0ur"
+ end
+
+ it "should not cache interpolated values such that stale information is returned" do
+ @settings[:two].should == "ONE TWO"
+ @settings[:one] = "one"
+ @settings[:two].should == "one TWO"
+ end
+
+ it "should not cache values such that information from one environment is returned for another environment" do
+ text = "[env1]\none = oneval\n[env2]\none = twoval\n"
+ file = mock 'file'
+ file.stubs(:changed?).returns(true)
+ file.stubs(:file).returns("/whatever")
+ @settings.stubs(:read_file).with(file).returns(text)
+ @settings.parse(file)
+
+ @settings.value(:one, "env1").should == "oneval"
+ @settings.value(:one, "env2").should == "twoval"
+ end
+
+ it "should have a name determined by the 'name' parameter" do
+ @settings.setdefaults(:whatever, :name => ["something", "yayness"])
+ @settings.name.should == :something
+ @settings[:name] = :other
+ @settings.name.should == :other
+ end
+end
+
+describe Puppet::Util::Settings, " when choosing which value to return" do
+ before do
+ @settings = Puppet::Util::Settings.new
+ @settings.setdefaults :section,
+ :one => ["ONE", "a"],
+ :name => ["myname", "w"]
+ end
+
+ it "should return default values if no values have been set" do
+ @settings[:one].should == "ONE"
+ end
+
+ it "should return values set on the cli before values set in the configuration file" do
+ text = "[main]\none = fileval\n"
+ file = mock 'file'
+ file.stubs(:changed?).returns(true)
+ file.stubs(:file).returns("/whatever")
+ @settings.stubs(:parse_file).returns(text)
+ @settings.handlearg("--one", "clival")
+ @settings.parse(file)
+
+ @settings[:one].should == "clival"
+ end
+
+ it "should return values set on the cli before values set in Ruby" do
+ @settings[:one] = "rubyval"
+ @settings.handlearg("--one", "clival")
+ @settings[:one].should == "clival"
+ end
+
+ it "should return values set in the executable-specific section before values set in the main section" do
+ text = "[main]\none = mainval\n[myname]\none = nameval\n"
+ file = mock 'file'
+ file.stubs(:changed?).returns(true)
+ file.stubs(:file).returns("/whatever")
+ @settings.stubs(:read_file).with(file).returns(text)
+ @settings.parse(file)
+
+ @settings[:one].should == "nameval"
+ end
+
+ it "should not return values outside of its search path" do
+ text = "[other]\none = oval\n"
+ file = "/some/file"
+ file = mock 'file'
+ file.stubs(:changed?).returns(true)
+ file.stubs(:file).returns("/whatever")
+ @settings.stubs(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ @settings[:one].should == "ONE"
+ end
+
+ it "should return values in a specified environment" do
+ text = "[env]\none = envval\n"
+ file = "/some/file"
+ file = mock 'file'
+ file.stubs(:changed?).returns(true)
+ file.stubs(:file).returns("/whatever")
+ @settings.stubs(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ @settings.value(:one, "env").should == "envval"
+ end
+
+ it "should return values in a specified environment before values in the main or name sections" do
+ text = "[env]\none = envval\n[main]\none = mainval\n[myname]\none = nameval\n"
+ file = "/some/file"
+ file = mock 'file'
+ file.stubs(:changed?).returns(true)
+ file.stubs(:file).returns("/whatever")
+ @settings.stubs(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ @settings.value(:one, "env").should == "envval"
+ end
+end
+
+describe Puppet::Util::Settings, " when parsing its configuration" do
+ before do
+ @settings = Puppet::Util::Settings.new
+ @settings.setdefaults :section, :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"]
+ end
+
+ it "should return values set in the configuration file" do
+ text = "[main]
+ one = fileval
+ "
+ file = "/some/file"
+ @settings.expects(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ @settings[:one].should == "fileval"
+ end
+
+ #484 - this should probably be in the regression area
+ it "should not throw an exception on unknown parameters" do
+ text = "[main]\nnosuchparam = mval\n"
+ file = "/some/file"
+ @settings.expects(:read_file).with(file).returns(text)
+ 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
+ two = false
+ "
+ file = "/some/file"
+ @settings.expects(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ @settings[:one].should == true
+ @settings[:two].should == false
+ end
+
+ it "should convert integers in the configuration file into Ruby Integers" do
+ text = "[main]
+ one = 65
+ "
+ file = "/some/file"
+ @settings.expects(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ @settings[:one].should == 65
+ end
+
+ it "should support specifying file all metadata (owner, group, mode) in the configuration file" do
+ @settings.setdefaults :section, :myfile => ["/myfile", "a"]
+
+ text = "[main]
+ myfile = /other/file {owner = luke, group = luke, mode = 644}
+ "
+ file = "/some/file"
+ @settings.expects(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ @settings[:myfile].should == "/other/file"
+ @settings.metadata(:myfile).should == {:owner => "luke", :group => "luke", :mode => "644"}
+ end
+
+ it "should support specifying file a single piece of metadata (owner, group, or mode) in the configuration file" do
+ @settings.setdefaults :section, :myfile => ["/myfile", "a"]
+
+ text = "[main]
+ myfile = /other/file {owner = luke}
+ "
+ file = "/some/file"
+ @settings.expects(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ @settings[:myfile].should == "/other/file"
+ @settings.metadata(:myfile).should == {:owner => "luke"}
+ end
+end
+
+describe Puppet::Util::Settings, " when reparsing its configuration" do
+ before do
+ @settings = Puppet::Util::Settings.new
+ @settings.setdefaults :section, :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"]
+ end
+
+ it "should replace in-memory values with on-file values" do
+ # Init the value
+ text = "[main]\none = disk-init\n"
+ file = mock 'file'
+ file.stubs(:changed?).returns(true)
+ file.stubs(:file).returns("/test/file")
+ @settings[:one] = "init"
+ @settings.file = file
+
+ # Now replace the value
+ text = "[main]\none = disk-replace\n"
+
+ # This is kinda ridiculous - the reason it parses twice is that
+ # it goes to parse again when we ask for the value, because the
+ # mock always says it should get reparsed.
+ @settings.expects(:read_file).with(file).returns(text).times(2)
+ @settings.reparse
+ @settings[:one].should == "disk-replace"
+ end
+
+ it "should retain parameters set by cli when configuration files are reparsed" do
+ @settings.handlearg("--one", "clival")
+
+ text = "[main]\none = on-disk\n"
+ file = mock 'file'
+ file.stubs(:file).returns("/test/file")
+ @settings.stubs(:read_file).with(file).returns(text)
+ @settings.parse(file)
+
+ @settings[:one].should == "clival"
+ end
+
+ it "should remove in-memory values that are no longer set in the file" do
+ # Init the value
+ text = "[main]\none = disk-init\n"
+ file = mock 'file'
+ file.stubs(:changed?).returns(true)
+ file.stubs(:file).returns("/test/file")
+ @settings.expects(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ @settings[:one].should == "disk-init"
+
+ # Now replace the value
+ text = "[main]\ntwo = disk-replace\n"
+ @settings.expects(:read_file).with(file).returns(text)
+ @settings.parse(file)
+ #@settings.reparse
+
+ # The originally-overridden value should be replaced with the default
+ @settings[:one].should == "ONE"
+
+ # and we should now have the new value in memory
+ @settings[:two].should == "disk-replace"
+ end
+end
+
+describe Puppet::Util::Settings, " when being used to manage the host machine" do
+ before do
+ @settings = Puppet::Util::Settings.new
+ @settings.setdefaults :main, :maindir => ["/maindir", "a"], :seconddir => ["/seconddir", "a"]
+ @settings.setdefaults :other, :otherdir => {:default => "/otherdir", :desc => "a", :owner => "luke", :group => "johnny", :mode => 0755}
+ @settings.setdefaults :files, :myfile => {:default => "/myfile", :desc => "a", :mode => 0755}
+ end
+
+ it "should provide a method that writes files with the correct modes" do
+ pending "Not converted from test/unit yet"
+ end
+
+ it "should provide a method that creates directories with the correct modes" do
+ Puppet::Util::SUIDManager.expects(:asuser).with("luke", "johnny").yields
+ Dir.expects(:mkdir).with("/otherdir", 0755)
+ @settings.mkdir(:otherdir)
+ end
+
+ it "should be able to create needed directories in a single section" do
+ Dir.expects(:mkdir).with("/maindir")
+ Dir.expects(:mkdir).with("/seconddir")
+ @settings.use(:main)
+ end
+
+ it "should be able to create needed directories in multiple sections" do
+ Dir.expects(:mkdir).with("/maindir")
+ Dir.expects(:mkdir).with("/otherdir", 0755)
+ Dir.expects(:mkdir).with("/seconddir")
+ @settings.use(:main, :other)
+ end
+
+ it "should provide a method to trigger enforcing of file modes on existing files and directories" do
+ pending "Not converted from test/unit yet"
+ end
+
+ it "should provide a method to convert the file mode enforcement into a Puppet manifest" do
+ pending "Not converted from test/unit yet"
+ end
+
+ it "should create files when configured to do so with the :create parameter"
+
+ it "should provide a method to convert the file mode enforcement into transportable resources" do
+ # Make it think we're root so it tries to manage user and group.
+ Puppet.features.stubs(:root?).returns(true)
+ File.stubs(:exist?).with("/myfile").returns(true)
+ trans = nil
+ trans = @settings.to_transportable
+ resources = []
+ trans.delve { |obj| resources << obj if obj.is_a? Puppet::TransObject }
+ %w{/maindir /seconddir /otherdir /myfile}.each do |path|
+ obj = resources.find { |r| r.type == "file" and r.name == path }
+ if path.include?("dir")
+ obj[:ensure].should == :directory
+ else
+ # Do not create the file, just manage mode
+ obj[:ensure].should be_nil
+ end
+ obj.should be_instance_of(Puppet::TransObject)
+ case path
+ when "/otherdir":
+ obj[:owner].should == "luke"
+ obj[:group].should == "johnny"
+ obj[:mode].should == 0755
+ when "/myfile":
+ obj[:mode].should == 0755
+ end
+ end
+ end
+
+ it "should not try to manage user or group when not running as root" do
+ Puppet.features.stubs(:root?).returns(false)
+ trans = nil
+ trans = @settings.to_transportable(:other)
+ trans.delve do |obj|
+ next unless obj.is_a?(Puppet::TransObject)
+ obj[:owner].should be_nil
+ obj[:group].should be_nil
+ end
+ end
+
+ it "should add needed users and groups to the manifest when asked" do
+ # This is how we enable user/group management
+ @settings.setdefaults :main, :mkusers => [true, "w"]
+ Puppet.features.stubs(:root?).returns(false)
+ trans = nil
+ trans = @settings.to_transportable(:other)
+ resources = []
+ trans.delve { |obj| resources << obj if obj.is_a? Puppet::TransObject and obj.type != "file" }
+
+ user = resources.find { |r| r.type == "user" }
+ user.should be_instance_of(Puppet::TransObject)
+ user.name.should == "luke"
+ user[:ensure].should == :present
+
+ # This should maybe be a separate test, but...
+ group = resources.find { |r| r.type == "group" }
+ group.should be_instance_of(Puppet::TransObject)
+ group.name.should == "johnny"
+ group[:ensure].should == :present
+ end
+
+ it "should ignore tags and schedules when creating files and directories"
+
+ it "should apply all resources in debug mode to reduce logging"
+
+ it "should not try to manage absent files" do
+ # Make it think we're root so it tries to manage user and group.
+ Puppet.features.stubs(:root?).returns(true)
+ trans = nil
+ trans = @settings.to_transportable
+ file = nil
+ trans.delve { |obj| file = obj if obj.name == "/myfile" }
+ file.should be_nil
+ end
+
+ it "should be able to turn the current configuration into a parseable manifest"
+
+ it "should convert octal numbers correctly when producing a manifest"
+
+ it "should be able to provide all of its parameters in a format compatible with GetOpt::Long" do
+ pending "Not converted from test/unit yet"
+ end
+
+ it "should not attempt to manage files within /dev" do
+ pending "Not converted from test/unit yet"
+ end
+
+ it "should not modify the stored state database when managing resources" do
+ Puppet::Util::Storage.expects(:store).never
+ Puppet::Util::Storage.expects(:load).never
+ Dir.expects(:mkdir).with("/maindir")
+ @settings.use(:main)
+ end
+
+ it "should convert all relative paths to fully-qualified paths (#795)" do
+ @settings[:myfile] = "unqualified"
+ dir = Dir.getwd
+ @settings[:myfile].should == File.join(dir, "unqualified")
+ end
+
+ it "should support a method for re-using all currently used sections" do
+ Dir.expects(:mkdir).with(@settings[:otherdir], 0755).times(2)
+ @settings.use(:other)
+ @settings.reuse
+ end
+end
diff --git a/test/certmgr/certmgr.rb b/test/certmgr/certmgr.rb
index fb1611d7f..3d863dc27 100755
--- a/test/certmgr/certmgr.rb
+++ b/test/certmgr/certmgr.rb
@@ -239,13 +239,13 @@ class TestCertMgr < Test::Unit::TestCase
ca.revoke(h1.serial)
- oldcert = File.read(Puppet.config[:cacert])
- oldserial = File.read(Puppet.config[:serial])
+ oldcert = File.read(Puppet.settings[:cacert])
+ oldserial = File.read(Puppet.settings[:serial])
# Recreate the CA from disk
ca = mkCA()
- newcert = File.read(Puppet.config[:cacert])
- newserial = File.read(Puppet.config[:serial])
+ newcert = File.read(Puppet.settings[:cacert])
+ newserial = File.read(Puppet.settings[:serial])
assert_equal(oldcert, newcert, "The certs are not equal after making a new CA.")
assert_equal(oldserial, newserial, "The serials are not equal after making a new CA.")
store = mkStore(ca)
diff --git a/test/certmgr/inventory.rb b/test/certmgr/inventory.rb
index 15d3e5217..9efcb0c09 100755
--- a/test/certmgr/inventory.rb
+++ b/test/certmgr/inventory.rb
@@ -56,8 +56,8 @@ class TestCertInventory < Test::Unit::TestCase
file.expects(:puts).with do |written|
written.include? cert.subject.to_s
end
- Puppet::Util::Config.any_instance.stubs(:write)
- Puppet::Util::Config.any_instance.expects(:write).
+ Puppet::Util::Settings.any_instance.stubs(:write)
+ Puppet::Util::Settings.any_instance.expects(:write).
with(:cert_inventory, 'a').yields(file)
Puppet::SSLCertificates::Inventory.add(cert)
diff --git a/test/data/snippets/failmissingexecpath.pp b/test/data/snippets/failmissingexecpath.pp
deleted file mode 100644
index b03875547..000000000
--- a/test/data/snippets/failmissingexecpath.pp
+++ /dev/null
@@ -1,14 +0,0 @@
-define distloc($path) {
- file { "/tmp/exectesting1":
- ensure => file
- }
- exec { "exectest":
- command => "touch $path",
- subscribe => File["/tmp/exectesting1"],
- refreshonly => true
- }
-}
-
-distloc { yay:
- path => "/tmp/execdisttesting",
-}
diff --git a/test/language/snippets.rb b/test/language/snippets.rb
index 2c74543e7..7168a81d8 100755
--- a/test/language/snippets.rb
+++ b/test/language/snippets.rb
@@ -197,7 +197,7 @@ class TestSnippets < Test::Unit::TestCase
def snippet_classpathtest
path = "/tmp/classtest"
- file = @file[path]
+ file = @configuration.resource(:file, path)
assert(file, "did not create file %s" % path)
assert_nothing_raised {
@@ -271,14 +271,6 @@ class TestSnippets < Test::Unit::TestCase
assert_mode_equal(0755, file)
end
- def snippet_failmissingexecpath
- file = "/tmp/exectesting1"
- execfile = "/tmp/execdisttesting"
- assert_file(file)
-
- assert_nil(Puppet::Type.type(:exec)["exectest"], "invalid exec was created")
- end
-
def snippet_selectorvalues
nums = %w{1 2 3 4 5}
files = nums.collect { |n|
@@ -472,13 +464,14 @@ class TestSnippets < Test::Unit::TestCase
:Manifest => snippet(file),
:Local => true
)
- server.send(:fact_handler).stubs(:set)
- server.send(:fact_handler).stubs(:get).returns(facts)
+ facts = Puppet::Node::Facts.new("testhost", facts)
+ Puppet::Node::Facts.stubs(:save)
+ Puppet::Node::Facts.stubs(:find).returns(facts)
client = Puppet::Network::Client.master.new(
:Master => server,
:Cache => false
)
- client.class.stubs(:facts).returns(facts)
+ client.class.stubs(:facts).returns(facts.values)
assert(client.local)
assert_nothing_raised {
@@ -507,6 +500,7 @@ class TestSnippets < Test::Unit::TestCase
assert(obj.name)
}
}
+ @configuration = client.configuration
assert_nothing_raised {
self.send(mname)
}
diff --git a/test/lib/puppettest.rb b/test/lib/puppettest.rb
index b56bc563e..021d6d1de 100755
--- a/test/lib/puppettest.rb
+++ b/test/lib/puppettest.rb
@@ -5,7 +5,12 @@ $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '../../lib
require 'puppet'
require 'mocha'
-require 'test/unit'
+
+# Only load the test/unit class if we're not in the spec directory.
+# Else we get the bogus 'no tests, no failures' message.
+unless Dir.getwd =~ /spec/
+ require 'test/unit'
+end
# Yay; hackish but it works
if ARGV.include?("-d")
@@ -141,7 +146,7 @@ module PuppetTest
end
@configpath = File.join(tmpdir,
- self.class.to_s + "configdir" + @@testcount.to_s + "/"
+ "configdir" + @@testcount.to_s + "/"
)
unless defined? $user and $group
@@ -149,7 +154,7 @@ module PuppetTest
$group = nonrootgroup().gid.to_s
end
- Puppet.config.clear
+ Puppet.settings.clear
Puppet[:user] = $user
Puppet[:group] = $group
@@ -197,8 +202,7 @@ module PuppetTest
@@tmpfilenum = 1
end
- f = File.join(self.tmpdir(), self.class.to_s + "_" + @method_name.to_s +
- @@tmpfilenum.to_s)
+ f = File.join(self.tmpdir(), "tempfile_" + @@tmpfilenum.to_s)
@@tmpfiles << f
return f
end
@@ -223,11 +227,11 @@ module PuppetTest
when "Darwin": "/private/tmp"
when "SunOS": "/var/tmp"
else
- "/tmp"
+ "/tmp"
end
- @tmpdir = File.join(@tmpdir, "puppettesting")
+ @tmpdir = File.join(@tmpdir, "puppettesting" + Process.pid.to_s)
unless File.exists?(@tmpdir)
FileUtils.mkdir_p(@tmpdir)
@@ -260,6 +264,8 @@ module PuppetTest
Puppet::Type.allclear
Puppet::Util::Storage.clear
Puppet.clear
+ Puppet.settings.clear
+ Puppet::Indirector::Indirection.clear_cache
@memoryatend = Puppet::Util.memory
diff = @memoryatend - @memoryatstart
diff --git a/test/lib/puppettest/graph.rb b/test/lib/puppettest/graph.rb
deleted file mode 100644
index db77889bd..000000000
--- a/test/lib/puppettest/graph.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env ruby
-#
-# Created by Luke A. Kanies on 2006-11-24.
-# Copyright (c) 2006. All rights reserved.
-
-require 'puppet/util/graph'
-
-class Container
- include Puppet::Util::Graph
- include Enumerable
- attr_accessor :name
- def each
- @children.each do |c| yield c end
- end
-
- def initialize(name, ary)
- @name = name
- @children = ary
- end
-
- def push(*ary)
- ary.each { |c| @children.push(c)}
- end
-
- def to_s
- @name
- end
-end
-
-module PuppetTest::Graph
- def build_tree
- one = Container.new("one", %w{a b})
- two = Container.new("two", ["c", "d"])
- three = Container.new("three", ["i", "j"])
- middle = Container.new("middle", ["e", "f", two])
- top = Container.new("top", ["g", "h", middle, one, three])
- return one, two, three, middle, top
- end
-end
-
-# $Id$
diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb
index eef0cd8bc..62fa7213e 100644
--- a/test/lib/puppettest/parsertesting.rb
+++ b/test/lib/puppettest/parsertesting.rb
@@ -42,7 +42,6 @@ module PuppetTest::ParserTesting
end
def mkcompile(parser = nil)
- require 'puppet/network/handler/node'
parser ||= mkparser
node = mknode
return Compile.new(node, parser)
@@ -309,17 +308,17 @@ module PuppetTest::ParserTesting
)
}
- config = nil
+ trans = nil
assert_nothing_raised {
- config = interp.compile(mknode)
+ trans = interp.compile(mknode)
}
- comp = nil
+ config = nil
assert_nothing_raised {
- comp = config.extract.to_type
+ config = trans.extract.to_configuration
}
- assert_apply(comp)
+ config.apply
files.each do |file|
assert(FileTest.exists?(file), "Did not create %s" % file)
diff --git a/test/lib/puppettest/runnable_test.rb b/test/lib/puppettest/runnable_test.rb
new file mode 100644
index 000000000..e4b0f9033
--- /dev/null
+++ b/test/lib/puppettest/runnable_test.rb
@@ -0,0 +1,30 @@
+# Manage whether a test is runnable.
+module PuppetTest
+ module RunnableTest
+ # Confine this test based on specified criteria. The keys of the
+ # hash should be the message to use if the test is not suitable,
+ # and the values should be either 'true' or 'false'; true values
+ # mean the test is suitable.
+ def confine(hash)
+ @confines ||= {}
+ hash.each do |message, result|
+ @confines[message] = result
+ end
+ end
+
+ # Evaluate all of our tests to see if any of them are false
+ # and thus whether this test is considered not runnable.
+ def runnable?
+ @messages ||= []
+ return false unless @messages.empty?
+ return true unless defined? @confines
+ @confines.find_all do |message, result|
+ ! result
+ end.each do |message, result|
+ @messages << message
+ end
+
+ return @messages.empty?
+ end
+ end
+end
diff --git a/test/lib/puppettest/support/assertions.rb b/test/lib/puppettest/support/assertions.rb
index 9369f17e7..7e3e5ca2b 100644
--- a/test/lib/puppettest/support/assertions.rb
+++ b/test/lib/puppettest/support/assertions.rb
@@ -38,7 +38,7 @@ module PuppetTest
run_events(:rollback, trans, events, msg)
end
- def assert_events(events, *items)
+ def assert_events(events, *resources)
trans = nil
comp = nil
msg = nil
@@ -46,56 +46,26 @@ module PuppetTest
unless events.is_a? Array
raise Puppet::DevError, "Incorrect call of assert_events"
end
- if items[-1].is_a? String
- msg = items.pop
+ if resources[-1].is_a? String
+ msg = resources.pop
end
- remove_comp = false
- # They either passed a comp or a list of items.
- if items[0].is_a? Puppet.type(:component)
- comp = items.shift
- else
- comp = newcomp(items[0].title, *items)
- remove_comp = true
- end
- msg ||= comp.title
- assert_nothing_raised("Component %s failed" % [msg]) {
- trans = comp.evaluate
- }
+ config = resources2config(*resources)
+ transaction = Puppet::Transaction.new(config)
- run_events(:evaluate, trans, events, msg)
+ run_events(:evaluate, transaction, events, msg)
- if remove_comp
- Puppet.type(:component).delete(comp)
- end
-
- return trans
+ return transaction
end
# A simpler method that just applies what we have.
- def assert_apply(*objects)
- if objects[0].is_a?(Puppet.type(:component))
- comp = objects.shift
- unless objects.empty?
- objects.each { |o| comp.push o }
- end
- else
- comp = newcomp(*objects)
- end
- trans = nil
-
- assert_nothing_raised("Failed to create transaction") {
- trans = comp.evaluate
- }
+ def assert_apply(*resources)
+ config = resources2config(*resources)
events = nil
- assert_nothing_raised("Failed to evaluate transaction") {
- events = trans.evaluate.collect { |e| e.event }
+ assert_nothing_raised("Failed to evaluate") {
+ events = config.apply.events
}
- trans.cleanup
- Puppet.type(:component).delete(comp)
events
end
end
-
-# $Id$
diff --git a/test/lib/puppettest/support/resources.rb b/test/lib/puppettest/support/resources.rb
index 45d89c5fb..18d7caa77 100755
--- a/test/lib/puppettest/support/resources.rb
+++ b/test/lib/puppettest/support/resources.rb
@@ -4,34 +4,34 @@
# Copyright (c) 2006. All rights reserved.
module PuppetTest::Support::Resources
- def treefile(name)
- Puppet::Type.type(:file).create :path => "/tmp/#{name}", :mode => 0755
+ def tree_resource(name)
+ Puppet::Type.type(:file).create :title => name, :path => "/tmp/#{name}", :mode => 0755
end
- def treecomp(name)
+ def tree_container(name)
Puppet::Type::Component.create :name => name, :type => "yay"
end
- def treenode(name, *children)
- comp = treecomp name
- children.each do |c|
- if c.is_a?(String)
- comp.push treefile(c)
- else
- comp.push c
+ def treenode(config, name, *resources)
+ comp = tree_container name
+ resources.each do |resource|
+ if resource.is_a?(String)
+ resource = tree_resource(resource)
end
+ config.add_edge!(comp, resource)
+ config.add_resource resource unless config.resource(resource.ref)
end
return comp
end
def mktree
- one = treenode("one", "a", "b")
- two = treenode("two", "c", "d")
- middle = treenode("middle", "e", "f", two)
- top = treenode("top", "g", "h", middle, one)
+ configuration = Puppet::Node::Configuration.new do |config|
+ one = treenode(config, "one", "a", "b")
+ two = treenode(config, "two", "c", "d")
+ middle = treenode(config, "middle", "e", "f", two)
+ top = treenode(config, "top", "g", "h", middle, one)
+ end
- return one, two, middle, top
+ return configuration
end
end
-
-# $Id$ \ No newline at end of file
diff --git a/test/lib/puppettest/support/utils.rb b/test/lib/puppettest/support/utils.rb
index c7d54d5e6..7f4260e31 100644
--- a/test/lib/puppettest/support/utils.rb
+++ b/test/lib/puppettest/support/utils.rb
@@ -19,6 +19,25 @@ module PuppetTest
}
end
+ # Turn a list of resources, or possibly a configuration and some resources,
+ # into a configuration object.
+ def resources2config(*resources)
+ if resources[0].is_a?(Puppet::Node::Configuration)
+ config = resources.shift
+ unless resources.empty?
+ resources.each { |r| config.add_resource r }
+ end
+ elsif resources[0].is_a?(Puppet.type(:component))
+ raise ArgumentError, "resource2config() no longer accpts components"
+ comp = resources.shift
+ comp.delve
+ else
+ config = Puppet::Node::Configuration.new
+ resources.each { |res| config.add_resource res }
+ end
+ return config
+ end
+
# stop any services that might be hanging around
def stopservices
if stype = Puppet::Type.type(:service)
@@ -127,20 +146,17 @@ module PuppetTest
}
end
- def newcomp(*ary)
- name = nil
- if ary[0].is_a?(String)
- name = ary.shift
+ def mk_configuration(*resources)
+ if resources[0].is_a?(String)
+ name = resources.shift
else
- name = ary[0].title
+ name = :testing
+ end
+ config = Puppet::Node::Configuration.new :testing do |conf|
+ resources.each { |resource| conf.add_resource resource }
end
- comp = Puppet.type(:component).create(:name => name)
- ary.each { |item|
- comp.push item
- }
-
- return comp
+ return config
end
def setme
diff --git a/test/lib/puppettest/testcase.rb b/test/lib/puppettest/testcase.rb
index cfedeee26..15c835854 100644
--- a/test/lib/puppettest/testcase.rb
+++ b/test/lib/puppettest/testcase.rb
@@ -4,28 +4,11 @@
# Copyright (c) 2007. All rights reserved.
require 'puppettest'
+require 'puppettest/runnable_test'
class PuppetTest::TestCase < Test::Unit::TestCase
include PuppetTest
- def self.confine(hash)
- @confines ||= {}
- hash.each do |message, result|
- @confines[message] = result
- end
- end
-
- def self.runnable?
- @messages ||= []
- return false unless @messages.empty?
- return true unless defined? @confines
- @confines.find_all do |message, result|
- ! result
- end.each do |message, result|
- @messages << message
- end
-
- return @messages.empty?
- end
+ extend PuppetTest::RunnableTest
def self.suite
# Always skip this parent class. It'd be nice if there were a
@@ -44,5 +27,3 @@ class PuppetTest::TestCase < Test::Unit::TestCase
end
end
end
-
-# $Id$
diff --git a/test/network/client/ca.rb b/test/network/client/ca.rb
index 00ed7413a..511b6fcaa 100755
--- a/test/network/client/ca.rb
+++ b/test/network/client/ca.rb
@@ -23,7 +23,7 @@ class TestClientCA < Test::Unit::TestCase
end
[:hostprivkey, :hostcert, :localcacert].each do |name|
- assert(FileTest.exists?(Puppet.config[name]),
+ assert(FileTest.exists?(Puppet.settings[name]),
"Did not create cert %s" % name)
end
end
diff --git a/test/network/client/client.rb b/test/network/client/client.rb
index 93c63d637..382cd55cf 100755
--- a/test/network/client/client.rb
+++ b/test/network/client/client.rb
@@ -113,9 +113,9 @@ class TestClient < Test::Unit::TestCase
# Create a new ssl root.
confdir = tempfile()
Puppet[:ssldir] = confdir
- Puppet.config.mkdir(:ssldir)
- Puppet.config.clearused
- Puppet.config.use(:ssl, :ca)
+ Puppet.settings.mkdir(:ssldir)
+ Puppet.settings.clearused
+ Puppet.settings.use(:ssl, :ca)
mkserver
diff --git a/test/network/client/master.rb b/test/network/client/master.rb
index a29254d16..169a1de5f 100755
--- a/test/network/client/master.rb
+++ b/test/network/client/master.rb
@@ -88,51 +88,6 @@ class TestMasterClient < Test::Unit::TestCase
return master, objects
end
- def test_apply
- master, objects = mk_fake_client
-
- check = Proc.new do |hash|
- assert(objects.trans, "transaction was not created")
- trans = objects.trans
- hash[:yes].each do |m|
- assert_equal(1, trans.send(m.to_s + "?"), "did not call #{m} enough times")
- end
- hash[:no].each do |m|
- assert_equal(0, trans.send(m.to_s + "?"), "called #{m} too many times")
- end
- end
-
- # First try it with no arguments
- assert_nothing_raised do
- master.apply
- end
- check.call :yes => %w{evaluate cleanup addtimes}, :no => %w{report tags ignoreschedules}
- assert_equal(0, master.reported, "master sent report with reports disabled")
-
-
- # Now enable reporting and make sure the report method gets called
- Puppet[:report] = true
- assert_nothing_raised do
- master.apply
- end
- check.call :yes => %w{evaluate cleanup addtimes}, :no => %w{tags ignoreschedules}
- assert_equal(1, master.reported, "master did not send report")
-
- # Now try it with tags enabled
- assert_nothing_raised do
- master.apply("tags")
- end
- check.call :yes => %w{evaluate cleanup tags addtimes}, :no => %w{ignoreschedules}
- assert_equal(2, master.reported, "master did not send report")
-
- # and ignoreschedules
- assert_nothing_raised do
- master.apply("tags", true)
- end
- check.call :yes => %w{evaluate cleanup tags ignoreschedules addtimes}, :no => %w{}
- assert_equal(3, master.reported, "master did not send report")
- end
-
def test_getconfig
client = mkclient
@@ -167,9 +122,8 @@ class TestMasterClient < Test::Unit::TestCase
[:getplugins, :get_actual_config].each do |method|
assert($methodsrun.include?(method), "method %s was not run" % method)
end
-
- objects = client.objects
- assert(objects.finalized?, "objects were not finalized")
+
+ assert_instance_of(Puppet::Node::Configuration, client.configuration, "Configuration was not created")
end
def test_disable
@@ -233,7 +187,7 @@ class TestMasterClient < Test::Unit::TestCase
}
end
- # This method is supposed
+ # This method downloads files, and yields each file object if a block is given.
def test_download
source = tempfile()
dest = tempfile()
@@ -726,7 +680,7 @@ end
client.apply
# Make sure the config is not cached.
- config = Puppet.config[:localconfig] + ".yaml"
+ config = Puppet.settings[:localconfig] + ".yaml"
assert(! File.exists?(config), "Cached an invalid configuration")
end
end
diff --git a/test/network/handler/configuration.rb b/test/network/handler/configuration.rb
index 072fdc053..29a393769 100755
--- a/test/network/handler/configuration.rb
+++ b/test/network/handler/configuration.rb
@@ -20,19 +20,6 @@ class TestHandlerConfiguration < Test::Unit::TestCase
assert(config.local?, "Config is not considered local after being started that way")
end
- # Make sure we create the node handler when necessary.
- def test_node_handler
- config = Config.new
- handler = nil
- assert_nothing_raised("Could not create node handler") do
- handler = config.send(:node_handler)
- end
- assert_instance_of(Puppet::Network::Handler.handler(:node), handler, "Did not create node handler")
-
- # Now make sure we get the same object back again
- assert_equal(handler.object_id, config.send(:node_handler).object_id, "Did not cache node handler")
- end
-
# Test creation/returning of the interpreter
def test_interpreter
config = Config.new
@@ -76,14 +63,14 @@ class TestHandlerConfiguration < Test::Unit::TestCase
fakenode = Object.new
# Set the server facts to something
config.instance_variable_set("@server_facts", :facts)
- fakenode.expects(:fact_merge).with(:facts)
+ fakenode.expects(:merge).with(:facts)
config.send(:add_node_data, fakenode)
# Now try it with classes.
config.instance_variable_set("@options", {:Classes => %w{a b}})
list = []
fakenode = Object.new
- fakenode.expects(:fact_merge).with(:facts)
+ fakenode.expects(:merge).with(:facts)
fakenode.expects(:classes).returns(list).times(2)
config.send(:add_node_data, fakenode)
assert_equal(%w{a b}, list, "Did not add classes to node")
@@ -170,19 +157,14 @@ class TestHandlerConfiguration < Test::Unit::TestCase
def test_version
# First try the case where we can't look up the node
config = Config.new
- handler = Object.new
- handler.expects(:details).with(:client).returns(false)
- config.expects(:node_handler).returns(handler)
+ node = Object.new
+ Puppet::Node.stubs(:search).with(:client).returns(false, node)
interp = Object.new
assert_instance_of(Bignum, config.version(:client), "Did not return configuration version")
# And then when we find the node.
config = Config.new
- node = Object.new
- handler = Object.new
- handler.expects(:details).with(:client).returns(node)
config.expects(:update_node_check).with(node)
- config.expects(:node_handler).returns(handler)
interp = Object.new
interp.expects(:configuration_version).returns(:version)
config.expects(:interpreter).returns(interp)
diff --git a/test/network/handler/facts.rb b/test/network/handler/facts.rb
deleted file mode 100755
index 03327b8c4..000000000
--- a/test/network/handler/facts.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/bin/env ruby
-
-$:.unshift("../../lib") if __FILE__ =~ /\.rb$/
-
-require 'puppettest'
-require 'mocha'
-require 'puppet/network/handler/facts'
-
-class TestFactsHandler < Test::Unit::TestCase
- include PuppetTest::ServerTest
-
- def setup
- super
-
- @class = Puppet::Network::Handler.handler(:facts)
-
- @@client_facts = {}
-
- unless Puppet::Util::FactStore.store(:testing)
- Puppet::Util::FactStore.newstore(:testing) do
- def get(node)
- @@client_facts[node]
- end
-
- def set(node, facts)
- @@client_facts[node] = facts
- end
- end
- end
-
- Puppet[:factstore] = :testing
-
- @handler = @class.new
-
- @facts = {:a => :b, :c => :d}
- @name = "foo"
-
- @backend = @handler.instance_variable_get("@backend")
- end
-
- def teardown
- @@client_facts.clear
- end
-
- def test_strip_internal
- @facts[:_puppet_one] = "yay"
- @facts[:_puppet_two] = "boo"
- @facts[:_puppetthree] = "foo"
-
- newfacts = nil
- assert_nothing_raised("Could not call strip_internal") do
- newfacts = @handler.send(:strip_internal, @facts)
- end
-
- [:_puppet_one, :_puppet_two, :_puppetthree].each do |name|
- assert(@facts.include?(name), "%s was removed in strip_internal from original hash" % name)
- end
- [:_puppet_one, :_puppet_two].each do |name|
- assert(! newfacts.include?(name), "%s was not removed in strip_internal" % name)
- end
- assert_equal("foo", newfacts[:_puppetthree], "_puppetthree was removed in strip_internal")
- end
-
- def test_add_internal
- newfacts = nil
- assert_nothing_raised("Could not call strip_internal") do
- newfacts = @handler.send(:add_internal, @facts)
- end
-
- assert_instance_of(Time, newfacts[:_puppet_timestamp], "Did not set timestamp in add_internal")
- assert(! @facts.include?(:_puppet_timestamp), "Modified original hash in add_internal")
- end
-
- def test_set
- newfacts = @facts.dup
- newfacts[:_puppet_timestamp] = Time.now
- @handler.expects(:add_internal).with(@facts).returns(newfacts)
- @backend.expects(:set).with(@name, newfacts).returns(nil)
-
- assert_nothing_raised("Could not set facts") do
- assert_nil(@handler.set(@name, @facts), "handler.set did not return nil")
- end
- end
-
- def test_get
- prefacts = @facts.dup
- prefacts[:_puppet_timestamp] = Time.now
- @@client_facts[@name] = prefacts
- @handler.expects(:strip_internal).with(prefacts).returns(@facts)
- @backend.expects(:get).with(@name).returns(prefacts)
-
- assert_nothing_raised("Could not retrieve facts") do
- assert_equal(@facts, @handler.get(@name), "did not get correct answer from handler.get")
- end
-
- @handler = @class.new
- assert_nothing_raised("Failed to call 'get' with no stored facts") do
- @handler.get("nosuchname")
- end
- end
-
- def test_store_date
- time = Time.now
- @facts[:_puppet_timestamp] = time
-
- @handler.expects(:get).with(@name).returns(@facts)
-
- assert_equal(time.to_i, @handler.store_date(@name), "Did not retrieve timestamp correctly")
- end
-end
-
-# $Id$
diff --git a/test/network/handler/master.rb b/test/network/handler/master.rb
index a976726ef..4f8e7fab2 100755
--- a/test/network/handler/master.rb
+++ b/test/network/handler/master.rb
@@ -8,6 +8,11 @@ require 'puppet/network/handler/master'
class TestMaster < Test::Unit::TestCase
include PuppetTest::ServerTest
+ def teardown
+ super
+ Puppet::Indirector::Indirection.clear_cache
+ end
+
def test_defaultmanifest
textfiles { |file|
Puppet[:manifest] = file
@@ -70,10 +75,11 @@ class TestMaster < Test::Unit::TestCase
assert(! client.fresh?(facts),
"Client is incorrectly up to date")
- Puppet.config.use(:main)
+ Puppet.settings.use(:main)
+ config = nil
assert_nothing_raised {
- client.getconfig
- client.apply
+ config = client.getconfig
+ config.apply
}
# Now it should be up to date
@@ -108,8 +114,8 @@ class TestMaster < Test::Unit::TestCase
# Retrieve and apply the new config
assert_nothing_raised {
- client.getconfig
- client.apply
+ config = client.getconfig
+ config.apply
}
assert(client.fresh?(facts), "Client is not up to date")
diff --git a/test/network/handler/node.rb b/test/network/handler/node.rb
deleted file mode 100755
index 6b8ab9290..000000000
--- a/test/network/handler/node.rb
+++ /dev/null
@@ -1,640 +0,0 @@
-#!/usr/bin/env ruby
-
-$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
-
-require 'mocha'
-require 'puppettest'
-require 'puppettest/resourcetesting'
-require 'puppettest/parsertesting'
-require 'puppettest/servertest'
-require 'puppet/network/handler/node'
-
-module NodeTesting
- include PuppetTest
- Node = Puppet::Network::Handler::Node
- SimpleNode = Puppet::Node
-
- def mk_node_mapper
- # First, make sure our nodesearch command works as we expect
- # Make a nodemapper
- mapper = tempfile()
- ruby = %x{which ruby}.chomp
- File.open(mapper, "w") { |f|
- f.puts "#!#{ruby}
- require 'yaml'
- name = ARGV.last.chomp
- result = {}
-
- if name =~ /a/
- result[:parameters] = {'one' => ARGV.last + '1', 'two' => ARGV.last + '2'}
- end
-
- if name =~ /p/
- result['classes'] = [1,2,3].collect { |n| ARGV.last + n.to_s }
- end
-
- puts YAML.dump(result)
- "
- }
- File.chmod(0755, mapper)
- mapper
- end
-
- def mk_searcher(name)
- searcher = Object.new
- searcher.extend(Node.node_source(name))
- searcher.meta_def(:newnode) do |name, *args|
- SimpleNode.new(name, *args)
- end
- searcher
- end
-
- def mk_node_source
- @node_info = {}
- @node_source = Node.newnode_source(:testing, :fact_merge => true) do
- def nodesearch(key)
- if info = @node_info[key]
- SimpleNode.new(info)
- else
- nil
- end
- end
- end
- Puppet[:node_source] = "testing"
-
- cleanup { Node.rm_node_source(:testing) }
- end
-end
-
-class TestNodeHandler < Test::Unit::TestCase
- include NodeTesting
-
- def setup
- super
- mk_node_source
- end
-
- # Make sure that the handler includes the appropriate
- # node source.
- def test_initialize
- # First try it when passing in the node source
- handler = nil
- assert_nothing_raised("Could not specify a node source") do
- handler = Node.new(:Source => :testing)
- end
- assert(handler.metaclass.included_modules.include?(@node_source), "Handler did not include node source")
-
- # Now use the Puppet[:node_source]
- Puppet[:node_source] = "testing"
- assert_nothing_raised("Could not specify a node source") do
- handler = Node.new()
- end
- assert(handler.metaclass.included_modules.include?(@node_source), "Handler did not include node source")
-
- # And make sure we throw an exception when an invalid node source is used
- assert_raise(ArgumentError, "Accepted an invalid node source") do
- handler = Node.new(:Source => "invalid")
- end
- end
-
- # Make sure we can find and we cache a fact handler.
- def test_fact_handler
- handler = Node.new
- fhandler = nil
- assert_nothing_raised("Could not retrieve the fact handler") do
- fhandler = handler.send(:fact_handler)
- end
- assert_instance_of(Puppet::Network::Handler::Facts, fhandler, "Did not get a fact handler back")
-
- # Now call it again, making sure we're caching the value.
- fhandler2 = nil
- assert_nothing_raised("Could not retrieve the fact handler") do
- fhandler2 = handler.send(:fact_handler)
- end
- assert_instance_of(Puppet::Network::Handler::Facts, fhandler2, "Did not get a fact handler on the second run")
- assert_equal(fhandler.object_id, fhandler2.object_id, "Did not cache fact handler")
- end
-
- # Make sure we can get node facts from the fact handler.
- def test_node_facts
- # Check the case where we find the node.
- handler = Node.new
- fhandler = handler.send(:fact_handler)
- fhandler.expects(:get).with("present").returns("a" => "b")
-
- result = nil
- assert_nothing_raised("Could not get facts from fact handler") do
- result = handler.send(:node_facts, "present")
- end
- assert_equal({"a" => "b"}, result, "Did not get correct facts back")
-
- # Now try the case where the fact handler knows nothing about our host
- fhandler.expects(:get).with('missing').returns(nil)
- result = nil
- assert_nothing_raised("Could not get facts from fact handler when host is missing") do
- result = handler.send(:node_facts, "missing")
- end
- assert_equal({}, result, "Did not get empty hash when no facts are known")
- end
-
- # Test our simple shorthand
- def test_newnode
- SimpleNode.expects(:new).with("stuff")
- handler = Node.new
- handler.send(:newnode, "stuff")
- end
-
- # Make sure we can build up the correct node names to search for
- def test_node_names
- handler = Node.new
-
- # Verify that the handler asks for the facts if we don't pass them in
- handler.expects(:node_facts).with("testing").returns({})
- handler.send(:node_names, "testing")
-
- handler = Node.new
- # Test it first with no parameters
- assert_equal(%w{testing}, handler.send(:node_names, "testing"), "Node names did not default to an array including just the node name")
-
- # Now test it with a fully qualified name
- assert_equal(%w{testing.domain.com testing}, handler.send(:node_names, "testing.domain.com"),
- "Fully qualified names did not get turned into multiple names, longest first")
-
- # And try it with a short name + domain fact
- assert_equal(%w{testing host.domain.com host}, handler.send(:node_names, "testing", "domain" => "domain.com", "hostname" => "host"),
- "The domain fact was not used to build up an fqdn")
-
- # And with an fqdn
- assert_equal(%w{testing host.domain.com host}, handler.send(:node_names, "testing", "fqdn" => "host.domain.com"),
- "The fqdn was not used")
-
- # And make sure the fqdn beats the domain
- assert_equal(%w{testing host.other.com host}, handler.send(:node_names, "testing", "domain" => "domain.com", "fqdn" => "host.other.com"),
- "The domain was used in preference to the fqdn")
- end
-
- # Make sure we can retrieve a whole node by name.
- def test_details_when_we_find_nodes
- handler = Node.new
-
- # Make sure we get the facts first
- handler.expects(:node_facts).with("host").returns(:facts)
-
- # Find the node names
- handler.expects(:node_names).with("host", :facts).returns(%w{a b c})
-
- # Iterate across them
- handler.expects(:nodesearch).with("a").returns(nil)
- handler.expects(:nodesearch).with("b").returns(nil)
-
- # Create an example node to return
- node = SimpleNode.new("host")
-
- # Make sure its source is set
- node.expects(:source=).with(handler.source)
-
- # And that the names are retained
- node.expects(:names=).with(%w{a b c})
-
- # And make sure we actually get it back
- handler.expects(:nodesearch).with("c").returns(node)
-
- handler.expects(:fact_merge?).returns(true)
-
- # Make sure we merge the facts with the node's parameters.
- node.expects(:fact_merge).with(:facts)
-
- # Now call the method
- result = nil
- assert_nothing_raised("could not call 'details'") do
- result = handler.details("host")
- end
- assert_equal(node, result, "Did not get correct node back")
- end
-
- # But make sure we pass through to creating default nodes when appropriate.
- def test_details_using_default_node
- handler = Node.new
-
- # Make sure we get the facts first
- handler.expects(:node_facts).with("host").returns(:facts)
-
- # Find the node names
- handler.expects(:node_names).with("host", :facts).returns([])
-
- # Create an example node to return
- node = SimpleNode.new("host")
-
- # Make sure its source is set
- node.expects(:source=).with(handler.source)
-
- # And make sure we actually get it back
- handler.expects(:nodesearch).with("default").returns(node)
-
- # This time, have it return false
- handler.expects(:fact_merge?).returns(false)
-
- # And because fact_merge was false, we don't merge them.
- node.expects(:fact_merge).never
-
- # Now call the method
- result = nil
- assert_nothing_raised("could not call 'details'") do
- result = handler.details("host")
- end
- assert_equal(node, result, "Did not get correct node back")
- end
-
- # Make sure our handler behaves rationally when it comes to getting environment data.
- def test_environment
- # What happens when we can't find the node
- handler = Node.new
- handler.expects(:details).with("fake").returns(nil)
-
- result = nil
- assert_nothing_raised("Could not call 'Node.environment'") do
- result = handler.environment("fake")
- end
- assert_nil(result, "Got an environment for a node we could not find")
-
- # Now for nodes we can find
- handler = Node.new
- node = SimpleNode.new("fake")
- handler.expects(:details).with("fake").returns(node)
- node.expects(:environment).returns("dev")
-
- result = nil
- assert_nothing_raised("Could not call 'Node.environment'") do
- result = handler.environment("fake")
- end
- assert_equal("dev", result, "Did not get environment back")
- end
-
- # Make sure our handler behaves rationally when it comes to getting parameter data.
- def test_parameters
- # What happens when we can't find the node
- handler = Node.new
- handler.expects(:details).with("fake").returns(nil)
-
- result = nil
- assert_nothing_raised("Could not call 'Node.parameters'") do
- result = handler.parameters("fake")
- end
- assert_nil(result, "Got parameters for a node we could not find")
-
- # Now for nodes we can find
- handler = Node.new
- node = SimpleNode.new("fake")
- handler.expects(:details).with("fake").returns(node)
- node.expects(:parameters).returns({"a" => "b"})
-
- result = nil
- assert_nothing_raised("Could not call 'Node.parameters'") do
- result = handler.parameters("fake")
- end
- assert_equal({"a" => "b"}, result, "Did not get parameters back")
- end
-
- def test_classes
- # What happens when we can't find the node
- handler = Node.new
- handler.expects(:details).with("fake").returns(nil)
-
- result = nil
- assert_nothing_raised("Could not call 'Node.classes'") do
- result = handler.classes("fake")
- end
- assert_nil(result, "Got classes for a node we could not find")
-
- # Now for nodes we can find
- handler = Node.new
- node = SimpleNode.new("fake")
- handler.expects(:details).with("fake").returns(node)
- node.expects(:classes).returns(%w{yay foo})
-
- result = nil
- assert_nothing_raised("Could not call 'Node.classes'") do
- result = handler.classes("fake")
- end
- assert_equal(%w{yay foo}, result, "Did not get classes back")
- end
-
- # We reuse the filetimeout for the node caching timeout.
- def test_node_caching
- handler = Node.new
-
- node = Object.new
- node.metaclass.instance_eval do
- attr_accessor :time, :name
- end
- node.time = Time.now
- node.name = "yay"
-
- # Make sure caching works normally
- assert_nothing_raised("Could not cache node") do
- handler.send(:cache, node)
- end
- assert_equal(node.object_id, handler.send(:cached?, "yay").object_id, "Did not get node back from the cache")
-
- # And that it's returned if we ask for it, instead of creating a new node.
- assert_equal(node.object_id, handler.details("yay").object_id, "Did not use cached node")
-
- # Now set the node's time to be a long time ago
- node.time = Time.now - 50000
- assert(! handler.send(:cached?, "yay"), "Timed-out node was returned from cache")
- end
-end
-
-# Test our configuration object.
-class TestNodeSources < Test::Unit::TestCase
- include NodeTesting
-
- def test_node_sources
- mod = nil
- assert_nothing_raised("Could not add new search type") do
- mod = Node.newnode_source(:testing) do
- def nodesearch(name)
- end
- end
- end
- assert_equal(mod, Node.node_source(:testing), "Did not get node_source back")
-
- cleanup do
- Node.rm_node_source(:testing)
- assert(! Node.const_defined?("Testing"), "Did not remove constant")
- end
- end
-
- def test_external_node_source
- source = Node.node_source(:external)
- assert(source, "Could not find external node source")
- mapper = mk_node_mapper
- searcher = mk_searcher(:external)
- assert(searcher.fact_merge?, "External node source does not merge facts")
-
- # Make sure it gives the right response
- assert_equal({'classes' => %w{apple1 apple2 apple3}, :parameters => {"one" => "apple1", "two" => "apple2"}},
- YAML.load(%x{#{mapper} apple}))
-
- # First make sure we get nil back by default
- assert_nothing_raised {
- assert_nil(searcher.nodesearch("apple"),
- "Interp#nodesearch_external defaulted to a non-nil response")
- }
- assert_nothing_raised { Puppet[:external_nodes] = mapper }
-
- node = nil
- # Both 'a' and 'p', so we get classes and parameters
- assert_nothing_raised { node = searcher.nodesearch("apple") }
- assert_equal("apple", node.name, "node name was not set correctly for apple")
- assert_equal(%w{apple1 apple2 apple3}, node.classes, "node classes were not set correctly for apple")
- assert_equal( {"one" => "apple1", "two" => "apple2"}, node.parameters, "node parameters were not set correctly for apple")
-
- # A 'p' but no 'a', so we only get classes
- assert_nothing_raised { node = searcher.nodesearch("plum") }
- assert_equal("plum", node.name, "node name was not set correctly for plum")
- assert_equal(%w{plum1 plum2 plum3}, node.classes, "node classes were not set correctly for plum")
- assert_equal({}, node.parameters, "node parameters were not set correctly for plum")
-
- # An 'a' but no 'p', so we only get parameters.
- assert_nothing_raised { node = searcher.nodesearch("guava")} # no p's, thus no classes
- assert_equal("guava", node.name, "node name was not set correctly for guava")
- assert_equal([], node.classes, "node classes were not set correctly for guava")
- assert_equal({"one" => "guava1", "two" => "guava2"}, node.parameters, "node parameters were not set correctly for guava")
-
- assert_nothing_raised { node = searcher.nodesearch("honeydew")} # neither, thus nil
- assert_nil(node)
- end
-
- # Make sure a nodesearch with arguments works
- def test_nodesearch_external_arguments
- mapper = mk_node_mapper
- Puppet[:external_nodes] = "#{mapper} -s something -p somethingelse"
- searcher = mk_searcher(:external)
- node = nil
- assert_nothing_raised do
- node = searcher.nodesearch("apple")
- end
- assert_instance_of(SimpleNode, node, "did not create node")
- end
-
- # A wrapper test, to make sure we're correctly calling the external search method.
- def test_nodesearch_external_functional
- mapper = mk_node_mapper
- searcher = mk_searcher(:external)
-
- Puppet[:external_nodes] = mapper
-
- node = nil
- assert_nothing_raised do
- node = searcher.nodesearch("apple")
- end
- assert_instance_of(SimpleNode, node, "did not create node")
- end
-
- # This can stay in the main test suite because it doesn't actually use ldapsearch,
- # it just overrides the method so it behaves as though it were hitting ldap.
- def test_ldap_nodesearch
- source = Node.node_source(:ldap)
- assert(source, "Could not find ldap node source")
- searcher = mk_searcher(:ldap)
- assert(searcher.fact_merge?, "LDAP node source does not merge facts")
-
- nodetable = {}
-
- # Override the ldapsearch definition, so we don't have to actually set it up.
- searcher.meta_def(:ldapsearch) do |name|
- nodetable[name]
- end
-
- # Make sure we get nothing for nonexistent hosts
- node = nil
- assert_nothing_raised do
- node = searcher.nodesearch("nosuchhost")
- end
-
- assert_nil(node, "Got a node for a non-existent host")
-
- # Now add a base node with some classes and parameters
- nodetable["base"] = [nil, %w{one two}, {"base" => "true"}]
-
- assert_nothing_raised do
- node = searcher.nodesearch("base")
- end
-
- assert_instance_of(SimpleNode, node, "Did not get node from ldap nodesearch")
- assert_equal("base", node.name, "node name was not set")
-
- assert_equal(%w{one two}, node.classes, "node classes were not set")
- assert_equal({"base" => "true"}, node.parameters, "node parameters were not set")
-
- # Now use a different with this as the base
- nodetable["middle"] = ["base", %w{three}, {"center" => "boo"}]
- assert_nothing_raised do
- node = searcher.nodesearch("middle")
- end
-
- assert_instance_of(SimpleNode, node, "Did not get node from ldap nodesearch")
- assert_equal("middle", node.name, "node name was not set")
-
- assert_equal(%w{one two three}.sort, node.classes.sort, "node classes were not set correctly with a parent node")
- assert_equal({"base" => "true", "center" => "boo"}, node.parameters, "node parameters were not set correctly with a parent node")
-
- # And one further, to make sure we fully recurse
- nodetable["top"] = ["middle", %w{four five}, {"master" => "far"}]
- assert_nothing_raised do
- node = searcher.nodesearch("top")
- end
-
- assert_instance_of(SimpleNode, node, "Did not get node from ldap nodesearch")
- assert_equal("top", node.name, "node name was not set")
-
- assert_equal(%w{one two three four five}.sort, node.classes.sort, "node classes were not set correctly with the top node")
- assert_equal({"base" => "true", "center" => "boo", "master" => "far"}, node.parameters, "node parameters were not set correctly with the top node")
- end
-
- # Make sure we always get a node back from the 'none' nodesource.
- def test_nodesource_none
- source = Node.node_source(:none)
- assert(source, "Could not find 'none' node source")
- searcher = mk_searcher(:none)
- assert(searcher.fact_merge?, "'none' node source does not merge facts")
-
- # Run a couple of node names through it
- node = nil
- %w{192.168.0.1 0:0:0:3:a:f host host.domain.com}.each do |name|
- assert_nothing_raised("Could not create an empty node with name '%s'" % name) do
- node = searcher.nodesearch(name)
- end
- assert_instance_of(SimpleNode, node, "Did not get a simple node back for %s" % name)
- assert_equal(name, node.name, "Name was not set correctly")
- end
- end
-end
-
-class LdapNodeTest < PuppetTest::TestCase
- include NodeTesting
- include PuppetTest::ServerTest
- include PuppetTest::ParserTesting
- include PuppetTest::ResourceTesting
- AST = Puppet::Parser::AST
- confine "LDAP is not available" => Puppet.features.ldap?
- confine "No LDAP test data for networks other than Luke's" => Facter.value(:domain) == "madstop.com"
-
- def ldapconnect
-
- @ldap = LDAP::Conn.new("ldap", 389)
- @ldap.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 )
- @ldap.simple_bind("", "")
-
- return @ldap
- end
-
- def ldaphost(name)
- node = Puppet::Node.new(name)
- parent = nil
- found = false
- @ldap.search( "ou=hosts, dc=madstop, dc=com", 2,
- "(&(objectclass=puppetclient)(cn=%s))" % name
- ) do |entry|
- node.classes = entry.vals("puppetclass") || []
- node.parameters = entry.to_hash.inject({}) do |hash, ary|
- if ary[1].length == 1
- hash[ary[0]] = ary[1].shift
- else
- hash[ary[0]] = ary[1]
- end
- hash
- end
- parent = node.parameters["parentnode"]
- found = true
- end
- raise "Could not find node %s" % name unless found
-
- return node, parent
- end
-
- def test_ldapsearch
- Puppet[:ldapbase] = "ou=hosts, dc=madstop, dc=com"
- Puppet[:ldapnodes] = true
-
- searcher = Object.new
- searcher.extend(Node.node_source(:ldap))
-
- ldapconnect()
-
- # Make sure we get nil and nil back when we search for something missing
- parent, classes, parameters = nil
- assert_nothing_raised do
- parent, classes, parameters = searcher.ldapsearch("nosuchhost")
- end
-
- assert_nil(parent, "Got a parent for a non-existent host")
- assert_nil(classes, "Got classes for a non-existent host")
-
- # Make sure we can find 'culain' in ldap
- assert_nothing_raised do
- parent, classes, parameters = searcher.ldapsearch("culain")
- end
-
- node, realparent = ldaphost("culain")
- assert_equal(realparent, parent, "did not get correct parent node from ldap")
- assert_equal(node.classes, classes, "did not get correct ldap classes from ldap")
- assert_equal(node.parameters, parameters, "did not get correct ldap parameters from ldap")
-
- # Now compare when we specify the attributes to get.
- Puppet[:ldapattrs] = "cn"
- assert_nothing_raised do
- parent, classes, parameters = searcher.ldapsearch("culain")
- end
- assert_equal(realparent, parent, "did not get correct parent node from ldap")
- assert_equal(node.classes, classes, "did not get correct ldap classes from ldap")
-
- list = %w{cn puppetclass parentnode dn}
- should = node.parameters.inject({}) { |h, a| h[a[0]] = a[1] if list.include?(a[0]); h }
- assert_equal(should, parameters, "did not get correct ldap parameters from ldap")
- end
-end
-
-class LdapReconnectTests < PuppetTest::TestCase
- include NodeTesting
- include PuppetTest::ServerTest
- include PuppetTest::ParserTesting
- include PuppetTest::ResourceTesting
- AST = Puppet::Parser::AST
- confine "Not running on culain as root" => (Puppet::Util::SUIDManager.uid == 0 and Facter.value("hostname") == "culain")
-
- def test_ldapreconnect
- Puppet[:ldapbase] = "ou=hosts, dc=madstop, dc=com"
- Puppet[:ldapnodes] = true
-
- searcher = Object.new
- searcher.extend(Node.node_source(:ldap))
- hostname = "culain.madstop.com"
-
- # look for our host
- assert_nothing_raised {
- parent, classes = searcher.nodesearch(hostname)
- }
-
- # Now restart ldap
- system("/etc/init.d/slapd restart 2>/dev/null >/dev/null")
- sleep(1)
-
- # and look again
- assert_nothing_raised {
- parent, classes = searcher.nodesearch(hostname)
- }
-
- # Now stop ldap
- system("/etc/init.d/slapd stop 2>/dev/null >/dev/null")
- cleanup do
- system("/etc/init.d/slapd start 2>/dev/null >/dev/null")
- end
-
- # And make sure we actually fail here
- assert_raise(Puppet::Error) {
- parent, classes = searcher.nodesearch(hostname)
- }
- end
-end
diff --git a/test/other/dsl.rb b/test/other/dsl.rb
index f1fd1a1e9..59610cd0f 100755
--- a/test/other/dsl.rb
+++ b/test/other/dsl.rb
@@ -214,5 +214,3 @@ class TestDSL < Test::Unit::TestCase
assert_instance_of(Puppet::Parser::Resource, file)
end
end
-
-# $Id$
diff --git a/test/other/events.rb b/test/other/events.rb
index 802a701a3..b67ea05a1 100755
--- a/test/other/events.rb
+++ b/test/other/events.rb
@@ -23,7 +23,7 @@ class TestEvents < Test::Unit::TestCase
:subscribe => [[file.class.name, file.name]]
)
- comp = newcomp("eventtesting", file, exec)
+ comp = mk_configuration("eventtesting", file, exec)
trans = assert_events([:file_created, :triggered], comp)
@@ -44,56 +44,16 @@ class TestEvents < Test::Unit::TestCase
)
- comp = Puppet.type(:component).create(
- :name => "eventtesting"
- )
- comp.push exec
- trans = comp.evaluate
- events = nil
- assert_nothing_raised {
- events = trans.evaluate
- }
+ config = mk_configuration
+ config.add_resource file
+ config.add_resource exec
+ trans = config.apply
- assert_equal(1, events.length)
+ assert_equal(1, trans.events.length)
assert_equal(0, trans.triggered?(exec, :refresh))
end
- # Verify that one component can subscribe to another component and the "right"
- # thing happens
- def test_ladderrequire
- comps = {}
- objects = {}
- fname = tempfile()
- file = Puppet.type(:file).create(
- :name => tempfile(),
- :ensure => "file"
- )
-
- exec = Puppet.type(:exec).create(
- :name => "touch %s" % fname,
- :path => "/usr/bin:/bin",
- :refreshonly => true
- )
-
- fcomp = newcomp(file)
- ecomp = newcomp(exec)
- comp = newcomp("laddercomp", fcomp, ecomp)
-
- ecomp[:subscribe] = [[fcomp.class.name, fcomp.name]]
-
- comp.finalize
-
- trans = comp.evaluate
- events = nil
- assert_nothing_raised {
- events = trans.evaluate
- }
-
- assert(FileTest.exists?(fname), "#{fname} does not exist")
- #assert_equal(events.length, trans.triggered?(objects[:b], :refresh))
- end
-
def test_multiplerefreshes
files = []
@@ -115,7 +75,7 @@ class TestEvents < Test::Unit::TestCase
["file", f.name]
}
- comp = newcomp(exec, *files)
+ comp = mk_configuration(exec, *files)
assert_apply(comp)
assert(FileTest.exists?(fname), "Exec file did not get created")
@@ -147,17 +107,16 @@ class TestEvents < Test::Unit::TestCase
)
execs = [exec1, exec2, exec3]
- comp = newcomp(exec1,exec2,exec3)
+ config = mk_configuration(exec1,exec2,exec3)
- trans = comp.evaluate
- execs.each do |e| assert(trans.resources.vertex?(e), "%s is not in graph" % e.title) end
+ trans = Puppet::Transaction.new(config)
+ execs.each do |e| assert(config.vertex?(e), "%s is not in graph" % e.title) end
trans.prepare
- execs.each do |e| assert(trans.relgraph.vertex?(e), "%s is not in relgraph" % e.title) end
- reverse = trans.relgraph.reversal
+ execs.each do |e| assert(config.vertex?(e), "%s is not in relgraph" % e.title) end
+ reverse = trans.relationship_graph.reversal
execs.each do |e| assert(reverse.vertex?(e), "%s is not in reversed graph" % e.title) end
-
- assert_apply(comp)
+ config.apply
assert(FileTest.exists?(file), "File does not exist")
diff --git a/test/other/overrides.rb b/test/other/overrides.rb
index 2bc443980..9a7c4b8ba 100755
--- a/test/other/overrides.rb
+++ b/test/other/overrides.rb
@@ -90,12 +90,10 @@ class TestOverrides < Test::Unit::TestCase
}
}
- comp = newcomp("overrides", baseobj)
- children.each { |child| comp.push child }
+ config = mk_configuration(baseobj, *children)
assert_nothing_raised("Could not eval component") {
- trans = comp.evaluate
- trans.evaluate
+ config.apply
}
files.each { |path, mode|
diff --git a/test/other/pgraph.rb b/test/other/pgraph.rb
deleted file mode 100755
index 34ba0e18c..000000000
--- a/test/other/pgraph.rb
+++ /dev/null
@@ -1,290 +0,0 @@
-#!/usr/bin/env ruby
-#
-# Created by Luke Kanies on 2006-11-16.
-# Copyright (c) 2006. All rights reserved.
-
-$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
-
-require 'puppettest'
-require 'puppettest/graph'
-
-class TestPGraph < Test::Unit::TestCase
- include PuppetTest
- include PuppetTest::Graph
-
- Edge = Puppet::Relationship
-
- def test_clear
- graph = Puppet::PGraph.new
- graph.add_edge!("a", "b")
- graph.add_vertex! "c"
- assert_nothing_raised do
- graph.clear
- end
- assert(graph.vertices.empty?, "Still have vertices after clear")
- assert(graph.edges.empty?, "still have edges after clear")
- end
-
-
- def test_matching_edges
- graph = Puppet::PGraph.new
-
- event = Puppet::Event.new(:source => "a", :event => :yay)
- none = Puppet::Event.new(:source => "a", :event => :NONE)
-
- edges = {}
-
- edges["a/b"] = Edge["a", "b", {:event => :yay, :callback => :refresh}]
- edges["a/c"] = Edge["a", "c", {:event => :yay, :callback => :refresh}]
-
- graph.add_edge!(edges["a/b"])
-
- # Try it for the trivial case of one target and a matching event
- assert_equal([edges["a/b"]], graph.matching_edges([event]))
-
- # Make sure we get nothing with a different event
- assert_equal([], graph.matching_edges([none]))
-
- # Set up multiple targets and make sure we get them all back
- graph.add_edge!(edges["a/c"])
- assert_equal([edges["a/b"], edges["a/c"]].sort, graph.matching_edges([event]).sort)
- assert_equal([], graph.matching_edges([none]))
- end
-
- def test_dependencies
- graph = Puppet::PGraph.new
-
- graph.add_edge!("a", "b")
- graph.add_edge!("a", "c")
- graph.add_edge!("b", "d")
-
- assert_equal(%w{b c d}.sort, graph.dependents("a").sort)
- assert_equal(%w{d}.sort, graph.dependents("b").sort)
- assert_equal([].sort, graph.dependents("c").sort)
-
- assert_equal(%w{a b}, graph.dependencies("d").sort)
- assert_equal(%w{a}, graph.dependencies("b").sort)
- assert_equal(%w{a}, graph.dependencies("c").sort)
- assert_equal([], graph.dependencies("a").sort)
-
- end
-
- # Test that we can take a containment graph and rearrange it by dependencies
- def test_splice
- one, two, three, middle, top = build_tree
- empty = Container.new("empty", [])
- # Also, add an empty container to top
- top.push empty
-
- contgraph = top.to_graph
-
- # Now add a couple of child files, so that we can test whether all
- # containers get spliced, rather than just components.
-
- # Now make a dependency graph
- deps = Puppet::PGraph.new
-
- contgraph.vertices.each do |v|
- deps.add_vertex(v)
- end
-
- # We have to specify a relationship to our empty container, else it
- # never makes it into the dep graph in the first place.
- {one => two, "f" => "c", "h" => middle, "c" => empty}.each do |source, target|
- deps.add_edge!(source, target, :callback => :refresh)
- end
-
- #contgraph.to_jpg(File.expand_path("~/Desktop/pics"), "main")
- #deps.to_jpg(File.expand_path("~/Desktop/pics"), "before")
- assert_nothing_raised { deps.splice!(contgraph, Container) }
-
- assert(! deps.cyclic?, "Created a cyclic graph")
-
- # Make sure there are no container objects remaining
- #deps.to_jpg(File.expand_path("~/Desktop/pics"), "after")
- c = deps.vertices.find_all { |v| v.is_a?(Container) }
- assert(c.empty?, "Still have containers %s" % c.inspect)
-
- # Now make sure the containers got spliced correctly.
- contgraph.leaves(middle).each do |leaf|
- assert(deps.edge?("h", leaf), "no edge for h => %s" % leaf)
- end
- one.each do |oobj|
- two.each do |tobj|
- assert(deps.edge?(oobj, tobj), "no %s => %s edge" % [oobj, tobj])
- end
- end
-
- nons = deps.vertices.find_all { |v| ! v.is_a?(String) }
- assert(nons.empty?,
- "still contain non-strings %s" % nons.inspect)
-
- deps.edges.each do |edge|
- assert_equal({:callback => :refresh}, edge.label,
- "Label was not copied for %s => %s" % [edge.source, edge.target])
- end
-
- # Now add some relationships to three, but only add labels to one of
- # the relationships.
-
- # Add a simple, label-less relationship
- deps.add_edge!(two, three)
- assert_nothing_raised { deps.splice!(contgraph, Container) }
-
- # And make sure it stuck, with no labels.
- assert_equal({}, deps.edge_label("c", "i"),
- "label was created for c => i")
-
- # Now add some edges with labels, in a way that should overwrite
- deps.add_edge!("c", three, {:callback => :refresh})
- assert_nothing_raised { deps.splice!(contgraph, Container) }
-
- # And make sure the label got copied.
- assert_equal({:callback => :refresh}, deps.edge_label("c", "i"),
- "label was not copied for c => i")
-
- # Lastly, add some new label-less edges and make sure the label stays.
- deps.add_edge!(middle, three)
- assert_nothing_raised { deps.splice!(contgraph, Container) }
- assert_equal({:callback => :refresh}, deps.edge_label("c", "i"),
- "label was lost for c => i")
-
- # Now make sure the 'three' edges all have the label we've used.
- # Note that this will not work when we support more than one type of
- # subscription.
- three.each do |child|
- edge = deps.edge_class.new("c", child)
- assert(deps.edge?(edge), "no c => %s edge" % child)
- assert_equal({:callback => :refresh}, deps[edge],
- "label was not retained for c => %s" % child)
- end
- end
-
- def test_copy_label
- graph = Puppet::PGraph.new
-
- # First make an edge with no label
- graph.add_edge!(:a, :b)
- assert_nil(graph.edge_label(:a, :b), "Created a label")
-
- # Now try to copy an empty label in.
- graph.copy_label(:a, :b, {})
-
- # It should just do nothing, since we copied an empty label.
- assert_nil(graph.edge_label(:a, :b), "Created a label")
-
- # Now copy in a real label.
- graph.copy_label(:a, :b, {:callback => :yay})
- assert_equal({:callback => :yay},
- graph.edge_label(:a, :b), "Did not copy label")
-
- # Now copy in a nil label
- graph.copy_label(:a, :b, nil)
- assert_equal({:callback => :yay},
- graph.edge_label(:a, :b), "lost label")
-
- # And an empty one.
- graph.copy_label(:a, :b, {})
- assert_equal({:callback => :yay},
- graph.edge_label(:a, :b), "lost label")
- end
-
- def test_fail_on_cycle
- {
- {:a => :b, :b => :a, :c => :a, :d => :c} => true, # larger tree involving a smaller cycle
- {:a => :b, :b => :c, :c => :a} => true,
- {:a => :b, :b => :a, :c => :d, :d => :c} => true,
- {:a => :b, :b => :c} => false,
- }.each do |hash, result|
- graph = Puppet::PGraph.new
- hash.each do |a,b|
- graph.add_edge!(a, b)
- end
-
- if result
- assert_raise(Puppet::Error, "%s did not fail" % hash.inspect) do
- graph.topsort
- end
- else
- assert_nothing_raised("%s failed" % hash.inspect) do
- graph.topsort
- end
- end
- end
- end
-
- # This isn't really a unit test, it's just a way to do some graphing with
- # tons of relationships so we can see how it performs.
- def disabled_test_lots_of_relationships
- containers = Puppet::PGraph.new
- relationships = Puppet::PGraph.new
- labels = %w{a b c d e}
- conts = {}
- vertices = {}
- labels.each do |label|
- vertices[label] = []
- end
- num = 100
- num.times do |i|
- labels.each do |label|
- vertices[label] << ("%s%s" % [label, i])
- end
- end
- labels.each do |label|
- conts[label] = Container.new(label, vertices[label])
- end
-
- conts.each do |label, cont|
- cont.each do |child|
- containers.add_edge!(cont, child)
- end
- end
- prev = nil
- labels.inject(nil) do |prev, label|
- if prev
- containers.add_edge!(conts[prev], conts[label])
- end
- label
- end
-
- containers.to_jpg(File.expand_path("~/Desktop/pics/lots"), "start")
-
- # Now create the relationship graph
-
- # Make everything in both b and c require d1
- %w{b c}.each do |label|
- conts[label].each do |v|
- relationships.add_edge!(v, "d1")
- #relationships.add_edge!(v, conts["d"])
- end
- end
-
- # Make most in b also require the appropriate thing in c
- conts["b"].each do |v|
- i = v.split('')[1]
-
- relationships.add_edge!(v, "c%s" % i)
- end
-
- # And make d1 require most of e
- num.times do |i|
- relationships.add_edge!("d1", "e%s" % i)
- end
-
- containers.vertices.each do |v|
- relationships.add_vertex!(v)
- end
- relationships.to_jpg(File.expand_path("~/Desktop/pics/lots"), "relationships")
-
- time = Benchmark.realtime do
- relationships.splice!(containers, Container)
- end
- relationships.to_jpg(File.expand_path("~/Desktop/pics/lots"), "final")
- puts time
- time = Benchmark.realtime do
- relationships.topsort
- end
- end
-end
-
-# $Id$
diff --git a/test/other/relationships.rb b/test/other/relationships.rb
index a5c9db5dc..771b119ee 100755
--- a/test/other/relationships.rb
+++ b/test/other/relationships.rb
@@ -172,15 +172,12 @@ class TestRelationships < Test::Unit::TestCase
end
assert_equal([Puppet::Relationship[file, exec]], reqs)
- # Now make sure that these relationships are added to the transaction's
- # relgraph
- trans = Puppet::Transaction.new(newcomp(file, exec))
- assert_nothing_raised do
- trans.evaluate
+ # Now make sure that these relationships are added to the
+ # relationship graph
+ config = mk_configuration(file, exec)
+ config.apply do |trans|
+ assert(config.relationship_graph.edge?(file, exec), "autorequire edge was not created")
end
-
- graph = trans.relgraph
- assert(graph.edge?(file, exec), "autorequire edge was not created")
end
def test_requires?
diff --git a/test/other/report.rb b/test/other/report.rb
index c59881f72..3de2dfbee 100755
--- a/test/other/report.rb
+++ b/test/other/report.rb
@@ -26,16 +26,10 @@ class TestReports < Test::Unit::TestCase
)
end
- comp = newcomp(*objects)
-
- trans = nil
- assert_nothing_raised("Failed to create transaction") {
- trans = comp.evaluate
- }
-
- assert_nothing_raised("Failed to evaluate transaction") {
- trans.evaluate
- }
+ config = mk_configuration(*objects)
+ # So the report works out.
+ config.retrieval_duration = 0.001
+ trans = config.apply
return trans.generate_report
end
@@ -92,7 +86,7 @@ class TestReports < Test::Unit::TestCase
# We have to reuse reporting here because of something going on in the
# server/report.rb file
- Puppet.config.use(:reporting)
+ Puppet.settings.use(:reporting)
3.times { |i|
log = Puppet.warning("Report test message %s" % i)
@@ -119,7 +113,7 @@ class TestReports < Test::Unit::TestCase
if Puppet.features.rrd?
def test_rrdgraph_report
- Puppet.config.use(:metrics)
+ Puppet.settings.use(:metrics)
report = mkreport
assert(! report.metrics.empty?, "Did not receive any metrics")
diff --git a/test/other/transactions.rb b/test/other/transactions.rb
index bf5f65084..7d17a92e7 100755
--- a/test/other/transactions.rb
+++ b/test/other/transactions.rb
@@ -7,8 +7,6 @@ require 'puppettest'
require 'mocha'
require 'puppettest/support/resources'
-# $Id$
-
class TestTransactions < Test::Unit::TestCase
include PuppetTest::FileTesting
include PuppetTest::Support::Resources
@@ -133,7 +131,7 @@ class TestTransactions < Test::Unit::TestCase
inst = type.create :name => "yay"
# Create a transaction
- trans = Puppet::Transaction.new(newcomp(inst))
+ trans = Puppet::Transaction.new(mk_configuration(inst))
# Make sure prefetch works
assert_nothing_raised do
@@ -255,7 +253,7 @@ class TestTransactions < Test::Unit::TestCase
}
- component = newcomp("file",file)
+ component = mk_configuration("file",file)
require 'etc'
groupname = Etc.getgrgid(File.stat(file.name).gid).name
assert_nothing_raised() {
@@ -295,12 +293,11 @@ class TestTransactions < Test::Unit::TestCase
file[:check] = check
file[:group] = @groups[0]
- assert_apply(file)
+ config = mk_configuration(file)
+ config.apply
@@tmpfiles << execfile
- component = newcomp("both",file,exec)
-
# 'subscribe' expects an array of arrays
exec[:subscribe] = [[file.class.name,file.name]]
exec[:refreshonly] = true
@@ -317,7 +314,11 @@ class TestTransactions < Test::Unit::TestCase
file[:mode] = "755"
}
- trans = assert_events([:file_changed, :triggered], component)
+ # Make a new configuration so the resource relationships get
+ # set up.
+ config = mk_configuration(file, exec)
+
+ trans = assert_events([:file_changed, :triggered], config)
assert(FileTest.exists?(execfile), "Execfile does not exist")
File.unlink(execfile)
@@ -325,7 +326,7 @@ class TestTransactions < Test::Unit::TestCase
file[:group] = @groups[1]
}
- trans = assert_events([:file_changed, :triggered], component)
+ trans = assert_events([:file_changed, :triggered], config)
assert(FileTest.exists?(execfile), "Execfile does not exist")
end
@@ -343,24 +344,30 @@ class TestTransactions < Test::Unit::TestCase
file[:group] = @groups[0]
assert_apply(file)
- fcomp = newcomp("file",file)
- ecomp = newcomp("exec",exec)
+ config = Puppet::Node::Configuration.new
+ fcomp = Puppet::Type.type(:component).create(:name => "file")
+ config.add_resource fcomp
+ config.add_resource file
+ config.add_edge!(fcomp, file)
- component = newcomp("both",fcomp,ecomp)
+ ecomp = Puppet::Type.type(:component).create(:name => "exec")
+ config.add_resource ecomp
+ config.add_resource exec
+ config.add_edge!(ecomp, exec)
# 'subscribe' expects an array of arrays
#component[:require] = [[file.class.name,file.name]]
ecomp[:subscribe] = fcomp
exec[:refreshonly] = true
- trans = assert_events([], component)
+ trans = assert_events([], config)
assert_nothing_raised() {
file[:group] = @groups[1]
file[:mode] = "755"
}
- trans = assert_events([:file_changed, :file_changed, :triggered], component)
+ trans = assert_events([:file_changed, :file_changed, :triggered], config)
end
# Make sure that multiple subscriptions get triggered.
@@ -426,7 +433,8 @@ class TestTransactions < Test::Unit::TestCase
Puppet[:ignoreschedules] = false
file = Puppet.type(:file).create(
:name => tempfile(),
- :ensure => "file"
+ :ensure => "file",
+ :backup => false
)
fname = tempfile()
@@ -437,11 +445,10 @@ class TestTransactions < Test::Unit::TestCase
:subscribe => ["file", file.name]
)
- comp = newcomp(file,exec)
- comp.finalize
+ config = mk_configuration(file, exec)
# Run it once
- assert_apply(comp)
+ assert_apply(config)
assert(FileTest.exists?(fname), "File did not get created")
assert(!exec.scheduled?, "Exec is somehow scheduled")
@@ -451,7 +458,8 @@ class TestTransactions < Test::Unit::TestCase
file[:content] = "some content"
- assert_events([:file_changed, :triggered], comp)
+ assert_events([:file_changed, :triggered], config)
+
assert(FileTest.exists?(fname), "File did not get recreated")
# Now remove it, so it can get created again
@@ -469,7 +477,7 @@ class TestTransactions < Test::Unit::TestCase
assert(! file.insync?(file.retrieve), "Uh, file is in sync?")
- assert_events([:file_changed, :triggered], comp)
+ assert_events([:file_changed, :triggered], config)
assert(FileTest.exists?(fname), "File did not get recreated")
end
@@ -493,11 +501,9 @@ class TestTransactions < Test::Unit::TestCase
:ensure => :file
)
- comp = newcomp(exec, file1, file2)
-
- comp.finalize
+ config = mk_configuration(exec, file1, file2)
- assert_apply(comp)
+ assert_apply(config)
assert(! FileTest.exists?(file1[:path]),
"File got created even tho its dependency failed")
@@ -506,31 +512,27 @@ class TestTransactions < Test::Unit::TestCase
end
end
- def f(n)
- Puppet::Type.type(:file)["/tmp/#{n.to_s}"]
- end
-
def test_relationship_graph
- one, two, middle, top = mktree
+ config = mktree
+
+ config.meta_def(:f) do |name|
+ self.resource("File[%s]" % name)
+ end
- {one => two, "f" => "c", "h" => middle}.each do |source, target|
- if source.is_a?(String)
- source = f(source)
- end
- if target.is_a?(String)
- target = f(target)
- end
+ {"one" => "two", "File[f]" => "File[c]", "File[h]" => "middle"}.each do |source_ref, target_ref|
+ source = config.resource(source_ref) or raise "Missing %s" % source_ref
+ target = config.resource(target_ref) or raise "Missing %s" % target_ref
target[:require] = source
end
- trans = Puppet::Transaction.new(top)
+ trans = Puppet::Transaction.new(config)
graph = nil
assert_nothing_raised do
graph = trans.relationship_graph
end
-
- assert_instance_of(Puppet::PGraph, graph,
+
+ assert_instance_of(Puppet::Node::Configuration, graph,
"Did not get relationship graph")
# Make sure all of the components are gone
@@ -544,13 +546,13 @@ class TestTransactions < Test::Unit::TestCase
sorted = graph.topsort.reverse
# Now make sure the appropriate edges are there and are in the right order
- assert(graph.dependents(f(:f)).include?(f(:c)),
+ assert(graph.dependents(config.f(:f)).include?(config.f(:c)),
"c not marked a dep of f")
- assert(sorted.index(f(:c)) < sorted.index(f(:f)),
+ assert(sorted.index(config.f(:c)) < sorted.index(config.f(:f)),
"c is not before f")
- one.each do |o|
- two.each do |t|
+ config.resource("one").each do |o|
+ config.resource("two").each do |t|
assert(graph.dependents(o).include?(t),
"%s not marked a dep of %s" % [t.ref, o.ref])
assert(sorted.index(t) < sorted.index(o),
@@ -558,22 +560,22 @@ class TestTransactions < Test::Unit::TestCase
end
end
- trans.resources.leaves(middle).each do |child|
- assert(graph.dependents(f(:h)).include?(child),
+ trans.configuration.leaves(config.resource("middle")).each do |child|
+ assert(graph.dependents(config.f(:h)).include?(child),
"%s not marked a dep of h" % [child.ref])
- assert(sorted.index(child) < sorted.index(f(:h)),
+ assert(sorted.index(child) < sorted.index(config.f(:h)),
"%s is not before h" % child.ref)
end
# Lastly, make sure our 'g' vertex made it into the relationship
# graph, since it's not involved in any relationships.
- assert(graph.vertex?(f(:g)),
+ assert(graph.vertex?(config.f(:g)),
"Lost vertexes with no relations")
# Now make the reversal graph and make sure all of the vertices made it into that
reverse = graph.reversal
%w{a b c d e f g h}.each do |letter|
- file = f(letter)
+ file = config.f(letter)
assert(reverse.vertex?(file), "%s did not make it into reversal" % letter)
end
end
@@ -594,15 +596,15 @@ class TestTransactions < Test::Unit::TestCase
yay = Puppet::Type.newgenerator :title => "yay"
rah = Puppet::Type.newgenerator :title => "rah"
- comp = newcomp(yay, rah)
- trans = comp.evaluate
+ config = mk_configuration(yay, rah)
+ trans = Puppet::Transaction.new(config)
assert_nothing_raised do
trans.generate
end
%w{ya ra y r}.each do |name|
- assert(trans.resources.vertex?(Puppet::Type.type(:generator)[name]),
+ assert(trans.configuration.vertex?(Puppet::Type.type(:generator)[name]),
"Generated %s was not a vertex" % name)
assert($finished.include?(name), "%s was not finished" % name)
end
@@ -613,7 +615,7 @@ class TestTransactions < Test::Unit::TestCase
end
%w{ya ra y r}.each do |name|
- assert(!trans.resources.vertex?(Puppet::Type.type(:generator)[name]),
+ assert(!trans.configuration.vertex?(Puppet::Type.type(: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)
@@ -633,8 +635,8 @@ class TestTransactions < Test::Unit::TestCase
yay = Puppet::Type.newgenerator :title => "yay"
rah = Puppet::Type.newgenerator :title => "rah", :subscribe => yay
- comp = newcomp(yay, rah)
- trans = comp.evaluate
+ config = mk_configuration(yay, rah)
+ trans = Puppet::Transaction.new(config)
trans.prepare
@@ -645,13 +647,13 @@ class TestTransactions < Test::Unit::TestCase
end
ya = type["ya"]
assert(ya, "Did not generate ya")
- assert(trans.relgraph.vertex?(ya),
+ assert(trans.relationship_graph.vertex?(ya),
"Did not add ya to rel_graph")
# Now make sure the appropriate relationships were added
- assert(trans.relgraph.edge?(yay, ya),
+ assert(trans.relationship_graph.edge?(yay, ya),
"parent was not required by child")
- assert(! trans.relgraph.edge?(ya, rah),
+ assert(! trans.relationship_graph.edge?(ya, rah),
"generated child ya inherited depencency on rah")
# Now make sure it in turn eval_generates appropriately
@@ -662,7 +664,7 @@ class TestTransactions < Test::Unit::TestCase
%w{y}.each do |name|
res = type[name]
assert(res, "Did not generate %s" % name)
- assert(trans.relgraph.vertex?(res),
+ assert(trans.relationship_graph.vertex?(res),
"Did not add %s to rel_graph" % name)
assert($finished.include?("y"), "y was not finished")
end
@@ -670,7 +672,7 @@ class TestTransactions < Test::Unit::TestCase
assert_nothing_raised("failed to eval_generate with nil response") do
trans.eval_resource(type["y"])
end
- assert(trans.relgraph.edge?(yay, ya), "no edge was created for ya => yay")
+ assert(trans.relationship_graph.edge?(yay, ya), "no edge was created for ya => yay")
assert_nothing_raised("failed to apply rah") do
trans.eval_resource(rah)
@@ -678,15 +680,15 @@ class TestTransactions < Test::Unit::TestCase
ra = type["ra"]
assert(ra, "Did not generate ra")
- assert(trans.relgraph.vertex?(ra),
+ assert(trans.relationship_graph.vertex?(ra),
"Did not add ra to rel_graph" % name)
assert($finished.include?("ra"), "y was not finished")
# Now make sure this generated resource has the same relationships as
# the generating resource
- assert(! trans.relgraph.edge?(yay, ra),
+ assert(! trans.relationship_graph.edge?(yay, ra),
"rah passed its dependencies on to its children")
- assert(! trans.relgraph.edge?(ya, ra),
+ assert(! trans.relationship_graph.edge?(ya, ra),
"children have a direct relationship")
# Now make sure that cleanup gets rid of those generated types.
@@ -695,14 +697,14 @@ class TestTransactions < Test::Unit::TestCase
end
%w{ya ra y r}.each do |name|
- assert(!trans.relgraph.vertex?(type[name]),
+ assert(!trans.relationship_graph.vertex?(type[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 = comp.evaluate
+ trans = Puppet::Transaction.new(config)
$evaluated.clear
assert_nothing_raised do
trans.evaluate
@@ -711,54 +713,41 @@ class TestTransactions < Test::Unit::TestCase
assert_equal(%w{yay ya y rah ra r}, $evaluated,
"Not all resources were evaluated or not in the right order")
end
-
- def test_tags
- res = Puppet::Type.newfile :path => tempfile()
- comp = newcomp(res)
-
- # Make sure they default to none
- assert_equal([], comp.evaluate.tags)
-
- # Make sure we get the main tags
- Puppet[:tags] = %w{this is some tags}
- assert_equal(%w{this is some tags}, comp.evaluate.tags)
-
- # And make sure they get processed correctly
- Puppet[:tags] = ["one", "two,three", "four"]
- assert_equal(%w{one two three four}, comp.evaluate.tags)
-
- # lastly, make sure we can override them
- trans = comp.evaluate
- trans.tags = ["one", "two,three", "four"]
- assert_equal(%w{one two three four}, comp.evaluate.tags)
+
+ def test_ignore_tags?
+ config = Puppet::Node::Configuration.new
+ config.host_config = true
+ transaction = Puppet::Transaction.new(config)
+ assert(! transaction.ignore_tags?, "Ignoring tags when applying a host configuration")
+
+ config.host_config = false
+ transaction = Puppet::Transaction.new(config)
+ assert(transaction.ignore_tags?, "Not ignoring tags when applying a non-host configuration")
end
- def test_tagged?
- res = Puppet::Type.newfile :path => tempfile()
- comp = newcomp(res)
- trans = comp.evaluate
-
- assert(trans.tagged?(res), "tagged? defaulted to false")
-
- # Now set some tags
- trans.tags = %w{some tags}
-
- # And make sure it's false
- assert(! trans.tagged?(res), "matched invalid tags")
-
- # Set ignoretags and make sure it sticks
- trans.ignoretags = true
- assert(trans.tagged?(res), "tags were not ignored")
-
- # Now make sure we actually correctly match tags
- res[:tag] = "mytag"
- trans.ignoretags = false
- trans.tags = %w{notag}
-
- assert(! trans.tagged?(res), "tags incorrectly matched")
-
- trans.tags = %w{mytag yaytag}
- assert(trans.tagged?(res), "tags should have matched")
+ def test_missing_tags?
+ resource = stub 'resource', :tagged? => true
+ config = Puppet::Node::Configuration.new
+
+ # Mark it as a host config so we don't care which test is first
+ config.host_config = true
+ transaction = Puppet::Transaction.new(config)
+ assert(! transaction.missing_tags?(resource), "Considered a resource to be missing tags when none are set")
+
+ # host configurations pay attention to tags, no one else does.
+ Puppet[:tags] = "three,four"
+ config.host_config = false
+ transaction = Puppet::Transaction.new(config)
+ assert(! transaction.missing_tags?(resource), "Considered a resource to be missing tags when not running a host configuration")
+
+ #
+ config.host_config = true
+ transaction = Puppet::Transaction.new(config)
+ assert(! transaction.missing_tags?(resource), "Considered a resource to be missing tags when running a host configuration and all tags are present")
+
+ transaction = Puppet::Transaction.new(config)
+ resource.stubs :tagged? => false
+ assert(transaction.missing_tags?(resource), "Considered a resource not to be missing tags when running a host configuration and tags are missing")
end
# Make sure changes generated by eval_generated resources have proxies
@@ -772,8 +761,8 @@ class TestTransactions < Test::Unit::TestCase
end
resource = type.create :name => "test"
- comp = newcomp(resource)
- trans = comp.evaluate
+ config = mk_configuration(resource)
+ trans = Puppet::Transaction.new(config)
trans.prepare
assert_nothing_raised do
@@ -831,7 +820,7 @@ class TestTransactions < Test::Unit::TestCase
end
# Make a graph with some stuff in it.
- graph = Puppet::PGraph.new
+ graph = Puppet::Node::Configuration.new
# Add a non-triggering edge.
a = trigger.new(:a)
@@ -883,52 +872,12 @@ class TestTransactions < Test::Unit::TestCase
assert(trans.triggered?(c, :refresh),
"Transaction did not store the trigger")
end
-
- def test_graph
- Puppet.config.use(:main)
- # Make a graph
- graph = Puppet::PGraph.new
- graph.add_edge!("a", "b")
-
- # Create our transaction
- trans = Puppet::Transaction.new(graph)
-
- assert_nothing_raised do
- trans.graph(graph, :testing)
- end
-
- dotfile = File.join(Puppet[:graphdir], "testing.dot")
- assert(! FileTest.exists?(dotfile), "Enabled graphing even tho disabled")
-
- # Now enable graphing
- Puppet[:graph] = true
-
- assert_nothing_raised do
- trans.graph(graph, :testing)
- end
- assert(FileTest.exists?(dotfile), "Did not create graph.")
- end
-
- def test_created_graphs
- FileUtils.mkdir_p(Puppet[:graphdir])
- file = Puppet::Type.newfile(:path => tempfile, :content => "yay")
- exec = Puppet::Type.type(:exec).create(:command => "echo yay", :path => ENV['PATH'],
- :require => file)
-
- Puppet[:graph] = true
- assert_apply(file, exec)
-
- %w{resources relationships expanded_relationships}.each do |name|
- file = File.join(Puppet[:graphdir], "%s.dot" % name)
- assert(FileTest.exists?(file), "graph for %s was not created" % name)
- end
- end
def test_set_target
file = Puppet::Type.newfile(:path => tempfile(), :content => "yay")
exec1 = Puppet::Type.type(:exec).create :command => "/bin/echo exec1"
exec2 = Puppet::Type.type(:exec).create :command => "/bin/echo exec2"
- trans = Puppet::Transaction.new(newcomp(file, exec1, exec2))
+ trans = Puppet::Transaction.new(mk_configuration(file, exec1, exec2))
# First try it with an edge that has no callback
edge = Puppet::Relationship.new(file, exec1)
@@ -975,7 +924,8 @@ class TestTransactions < Test::Unit::TestCase
one[:require] = two
two[:require] = one
- trans = newcomp(one, two).evaluate
+ config = mk_configuration(one, two)
+ trans = Puppet::Transaction.new(config)
assert_raise(Puppet::Error) do
trans.prepare
end
@@ -1042,15 +992,15 @@ class TestTransactions < Test::Unit::TestCase
rels[dir] = file
rels.each do |after, before|
- comp = newcomp(before, after)
- trans = comp.evaluate
+ config = mk_configuration(before, after)
+ trans = Puppet::Transaction.new(config)
str = "from %s to %s" % [before, after]
assert_nothing_raised("Failed to create graph %s" % str) do
trans.prepare
end
- graph = trans.relgraph
+ graph = trans.relationship_graph
assert(graph.edge?(before, after), "did not create manual relationship %s" % str)
assert(! graph.edge?(after, before), "created automatic relationship %s" % str)
end
@@ -1063,7 +1013,7 @@ class TestTransactions < Test::Unit::TestCase
one[:require] = two
one[:subscribe] = two
- comp = newcomp(one, two)
+ comp = mk_configuration(one, two)
trans = Puppet::Transaction.new(comp)
graph = trans.relationship_graph
@@ -1188,5 +1138,3 @@ class TestTransactions < Test::Unit::TestCase
assert_equal(1, $flushed, "object was flushed in noop")
end
end
-
-# $Id$
diff --git a/test/puppet/conffiles.rb b/test/puppet/conffiles.rb
index 3dfa53a13..1800c80f6 100755
--- a/test/puppet/conffiles.rb
+++ b/test/puppet/conffiles.rb
@@ -3,7 +3,6 @@
$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
require 'puppettest'
-require 'puppet/util/config'
class TestConfFiles < Test::Unit::TestCase
include PuppetTest
@@ -72,7 +71,7 @@ class TestConfFiles < Test::Unit::TestCase
path = tempfile()
sampledata { |data|
- config = Puppet::Util::Config.new
+ config = Puppet::Util::Settings.new
data.each { |section, hash|
hash.each { |param, value|
config.setdefaults(section, param => [value, value])
@@ -100,7 +99,7 @@ class TestConfFiles < Test::Unit::TestCase
# that the default config is free of simple typos etc.
def test_genconfig
assert_nothing_raised {
- Puppet::config::to_config
+ Puppet::settings::to_config
}
end
diff --git a/test/ral/manager/type.rb b/test/ral/manager/type.rb
index 534c35759..b2c111e60 100755
--- a/test/ral/manager/type.rb
+++ b/test/ral/manager/type.rb
@@ -174,7 +174,7 @@ class TestType < Test::Unit::TestCase
)
}
- comp = newcomp(twoobj, oneobj)
+ comp = mk_configuration(twoobj, oneobj)
assert_nothing_raised {
comp.finalize
@@ -246,76 +246,6 @@ class TestType < Test::Unit::TestCase
# and make sure managed objects start with them
assert(user.property(:ensure), "User did not get an ensure property")
end
-
- # Make sure removal works
- def test_remove
- objects = {}
- top = Puppet.type(:component).create(:name => "top")
- objects[top.class] = top
-
- base = tempfile()
-
- # now make a two-tier, 5 piece tree
- %w{a b}.each do |letter|
- name = "comp%s" % letter
- comp = Puppet.type(:component).create(:name => name)
- top.push comp
- objects[comp.class] = comp
-
- 5.times do |i|
- file = base + letter + i.to_s
-
- obj = Puppet.type(:file).create(:name => file, :ensure => "file")
-
- comp.push obj
- objects[obj.class] = obj
- end
- end
-
- assert_nothing_raised do
- top.remove
- end
-
- objects.each do |klass, obj|
- assert_nil(klass[obj.name], "object %s was not removed" % obj.name)
- end
- end
-
- # Verify that objects can't be their own children.
- def test_object_recursion
- comp = Puppet.type(:component).create(:name => "top")
-
- file = Puppet.type(:component).create(:name => "middle")
-
- assert_raise(Puppet::DevError) do
- comp.push(comp)
- end
-
- assert_raise(Puppet::DevError) do
- file.push(file)
- end
-
- assert_raise(Puppet::DevError) do
- comp.parent = comp
- end
-
- assert_raise(Puppet::DevError) do
- file.parent = file
- end
-
- assert_nothing_raised {
- comp.push(file)
- }
-
- assert_raise(Puppet::DevError) do
- file.push(comp)
- end
-
- assert_raise(Puppet::DevError) do
- comp.parent = file
- end
- end
-
def test_newtype_methods
assert_nothing_raised {
Puppet::Type.newtype(:mytype) do
@@ -732,12 +662,22 @@ class TestType < Test::Unit::TestCase
end
def test_path
+ config = mk_configuration
+
# Check that our paths are built correctly. Just pick a random, "normal" type.
type = Puppet::Type.type(:exec)
mk = Proc.new do |i, hash|
hash[:title] = "exec%s" % i
hash[:command] = "/bin/echo"
- type.create(hash)
+ if parent = hash[:parent]
+ hash.delete(:parent)
+ end
+ res = type.create(hash)
+ config.add_resource res
+ if parent
+ config.add_edge!(parent, res)
+ end
+ res
end
exec = mk.call(1, {})
@@ -745,25 +685,31 @@ class TestType < Test::Unit::TestCase
assert_equal("/Exec[exec1]", exec.path)
comp = Puppet::Type.newcomponent :title => "My[component]", :type => "Yay"
+ config.add_resource comp
exec = mk.call(2, :parent => comp)
assert_equal("/My[component]/Exec[exec2]", exec.path)
comp = Puppet::Type.newcomponent :name => "Other[thing]"
+ config.add_resource comp
exec = mk.call(3, :parent => comp)
assert_equal("/Other[thing]/Exec[exec3]", exec.path)
comp = Puppet::Type.newcomponent :type => "server", :name => "server"
+ config.add_resource comp
exec = mk.call(4, :parent => comp)
assert_equal("/server/Exec[exec4]", exec.path)
comp = Puppet::Type.newcomponent :type => "whatever", :name => "class[main]"
+ config.add_resource comp
exec = mk.call(5, :parent => comp)
assert_equal("//Exec[exec5]", exec.path)
- comp = Puppet::Type.newcomponent :type => "yay", :name => "Good[bad]", :parent => comp
- exec = mk.call(6, :parent => comp)
+ newcomp = Puppet::Type.newcomponent :type => "yay", :name => "Good[bad]"
+ config.add_resource newcomp
+ config.add_edge! comp, newcomp
+ exec = mk.call(6, :parent => newcomp)
assert_equal("//Good[bad]/Exec[exec6]", exec.path)
end
diff --git a/test/ral/providers/service.rb b/test/ral/providers/service.rb
index d21298162..5a4a6c1c2 100755
--- a/test/ral/providers/service.rb
+++ b/test/ral/providers/service.rb
@@ -54,7 +54,7 @@ class TestLocalService < Test::Unit::TestCase
service.retrieve
}
- comp = newcomp("servicetst", service)
+ comp = mk_configuration("servicetst", service)
service[:ensure] = :running
Puppet.info "Starting %s" % service.name
@@ -105,7 +105,7 @@ class TestLocalService < Test::Unit::TestCase
service.retrieve
}
- comp = newcomp("servicetst", service)
+ comp = mk_configuration("servicetst", service)
service[:enable] = true
Puppet.info "Enabling %s" % service.name
diff --git a/test/ral/types/basic.rb b/test/ral/types/basic.rb
index 5d09a5183..2802f3440 100755
--- a/test/ral/types/basic.rb
+++ b/test/ral/types/basic.rb
@@ -35,12 +35,9 @@ class TestBasic < Test::Unit::TestCase
:path => ENV["PATH"]
)
}
- assert_nothing_raised() {
- @component.push(
- @configfile,
- @command
- )
- }
+ @config = mk_configuration(@component, @configfile, @command)
+ @config.add_edge! @component, @configfile
+ @config.add_edge! @component, @command
end
def teardown
@@ -86,5 +83,3 @@ class TestBasic < Test::Unit::TestCase
}
end
end
-
-# $Id$
diff --git a/test/ral/types/component.rb b/test/ral/types/component.rb
deleted file mode 100755
index 06c32dd01..000000000
--- a/test/ral/types/component.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-#!/usr/bin/env ruby
-
-$:.unshift("../../lib") if __FILE__ =~ /\.rb$/
-
-require 'puppettest'
-require 'puppettest/support/resources'
-
-# $Id$
-
-class TestComponent < Test::Unit::TestCase
- include PuppetTest
- include PuppetTest::Support::Resources
- def setup
- super
- @@used = {}
- @type = Puppet::Type::Component
- @file = Puppet::Type.type(:file)
- end
-
- def randnum(limit)
- num = nil
- looped = 0
- loop do
- looped += 1
- if looped > 2000
- raise "Reached limit of looping"
- break
- end
- num = rand(limit)
- unless @@used.include?(num)
- @@used[num] = true
- break
- end
- end
-
- num
- end
-
- def mkfile(num = nil)
- unless num
- num = randnum(1000)
- end
- name = tempfile() + num.to_s
-
- file = Puppet.type(:file).create(
- :path => name,
- :checksum => "md5"
- )
- @@tmpfiles << name
- file
- end
-
- def mkcomp
- Puppet.type(:component).create(:name => "component_" + randnum(1000).to_s)
- end
-
- def mkrandcomp(numfiles, numdivs)
- comp = mkcomp
- hash = {}
- found = 0
-
- divs = {}
-
- numdivs.times { |i|
- num = i + 2
- divs[num] = nil
- }
- while found < numfiles
- num = randnum(numfiles)
- found += 1
- f = mkfile(num)
- hash[f.name] = f
- reqd = []
- divs.each { |n,obj|
- if rand(50) % n == 0
- if obj
- unless reqd.include?(obj.object_id)
- f[:require] = [[obj.class.name, obj.name]]
- reqd << obj.object_id
- end
- end
- end
-
- divs[n] = f
- }
- end
-
- hash.each { |name, obj|
- comp.push obj
- }
-
- comp.finalize
- comp
- end
-
- def test_to_graph
- one, two, middle, top = mktree
-
- graph = nil
- assert_nothing_raised do
- graph = top.to_graph
- end
-
- assert(graph.is_a?(Puppet::PGraph), "result is not a pgraph")
-
- [one, two, middle, top].each do |comp|
- comp.each do |child|
- assert(graph.edge?(comp, child),
- "Did not create edge from %s => %s" % [comp.name, child.name])
- end
- end
- end
-end
diff --git a/test/ral/types/cron.rb b/test/ral/types/cron.rb
index 7b2e770f0..1695befac 100755
--- a/test/ral/types/cron.rb
+++ b/test/ral/types/cron.rb
@@ -94,7 +94,7 @@ class TestCron < Test::Unit::TestCase
text = obj.read
name = cron.name
- comp = newcomp(name, cron)
+ comp = mk_configuration(name, cron)
assert_events([:cron_created], comp)
cron.provider.class.prefetch
@@ -157,7 +157,7 @@ class TestCron < Test::Unit::TestCase
def test_makeandretrievecron
%w{storeandretrieve a-name another-name more_naming SomeName}.each do |name|
cron = mkcron(name)
- comp = newcomp(name, cron)
+ comp = mk_configuration(name, cron)
trans = assert_events([:cron_created], comp, name)
cron.provider.class.prefetch
diff --git a/test/ral/types/exec.rb b/test/ral/types/exec.rb
index ede6361cd..0c7cc1d90 100755
--- a/test/ral/types/exec.rb
+++ b/test/ral/types/exec.rb
@@ -179,7 +179,7 @@ class TestExec < Test::Unit::TestCase
)
}
- comp = newcomp("createstest", exec)
+ comp = mk_configuration("createstest", exec)
assert_events([:executed_command], comp, "creates")
assert_events([], comp, "creates")
end
@@ -202,7 +202,7 @@ class TestExec < Test::Unit::TestCase
:require => [:file, oexe]
)
- comp = newcomp("Testing", file, exec)
+ comp = mk_configuration("Testing", file, exec)
assert_events([:file_created, :executed_command], comp)
end
@@ -299,7 +299,7 @@ class TestExec < Test::Unit::TestCase
:path => ENV['PATH']
)
}
- comp = newcomp(exec)
+ comp = mk_configuration(exec)
assert_events([:executed_command], comp)
assert_events([:executed_command], comp)
@@ -344,7 +344,7 @@ class TestExec < Test::Unit::TestCase
exec = Puppet.type(:exec).create(args)
}
- comp = newcomp("usertest", exec)
+ comp = mk_configuration("usertest", exec)
assert_events([:executed_command], comp, "usertest")
assert(FileTest.exists?(file), "File does not exist")
@@ -425,7 +425,7 @@ class TestExec < Test::Unit::TestCase
)
}
- comp = newcomp(file, exec)
+ comp = mk_configuration(file, exec)
comp.finalize
assert_events([:executed_command, :file_changed], comp)
diff --git a/test/ral/types/file.rb b/test/ral/types/file.rb
index f3e1a562d..0c16d6dff 100755
--- a/test/ral/types/file.rb
+++ b/test/ral/types/file.rb
@@ -122,7 +122,7 @@ class TestFile < Test::Unit::TestCase
)
}
- comp = newcomp("createusertest", file)
+ comp = mk_configuration("createusertest", file)
assert_events([:file_created], comp)
end
@@ -397,6 +397,8 @@ class TestFile < Test::Unit::TestCase
events = assert_apply(file)
+ assert(events)
+
assert(! events.include?(:file_changed),
"File incorrectly changed")
assert_events([], file)
@@ -493,6 +495,7 @@ class TestFile < Test::Unit::TestCase
# Create a test directory
path = tempfile()
dir = @file.create :path => path, :mode => 0755, :recurse => true
+ config = mk_configuration(dir)
Dir.mkdir(path)
@@ -673,6 +676,7 @@ class TestFile < Test::Unit::TestCase
:check => %w{owner mode group}
)
}
+ config = mk_configuration dir
children = nil
@@ -683,19 +687,22 @@ class TestFile < Test::Unit::TestCase
assert_equal([subdir], children.collect {|c| c.title },
"Incorrect generated children")
- dir.class[subdir].remove
+ # Remove our subdir resource,
+ subdir_resource = config.resource(:file, subdir)
+ config.remove_resource(subdir_resource)
+ # Create the test file
File.open(tmpfile, "w") { |f| f.puts "yayness" }
assert_nothing_raised {
children = dir.eval_generate
}
+ # And make sure we get both resources back.
assert_equal([subdir, tmpfile].sort, children.collect {|c| c.title }.sort,
- "Incorrect generated children")
+ "Incorrect generated children when recurse == %s" % value.inspect)
File.unlink(tmpfile)
- #system("rm -rf %s" % basedir)
Puppet.type(:file).clear
end
end
@@ -754,6 +761,7 @@ class TestFile < Test::Unit::TestCase
:check => %w{owner mode group}
)
}
+ mk_configuration dir
assert_nothing_raised {
dir.eval_generate
@@ -796,6 +804,7 @@ class TestFile < Test::Unit::TestCase
:check => %w{mode owner group}
)
}
+ mk_configuration dirobj
assert_nothing_raised {
dirobj.eval_generate
@@ -884,7 +893,7 @@ class TestFile < Test::Unit::TestCase
)
}
- comp = newcomp("yay", file)
+ comp = mk_configuration("yay", file)
comp.finalize
assert_apply(comp)
#assert_events([:directory_created], comp)
@@ -1274,26 +1283,27 @@ class TestFile < Test::Unit::TestCase
lfobj = Puppet::Type.newfile(
:title => "localfile",
:path => localfile,
- :content => "rahtest"
+ :content => "rahtest",
+ :backup => false
)
-
destobj = Puppet::Type.newfile(:title => "destdir", :path => destdir,
:source => sourcedir,
+ :backup => false,
:recurse => true)
- comp = newcomp(lfobj, destobj)
- assert_apply(comp)
+ config = mk_configuration(lfobj, destobj)
+ config.apply
assert(FileTest.exists?(dsourcefile), "File did not get copied")
assert(FileTest.exists?(localfile), "File did not get created")
assert(FileTest.exists?(purgee), "File got prematurely purged")
assert_nothing_raised { destobj[:purge] = true }
- assert_apply(comp)
+ config.apply
- assert(FileTest.exists?(dsourcefile), "Source file got purged")
assert(FileTest.exists?(localfile), "Local file got purged")
+ assert(FileTest.exists?(dsourcefile), "Source file got purged")
assert(! FileTest.exists?(purgee), "File did not get purged")
end
@@ -1333,7 +1343,7 @@ class TestFile < Test::Unit::TestCase
group = Puppet.type(:group).create(
:name => "pptestg"
)
- comp = newcomp(user, group, home)
+ comp = mk_configuration(user, group, home)
}
# Now make sure we get a relationship for each of these
@@ -1629,6 +1639,7 @@ 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_configuration obj
assert_equal("/%s" % obj.ref, obj.path)
@@ -1739,6 +1750,7 @@ 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_configuration(obj)
children = nil
assert_nothing_raised("Failure when recursing") do
@@ -1747,6 +1759,7 @@ class TestFile < Test::Unit::TestCase
assert(obj.class[subdir], "did not create subdir object")
children.each do |c|
assert_nothing_raised("Failure when recursing on %s" % c) do
+ c.configuration = config
others = c.eval_generate
end
end
@@ -1780,6 +1793,7 @@ class TestFile < Test::Unit::TestCase
obj = Puppet::Type.newfile(:path => dir, :ensure => :directory,
:recurse => true)
+ config = mk_configuration(obj)
children = nil
assert_nothing_raised do
children = obj.eval_generate
diff --git a/test/ral/types/file/target.rb b/test/ral/types/file/target.rb
index 1e62f07ac..c4597cedf 100755
--- a/test/ral/types/file/target.rb
+++ b/test/ral/types/file/target.rb
@@ -44,6 +44,7 @@ class TestFileTarget < Test::Unit::TestCase
def test_linkrecurse
dest = tempfile()
link = @file.create :path => tempfile(), :recurse => true, :ensure => dest
+ mk_configuration link
ret = nil
@@ -317,9 +318,8 @@ class TestFileTarget < Test::Unit::TestCase
:source => dirs["source"],
:recurse => true
)
-
-
- trans = assert_apply(obj)
+ config = mk_configuration obj
+ config.apply
newfile = File.join(dirs["target"], "sourcefile")
diff --git a/test/ral/types/fileignoresource.rb b/test/ral/types/fileignoresource.rb
index fa01aecdc..153946770 100755
--- a/test/ral/types/fileignoresource.rb
+++ b/test/ral/types/fileignoresource.rb
@@ -73,19 +73,8 @@ class TestFileIgnoreSources < Test::Unit::TestCase
)
}
- #make a component and adds the file
- comp = Puppet.type(:component).create(
- :name => "component"
- )
- comp.push tofile
-
- #make, evaluate transaction and sync the component
- assert_nothing_raised {
- trans = comp.evaluate
- }
- assert_nothing_raised {
- trans.evaluate
- }
+ config = mk_configuration(tofile)
+ config.apply
#topath should exist as a directory with sourcedir as a directory
@@ -150,19 +139,8 @@ class TestFileIgnoreSources < Test::Unit::TestCase
)
}
- #make a component and adds the file
- comp = Puppet.type(:component).create(
- :name => "component"
- )
- comp.push tofile
-
- #make, evaluate transaction and sync the component
- assert_nothing_raised {
- trans = comp.evaluate
- }
- assert_nothing_raised {
- trans.evaluate
- }
+ config = mk_configuration(tofile)
+ config.apply
#topath should exist as a directory with sourcedir as a directory
@@ -170,6 +148,7 @@ class TestFileIgnoreSources < Test::Unit::TestCase
assert(FileTest.exists?(File.join(topath,sourcefile1)))
assert(FileTest.exists?(File.join(topath,subdir)))
assert(FileTest.exists?(File.join(File.join(topath,subdir),sourcefile1)))
+
#This file should not
assert(!(FileTest.exists?(File.join(topath,sourcefile2))))
assert(!(FileTest.exists?(File.join(topath,subdir2))))
@@ -235,19 +214,8 @@ class TestFileIgnoreSources < Test::Unit::TestCase
)
}
- #make a component and adds the file
- comp = Puppet.type(:component).create(
- :name => "component"
- )
- comp.push tofile
-
- #make, evaluate transaction and sync the component
- assert_nothing_raised {
- trans = comp.evaluate
- }
- assert_nothing_raised {
- trans.evaluate
- }
+ config = mk_configuration(tofile)
+ config.apply
#topath should exist as a directory with sourcedir as a directory
@@ -273,5 +241,3 @@ class TestFileIgnoreSources < Test::Unit::TestCase
end
end
-
-# $Id$
diff --git a/test/ral/types/filesources.rb b/test/ral/types/filesources.rb
index b257fd935..01d9766db 100755
--- a/test/ral/types/filesources.rb
+++ b/test/ral/types/filesources.rb
@@ -62,6 +62,7 @@ class TestFileSources < Test::Unit::TestCase
:name => path
)
}
+ config = mk_configuration(file)
child = nil
assert_nothing_raised {
child = file.newchild("childtest", true)
@@ -275,6 +276,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_configuration(obj)
result = nil
sourced = nil
@@ -288,7 +290,7 @@ class TestFileSources < Test::Unit::TestCase
assert_equal([dfileobj], result)
# Clean this up so it can be recreated
- dfileobj.remove
+ config.remove_resource(dfileobj)
# Make sure we correctly iterate over the sources
nosource = tempfile()
@@ -577,51 +579,6 @@ class TestFileSources < Test::Unit::TestCase
}
end
- def test_networkSourcesWithoutService
- server = nil
-
- Puppet[:autosign] = true
- Puppet[:masterport] = 8765
-
- serverpid = nil
- assert_nothing_raised() {
- server = Puppet::Network::Server::WEBrick.new(
- :Handlers => {
- :CA => {}, # so that certs autogenerate
- }
- )
-
- }
- 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/dist/file",
- :name => name
- )
-
- assert_nothing_raised {
- file.retrieve
- }
-
- comp = newcomp("nosource", file)
-
- assert_nothing_raised {
- comp.evaluate
- }
-
- assert(!FileTest.exists?(name), "File with no source exists anyway")
- end
-
def test_unmountedNetworkSources
server = nil
mounts = {
@@ -669,11 +626,8 @@ class TestFileSources < Test::Unit::TestCase
file.retrieve
}
- comp = newcomp("nosource", file)
-
- assert_nothing_raised {
- comp.evaluate
- }
+ comp = mk_configuration(file)
+ comp.apply
assert(!FileTest.exists?(name), "File with no source exists anyway")
end
@@ -722,7 +676,7 @@ class TestFileSources < Test::Unit::TestCase
)
}
- comp = newcomp(file)
+ comp = mk_configuration(file)
assert_events([:file_created], comp)
assert(File.exists?(to), "File does not exist")
@@ -808,9 +762,8 @@ class TestFileSources < Test::Unit::TestCase
trans = nil
assert_nothing_raised {
file[:links] = :manage
- comp = newcomp(file)
- trans = comp.evaluate
- trans.evaluate
+ comp = mk_configuration(file)
+ trans = comp.apply
}
assert(trans.failed?(file), "Object did not fail to copy links")
diff --git a/test/ral/types/group.rb b/test/ral/types/group.rb
index 9870d533a..5189c63a1 100755
--- a/test/ral/types/group.rb
+++ b/test/ral/types/group.rb
@@ -65,7 +65,7 @@ class TestGroup < Test::Unit::TestCase
def attrtest_ensure(group)
group[:ensure] = :absent
- comp = newcomp("ensuretest", group)
+ comp = mk_configuration("ensuretest", group)
assert_apply(comp)
assert_equal(:absent, group.provider.ensure, "Group is still present")
group[:ensure] = :present
@@ -91,7 +91,7 @@ class TestGroup < Test::Unit::TestCase
assert_equal(15, group.should(:gid),
"Did not convert gid to number")
- comp = newcomp(group)
+ comp = mk_configuration(group)
trans = assert_events([:group_modified], comp, "group")
assert_equal(15, group.provider.gid, "GID was not changed")
diff --git a/test/ral/types/tidy.rb b/test/ral/types/tidy.rb
index b8d576b9a..8fada1adb 100755
--- a/test/ral/types/tidy.rb
+++ b/test/ral/types/tidy.rb
@@ -55,7 +55,7 @@ class TestTidy < Test::Unit::TestCase
assert_nothing_raised {
link = newlink(:target => source, :recurse => true)
}
- comp = newcomp("linktest",link)
+ comp = mk_configuration("linktest",link)
cycle(comp)
path = link.name
diff --git a/test/ral/types/user.rb b/test/ral/types/user.rb
index 121ac9cf0..9b24cc74a 100755
--- a/test/ral/types/user.rb
+++ b/test/ral/types/user.rb
@@ -82,7 +82,7 @@ class TestUser < Test::Unit::TestCase
old = user.provider.ensure
user[:ensure] = :absent
- comp = newcomp("ensuretest", user)
+ comp = mk_configuration("ensuretest", user)
assert_apply(user)
assert(!user.provider.exists?, "User is still present")
user[:ensure] = :present
@@ -102,7 +102,7 @@ class TestUser < Test::Unit::TestCase
old = user.provider.comment
user[:comment] = "A different comment"
- comp = newcomp("commenttest", user)
+ comp = mk_configuration("commenttest", user)
trans = assert_events([:user_changed], comp, "user")
@@ -117,7 +117,7 @@ class TestUser < Test::Unit::TestCase
def attrtest_home(user)
obj = nil
- comp = newcomp("hometest", user)
+ comp = mk_configuration("hometest", user)
old = user.provider.home
user[:home] = old
@@ -137,7 +137,7 @@ class TestUser < Test::Unit::TestCase
def attrtest_shell(user)
old = user.provider.shell
- comp = newcomp("shelltest", user)
+ comp = mk_configuration("shelltest", user)
user[:shell] = old
@@ -167,7 +167,7 @@ class TestUser < Test::Unit::TestCase
def attrtest_gid(user)
obj = nil
old = user.provider.gid
- comp = newcomp("gidtest", user)
+ comp = mk_configuration("gidtest", user)
user.retrieve
@@ -216,7 +216,7 @@ class TestUser < Test::Unit::TestCase
def attrtest_uid(user)
obj = nil
- comp = newcomp("uidtest", user)
+ comp = mk_configuration("uidtest", user)
user.provider.uid = 1
@@ -387,7 +387,7 @@ class TestUser < Test::Unit::TestCase
ogroup = Puppet.type(:group).create(
:name => "yayness"
)
- comp = newcomp(user, group, home, ogroup)
+ comp = mk_configuration(user, group, home, ogroup)
}
rels = nil
@@ -404,7 +404,7 @@ class TestUser < Test::Unit::TestCase
user = mkuser(name)
- comp = newcomp("usercomp", user)
+ comp = mk_configuration("usercomp", user)
trans = assert_events([:user_created], comp, "user")
@@ -424,7 +424,7 @@ class TestUser < Test::Unit::TestCase
assert(! user.provider.exists?, "User %s is present" % name)
- comp = newcomp("usercomp", user)
+ comp = mk_configuration("usercomp", user)
trans = assert_events([:user_created], comp, "user")
diff --git a/test/util/fact_store.rb b/test/util/fact_store.rb
deleted file mode 100755
index 5b04d1374..000000000
--- a/test/util/fact_store.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env ruby
-#
-# Created by Luke Kanies on 2007-05-02.
-# Copyright (c) 2007. All rights reserved.
-
-$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
-
-require 'puppettest'
-require 'puppet/util/fact_store'
-
-class TestFactStore < Test::Unit::TestCase
- include PuppetTest
-
- def test_new_fact_store
- klass = nil
- assert_nothing_raised("Could not create fact store") do
- klass = Puppet::Util::FactStore.newstore(:yay) do
- end
- end
-
- assert_equal(klass, Puppet::Util::FactStore.store(:yay), "Did not get created store back by name")
- end
-
- def test_yaml_store
- yaml = Puppet::Util::FactStore.store(:yaml)
- assert(yaml, "Could not retrieve yaml store")
-
- name = "node"
- facts = {"a" => :b, :c => "d", :e => :f, "g" => "h"}
-
- store = nil
- assert_nothing_raised("Could not create YAML store instance") do
- store = yaml.new
- end
-
- assert_nothing_raised("Could not store host facts") do
- store.set(name, facts)
- end
-
- dir = Puppet[:yamlfactdir]
-
- file = File.join(dir, name + ".yaml")
- assert(FileTest.exists?(file), "Did not create yaml file for node")
-
- text = File.read(file)
- newfacts = nil
- assert_nothing_raised("Could not deserialize yaml") do
- newfacts = YAML::load(text)
- end
-
- # Don't directly compare the hashes, because there might be extra
- # data stored in the client hash
- facts.each do |var, value|
- assert_equal(value, newfacts[var], "Value for %s changed during storage" % var)
- end
-
- # Now make sure the facts get retrieved correctly
- assert_nothing_raised("Could not retrieve facts") do
- newfacts = store.get(name)
- end
-
- # Now make sure the hashes are equal, since internal facts should not be returned.
- assert_equal(facts, newfacts, "Retrieved facts are not equal")
- end
-end
-
-# $Id$
diff --git a/test/util/features.rb b/test/util/features.rb
index 14e93c537..1e5858877 100755
--- a/test/util/features.rb
+++ b/test/util/features.rb
@@ -93,5 +93,3 @@ class TestFeatures < Test::Unit::TestCase
end
end
end
-
-# $Id$
diff --git a/test/util/graph.rb b/test/util/graph.rb
deleted file mode 100755
index 875fd0ec3..000000000
--- a/test/util/graph.rb
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env ruby
-#
-# Created by Luke Kanies on 2006-11-16.
-# Copyright (c) 2006. All rights reserved.
-
-$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
-
-require 'puppettest'
-require 'puppettest/graph'
-require 'puppet/util/graph'
-
-class TestUtilGraph < Test::Unit::TestCase
- include PuppetTest
- include PuppetTest::Graph
-
- def test_to_graph
- children = %w{a b c d}
- list = Container.new("yay", children)
-
- graph = nil
- assert_nothing_raised do
- graph = list.to_graph
- end
-
- assert(graph.vertices.include?(list), "wtf?")
-
- ([list] + children).each do |thing|
- assert(graph.vertex?(thing), "%s is not a vertex" % thing)
- end
- children.each do |child|
- assert(graph.edge?(list, child),
- "%s/%s was not added as an edge" % ["yay", child])
- end
- end
-
- def test_recursive_to_graph
- one, two, three, middle, top = build_tree
-
- graph = nil
- assert_nothing_raised do
- graph = top.to_graph
- end
-
- (%w{a b c d e f g h} + [one, two, middle, top]).each do |v|
- assert(graph.vertex?(v), "%s is not a vertex" % v)
- end
-
- [one, two, middle, top].each do |con|
- con.each do |child|
- assert(graph.edge?(con, child), "%s/%s is not an edge" % [con, child])
- end
- end
-
- # Now make sure we correctly retrieve the leaves from each container
- {top => %w{a b c d e f g h i j},
- one => %w{a b},
- two => %w{c d},
- three => %w{i j},
- middle => %w{c d e f}}.each do |cont, list|
- leaves = nil
- assert_nothing_raised do
- leaves = graph.leaves(cont)
- end
- leaves = leaves.sort
- assert_equal(list.sort, leaves.sort,
- "Got incorrect leaf list for %s" % cont.name)
- %w{a b c d e f g h}.each do |letter|
- unless list.include?(letter)
- assert(!leaves.include?(letter),
- "incorrectly got %s as a leaf of %s" %
- [letter, cont.to_s])
- end
- end
- end
- end
-
- def test_to_graph_with_block
- middle = Container.new "middle", ["c", "d", 3, 4]
- top = Container.new "top", ["a", "b", middle, 1, 2]
-
- graph = nil
- assert_nothing_raised() {
- graph = top.to_graph { |c| c.is_a?(String) or c.is_a?(Container) }
- }
-
- %w{a b c d}.each do |child|
- assert(graph.vertex?(child), "%s was not added as a vertex" % child)
- end
-
- [1, 2, 3, 4].each do |child|
- assert(! graph.vertex?(child), "%s is a vertex" % child)
- end
- end
-
- def test_cyclic_graphs
- one = Container.new "one", %w{a b}
- two = Container.new "two", %w{c d}
-
- one.push(two)
- two.push(one)
-
- assert_raise(Puppet::Error, "did not fail on cyclic graph") do
- one.to_graph
- end
- end
-end
-
-# $Id$
diff --git a/test/util/config.rb b/test/util/settings.rb
index f99ad54b4..62f34fda6 100755
--- a/test/util/config.rb
+++ b/test/util/settings.rb
@@ -4,14 +4,14 @@ $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/
require 'mocha'
require 'puppettest'
-require 'puppet/util/config'
+require 'puppet/util/settings'
require 'puppettest/parsertesting'
-class TestConfig < Test::Unit::TestCase
+class TestSettings < Test::Unit::TestCase
include PuppetTest
include PuppetTest::ParserTesting
- CElement = Puppet::Util::Config::CElement
- CBoolean = Puppet::Util::Config::CBoolean
+ CElement = Puppet::Util::Settings::CElement
+ CBoolean = Puppet::Util::Settings::CBoolean
def setup
super
@@ -59,57 +59,6 @@ class TestConfig < Test::Unit::TestCase
}
end
- # #795 - when --config=relative, we want to fully expand file paths.
- def test_relative_paths_when_to_transportable
- config = mkconfig
- config.setdefaults :yay, :transtest => ["/what/ever", "yo"]
- file = config.element(:transtest)
-
- # Now override it with a relative path name
- config[:transtest] = "here"
-
- should = File.join(Dir.getwd, "here")
-
- object = file.to_transportable[0]
- assert_equal(should, object.name, "Did not translate relative pathnames to full path names")
- end
-
- def test_to_manifest
- set_configs
- manifest = nil
- assert_nothing_raised("Could not convert to a manifest") {
- manifest = @config.to_manifest
- }
-
- Puppet[:parseonly] = true
-
- interp = nil
- assert_nothing_raised do
- interp = mkinterp :Code => manifest, :UseNodes => false
- end
-
- trans = nil
- node = Puppet::Node.new("node")
- assert_nothing_raised do
- trans = interp.compile(node)
- end
- assert_nothing_raised("Could not instantiate objects") {
- trans.extract.to_type
- }
- end
-
- def test_to_comp
- set_configs
- comp = nil
- assert_nothing_raised("Could not convert to a component") {
- comp = @config.to_component
- }
-
- assert_nothing_raised("Could not retrieve component") {
- comp.retrieve
- }
- end
-
def test_to_config
set_configs
@@ -146,7 +95,7 @@ class TestConfig < Test::Unit::TestCase
def mkconfig
c = nil
assert_nothing_raised {
- c = Puppet::Util::Config.new
+ c = Puppet::Util::Settings.new
}
return c
end
@@ -668,91 +617,6 @@ yay = /a/path
assert_equal("/my/file", @config[:b], "Values are not equal")
end
- def test_reuse
- c = mkconfig
-
- file = tempfile()
- section = "testing"
- assert_nothing_raised {
- @config.setdefaults(section,
- :myfile => {:default => file, :create => true, :desc => "yay"}
- )
- }
-
- assert_nothing_raised("Could not use a section") {
- @config.use(section)
- }
-
- assert(FileTest.exists?(file), "Did not create file")
-
- assert(! Puppet::Type.type(:file)[file], "File obj still exists")
-
- File.unlink(file)
-
- @config.reuse
- assert(FileTest.exists?(file), "Did not create file")
- end
-
- def test_mkusers
- c = mkconfig
-
- file = tempfile()
- section = "testing"
- assert_nothing_raised {
- @config.setdefaults(section,
- :mkusers => [false, "yay"],
- :myfile => {
- :default => file,
- :owner => "pptest",
- :group => "pptest",
- :desc => "yay",
- :create => true
- }
- )
- }
-
- comp = nil
- assert_nothing_raised {
- comp = @config.to_component
- }
-
- [:user, :group].each do |type|
- # The objects might get created internally by Puppet::Util; just
- # make sure they're not being managed
- if obj = Puppet.type(type)["pptest"]
- assert(! obj.managed?, "%s objectis managed" % type)
- end
- end
- comp.each { |o| o.remove }
-
- @config[:mkusers] = true
-
- assert_nothing_raised {
- @config.to_component
- }
-
- user = Puppet.type(:user)["pptest"]
- assert(user, "User object did not get created")
- assert(user.managed?, "User object is not managed.")
- assert(user.should(:comment), "user does not have a comment set")
-
- group = Puppet.type(:group)["pptest"]
- assert(group, "Group object did not get created")
- assert(group.managed?,
- "Group object is not managed."
- )
-
- if Process.uid == 0
- cleanup do
- user[:ensure] = :absent
- group[:ensure] = :absent
- assert_apply(user, group)
- end
-
- assert_apply(user, group)
- end
- end
-
def test_notmanagingdev
c = mkconfig
path = "/dev/testing"
@@ -764,11 +628,9 @@ yay = /a/path
}
)
- assert_nothing_raised {
- @config.to_component
- }
+ config = @config.to_configuration
- assert(! Puppet.type(:file)["/dev/testing"], "Created dev file")
+ assert(! config.resource(:file, "/dev/testing"), "Created dev file")
end
def test_groupsetting
@@ -906,15 +768,15 @@ yay = /a/path
}
assert_equal("http://yayness/rahness", val,
- "Config got messed up")
+ "Settings got messed up")
end
def test_correct_type_assumptions
config = mkconfig
- file = Puppet::Util::Config::CFile
- element = Puppet::Util::Config::CElement
- bool = Puppet::Util::Config::CBoolean
+ file = Puppet::Util::Settings::CFile
+ element = Puppet::Util::Settings::CElement
+ bool = Puppet::Util::Settings::CBoolean
# We have to keep these ordered, unfortunately.
[
@@ -1119,12 +981,12 @@ yay = /a/path
# Now enable it so they'll be added
config[:mkusers] = true
- comp = config.to_component
+ comp = config.to_configuration
- Puppet::Type.type(:user).each do |u|
+ comp.vertices.find_all { |r| r.class.name == :user }.each do |u|
assert(u.name != "root", "Tried to manage root user")
end
- Puppet::Type.type(:group).each do |u|
+ comp.vertices.find_all { |r| r.class.name == :group }.each do |u|
assert(u.name != "root", "Tried to manage root group")
assert(u.name != "wheel", "Tried to manage wheel group")
end