mrsk 0.8.1 → 0.8.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a560b5048509237f8c8440a41b35d674915ac493bcf0176256b1006a6aef004
4
- data.tar.gz: d69f0682c43e62fd0574d626456bcb62452ec972b8dd1182b1780958a65aadbd
3
+ metadata.gz: 0065b91bb3c00ef0ef6db78eb605d8db5df3606ccf97be15bb059ab1985231d5
4
+ data.tar.gz: 2ed2b0c6235ea398bc5717aebf99e2a4f1e6c9434c64da5eed6d8899b0ca335e
5
5
  SHA512:
6
- metadata.gz: d670dd54f94d64b2e35f5082f3a5cd78100780b0e0c5d51d050dc25f00ca4cdca26d0a4d797c01860d04205a2cd0fa4285089a944f72977d287e1c6fd313845e
7
- data.tar.gz: 6d28b436a2a0d33da1e32af340e5cd80972b57b946b6b51ec6481b5c832020867075ac53f24dd53f0d86e0d1738a78fb233986530a4ad0d9be1e83e73136522b
6
+ metadata.gz: c00ed2e4693b62e0eeb238c17d4c17b3e06ed03ed580aea7ca724a4629c28274d77bc31fa63ca1d1e5f07b1f73e6b2ecc164a076d2ad5307b7e30625cea2ee7a
7
+ data.tar.gz: ee273834e9e330640ef6b55acc4dabeeef6c4e9178112351376c3ab1e23afeb9fa389a08b6cf5a8c3bbaafc079d7cabc98d316fd08030a8886c12d5020a68653
data/README.md CHANGED
@@ -330,6 +330,21 @@ accessories:
330
330
 
331
331
  Now run `mrsk accessory start mysql` to start the MySQL server on 1.1.1.3. See `mrsk accessory` for all the commands possible.
332
332
 
333
+ ### Using Cron
334
+
335
+ You can use a specific container to run your Cron jobs:
336
+
337
+ ```yaml
338
+ servers:
339
+ cron:
340
+ hosts:
341
+ - 192.168.0.1
342
+ cmd:
343
+ bash -c "cat config/crontab | crontab - && cron -f"
344
+ ```
345
+
346
+ This assumes the Cron settings are stored in `config/crontab`.
347
+
333
348
  ### Using a generated .env file
334
349
 
335
350
  If you're using a centralized secret store, like 1Password, you can create `.env.erb` as a template which looks up the secrets. Example of a .env.erb file:
@@ -498,7 +513,7 @@ If you wish to remove the entire application, including Traefik, containers, ima
498
513
 
499
514
  ## Stage of development
500
515
 
501
- This is alpha software. Lots of stuff is missing. Lots of stuff will keep moving around for a while.
516
+ This is beta software. Commands may still move around. But we're live in production at [37signals](https://37signals.com).
502
517
 
503
518
  ## License
504
519
 
@@ -13,7 +13,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
13
13
  execute *accessory.run
14
14
  end
15
15
 
16
- audit_broadcast "Booted accessory #{name}"
16
+ audit_broadcast "Booted accessory #{name}" unless options[:skip_broadcast]
17
17
  end
18
18
  end
19
19
  end
data/lib/mrsk/cli/app.rb CHANGED
@@ -5,18 +5,27 @@ class Mrsk::Cli::App < Mrsk::Cli::Base
5
5
  using_version(options[:version] || most_recent_version_available) do |version|
6
6
  say "Start container with version #{version} (or reboot if already running)...", :magenta
7
7
 
8
+ cli = self
9
+
8
10
  MRSK.config.roles.each do |role|
9
11
  on(role.hosts) do |host|
10
12
  execute *MRSK.auditor.record("Booted app version #{version}"), verbosity: :debug
11
13
 
12
14
  begin
13
- execute *MRSK.app.stop, raise_on_non_zero_exit: false
15
+ old_version = capture_with_info(*MRSK.app.current_running_version).strip
14
16
  execute *MRSK.app.run(role: role.name)
17
+
18
+ cli.say "Waiting #{MRSK.config.readiness_delay}s for app to boot...", :magenta
19
+ sleep MRSK.config.readiness_delay
20
+
21
+ execute *MRSK.app.stop(version: old_version), raise_on_non_zero_exit: false if old_version.present?
22
+
15
23
  rescue SSHKit::Command::Failed => e
16
24
  if e.message =~ /already in use/
17
- error "Rebooting container with same version already deployed on #{host}"
25
+ error "Rebooting container with same version #{version} already deployed on #{host} (may cause gap in zero-downtime promise!)"
18
26
  execute *MRSK.auditor.record("Rebooted app version #{version}"), verbosity: :debug
19
27
 
28
+ execute *MRSK.app.stop(version: version)
20
29
  execute *MRSK.app.remove_container(version: version)
21
30
  execute *MRSK.app.run(role: role.name)
22
31
  else
data/lib/mrsk/cli/base.rb CHANGED
@@ -20,6 +20,8 @@ module Mrsk::Cli
20
20
  class_option :config_file, aliases: "-c", default: "config/deploy.yml", desc: "Path to config file"
21
21
  class_option :destination, aliases: "-d", desc: "Specify destination to be used for config file (staging -> deploy.staging.yml)"
22
22
 
23
+ class_option :skip_broadcast, aliases: "-B", type: :boolean, default: false, desc: "Skip audit broadcasts"
24
+
23
25
  def initialize(*)
24
26
  super
25
27
  load_envs
@@ -1,5 +1,7 @@
1
1
  class Mrsk::Cli::Healthcheck < Mrsk::Cli::Base
2
- MAX_ATTEMPTS = 5
2
+ MAX_ATTEMPTS = 7
3
+
4
+ class HealthcheckError < StandardError; end
3
5
 
4
6
  default_command :perform
5
7
 
@@ -18,7 +20,7 @@ class Mrsk::Cli::Healthcheck < Mrsk::Cli::Base
18
20
  if status == "200"
19
21
  info "#{target} succeeded with 200 OK!"
20
22
  else
21
- raise "#{target} failed with status #{status}"
23
+ raise HealthcheckError, "#{target} failed with status #{status}"
22
24
  end
23
25
  rescue SSHKit::Command::Failed
24
26
  if attempt <= MAX_ATTEMPTS
@@ -31,7 +33,7 @@ class Mrsk::Cli::Healthcheck < Mrsk::Cli::Base
31
33
  raise
32
34
  end
33
35
  end
34
- rescue SSHKit::Command::Failed => e
36
+ rescue SSHKit::Command::Failed, HealthcheckError => e
35
37
  error capture_with_info(*MRSK.healthcheck.logs)
36
38
 
37
39
  if e.message =~ /curl/
data/lib/mrsk/cli/main.rb CHANGED
@@ -32,7 +32,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
32
32
  invoke "mrsk:cli:prune:all"
33
33
  end
34
34
 
35
- audit_broadcast "Deployed app in #{runtime.to_i} seconds"
35
+ audit_broadcast "Deployed app in #{runtime.to_i} seconds" unless options[:skip_broadcast]
36
36
  end
37
37
 
38
38
  desc "redeploy", "Deploy app to servers without bootstrapping servers, starting Traefik, pruning, and registry login"
@@ -47,7 +47,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
47
47
  invoke "mrsk:cli:app:boot"
48
48
  end
49
49
 
50
- audit_broadcast "Redeployed app in #{runtime.to_i} seconds"
50
+ audit_broadcast "Redeployed app in #{runtime.to_i} seconds" unless options[:skip_broadcast]
51
51
  end
52
52
 
53
53
  desc "rollback [VERSION]", "Rollback app to VERSION"
@@ -55,14 +55,22 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
55
55
  MRSK.version = version
56
56
 
57
57
  if container_name_available?(MRSK.config.service_with_version)
58
- say "Stop current version, then start version #{version}...", :magenta
58
+ say "Start version #{version}, then stop the old version...", :magenta
59
+
60
+ cli = self
59
61
 
60
62
  on(MRSK.hosts) do |host|
61
- execute *MRSK.app.stop, raise_on_non_zero_exit: false
63
+ old_version = capture_with_info(*MRSK.app.current_running_version).strip.presence
64
+
62
65
  execute *MRSK.app.start
66
+
67
+ cli.say "Waiting #{MRSK.config.readiness_delay}s for app to start...", :magenta
68
+ sleep MRSK.config.readiness_delay
69
+
70
+ execute *MRSK.app.stop(version: old_version), raise_on_non_zero_exit: false
63
71
  end
64
72
 
65
- audit_broadcast "Rolled back app to version #{version}"
73
+ audit_broadcast "Rolled back app to version #{version}" unless options[:skip_broadcast]
66
74
  else
67
75
  say "The app version '#{version}' is not available as a container (use 'mrsk app containers' for available versions)", :red
68
76
  end
@@ -138,7 +146,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
138
146
  if options[:confirmed] || ask(remove_confirmation_question, limited_to: %w( y N ), default: "N") == "y"
139
147
  invoke "mrsk:cli:traefik:remove", [], options.without(:confirmed)
140
148
  invoke "mrsk:cli:app:remove", [], options.without(:confirmed)
141
- invoke "mrsk:cli:accessory:remove", [ "all" ]
149
+ invoke "mrsk:cli:accessory:remove", [ "all" ], options
142
150
  invoke "mrsk:cli:registry:logout", [], options.without(:confirmed)
143
151
  end
144
152
  end
@@ -18,8 +18,10 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
18
18
  docker :start, service_with_version
19
19
  end
20
20
 
21
- def stop
22
- pipe current_container_id, xargs(docker(:stop))
21
+ def stop(version: nil)
22
+ pipe \
23
+ version ? container_id_for_version(version) : current_container_id,
24
+ xargs(docker(:stop))
23
25
  end
24
26
 
25
27
  def info
@@ -132,6 +134,10 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
132
134
  end
133
135
  end
134
136
 
137
+ def container_id_for_version(version)
138
+ container_id_for(container_name: service_with_version(version))
139
+ end
140
+
135
141
  def service_filter
136
142
  [ "--filter", "label=service=#{config.service}" ]
137
143
  end
@@ -61,7 +61,7 @@ class Mrsk::Configuration::Role
61
61
  "traefik.http.routers.#{config.service}.rule" => "PathPrefix(`/`)",
62
62
  "traefik.http.services.#{config.service}.loadbalancer.healthcheck.path" => config.healthcheck["path"],
63
63
  "traefik.http.services.#{config.service}.loadbalancer.healthcheck.interval" => "1s",
64
- "traefik.http.middlewares.#{config.service}.retry.attempts" => "3",
64
+ "traefik.http.middlewares.#{config.service}.retry.attempts" => "5",
65
65
  "traefik.http.middlewares.#{config.service}.retry.initialinterval" => "500ms"
66
66
  }
67
67
  else
@@ -136,6 +136,9 @@ class Mrsk::Configuration
136
136
  { "path" => "/up", "port" => 3000 }.merge(raw_config.healthcheck || {})
137
137
  end
138
138
 
139
+ def readiness_delay
140
+ raw_config.readiness_delay || 7
141
+ end
139
142
 
140
143
  def valid?
141
144
  ensure_required_keys_present && ensure_env_available
data/lib/mrsk/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mrsk
2
- VERSION = "0.8.1"
2
+ VERSION = "0.8.3"
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.8.1
4
+ version: 0.8.3
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-02-20 00:00:00.000000000 Z
11
+ date: 2023-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport