container_broker 1.0.1 → 1.1.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: 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