mrsk 0.13.2 → 0.14.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 +41 -0
- data/lib/mrsk/cli/accessory.rb +11 -11
- data/lib/mrsk/cli/app.rb +8 -8
- data/lib/mrsk/cli/base.rb +16 -16
- data/lib/mrsk/cli/build.rb +5 -5
- data/lib/mrsk/cli/main.rb +5 -5
- data/lib/mrsk/cli/prune.rb +3 -3
- data/lib/mrsk/cli/templates/sample_hooks/pre-deploy.sample +49 -22
- data/lib/mrsk/cli/traefik.rb +8 -8
- data/lib/mrsk/commands/base.rb +5 -1
- data/lib/mrsk/commands/builder/base.rb +12 -16
- data/lib/mrsk/commands/builder/multiarch/remote.rb +6 -14
- data/lib/mrsk/commands/builder/native/cached.rb +16 -0
- data/lib/mrsk/commands/builder/native/remote.rb +3 -11
- data/lib/mrsk/commands/builder/native.rb +2 -2
- data/lib/mrsk/commands/builder.rb +9 -3
- data/lib/mrsk/commands/traefik.rb +5 -3
- data/lib/mrsk/configuration/builder.rb +114 -0
- data/lib/mrsk/configuration.rb +24 -7
- data/lib/mrsk/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39d645ed2ca51ebf7edeaca7502b9b9d83456ad4fd11d5b905903de2ee76f189
|
4
|
+
data.tar.gz: c8fe80b16c14e89fd333224b887968620a88741c32a8b7cb4ee1cf9c37c1dcd5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa4264e442bc470b02ebd946b4667535b9e5e8795cf9cb22c311693f381a0a9671c67d16dd6f1ae6391e48b8e7b2be51fc49671bccd2610e3ec98afd75002a12
|
7
|
+
data.tar.gz: 408f3500ff87847217b08f21c86a189b77e73f54d3b1a407a7e16a9f73fea20a883233cf8970f9f5fb6b6ebdcd69d3a47ec5006e42b7190cffd41c1c5b9bfb60
|
data/README.md
CHANGED
@@ -380,6 +380,16 @@ servers:
|
|
380
380
|
|
381
381
|
That'll start the job containers with `docker run ... --cap-add --cpu-count 4 ...`.
|
382
382
|
|
383
|
+
### Setting a minimum version
|
384
|
+
|
385
|
+
You can set the minimum MRSK version with:
|
386
|
+
|
387
|
+
```yaml
|
388
|
+
minimum_version: 0.13.3
|
389
|
+
```
|
390
|
+
|
391
|
+
Note: versions <= 0.13.2 will ignore this setting.
|
392
|
+
|
383
393
|
### Configuring logging
|
384
394
|
|
385
395
|
You can configure the logging driver and options passed to Docker using `logging`:
|
@@ -463,6 +473,37 @@ builder:
|
|
463
473
|
context: ".."
|
464
474
|
```
|
465
475
|
|
476
|
+
### Using multistage builder cache
|
477
|
+
|
478
|
+
Docker multistage build cache can singlehandedly speed up your builds by a lot. Currently MRSK only supports using the GHA cache or the Registry cache:
|
479
|
+
|
480
|
+
```yaml
|
481
|
+
# Using GHA cache
|
482
|
+
builder:
|
483
|
+
cache:
|
484
|
+
type: gha
|
485
|
+
|
486
|
+
# Using Registry cache
|
487
|
+
builder:
|
488
|
+
cache:
|
489
|
+
type: registry
|
490
|
+
|
491
|
+
# Using Registry cache with different cache image
|
492
|
+
builder:
|
493
|
+
cache:
|
494
|
+
type: registry
|
495
|
+
# default image name is <image>-build-cache
|
496
|
+
image: application-cache-image
|
497
|
+
|
498
|
+
# Using Registry cache with additinonal cache-to options
|
499
|
+
builder:
|
500
|
+
cache:
|
501
|
+
type: registry
|
502
|
+
options: mode=max,image-manifest=true,oci-mediatypes=true
|
503
|
+
```
|
504
|
+
|
505
|
+
For further insights into build cache optimization, check out documentation on Docker's official website: https://docs.docker.com/build/cache/.
|
506
|
+
|
466
507
|
### Using build secrets for new images
|
467
508
|
|
468
509
|
Some images need a secret passed in during build time, like a GITHUB_TOKEN, to give access to private gem repositories. This can be done by having the secret in ENV, then referencing it in the builder configuration:
|
data/lib/mrsk/cli/accessory.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
2
2
|
desc "boot [NAME]", "Boot new accessory service on host (use NAME=all to boot all accessories)"
|
3
3
|
def boot(name)
|
4
|
-
|
4
|
+
mutating do
|
5
5
|
if name == "all"
|
6
6
|
MRSK.accessory_names.each { |accessory_name| boot(accessory_name) }
|
7
7
|
else
|
@@ -21,7 +21,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
21
21
|
|
22
22
|
desc "upload [NAME]", "Upload accessory files to host", hide: true
|
23
23
|
def upload(name)
|
24
|
-
|
24
|
+
mutating do
|
25
25
|
with_accessory(name) do |accessory|
|
26
26
|
on(accessory.hosts) do
|
27
27
|
accessory.files.each do |(local, remote)|
|
@@ -38,7 +38,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
38
38
|
|
39
39
|
desc "directories [NAME]", "Create accessory directories on host", hide: true
|
40
40
|
def directories(name)
|
41
|
-
|
41
|
+
mutating do
|
42
42
|
with_accessory(name) do |accessory|
|
43
43
|
on(accessory.hosts) do
|
44
44
|
accessory.directories.keys.each do |host_path|
|
@@ -51,7 +51,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
51
51
|
|
52
52
|
desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container)"
|
53
53
|
def reboot(name)
|
54
|
-
|
54
|
+
mutating do
|
55
55
|
with_accessory(name) do |accessory|
|
56
56
|
stop(name)
|
57
57
|
remove_container(name)
|
@@ -62,7 +62,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
62
62
|
|
63
63
|
desc "start [NAME]", "Start existing accessory container on host"
|
64
64
|
def start(name)
|
65
|
-
|
65
|
+
mutating do
|
66
66
|
with_accessory(name) do |accessory|
|
67
67
|
on(accessory.hosts) do
|
68
68
|
execute *MRSK.auditor.record("Started #{name} accessory"), verbosity: :debug
|
@@ -74,7 +74,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
74
74
|
|
75
75
|
desc "stop [NAME]", "Stop existing accessory container on host"
|
76
76
|
def stop(name)
|
77
|
-
|
77
|
+
mutating do
|
78
78
|
with_accessory(name) do |accessory|
|
79
79
|
on(accessory.hosts) do
|
80
80
|
execute *MRSK.auditor.record("Stopped #{name} accessory"), verbosity: :debug
|
@@ -86,7 +86,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
86
86
|
|
87
87
|
desc "restart [NAME]", "Restart existing accessory container on host"
|
88
88
|
def restart(name)
|
89
|
-
|
89
|
+
mutating do
|
90
90
|
with_accessory(name) do
|
91
91
|
stop(name)
|
92
92
|
start(name)
|
@@ -165,7 +165,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
165
165
|
desc "remove [NAME]", "Remove accessory container, image and data directory from host (use NAME=all to remove all accessories)"
|
166
166
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
167
167
|
def remove(name)
|
168
|
-
|
168
|
+
mutating do
|
169
169
|
if name == "all"
|
170
170
|
MRSK.accessory_names.each { |accessory_name| remove(accessory_name) }
|
171
171
|
else
|
@@ -183,7 +183,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
183
183
|
|
184
184
|
desc "remove_container [NAME]", "Remove accessory container from host", hide: true
|
185
185
|
def remove_container(name)
|
186
|
-
|
186
|
+
mutating do
|
187
187
|
with_accessory(name) do |accessory|
|
188
188
|
on(accessory.hosts) do
|
189
189
|
execute *MRSK.auditor.record("Remove #{name} accessory container"), verbosity: :debug
|
@@ -195,7 +195,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
195
195
|
|
196
196
|
desc "remove_image [NAME]", "Remove accessory image from host", hide: true
|
197
197
|
def remove_image(name)
|
198
|
-
|
198
|
+
mutating do
|
199
199
|
with_accessory(name) do |accessory|
|
200
200
|
on(accessory.hosts) do
|
201
201
|
execute *MRSK.auditor.record("Removed #{name} accessory image"), verbosity: :debug
|
@@ -207,7 +207,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|
207
207
|
|
208
208
|
desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host", hide: true
|
209
209
|
def remove_service_directory(name)
|
210
|
-
|
210
|
+
mutating do
|
211
211
|
with_accessory(name) do |accessory|
|
212
212
|
on(accessory.hosts) do
|
213
213
|
execute *accessory.remove_service_directory
|
data/lib/mrsk/cli/app.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Mrsk::Cli::App < Mrsk::Cli::Base
|
2
2
|
desc "boot", "Boot app on servers (or reboot app if already running)"
|
3
3
|
def boot
|
4
|
-
|
4
|
+
mutating do
|
5
5
|
hold_lock_on_error do
|
6
6
|
say "Get most recent version available as an image...", :magenta unless options[:version]
|
7
7
|
using_version(version_or_latest) do |version|
|
@@ -43,7 +43,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
43
43
|
|
44
44
|
desc "start", "Start existing app container on servers"
|
45
45
|
def start
|
46
|
-
|
46
|
+
mutating do
|
47
47
|
on(MRSK.hosts) do |host|
|
48
48
|
roles = MRSK.roles_on(host)
|
49
49
|
|
@@ -57,7 +57,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
57
57
|
|
58
58
|
desc "stop", "Stop app container on servers"
|
59
59
|
def stop
|
60
|
-
|
60
|
+
mutating do
|
61
61
|
on(MRSK.hosts) do |host|
|
62
62
|
roles = MRSK.roles_on(host)
|
63
63
|
|
@@ -135,7 +135,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
135
135
|
desc "stale_containers", "Detect app stale containers"
|
136
136
|
option :stop, aliases: "-s", type: :boolean, default: false, desc: "Stop the stale containers found"
|
137
137
|
def stale_containers
|
138
|
-
|
138
|
+
mutating do
|
139
139
|
stop = options[:stop]
|
140
140
|
|
141
141
|
cli = self
|
@@ -202,7 +202,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
202
202
|
|
203
203
|
desc "remove", "Remove app containers and images from servers"
|
204
204
|
def remove
|
205
|
-
|
205
|
+
mutating do
|
206
206
|
stop
|
207
207
|
remove_containers
|
208
208
|
remove_images
|
@@ -211,7 +211,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
211
211
|
|
212
212
|
desc "remove_container [VERSION]", "Remove app container with given version from servers", hide: true
|
213
213
|
def remove_container(version)
|
214
|
-
|
214
|
+
mutating do
|
215
215
|
on(MRSK.hosts) do |host|
|
216
216
|
roles = MRSK.roles_on(host)
|
217
217
|
|
@@ -225,7 +225,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
225
225
|
|
226
226
|
desc "remove_containers", "Remove all app containers from servers", hide: true
|
227
227
|
def remove_containers
|
228
|
-
|
228
|
+
mutating do
|
229
229
|
on(MRSK.hosts) do |host|
|
230
230
|
roles = MRSK.roles_on(host)
|
231
231
|
|
@@ -239,7 +239,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
|
|
239
239
|
|
240
240
|
desc "remove_images", "Remove all app images from servers", hide: true
|
241
241
|
def remove_images
|
242
|
-
|
242
|
+
mutating do
|
243
243
|
on(MRSK.hosts) do
|
244
244
|
execute *MRSK.auditor.record("Removed all app images"), verbosity: :debug
|
245
245
|
execute *MRSK.app.remove_images
|
data/lib/mrsk/cli/base.rb
CHANGED
@@ -72,28 +72,28 @@ module Mrsk::Cli
|
|
72
72
|
puts " Finished all in #{sprintf("%.1f seconds", runtime)}"
|
73
73
|
end
|
74
74
|
|
75
|
-
def
|
76
|
-
if MRSK.holding_lock?
|
77
|
-
|
78
|
-
|
79
|
-
run_hook "pre-connect"
|
75
|
+
def mutating
|
76
|
+
return yield if MRSK.holding_lock?
|
77
|
+
|
78
|
+
MRSK.config.ensure_env_available
|
80
79
|
|
81
|
-
|
80
|
+
run_hook "pre-connect"
|
82
81
|
|
83
|
-
|
84
|
-
yield
|
85
|
-
rescue
|
86
|
-
if MRSK.hold_lock_on_error?
|
87
|
-
error " \e[31mDeploy lock was not released\e[0m"
|
88
|
-
else
|
89
|
-
release_lock
|
90
|
-
end
|
82
|
+
acquire_lock
|
91
83
|
|
92
|
-
|
84
|
+
begin
|
85
|
+
yield
|
86
|
+
rescue
|
87
|
+
if MRSK.hold_lock_on_error?
|
88
|
+
error " \e[31mDeploy lock was not released\e[0m"
|
89
|
+
else
|
90
|
+
release_lock
|
93
91
|
end
|
94
92
|
|
95
|
-
|
93
|
+
raise
|
96
94
|
end
|
95
|
+
|
96
|
+
release_lock
|
97
97
|
end
|
98
98
|
|
99
99
|
def acquire_lock
|
data/lib/mrsk/cli/build.rb
CHANGED
@@ -3,7 +3,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base
|
|
3
3
|
|
4
4
|
desc "deliver", "Build app and push app image to registry then pull image on servers"
|
5
5
|
def deliver
|
6
|
-
|
6
|
+
mutating do
|
7
7
|
push
|
8
8
|
pull
|
9
9
|
end
|
@@ -11,7 +11,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base
|
|
11
11
|
|
12
12
|
desc "push", "Build and push app image to registry"
|
13
13
|
def push
|
14
|
-
|
14
|
+
mutating do
|
15
15
|
cli = self
|
16
16
|
|
17
17
|
verify_local_dependencies
|
@@ -37,7 +37,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base
|
|
37
37
|
|
38
38
|
desc "pull", "Pull app image from registry onto servers"
|
39
39
|
def pull
|
40
|
-
|
40
|
+
mutating do
|
41
41
|
on(MRSK.hosts) do
|
42
42
|
execute *MRSK.auditor.record("Pulled image with version #{MRSK.config.version}"), verbosity: :debug
|
43
43
|
execute *MRSK.builder.clean, raise_on_non_zero_exit: false
|
@@ -48,7 +48,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base
|
|
48
48
|
|
49
49
|
desc "create", "Create a build setup"
|
50
50
|
def create
|
51
|
-
|
51
|
+
mutating do
|
52
52
|
run_locally do
|
53
53
|
begin
|
54
54
|
debug "Using builder: #{MRSK.builder.name}"
|
@@ -67,7 +67,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base
|
|
67
67
|
|
68
68
|
desc "remove", "Remove build setup"
|
69
69
|
def remove
|
70
|
-
|
70
|
+
mutating do
|
71
71
|
run_locally do
|
72
72
|
debug "Using builder: #{MRSK.builder.name}"
|
73
73
|
execute *MRSK.builder.remove
|
data/lib/mrsk/cli/main.rb
CHANGED
@@ -2,7 +2,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|
2
2
|
desc "setup", "Setup all accessories and deploy app to servers"
|
3
3
|
def setup
|
4
4
|
print_runtime do
|
5
|
-
|
5
|
+
mutating do
|
6
6
|
invoke "mrsk:cli:server:bootstrap"
|
7
7
|
invoke "mrsk:cli:accessory:boot", [ "all" ]
|
8
8
|
deploy
|
@@ -14,7 +14,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|
14
14
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
15
15
|
def deploy
|
16
16
|
runtime = print_runtime do
|
17
|
-
|
17
|
+
mutating do
|
18
18
|
invoke_options = deploy_options
|
19
19
|
|
20
20
|
say "Log into image registry...", :magenta
|
@@ -53,7 +53,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|
53
53
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
54
54
|
def redeploy
|
55
55
|
runtime = print_runtime do
|
56
|
-
|
56
|
+
mutating do
|
57
57
|
invoke_options = deploy_options
|
58
58
|
|
59
59
|
if options[:skip_push]
|
@@ -83,7 +83,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|
83
83
|
def rollback(version)
|
84
84
|
rolled_back = false
|
85
85
|
runtime = print_runtime do
|
86
|
-
|
86
|
+
mutating do
|
87
87
|
invoke_options = deploy_options
|
88
88
|
|
89
89
|
MRSK.config.version = version
|
@@ -180,7 +180,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
|
|
180
180
|
desc "remove", "Remove Traefik, app, accessories, and registry session from servers"
|
181
181
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
182
182
|
def remove
|
183
|
-
|
183
|
+
mutating do
|
184
184
|
if options[:confirmed] || ask("This will remove all containers and images. Are you sure?", limited_to: %w( y N ), default: "N") == "y"
|
185
185
|
invoke "mrsk:cli:traefik:remove", [], options.without(:confirmed)
|
186
186
|
invoke "mrsk:cli:app:remove", [], options.without(:confirmed)
|
data/lib/mrsk/cli/prune.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Mrsk::Cli::Prune < Mrsk::Cli::Base
|
2
2
|
desc "all", "Prune unused images and stopped containers"
|
3
3
|
def all
|
4
|
-
|
4
|
+
mutating do
|
5
5
|
containers
|
6
6
|
images
|
7
7
|
end
|
@@ -9,7 +9,7 @@ class Mrsk::Cli::Prune < Mrsk::Cli::Base
|
|
9
9
|
|
10
10
|
desc "images", "Prune dangling images"
|
11
11
|
def images
|
12
|
-
|
12
|
+
mutating do
|
13
13
|
on(MRSK.hosts) do
|
14
14
|
execute *MRSK.auditor.record("Pruned images"), verbosity: :debug
|
15
15
|
execute *MRSK.prune.dangling_images
|
@@ -20,7 +20,7 @@ class Mrsk::Cli::Prune < Mrsk::Cli::Base
|
|
20
20
|
|
21
21
|
desc "containers", "Prune all stopped containers, except the last 5"
|
22
22
|
def containers
|
23
|
-
|
23
|
+
mutating do
|
24
24
|
on(MRSK.hosts) do
|
25
25
|
execute *MRSK.auditor.record("Pruned containers"), verbosity: :debug
|
26
26
|
execute *MRSK.prune.containers
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/bin/
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
# A sample pre-deploy hook
|
4
4
|
#
|
@@ -16,8 +16,6 @@
|
|
16
16
|
# MRSK_ROLE (if set)
|
17
17
|
# MRSK_DESTINATION (if set)
|
18
18
|
|
19
|
-
#!/usr/bin/env ruby
|
20
|
-
|
21
19
|
# Only check the build status for production deployments
|
22
20
|
if ENV["MRSK_COMMAND"] == "rollback" || ENV["MRSK_DESTINATION"] != "production"
|
23
21
|
exit 0
|
@@ -41,41 +39,70 @@ def exit_with_error(message)
|
|
41
39
|
exit 1
|
42
40
|
end
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
class GithubStatusChecks
|
43
|
+
attr_reader :remote_url, :git_sha, :github_client, :combined_status
|
44
|
+
|
45
|
+
def initialize
|
46
|
+
@remote_url = `git config --get remote.origin.url`.strip.delete_prefix("https://github.com/")
|
47
|
+
@git_sha = `git rev-parse HEAD`.strip
|
48
|
+
@github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
|
49
|
+
refresh!
|
50
|
+
end
|
51
|
+
|
52
|
+
def refresh!
|
53
|
+
@combined_status = github_client.combined_status(remote_url, git_sha)
|
54
|
+
end
|
55
|
+
|
56
|
+
def state
|
57
|
+
combined_status[:state]
|
58
|
+
end
|
59
|
+
|
60
|
+
def first_status_url
|
61
|
+
first_status = combined_status[:statuses].find { |status| status[:state] == state }
|
62
|
+
first_status && first_status[:target_url]
|
63
|
+
end
|
64
|
+
|
65
|
+
def complete_count
|
66
|
+
combined_status[:statuses].count { |status| status[:state] != "pending"}
|
67
|
+
end
|
68
|
+
|
69
|
+
def total_count
|
70
|
+
combined_status[:statuses].count
|
71
|
+
end
|
72
|
+
|
73
|
+
def current_status
|
74
|
+
if total_count > 0
|
75
|
+
"Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..."
|
76
|
+
else
|
77
|
+
"Build not started..."
|
78
|
+
end
|
79
|
+
end
|
47
80
|
end
|
48
81
|
|
49
|
-
remote_url = `git config --get remote.origin.url`.strip.delete_prefix("https://github.com/")
|
50
|
-
git_sha = `git rev-parse HEAD`.strip
|
51
82
|
|
52
|
-
|
53
|
-
|
83
|
+
$stdout.sync = true
|
84
|
+
|
85
|
+
puts "Checking build status..."
|
54
86
|
attempts = 0
|
87
|
+
checks = GithubStatusChecks.new
|
55
88
|
|
56
89
|
begin
|
57
90
|
loop do
|
58
|
-
|
59
|
-
state = combined_status[:state]
|
60
|
-
first_status_url = first_status_url(combined_status, state)
|
61
|
-
|
62
|
-
case state
|
91
|
+
case checks.state
|
63
92
|
when "success"
|
64
|
-
puts "
|
93
|
+
puts "Checks passed, see #{checks.first_status_url}"
|
65
94
|
exit 0
|
66
95
|
when "failure"
|
67
|
-
exit_with_error "
|
96
|
+
exit_with_error "Checks failed, see #{checks.first_status_url}"
|
68
97
|
when "pending"
|
69
98
|
attempts += 1
|
70
99
|
end
|
71
100
|
|
72
|
-
|
73
|
-
|
74
|
-
if attempts == MAX_ATTEMPTS
|
75
|
-
exit_with_error "Build status is still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds"
|
76
|
-
end
|
101
|
+
exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS
|
77
102
|
|
103
|
+
puts checks.current_status
|
78
104
|
sleep(ATTEMPTS_GAP)
|
105
|
+
checks.refresh!
|
79
106
|
end
|
80
107
|
rescue Octokit::NotFound
|
81
108
|
exit_with_error "Build status could not be found"
|
data/lib/mrsk/cli/traefik.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
2
2
|
desc "boot", "Boot Traefik on servers"
|
3
3
|
def boot
|
4
|
-
|
4
|
+
mutating do
|
5
5
|
on(MRSK.traefik_hosts) do
|
6
6
|
execute *MRSK.registry.login
|
7
7
|
execute *MRSK.traefik.run, raise_on_non_zero_exit: false
|
@@ -11,7 +11,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
|
11
11
|
|
12
12
|
desc "reboot", "Reboot Traefik on servers (stop container, remove container, start new container)"
|
13
13
|
def reboot
|
14
|
-
|
14
|
+
mutating do
|
15
15
|
stop
|
16
16
|
remove_container
|
17
17
|
boot
|
@@ -20,7 +20,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
|
20
20
|
|
21
21
|
desc "start", "Start existing Traefik container on servers"
|
22
22
|
def start
|
23
|
-
|
23
|
+
mutating do
|
24
24
|
on(MRSK.traefik_hosts) do
|
25
25
|
execute *MRSK.auditor.record("Started traefik"), verbosity: :debug
|
26
26
|
execute *MRSK.traefik.start, raise_on_non_zero_exit: false
|
@@ -30,7 +30,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
|
30
30
|
|
31
31
|
desc "stop", "Stop existing Traefik container on servers"
|
32
32
|
def stop
|
33
|
-
|
33
|
+
mutating do
|
34
34
|
on(MRSK.traefik_hosts) do
|
35
35
|
execute *MRSK.auditor.record("Stopped traefik"), verbosity: :debug
|
36
36
|
execute *MRSK.traefik.stop, raise_on_non_zero_exit: false
|
@@ -40,7 +40,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
|
40
40
|
|
41
41
|
desc "restart", "Restart existing Traefik container on servers"
|
42
42
|
def restart
|
43
|
-
|
43
|
+
mutating do
|
44
44
|
stop
|
45
45
|
start
|
46
46
|
end
|
@@ -77,7 +77,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
|
77
77
|
|
78
78
|
desc "remove", "Remove Traefik container and image from servers"
|
79
79
|
def remove
|
80
|
-
|
80
|
+
mutating do
|
81
81
|
stop
|
82
82
|
remove_container
|
83
83
|
remove_image
|
@@ -86,7 +86,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
|
86
86
|
|
87
87
|
desc "remove_container", "Remove Traefik container from servers", hide: true
|
88
88
|
def remove_container
|
89
|
-
|
89
|
+
mutating do
|
90
90
|
on(MRSK.traefik_hosts) do
|
91
91
|
execute *MRSK.auditor.record("Removed traefik container"), verbosity: :debug
|
92
92
|
execute *MRSK.traefik.remove_container
|
@@ -96,7 +96,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base
|
|
96
96
|
|
97
97
|
desc "remove_image", "Remove Traefik image from servers", hide: true
|
98
98
|
def remove_image
|
99
|
-
|
99
|
+
mutating do
|
100
100
|
on(MRSK.traefik_hosts) do
|
101
101
|
execute *MRSK.auditor.record("Removed traefik image"), verbosity: :debug
|
102
102
|
execute *MRSK.traefik.remove_image
|
data/lib/mrsk/commands/base.rb
CHANGED
@@ -13,7 +13,11 @@ module Mrsk::Commands
|
|
13
13
|
|
14
14
|
def run_over_ssh(*command, host:)
|
15
15
|
"ssh".tap do |cmd|
|
16
|
-
|
16
|
+
if config.ssh_proxy && config.ssh_proxy.is_a?(Net::SSH::Proxy::Jump)
|
17
|
+
cmd << " -J #{config.ssh_proxy.jump_proxies}"
|
18
|
+
elsif config.ssh_proxy && config.ssh_proxy.is_a?(Net::SSH::Proxy::Command)
|
19
|
+
cmd << " -o ProxyCommand='#{config.ssh_proxy.command_line_template}'"
|
20
|
+
end
|
17
21
|
cmd << " -t #{config.ssh_user}@#{host} '#{command.join(" ")}'"
|
18
22
|
end
|
19
23
|
end
|
@@ -3,6 +3,7 @@ class Mrsk::Commands::Builder::Base < Mrsk::Commands::Base
|
|
3
3
|
class BuilderError < StandardError; end
|
4
4
|
|
5
5
|
delegate :argumentize, to: Mrsk::Utils
|
6
|
+
delegate :args, :secrets, :dockerfile, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, to: :builder_config
|
6
7
|
|
7
8
|
def clean
|
8
9
|
docker :image, :rm, "--force", config.absolute_image
|
@@ -13,11 +14,11 @@ class Mrsk::Commands::Builder::Base < Mrsk::Commands::Base
|
|
13
14
|
end
|
14
15
|
|
15
16
|
def build_options
|
16
|
-
[ *build_tags, *build_labels, *build_args, *build_secrets, *build_dockerfile ]
|
17
|
+
[ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile ]
|
17
18
|
end
|
18
19
|
|
19
20
|
def build_context
|
20
|
-
context
|
21
|
+
config.builder.context
|
21
22
|
end
|
22
23
|
|
23
24
|
|
@@ -26,6 +27,13 @@ class Mrsk::Commands::Builder::Base < Mrsk::Commands::Base
|
|
26
27
|
[ "-t", config.absolute_image, "-t", config.latest_image ]
|
27
28
|
end
|
28
29
|
|
30
|
+
def build_cache
|
31
|
+
if cache_to && cache_from
|
32
|
+
["--cache-to", cache_to,
|
33
|
+
"--cache-from", cache_from]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
29
37
|
def build_labels
|
30
38
|
argumentize "--label", { service: config.service }
|
31
39
|
end
|
@@ -46,19 +54,7 @@ class Mrsk::Commands::Builder::Base < Mrsk::Commands::Base
|
|
46
54
|
end
|
47
55
|
end
|
48
56
|
|
49
|
-
def
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
def secrets
|
54
|
-
(config.builder && config.builder["secrets"]) || []
|
55
|
-
end
|
56
|
-
|
57
|
-
def dockerfile
|
58
|
-
(config.builder && config.builder["dockerfile"]) || "Dockerfile"
|
59
|
-
end
|
60
|
-
|
61
|
-
def context
|
62
|
-
(config.builder && config.builder["context"]) || "."
|
57
|
+
def builder_config
|
58
|
+
config.builder
|
63
59
|
end
|
64
60
|
end
|
@@ -22,17 +22,17 @@ class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Mult
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def create_local_buildx
|
25
|
-
docker :buildx, :create, "--name", builder_name, builder_name_with_arch(
|
25
|
+
docker :buildx, :create, "--name", builder_name, builder_name_with_arch(local_arch), "--platform", "linux/#{local_arch}"
|
26
26
|
end
|
27
27
|
|
28
28
|
def append_remote_buildx
|
29
|
-
docker :buildx, :create, "--append", "--name", builder_name, builder_name_with_arch(
|
29
|
+
docker :buildx, :create, "--append", "--name", builder_name, builder_name_with_arch(remote_arch), "--platform", "linux/#{remote_arch}"
|
30
30
|
end
|
31
31
|
|
32
32
|
def create_contexts
|
33
33
|
combine \
|
34
|
-
create_context(
|
35
|
-
create_context(
|
34
|
+
create_context(local_arch, local_host),
|
35
|
+
create_context(remote_arch, remote_host)
|
36
36
|
end
|
37
37
|
|
38
38
|
def create_context(arch, host)
|
@@ -41,19 +41,11 @@ class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Mult
|
|
41
41
|
|
42
42
|
def remove_contexts
|
43
43
|
combine \
|
44
|
-
remove_context(
|
45
|
-
remove_context(
|
44
|
+
remove_context(local_arch),
|
45
|
+
remove_context(remote_arch)
|
46
46
|
end
|
47
47
|
|
48
48
|
def remove_context(arch)
|
49
49
|
docker :context, :rm, builder_name_with_arch(arch)
|
50
50
|
end
|
51
|
-
|
52
|
-
def local
|
53
|
-
config.builder["local"]
|
54
|
-
end
|
55
|
-
|
56
|
-
def remote
|
57
|
-
config.builder["remote"]
|
58
|
-
end
|
59
51
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Mrsk::Commands::Builder::Native::Cached < Mrsk::Commands::Builder::Native
|
2
|
+
def create
|
3
|
+
docker :buildx, :create, "--use", "--driver=docker-container"
|
4
|
+
end
|
5
|
+
|
6
|
+
def remove
|
7
|
+
docker :buildx, :rm, builder_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def push
|
11
|
+
docker :buildx, :build,
|
12
|
+
"--push",
|
13
|
+
*build_options,
|
14
|
+
build_context
|
15
|
+
end
|
16
|
+
end
|
@@ -28,29 +28,21 @@ class Mrsk::Commands::Builder::Native::Remote < Mrsk::Commands::Builder::Native
|
|
28
28
|
|
29
29
|
|
30
30
|
private
|
31
|
-
def arch
|
32
|
-
config.builder["remote"]["arch"]
|
33
|
-
end
|
34
|
-
|
35
|
-
def host
|
36
|
-
config.builder["remote"]["host"]
|
37
|
-
end
|
38
|
-
|
39
31
|
def builder_name
|
40
32
|
"mrsk-#{config.service}-native-remote"
|
41
33
|
end
|
42
34
|
|
43
35
|
def builder_name_with_arch
|
44
|
-
"#{builder_name}-#{
|
36
|
+
"#{builder_name}-#{remote_arch}"
|
45
37
|
end
|
46
38
|
|
47
39
|
def platform
|
48
|
-
"linux/#{
|
40
|
+
"linux/#{remote_arch}"
|
49
41
|
end
|
50
42
|
|
51
43
|
def create_context
|
52
44
|
docker :context, :create,
|
53
|
-
builder_name_with_arch, "--description", "'#{builder_name} #{
|
45
|
+
builder_name_with_arch, "--description", "'#{builder_name} #{remote_arch} native host'", "--docker", "'host=#{remote_host}'"
|
54
46
|
end
|
55
47
|
|
56
48
|
def remove_context
|
@@ -7,11 +7,13 @@ class Mrsk::Commands::Builder < Mrsk::Commands::Base
|
|
7
7
|
|
8
8
|
def target
|
9
9
|
case
|
10
|
-
when config.builder && config.builder
|
10
|
+
when !config.builder.multiarch? && !config.builder.cached?
|
11
11
|
native
|
12
|
-
when config.builder && config.builder
|
12
|
+
when !config.builder.multiarch? && config.builder.cached?
|
13
|
+
native_cached
|
14
|
+
when config.builder.local? && config.builder.remote?
|
13
15
|
multiarch_remote
|
14
|
-
when config.builder
|
16
|
+
when config.builder.remote?
|
15
17
|
native_remote
|
16
18
|
else
|
17
19
|
multiarch
|
@@ -22,6 +24,10 @@ class Mrsk::Commands::Builder < Mrsk::Commands::Base
|
|
22
24
|
@native ||= Mrsk::Commands::Builder::Native.new(config)
|
23
25
|
end
|
24
26
|
|
27
|
+
def native_cached
|
28
|
+
@native ||= Mrsk::Commands::Builder::Native::Cached.new(config)
|
29
|
+
end
|
30
|
+
|
25
31
|
def native_remote
|
26
32
|
@native ||= Mrsk::Commands::Builder::Native::Remote.new(config)
|
27
33
|
end
|
@@ -3,6 +3,9 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
|
|
3
3
|
|
4
4
|
DEFAULT_IMAGE = "traefik:v2.9"
|
5
5
|
CONTAINER_PORT = 80
|
6
|
+
DEFAULT_ARGS = {
|
7
|
+
'log.level' => 'DEBUG'
|
8
|
+
}
|
6
9
|
|
7
10
|
def run
|
8
11
|
docker :run, "--name traefik",
|
@@ -16,7 +19,6 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
|
|
16
19
|
*docker_options_args,
|
17
20
|
image,
|
18
21
|
"--providers.docker",
|
19
|
-
"--log.level=DEBUG",
|
20
22
|
*cmd_option_args
|
21
23
|
end
|
22
24
|
|
@@ -86,9 +88,9 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
|
|
86
88
|
|
87
89
|
def cmd_option_args
|
88
90
|
if args = config.traefik["args"]
|
89
|
-
optionize args, with: "="
|
91
|
+
optionize DEFAULT_ARGS.merge(args), with: "="
|
90
92
|
else
|
91
|
-
|
93
|
+
optionize DEFAULT_ARGS, with: "="
|
92
94
|
end
|
93
95
|
end
|
94
96
|
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class Mrsk::Configuration::Builder
|
2
|
+
def initialize(config:)
|
3
|
+
@options = config.raw_config.builder || {}
|
4
|
+
@image = config.image
|
5
|
+
@server = config.registry["server"]
|
6
|
+
|
7
|
+
valid?
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_h
|
11
|
+
@options
|
12
|
+
end
|
13
|
+
|
14
|
+
def multiarch?
|
15
|
+
@options["multiarch"] != false
|
16
|
+
end
|
17
|
+
|
18
|
+
def local?
|
19
|
+
!!@options["local"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def remote?
|
23
|
+
!!@options["remote"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def cached?
|
27
|
+
!!@options["cache"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def args
|
31
|
+
@options["args"] || {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def secrets
|
35
|
+
@options["secrets"] || []
|
36
|
+
end
|
37
|
+
|
38
|
+
def dockerfile
|
39
|
+
@options["dockerfile"] || "Dockerfile"
|
40
|
+
end
|
41
|
+
|
42
|
+
def context
|
43
|
+
@options["context"] || "."
|
44
|
+
end
|
45
|
+
|
46
|
+
def local_arch
|
47
|
+
@options["local"]["arch"] if local?
|
48
|
+
end
|
49
|
+
|
50
|
+
def local_host
|
51
|
+
@options["local"]["host"] if local?
|
52
|
+
end
|
53
|
+
|
54
|
+
def remote_arch
|
55
|
+
@options["remote"]["arch"] if remote?
|
56
|
+
end
|
57
|
+
|
58
|
+
def remote_host
|
59
|
+
@options["remote"]["host"] if remote?
|
60
|
+
end
|
61
|
+
|
62
|
+
def cache_from
|
63
|
+
if cached?
|
64
|
+
case @options["cache"]["type"]
|
65
|
+
when "gha"
|
66
|
+
cache_from_config_for_gha
|
67
|
+
when "registry"
|
68
|
+
cache_from_config_for_registry
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def cache_to
|
74
|
+
if cached?
|
75
|
+
case @options["cache"]["type"]
|
76
|
+
when "gha"
|
77
|
+
cache_to_config_for_gha
|
78
|
+
when "registry"
|
79
|
+
cache_to_config_for_registry
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def valid?
|
86
|
+
if @options["local"] && !@options["remote"]
|
87
|
+
raise ArgumentError, "You must specify both local and remote builder config for remote multiarch builds"
|
88
|
+
end
|
89
|
+
|
90
|
+
if @options["cache"] && @options["cache"]["type"]
|
91
|
+
raise ArgumentError, "Invalid cache type: #{@options["cache"]["type"]}" unless ["gha", "registry"].include?(@options["cache"]["type"])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def cache_image
|
96
|
+
@options["cache"]&.fetch("image", nil) || "#{@image}-build-cache"
|
97
|
+
end
|
98
|
+
|
99
|
+
def cache_from_config_for_gha
|
100
|
+
"type=gha"
|
101
|
+
end
|
102
|
+
|
103
|
+
def cache_from_config_for_registry
|
104
|
+
[ "type=registry", "ref=#{@server}/#{cache_image}" ].compact.join(",")
|
105
|
+
end
|
106
|
+
|
107
|
+
def cache_to_config_for_gha
|
108
|
+
[ "type=gha", @options["cache"]&.fetch("options", nil)].compact.join(",")
|
109
|
+
end
|
110
|
+
|
111
|
+
def cache_to_config_for_registry
|
112
|
+
[ "type=registry", @options["cache"]&.fetch("options", nil), "ref=#{@server}/#{cache_image}" ].compact.join(",")
|
113
|
+
end
|
114
|
+
end
|
data/lib/mrsk/configuration.rb
CHANGED
@@ -6,7 +6,7 @@ require "erb"
|
|
6
6
|
require "net/ssh/proxy/jump"
|
7
7
|
|
8
8
|
class Mrsk::Configuration
|
9
|
-
delegate :service, :image, :servers, :env, :labels, :registry, :
|
9
|
+
delegate :service, :image, :servers, :env, :labels, :registry, :stop_wait_time, :hooks_path, to: :raw_config, allow_nil: true
|
10
10
|
delegate :argumentize, :argumentize_env_with_secrets, :optionize, to: Mrsk::Utils
|
11
11
|
|
12
12
|
attr_accessor :destination
|
@@ -165,8 +165,12 @@ class Mrsk::Configuration
|
|
165
165
|
raw_config.readiness_delay || 7
|
166
166
|
end
|
167
167
|
|
168
|
+
def minimum_version
|
169
|
+
raw_config.minimum_version
|
170
|
+
end
|
171
|
+
|
168
172
|
def valid?
|
169
|
-
ensure_required_keys_present &&
|
173
|
+
ensure_required_keys_present && ensure_valid_mrsk_version
|
170
174
|
end
|
171
175
|
|
172
176
|
|
@@ -182,7 +186,7 @@ class Mrsk::Configuration
|
|
182
186
|
env_args: env_args,
|
183
187
|
volume_args: volume_args,
|
184
188
|
ssh_options: ssh_options,
|
185
|
-
builder:
|
189
|
+
builder: builder.to_h,
|
186
190
|
accessories: raw_config.accessories,
|
187
191
|
logging: logging_args,
|
188
192
|
healthcheck: healthcheck
|
@@ -197,6 +201,18 @@ class Mrsk::Configuration
|
|
197
201
|
raw_config.hooks_path || ".mrsk/hooks"
|
198
202
|
end
|
199
203
|
|
204
|
+
def builder
|
205
|
+
Mrsk::Configuration::Builder.new(config: self)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Will raise KeyError if any secret ENVs are missing
|
209
|
+
def ensure_env_available
|
210
|
+
env_args
|
211
|
+
roles.each(&:env_args)
|
212
|
+
|
213
|
+
true
|
214
|
+
end
|
215
|
+
|
200
216
|
private
|
201
217
|
# Will raise ArgumentError if any required config keys are missing
|
202
218
|
def ensure_required_keys_present
|
@@ -221,14 +237,15 @@ class Mrsk::Configuration
|
|
221
237
|
true
|
222
238
|
end
|
223
239
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
240
|
+
def ensure_valid_mrsk_version
|
241
|
+
if minimum_version && Gem::Version.new(minimum_version) > Gem::Version.new(Mrsk::VERSION)
|
242
|
+
raise ArgumentError, "Current version is #{Mrsk::VERSION}, minimum required is #{minimum_version}"
|
243
|
+
end
|
228
244
|
|
229
245
|
true
|
230
246
|
end
|
231
247
|
|
248
|
+
|
232
249
|
def role_names
|
233
250
|
raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
|
234
251
|
end
|
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.14.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-06-
|
11
|
+
date: 2023-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -204,6 +204,7 @@ files:
|
|
204
204
|
- lib/mrsk/commands/builder/multiarch.rb
|
205
205
|
- lib/mrsk/commands/builder/multiarch/remote.rb
|
206
206
|
- lib/mrsk/commands/builder/native.rb
|
207
|
+
- lib/mrsk/commands/builder/native/cached.rb
|
207
208
|
- lib/mrsk/commands/builder/native/remote.rb
|
208
209
|
- lib/mrsk/commands/docker.rb
|
209
210
|
- lib/mrsk/commands/healthcheck.rb
|
@@ -215,6 +216,7 @@ files:
|
|
215
216
|
- lib/mrsk/configuration.rb
|
216
217
|
- lib/mrsk/configuration/accessory.rb
|
217
218
|
- lib/mrsk/configuration/boot.rb
|
219
|
+
- lib/mrsk/configuration/builder.rb
|
218
220
|
- lib/mrsk/configuration/role.rb
|
219
221
|
- lib/mrsk/sshkit_with_ext.rb
|
220
222
|
- lib/mrsk/tags.rb
|