mrsk 0.13.2 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a752ca316aea9ce851cc9b4ac96cd7fde613f94dd1b63e238c3320b10f82e8c
4
- data.tar.gz: 689bba95ccc72b27b9cc85572b6e4d995f6bfed3d09be30c2076a81ed1eb07f6
3
+ metadata.gz: 39d645ed2ca51ebf7edeaca7502b9b9d83456ad4fd11d5b905903de2ee76f189
4
+ data.tar.gz: c8fe80b16c14e89fd333224b887968620a88741c32a8b7cb4ee1cf9c37c1dcd5
5
5
  SHA512:
6
- metadata.gz: cdbb9e9b58364ba933778bb18bf4576ee3c611fcbb3be9b341c2e21d53d08d37bd524c694e058be4456f0d7da837b488d20c009973017fa39f6c57fb5835d0ce
7
- data.tar.gz: eb58c8ac236172f91719582f7b9606d2255c122be41c7f341a6a54e6b1680b4715f55ad99492ee47a57c38b74626b129d92bd77ed0d864042a7c457343aade13
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:
@@ -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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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 with_lock
76
- if MRSK.holding_lock?
77
- yield
78
- else
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
- acquire_lock
80
+ run_hook "pre-connect"
82
81
 
83
- begin
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
- raise
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
- release_lock
93
+ raise
96
94
  end
95
+
96
+ release_lock
97
97
  end
98
98
 
99
99
  def acquire_lock
@@ -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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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)
@@ -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
- with_lock do
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
- with_lock do
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
- with_lock do
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/sh
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
- def first_status_url(combined_status, state)
45
- first_status = combined_status[:statuses].find { |status| status[:state] == state }
46
- first_status && first_status[:target_url]
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
- repository = Octokit::Repository.from_url(remote_url)
53
- github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
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
- combined_status = github_client.combined_status(remote_url, git_sha)
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 "Build passed, see #{first_status_url}"
93
+ puts "Checks passed, see #{checks.first_status_url}"
65
94
  exit 0
66
95
  when "failure"
67
- exit_with_error "Build failed, see #{first_status_url}"
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
- puts "Waiting #{ATTEMPTS_GAP} more seconds for build to complete#{", see #{first_status_url}" if first_status_url}..."
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"
@@ -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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
- with_lock do
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
@@ -13,7 +13,11 @@ module Mrsk::Commands
13
13
 
14
14
  def run_over_ssh(*command, host:)
15
15
  "ssh".tap do |cmd|
16
- cmd << " -J #{config.ssh_proxy.jump_proxies}" if config.ssh_proxy
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 args
50
- (config.builder && config.builder["args"]) || {}
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(local["arch"]), "--platform", "linux/#{local["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(remote["arch"]), "--platform", "linux/#{remote["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(local["arch"], local["host"]),
35
- create_context(remote["arch"], remote["host"])
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(local["arch"]),
45
- remove_context(remote["arch"])
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}-#{arch}"
36
+ "#{builder_name}-#{remote_arch}"
45
37
  end
46
38
 
47
39
  def platform
48
- "linux/#{arch}"
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} #{arch} native host'", "--docker", "'host=#{host}'"
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
@@ -1,10 +1,10 @@
1
1
  class Mrsk::Commands::Builder::Native < Mrsk::Commands::Builder::Base
2
2
  def create
3
- # No-op on native
3
+ # No-op on native without cache
4
4
  end
5
5
 
6
6
  def remove
7
- # No-op on native
7
+ # No-op on native without cache
8
8
  end
9
9
 
10
10
  def push
@@ -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["multiarch"] == false
10
+ when !config.builder.multiarch? && !config.builder.cached?
11
11
  native
12
- when config.builder && config.builder["local"] && config.builder["remote"]
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 && config.builder["remote"]
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
@@ -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, :builder, :stop_wait_time, :hooks_path, to: :raw_config, allow_nil: true
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 && ensure_env_available
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: raw_config.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
- # Will raise KeyError if any secret ENVs are missing
225
- def ensure_env_available
226
- env_args
227
- roles.each(&:env_args)
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
@@ -1,3 +1,3 @@
1
1
  module Mrsk
2
- VERSION = "0.13.2"
2
+ VERSION = "0.14.0"
3
3
  end
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.13.2
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-01 00:00:00.000000000 Z
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