130 lines
3.4 KiB
Ruby
130 lines
3.4 KiB
Ruby
class DockerManager::Upgrader
|
|
|
|
def initialize(user_id, repo, from_version)
|
|
@user_id = user_id
|
|
@repo = repo
|
|
@from_version = from_version
|
|
end
|
|
|
|
def reset!
|
|
@repo.stop_upgrading
|
|
clear_logs
|
|
percent(0)
|
|
end
|
|
|
|
def upgrade
|
|
return unless @repo.start_upgrading
|
|
|
|
percent(0)
|
|
clear_logs
|
|
|
|
# HEAD@{upstream} is just a fancy way how to say origin/master (in normal case)
|
|
# see http://stackoverflow.com/a/12699604/84283
|
|
run("cd #{@repo.path} && git fetch --tags && git reset --hard HEAD@{upstream}")
|
|
log("********************************************************")
|
|
log("*** Please be patient, next steps might take a while ***")
|
|
log("********************************************************")
|
|
percent(5)
|
|
run("bundle install --deployment --without test --without development")
|
|
percent(25)
|
|
run("bundle exec rake multisite:migrate")
|
|
percent(50)
|
|
log("*** Bundling assets. This might take a while *** ")
|
|
run("bundle exec rake assets:precompile")
|
|
percent(75)
|
|
sidekiq_pid = `ps aux | grep sidekiq.*busy | grep -v grep | awk '{ print $2 }'`.strip.to_i
|
|
if sidekiq_pid > 0
|
|
Process.kill("TERM", sidekiq_pid)
|
|
log("Killed sidekiq")
|
|
else
|
|
log("Warning: Sidekiq was not found")
|
|
end
|
|
percent(100)
|
|
publish('status', 'complete')
|
|
pid = `ps aux | grep unicorn_launcher | grep -v sudo | grep -v grep | awk '{ print $2 }'`.strip
|
|
if pid.to_i > 0
|
|
log("***********************************************")
|
|
log("*** After restart, upgrade will be complete ***")
|
|
log("***********************************************")
|
|
log("Restarting unicorn pid: #{pid}")
|
|
Process.kill("USR2", pid.to_i)
|
|
log("DONE")
|
|
else
|
|
log("Did not find unicorn launcher")
|
|
end
|
|
rescue => ex
|
|
publish('status', 'failed')
|
|
STDERR.puts("Docker Manager: FAILED TO UPGRADE")
|
|
STDERR.puts(ex.inspect)
|
|
raise
|
|
ensure
|
|
@repo.stop_upgrading
|
|
end
|
|
|
|
def publish(type, value)
|
|
MessageBus.publish("/docker/upgrade", {type: type, value: value}, user_ids: [@user_id])
|
|
end
|
|
|
|
def run(cmd)
|
|
log "$ #{cmd}"
|
|
msg = ""
|
|
|
|
clear_env = Hash[*ENV.map{|k,v| [k,nil]}
|
|
.reject{ |k,v|
|
|
["PWD","HOME","SHELL","PATH"].include?(k) ||
|
|
k =~ /^DISCOURSE_/
|
|
}
|
|
.flatten]
|
|
clear_env["RAILS_ENV"] = "production"
|
|
clear_env["TERM"] = 'dumb' # claim we have a terminal
|
|
|
|
retval = nil
|
|
Open3.popen2e(clear_env, "cd #{Rails.root} && #{cmd} 2>&1") do |_in, out, wait_thread|
|
|
out.each do |line|
|
|
line.rstrip! # the client adds newlines, so remove the one we're given
|
|
log(line)
|
|
msg << line << "\n"
|
|
end
|
|
retval = wait_thread.value
|
|
end
|
|
|
|
unless retval == 0
|
|
STDERR.puts("FAILED: '#{cmd}' exited with a return value of #{retval}")
|
|
STDERR.puts(msg)
|
|
raise RuntimeError
|
|
end
|
|
end
|
|
|
|
def logs_key
|
|
"logs:#{@repo.path}:#{@from_version}"
|
|
end
|
|
|
|
def clear_logs
|
|
$redis.del(logs_key)
|
|
end
|
|
|
|
def find_logs
|
|
$redis.get(logs_key)
|
|
end
|
|
|
|
def percent_key
|
|
"percent:#{@repo.path}:#{@from_version}"
|
|
end
|
|
|
|
def last_percentage
|
|
$redis.get(percent_key)
|
|
end
|
|
|
|
def percent(val)
|
|
$redis.set(percent_key, val)
|
|
$redis.expire(percent_key, 30.minutes)
|
|
publish('percent', val)
|
|
end
|
|
|
|
def log(message)
|
|
$redis.append logs_key, message + "\n"
|
|
$redis.expire(logs_key, 30.minutes)
|
|
publish 'log', message
|
|
end
|
|
end
|