mrsk 0.10.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +130 -18
- data/lib/mrsk/cli/app.rb +58 -16
- data/lib/mrsk/cli/base.rb +39 -18
- data/lib/mrsk/cli/build.rb +23 -1
- data/lib/mrsk/cli/healthcheck.rb +3 -34
- data/lib/mrsk/cli/lock.rb +2 -2
- data/lib/mrsk/cli/main.rb +58 -25
- data/lib/mrsk/cli/prune.rb +2 -2
- data/lib/mrsk/cli/server.rb +13 -9
- data/lib/mrsk/cli/traefik.rb +5 -2
- data/lib/mrsk/cli.rb +1 -0
- data/lib/mrsk/commander.rb +24 -3
- data/lib/mrsk/commands/app.rb +25 -12
- data/lib/mrsk/commands/base.rb +3 -1
- data/lib/mrsk/commands/builder/base.rb +10 -3
- data/lib/mrsk/commands/builder.rb +21 -1
- data/lib/mrsk/commands/docker.rb +21 -0
- data/lib/mrsk/commands/healthcheck.rb +3 -2
- data/lib/mrsk/commands/prune.rb +12 -4
- data/lib/mrsk/commands/registry.rb +1 -1
- data/lib/mrsk/commands/traefik.rb +16 -3
- data/lib/mrsk/configuration/boot.rb +20 -0
- data/lib/mrsk/configuration/role.rb +30 -6
- data/lib/mrsk/configuration.rb +7 -1
- data/lib/mrsk/sshkit_with_ext.rb +2 -2
- data/lib/mrsk/utils/healthcheck_poller.rb +39 -0
- data/lib/mrsk/utils/sensitive.rb +19 -0
- data/lib/mrsk/utils.rb +41 -8
- data/lib/mrsk/version.rb +1 -1
- metadata +21 -3
data/lib/mrsk/configuration.rb
CHANGED
@@ -87,6 +87,10 @@ class Mrsk::Configuration
|
|
87
87
|
roles.select(&:running_traefik?).flat_map(&:hosts).uniq
|
88
88
|
end
|
89
89
|
|
90
|
+
def boot
|
91
|
+
Mrsk::Configuration::Boot.new(config: self)
|
92
|
+
end
|
93
|
+
|
90
94
|
|
91
95
|
def repository
|
92
96
|
[ raw_config.registry["server"], image ].compact.join("/")
|
@@ -143,6 +147,8 @@ class Mrsk::Configuration
|
|
143
147
|
if raw_config.ssh.present? && raw_config.ssh["proxy"]
|
144
148
|
Net::SSH::Proxy::Jump.new \
|
145
149
|
raw_config.ssh["proxy"].include?("@") ? raw_config.ssh["proxy"] : "root@#{raw_config.ssh["proxy"]}"
|
150
|
+
elsif raw_config.ssh.present? && raw_config.ssh["proxy_command"]
|
151
|
+
Net::SSH::Proxy::Command.new(raw_config.ssh["proxy_command"])
|
146
152
|
end
|
147
153
|
end
|
148
154
|
|
@@ -156,7 +162,7 @@ class Mrsk::Configuration
|
|
156
162
|
end
|
157
163
|
|
158
164
|
def healthcheck
|
159
|
-
{ "path" => "/up", "port" => 3000 }.merge(raw_config.healthcheck || {})
|
165
|
+
{ "path" => "/up", "port" => 3000, "max_attempts" => 7 }.merge(raw_config.healthcheck || {})
|
160
166
|
end
|
161
167
|
|
162
168
|
def readiness_delay
|
data/lib/mrsk/sshkit_with_ext.rb
CHANGED
@@ -2,8 +2,8 @@ require "sshkit"
|
|
2
2
|
require "sshkit/dsl"
|
3
3
|
|
4
4
|
class SSHKit::Backend::Abstract
|
5
|
-
def capture_with_info(*args)
|
6
|
-
capture(*args, verbosity: Logger::INFO)
|
5
|
+
def capture_with_info(*args, **kwargs)
|
6
|
+
capture(*args, **kwargs, verbosity: Logger::INFO)
|
7
7
|
end
|
8
8
|
|
9
9
|
def puts_by_host(host, output, type: "App")
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Mrsk::Utils::HealthcheckPoller
|
2
|
+
TRAEFIK_HEALTHY_DELAY = 2
|
3
|
+
|
4
|
+
class HealthcheckError < StandardError; end
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def wait_for_healthy(pause_after_ready: false, &block)
|
8
|
+
attempt = 1
|
9
|
+
max_attempts = MRSK.config.healthcheck["max_attempts"]
|
10
|
+
|
11
|
+
begin
|
12
|
+
case status = block.call
|
13
|
+
when "healthy"
|
14
|
+
sleep TRAEFIK_HEALTHY_DELAY if pause_after_ready
|
15
|
+
when "running" # No health check configured
|
16
|
+
sleep MRSK.config.readiness_delay if pause_after_ready
|
17
|
+
else
|
18
|
+
raise HealthcheckError, "container not ready (#{status})"
|
19
|
+
end
|
20
|
+
rescue HealthcheckError => e
|
21
|
+
if attempt <= max_attempts
|
22
|
+
info "#{e.message}, retrying in #{attempt}s (attempt #{attempt}/#{max_attempts})..."
|
23
|
+
sleep attempt
|
24
|
+
attempt += 1
|
25
|
+
retry
|
26
|
+
else
|
27
|
+
raise
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
info "Container is healthy!"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def info(message)
|
36
|
+
SSHKit.config.output.info(message)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "active_support/core_ext/module/delegation"
|
2
|
+
|
3
|
+
class Mrsk::Utils::Sensitive
|
4
|
+
# So SSHKit knows to redact these values.
|
5
|
+
include SSHKit::Redaction
|
6
|
+
|
7
|
+
attr_reader :unredacted, :redaction
|
8
|
+
delegate :to_s, to: :unredacted
|
9
|
+
delegate :inspect, to: :redaction
|
10
|
+
|
11
|
+
def initialize(value, redaction: "[REDACTED]")
|
12
|
+
@unredacted, @redaction = value, redaction
|
13
|
+
end
|
14
|
+
|
15
|
+
# Sensitive values won't leak into YAML output.
|
16
|
+
def encode_with(coder)
|
17
|
+
coder.represent_scalar nil, redaction
|
18
|
+
end
|
19
|
+
end
|
data/lib/mrsk/utils.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
module Mrsk::Utils
|
2
2
|
extend self
|
3
3
|
|
4
|
+
DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX = /\$(?!{[^\}]*\})/
|
5
|
+
|
4
6
|
# Return a list of escaped shell arguments using the same named argument against the passed attributes (hash or array).
|
5
|
-
def argumentize(argument, attributes,
|
7
|
+
def argumentize(argument, attributes, sensitive: false)
|
6
8
|
Array(attributes).flat_map do |key, value|
|
7
9
|
if value.present?
|
8
|
-
|
9
|
-
|
10
|
+
attr = "#{key}=#{escape_shell_value(value)}"
|
11
|
+
attr = self.sensitive(attr, redaction: "#{key}=[REDACTED]") if sensitive
|
12
|
+
[ argument, attr]
|
10
13
|
else
|
11
14
|
[ argument, key ]
|
12
15
|
end
|
@@ -17,7 +20,7 @@ module Mrsk::Utils
|
|
17
20
|
# but redacts and expands secrets.
|
18
21
|
def argumentize_env_with_secrets(env)
|
19
22
|
if (secrets = env["secret"]).present?
|
20
|
-
argumentize("-e", secrets.to_h { |key| [ key, ENV.fetch(key) ] },
|
23
|
+
argumentize("-e", secrets.to_h { |key| [ key, ENV.fetch(key) ] }, sensitive: true) + argumentize("-e", env["clear"])
|
21
24
|
else
|
22
25
|
argumentize "-e", env.fetch("clear", env)
|
23
26
|
end
|
@@ -39,14 +42,44 @@ module Mrsk::Utils
|
|
39
42
|
args.flat_map { |key, value| value.try(:map) { |entry| [key, entry] } || [ [ key, value ] ] }
|
40
43
|
end
|
41
44
|
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
+
# Marks sensitive values for redaction in logs and human-visible output.
|
46
|
+
# Pass `redaction:` to change the default `"[REDACTED]"` redaction, e.g.
|
47
|
+
# `sensitive "#{arg}=#{secret}", redaction: "#{arg}=xxxx"
|
48
|
+
def sensitive(...)
|
49
|
+
Mrsk::Utils::Sensitive.new(...)
|
50
|
+
end
|
51
|
+
|
52
|
+
def redacted(value)
|
53
|
+
case
|
54
|
+
when value.respond_to?(:redaction)
|
55
|
+
value.redaction
|
56
|
+
when value.respond_to?(:transform_values)
|
57
|
+
value.transform_values { |value| redacted value }
|
58
|
+
when value.respond_to?(:map)
|
59
|
+
value.map { |element| redacted element }
|
60
|
+
else
|
61
|
+
value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def unredacted(value)
|
66
|
+
case
|
67
|
+
when value.respond_to?(:unredacted)
|
68
|
+
value.unredacted
|
69
|
+
when value.respond_to?(:transform_values)
|
70
|
+
value.transform_values { |value| unredacted value }
|
71
|
+
when value.respond_to?(:map)
|
72
|
+
value.map { |element| unredacted element }
|
73
|
+
else
|
74
|
+
value
|
75
|
+
end
|
45
76
|
end
|
46
77
|
|
47
78
|
# Escape a value to make it safe for shell use.
|
48
79
|
def escape_shell_value(value)
|
49
|
-
value.to_s.dump
|
80
|
+
value.to_s.dump
|
81
|
+
.gsub(/`/, '\\\\`')
|
82
|
+
.gsub(DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX, '\$')
|
50
83
|
end
|
51
84
|
|
52
85
|
# Abbreviate a git revhash for concise display
|
data/lib/mrsk/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mrsk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.21'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: net-ssh
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '7.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '7.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: thor
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -187,6 +201,7 @@ files:
|
|
187
201
|
- lib/mrsk/commands/builder/multiarch/remote.rb
|
188
202
|
- lib/mrsk/commands/builder/native.rb
|
189
203
|
- lib/mrsk/commands/builder/native/remote.rb
|
204
|
+
- lib/mrsk/commands/docker.rb
|
190
205
|
- lib/mrsk/commands/healthcheck.rb
|
191
206
|
- lib/mrsk/commands/lock.rb
|
192
207
|
- lib/mrsk/commands/prune.rb
|
@@ -194,9 +209,12 @@ files:
|
|
194
209
|
- lib/mrsk/commands/traefik.rb
|
195
210
|
- lib/mrsk/configuration.rb
|
196
211
|
- lib/mrsk/configuration/accessory.rb
|
212
|
+
- lib/mrsk/configuration/boot.rb
|
197
213
|
- lib/mrsk/configuration/role.rb
|
198
214
|
- lib/mrsk/sshkit_with_ext.rb
|
199
215
|
- lib/mrsk/utils.rb
|
216
|
+
- lib/mrsk/utils/healthcheck_poller.rb
|
217
|
+
- lib/mrsk/utils/sensitive.rb
|
200
218
|
- lib/mrsk/version.rb
|
201
219
|
homepage: https://github.com/rails/mrsk
|
202
220
|
licenses:
|
@@ -217,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
235
|
- !ruby/object:Gem::Version
|
218
236
|
version: '0'
|
219
237
|
requirements: []
|
220
|
-
rubygems_version: 3.4.
|
238
|
+
rubygems_version: 3.4.10
|
221
239
|
signing_key:
|
222
240
|
specification_version: 4
|
223
241
|
summary: Deploy web apps in containers to servers running Docker with zero downtime.
|