summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-09-05 18:10:57 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-09-05 18:10:57 +0000
commitb303e8d3b7c31ebccabb0b3238104f5f019c5b6a (patch)
tree149d9eaa498d97456756605711cb62c5e24fec2d
parentb36df181f4f2064b3dbbce861912262594044b14 (diff)
downloadpuppet-b303e8d3b7c31ebccabb0b3238104f5f019c5b6a.tar.gz
puppet-b303e8d3b7c31ebccabb0b3238104f5f019c5b6a.tar.xz
puppet-b303e8d3b7c31ebccabb0b3238104f5f019c5b6a.zip
Adding the ability to download facts from the central server. This allows facts to be available before the configuration is compiled.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1561 980ebf18-57e1-0310-9a29-db15c13687c0
-rw-r--r--lib/puppet/client/master.rb137
-rw-r--r--test/client/master.rb82
2 files changed, 184 insertions, 35 deletions
diff --git a/lib/puppet/client/master.rb b/lib/puppet/client/master.rb
index 906f8be3c..ba6e7ec84 100644
--- a/lib/puppet/client/master.rb
+++ b/lib/puppet/client/master.rb
@@ -28,6 +28,7 @@ class Puppet::Client::MasterClient < Puppet::Client
]
)
+ # Plugin information.
Puppet.setdefaults("puppet",
:pluginpath => ["$vardir/plugins",
"Where Puppet should look for plugins. Multiple directories should
@@ -42,7 +43,25 @@ class Puppet::Client::MasterClient < Puppet::Client
:pluginsync => [false,
"Whether plugins should be synced with the central server."],
:pluginsignore => [".svn CVS",
- "What files to ignore when pulling down plugins.."]
+ "What files to ignore when pulling down plugins."]
+ )
+
+ # Central fact information.
+ Puppet.setdefaults("puppet",
+ :factpath => ["$vardir/facts",
+ "Where Puppet should look for facts. Multiple directories should
+ be colon-separated, like normal PATH variables."],
+ :factdest => ["$vardir/facts",
+ "Where Puppet should store facts that it pulls down from the central
+ server."],
+ :factsource => ["puppet://$server/facts",
+ "From where to retrieve facts. The standard Puppet ``file`` type
+ is used for retrieval, so anything that is a valid file source can
+ be used here."],
+ :factsync => [false,
+ "Whether facts should be synced with the central server."],
+ :factsignore => [".svn CVS",
+ "What files to ignore when pulling down facts."]
)
@drivername = :Master
@@ -57,6 +76,11 @@ class Puppet::Client::MasterClient < Puppet::Client
end
def self.facts
+ # Retrieve the facts from the central server.
+ if Puppet[:factsync]
+ self.class.getfacts()
+ end
+
facts = {}
Facter.each { |name,fact|
facts[name] = fact.to_s.downcase
@@ -218,6 +242,11 @@ class Puppet::Client::MasterClient < Puppet::Client
Puppet.debug("getting config")
dostorage()
+ # Retrieve the plugins.
+ if Puppet[:pluginsync]
+ self.class.getplugins()
+ end
+
facts = self.class.facts
unless facts.length > 0
@@ -226,11 +255,6 @@ class Puppet::Client::MasterClient < Puppet::Client
)
end
- # Retrieve the plugins.
- if Puppet[:pluginsync]
- getplugins()
- end
-
objects = nil
if @local
# If we're local, we don't have to do any of the conversion
@@ -471,50 +495,109 @@ class Puppet::Client::MasterClient < Puppet::Client
end
private
- # Retrieve the plugins from the central server.
- def getplugins
- plugins = Puppet::Type.type(:component).create(
- :name => "plugin_collector"
+
+ def self.download(args)
+ objects = Puppet::Type.type(:component).create(
+ :name => "#{args[:name]}_collector"
)
- plugins.push Puppet::Type.type(:file).create(
- :path => Puppet[:plugindest],
+ hash = {
+ :path => args[:dest],
:recurse => true,
- :source => Puppet[:pluginsource],
- :ignore => Puppet[:pluginsignore].split(/\s+/),
- :tag => "plugins",
+ :source => args[:source],
+ :tag => "#{args[:name]}s",
:owner => "root"
- )
+ }
- Puppet.info "Retrieving plugins"
+ if args[:ignore]
+ hash[:ignore] = args[:ignore].split(/\s+/)
+ end
+ objects.push Puppet::Type.type(:file).create(hash)
+ Puppet.info "Retrieving #{args[:name]}s"
begin
- trans = plugins.evaluate
+ trans = objects.evaluate
trans.evaluate
rescue Puppet::Error => detail
if Puppet[:debug]
puts detail.backtrace
end
- Puppet.err "Could not retrieve plugins: %s" % detail
+ 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.
- trans.changed?.find_all { |object|
- File.dirname(object[:path]) == Puppet[:pluginpath]
- }.each do |object|
+ trans.changed?.find_all do |object|
+ yield object
+ end
+
+ # Now clean up after ourselves
+ objects.remove
+ end
+
+ # Retrieve facts from the central server.
+ def self.getfacts
+ # First clear all existing definitions.
+ Facter.clear
+
+ path = Puppet[:factpath].split(":")
+ download(:dest => Puppet[:factdest], :source => Puppet[:factsource],
+ :ignore => Puppet[:factsignore], :name => "fact") do |object|
+
+ next unless path.include?(File.dirname(object[:path]))
+
begin
- Puppet.info "Loading plugin %s" %
- File.basename(object[:path]).sub(".rb",'')
+ Puppet.info "Loading fact %s" %
+ File.basename(File.basename(object[:path])).sub(".rb",'')
+ load object[:path]
+ rescue => detail
+ Puppet.warning "Could not reload fact %s: %s" %
+ [object[:path], detail]
+ end
+ end
+ ensure
+ Facter.loadfacts
+ end
+
+ # Retrieve the plugins from the central server. We only have to load the
+ # changed plugins, because Puppet::Type loads plugins on demand.
+ def self.getplugins
+ path = Puppet[:pluginpath].split(":")
+ download(:dest => Puppet[:plugindest], :source => Puppet[:pluginsource],
+ :ignore => Puppet[:pluginsignore], :name => "plugin") do |object|
+
+ next unless path.include?(File.dirname(object[:path]))
+
+ begin
+ Puppet.info "Reloading plugin %s" %
+ File.basename(File.basename(object[:path])).sub(".rb",'')
load object[:path]
rescue => detail
Puppet.warning "Could not reload plugin %s: %s" %
[object[:path], detail]
end
end
+ end
- # Now clean up after ourselves
- plugins.remove
+ def self.loaddir(dir, type)
+ return unless FileTest.directory?(dir)
+
+ Dir.entries(dir).find_all { |e| e =~ /\.rb$/ }.each do |file|
+ fqfile = File.join(dir, file)
+ begin
+ Puppet.info "Loading #{type} %s" %
+ File.basename(file.sub(".rb",''))
+ load fqfile
+ rescue => detail
+ Puppet.warning "Could not load #{type} %s: %s" % [fqfile, detail]
+ end
+ end
+ end
+
+ def self.loadfacts
+ Puppet[:factpath].split(":").each do |dir|
+ loaddir(dir, "fact")
+ end
end
def reportclient
@@ -526,6 +609,8 @@ class Puppet::Client::MasterClient < Puppet::Client
@reportclient
end
+
+ loadfacts()
end
# $Id$
diff --git a/test/client/master.rb b/test/client/master.rb
index 655b3fae6..2f88123b5 100644
--- a/test/client/master.rb
+++ b/test/client/master.rb
@@ -146,10 +146,8 @@ end
}
end
- client = mkclient()
-
assert_nothing_raised {
- client.send(:getplugins)
+ Puppet::Client::MasterClient.getplugins
}
destfile = File.join(Puppet[:plugindest], "myplugin.rb")
@@ -177,7 +175,7 @@ end
end
assert_nothing_raised {
- client.send(:getplugins)
+ Puppet::Client::MasterClient.getplugins
}
destfile = File.join(Puppet[:pluginpath], "myplugin.rb")
@@ -194,13 +192,79 @@ end
assert(! obj.validattr?(:argument),
"Old namevar is still valid")
+ end
- # Now make sure it works with multiple paths specified.
- newdir = tempfile()
- Dir.mkdir(newdir)
- Puppet[:pluginpath] = [Puppet[:pluginpath], newdir].join(":")
+ def test_getfacts
+ Puppet[:factsource] = tempfile()
+ Dir.mkdir(Puppet[:factsource])
- client.send(:getplugins)
+ myfact = File.join(Puppet[:factsource], "myfact.rb")
+ File.open(myfact, "w") do |f|
+ f.puts %{Facter.add("myfact") do
+ setcode { "yayness" }
+end
+}
+ end
+
+ assert_nothing_raised {
+ Puppet::Client::MasterClient.getfacts
+ }
+
+ destfile = File.join(Puppet[:factdest], "myfact.rb")
+
+ assert(File.exists?(destfile), "Did not get fact")
+
+ assert_equal("yayness", Facter["myfact"].value,
+ "Did not get correct fact value")
+
+ # Now modify the file and make sure the type is replaced
+ File.open(myfact, "w") do |f|
+ f.puts %{Facter.add("myfact") do
+ setcode { "funtest" }
+end
+}
+ end
+
+ assert_nothing_raised {
+ Puppet::Client::MasterClient.getfacts
+ }
+
+ assert_equal("funtest", Facter["myfact"].value,
+ "Did not reload fact")
+ end
+
+ # Make sure we load all facts on startup.
+ def test_loadfacts
+ dirs = [tempfile(), tempfile()]
+ count = 0
+ names = []
+ dirs.each do |dir|
+ Dir.mkdir(dir)
+ name = "fact%s" % count
+ names << name
+ file = File.join(dir, "%s.rb" % name)
+
+ # Write out a plugin file
+ File.open(file, "w") do |f|
+ f.puts %{Facter.add("#{name}") do setcode { "#{name}" } end }
+ end
+ count += 1
+ end
+
+ Puppet[:factpath] = dirs.join(":")
+
+ names.each do |name|
+ assert_nil(Facter.value(name), "Somehow retrieved invalid fact")
+ end
+
+ assert_nothing_raised {
+ Puppet::Client::MasterClient.loadfacts
+ }
+
+ names.each do |name|
+ assert_equal(name, Facter.value(name),
+ "Did not retrieve facts")
+ end
end
end