diff --git a/lib/puppet/network/handler/node.rb b/lib/puppet/network/handler/node.rb index f93087a2f..c6ccc2eb6 100644 --- a/lib/puppet/network/handler/node.rb +++ b/lib/puppet/network/handler/node.rb @@ -1,242 +1,242 @@ # 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. - autoload :node_source, 'puppet/node_source' + 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 8a82f5a58..81aee6a3c 100755 --- a/lib/puppet/network/handler/report.rb +++ b/lib/puppet/network/handler/report.rb @@ -1,145 +1,145 @@ require 'puppet/util/instance_loader' # A simple server for triggering a new run on a Puppet client. class Puppet::Network::Handler class Report < Handler desc "Accepts a Puppet transaction report and processes it." extend Puppet::Util::ClassGen extend Puppet::Util::InstanceLoader module ReportBase include Puppet::Util::Docs attr_writer :useyaml def useyaml? if defined? @useyaml @useyaml else false end end end @interface = XMLRPC::Service::Interface.new("puppetreports") { |iface| iface.add_method("string report(array)") } # Set up autoloading and retrieving of reports. - autoload :report, 'puppet/reports' + instance_load :report, 'puppet/reports' class << self attr_reader :hooks end # Add a new report type. def self.newreport(name, options = {}, &block) name = symbolize(name) mod = genmodule(name, :extend => ReportBase, :hash => instance_hash(:report), :block => block) if options[:useyaml] mod.useyaml = true end mod.send(:define_method, :report_name) do name end end # Collect the docs for all of our reports. def self.reportdocs docs = "" # Use this method so they all get loaded instance_loader(:report).loadall loaded_instances(:report).sort { |a,b| a.to_s <=> b.to_s }.each do |name| mod = self.report(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 reports. def self.reports instance_loader(:report).loadall loaded_instances(:report) end def initialize(*args) super Puppet.config.use(:reporting) Puppet.config.use(:metrics) end # Accept a report from a client. def report(report, client = nil, clientip = nil) # Unescape the report unless @local report = CGI.unescape(report) end Puppet.info "Processing reports %s for %s" % [reports().join(", "), client] begin process(report) rescue => detail Puppet.err "Could not process report for %s: %s" % [client, detail] if Puppet[:trace] puts detail.backtrace end end end private # Process the report using all of the existing hooks. def process(yaml) return if Puppet[:reports] == "none" # First convert the report to real objects begin report = YAML.load(yaml) rescue => detail Puppet.warning "Could not load report: %s" % detail return end # Used for those reports that accept yaml client = report.host reports().each do |name| if mod = self.class.report(name) # We have to use a dup because we're including a module in the # report. newrep = report.dup begin newrep.extend(mod) if mod.useyaml? newrep.process(yaml) else newrep.process end rescue => detail if Puppet[:trace] puts detail.backtrace end Puppet.err "Report %s failed: %s" % [name, detail] end else Puppet.warning "No report named '%s'" % name end end end # Handle the parsing of the reports attribute. def reports Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/) end end end # $Id$ diff --git a/lib/puppet/util/instance_loader.rb b/lib/puppet/util/instance_loader.rb index 3613b4e39..1a64c9c69 100755 --- a/lib/puppet/util/instance_loader.rb +++ b/lib/puppet/util/instance_loader.rb @@ -1,74 +1,74 @@ require 'puppet/util/autoload' require 'puppet/util' # A module that can easily autoload things for us. Uses an instance # of Puppet::Util::Autoload module Puppet::Util::InstanceLoader include Puppet::Util # Define a new type of autoloading. - def autoload(type, path, options = {}) + def instance_load(type, path, options = {}) @autoloaders ||= {} @instances ||= {} type = symbolize(type) @instances[type] = {} @autoloaders[type] = Puppet::Util::Autoload.new(self, path, options) # Now define our new simple methods unless respond_to?(type) meta_def(type) do |name| loaded_instance(type, name) end end end # Return a list of the names of all instances def loaded_instances(type) @instances[type].keys end # Collect the docs for all of our instances. def instance_docs(type) docs = "" # Use this method so they all get loaded loaded_instances(type).sort { |a,b| a.to_s <=> b.to_s }.each do |name| mod = self.loaded_instance(name) docs += "%s\n%s\n" % [name, "-" * name.to_s.length] docs += Puppet::Util::Docs.scrub(mod.doc) + "\n\n" end docs end # Return the instance hash for our type. def instance_hash(type) @instances[symbolize(type)] end # Return the Autoload object for a given type. def instance_loader(type) @autoloaders[symbolize(type)] end # Retrieve an alread-loaded instance, or attempt to load our instance. def loaded_instance(type, name) name = symbolize(name) instances = instance_hash(type) unless instances.include? name if instance_loader(type).load(name) unless instances.include? name Puppet.warning( "Loaded %s file for %s but %s was not defined" % [type, name, type] ) return nil end else return nil end end instances[name] end end # $Id$ diff --git a/lib/puppet/util/reference.rb b/lib/puppet/util/reference.rb index ce3d6550c..3446aeb06 100644 --- a/lib/puppet/util/reference.rb +++ b/lib/puppet/util/reference.rb @@ -1,189 +1,189 @@ require 'puppet/util/instance_loader' # Manage Reference Documentation. class Puppet::Util::Reference include Puppet::Util include Puppet::Util::Docs extend Puppet::Util::InstanceLoader - autoload(:reference, 'puppet/reference') + instance_load(:reference, 'puppet/reference') def self.footer "\n\n----------------\n\n*This page autogenerated on %s*\n" % Time.now end def self.modes %w{pdf trac text} end def self.newreference(name, options = {}, &block) ref = self.new(name, options, &block) instance_hash(:reference)[symbolize(name)] = ref ref end def self.page(*sections) depth = 4 # Use the minimum depth sections.each do |name| section = reference(name) or raise "Could not find section %s" % name depth = section.depth if section.depth < depth end text = ".. contents:: :depth: 2\n\n" end def self.pdf(text) puts "creating pdf" File.open("/tmp/puppetdoc.txt", "w") do |f| f.puts text end rst2latex = %x{which rst2latex} if $? != 0 or rst2latex =~ /no / rst2latex = %x{which rst2latex.py} end if $? != 0 or rst2latex =~ /no / raise "Could not find rst2latex" end rst2latex.chomp! cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex} output = %x{#{cmd}} unless $? == 0 $stderr.puts "rst2latex failed" $stderr.puts output exit(1) end $stderr.puts output # Now convert to pdf puts "handling pdf" Dir.chdir("/tmp") do %x{texi2pdf puppetdoc.tex >/dev/null 2>/dev/null} end #if FileTest.exists?("/tmp/puppetdoc.pdf") # FileUtils.mv("/tmp/puppetdoc.pdf", "/export/apache/docroots/reductivelabs.com/htdocs/downloads/puppet/reference.pdf") #end end def self.references instance_loader(:reference).loadall loaded_instances(:reference).sort { |a,b| a.to_s <=> b.to_s } end HEADER_LEVELS = [nil, "=", "-", "+", "'", "~"] attr_accessor :page, :depth, :header, :title, :dynamic attr_writer :doc def doc if defined?(@doc) return "%s - %s" % [@name, @doc] else return @title end end def dynamic? self.dynamic end def h(name, level) return "%s\n%s\n\n" % [name, HEADER_LEVELS[level] * name.to_s.length] end def initialize(name, options = {}, &block) @name = name options.each do |option, value| send(option.to_s + "=", value) end meta_def(:generate, &block) # Now handle the defaults @title ||= "%s Reference" % @name.to_s.capitalize @page ||= @title.gsub(/\s+/, '') @depth ||= 2 @header ||= "" end # Indent every line in the chunk except those which begin with '..'. def indent(text, tab) return text.gsub(/(^|\A)/, tab).gsub(/^ +\.\./, "..") end def option(name, value) ":%s: %s\n" % [name.to_s.capitalize, value] end def paramwrap(name, text, options = {}) options[:level] ||= 5 #str = "%s : " % name str = h(name, options[:level]) if options[:namevar] str += "- **namevar**\n\n" end str += text #str += text.gsub(/\n/, "\n ") str += "\n\n" return str end # Remove all trac links. def strip_trac(text) text.gsub(/`\w+\s+([^`]+)`:trac:/) { |m| $1 } end def text puts output end def to_rest(withcontents = true) # First the header text = h(@title, 1) text += "\n\n**This page is autogenerated; any changes will get overwritten**\n\n" if withcontents text += ".. contents:: :depth: %s\n\n" % @depth end text += @header text += generate() if withcontents text += self.class.footer end return text end def to_text(withcontents = true) strip_trac(to_rest(withcontents)) end def to_trac(with_contents = true) "{{{\n#!rst\n#{self.to_rest(with_contents)}\n}}}" end def trac File.open("/tmp/puppetdoc.txt", "w") do |f| f.puts self.to_trac end puts "Writing %s reference to trac as %s" % [@name, @page] cmd = %{sudo trac-admin /opt/rl/trac/puppet wiki import %s /tmp/puppetdoc.txt} % self.page output = %x{#{cmd}} unless $? == 0 $stderr.puts "trac-admin failed" $stderr.puts output exit(1) end unless output =~ /^\s+/ $stderr.puts output end end end # $Id$ diff --git a/test/util/instance_loader.rb b/test/util/instance_loader.rb index fa08d1bd6..24e8c9cab 100755 --- a/test/util/instance_loader.rb +++ b/test/util/instance_loader.rb @@ -1,53 +1,53 @@ #!/usr/bin/env ruby $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'puppet' require 'puppet/util/instance_loader' require 'puppettest' class TestInstanceloader < Test::Unit::TestCase include PuppetTest def setup super @loader = Class.new do extend Puppet::Util::InstanceLoader def self.newstuff(name, value) instance_hash(:stuff)[name] = value end end - assert_nothing_raised("Could not create autoloader") do - @loader.autoload(:stuff, "puppet/stuff") + assert_nothing_raised("Could not create instance loader") do + @loader.instance_load(:stuff, "puppet/stuff") end end # Make sure we correctly create our autoload instance. This covers the basics. def test_autoload # Make sure we can retrieve the loader - assert_instance_of(Puppet::Util::Autoload, @loader.instance_loader(:stuff), "Could not get autoloader") + assert_instance_of(Puppet::Util::Autoload, @loader.instance_loader(:stuff), "Could not get instance loader") # Make sure we can get the instance hash assert(@loader.instance_hash(:stuff), "Could not get instance hash") # Make sure it defines the instance retrieval method assert(@loader.respond_to?(:stuff), "Did not define instance retrieval method") end def test_loaded_instances assert_equal([], @loader.loaded_instances(:stuff), "Incorrect loaded instances") @loader.newstuff(:testing, "a value") assert_equal([:testing], @loader.loaded_instances(:stuff), "Incorrect loaded instances") assert_equal("a value", @loader.loaded_instance(:stuff, :testing), "Got incorrect loaded instance") end - def test_autoloading + def test_instance_loading end end # $Id$