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,17 +6,17 @@ 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
with_accessory(name) do |accessory|
directories(name) directories(name)
upload(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)
@@ -27,70 +27,79 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
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)
with_accessory(name) do |accessory|
stop(name) stop(name)
remove_container(name) remove_container(name)
boot(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)
with_accessory(name) do
stop(name) stop(name)
start(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)"
def details(name) def details(name)
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
desc "logs [NAME]", "Show log lines from accessory on host" desc "logs [NAME]", "Show log lines from accessory on host"
option :since, aliases: "-s", desc: "Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)" option :since, aliases: "-s", desc: "Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)"
@@ -98,8 +107,7 @@ 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] if options[:follow]
@@ -117,34 +125,57 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
end end
end end
end end
end
desc "remove [NAME]", "Remove accessory container and image from host (use NAME=all to boot all accessories)" desc "remove [NAME]", "Remove accessory container and image from host (use NAME=all to boot all accessories)"
def remove(name) def remove(name)
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
with_accessory(name) do
stop(name) stop(name)
remove_container(name) remove_container(name)
remove_image(name) remove_image(name)
remove_service_directory(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