moby-derp 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99faf7a4a2ccef6a30df32e08d424bf89c5693278100484a75e21276136e6a3a
4
- data.tar.gz: 379c96e91a43e3b19db58d0e61d1324749969f58a2946a72f687429cda959f34
3
+ metadata.gz: 513a47c0b56a264731bf12050cbc651c7799c4ec60955c06e8cff46377328825
4
+ data.tar.gz: 01d2f26f2fa6300cdddf599b9f544616d1781c4a53879ec009bec1d4dd340b9d
5
5
  SHA512:
6
- metadata.gz: 6d7b1071d6a38f8aa880ad7287c7355460a32dc4a66250e13bcec612d1f11ee91530d2cfedbba0bb4e8bdf54f5784fbaac00f807a46a967a35ddf45193feb6a6
7
- data.tar.gz: ef1b7425e29551844fe383159a19010cc611ffc8dc07566f4c7e30afa4d3d02882692a3beaed35d6490263d51e093decd662e59b9e0169f177f2c221eb9079c4
6
+ metadata.gz: 307556e56b26e97437df00b9db1277f254554ba88af5a22d9b786de2daba8a30d91f5c932c3b28f4cebb972175958c7c1be81d3cd8ad718a23638d8f696aaa12
7
+ data.tar.gz: eb0c7f7f7514dbb93911cc65037a129aadfc1888454529071f2811e606dd3291dc57e5f2ced377df3896bbaccbac22c163bd5fad4e90cc0435304bb32b65ef6a
@@ -213,6 +213,33 @@ containers:
213
213
  ulimit-rttime: 15:16
214
214
  ulimit-stack: 17:18
215
215
 
216
+ # If you're a bit suss as to whether or not one of your containers will
217
+ # successfully start up, you can use the following section to define a
218
+ # start-time health checking regime.
219
+ #
220
+ # How it works is that the defined command is run in the container (using
221
+ # `exec`), and if-and-when that command returns a `0` exit status, the
222
+ # container is considered to be healthy and we're done. If the command
223
+ # returns a non-zero exit status, we wait for `interval` seconds and then
224
+ # retry. If the command executes `attempts` times without receiving a `0`
225
+ # exit status, the container is considered "failed", and no further
226
+ # containers in the pod will be processed, and the `moby-derp` execution
227
+ # will itself exit with a non-zero status.
228
+ startup_health_check:
229
+ # The command to run inside the container via `exec`. You can specify
230
+ # this as a string, or as an array of strings if you prefer to avoid
231
+ # shell quoting hell.
232
+ command: '/usr/local/bin/r-u-ok'
233
+
234
+ # How many seconds to wait between invocations of the command, when
235
+ # it fails. Can be any non-negative number. Defaults to 3.
236
+ interval: 3
237
+
238
+ # How many times to attempt to execute the health-check command before
239
+ # declaring the container hopelessly busticated, and aborting the
240
+ # `moby-derp` run. Must be a positive integer. Defaults to 10.
241
+ attempts: 10
242
+
216
243
  # SECTION 2: POD-LEVEL CONFIGURATION
217
244
  #
218
245
  # The remainder of the configuration items in this file correspond to settings
@@ -43,7 +43,35 @@ module MobyDerp
43
43
  end
44
44
 
45
45
  begin
46
- Docker::Container.create(hash_labelled(container_creation_parameters)).start!.id
46
+ c = Docker::Container.create(hash_labelled(container_creation_parameters))
47
+ c.start!.object_id
48
+
49
+ if @config.startup_health_check
50
+ attempts = @config.startup_health_check[:attempts]
51
+
52
+ while attempts > 0
53
+ stdout, stderr, exitstatus = c.exec(@config.startup_health_check[:command])
54
+ if exitstatus > 0
55
+ stdout_lines = stdout.empty? ? [] : ["stdout:"] + stdout.join("\n").split("\n").map { |l| " #{l}" }
56
+ stderr_lines = stderr.empty? ? [] : ["stderr:"] + stderr.join("\n").split("\n").map { |l| " #{l}" }
57
+ output_lines = stdout_lines + stderr_lines
58
+ @logger.warn(logloc) { "Startup health check failed on #{container_name} with status #{exitstatus}." + (output_lines.empty? ? "" : ([" Output:"] + output_lines.join("\n "))) }
59
+
60
+ attempts -= 1
61
+ sleep @config.startup_health_check[:interval]
62
+ else
63
+ @logger.info(logloc) { "Startup health check passed." }
64
+ break
65
+ end
66
+ end
67
+
68
+ if attempts == 0
69
+ raise MobyDerp::StartupHealthCheckError,
70
+ "Container #{container_name} has failed the startup health check command #{@config.startup_health_check[:attempts]} times. Aborting."
71
+ end
72
+ end
73
+
74
+ c.id
47
75
  rescue Docker::Error::ClientError => ex
48
76
  raise MobyDerp::ContainerError,
49
77
  "moby daemon returned error: #{ex.message}"
@@ -8,7 +8,8 @@ require "shellwords"
8
8
  module MobyDerp
9
9
  class ContainerConfig
10
10
  attr_reader :name, :image, :update_image, :command, :environment, :mounts,
11
- :labels, :readonly, :stop_signal, :stop_timeout, :user, :restart, :limits
11
+ :labels, :readonly, :stop_signal, :stop_timeout, :user, :restart, :limits,
12
+ :startup_health_check
12
13
 
13
14
  def initialize(system_config:,
14
15
  pod_config:,
@@ -24,13 +25,14 @@ module MobyDerp
24
25
  stop_timeout: 10,
25
26
  user: nil,
26
27
  restart: "no",
27
- limits: {}
28
+ limits: {},
29
+ startup_health_check: nil
28
30
  )
29
31
  @system_config, @pod_config, @name, @image = system_config, pod_config, "#{pod_config.name}.#{container_name}", image
30
32
 
31
33
  @update_image, @command, @environment, @mounts, @labels = update_image, command, environment, mounts, labels
32
34
  @readonly, @stop_signal, @stop_timeout, @user, @restart = readonly, stop_signal, stop_timeout, user, restart
33
- @limits = limits
35
+ @limits, @startup_health_check = limits, startup_health_check
34
36
 
35
37
  validate_image
36
38
  validate_update_image
@@ -44,6 +46,7 @@ module MobyDerp
44
46
  validate_user
45
47
  validate_restart
46
48
  validate_limits
49
+ validate_startup_health_check
47
50
  end
48
51
 
49
52
  private
@@ -331,6 +334,51 @@ module MobyDerp
331
334
  end
332
335
  end
333
336
 
337
+ def validate_startup_health_check
338
+ if @startup_health_check.nil?
339
+ # This is fine
340
+ return
341
+ end
342
+
343
+ unless @startup_health_check.is_a?(Hash)
344
+ raise ConfigurationError,
345
+ "startup_health_check must be a hash"
346
+ end
347
+
348
+ case @startup_health_check[:command]
349
+ when String
350
+ @startup_health_check[:command] = Shellwords.split(@startup_health_check[:command])
351
+ when Array
352
+ unless @startup_health_check[:command].all? { |c| String === c }
353
+ raise ConfigurationError, "all elements of the health check command array must be strings"
354
+ end
355
+ when NilClass
356
+ raise ConfigurationError, "health check command must be specified"
357
+ else
358
+ raise ConfigurationError,
359
+ "health check command must be string or array of strings"
360
+ end
361
+
362
+ @startup_health_check[:interval] ||= 3
363
+ @startup_health_check[:attempts] ||= 10
364
+
365
+ unless Numeric === @startup_health_check[:interval]
366
+ raise ConfigurationError, "startup health check interval must be a number"
367
+ end
368
+
369
+ if @startup_health_check[:interval] < 0
370
+ raise ConfigurationError, "startup health check interval cannot be negative"
371
+ end
372
+
373
+ unless Integer === @startup_health_check[:attempts]
374
+ raise ConfigurationError, "startup health check attempt count must be an integer"
375
+ end
376
+
377
+ if @startup_health_check[:attempts] < 1
378
+ raise ConfigurationError, "startup health check attempt count must be a positive integer"
379
+ end
380
+ end
381
+
334
382
  def validate_boolean(name)
335
383
  v = instance_variable_get(:"@#{name}")
336
384
  unless v == true || v == false
@@ -9,6 +9,10 @@ module MobyDerp
9
9
  # Indicates there was a problem manipulating a live container
10
10
  class ContainerError < Error; end
11
11
 
12
+ # Raised when the startup health check has failed spectacularly for
13
+ # a container
14
+ class StartupHealthCheckError < Error; end
15
+
12
16
  # Only appears when an inviolable assertion is invalid, and indicates
13
17
  # there is a bug in the code
14
18
  class BugError < Error; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moby-derp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Palmer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-10 00:00:00.000000000 Z
11
+ date: 2020-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docker-api