container_broker 1.0.1 → 1.1.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: 021bb9a1ca3d028ae71c5640840335415923572f5427f4ae2ab0905cadd35fe4
4
- data.tar.gz: e8af975eb58b008668e654fa0e1d0ca4b7ea70e9832ca788ed4842d021fe6f8d
3
+ metadata.gz: c1d863ef7a79cf23d92d509e16473a5fb717afbb4327adf8a7c60ff0ac5483f6
4
+ data.tar.gz: 4afbefff24adf873548bfd36542d38ade60f6b8031f8a7de2274cc1820d9efbd
5
5
  SHA512:
6
- metadata.gz: 963ddbcc97ebc45676eab092818f8f3e23d20be0e24f45aec26fb3c5f49db3ef7fe9342f6bc0488b7827b6d99bdb8bbba586f446a7cf25ba6b5613bc0f9fa35d
7
- data.tar.gz: c59b5198d1b4fdc532ac1ea93cafd947ea04b35573f752b9c8ce6277c9a40a76fa1903ac774d98afc13693e846558056ef8d2ac0a771c9b3c26edb9a36675d36
6
+ metadata.gz: 72276623eadee051da7078c9a203b1c5eb2ac4e82d826e1545deba5e8fba6273e6cd820b65507e76a2e34e4054701b5c893ddf9528c47079f5b790d6980973cf
7
+ data.tar.gz: 5222da3fcf97e5fb7bb962c337e21e661cd3c6922f1eeb560e6d4e40d1c90ef3b6878dc2ca2f9d14c4a02bb6fae5bdc81a64f49b597dc47e51857f56015c7e30
data/README.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Container Broker
2
2
 
3
+ ## Key Features
4
+ - Run any Docker based task
5
+ - A Node only needs Docker HTTP API
6
+ - Separate Tasks by execution type
7
+ - Easily get Task logs
8
+ - Automatically retry jobs
9
+ - Enqueue tasks if no slots available
10
+ - Distribute load between Nodes
11
+ - If a node dies, tasks are automatically moved to another healthy Node (Failover)
12
+ - Support external volume mounts
13
+
3
14
  ## Installation
4
15
 
5
16
  Add this line to your application's Gemfile:
@@ -66,14 +66,7 @@ class TasksController < ApplicationController
66
66
  :execution_type,
67
67
  storage_mounts: {},
68
68
  tags: {}
69
- ).tap do |permitted_params|
70
- # TODO: Remove after migrate encoder
71
- if params.key?(:ingest_storage_mount) || params[:task].key?(:ingest_storage_mount)
72
- permitted_params[:storage_mounts] = {
73
- "ingest-nfs" => params[:ingest_storage_mount] || params.dig(:task, :ingest_storage_mount)
74
- }
75
- end
76
- end
69
+ )
77
70
  end
78
71
 
79
72
  def set_request_id
@@ -6,7 +6,7 @@ class AddTaskTagsJob < ContainerBrokerBaseJob
6
6
  queue_as :default
7
7
 
8
8
  def perform(task:)
9
- task.tags.keys.each do |tag_name|
9
+ task.tags.each_key do |tag_name|
10
10
  TaskTag.find_or_create_by(name: tag_name.to_s)
11
11
  end
12
12
  end
@@ -6,9 +6,6 @@ class RunTaskJob < ContainerBrokerBaseJob
6
6
  queue_as :default
7
7
 
8
8
  def perform(task:, slot:)
9
- # TODO: remove after successful deploy
10
- task.update!(storage_mounts: { "ingest-nfs" => task.attributes["ingest_storage_mount"] }) if task.attributes["ingest_storage_mount"] && task.storage_mounts.blank?
11
-
12
9
  Rails.logger.debug("Performing RunTaskJob for #{task} #{slot}")
13
10
 
14
11
  raise "Invalid task status - #{task}" unless task.starting?
@@ -2,6 +2,7 @@
2
2
 
3
3
  class MongoidSerializableModel
4
4
  attr_reader :model
5
+
5
6
  include GlobalID::Identification
6
7
 
7
8
  def initialize(model)
@@ -83,10 +83,8 @@ class Node
83
83
  "Node #{name} #{uuid} #{runner_provider} (#{status}#{last_success})"
84
84
  end
85
85
 
86
- def run_with_lock_no_wait
87
- LockManager.new(type: self.class.to_s, id: id, wait: false, expire: 5.minutes).lock do
88
- yield
89
- end
86
+ def run_with_lock_no_wait(&block)
87
+ LockManager.new(type: self.class.to_s, id: id, wait: false, expire: 5.minutes).lock(&block)
90
88
  end
91
89
 
92
90
  private
@@ -19,7 +19,6 @@ class Task
19
19
  field :created_at, type: DateTime
20
20
  field :started_at, type: DateTime
21
21
  field :finished_at, type: DateTime
22
- field :progress, type: String
23
22
  field :try_count, type: Integer, default: 0
24
23
  field :persist_logs, type: Boolean, default: false
25
24
  field :tags, type: Hash, default: {}
@@ -2,7 +2,7 @@
2
2
 
3
3
  class StatusPanelTaskSerializer < ActiveModel::Serializer
4
4
  attributes :uuid, :name, :image, :cmd, :status, :exit_code, :error, :try_count, :created_at,
5
- :started_at, :finished_at, :progress, :seconds_running, :tags, :runner_id,
5
+ :started_at, :finished_at, :seconds_running, :tags, :runner_id,
6
6
  :storage_mounts, :slot, :execution_type
7
7
 
8
8
  def slot
@@ -2,6 +2,6 @@
2
2
 
3
3
  class TaskSerializer < ActiveModel::Serializer
4
4
  attributes :uuid, :status, :exit_code, :error, :try_count,
5
- :created_at, :started_at, :finished_at, :progress, :seconds_running,
5
+ :created_at, :started_at, :finished_at, :seconds_running,
6
6
  :execution_type
7
7
  end
@@ -3,7 +3,7 @@
3
3
  class FriendlyNameNodes
4
4
  def perform
5
5
  Node.order(runner_provider: :desc, hostname: :asc, id: :asc).each_with_index do |node, index|
6
- node.update(name: "n#{format("%02d%s", (index + 1), node.runner_provider.first)}")
6
+ node.update(name: format("n%<sequence>02d%<provider>s", sequence: (index + 1), provider: node.runner_provider.first))
7
7
  FriendlyNameSlots.new(node: node).perform
8
8
  end
9
9
  end
@@ -2,7 +2,9 @@
2
2
 
3
3
  class KubernetesClient
4
4
  class PodNotFoundError < StandardError; end
5
+
5
6
  class NetworkError < StandardError; end
7
+
6
8
  class LogsNotFoundError < StandardError; end
7
9
 
8
10
  LOG_UNAVAILABLE_HTTP_ERROR = 400
@@ -20,7 +22,7 @@ class KubernetesClient
20
22
  end
21
23
 
22
24
  # rubocop:disable Metrics/ParameterLists
23
- def create_pod(pod_name:, image:, cmd:, internal_mounts: [], external_mounts: [], node_selector:)
25
+ def create_pod(pod_name:, image:, cmd:, node_selector:, internal_mounts: [], external_mounts: [])
24
26
  handle_exception do
25
27
  pod = Kubeclient::Resource.new(
26
28
  metadata: {
@@ -2,6 +2,7 @@
2
2
 
3
3
  class LockManager
4
4
  attr_reader :expire, :wait, :locked, :key
5
+
5
6
  KEY_PREFIX = "lockmanager"
6
7
 
7
8
  def initialize(type:, id:, expire:, wait: true)
@@ -13,7 +14,7 @@ class LockManager
13
14
  def lock
14
15
  if lock!
15
16
  begin
16
- yield(self)
17
+ yield(self) if block_given?
17
18
  ensure
18
19
  unlock!
19
20
  end
@@ -11,7 +11,7 @@ class RescheduleTasksForMissingRunners
11
11
  def perform
12
12
  tasks_without_runner.each do |runner_id|
13
13
  task = started_tasks_group_by_runner_id[runner_id]
14
- message = "Task retryied because runner #{runner_id} is missing (#{task} #{task&.slot})"
14
+ message = "Task retried because runner is missing"
15
15
  Rails.logger.debug(message)
16
16
 
17
17
  report_event(message: message, task: task, runner_id: runner_id)
@@ -36,18 +36,18 @@ class RescheduleTasksForMissingRunners
36
36
  runner: slot&.node&.runner_provider,
37
37
  runner_id: runner_id,
38
38
  slot: {
39
- id: slot&.id,
39
+ uuid: slot&.uuid,
40
40
  name: slot&.name,
41
41
  status: slot&.status,
42
42
  runner_id: slot&.runner_id
43
43
  },
44
44
  node: {
45
- id: node&.id,
45
+ uuid: node&.uuid,
46
46
  name: node&.name,
47
47
  status: node&.status
48
48
  },
49
49
  task: {
50
- id: task.id,
50
+ uuid: task.uuid,
51
51
  name: task.name,
52
52
  status: task.status
53
53
  }
@@ -16,9 +16,9 @@ module Runners
16
16
  Runners::ExecutionInfo.new(
17
17
  id: pod&.metadata&.name,
18
18
  status: status,
19
- exit_code: container_status&.state&.terminated&.exitCode,
19
+ exit_code: exit_code,
20
20
  started_at: started_at,
21
- finished_at: container_status&.state&.terminated&.finishedAt,
21
+ finished_at: finished_at,
22
22
  error: error_message,
23
23
  schedule_pending: schedule_pending?
24
24
  )
@@ -54,6 +54,14 @@ module Runners
54
54
  container_status&.state&.terminated&.exitCode&.zero?
55
55
  end
56
56
 
57
+ def exit_code
58
+ container_status&.state&.terminated&.exitCode
59
+ end
60
+
61
+ def finished_at
62
+ container_status&.state&.terminated&.finishedAt
63
+ end
64
+
57
65
  def reason_is_error?
58
66
  waiting? && ERROR_REASONS.include?(reason[:reason])
59
67
  end
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- ::Docker.logger = Logger.new(STDOUT)
3
+ ::Docker.logger = Logger.new($stdout)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Constants
4
4
  class ExecutionType
5
- FORMAT = /\A([a-z0-9])+(\-[a-z0-9]+)*\z/.freeze
5
+ FORMAT = /\A([a-z0-9])+(-[a-z0-9]+)*\z/.freeze
6
6
  INVALID_FORMAT_MESSAGE = "only allows lowercase letters, numbers and hyphen symbol"
7
7
  end
8
8
 
@@ -12,7 +12,6 @@ require "current_thread_request_id"
12
12
  require "config"
13
13
  require "docker-api"
14
14
  require "active_model_serializers"
15
- require "config"
16
15
  require "idempotent-request"
17
16
  require "kubeclient"
18
17
  require "mongoid/uuid"
@@ -22,7 +21,6 @@ require "sentry-raven"
22
21
  require "sidekiq"
23
22
  require "sidekiq-failures"
24
23
  require "sidekiq-scheduler"
25
- require "docker-api"
26
24
  require "measures"
27
25
 
28
26
  module ContainerBroker
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ContainerBroker
4
- VERSION = "1.0.1"
4
+ VERSION = "1.1.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: container_broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Douglas Lise
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-10-07 00:00:00.000000000 Z
13
+ date: 2021-01-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -583,7 +583,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
583
583
  - !ruby/object:Gem::Version
584
584
  version: '0'
585
585
  requirements: []
586
- rubygems_version: 3.1.2
586
+ rubygems_version: 3.1.4
587
587
  signing_key:
588
588
  specification_version: 4
589
589
  summary: ContainerBroker