Protect accessory cli from missing accessory

This commit is contained in:
David Heinemeier Hansson
2023-01-27 16:12:18 +01:00
parent f58e5e0935
commit 407e1cc028
2 changed files with 93 additions and 62 deletions

View File

@@ -6,61 +6,69 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
if name == "all" if name == "all"
MRSK.accessory_names.each { |accessory_name| boot(accessory_name) } MRSK.accessory_names.each { |accessory_name| boot(accessory_name) }
else else
directories(name) with_accessory(name) do |accessory|
upload(name) directories(name)
upload(name)
accessory = MRSK.accessory(name) on(accessory.host) { execute *accessory.run }
on(accessory.host) { execute *accessory.run } end
end end
end end
desc "upload [NAME]", "Upload accessory files to host" desc "upload [NAME]", "Upload accessory files to host"
def upload(name) def upload(name)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
on(accessory.host) do on(accessory.host) do
accessory.files.each do |(local, remote)| accessory.files.each do |(local, remote)|
accessory.ensure_local_file_present(local) accessory.ensure_local_file_present(local)
execute *accessory.make_directory_for(remote) execute *accessory.make_directory_for(remote)
upload! local, remote upload! local, remote
execute :chmod, "755", remote execute :chmod, "755", remote
end
end end
end end
end end
desc "directories [NAME]", "Create accessory directories on host" desc "directories [NAME]", "Create accessory directories on host"
def directories(name) def directories(name)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
on(accessory.host) do on(accessory.host) do
accessory.directories.keys.each do |host_path| accessory.directories.keys.each do |host_path|
execute *accessory.make_directory(host_path) execute *accessory.make_directory(host_path)
end
end end
end end
end end
desc "reboot [NAME]", "Reboot accessory on host (stop container, remove container, start new container)" desc "reboot [NAME]", "Reboot accessory on host (stop container, remove container, start new container)"
def reboot(name) def reboot(name)
stop(name) with_accessory(name) do |accessory|
remove_container(name) stop(name)
boot(name) remove_container(name)
boot(name)
end
end end
desc "start [NAME]", "Start existing accessory on host" desc "start [NAME]", "Start existing accessory on host"
def start(name) def start(name)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
on(accessory.host) { execute *accessory.start } on(accessory.host) { execute *accessory.start }
end
end end
desc "stop [NAME]", "Stop accessory on host" desc "stop [NAME]", "Stop accessory on host"
def stop(name) def stop(name)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
on(accessory.host) { execute *accessory.stop, raise_on_non_zero_exit: false } on(accessory.host) { execute *accessory.stop, raise_on_non_zero_exit: false }
end
end end
desc "restart [NAME]", "Restart accessory on host" desc "restart [NAME]", "Restart accessory on host"
def restart(name) def restart(name)
stop(name) with_accessory(name) do
start(name) stop(name)
start(name)
end
end end
desc "details [NAME]", "Display details about accessory on host (use NAME=all to boot all accessories)" desc "details [NAME]", "Display details about accessory on host (use NAME=all to boot all accessories)"
@@ -68,27 +76,28 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
if name == "all" if name == "all"
MRSK.accessory_names.each { |accessory_name| details(accessory_name) } MRSK.accessory_names.each { |accessory_name| details(accessory_name) }
else else
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
on(accessory.host) { puts capture_with_info(*accessory.info) } on(accessory.host) { puts capture_with_info(*accessory.info) }
end
end end
end end
desc "exec [NAME] [CMD]", "Execute a custom command on accessory host" desc "exec [NAME] [CMD]", "Execute a custom command on accessory host"
option :run, type: :boolean, default: false, desc: "Start a new container to run the command rather than reusing existing" option :run, type: :boolean, default: false, desc: "Start a new container to run the command rather than reusing existing"
def exec(name, cmd) def exec(name, cmd)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
runner = options[:run] ? :run_exec : :exec
runner = options[:run] ? :run_exec : :exec on(accessory.host) { |host| puts_by_host host, capture_with_info(*accessory.send(runner, cmd)) }
on(accessory.host) { |host| puts_by_host host, capture_with_info(*accessory.send(runner, cmd)) } end
end end
desc "bash [NAME]", "Start a bash session on primary host (or specific host set by --hosts)" desc "bash [NAME]", "Start a bash session on primary host (or specific host set by --hosts)"
def bash(name) def bash(name)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
run_locally do
run_locally do info "Launching bash session on #{accessory.host}"
info "Launching bash session on #{accessory.host}" exec accessory.bash(host: accessory.host)
exec accessory.bash(host: accessory.host) end
end end
end end
@@ -98,22 +107,22 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
option :grep, aliases: "-g", desc: "Show lines with grep match only (use this to fetch specific requests by id)" option :grep, aliases: "-g", desc: "Show lines with grep match only (use this to fetch specific requests by id)"
option :follow, aliases: "-f", desc: "Follow logs on primary server (or specific host set by --hosts)" option :follow, aliases: "-f", desc: "Follow logs on primary server (or specific host set by --hosts)"
def logs(name) def logs(name)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
grep = options[:grep]
grep = options[:grep] if options[:follow]
run_locally do
info "Following logs on #{accessory.host}..."
info accessory.follow_logs(grep: grep)
exec accessory.follow_logs(grep: grep)
end
else
since = options[:since]
lines = options[:lines]
if options[:follow] on(accessory.host) do
run_locally do puts capture_with_info(*accessory.logs(since: since, lines: lines, grep: grep))
info "Following logs on #{accessory.host}..." end
info accessory.follow_logs(grep: grep)
exec accessory.follow_logs(grep: grep)
end
else
since = options[:since]
lines = options[:lines]
on(accessory.host) do
puts capture_with_info(*accessory.logs(since: since, lines: lines, grep: grep))
end end
end end
end end
@@ -123,28 +132,50 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
if name == "all" if name == "all"
MRSK.accessory_names.each { |accessory_name| remove(accessory_name) } MRSK.accessory_names.each { |accessory_name| remove(accessory_name) }
else else
stop(name) with_accessory(name) do
remove_container(name) stop(name)
remove_image(name) remove_container(name)
remove_service_directory(name) remove_image(name)
remove_service_directory(name)
end
end end
end end
desc "remove_container [NAME]", "Remove accessory container from host" desc "remove_container [NAME]", "Remove accessory container from host"
def remove_container(name) def remove_container(name)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
on(accessory.host) { execute *accessory.remove_container } on(accessory.host) { execute *accessory.remove_container }
end
end end
desc "remove_container [NAME]", "Remove accessory image from host" desc "remove_container [NAME]", "Remove accessory image from host"
def remove_image(name) def remove_image(name)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
on(accessory.host) { execute *accessory.remove_image } on(accessory.host) { execute *accessory.remove_image }
end
end end
desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host" desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host"
def remove_service_directory(name) def remove_service_directory(name)
accessory = MRSK.accessory(name) with_accessory(name) do |accessory|
on(accessory.host) { execute *accessory.remove_service_directory } on(accessory.host) { execute *accessory.remove_service_directory }
end
end end
private
def with_accessory(name)
if accessory = MRSK.accessory(name)
yield accessory
else
error_on_missing_accessory(name)
end
end
def error_on_missing_accessory(name)
options = MRSK.accessory_names.presence
error \
"No accessory by the name of '#{name}'" +
(options ? " (options: #{options.to_sentence})" : "")
end
end end

View File

@@ -49,7 +49,7 @@ class Mrsk::Commander
end end
def accessory_names def accessory_names
config.accessories.collect(&:name) config.accessories&.collect(&:name) || []
end end
@@ -74,7 +74,7 @@ class Mrsk::Commander
end end
def accessory(name) def accessory(name)
(@accessories ||= {})[name] ||= Mrsk::Commands::Accessory.new(config, name: name) config.accessories.detect { |a| a.name == name }
end end