diff --git a/lib/puppet/application/resource.rb b/lib/puppet/application/resource.rb index f55caa58a..b7967772c 100644 --- a/lib/puppet/application/resource.rb +++ b/lib/puppet/application/resource.rb @@ -1,118 +1,125 @@ require 'puppet/application' 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 = 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 #{setting}" end end raise "You cannot edit a remote host" if options[:edit] and @host 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 trans.delete(param) unless properties.include?(param) or @extra_params.include?(param) 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, :parameters => params ).save( key ) ] end else Puppet::Resource.search( key, {} ) end.map(&format).join("\n") if options[:edit] - file = "/tmp/x2puppet-#{Process.pid}.pp" + require 'tempfile' + # Prefer the current directory, which is more likely to be secure + # and, in the case of interactive use, accessible to the user. + tmpfile = Tempfile.new('x2puppet', Dir.pwd) begin - File.open(file, "w") do |f| - f.puts text - end - ENV["EDITOR"] ||= "vi" - system(ENV["EDITOR"], file) - system("puppet -v #{file}") + # sync write, so nothing buffers before we invoke the editor. + tmpfile.sync = true + tmpfile.puts text + + # edit the content + system(ENV["EDITOR"] || 'vi', tmpfile.path) + + # ...and, now, pass that file to puppet to apply. Because + # many editors rename or replace the original file we need to + # feed the pathname, not the file content itself, to puppet. + system('puppet -v ' + tmpfile.path) ensure - #if FileTest.exists? file - # File.unlink(file) - #end + # The temporary file will be safely removed. + tmpfile.close(true) 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