diff --git a/lib/puppet/application.rb b/lib/puppet/application.rb index 49a146ffe..f72714b12 100644 --- a/lib/puppet/application.rb +++ b/lib/puppet/application.rb @@ -1,370 +1,371 @@ require 'puppet' require 'optparse' # This class handles all the aspects of a Puppet application/executable # * setting up options # * setting up logs # * choosing what to run # * representing execution status # # === Usage # An application is a subclass of Puppet::Application. # # For legacy compatibility, # Puppet::Application[:example].run # is equivalent to # Puppet::Application::Example.new.run # # # class Puppet::Application::Example << Puppet::Application # # def preinit # # perform some pre initialization # @all = false # end # # # run_command is called to actually run the specified command # def run_command # send Puppet::Util::CommandLine.args.shift # end # # # option uses metaprogramming to create a method # # and also tells the option parser how to invoke that method # option("--arg ARGUMENT") do |v| # @args << v # end # # option("--debug", "-d") do |v| # @debug = v # end # # option("--all", "-a:) do |v| # @all = v # end # # def handle_unknown(opt,arg) # # last chance to manage an option # ... # # let's say to the framework we finally handle this option # true # end # # def read # # read action # end # # def write # # writeaction # end # # end # # === Preinit # The preinit block is the first code to be called in your application, before option parsing, # setup or command execution. # # === Options # Puppet::Application uses +OptionParser+ to manage the application options. # Options are defined with the +option+ method to which are passed various # arguments, including the long option, the short option, a description... # Refer to +OptionParser+ documentation for the exact format. # * If the option method is given a block, this one will be called whenever # the option is encountered in the command-line argument. # * If the option method has no block, a default functionnality will be used, that # stores the argument (or true/false if the option doesn't require an argument) in # the global (to the application) options array. # * If a given option was not defined by a the +option+ method, but it exists as a Puppet settings: # * if +unknown+ was used with a block, it will be called with the option name and argument # * if +unknown+ wasn't used, then the option/argument is handed to Puppet.settings.handlearg for # a default behavior # # --help is managed directly by the Puppet::Application class, but can be overriden. # # === Setup # Applications can use the setup block to perform any initialization. # The defaul +setup+ behaviour is to: read Puppet configuration and manage log level and destination # # === What and how to run # If the +dispatch+ block is defined it is called. This block should return the name of the registered command # to be run. # If it doesn't exist, it defaults to execute the +main+ command if defined. # # === Execution state # The class attributes/methods of Puppet::Application serve as a global place to set and query the execution # status of the application: stopping, restarting, etc. The setting of the application status does not directly # aftect its running status; it's assumed that the various components within the application will consult these # settings appropriately and affect their own processing accordingly. Control operations (signal handlers and # the like) should set the status appropriately to indicate to the overall system that it's the process of # stopping or restarting (or just running as usual). # # So, if something in your application needs to stop the process, for some reason, you might consider: # # def stop_me! # # indicate that we're stopping # Puppet::Application.stop! # # ...do stuff... # end # # And, if you have some component that involves a long-running process, you might want to consider: # # def my_long_process(giant_list_to_munge) # giant_list_to_munge.collect do |member| # # bail if we're stopping # return if Puppet::Application.stop_requested? # process_member(member) # end # end class Puppet::Application include Puppet::Util BINDIRS = %w{sbin bin}.map{|dir| File.expand_path(File.dirname(__FILE__)) + "/../../#{dir}/*"}.join(" ") class << self include Puppet::Util attr_accessor :run_status def clear! self.run_status = nil end def stop! self.run_status = :stop_requested end def restart! self.run_status = :restart_requested end # Indicates that Puppet::Application.restart! has been invoked and components should # do what is necessary to facilitate a restart. def restart_requested? :restart_requested == run_status end # Indicates that Puppet::Application.stop! has been invoked and components should do what is necessary # for a clean stop. def stop_requested? :stop_requested == run_status end # Indicates that one of stop! or start! was invoked on Puppet::Application, and some kind of process # shutdown/short-circuit may be necessary. def interrupted? [:restart_requested, :stop_requested].include? run_status end # Indicates that Puppet::Application believes that it's in usual running mode (no stop/restart request # currently active). def clear? run_status.nil? end # Only executes the given block if the run status of Puppet::Application is clear (no restarts, stops, # etc. requested). # Upon block execution, checks the run status again; if a restart has been requested during the block's # execution, then controlled_run will send a new HUP signal to the current process. # Thus, long-running background processes can potentially finish their work before a restart. def controlled_run(&block) return unless clear? result = block.call Process.kill(:HUP, $$) if restart_requested? result end def should_parse_config @parse_config = true end def should_not_parse_config @parse_config = false end def should_parse_config? if ! defined? @parse_config @parse_config = true end return @parse_config end # used to declare code that handle an option def option(*options, &block) long = options.find { |opt| opt =~ /^--/ }.gsub(/^--(?:\[no-\])?([^ =]+).*$/, '\1' ).gsub('-','_') fname = symbolize("handle_#{long}") if (block_given?) define_method(fname, &block) else define_method(fname) do |value| self.options["#{long}".to_sym] = value end end @opt_parser_commands ||= [] @opt_parser_commands << [options, fname] end def banner(banner = nil) @banner = banner unless banner.nil? end def new_option_parser( target ) @banner ||= nil opt_parser = OptionParser.new(@banner) @opt_parser_commands ||= [] @opt_parser_commands.each do |options, fname| opt_parser.on(*options) do |value| target.send(fname, value) end end opt_parser end def find(name) self.const_get(name.to_s.capitalize) end def [](name) find(name).new end end - attr_reader :options, :opt_parser + attr_reader :options, :opt_parser, :command_line # Every app responds to --version option("--version", "-V") do |arg| puts "%s" % Puppet.version exit end # Every app responds to --help option("--help", "-h") do |v| help end def should_parse_config? self.class.should_parse_config? end # override to execute code before running anything else def preinit end - def initialize + def initialize(command_line = nil) + @command_line = command_line || Puppet::Util::CommandLine.new @opt_parser = self.class.new_option_parser( self ) @options = {} end # This is the main application entry point def run exit_on_fail("initialize") { preinit } exit_on_fail("parse options") { parse_options } exit_on_fail("parse configuration file") { Puppet.settings.parse } if should_parse_config? exit_on_fail("prepare for execution") { setup } exit_on_fail("run") { run_command } end def main raise NotImplementedError, "No valid command or main" end def run_command main end def setup # Handle the logging settings if options[:debug] or options[:verbose] Puppet::Util::Log.newdestination(:console) if options[:debug] Puppet::Util::Log.level = :debug else Puppet::Util::Log.level = :info end end unless options[:setdest] Puppet::Util::Log.newdestination(:syslog) end end def parse_options # get all puppet options optparse_opt = [] optparse_opt = Puppet.settings.optparse_addargs(optparse_opt) # convert them to OptionParser format optparse_opt.each do |option| @opt_parser.on(*option) do |arg| handlearg(option[0], arg) end end # scan command line argument begin @opt_parser.parse! rescue OptionParser::ParseError => detail $stderr.puts detail $stderr.puts "Try '#{$0} --help'" exit(1) end end def handlearg(opt, arg) # rewrite --[no-]option to --no-option if that's what was given if opt =~ /\[no-\]/ and !arg opt = opt.gsub(/\[no-\]/,'no-') end # otherwise remove the [no-] prefix to not confuse everybody opt = opt.gsub(/\[no-\]/, '') unless respond_to?(:handle_unknown) and send(:handle_unknown, opt, arg) # Puppet.settings.handlearg doesn't handle direct true/false :-) if arg.is_a?(FalseClass) arg = "false" elsif arg.is_a?(TrueClass) arg = "true" end Puppet.settings.handlearg(opt, arg) end end # this is used for testing def self.exit(code) exit(code) end def name self.class.to_s.sub(/.*::/,"").downcase.to_sym end def help if Puppet.features.usage? # RH:FIXME: My goodness, this is ugly. ::RDoc.const_set("PuppetSourceFile", name) def (::RDoc).caller docfile = `grep -l 'Puppet::Application\\[:#{::RDoc::PuppetSourceFile}\\]' #{BINDIRS}`.chomp super << "#{docfile}:0" end ::RDoc::usage && exit else puts "No help available unless you have RDoc::usage installed" exit end rescue Errno::ENOENT puts "No help available for puppet #{name}" exit end private def exit_on_fail(message, code = 1) begin yield rescue RuntimeError, NotImplementedError => detail puts detail.backtrace if Puppet[:trace] $stderr.puts "Could not %s: %s" % [message, detail] exit(code) end end end diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb index 88385f0a0..fde0c9b8d 100644 --- a/lib/puppet/application/apply.rb +++ b/lib/puppet/application/apply.rb @@ -1,183 +1,183 @@ require 'puppet' require 'puppet/application' require 'puppet/configurer' require 'puppet/network/handler' require 'puppet/network/client' class Puppet::Application::Apply < Puppet::Application should_parse_config option("--debug","-d") option("--execute EXECUTE","-e") do |arg| options[:code] = arg end option("--loadclasses","-L") option("--verbose","-v") option("--use-nodes") option("--detailed-exitcodes") option("--apply catalog", "-a catalog") do |arg| options[:catalog] = arg end option("--logdest LOGDEST", "-l") do |arg| begin Puppet::Util::Log.newdestination(arg) options[:logset] = true rescue => detail $stderr.puts detail.to_s end end def run_command if options[:catalog] apply elsif Puppet[:parseonly] parseonly else main end end def apply require 'puppet/configurer' if options[:catalog] == "-" text = $stdin.read else text = File.read(options[:catalog]) end begin catalog = Puppet::Resource::Catalog.convert_from(Puppet::Resource::Catalog.default_format,text) unless catalog.is_a?(Puppet::Resource::Catalog) catalog = Puppet::Resource::Catalog.pson_create(catalog) end rescue => detail raise Puppet::Error, "Could not deserialize catalog from pson: %s" % detail end catalog = catalog.to_ral configurer = Puppet::Configurer.new configurer.run :catalog => catalog end def parseonly # Set our code or file to use. - if options[:code] or Puppet::Util::CommandLine.args.length == 0 + if options[:code] or command_line.args.length == 0 Puppet[:code] = options[:code] || STDIN.read else - Puppet[:manifest] = Puppet::Util::CommandLine.args.shift + Puppet[:manifest] = command_line.args.shift end begin Puppet::Resource::TypeCollection.new(Puppet[:environment]).perform_initial_import rescue => detail Puppet.err detail exit 1 end exit 0 end def main # Set our code or file to use. - if options[:code] or Puppet::Util::CommandLine.args.length == 0 + if options[:code] or command_line.args.length == 0 Puppet[:code] = options[:code] || STDIN.read else - Puppet[:manifest] = Puppet::Util::CommandLine.args.shift + Puppet[:manifest] = command_line.args.shift end # Collect our facts. unless facts = Puppet::Node::Facts.find(Puppet[:certname]) raise "Could not find facts for %s" % Puppet[:certname] end # 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::Resource::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 configurer = Puppet::Configurer.new configurer.execute_prerun_command # And apply it transaction = catalog.apply configurer.execute_postrun_command status = 0 if not Puppet[:noop] and options[:detailed_exitcodes] then transaction.generate_report exit(transaction.report.exit_status) else exit(0) end rescue => detail puts detail.backtrace if Puppet[:trace] if detail.is_a?(XMLRPC::FaultException) $stderr.puts detail.message else $stderr.puts detail end exit(1) end end def setup 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 trap(:INT) do $stderr.puts "Exiting" exit(1) end if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] Puppet::Util::Log.level = :info end end end diff --git a/lib/puppet/application/cert.rb b/lib/puppet/application/cert.rb index 92da03ca7..a4ee5fef3 100644 --- a/lib/puppet/application/cert.rb +++ b/lib/puppet/application/cert.rb @@ -1,76 +1,76 @@ require 'puppet' require 'puppet/application' require 'puppet/ssl/certificate_authority' class Puppet::Application::Cert < Puppet::Application should_parse_config attr_accessor :mode, :all, :ca, :digest def find_mode(opt) modes = Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS tmp = opt.sub("--", '').to_sym @mode = modes.include?(tmp) ? tmp : nil end option("--clean", "-c") do @mode = :destroy end option("--all", "-a") do @all = true end option("--digest DIGEST") do |arg| @digest = arg end option("--debug", "-d") do |arg| Puppet::Util::Log.level = :debug end Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.reject {|m| m == :destroy }.each do |method| option("--#{method}", "-%s" % method.to_s[0,1] ) do find_mode("--#{method}") end end option("--verbose", "-v") do Puppet::Util::Log.level = :info end def main if @all hosts = :all else - hosts = Puppet::Util::CommandLine.args.collect { |h| puts h; h.downcase } + hosts = command_line.args.collect { |h| puts h; h.downcase } end begin @ca.apply(:revoke, :to => hosts) if @mode == :destroy @ca.apply(@mode, :to => hosts, :digest => @digest) rescue => detail puts detail.backtrace if Puppet[:trace] puts detail.to_s exit(24) end end def setup if Puppet.settings.print_configs? exit(Puppet.settings.print_configs ? 0 : 1) end Puppet::Util::Log.newdestination :console Puppet::SSL::Host.ca_location = :only begin @ca = Puppet::SSL::CertificateAuthority.new rescue => detail puts detail.backtrace if Puppet[:trace] puts detail.to_s exit(23) end end end diff --git a/lib/puppet/application/describe.rb b/lib/puppet/application/describe.rb index 45f017a48..ae33fb92a 100644 --- a/lib/puppet/application/describe.rb +++ b/lib/puppet/application/describe.rb @@ -1,215 +1,215 @@ require 'puppet' require 'puppet/application' class Formatter def initialize(width) @width = width end def wrap(txt, opts) return "" unless txt && !txt.empty? work = (opts[:scrub] ? scrub(txt) : txt) indent = (opts[:indent] ? opts[:indent] : 0) textLen = @width - indent patt = Regexp.new("^(.{0,#{textLen}})[ \n]") prefix = " " * indent res = [] while work.length > textLen if work =~ patt res << $1 work.slice!(0, $&.length) else res << work.slice!(0, textLen) end end res << work if work.length.nonzero? return prefix + res.join("\n" + prefix) end def header(txt, sep = "-") "\n#{txt}\n" + sep * txt.size end private def scrub(text) # For text with no carriage returns, there's nothing to do. if text !~ /\n/ return text end indent = nil # If we can match an indentation, then just remove that same level of # indent from every line. if text =~ /^(\s+)/ indent = $1 return text.gsub(/^#{indent}/,'') else return text end end end class TypeDoc def initialize @format = Formatter.new(76) @types = {} Puppet::Type.loadall Puppet::Type.eachtype { |type| next if type.name == :component @types[type.name] = type } end def list_types puts "These are the types known to puppet:\n" @types.keys.sort { |a, b| a.to_s <=> b.to_s }.each do |name| type = @types[name] s = type.doc.gsub(/\s+/, " ") n = s.index(".") if n.nil? s = ".. no documentation .." elsif n > 45 s = s[0, 45] + " ..." else s = s[0, n] end printf "%-15s - %s\n", name, s end end def format_type(name, opts) name = name.to_sym unless @types.has_key?(name) puts "Unknown type #{name}" return end type = @types[name] puts @format.header(name.to_s, "=") puts @format.wrap(type.doc, :indent => 0, :scrub => true) + "\n\n" puts @format.header("Parameters") if opts[:parameters] format_attrs(type, [:property, :param]) else list_attrs(type, [:property, :param]) end if opts[:meta] puts @format.header("Meta Parameters") if opts[:parameters] format_attrs(type, [:meta]) else list_attrs(type, [:meta]) end end if type.providers.size > 0 puts @format.header("Providers") if opts[:providers] format_providers(type) else list_providers(type) end end end # List details about attributes def format_attrs(type, attrs) docs = {} type.allattrs.each do |name| kind = type.attrtype(name) if attrs.include?(kind) && name != :provider docs[name] = type.attrclass(name).doc end end docs.sort { |a,b| a[0].to_s <=> b[0].to_s }.each { |name, doc| print "\n- **%s**" % name if type.namevar == name and name != :name puts " (*namevar*)" else puts "" end puts @format.wrap(doc, :indent => 4, :scrub => true) } end # List the names of attributes def list_attrs(type, attrs) params = [] type.allattrs.each do |name| kind = type.attrtype(name) if attrs.include?(kind) && name != :provider params << name.to_s end end puts @format.wrap(params.sort.join(", "), :indent => 4) end def format_providers(type) type.providers.sort { |a,b| a.to_s <=> b.to_s }.each { |prov| puts "\n- **%s**" % prov puts @format.wrap(type.provider(prov).doc, :indent => 4, :scrub => true) } end def list_providers(type) list = type.providers.sort { |a,b| a.to_s <=> b.to_s }.join(", ") puts @format.wrap(list, :indent => 4) end end class Puppet::Application::Describe < Puppet::Application banner "puppet describe [options] [type]" should_not_parse_config option("--short", "-s", "Only list parameters without detail") do |arg| options[:parameters] = false end option("--providers","-p") option("--list", "-l") option("--meta","-m") def preinit options[:parameters] = true end def main doc = TypeDoc.new if options[:list] doc.list_types else options[:types].each { |name| doc.format_type(name, options) } end end def setup - options[:types] = Puppet::Util::CommandLine.args.dup + options[:types] = command_line.args.dup unless options[:list] || options[:types].size > 0 handle_help(nil) end if options[:list] && options[:types].size > 0 $stderr.puts "Warning: ignoring types when listing all types" end end end diff --git a/lib/puppet/application/doc.rb b/lib/puppet/application/doc.rb index 295cd6771..74cde98bd 100644 --- a/lib/puppet/application/doc.rb +++ b/lib/puppet/application/doc.rb @@ -1,224 +1,224 @@ require 'puppet' require 'puppet/application' require 'puppet/util/reference' require 'puppet/network/handler' require 'puppet/util/rdoc' $tab = " " Reference = Puppet::Util::Reference class Puppet::Application::Doc < Puppet::Application should_not_parse_config attr_accessor :unknown_args, :manifest def preinit {:references => [], :mode => :text, :format => :to_rest }.each do |name,value| options[name] = value end @unknown_args = [] @manifest = false end option("--all","-a") option("--outputdir OUTPUTDIR","-o") option("--verbose","-v") option("--debug","-d") option("--format FORMAT", "-f") do |arg| method = "to_%s" % arg if Reference.method_defined?(method) options[:format] = method else raise "Invalid output format %s" % arg end end option("--mode MODE", "-m") do |arg| if Reference.modes.include?(arg) or arg.intern==:rdoc options[:mode] = arg.intern else raise "Invalid output mode %s" % arg end end option("--list", "-l") do |arg| puts Reference.references.collect { |r| Reference.reference(r).doc }.join("\n") exit(0) end option("--reference REFERENCE", "-r") do |arg| options[:references] << arg.intern end def handle_unknown( opt, arg ) @unknown_args << {:opt => opt, :arg => arg } true end def run_command return send(options[:mode]) if [:rdoc, :trac, :markdown].include?(options[:mode]) return other end def rdoc exit_code = 0 files = [] unless @manifest env = Puppet::Node::Environment.new files += env.modulepath files << File.dirname(env[:manifest]) end - files += Puppet::Util::CommandLine.args + files += command_line.args Puppet.info "scanning: %s" % files.inspect Puppet.settings.setdefaults("puppetdoc", "document_all" => [false, "Document all resources"] ) Puppet.settings[:document_all] = options[:all] || false begin if @manifest Puppet::Util::RDoc.manifestdoc(files) else options[:outputdir] = "doc" unless options[:outputdir] Puppet::Util::RDoc.rdoc(options[:outputdir], files) end rescue => detail if Puppet[:trace] puts detail.backtrace end $stderr.puts "Could not generate documentation: %s" % detail exit_code = 1 end exit exit_code end def trac options[:references].each do |name| section = Puppet::Util::Reference.reference(name) or raise "Could not find section %s" % name unless options[:mode] == :pdf section.trac end end end def markdown text = "" with_contents = false exit_code = 0 options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name| raise "Could not find reference %s" % name unless section = Puppet::Util::Reference.reference(name) begin # Add the per-section text, but with no ToC text += section.send(options[:format], with_contents) text += Puppet::Util::Reference.footer text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 } Puppet::Util::Reference.markdown(name, text) text = "" rescue => detail puts detail.backtrace $stderr.puts "Could not generate reference %s: %s" % [name, detail] exit_code = 1 next end end exit exit_code end def other text = "" if options[:references].length > 1 with_contents = false else with_contents = true end exit_code = 0 options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name| raise "Could not find reference %s" % name unless section = Puppet::Util::Reference.reference(name) begin # Add the per-section text, but with no ToC text += section.send(options[:format], with_contents) rescue => detail puts detail.backtrace $stderr.puts "Could not generate reference %s: %s" % [name, detail] exit_code = 1 next end end unless with_contents # We've only got one reference text += Puppet::Util::Reference.footer end # Replace the trac links, since they're invalid everywhere else text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 } if options[:mode] == :pdf Puppet::Util::Reference.pdf(text) else puts text end exit exit_code end def setup # sole manifest documentation - if Puppet::Util::CommandLine.args.size > 0 + if command_line.args.size > 0 options[:mode] = :rdoc @manifest = true end if options[:mode] == :rdoc setup_rdoc else setup_reference end end def setup_reference if options[:all] # Don't add dynamic references to the "all" list. options[:references] = Reference.references.reject do |ref| Reference.reference(ref).dynamic? end end if options[:references].empty? options[:references] << :type end end def setup_rdoc(dummy_argument=:work_arround_for_ruby_GC_bug) # consume the unknown options # and feed them as settings if @unknown_args.size > 0 @unknown_args.each do |option| # force absolute path for modulepath when passed on commandline if option[:opt]=="--modulepath" or option[:opt] == "--manifestdir" option[:arg] = option[:arg].split(':').collect { |p| File.expand_path(p) }.join(':') end Puppet.settings.handlearg(option[:opt], option[:arg]) end end # hack to get access to puppetmasterd modulepath and manifestdir Puppet[:name] = "puppetmasterd" # Now parse the config Puppet.parse_config # Handle the logging settings. if options[:debug] or options[:verbose] if options[:debug] Puppet::Util::Log.level = :debug else Puppet::Util::Log.level = :info end Puppet::Util::Log.newdestination(:console) end end end diff --git a/lib/puppet/application/filebucket.rb b/lib/puppet/application/filebucket.rb index ddc46e394..8e930f5e4 100644 --- a/lib/puppet/application/filebucket.rb +++ b/lib/puppet/application/filebucket.rb @@ -1,92 +1,92 @@ require 'puppet' require 'puppet/application' require 'puppet/file_bucket/dipper' class Puppet::Application::Filebucket < Puppet::Application should_not_parse_config option("--bucket BUCKET","-b") option("--debug","-d") option("--local","-l") option("--remote","-r") option("--verbose","-v") attr :args def run_command - @args = Puppet::Util::CommandLine.args + @args = command_line.args command = args.shift return send(command) if %w[get backup restore].include? command help end def get md5 = args.shift out = @client.getfile(md5) print out end def backup args.each do |file| unless FileTest.exists?(file) $stderr.puts "%s: no such file" % file next end unless FileTest.readable?(file) $stderr.puts "%s: cannot read file" % file next end md5 = @client.backup(file) puts "%s: %s" % [file, md5] end end def restore file = args.shift md5 = args.shift @client.restore(file, md5) end def setup Puppet::Log.newdestination(:console) @client = nil @server = nil trap(:INT) do $stderr.puts "Cancelling" exit(1) end if options[:debug] Puppet::Log.level = :debug elsif options[:verbose] Puppet::Log.level = :info end # Now parse the config Puppet.parse_config if Puppet.settings.print_configs? exit(Puppet.settings.print_configs ? 0 : 1) end begin if options[:local] or options[:bucket] path = options[:bucket] || Puppet[:bucketdir] @client = Puppet::FileBucket::Dipper.new(:Path => path) else @client = Puppet::FileBucket::Dipper.new(:Server => Puppet[:server]) end rescue => detail $stderr.puts detail if Puppet[:trace] puts detail.backtrace end exit(1) end end end diff --git a/lib/puppet/application/resource.rb b/lib/puppet/application/resource.rb index 52320e7a1..6a8c4e47c 100644 --- a/lib/puppet/application/resource.rb +++ b/lib/puppet/application/resource.rb @@ -1,124 +1,124 @@ require 'puppet' require 'puppet/application' require 'facter' class Puppet::Application::Resource < Puppet::Application should_not_parse_config attr_accessor :host, :extra_params def preinit @extra_params = [] @host = nil Facter.loadfacts end option("--debug","-d") option("--verbose","-v") option("--edit","-e") option("--host HOST","-H") do |arg| @host = arg end option("--types", "-t") do |arg| types = [] Puppet::Type.loadall Puppet::Type.eachtype do |t| next if t.name == :component types << t.name.to_s end puts types.sort exit end option("--param PARAM", "-p") do |arg| @extra_params << arg.to_sym end def main - args = Puppet::Util::CommandLine.args + args = command_line.args type = args.shift or raise "You must specify the type to display" typeobj = Puppet::Type.type(type) or raise "Could not find type #{type}" name = args.shift params = {} args.each do |setting| if setting =~ /^(\w+)=(.+)$/ params[$1] = $2 else raise "Invalid parameter setting %s" % setting end end if options[:edit] and @host raise "You cannot edit a remote host" end properties = typeobj.properties.collect { |s| s.name } format = proc {|trans| trans.dup.collect do |param, value| if value.nil? or value.to_s.empty? trans.delete(param) elsif value.to_s == "absent" and param.to_s != "ensure" trans.delete(param) end unless properties.include?(param) or @extra_params.include?(param) trans.delete(param) end end trans.to_manifest } if @host Puppet::Resource.indirection.terminus_class = :rest port = Puppet[:puppetport] key = ["https://#{host}:#{port}", "production", "resources", type, name].join('/') else key = [type, name].join('/') end text = if name if params.empty? [ Puppet::Resource.find( key ) ] else [ Puppet::Resource.new( type, name, params ).save( key ) ] end else Puppet::Resource.search( key, {} ) end.map(&format).join("\n") if options[:edit] file = "/tmp/x2puppet-#{Process.pid}.pp" begin File.open(file, "w") do |f| f.puts text end ENV["EDITOR"] ||= "vi" system(ENV["EDITOR"], file) system("puppet -v " + file) ensure #if FileTest.exists? file # File.unlink(file) #end end else puts text end end def setup Puppet::Util::Log.newdestination(:console) # Now parse the config Puppet.parse_config if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] Puppet::Util::Log.level = :info end end end diff --git a/lib/puppet/util/command_line.rb b/lib/puppet/util/command_line.rb index 6e67fd706..e6656985f 100644 --- a/lib/puppet/util/command_line.rb +++ b/lib/puppet/util/command_line.rb @@ -1,89 +1,89 @@ module Puppet module Util class CommandLine def self.subcommand_name(*args) subcommand_name, args = subcommand_and_args(*args) return subcommand_name end def self.args(*args) subcommand_name, args = subcommand_and_args(*args) return args end LegacyName = Hash.new{|h,k| k}.update({ 'agent' => 'puppetd', 'cert' => 'puppetca', 'doc' => 'puppetdoc', 'filebucket' => 'filebucket', 'apply' => 'puppet', 'describe' => 'pi', 'queue' => 'puppetqd', 'resource' => 'ralsh', 'kick' => 'puppetrun', 'master' => 'puppetmasterd', }) def self.legacy_executable_name(*args) LegacyName[ subcommand_name(*args) ] end def self.subcommand_and_args( zero = $0, argv = ARGV, stdin = STDIN ) zero = zero.gsub(/.*#{File::SEPARATOR}/,'').sub(/\.rb$/, '') if zero == 'puppet' case argv.first when nil; [ stdin.tty? ? nil : "apply", argv] # ttys get usage info when "--help"; [nil, argv] # help should give you usage, not the help for `puppet apply` when /^-|\.pp$|\.rb$/; ["apply", argv] else [ argv.first, argv[1..-1] ] end else [ zero, argv ] end end def self.appdir File.join('puppet', 'application') end def self.available_subcommands appdir = File.join('puppet', 'application') absolute_appdir = $:.collect { |x| File.join(x,'puppet','application') }.detect{ |x| File.directory?(x) } Dir[File.join(absolute_appdir, '*.rb')].map{|fn| File.basename(fn, '.rb')} end def self.usage_message usage = "Usage: puppet command " available = "Available commands are: #{available_subcommands.sort.join(', ')}" [usage, available].join("\n") end def initialize( zero = $0, argv = ARGV, stdin = STDIN ) @zero = zero @argv = argv.dup @stdin = stdin @subcommand_name, @args = self.class.subcommand_and_args( @zero, @argv, @stdin ) end attr :subcommand_name attr :args def execute if subcommand_name.nil? puts self.class.usage_message elsif self.class.available_subcommands.include?(subcommand_name) #subcommand require File.join(self.class.appdir, subcommand_name) - Puppet::Application[subcommand_name].run + Puppet::Application.find(subcommand_name).new(self).run else abort "Error: Unknown command #{subcommand_name}.\n#{usage_message}" end end def legacy_executable_name LegacyName[ subcommand_name ] end end end end diff --git a/spec/unit/application/apply.rb b/spec/unit/application/apply.rb index 10202e196..a1a7e7b31 100755 --- a/spec/unit/application/apply.rb +++ b/spec/unit/application/apply.rb @@ -1,387 +1,387 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/apply' describe Puppet::Application::Apply do before :each do @apply = Puppet::Application[:apply] Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) end [:debug,:loadclasses,:verbose,:use_nodes,:detailed_exitcodes].each do |option| it "should declare handle_#{option} method" do @apply.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @apply.options.expects(:[]=).with(option, 'arg') @apply.send("handle_#{option}".to_sym, 'arg') end end it "should set the code to the provided code when :execute is used" do @apply.options.expects(:[]=).with(:code, 'arg') @apply.send("handle_execute".to_sym, 'arg') end it "should ask Puppet::Application to parse Puppet configuration file" do @apply.should_parse_config?.should be_true end describe "when applying options" do it "should set the log destination with --logdest" do Puppet::Log.expects(:newdestination).with("console") @apply.handle_logdest("console") end it "should put the logset options to true" do @apply.options.expects(:[]=).with(:logset,true) @apply.handle_logdest("console") end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet.stubs(:trap) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) require 'lib/puppet/file_bucket/dipper' Puppet::FileBucket::Dipper.stubs(:new) STDIN.stubs(:read) @apply.options.stubs(:[]).with(any_parameters) end it "should set show_diff on --noop" do Puppet.stubs(:[]=) Puppet.stubs(:[]).with(:config) Puppet.stubs(:[]).with(:noop).returns(true) Puppet.expects(:[]=).with(:show_diff, true) @apply.setup end it "should set console as the log destination if logdest option wasn't provided" do Puppet::Log.expects(:newdestination).with(:console) @apply.setup end it "should set INT trap" do @apply.expects(:trap).with(:INT) @apply.setup end it "should set log level to debug if --debug was passed" do @apply.options.stubs(:[]).with(:debug).returns(true) Puppet::Log.expects(:level=).with(:debug) @apply.setup end it "should set log level to info if --verbose was passed" do @apply.options.stubs(:[]).with(:verbose).returns(true) Puppet::Log.expects(:level=).with(:info) @apply.setup end it "should print puppet config if asked to in Puppet config" do @apply.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) Puppet.settings.expects(:print_configs) @apply.setup end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) lambda { @apply.setup }.should raise_error(SystemExit) end end describe "when executing" do it "should dispatch to parseonly if parseonly is set" do @apply.stubs(:options).returns({}) Puppet.stubs(:[]).with(:parseonly).returns(true) @apply.expects(:parseonly) @apply.run_command end it "should dispatch to 'apply' if it was called with 'apply'" do @apply.options[:catalog] = "foo" @apply.expects(:apply) @apply.run_command end it "should dispatch to main if parseonly is not set" do @apply.stubs(:options).returns({}) Puppet.stubs(:[]).with(:parseonly).returns(false) @apply.expects(:main) @apply.run_command end describe "the parseonly command" do before :each do Puppet.stubs(:[]).with(:environment) Puppet.stubs(:[]).with(:manifest).returns("site.pp") Puppet.stubs(:err) @apply.stubs(:exit) @apply.options.stubs(:[]).with(:code).returns "some code" @collection = stub_everything Puppet::Resource::TypeCollection.stubs(:new).returns(@collection) end it "should use a Puppet Resource Type Collection to parse the file" do @collection.expects(:perform_initial_import) @apply.parseonly end it "should exit with exit code 0 if no error" do @apply.expects(:exit).with(0) @apply.parseonly end it "should exit with exit code 1 if error" do @collection.stubs(:perform_initial_import).raises(Puppet::ParseError) @apply.expects(:exit).with(1) @apply.parseonly end end describe "the main command" do before :each do Puppet.stubs(:[]) Puppet.settings.stubs(:use) Puppet.stubs(:[]).with(:prerun_command).returns "" Puppet.stubs(:[]).with(:postrun_command).returns "" Puppet.stubs(:[]).with(:trace).returns(true) @apply.options.stubs(:[]) @facts = stub_everything 'facts' Puppet::Node::Facts.stubs(:find).returns(@facts) @node = stub_everything 'node' Puppet::Node.stubs(:find).returns(@node) @catalog = stub_everything 'catalog' @catalog.stubs(:to_ral).returns(@catalog) Puppet::Resource::Catalog.stubs(:find).returns(@catalog) STDIN.stubs(:read) @transaction = stub_everything 'transaction' @catalog.stubs(:apply).returns(@transaction) @apply.stubs(:exit) end it "should set the code to run from --code" do @apply.options.stubs(:[]).with(:code).returns("code to run") Puppet.expects(:[]=).with(:code,"code to run") @apply.main end it "should set the code to run from STDIN if no arguments" do - Puppet::Util::CommandLine.stubs(:args).returns([]) + @apply.command_line.stubs(:args).returns([]) STDIN.stubs(:read).returns("code to run") Puppet.expects(:[]=).with(:code,"code to run") @apply.main end it "should set the manifest if some files are passed on command line" do - Puppet::Util::CommandLine.stubs(:args).returns(['site.pp']) + @apply.command_line.stubs(:args).returns(['site.pp']) Puppet.expects(:[]=).with(:manifest,"site.pp") @apply.main end it "should collect the node facts" do Puppet::Node::Facts.expects(:find).returns(@facts) @apply.main end it "should raise an error if we can't find the node" do Puppet::Node::Facts.expects(:find).returns(nil) lambda { @apply.main }.should raise_error end it "should find the node" do Puppet::Node.expects(:find).returns(@node) @apply.main end it "should raise an error if we can't find the node" do Puppet::Node.expects(:find).returns(nil) lambda { @apply.main }.should raise_error end it "should merge in our node the loaded facts" do @facts.stubs(:values).returns("values") @node.expects(:merge).with("values") @apply.main end it "should load custom classes if loadclasses" do @apply.options.stubs(:[]).with(:loadclasses).returns(true) Puppet.stubs(:[]).with(:classfile).returns("/etc/puppet/classes.txt") FileTest.stubs(:exists?).with("/etc/puppet/classes.txt").returns(true) FileTest.stubs(:readable?).with("/etc/puppet/classes.txt").returns(true) File.stubs(:read).with("/etc/puppet/classes.txt").returns("class") @node.expects(:classes=) @apply.main end it "should compile the catalog" do Puppet::Resource::Catalog.expects(:find).returns(@catalog) @apply.main end it "should transform the catalog to ral" do @catalog.expects(:to_ral).returns(@catalog) @apply.main end it "should finalize the catalog" do @catalog.expects(:finalize) @apply.main end it "should call the prerun and postrun commands on a Configurer instance" do configurer = stub 'configurer' Puppet::Configurer.expects(:new).returns configurer configurer.expects(:execute_prerun_command) configurer.expects(:execute_postrun_command) @apply.main end it "should apply the catalog" do @catalog.expects(:apply) @apply.main end describe "with detailed_exitcodes" do it "should exit with report's computed exit status" do Puppet.stubs(:[]).with(:noop).returns(false) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) report = stub 'report', :exit_status => 666 @transaction.stubs(:report).returns(report) @apply.expects(:exit).with(666) @apply.main end it "should always exit with 0 if option is disabled" do Puppet.stubs(:[]).with(:noop).returns(false) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(false) report = stub 'report', :exit_status => 666 @transaction.stubs(:report).returns(report) @apply.expects(:exit).with(0) @apply.main end it "should always exit with 0 if --noop" do Puppet.stubs(:[]).with(:noop).returns(true) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) report = stub 'report', :exit_status => 666 @transaction.stubs(:report).returns(report) @apply.expects(:exit).with(0) @apply.main end end end describe "the 'apply' command" do it "should read the catalog in from disk if a file name is provided" do @apply.options[:catalog] = "/my/catalog.pson" File.expects(:read).with("/my/catalog.pson").returns "something" Puppet::Resource::Catalog.stubs(:convert_from).with(:pson,'something').returns Puppet::Resource::Catalog.new @apply.apply end it "should read the catalog in from stdin if '-' is provided" do @apply.options[:catalog] = "-" $stdin.expects(:read).returns "something" Puppet::Resource::Catalog.stubs(:convert_from).with(:pson,'something').returns Puppet::Resource::Catalog.new @apply.apply end it "should deserialize the catalog from the default format" do @apply.options[:catalog] = "/my/catalog.pson" File.stubs(:read).with("/my/catalog.pson").returns "something" Puppet::Resource::Catalog.stubs(:default_format).returns :rot13_piglatin Puppet::Resource::Catalog.stubs(:convert_from).with(:rot13_piglatin,'something').returns Puppet::Resource::Catalog.new @apply.apply end it "should fail helpfully if deserializing fails" do @apply.options[:catalog] = "/my/catalog.pson" File.stubs(:read).with("/my/catalog.pson").returns "something syntacically invalid" lambda { @apply.apply }.should raise_error(Puppet::Error) end it "should convert plain data structures into a catalog if deserialization does not do so" do @apply.options[:catalog] = "/my/catalog.pson" File.stubs(:read).with("/my/catalog.pson").returns "something" Puppet::Resource::Catalog.stubs(:convert_from).with(:pson,"something").returns({:foo => "bar"}) Puppet::Resource::Catalog.expects(:pson_create).with({:foo => "bar"}).returns(Puppet::Resource::Catalog.new) @apply.apply end it "should convert the catalog to a RAL catalog and use a Configurer instance to apply it" do @apply.options[:catalog] = "/my/catalog.pson" File.stubs(:read).with("/my/catalog.pson").returns "something" catalog = Puppet::Resource::Catalog.new Puppet::Resource::Catalog.stubs(:convert_from).with(:pson,'something').returns catalog catalog.expects(:to_ral).returns "mycatalog" configurer = stub 'configurer' Puppet::Configurer.expects(:new).returns configurer configurer.expects(:run).with(:catalog => "mycatalog") @apply.apply end end end end diff --git a/spec/unit/application/cert.rb b/spec/unit/application/cert.rb index 3fb2f1ed4..5970355e8 100644 --- a/spec/unit/application/cert.rb +++ b/spec/unit/application/cert.rb @@ -1,167 +1,167 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/cert' describe Puppet::Application::Cert do before :each do @cert_app = Puppet::Application[:cert] Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) end it "should ask Puppet::Application to parse Puppet configuration file" do @cert_app.should_parse_config?.should be_true end it "should declare a main command" do @cert_app.should respond_to(:main) end Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.reject{ |m| m == :destroy }.each do |method| it "should declare option --#{method}" do @cert_app.should respond_to("handle_#{method}".to_sym) end end it "should set log level to info with the --verbose option" do Puppet::Log.expects(:level=).with(:info) @cert_app.handle_verbose(0) end it "should set log level to debug with the --debug option" do Puppet::Log.expects(:level=).with(:debug) @cert_app.handle_debug(0) end it "should set the fingerprint digest with the --digest option" do @cert_app.handle_digest(:digest) @cert_app.digest.should == :digest end it "should set mode to :destroy for --clean" do @cert_app.handle_clean(0) @cert_app.mode.should == :destroy end it "should set all to true for --all" do @cert_app.handle_all(0) @cert_app.all.should be_true end Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.reject { |m| m == :destroy }.each do |method| it "should set mode to #{method} with option --#{method}" do @cert_app.send("handle_#{method}".to_sym, nil) @cert_app.mode.should == method end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet::SSL::Host.stubs(:ca_location=) Puppet::SSL::CertificateAuthority.stubs(:new) end it "should set console as the log destination" do Puppet::Log.expects(:newdestination).with(:console) @cert_app.setup end it "should print puppet config if asked to in Puppet config" do @cert_app.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) Puppet.settings.expects(:print_configs) @cert_app.setup end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) lambda { @cert_app.setup }.should raise_error(SystemExit) end it "should set the CA location to 'only'" do Puppet::SSL::Host.expects(:ca_location=).with(:only) @cert_app.setup end it "should create a new certificate authority" do Puppet::SSL::CertificateAuthority.expects(:new) @cert_app.setup end end describe "when running" do before :each do @cert_app.all = false @ca = stub_everything 'ca' @cert_app.ca = @ca - Puppet::Util::CommandLine.stubs(:args).returns([]) + @cert_app.command_line.stubs(:args).returns([]) end it "should delegate to the CertificateAuthority" do @ca.expects(:apply) @cert_app.main end it "should delegate with :all if option --all was given" do @cert_app.handle_all(0) @ca.expects(:apply).with { |mode,to| to[:to] == :all } @cert_app.main end it "should delegate to ca.apply with the hosts given on command line" do - Puppet::Util::CommandLine.stubs(:args).returns(["host"]) + @cert_app.command_line.stubs(:args).returns(["host"]) @ca.expects(:apply).with { |mode,to| to[:to] == ["host"]} @cert_app.main end it "should send the currently set digest" do - Puppet::Util::CommandLine.stubs(:args).returns(["host"]) + @cert_app.command_line.stubs(:args).returns(["host"]) @cert_app.handle_digest(:digest) @ca.expects(:apply).with { |mode,to| to[:digest] == :digest} @cert_app.main end it "should delegate to ca.apply with current set mode" do @cert_app.mode = "currentmode" - Puppet::Util::CommandLine.stubs(:args).returns(["host"]) + @cert_app.command_line.stubs(:args).returns(["host"]) @ca.expects(:apply).with { |mode,to| mode == "currentmode" } @cert_app.main end it "should revoke cert if mode is clean" do @cert_app.mode = :destroy - Puppet::Util::CommandLine.stubs(:args).returns(["host"]) + @cert_app.command_line.stubs(:args).returns(["host"]) @ca.expects(:apply).with { |mode,to| mode == :revoke } @ca.expects(:apply).with { |mode,to| mode == :destroy } @cert_app.main end end end diff --git a/spec/unit/application/doc.rb b/spec/unit/application/doc.rb index 3bda25f2f..c1184925e 100755 --- a/spec/unit/application/doc.rb +++ b/spec/unit/application/doc.rb @@ -1,359 +1,359 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/doc' describe Puppet::Application::Doc do before :each do @doc = Puppet::Application[:doc] @doc.stubs(:puts) @doc.preinit Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) end it "should ask Puppet::Application to not parse Puppet configuration file" do @doc.should_parse_config?.should be_false end it "should declare a other command" do @doc.should respond_to(:other) end it "should declare a rdoc command" do @doc.should respond_to(:rdoc) end it "should declare a trac command" do @doc.should respond_to(:trac) end it "should declare a fallback for unknown options" do @doc.should respond_to(:handle_unknown) end it "should declare a preinit block" do @doc.should respond_to(:preinit) end describe "in preinit" do it "should set references to []" do @doc.preinit @doc.options[:references].should == [] end it "should init mode to text" do @doc.preinit @doc.options[:mode].should == :text end it "should init format to to_rest" do @doc.preinit @doc.options[:format].should == :to_rest end end describe "when handling options" do [:all, :outputdir, :verbose, :debug].each do |option| it "should declare handle_#{option} method" do @doc.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @doc.options.expects(:[]=).with(option, 'arg') @doc.send("handle_#{option}".to_sym, 'arg') end end it "should store the format if valid" do Puppet::Util::Reference.stubs(:method_defined?).with('to_format').returns(true) @doc.options.expects(:[]=).with(:format, 'to_format') @doc.handle_format('format') end it "should raise an error if the format is not valid" do Puppet::Util::Reference.stubs(:method_defined?).with('to_format').returns(false) lambda { @doc.handle_format('format') } end it "should store the mode if valid" do Puppet::Util::Reference.stubs(:modes).returns(stub('mode', :include? => true)) @doc.options.expects(:[]=).with(:mode, :mode) @doc.handle_mode('mode') end it "should store the mode if :rdoc" do Puppet::Util::Reference.modes.stubs(:include?).with('rdoc').returns(false) @doc.options.expects(:[]=).with(:mode, :rdoc) @doc.handle_mode('rdoc') end it "should raise an error if the mode is not valid" do Puppet::Util::Reference.modes.stubs(:include?).with('unknown').returns(false) lambda { @doc.handle_mode('unknown') } end it "should list all references on list and exit" do reference = stubs 'reference' ref = stubs 'ref' Puppet::Util::Reference.stubs(:references).returns([reference]) Puppet::Util::Reference.expects(:reference).with(reference).returns(ref) ref.expects(:doc) @doc.expects(:exit) @doc.handle_list(nil) end it "should add reference to references list with --reference" do @doc.options[:references] = [:ref1] @doc.handle_reference('ref2') @doc.options[:references].should == [:ref1,:ref2] end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) - Puppet::Util::CommandLine.stubs(:args).returns([]) + @doc.command_line.stubs(:args).returns([]) end it "should default to rdoc mode if there are command line arguments" do - Puppet::Util::CommandLine.stubs(:args).returns(["1"]) + @doc.command_line.stubs(:args).returns(["1"]) @doc.stubs(:setup_rdoc) @doc.options.expects(:[]=).with(:mode,:rdoc) @doc.setup end it "should call setup_rdoc in rdoc mode" do @doc.options.stubs(:[]).with(:mode).returns(:rdoc) @doc.expects(:setup_rdoc) @doc.setup end it "should call setup_reference if not rdoc" do @doc.options.stubs(:[]).with(:mode).returns(:test) @doc.expects(:setup_reference) @doc.setup end describe "in non-rdoc mode" do it "should get all non-dynamic reference if --all" do @doc.options.stubs(:[]).with(:all).returns(true) @doc.options.stubs(:[]).with(:references).returns([]) static = stub 'static', :dynamic? => false dynamic = stub 'dynamic', :dynamic? => true Reference.stubs(:reference).with(:static).returns(static) Reference.stubs(:reference).with(:dynamic).returns(dynamic) Reference.stubs(:references).returns([:static,:dynamic]) @doc.options.stubs(:[]=).with(:references, [:static]) @doc.setup_reference end it "should default to :type if no references" do @doc.options.stubs(:[]).with(:all).returns(false) array = stub 'array', :empty? => true @doc.options.stubs(:[]).with(:references).returns(array) array.expects(:<<).with(:type) @doc.setup_reference end end describe "in rdoc mode" do before :each do @doc.options.stubs(:[]).returns(false) Puppet.stubs(:[]=).with(:name, "puppetmasterd") Puppet.stubs(:parse_config) Puppet::Util::Log.stubs(:level=) Puppet::Util::Log.stubs(:newdestination) end describe "when there are unknown args" do it "should expand --modulepath if any" do @doc.unknown_args = [ { :opt => "--modulepath", :arg => "path" } ] Puppet.settings.stubs(:handlearg) File.expects(:expand_path).with("path") @doc.setup_rdoc end it "should expand --manifestdir if any" do @doc.unknown_args = [ { :opt => "--manifestdir", :arg => "path" } ] Puppet.settings.stubs(:handlearg) File.expects(:expand_path).with("path") @doc.setup_rdoc end it "should give them to Puppet.settings" do @doc.unknown_args = [ { :opt => :option, :arg => :argument } ] Puppet.settings.expects(:handlearg).with(:option,:argument) @doc.setup_rdoc end end it "should pretend to be puppetmasterd" do Puppet.expects(:[]=).with(:name, "puppetmasterd") @doc.setup_rdoc end it "should parse puppet configuration" do Puppet.expects(:parse_config) @doc.setup_rdoc end it "should set log level to debug if --debug" do @doc.options.stubs(:[]).with(:debug).returns(true) Puppet::Util::Log.expects(:level=).with(:debug) @doc.setup_rdoc end it "should set log level to info if --verbose" do @doc.options.stubs(:[]).with(:verbose).returns(true) Puppet::Util::Log.expects(:level=).with(:info) @doc.setup_rdoc end it "should set log destination to console if --verbose" do @doc.options.stubs(:[]).with(:verbose).returns(true) Puppet::Util::Log.expects(:newdestination).with(:console) @doc.setup_rdoc end it "should set log destination to console if --debug" do @doc.options.stubs(:[]).with(:debug).returns(true) Puppet::Util::Log.expects(:newdestination).with(:console) @doc.setup_rdoc end end end describe "when running" do before :each do end describe "in trac mode" do it "should call trac for each reference" do ref = stub 'ref' Puppet::Util::Reference.stubs(:reference).with(:ref).returns(ref) @doc.options.stubs(:[]).with(:references).returns([:ref]) @doc.options.stubs(:[]).with(:mode).returns(:trac) ref.expects(:trac) @doc.trac end end describe "in rdoc mode" do before :each do @doc.manifest = false Puppet.stubs(:info) Puppet.stubs(:[]).with(:trace).returns(false) @env = stub 'env' Puppet::Node::Environment.stubs(:new).returns(@env) @env.stubs(:modulepath).returns(['modules']) @env.stubs(:[]).with(:manifest).returns('manifests/site.pp') Puppet.stubs(:[]).with(:modulepath).returns('modules') Puppet.stubs(:[]).with(:manifestdir).returns('manifests') @doc.options.stubs(:[]).with(:all).returns(false) @doc.options.stubs(:[]).with(:outputdir).returns('doc') Puppet.settings.stubs(:[]=).with(:document_all, false) Puppet.settings.stubs(:setdefaults) Puppet::Util::RDoc.stubs(:rdoc) @doc.stubs(:exit) File.stubs(:expand_path).with('modules').returns('modules') File.stubs(:expand_path).with('manifests').returns('manifests') - Puppet::Util::CommandLine.stubs(:args).returns([]) + @doc.command_line.stubs(:args).returns([]) end it "should set document_all on --all" do @doc.options.expects(:[]).with(:all).returns(true) Puppet.settings.expects(:[]=).with(:document_all, true) @doc.rdoc end it "should call Puppet::Util::RDoc.rdoc in full mode" do Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests']) @doc.rdoc end it "should call Puppet::Util::RDoc.rdoc in full mode with outputdir set to doc if no --outputdir" do @doc.options.expects(:[]).with(:outputdir).returns(false) Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests']) @doc.rdoc end it "should call Puppet::Util::RDoc.manifestdoc in manifest mode" do @doc.manifest = true Puppet::Util::RDoc.expects(:manifestdoc) @doc.rdoc end it "should get modulepath and manifestdir values from the environment" do @env.expects(:modulepath).returns(['envmodules1','envmodules2']) @env.expects(:[]).with(:manifest).returns('envmanifests/site.pp') Puppet::Util::RDoc.expects(:rdoc).with('doc', ['envmodules1','envmodules2','envmanifests']) @doc.rdoc end end describe "in the other modes" do it "should get reference in given format" do reference = stub 'reference' @doc.options.stubs(:[]).with(:mode).returns(:none) @doc.options.stubs(:[]).with(:references).returns([:ref]) Puppet::Util::Reference.expects(:reference).with(:ref).returns(reference) @doc.options.stubs(:[]).with(:format).returns(:format) @doc.stubs(:exit) reference.expects(:send).with { |format,contents| format == :format }.returns('doc') @doc.other end end end end diff --git a/spec/unit/application/filebucket.rb b/spec/unit/application/filebucket.rb index 68af45c40..58c7f7c75 100644 --- a/spec/unit/application/filebucket.rb +++ b/spec/unit/application/filebucket.rb @@ -1,223 +1,223 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/filebucket' describe Puppet::Application::Filebucket do before :each do @filebucket = Puppet::Application[:filebucket] end it "should ask Puppet::Application to not parse Puppet configuration file" do @filebucket.should_parse_config?.should be_false end it "should declare a get command" do @filebucket.should respond_to(:get) end it "should declare a backup command" do @filebucket.should respond_to(:backup) end it "should declare a restore command" do @filebucket.should respond_to(:restore) end [:bucket, :debug, :local, :remote, :verbose].each do |option| it "should declare handle_#{option} method" do @filebucket.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @filebucket.options.expects(:[]=).with("#{option}".to_sym, 'arg') @filebucket.send("handle_#{option}".to_sym, 'arg') end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet.stubs(:settraps) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) Puppet::FileBucket::Dipper.stubs(:new) @filebucket.options.stubs(:[]).with(any_parameters) end it "should set console as the log destination" do Puppet::Log.expects(:newdestination).with(:console) @filebucket.setup end it "should trap INT" do @filebucket.expects(:trap).with(:INT) @filebucket.setup end it "should set log level to debug if --debug was passed" do @filebucket.options.stubs(:[]).with(:debug).returns(true) Puppet::Log.expects(:level=).with(:debug) @filebucket.setup end it "should set log level to info if --verbose was passed" do @filebucket.options.stubs(:[]).with(:verbose).returns(true) Puppet::Log.expects(:level=).with(:info) @filebucket.setup end it "should Parse puppet config" do Puppet.expects(:parse_config) @filebucket.setup end it "should print puppet config if asked to in Puppet config" do @filebucket.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) Puppet.settings.expects(:print_configs) @filebucket.setup end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) lambda { @filebucket.setup }.should raise_error(SystemExit) end describe "with local bucket" do before :each do @filebucket.options.stubs(:[]).with(:local).returns(true) end it "should create a client with the default bucket if none passed" do Puppet.stubs(:[]).with(:bucketdir).returns("path") Puppet::FileBucket::Dipper.expects(:new).with { |h| h[:Path] == "path" } @filebucket.setup end it "should create a local Dipper with the given bucket" do @filebucket.options.stubs(:[]).with(:bucket).returns("path") Puppet::FileBucket::Dipper.expects(:new).with { |h| h[:Path] == "path" } @filebucket.setup end end describe "with remote bucket" do it "should create a remote Client to the configured server" do Puppet.stubs(:[]).with(:server).returns("puppet.reductivelabs.com") Puppet::FileBucket::Dipper.expects(:new).with { |h| h[:Server] == "puppet.reductivelabs.com" } @filebucket.setup end end end describe "when running" do before :each do Puppet::Log.stubs(:newdestination) Puppet.stubs(:settraps) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) Puppet::FileBucket::Dipper.stubs(:new) @filebucket.options.stubs(:[]).with(any_parameters) @client = stub 'client' Puppet::FileBucket::Dipper.stubs(:new).returns(@client) @filebucket.setup end it "should use the first non-option parameter as the dispatch" do - Puppet::Util::CommandLine.stubs(:args).returns([:get]) + @filebucket.command_line.stubs(:args).returns(['get']) @filebucket.expects(:get) @filebucket.run_command end describe "the command get" do before :each do @filebucket.stubs(:print) @filebucket.stubs(:args).returns([]) end it "should call the client getfile method" do @client.expects(:getfile) @filebucket.get end it "should call the client getfile method with the given md5" do md5="DEADBEEF" @filebucket.stubs(:args).returns([md5]) @client.expects(:getfile).with(md5) @filebucket.get end it "should print the file content" do @client.stubs(:getfile).returns("content") @filebucket.expects(:print).returns("content") @filebucket.get end end describe "the command backup" do it "should call the client backup method for each given parameter" do @filebucket.stubs(:puts) FileTest.stubs(:exists?).returns(true) FileTest.stubs(:readable?).returns(true) @filebucket.stubs(:args).returns(["file1", "file2"]) @client.expects(:backup).with("file1") @client.expects(:backup).with("file2") @filebucket.backup end end describe "the command restore" do it "should call the client getfile method with the given md5" do md5="DEADBEEF" file="testfile" @filebucket.stubs(:args).returns([file, md5]) @client.expects(:restore).with(file,md5) @filebucket.restore end end end end diff --git a/spec/unit/application/resource.rb b/spec/unit/application/resource.rb index 2e90cc288..3487b2c3c 100755 --- a/spec/unit/application/resource.rb +++ b/spec/unit/application/resource.rb @@ -1,232 +1,233 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/resource' describe Puppet::Application::Resource do before :each do @resource = Puppet::Application[:resource] Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) Puppet::Resource.indirection.stubs(:terminus_class=) end it "should ask Puppet::Application to not parse Puppet configuration file" do @resource.should_parse_config?.should be_false end it "should declare a main command" do @resource.should respond_to(:main) end it "should declare a host option" do @resource.should respond_to(:handle_host) end it "should declare a types option" do @resource.should respond_to(:handle_types) end it "should declare a param option" do @resource.should respond_to(:handle_param) end it "should declare a preinit block" do @resource.should respond_to(:preinit) end describe "in preinit" do it "should set hosts to nil" do @resource.preinit @resource.host.should be_nil end it "should init extra_params to empty array" do @resource.preinit @resource.extra_params.should == [] end it "should load Facter facts" do Facter.expects(:loadfacts).once @resource.preinit end end describe "when handling options" do [:debug, :verbose, :edit].each do |option| it "should declare handle_#{option} method" do @resource.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @resource.options.expects(:[]=).with(option, 'arg') @resource.send("handle_#{option}".to_sym, 'arg') end end it "should set options[:host] to given host" do @resource.handle_host(:whatever) @resource.host.should == :whatever end it "should load an display all types with types option" do type1 = stub_everything 'type1', :name => :type1 type2 = stub_everything 'type2', :name => :type2 Puppet::Type.stubs(:loadall) Puppet::Type.stubs(:eachtype).multiple_yields(type1,type2) @resource.stubs(:exit) @resource.expects(:puts).with(['type1','type2']) @resource.handle_types(nil) end it "should add param to extra_params list" do @resource.extra_params = [ :param1 ] @resource.handle_param("whatever") @resource.extra_params.should == [ :param1, :whatever ] end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) end it "should set console as the log destination" do Puppet::Log.expects(:newdestination).with(:console) @resource.setup end it "should set log level to debug if --debug was passed" do @resource.options.stubs(:[]).with(:debug).returns(true) Puppet::Log.expects(:level=).with(:debug) @resource.setup end it "should set log level to info if --verbose was passed" do @resource.options.stubs(:[]).with(:debug).returns(false) @resource.options.stubs(:[]).with(:verbose).returns(true) Puppet::Log.expects(:level=).with(:info) @resource.setup end it "should Parse puppet config" do Puppet.expects(:parse_config) @resource.setup end end describe "when running" do before :each do @type = stub_everything 'type', :properties => [] - Puppet::Util::CommandLine.stubs(:args).returns(['type']) + @resource.command_line.stubs(:args).returns(['type']) Puppet::Type.stubs(:type).returns(@type) end it "should raise an error if no type is given" do - Puppet::Util::CommandLine.stubs(:args).returns([]) + @resource.command_line.stubs(:args).returns([]) lambda { @resource.main }.should raise_error end it "should raise an error when editing a remote host" do @resource.options.stubs(:[]).with(:edit).returns(true) @resource.host = 'host' lambda { @resource.main }.should raise_error end it "should raise an error if the type is not found" do Puppet::Type.stubs(:type).returns(nil) lambda { @resource.main }.should raise_error end describe "with a host" do before :each do @resource.stubs(:puts) @resource.host = 'host' Puppet::Resource.stubs(:find ).never Puppet::Resource.stubs(:search).never Puppet::Resource.stubs(:save ).never end it "should search for resources" do + @resource.command_line.stubs(:args).returns(['type']) Puppet::Resource.expects(:search).with('https://host:8139/production/resources/type/', {}).returns([]) @resource.main end it "should describe the given resource" do - Puppet::Util::CommandLine.stubs(:args).returns(['type', 'name']) + @resource.command_line.stubs(:args).returns(['type', 'name']) x = stub_everything 'resource' Puppet::Resource.expects(:find).with('https://host:8139/production/resources/type/name').returns(x) @resource.main end it "should add given parameters to the object" do - Puppet::Util::CommandLine.stubs(:args).returns(['type','name','param=temp']) + @resource.command_line.stubs(:args).returns(['type','name','param=temp']) res = stub "resource" res.expects(:save).with('https://host:8139/production/resources/type/name').returns(res) res.expects(:collect) res.expects(:to_manifest) Puppet::Resource.expects(:new).with('type', 'name', {'param' => 'temp'}).returns(res) @resource.main end end describe "without a host" do before :each do @resource.stubs(:puts) @resource.host = nil Puppet::Resource.stubs(:find ).never Puppet::Resource.stubs(:search).never Puppet::Resource.stubs(:save ).never end it "should search for resources" do Puppet::Resource.expects(:search).with('type/', {}).returns([]) @resource.main end it "should describe the given resource" do - Puppet::Util::CommandLine.stubs(:args).returns(['type','name']) + @resource.command_line.stubs(:args).returns(['type','name']) x = stub_everything 'resource' Puppet::Resource.expects(:find).with('type/name').returns(x) @resource.main end it "should add given parameters to the object" do - Puppet::Util::CommandLine.stubs(:args).returns(['type','name','param=temp']) + @resource.command_line.stubs(:args).returns(['type','name','param=temp']) res = stub "resource" res.expects(:save).with('type/name').returns(res) res.expects(:collect) res.expects(:to_manifest) Puppet::Resource.expects(:new).with('type', 'name', {'param' => 'temp'}).returns(res) @resource.main end end end end