diff --git a/lib/mrsk/cli/accessory.rb b/lib/mrsk/cli/accessory.rb index 918c3d0b..549ba8e0 100644 --- a/lib/mrsk/cli/accessory.rb +++ b/lib/mrsk/cli/accessory.rb @@ -9,7 +9,10 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base with_accessory(name) do |accessory| directories(name) upload(name) - on(accessory.host) { execute *accessory.run } + on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} boot"), verbosity: :debug + execute *accessory.run + end end end end @@ -18,6 +21,8 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base def upload(name) with_accessory(name) do |accessory| on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} upload files"), verbosity: :debug + accessory.files.each do |(local, remote)| accessory.ensure_local_file_present(local) @@ -33,6 +38,8 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base def directories(name) with_accessory(name) do |accessory| on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} create directories"), verbosity: :debug + accessory.directories.keys.each do |host_path| execute *accessory.make_directory(host_path) end @@ -52,14 +59,20 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "start [NAME]", "Start existing accessory on host" def start(name) with_accessory(name) do |accessory| - on(accessory.host) { execute *accessory.start } + on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} start"), verbosity: :debug + execute *accessory.start + end end end desc "stop [NAME]", "Stop accessory on host" def stop(name) with_accessory(name) do |accessory| - on(accessory.host) { execute *accessory.stop, raise_on_non_zero_exit: false } + on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} stop"), verbosity: :debug + execute *accessory.stop, raise_on_non_zero_exit: false + end end end @@ -98,11 +111,17 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base when options[:reuse] say "Launching command from existing container...", :magenta - on(accessory.host) { capture_with_info(*accessory.execute_in_existing_container(cmd)) } + on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} cmd '#{cmd}'"), verbosity: :debug + capture_with_info(*accessory.execute_in_existing_container(cmd)) + end else say "Launching command from new container...", :magenta - on(accessory.host) { capture_with_info(*accessory.execute_in_new_container(cmd)) } + on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} cmd '#{cmd}'"), verbosity: :debug + capture_with_info(*accessory.execute_in_new_container(cmd)) + end end end end @@ -150,21 +169,30 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "remove_container [NAME]", "Remove accessory container from host" def remove_container(name) with_accessory(name) do |accessory| - on(accessory.host) { execute *accessory.remove_container } + on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} remove container"), verbosity: :debug + execute *accessory.remove_container + end end end desc "remove_image [NAME]", "Remove accessory image from host" def remove_image(name) with_accessory(name) do |accessory| - on(accessory.host) { execute *accessory.remove_image } + on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} remove image"), verbosity: :debug + execute *accessory.remove_image + end end end desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host" def remove_service_directory(name) with_accessory(name) do |accessory| - on(accessory.host) { execute *accessory.remove_service_directory } + on(accessory.host) do + execute *MRSK.auditor.record("accessory #{name} remove service directory"), verbosity: :debug + execute *accessory.remove_service_directory + end end end diff --git a/lib/mrsk/cli/app.rb b/lib/mrsk/cli/app.rb index 7fdad85a..9d3e5b58 100644 --- a/lib/mrsk/cli/app.rb +++ b/lib/mrsk/cli/app.rb @@ -14,6 +14,8 @@ class Mrsk::Cli::App < Mrsk::Cli::Base MRSK.config.roles.each do |role| on(role.hosts) do |host| + execute *MRSK.auditor.record("app boot version #{version}"), verbosity: :debug + begin execute *MRSK.app.run(role: role.name) rescue SSHKit::Command::Failed => e @@ -33,12 +35,18 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "start", "Start existing app on servers (use --version= to designate specific version)" def start - on(MRSK.hosts) { execute *MRSK.app.start, raise_on_non_zero_exit: false } + on(MRSK.hosts) do + execute *MRSK.auditor.record("app start version #{MRSK.version}"), verbosity: :debug + execute *MRSK.app.start, raise_on_non_zero_exit: false + end end desc "stop", "Stop app on servers" def stop - on(MRSK.hosts) { execute *MRSK.app.stop, raise_on_non_zero_exit: false } + on(MRSK.hosts) do + execute *MRSK.auditor.record("app stop"), verbosity: :debug + execute *MRSK.app.stop, raise_on_non_zero_exit: false + end end desc "details", "Display details about app containers" @@ -68,15 +76,22 @@ class Mrsk::Cli::App < Mrsk::Cli::Base when options[:reuse] say "Get current version of running container...", :magenta unless options[:version] using_version(options[:version] || current_running_version) do |version| - say "Launching command with version #{version} from existing container on #{MRSK.primary_host}...", :magenta - on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.execute_in_existing_container(cmd)) } + say "Launching command with version #{version} from existing container...", :magenta + + on(MRSK.hosts) do |host| + execute *MRSK.auditor.record("app cmd '#{cmd}' with version #{version}"), verbosity: :debug + puts_by_host host, capture_with_info(*MRSK.app.execute_in_existing_container(cmd)) + end end else say "Get most recent version available as an image...", :magenta unless options[:version] using_version(options[:version] || most_recent_version_available) do |version| - say "Launching command with version #{version} from new container on #{MRSK.primary_host}...", :magenta - on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.execute_in_new_container(cmd)) } + say "Launching command with version #{version} from new container...", :magenta + on(MRSK.hosts) do |host| + execute *MRSK.auditor.record("app cmd '#{cmd}' with version #{version}"), verbosity: :debug + puts_by_host host, capture_with_info(*MRSK.app.execute_in_new_container(cmd)) + end end end end @@ -134,17 +149,26 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "remove_container [VERSION]", "Remove app container with given version from servers" def remove_container(version) - on(MRSK.hosts) { execute *MRSK.app.remove_container(version: version) } + on(MRSK.hosts) do + execute *MRSK.auditor.record("app remove container #{version}"), verbosity: :debug + execute *MRSK.app.remove_container(version: version) + end end desc "remove_containers", "Remove all app containers from servers" def remove_containers - on(MRSK.hosts) { execute *MRSK.app.remove_containers } + on(MRSK.hosts) do + execute *MRSK.auditor.record("app remove containers"), verbosity: :debug + execute *MRSK.app.remove_containers + end end desc "remove_images", "Remove all app images from servers" def remove_images - on(MRSK.hosts) { execute *MRSK.app.remove_images } + on(MRSK.hosts) do + execute *MRSK.auditor.record("app remove images"), verbosity: :debug + execute *MRSK.app.remove_images + end end desc "current_version", "Shows the version currently running" diff --git a/lib/mrsk/cli/build.rb b/lib/mrsk/cli/build.rb index 8a8e856d..2873dfed 100644 --- a/lib/mrsk/cli/build.rb +++ b/lib/mrsk/cli/build.rb @@ -30,7 +30,10 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base desc "pull", "Pull app image from the registry onto servers" def pull - on(MRSK.hosts) { execute *MRSK.builder.pull } + on(MRSK.hosts) do + execute *MRSK.auditor.record("build pull image #{MRSK.version}"), verbosity: :debug + execute *MRSK.builder.pull + end end desc "create", "Create a local build setup" diff --git a/lib/mrsk/cli/main.rb b/lib/mrsk/cli/main.rb index ca28ab72..dd570c50 100644 --- a/lib/mrsk/cli/main.rb +++ b/lib/mrsk/cli/main.rb @@ -70,6 +70,13 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base invoke "mrsk:cli:accessory:details", [ "all" ] end + desc "audit", "Show audit log from servers" + def audit + on(MRSK.hosts) do |host| + puts_by_host host, capture_with_info(*MRSK.auditor.reveal) + end + end + desc "config", "Show combined config" def config run_locally do diff --git a/lib/mrsk/cli/prune.rb b/lib/mrsk/cli/prune.rb index 37bb4f08..32bd7f04 100644 --- a/lib/mrsk/cli/prune.rb +++ b/lib/mrsk/cli/prune.rb @@ -9,11 +9,17 @@ class Mrsk::Cli::Prune < Mrsk::Cli::Base desc "images", "Prune unused images older than 30 days" def images - on(MRSK.hosts) { execute *MRSK.prune.images } + on(MRSK.hosts) do + execute *MRSK.auditor.record("prune images"), verbosity: :debug + execute *MRSK.prune.images + end end desc "containers", "Prune stopped containers for the service older than 3 days" def containers - on(MRSK.hosts) { execute *MRSK.prune.containers } + on(MRSK.hosts) do + execute *MRSK.auditor.record("prune containers"), verbosity: :debug + execute *MRSK.prune.containers + end end end diff --git a/lib/mrsk/cli/traefik.rb b/lib/mrsk/cli/traefik.rb index ca62bbd3..04cb108e 100644 --- a/lib/mrsk/cli/traefik.rb +++ b/lib/mrsk/cli/traefik.rb @@ -15,12 +15,18 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "start", "Start existing Traefik on servers" def start - on(MRSK.traefik_hosts) { execute *MRSK.traefik.start, raise_on_non_zero_exit: false } + on(MRSK.traefik_hosts) do + execute *MRSK.auditor.record("traefik start"), verbosity: :debug + execute *MRSK.traefik.start, raise_on_non_zero_exit: false + end end desc "stop", "Stop Traefik on servers" def stop - on(MRSK.traefik_hosts) { execute *MRSK.traefik.stop, raise_on_non_zero_exit: false } + on(MRSK.traefik_hosts) do + execute *MRSK.auditor.record("traefik stop"), verbosity: :debug + execute *MRSK.traefik.stop, raise_on_non_zero_exit: false + end end desc "restart", "Restart Traefik on servers" @@ -67,11 +73,17 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "remove_container", "Remove Traefik container from servers" def remove_container - on(MRSK.traefik_hosts) { execute *MRSK.traefik.remove_container } + on(MRSK.traefik_hosts) do + execute *MRSK.auditor.record("traefik remove container"), verbosity: :debug + execute *MRSK.traefik.remove_container + end end desc "remove_container", "Remove Traefik image from servers" def remove_image - on(MRSK.traefik_hosts) { execute *MRSK.traefik.remove_image } + on(MRSK.traefik_hosts) do + execute *MRSK.auditor.record("traefik remove image"), verbosity: :debug + execute *MRSK.traefik.remove_image + end end end diff --git a/lib/mrsk/commander.rb b/lib/mrsk/commander.rb index c8d929fd..3dd95941 100644 --- a/lib/mrsk/commander.rb +++ b/lib/mrsk/commander.rb @@ -3,6 +3,7 @@ require "active_support/core_ext/enumerable" require "mrsk/configuration" require "mrsk/commands/accessory" require "mrsk/commands/app" +require "mrsk/commands/auditor" require "mrsk/commands/builder" require "mrsk/commands/prune" require "mrsk/commands/traefik" @@ -77,6 +78,10 @@ class Mrsk::Commander Mrsk::Commands::Accessory.new(config, name: name) end + def auditor + @auditor ||= Mrsk::Commands::Auditor.new(config) + end + def with_verbosity(level) old_level = SSHKit.config.output_verbosity @@ -89,7 +94,7 @@ class Mrsk::Commander # Test-induced damage! def reset @config = @config_file = @destination = @version = nil - @app = @builder = @traefik = @registry = @prune = nil + @app = @builder = @traefik = @registry = @prune = @auditor = nil @verbosity = :info end diff --git a/lib/mrsk/commands/auditor.rb b/lib/mrsk/commands/auditor.rb new file mode 100644 index 00000000..28267463 --- /dev/null +++ b/lib/mrsk/commands/auditor.rb @@ -0,0 +1,31 @@ +require "active_support/core_ext/time/conversions" +require "mrsk/commands/base" + +class Mrsk::Commands::Auditor < Mrsk::Commands::Base + def record(line) + append \ + [ :echo, "'#{tags} #{line}'" ], + audit_log_file + end + + def reveal + [ :tail, "-n", 50, audit_log_file ] + end + + private + def audit_log_file + "mrsk-#{config.service}-audit.log" + end + + def tags + "[#{timestamp}] [#{performer}]" + end + + def performer + `whoami`.strip + end + + def timestamp + Time.now.to_fs(:db) + end +end diff --git a/lib/mrsk/commands/base.rb b/lib/mrsk/commands/base.rb index 44c1807f..9c0bd1c7 100644 --- a/lib/mrsk/commands/base.rb +++ b/lib/mrsk/commands/base.rb @@ -28,6 +28,10 @@ module Mrsk::Commands combine *commands, by: "|" end + def append(*commands) + combine *commands, by: ">>" + end + def xargs(command) [ :xargs, command ].flatten end