mrsk 0.3.1 → 0.4.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 +21 -0
- data/bin/mrsk +4 -0
- data/lib/mrsk/cli/accessory.rb +23 -5
- data/lib/mrsk/cli/app.rb +1 -1
- data/lib/mrsk/cli/base.rb +10 -1
- data/lib/mrsk/cli/build.rb +2 -3
- data/lib/mrsk/cli/traefik.rb +1 -1
- data/lib/mrsk/commander.rb +5 -5
- data/lib/mrsk/commands/accessory.rb +12 -10
- data/lib/mrsk/commands/app.rb +2 -5
- data/lib/mrsk/commands/base.rb +4 -4
- data/lib/mrsk/commands/traefik.rb +8 -2
- data/lib/mrsk/configuration/accessory.rb +8 -1
- data/lib/mrsk/configuration.rb +18 -1
- data/lib/mrsk/utils.rb +1 -1
- data/lib/mrsk/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b7f4333081763cf001d3891931c1615eeb46bc29c2a8754ec863db67259f542
|
4
|
+
data.tar.gz: 809cc3d35b9c9f445299f3e188cd74b32e504dd7747d7dfcd0b11a698b34ebf9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 675b6e985621e236c9a3cde0b19d245bb8ac68ce9ae0ceef68c574c3427b1d8255bcd84f4547f9329eca535994a66b6cc6e88470181ca3ef74ea4e06e1a88244
|
7
|
+
data.tar.gz: 701df3deb670cfcd323a57d0baa5ded62e267657a7ad2198d226c809b89ace6eda46a282146d18123b569db4ef72d996ea487fd157ec8f0f7b639dbb56bf1fa4
|
data/README.md
CHANGED
@@ -46,6 +46,15 @@ Kubernetes is a beast. Running it yourself on your own hardware is not for the f
|
|
46
46
|
|
47
47
|
## Configuration
|
48
48
|
|
49
|
+
### Using .env file to load required environment variables
|
50
|
+
|
51
|
+
MRSK uses [dotenv](https://github.com/bkeepers/dotenv) to automatically load environment variables set in the `.env` file present in the application root. This file can be used to set variables like `MRSK_REGISTRY_PASSWORD` or database passwords. But for this reason you must ensure that .env files are not checked into Git or included in your Dockerfile! The format is just key-value like:
|
52
|
+
|
53
|
+
```bash
|
54
|
+
MRSK_REGISTRY_PASSWORD=pw
|
55
|
+
DB_PASSWORD=secret123
|
56
|
+
```
|
57
|
+
|
49
58
|
### Using another registry than Docker Hub
|
50
59
|
|
51
60
|
The default registry is Docker Hub, but you can change it using `registry/server`:
|
@@ -226,6 +235,18 @@ RUN --mount=type=secret,id=GITHUB_TOKEN \
|
|
226
235
|
bundle install
|
227
236
|
```
|
228
237
|
|
238
|
+
### Using command arguments for Traefik
|
239
|
+
|
240
|
+
You can customize the traefik command line:
|
241
|
+
|
242
|
+
```yaml
|
243
|
+
traefik:
|
244
|
+
accesslog: true
|
245
|
+
accesslog.format: json
|
246
|
+
metrics.prometheus: true
|
247
|
+
metrics.prometheus.buckets: 0.1,0.3,1.2,5.0
|
248
|
+
```
|
249
|
+
|
229
250
|
### Configuring build args for new images
|
230
251
|
|
231
252
|
Build arguments that aren't secret can also be configured:
|
data/bin/mrsk
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
# Prevent failures from being reported twice.
|
4
4
|
Thread.report_on_exception = false
|
5
5
|
|
6
|
+
require "dotenv/load"
|
6
7
|
require "mrsk/cli"
|
7
8
|
|
8
9
|
begin
|
@@ -10,4 +11,7 @@ begin
|
|
10
11
|
rescue SSHKit::Runner::ExecuteError => e
|
11
12
|
puts " \e[31mERROR (#{e.cause.class}): #{e.cause.message}\e[0m"
|
12
13
|
puts e.cause.backtrace if ENV["VERBOSE"]
|
14
|
+
rescue => e
|
15
|
+
puts " \e[31mERROR (#{e.class}): #{e.message}\e[0m"
|
16
|
+
puts e.backtrace if ENV["VERBOSE"]
|
13
17
|
end
|
data/lib/mrsk/cli/accessory.rb
CHANGED
@@ -83,11 +83,29 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
83
83
|
end
|
84
84
|
|
85
85
|
desc "exec [NAME] [CMD]", "Execute a custom command on accessory host"
|
86
|
-
option :
|
86
|
+
option :method, aliases: "-m", default: "exec", desc: "Execution method: [exec] perform inside container / [run] perform in new container / [ssh] perform over ssh"
|
87
87
|
def exec(name, cmd)
|
88
|
+
runner = \
|
89
|
+
case options[:method]
|
90
|
+
when "exec" then "exec"
|
91
|
+
when "run" then "run_exec"
|
92
|
+
when "ssh_exec" then "exec_over_ssh"
|
93
|
+
when "ssh_run" then "run_over_ssh"
|
94
|
+
else raise "Unknown method: #{options[:method]}"
|
95
|
+
end.inquiry
|
96
|
+
|
88
97
|
with_accessory(name) do |accessory|
|
89
|
-
runner
|
90
|
-
|
98
|
+
if runner.exec_over_ssh? || runner.run_over_ssh?
|
99
|
+
run_locally do
|
100
|
+
info "Launching command on #{accessory.host}"
|
101
|
+
exec accessory.send(runner, cmd)
|
102
|
+
end
|
103
|
+
else
|
104
|
+
on(accessory.host) do
|
105
|
+
info "Launching command on #{accessory.host}"
|
106
|
+
execute *accessory.send(runner, cmd)
|
107
|
+
end
|
108
|
+
end
|
91
109
|
end
|
92
110
|
end
|
93
111
|
|
@@ -96,7 +114,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
96
114
|
with_accessory(name) do |accessory|
|
97
115
|
run_locally do
|
98
116
|
info "Launching bash session on #{accessory.host}"
|
99
|
-
exec accessory.bash
|
117
|
+
exec accessory.bash
|
100
118
|
end
|
101
119
|
end
|
102
120
|
end
|
@@ -118,7 +136,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
118
136
|
end
|
119
137
|
else
|
120
138
|
since = options[:since]
|
121
|
-
lines = options[:lines]
|
139
|
+
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
122
140
|
|
123
141
|
on(accessory.host) do
|
124
142
|
puts capture_with_info(*accessory.logs(since: since, lines: lines, grep: grep))
|
data/lib/mrsk/cli/app.rb
CHANGED
@@ -109,7 +109,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
109
109
|
end
|
110
110
|
else
|
111
111
|
since = options[:since]
|
112
|
-
lines = options[:lines]
|
112
|
+
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
113
113
|
|
114
114
|
on(MRSK.hosts) do |host|
|
115
115
|
begin
|
data/lib/mrsk/cli/base.rb
CHANGED
@@ -8,6 +8,7 @@ module Mrsk::Cli
|
|
8
8
|
def self.exit_on_failure?() true end
|
9
9
|
|
10
10
|
class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging"
|
11
|
+
class_option :quiet, type: :boolean, aliases: "-q", desc: "Minimal logging"
|
11
12
|
|
12
13
|
class_option :version, desc: "Run commands against a specific app version"
|
13
14
|
|
@@ -28,12 +29,20 @@ module Mrsk::Cli
|
|
28
29
|
MRSK.tap do |commander|
|
29
30
|
commander.config_file = Pathname.new(File.expand_path(options[:config_file]))
|
30
31
|
commander.destination = options[:destination]
|
31
|
-
commander.verbose = options[:verbose]
|
32
32
|
commander.version = options[:version]
|
33
33
|
|
34
34
|
commander.specific_hosts = options[:hosts]&.split(",")
|
35
35
|
commander.specific_roles = options[:roles]&.split(",")
|
36
36
|
commander.specific_primary! if options[:primary]
|
37
|
+
|
38
|
+
if options[:verbose]
|
39
|
+
ENV["VERBOSE"] = "1" # For backtraces via cli/start
|
40
|
+
commander.verbosity = :debug
|
41
|
+
end
|
42
|
+
|
43
|
+
if options[:quiet]
|
44
|
+
commander.verbosity = :error
|
45
|
+
end
|
37
46
|
end
|
38
47
|
end
|
39
48
|
|
data/lib/mrsk/cli/build.rb
CHANGED
@@ -9,18 +9,17 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base
|
|
9
9
|
|
10
10
|
desc "push", "Build locally and push app image to registry"
|
11
11
|
def push
|
12
|
-
verbose = options[:verbose]
|
13
12
|
cli = self
|
14
13
|
|
15
14
|
run_locally do
|
16
15
|
begin
|
17
|
-
MRSK.
|
16
|
+
MRSK.with_verbosity(:debug) { execute *MRSK.builder.push }
|
18
17
|
rescue SSHKit::Command::Failed => e
|
19
18
|
if e.message =~ /(no builder)|(no such file or directory)/
|
20
19
|
error "Missing compatible builder, so creating a new one first"
|
21
20
|
|
22
21
|
if cli.create
|
23
|
-
MRSK.
|
22
|
+
MRSK.with_verbosity(:debug) { execute *MRSK.builder.push }
|
24
23
|
end
|
25
24
|
else
|
26
25
|
raise
|
data/lib/mrsk/cli/traefik.rb
CHANGED
@@ -50,7 +50,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
|
50
50
|
end
|
51
51
|
else
|
52
52
|
since = options[:since]
|
53
|
-
lines = options[:lines]
|
53
|
+
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
54
54
|
|
55
55
|
on(MRSK.traefik_hosts) do |host|
|
56
56
|
puts_by_host host, capture(*MRSK.traefik.logs(since: since, lines: lines, grep: grep)), type: "Traefik"
|
data/lib/mrsk/commander.rb
CHANGED
@@ -9,10 +9,10 @@ require "mrsk/commands/traefik"
|
|
9
9
|
require "mrsk/commands/registry"
|
10
10
|
|
11
11
|
class Mrsk::Commander
|
12
|
-
attr_accessor :config_file, :destination, :
|
12
|
+
attr_accessor :config_file, :destination, :verbosity, :version
|
13
13
|
|
14
|
-
def initialize(config_file: nil, destination: nil,
|
15
|
-
@config_file, @destination, @
|
14
|
+
def initialize(config_file: nil, destination: nil, verbosity: :info)
|
15
|
+
@config_file, @destination, @verbosity = config_file, destination, verbosity
|
16
16
|
end
|
17
17
|
|
18
18
|
def config
|
@@ -78,7 +78,7 @@ class Mrsk::Commander
|
|
78
78
|
end
|
79
79
|
|
80
80
|
|
81
|
-
def
|
81
|
+
def with_verbosity(level)
|
82
82
|
old_level = SSHKit.config.output_verbosity
|
83
83
|
SSHKit.config.output_verbosity = level
|
84
84
|
yield
|
@@ -95,6 +95,6 @@ class Mrsk::Commander
|
|
95
95
|
def configure_sshkit_with(config)
|
96
96
|
SSHKit::Backend::Netssh.configure { |ssh| ssh.ssh_options = config.ssh_options }
|
97
97
|
SSHKit.config.command_map[:docker] = "docker" # No need to use /usr/bin/env, just clogs up the logs
|
98
|
-
SSHKit.config.output_verbosity =
|
98
|
+
SSHKit.config.output_verbosity = verbosity
|
99
99
|
end
|
100
100
|
end
|
@@ -42,15 +42,13 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
|
42
42
|
def follow_logs(grep: nil)
|
43
43
|
run_over_ssh pipe(
|
44
44
|
docker(:logs, service_name, "-t", "-n", "10", "-f", "2>&1"),
|
45
|
-
(
|
46
|
-
).join(" ")
|
45
|
+
(%(grep "#{grep}") if grep)
|
46
|
+
).join(" ")
|
47
47
|
end
|
48
48
|
|
49
49
|
def exec(*command, interactive: false)
|
50
50
|
docker :exec,
|
51
51
|
("-it" if interactive),
|
52
|
-
*env_args,
|
53
|
-
*volume_args,
|
54
52
|
service_name,
|
55
53
|
*command
|
56
54
|
end
|
@@ -65,8 +63,16 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
|
65
63
|
*command
|
66
64
|
end
|
67
65
|
|
68
|
-
def
|
69
|
-
|
66
|
+
def run_over_ssh(command)
|
67
|
+
super command, host: host
|
68
|
+
end
|
69
|
+
|
70
|
+
def exec_over_ssh(*command)
|
71
|
+
run_over_ssh run_exec(*command, interactive: true).join(" ")
|
72
|
+
end
|
73
|
+
|
74
|
+
def bash
|
75
|
+
exec_over_ssh "bash"
|
70
76
|
end
|
71
77
|
|
72
78
|
def ensure_local_file_present(local_file)
|
@@ -96,10 +102,6 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
|
96
102
|
end
|
97
103
|
|
98
104
|
private
|
99
|
-
def exec_over_ssh(*command, host:)
|
100
|
-
run_over_ssh run_exec(*command, interactive: true).join(" "), host: host
|
101
|
-
end
|
102
|
-
|
103
105
|
def service_filter
|
104
106
|
[ "--filter", "label=service=#{service_name}" ]
|
105
107
|
end
|
data/lib/mrsk/commands/app.rb
CHANGED
@@ -35,16 +35,13 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
35
35
|
def logs(since: nil, lines: nil, grep: nil)
|
36
36
|
pipe \
|
37
37
|
current_container_id,
|
38
|
-
"xargs docker logs#{" --since #{since}" if since}#{" -n #{lines}" if lines}
|
38
|
+
"xargs docker logs#{" --since #{since}" if since}#{" -n #{lines}" if lines} 2>&1",
|
39
39
|
("grep '#{grep}'" if grep)
|
40
40
|
end
|
41
41
|
|
42
42
|
def exec(*command, interactive: false)
|
43
43
|
docker :exec,
|
44
44
|
("-it" if interactive),
|
45
|
-
*rails_master_key_arg,
|
46
|
-
*config.env_args,
|
47
|
-
*config.volume_args,
|
48
45
|
config.service_with_version,
|
49
46
|
*command
|
50
47
|
end
|
@@ -68,7 +65,7 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
68
65
|
run_over_ssh pipe(
|
69
66
|
current_container_id,
|
70
67
|
"xargs docker logs -t -n 10 -f 2>&1",
|
71
|
-
(
|
68
|
+
(%(grep "#{grep}") if grep)
|
72
69
|
).join(" "), host: host
|
73
70
|
end
|
74
71
|
|
data/lib/mrsk/commands/base.rb
CHANGED
@@ -8,6 +8,10 @@ module Mrsk::Commands
|
|
8
8
|
@config = config
|
9
9
|
end
|
10
10
|
|
11
|
+
def run_over_ssh(command, host:)
|
12
|
+
"ssh -t #{config.ssh_user}@#{host} '#{command}'"
|
13
|
+
end
|
14
|
+
|
11
15
|
private
|
12
16
|
def combine(*commands, by: "&&")
|
13
17
|
commands
|
@@ -27,9 +31,5 @@ module Mrsk::Commands
|
|
27
31
|
def docker(*args)
|
28
32
|
args.compact.unshift :docker
|
29
33
|
end
|
30
|
-
|
31
|
-
def run_over_ssh(command, host:)
|
32
|
-
"ssh -t #{config.ssh_user}@#{host} '#{command}'"
|
33
|
-
end
|
34
34
|
end
|
35
35
|
end
|
@@ -9,7 +9,8 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
|
|
9
9
|
"-v /var/run/docker.sock:/var/run/docker.sock",
|
10
10
|
"traefik",
|
11
11
|
"--providers.docker",
|
12
|
-
"--log.level=DEBUG"
|
12
|
+
"--log.level=DEBUG",
|
13
|
+
*cmd_args
|
13
14
|
end
|
14
15
|
|
15
16
|
def start
|
@@ -33,7 +34,7 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
|
|
33
34
|
def follow_logs(host:, grep: nil)
|
34
35
|
run_over_ssh pipe(
|
35
36
|
docker(:logs, "traefik", "-t", "-n", "10", "-f", "2>&1"),
|
36
|
-
(
|
37
|
+
(%(grep "#{grep}") if grep)
|
37
38
|
).join(" "), host: host
|
38
39
|
end
|
39
40
|
|
@@ -44,4 +45,9 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
|
|
44
45
|
def remove_image
|
45
46
|
docker :image, :prune, "-a", "-f", "--filter", "label=org.opencontainers.image.title=Traefik"
|
46
47
|
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def cmd_args
|
51
|
+
(config.raw_config.dig(:traefik, "args") || { }).collect { |(key, value)| [ "--#{key}", value ] }.flatten
|
52
|
+
end
|
47
53
|
end
|
@@ -74,12 +74,19 @@ class Mrsk::Configuration::Assessory
|
|
74
74
|
|
75
75
|
def expand_local_file(local_file)
|
76
76
|
if local_file.end_with?("erb")
|
77
|
-
read_dynamic_file(local_file)
|
77
|
+
with_clear_env_loaded { read_dynamic_file(local_file) }
|
78
78
|
else
|
79
79
|
Pathname.new(File.expand_path(local_file)).to_s
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
+
def with_clear_env_loaded
|
84
|
+
(env["clear"] || env).each { |k, v| ENV[k] = v }
|
85
|
+
yield
|
86
|
+
ensure
|
87
|
+
(env["clear"] || env).each { |k, v| ENV.delete(k) }
|
88
|
+
end
|
89
|
+
|
83
90
|
def read_dynamic_file(local_file)
|
84
91
|
StringIO.new(ERB.new(IO.read(local_file)).result)
|
85
92
|
end
|
data/lib/mrsk/configuration.rb
CHANGED
@@ -39,7 +39,7 @@ class Mrsk::Configuration
|
|
39
39
|
def initialize(raw_config, version: "missing", validate: true)
|
40
40
|
@raw_config = ActiveSupport::InheritableOptions.new(raw_config)
|
41
41
|
@version = version
|
42
|
-
|
42
|
+
valid? if validate
|
43
43
|
end
|
44
44
|
|
45
45
|
|
@@ -120,6 +120,12 @@ class Mrsk::Configuration
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
+
|
124
|
+
def valid?
|
125
|
+
ensure_required_keys_present && ensure_env_available
|
126
|
+
end
|
127
|
+
|
128
|
+
|
123
129
|
def to_h
|
124
130
|
{
|
125
131
|
roles: role_names,
|
@@ -139,6 +145,7 @@ class Mrsk::Configuration
|
|
139
145
|
|
140
146
|
|
141
147
|
private
|
148
|
+
# Will raise ArgumentError if any required config keys are missing
|
142
149
|
def ensure_required_keys_present
|
143
150
|
%i[ service image registry servers ].each do |key|
|
144
151
|
raise ArgumentError, "Missing required configuration for #{key}" unless raw_config[key].present?
|
@@ -151,6 +158,16 @@ class Mrsk::Configuration
|
|
151
158
|
if raw_config.registry["password"].blank?
|
152
159
|
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
|
153
160
|
end
|
161
|
+
|
162
|
+
true
|
163
|
+
end
|
164
|
+
|
165
|
+
# Will raise KeyError if any secret ENVs are missing
|
166
|
+
def ensure_env_available
|
167
|
+
env_args
|
168
|
+
roles.each(&:env_args)
|
169
|
+
|
170
|
+
true
|
154
171
|
end
|
155
172
|
|
156
173
|
def role_names
|
data/lib/mrsk/utils.rb
CHANGED
@@ -18,7 +18,7 @@ module Mrsk::Utils
|
|
18
18
|
if (secrets = env["secret"]).present?
|
19
19
|
argumentize("-e", secrets.to_h { |key| [ key, ENV.fetch(key) ] }, redacted: true) + argumentize("-e", env["clear"])
|
20
20
|
else
|
21
|
-
argumentize "-e", env
|
21
|
+
argumentize "-e", env.fetch("clear", env)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
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.4.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-01
|
11
|
+
date: 2023-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: dotenv
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.8'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.8'
|
55
69
|
description:
|
56
70
|
email: dhh@hey.com
|
57
71
|
executables:
|