#!/usr/bin/env ruby # # = Synopsis # # Run a stand-alone +puppet+ manifest. # # = Usage # # puppet [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose] # [--detailed-exitcodes] [-l|--logdest ] # # = Description # # This is the standalone puppet execution tool; use it to execute # individual manifests that you write. If you need to execute site-wide # manifests, use +puppetd+ and +puppetmasterd+. # # = Options # # Note that any configuration parameter that's valid in the configuration file # is also a valid long argument. For example, 'ssldir' is a valid configuration # parameter, so you can specify '--ssldir ' as an argument. # # See the configuration file documentation at # http://reductivelabs.com/projects/puppet/reference/configref.html for # the full list of acceptable parameters. A commented list of all # configuration options can also be generated by running puppet with # '--genconfig'. # # debug:: # Enable full debugging. # # detailed-exitcodes:: # Provide transaction information via exit codes. If this is enabled, an exit # code of '2' means there were changes, and an exit code of '4' means that there # were failures during the transaction. # # help:: # Print this help message # # loadclasses:: # Load any stored classes. +puppetd+ caches configured classes (usually at # /etc/puppet/classes.txt), and setting this option causes all of those classes # to be set in your +puppet+ manifest. # # logdest:: # Where to send messages. Choose between syslog, the console, and a log file. # Defaults to sending messages to the console. # # verbose:: # Print extra information. # # = Example # # puppet -l /tmp/manifest.log manifest.pp # # = Author # # Luke Kanies # # = Copyright # # Copyright (c) 2005 Reductive Labs, LLC # Licensed under the GNU Public License require 'puppet' require 'puppet/network/handler' require 'puppet/network/client' require 'getoptlong' options = [ [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ], [ "--logdest", "-l", GetoptLong::REQUIRED_ARGUMENT ], [ "--execute", "-e", GetoptLong::REQUIRED_ARGUMENT ], [ "--loadclasses", "-L", GetoptLong::NO_ARGUMENT ], [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], [ "--use-nodes", GetoptLong::NO_ARGUMENT ], [ "--detailed-exitcodes", GetoptLong::NO_ARGUMENT ], [ "--version", "-V", GetoptLong::NO_ARGUMENT ] ] # Add all of the config parameters as valid options. Puppet.settings.addargs(options) result = GetoptLong.new(*options) options = { :debug => false, :verbose => false, :noop => false, :logfile => false, :loadclasses => false, :logset => false, :code => nil, :detailed_exits => false, } master = { :Local => true } begin result.each { |opt,arg| case opt when "--version" puts "%s" % Puppet.version exit when "--help" if Puppet.features.usage? RDoc::usage && exit else puts "No help available unless you have RDoc::usage installed" exit end when "--use-nodes" options[:UseNodes] = true when "--verbose" options[:verbose] = true when "--debug" options[:debug] = true when "--execute" options[:code] = arg when "--loadclasses" options[:loadclasses] = true when "--detailed-exitcodes" options[:detailed_exits] = true when "--logdest" begin Puppet::Util::Log.newdestination(arg) options[:logset] = true rescue => detail $stderr.puts detail.to_s end else Puppet.settings.handlearg(opt, arg) end } rescue GetoptLong::InvalidOption => detail $stderr.puts "Try '#{$0} --help'" exit(1) end Puppet.parse_config # Now parse the config if Puppet[:config] and File.exists? Puppet[:config] Puppet.settings.parse(Puppet[:config]) end if Puppet.settings.print_configs? exit(Puppet.settings.print_configs ? 0 : 1) end # If noop is set, then also enable diffs if Puppet[:noop] Puppet[:show_diff] = true end unless options[:logset] Puppet::Util::Log.newdestination(:console) end client = nil server = nil Puppet.settraps if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] Puppet::Util::Log.level = :info end # Set our code or file to use. if options[:code] or ARGV.length == 0 Puppet[:code] = options[:code] || STDIN.read else Puppet[:manifest] = ARGV.shift end if Puppet[:parseonly] begin Puppet::Parser::Interpreter.new.parser(Puppet[:environment]) rescue => detail Puppet.err detail exit 1 end exit 0 end # Collect our facts. facts = Puppet::Node::Facts.find(Puppet[:certname]) # Find our Node unless node = Puppet::Node.find(Puppet[:certname]) raise "Could not find node %s" % Puppet[:certname] end # Merge in the facts. node.merge(facts.values) # Allow users to load the classes that puppetd creates. if options[:loadclasses] file = Puppet[:classfile] if FileTest.exists?(file) unless FileTest.readable?(file) $stderr.puts "%s is not readable" % file exit(63) end node.classes = File.read(file).split(/[\s\n]+/) end end begin # Compile our catalog starttime = Time.now catalog = Puppet::Node::Catalog.find(node.name, :use_node => node) # Translate it to a RAL catalog catalog = catalog.to_ral catalog.host_config = true if Puppet[:graph] or Puppet[:report] catalog.finalize catalog.retrieval_duration = Time.now - starttime # And apply it transaction = catalog.apply status = 0 if not Puppet[:noop] and options[:detailed_exits] then transaction.generate_report status |= 2 if transaction.report.metrics["changes"][:total] > 0 status |= 4 if transaction.report.metrics["resources"][:failed] > 0 end exit(status) rescue => detail if Puppet[:trace] puts detail.backtrace end if detail.is_a?(XMLRPC::FaultException) $stderr.puts detail.message else $stderr.puts detail end exit(1) end