diff options
author | Brice Figureau <brice-puppet@daysofwonder.com> | 2009-02-14 17:15:52 +0100 |
---|---|---|
committer | Brice Figureau <brice-puppet@daysofwonder.com> | 2009-02-16 20:12:11 +0100 |
commit | e317fa9717e648435dbbc62497d73f803b7b2760 (patch) | |
tree | ecca31f78e118848ea83188368f980ec5e7ff6ad | |
parent | 81f5438f663820748d3bd580d7436619ed57b6f0 (diff) | |
download | puppet-e317fa9717e648435dbbc62497d73f803b7b2760.tar.gz puppet-e317fa9717e648435dbbc62497d73f803b7b2760.tar.xz puppet-e317fa9717e648435dbbc62497d73f803b7b2760.zip |
Move ralsh to the Application Controller paradigm
Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>
-rwxr-xr-x | bin/ralsh | 187 | ||||
-rw-r--r-- | lib/puppet/application/ralsh.rb | 166 | ||||
-rw-r--r-- | spec/unit/application/ralsh.rb | 230 |
3 files changed, 398 insertions, 185 deletions
@@ -85,188 +85,5 @@ # Copyright (c) 2005-2007 Reductive Labs, LLC # Licensed under the GNU Public License - -require 'getoptlong' -require 'puppet' - -options = [ - [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], - [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], - [ "--types", "-t", GetoptLong::NO_ARGUMENT ], - [ "--param", "-p", GetoptLong::REQUIRED_ARGUMENT ], - [ "--host", "-H", GetoptLong::REQUIRED_ARGUMENT ], - [ "--edit", "-e", GetoptLong::NO_ARGUMENT ], - [ "--help", "-h", GetoptLong::NO_ARGUMENT ] -] - -# Add all of the config parameters as valid options. -Puppet.settings.addargs(options) - -result = GetoptLong.new(*options) - -debug = false -verbose = false -edit = false -extra_params = [] -host = nil - -result.each { |opt,arg| - case opt - when "--host" - host = arg - when "--types" - types = [] - Puppet::Type.loadall - Puppet::Type.eachtype do |t| - next if t.name == :component - types << t.name.to_s - end - puts types.sort - exit - when "--param" - extra_params << arg.to_sym - when "--edit" - edit = true - when "--help" - if Puppet.features.usage? - RDoc::usage - else - puts "install RDoc:usage for help" - end - exit - when "--verbose" - verbose = true - when "--debug" - debug = true - else - # Anything else is handled by the config stuff - Puppet.settings.handlearg(opt, arg) - end -} - -Puppet::Util::Log.newdestination(:console) - -# Now parse the config -Puppet.parse_config - -if debug - Puppet::Util::Log.level = :debug -elsif verbose - Puppet::Util::Log.level = :info -end - - -if ARGV.length > 0 - type = ARGV.shift -else - raise "You must specify the type to display" -end - -name = nil -params = {} -if ARGV.length > 0 - name = ARGV.shift -end - -if ARGV.length > 0 - ARGV.each do |setting| - if setting =~ /^(\w+)=(.+)$/ - params[$1] = $2 - else - raise "Invalid parameter setting %s" % setting - end - end -end - -if edit and host - raise "You cannot edit a remote host" -end - -typeobj = nil - -unless typeobj = Puppet::Type.type(type) - raise "Could not find type %s" % type -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 -} - -text = if host - client = Puppet::Network::Client.resource.new(:Server => host, :Port => Puppet[:puppetport]) - unless client.read_cert - raise "client.read_cert failed" - end - begin - # They asked for a single resource. - if name - transbucket = [client.describe(type, name)] - else - # Else, list the whole thing out. - transbucket = client.instances(type) - end - rescue Puppet::Network::XMLRPCClientError => exc - raise "client.list(#{type}) failed: #{exc.message}" - end - transbucket.sort { |a,b| a.name <=> b.name }.collect(&format) -else - if name - obj = typeobj.create(:name => name, :check => properties) - vals = obj.retrieve - - unless params.empty? - params.each do |param, value| - obj[param] = value - end - catalog = Puppet::Resource::Catalog.new - catalog.add_resource obj - begin - catalog.apply - rescue => detail - if Puppet[:trace] - puts detail.backtrace - end - end - - end - [format.call(obj.to_trans(true))] - else - typeobj.instances.collect do |obj| - next if ARGV.length > 0 and ! ARGV.include? obj.name - trans = obj.to_trans(true) - format.call(trans) - end - end -end.compact.join("\n") - -if 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 - +require 'puppet/application/ralsh' +Puppet::Application[:ralsh].run diff --git a/lib/puppet/application/ralsh.rb b/lib/puppet/application/ralsh.rb new file mode 100644 index 000000000..d15d3e617 --- /dev/null +++ b/lib/puppet/application/ralsh.rb @@ -0,0 +1,166 @@ +require 'puppet' +require 'puppet/application' + +Puppet::Application.new(:ralsh) do + + should_not_parse_config + + attr_accessor :host, :extra_params + + preinit do + @extra_params = [] + @host = nil + 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 + + command(:main) do + if ARGV.length > 0 + type = ARGV.shift + else + raise "You must specify the type to display" + end + + name = nil + params = {} + if ARGV.length > 0 + name = ARGV.shift + end + + if ARGV.length > 0 + ARGV.each do |setting| + if setting =~ /^(\w+)=(.+)$/ + params[$1] = $2 + else + raise "Invalid parameter setting %s" % setting + end + end + end + + if options[:edit] and @host + raise "You cannot edit a remote host" + end + + typeobj = nil + + unless typeobj = Puppet::Type.type(type) + raise "Could not find type %s" % type + 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 + } + + text = if @host + client = Puppet::Network::Client.resource.new(:Server => @host, :Port => Puppet[:puppetport]) + unless client.read_cert + raise "client.read_cert failed" + end + begin + # They asked for a single resource. + if name + transbucket = [client.describe(type, name)] + else + # Else, list the whole thing out. + transbucket = client.instances(type) + end + rescue Puppet::Network::XMLRPCClientError => exc + raise "client.list(#{type}) failed: #{exc.message}" + end + transbucket.sort { |a,b| a.name <=> b.name }.collect(&format) + else + if name + obj = typeobj.create(:name => name, :check => properties) + vals = obj.retrieve + + unless params.empty? + params.each do |param, value| + obj[param] = value + end + catalog = Puppet::Resource::Catalog.new + catalog.add_resource obj + begin + catalog.apply + rescue => detail + if Puppet[:trace] + puts detail.backtrace + end + end + + end + [format.call(obj.to_trans(true))] + else + typeobj.instances.collect do |obj| + next if ARGV.length > 0 and ! ARGV.include? obj.name + trans = obj.to_trans(true) + format.call(trans) + end + end + end.compact.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 + + setup do + 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/spec/unit/application/ralsh.rb b/spec/unit/application/ralsh.rb new file mode 100644 index 000000000..8f3951447 --- /dev/null +++ b/spec/unit/application/ralsh.rb @@ -0,0 +1,230 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/application/ralsh' + +describe "ralsh" do + before :each do + @ralsh = Puppet::Application[:ralsh] + end + + it "should ask Puppet::Application to not parse Puppet configuration file" do + @ralsh.should_parse_config?.should be_false + end + + it "should declare a main command" do + @ralsh.should respond_to(:main) + end + + it "should declare a host option" do + @ralsh.should respond_to(:handle_host) + end + + it "should declare a types option" do + @ralsh.should respond_to(:handle_types) + end + + it "should declare a param option" do + @ralsh.should respond_to(:handle_param) + end + + it "should declare a preinit block" do + @ralsh.should respond_to(:run_preinit) + end + + describe "in preinit" do + it "should set hosts to nil" do + @ralsh.run_preinit + + @ralsh.host.should be_nil + end + + it "should init extra_params to empty array" do + @ralsh.run_preinit + + @ralsh.extra_params.should == [] + end + end + + describe "when handling options" do + + [:debug, :verbose, :edit].each do |option| + it "should declare handle_#{option} method" do + @ralsh.should respond_to("handle_#{option}".to_sym) + end + + it "should store argument value when calling handle_#{option}" do + @ralsh.options.expects(:[]=).with(option, 'arg') + @ralsh.send("handle_#{option}".to_sym, 'arg') + end + end + + it "should set options[:host] to given host" do + @ralsh.handle_host(:whatever) + + @ralsh.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) + @ralsh.stubs(:exit) + + @ralsh.expects(:puts).with(['type1','type2']) + @ralsh.handle_types(nil) + end + + it "should add param to extra_params list" do + @ralsh.extra_params = [ :param1 ] + @ralsh.handle_param("whatever") + + @ralsh.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) + + @ralsh.run_setup + end + + it "should set log level to debug if --debug was passed" do + @ralsh.options.stubs(:[]).with(:debug).returns(true) + + Puppet::Log.expects(:level=).with(:debug) + + @ralsh.run_setup + end + + it "should set log level to info if --verbose was passed" do + @ralsh.options.stubs(:[]).with(:debug).returns(false) + @ralsh.options.stubs(:[]).with(:verbose).returns(true) + + Puppet::Log.expects(:level=).with(:info) + + @ralsh.run_setup + end + + it "should Parse puppet config" do + Puppet.expects(:parse_config) + + @ralsh.run_setup + end + end + + describe "when running" do + + before :each do + @type = stub_everything 'type', :properties => [] + ARGV.stubs(:shift).returns("type") + ARGV.stubs(:length).returns(1).then.returns(0) + Puppet::Type.stubs(:type).returns(@type) + end + + it "should raise an error if no type is given" do + ARGV.stubs(:length).returns(0) + + lambda { @ralsh.main }.should raise_error + end + + it "should raise an error when editing a remote host" do + @ralsh.options.stubs(:[]).with(:edit).returns(true) + @ralsh.host = 'host' + + lambda { @ralsh.main }.should raise_error + end + + it "should raise an error if the type is not found" do + Puppet::Type.stubs(:type).returns(nil) + + lambda { @ralsh.main }.should raise_error + end + + describe "with a host" do + before :each do + @ralsh.stubs(:puts) + @ralsh.host = 'host' + @client = stub_everything 'client' + @client.stubs(:read_cert).returns(true) + @client.stubs(:instances).returns([]) + Puppet::Network::Client.resource.stubs(:new).returns(@client) + end + + it "should connect to it" do + Puppet::Network::Client.resource.expects(:new).with { |h| h[:Server] == 'host' }.returns(@client) + @ralsh.main + end + + it "should raise an error if there are no certs" do + @client.stubs(:read_cert).returns(nil) + + lambda { @ralsh.main }.should raise_error + end + + it "should retrieve all the instances if there is no name" do + @client.expects(:instances).returns([]) + + @ralsh.main + end + + it "should describe the given resource" do + ARGV.stubs(:shift).returns("type").then.returns('name') + ARGV.stubs(:length).returns(1).then.returns(1).then.returns(0) + @client.expects(:describe).returns(stub_everything) + + @ralsh.main + end + end + + describe "without a host" do + before :each do + @ralsh.stubs(:puts) + @ralsh.host = nil + end + + it "should retrieve all the instances if there is no name" do + @type.expects(:instances).returns([]) + + @ralsh.main + end + + describe 'but with a given name' do + before :each do + ARGV.stubs(:shift).returns("type").then.returns('name') + ARGV.stubs(:length).returns(1).then.returns(1).then.returns(0) + @object = stub_everything 'object', :to_trans => stub_everything('transportable') + @type.stubs(:create).returns(@object) + @object.stubs(:retrieve) + end + + it "should retrieve a specific instace" do + @type.expects(:create).returns(@object) + @object.expects(:retrieve) + + @ralsh.main + end + + it "should add given parameters to object" do + ARGV.stubs(:each).yields('param=temp') + ARGV.stubs(:length).returns(1).then.returns(1).then.returns(1) + Puppet::Resource::Catalog.stubs(:new).returns(stub_everything) + @object.expects(:[]=).with('param','temp') + + @ralsh.main + end + end + end + + end +end |