mrsk 0.10.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|