other places, it is easier to create the symlink. If you run ``leap`` directly, and not via
the command launcher that rubygems installs, leap will run in a mode that simulates
``bundle exec leap`` (i.e. only gems included in Gemfile are allowed to be loaded).
+
+Future development
+----------------------------------------------------
+
+(1) remove supply_drop - our use of supply drop no longer makes sense, as our needs diverge and we have more and more patches against upstream. the supply drop code we use should be cherry picked and brought into leap_cli.
+
+ (a) create a separate rsync library independent of capistrano or supply_drop.
+ (b) do our own rsync for the puppet manifests (make sure to include --copy-links)
+ (c) do our own puppet apply, with capture of exit status.
+
+(2) remove capistrano. we don't need it, and it makes it awkward to do what we want (exit codes, different options for different hosts). either use another shell lib, or roll our own. maybe something like 'remotedly(hosts) do |host|....'
# load commands and run
commands_from('leap_cli/commands')
ORIGINAL_ARGV = ARGV.dup
- exit run(ARGV)
+ exit_status = run(ARGV)
+ exit(LeapCli::Util.exit_status || exit_status)
end
else ''
end
- ssh.set :puppet_command, "/usr/bin/puppet apply --color=false --tags=#{tags.join(',')} #{verbosity}"
+ ssh.set :puppet_command, "/usr/bin/puppet apply --color=false --tags=#{tags.join(',')} --detailed-exitcodes #{verbosity}"
ssh.set :puppet_lib, "puppet/modules"
ssh.set :puppet_parameters, '--libdir puppet/lib --confdir puppet puppet/manifests/site.pp'
ssh.set :puppet_stream_output, true
{ :match => /^warning:/, :level => 0, :color => :yellow, :priority => -20},
{ :match => /^Duplicate declaration:/, :level => 0, :color => :red, :priority => -20},
{ :match => /Finished catalog run/, :level => 0, :color => :green, :priority => -10},
+ { :match => /^Puppet apply complete \(changes made\)/, :level => 0, :color => :green, :priority => -10},
+ { :match => /^Puppet apply complete \(no changes\)/, :level => 0, :color => :green, :priority => -10},
# PUPPET FATAL ERRORS
{ :match => /^err:/, :level => 0, :color => :red, :priority => -1, :exit => 1},
{ :match => /^Parameter matches failed:/, :level => 0, :color => :red, :priority => -1, :exit => 1},
{ :match => /^Syntax error/, :level => 0, :color => :red, :priority => -1, :exit => 1},
{ :match => /^Cannot reassign variable/, :level => 0, :color => :red, :priority => -1, :exit => 1},
- { :match => /^Could not find template/, :level => 0, :color => :red, :priority => -1, :exit => 1}
+ { :match => /^Could not find template/, :level => 0, :color => :red, :priority => -1, :exit => 1},
+ { :match => /^Puppet apply complete.*fail/, :level => 0, :color => :red, :priority => -1, :exit => 1}
]
def self.sorted_formatters
## QUITTING
##
- def exit_status(code)
- @exit_status = code
+ def exit_status(code=nil)
+ @exit_status = code if code
+ @exit_status
end
#
writer = SupplyDrop::Writer::File.new(writer, puppet_write_to_file) unless puppet_write_to_file.nil?
begin
- run "#{puppet_cmd} #{flag}" do |channel, stream, data|
- writer.collect_output(channel[:host], data)
+ exitcode = nil
+ run "#{puppet_cmd} #{flag}; echo exitcode:$?" do |channel, stream, data|
+ if data =~ /exitcode:(\d+)/
+ exitcode = $1
+ writer.collect_output(channel[:host], "Puppet #{command} complete (#{exitcode_description(exitcode)}).\n")
+ else
+ writer.collect_output(channel[:host], data)
+ end
end
- logger.debug "Puppet #{command} complete."
ensure
writer.all_output_collected
end
end
+ def exitcode_description(code)
+ case code
+ when "0" then "no changes"
+ when "2" then "changes made"
+ when "4" then "failed"
+ when "6" then "changes and failures"
+ else code
+ end
+ end
+
def red_text(text)
"\033[0;31m#{text}\033[0m"
end