wrapbox 0.7.0 → 0.8.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: 12b4d996dbd5a6dd05a700e8654c369b670246eaaed96514e9783e94be18a506
4
- data.tar.gz: 06db857821782f32d3cbf3bbcd679182287735224c17256b85f57644b13ea69f
3
+ metadata.gz: 207f24c9cc5e7fc32e69652b7ff9f012b32da2203ac5c044b6adb755fa34ba6c
4
+ data.tar.gz: 6a1dcfd5cd2e09cba65449184f2d736074e5436419abe20b54dcb1117c8af81a
5
5
  SHA512:
6
- metadata.gz: 05f3a8b158b5c54b0f010695fd020a3ea381140a88da9b57488cd469091f66da63215b36b6973e0736b3422200495a1f6dd1d199be07ccc94f32c985f3c17762
7
- data.tar.gz: 10a3aecb71fb45e22b9ffe3123e592142ae4fab5ef5e70bb372c328f8c8b302ffcf8caac592305e9f3466e80570752421ed398936a5f3aabf5764faac40334ce
6
+ metadata.gz: a02a9ab56bf3f0d4bdd2d24fab5acef9d41a128bbdd477f0e4cab16f2a00d90cb20d23c93bc6ec5c7416faa059eacb3dd9a46a050559b994ce772b28f1dabaeb
7
+ data.tar.gz: c0e5595b908a11924854830867af67312f851430d4b5dadf058c273178d111d63d8164a4573efc3a20bbbff8b2f6386dfca8bcb1bd829d1624004b96aa87a853
data/lib/wrapbox.rb CHANGED
@@ -4,6 +4,10 @@ module Wrapbox
4
4
  METHOD_ARGS_ENV = "WRAPBOX_METHOD_ARGS".freeze
5
5
 
6
6
  class << self
7
+ def load_config(filename)
8
+ configs.load_yaml(filename)
9
+ end
10
+
7
11
  def configs
8
12
  @configs ||= ConfigRepository.new
9
13
  end
@@ -12,12 +16,12 @@ module Wrapbox
12
16
  yield configs
13
17
  end
14
18
 
15
- def run(*args, config_name: nil, **options)
19
+ def run(*args, runner: nil, config_name: nil, **options)
16
20
  config = @configs.get(config_name)
17
21
  config.run(*args, **options)
18
22
  end
19
23
 
20
- def run_cmd(*args, config_name: nil, **options)
24
+ def run_cmd(*args, runner: nil, config_name: nil, **options)
21
25
  config = @configs.get(config_name)
22
26
  config.run_cmd(*args, **options)
23
27
  end
data/lib/wrapbox/cli.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "thor/group"
2
+ require "wrapbox"
2
3
  require "wrapbox/runner/docker"
3
4
  require "wrapbox/runner/ecs"
4
5
 
@@ -4,6 +4,7 @@ require "active_support/core_ext/string"
4
4
  module Wrapbox
5
5
  Configuration = Struct.new(
6
6
  :name,
7
+ :task_definition_name,
7
8
  :revision,
8
9
  :runner,
9
10
  :cluster,
@@ -32,6 +33,7 @@ module Wrapbox
32
33
  def self.load_config(config)
33
34
  new(
34
35
  config["name"],
36
+ config["task_definition_name"],
35
37
  config["revision"],
36
38
  config["runner"] ? config["runner"].to_sym : :docker,
37
39
  config["cluster"],
@@ -72,12 +74,12 @@ module Wrapbox
72
74
  Wrapbox::Runner.const_get(r.to_s.camelcase).new(to_h)
73
75
  end
74
76
 
75
- def run(class_name, method_name, args, **options)
76
- build_runner.run(class_name, method_name, args, **options)
77
+ def run(class_name, method_name, args, runner: nil, **options)
78
+ build_runner(runner).run(class_name, method_name, args, **options)
77
79
  end
78
80
 
79
- def run_cmd(*cmd, **options)
80
- build_runner.run_cmd(*cmd, **options)
81
+ def run_cmd(*cmd, runner: nil, **options)
82
+ build_runner(runner).run_cmd(*cmd, **options)
81
83
  end
82
84
  end
83
85
  end
@@ -8,7 +8,15 @@ module Wrapbox
8
8
  def self.new(type, **options)
9
9
  raise "log_fetcher config needs `type`" unless type
10
10
  require "wrapbox/log_fetcher/#{type}"
11
- self.const_get(type.classify).new(**options)
11
+ self.const_get(type.camelize).new(**options)
12
+ end
13
+
14
+ def run(task:)
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def stop
19
+ raise NotImplementedError
12
20
  end
13
21
  end
14
22
  end
@@ -0,0 +1,104 @@
1
+ module Wrapbox
2
+ module LogFetcher
3
+ class Awslogs
4
+ STOP_WAIT_TIMELIMIT = 10
5
+
6
+ def initialize(log_group:, log_stream_prefix:, filter_pattern: nil, region: nil, access_key_id: nil, secret_access_key: nil, timestamp_format: "%Y-%m-%d %H:%M:%S.%3N", delay: 2, **options)
7
+ begin
8
+ require 'aws-sdk-cloudwatchlogs'
9
+ rescue LoadError
10
+ $stderr.puts "Require aws-sdk-cloudwatchlogs gem"
11
+ exit 1
12
+ end
13
+
14
+ @log_group = log_group
15
+ @log_stream_prefix = log_stream_prefix
16
+ @filter_pattern = filter_pattern
17
+ @region = region
18
+ @access_key_id = access_key_id
19
+ @secret_access_key = secret_access_key
20
+ @timestamp_format = timestamp_format
21
+ @delay = delay
22
+ @options = options.reject { |_, v| v.nil? }
23
+ @displayed_log_stream_names = {}
24
+ @displayed_log_stream_number = 0
25
+ @displayed_event_ids = {}
26
+ end
27
+
28
+ def run(task:)
29
+ @loop_thread = Thread.start do
30
+ main_loop(task)
31
+ end
32
+ end
33
+
34
+ def stop
35
+ @stop = true
36
+ @loop_thread&.join(STOP_WAIT_TIMELIMIT)
37
+ end
38
+
39
+ def main_loop(task)
40
+ task_id = task.task_arn.split("/").last
41
+ log_stream_names = task.containers.map do |container|
42
+ [@log_stream_prefix, container.name, task_id].join("/")
43
+ end
44
+ filter_log_opts = {
45
+ log_group_name: @log_group,
46
+ log_stream_names: log_stream_names,
47
+ filter_pattern: @filter_pattern,
48
+ interleaved: true,
49
+ }.compact
50
+ @max_timestamp = ((Time.now.to_f - 120) * 1000).round
51
+
52
+ until @stop do
53
+ filter_log_opts[:start_time] = @max_timestamp + 1
54
+ resp = client.filter_log_events(filter_log_opts) rescue nil
55
+ resp&.each do |r|
56
+ r.events.each do |ev|
57
+ next if @displayed_event_ids.member?(ev.event_id)
58
+ display_message(ev)
59
+ @displayed_event_ids[ev.event_id] = ev.timestamp
60
+ @max_timestamp = ev.timestamp if @max_timestamp < ev.timestamp
61
+ end
62
+ end
63
+ Thread.start do
64
+ @displayed_event_ids.each do |event_id, ts|
65
+ if ts < (Time.now.to_f - 600) * 1000
66
+ @displayed_event_ids.delete(event_id)
67
+ end
68
+ end
69
+ end.tap do
70
+ sleep @delay
71
+ end.join
72
+ end
73
+ end
74
+
75
+ COLOR_ESCAPE_SEQUENCES = [33, 31, 32, 34, 35, 36]
76
+ def display_message(ev, output: $stdout)
77
+ num = @displayed_log_stream_names.fetch(ev.log_stream_name) do |key|
78
+ current = @displayed_log_stream_number
79
+ @displayed_log_stream_names[key] = current
80
+ @displayed_log_stream_number += 1
81
+ current
82
+ end
83
+
84
+ sequence_number = COLOR_ESCAPE_SEQUENCES[num % COLOR_ESCAPE_SEQUENCES.length]
85
+
86
+ time = Time.at(ev.timestamp / 1000.0)
87
+ output.puts("\e[#{sequence_number}m#{time.strftime(@timestamp_format)} #{ev.log_stream_name}\e[0m #{ev.message}")
88
+ end
89
+
90
+ private
91
+
92
+ def client
93
+ return @client if @client
94
+
95
+ options = {
96
+ region: @region,
97
+ access_key_id: @access_key_id,
98
+ secret_access_key: @secret_access_key,
99
+ }.compact
100
+ @client = Aws::CloudWatchLogs::Client.new(**options)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -17,7 +17,7 @@ module Wrapbox
17
17
  @options = options.reject { |_, v| v.nil? }
18
18
  end
19
19
 
20
- def run
20
+ def run(task:)
21
21
  @started_at = Time.now
22
22
  @loop_thread = Thread.start(&method(:main_loop))
23
23
  end
@@ -139,10 +139,8 @@ module Wrapbox
139
139
  method_option :environments, aliases: "-e"
140
140
  method_option :ignore_signal, type: :boolean, default: false, desc: "Even if receive a signal (like TERM, INT, QUIT), Docker container continue running"
141
141
  def run_cmd(*args)
142
- repo = Wrapbox::ConfigRepository.new.tap { |r| r.load_yaml(options[:config]) }
143
- config = repo.get(options[:config_name])
144
- config.runner = :docker
145
- runner = config.build_runner
142
+ Wrapbox.load_config(options[:config])
143
+ config = Wrapbox.configs[options[:config_name]]
146
144
  environments = options[:environments].to_s.split(/,\s*/).map { |kv| kv.split("=") }.map do |k, v|
147
145
  {name: k, value: v}
148
146
  end
@@ -151,7 +149,7 @@ module Wrapbox
151
149
  else
152
150
  container_definition_overrides = {}
153
151
  end
154
- unless runner.run_cmd(args, environments: environments, container_definition_overrides: container_definition_overrides, ignore_signal: options[:ignore_signal])
152
+ unless config.run_cmd(args, runner: "docker", environments: environments, container_definition_overrides: container_definition_overrides, ignore_signal: options[:ignore_signal])
155
153
  exit 1
156
154
  end
157
155
  end
@@ -48,6 +48,7 @@ module Wrapbox
48
48
 
49
49
  def initialize(options)
50
50
  @name = options[:name]
51
+ @task_definition_name = options[:task_definition_name]
51
52
  @revision = options[:revision]
52
53
  @cluster = options[:cluster]
53
54
  @region = options[:region]
@@ -75,7 +76,7 @@ module Wrapbox
75
76
  @task_definition_info = options[:task_definition]
76
77
 
77
78
  if !@container_definitions.empty?
78
- @task_definition_name = "wrapbox_#{@name}"
79
+ @task_definition_name ||= "wrapbox_#{@name}"
79
80
  @main_container_name = @container_definitions[0][:name] || @task_definition_name
80
81
  elsif @task_definition_info
81
82
  @task_definition_name = @task_definition_info[:task_definition_name]
@@ -107,6 +108,7 @@ module Wrapbox
107
108
  :execution_role_arn,
108
109
  :cluster,
109
110
  :timeout,
111
+ :launch_type,
110
112
  :launch_timeout,
111
113
  :launch_retry,
112
114
  :retry_interval,
@@ -114,7 +116,7 @@ module Wrapbox
114
116
  :max_retry_interval,
115
117
  :execution_retry
116
118
 
117
- def initialize(environments: [], task_role_arn: nil, cluster: nil, timeout: 3600 * 24, launch_timeout: 60 * 10, launch_retry: 10, retry_interval: 1, retry_interval_multiplier: 2, max_retry_interval: 120, execution_retry: 0)
119
+ def initialize(environments: [], task_role_arn: nil, cluster: nil, timeout: 3600 * 24, launch_type: "EC2", launch_timeout: 60 * 10, launch_retry: 10, retry_interval: 1, retry_interval_multiplier: 2, max_retry_interval: 120, execution_retry: 0)
118
120
  b = binding
119
121
  method(:initialize).parameters.each do |param|
120
122
  instance_variable_set("@#{param[1]}", b.local_variable_get(param[1]))
@@ -186,8 +188,6 @@ module Wrapbox
186
188
  task = create_task(task_definition_arn, class_name, method_name, args, command, parameter)
187
189
  return unless task # only Task creation aborted by SignalException
188
190
 
189
- @log_fetcher.run if @log_fetcher
190
-
191
191
  @logger.debug("Launch Task: #{task.task_arn}")
192
192
 
193
193
  wait_task_stopped(cl, task.task_arn, parameter.timeout)
@@ -237,16 +237,18 @@ module Wrapbox
237
237
 
238
238
  def create_task(task_definition_arn, class_name, method_name, args, command, parameter)
239
239
  cl = parameter.cluster || self.cluster
240
+ launch_type = parameter.launch_type || self.launch_type
240
241
  args = Array(args)
241
242
 
242
243
  launch_try_count = 0
243
244
  current_retry_interval = parameter.retry_interval
244
245
 
245
246
  begin
246
- run_task_options = build_run_task_options(task_definition_arn, class_name, method_name, args, command, cl, parameter.environments, parameter.task_role_arn)
247
+ run_task_options = build_run_task_options(task_definition_arn, class_name, method_name, args, command, cl, launch_type, parameter.environments, parameter.task_role_arn)
247
248
  @logger.debug("Task Options: #{run_task_options}")
248
249
  resp = client.run_task(run_task_options)
249
250
  task = resp.tasks[0]
251
+ @log_fetcher.run(task: task) if @log_fetcher
250
252
 
251
253
  resp.failures.each do |failure|
252
254
  @logger.debug("Failure: Arn=#{failure.arn}, Reason=#{failure.reason}")
@@ -438,7 +440,7 @@ module Wrapbox
438
440
  )
439
441
  end
440
442
 
441
- def build_run_task_options(task_definition_arn, class_name, method_name, args, command, cluster, environments, task_role_arn)
443
+ def build_run_task_options(task_definition_arn, class_name, method_name, args, command, cluster, launch_type, environments, task_role_arn)
442
444
  env = environments
443
445
  env += [
444
446
  {
@@ -502,16 +504,15 @@ module Wrapbox
502
504
  method_option :environments, aliases: "-e"
503
505
  method_option :task_role_arn
504
506
  method_option :timeout, type: :numeric
507
+ method_option :launch_type, type: :string, default: "EC2", enum: ["EC2", "FARGATE"]
505
508
  method_option :launch_timeout, type: :numeric
506
509
  method_option :launch_retry, type: :numeric
507
510
  method_option :execution_retry, type: :numeric
508
511
  method_option :max_retry_interval, type: :numeric
509
512
  method_option :ignore_signal, type: :boolean, default: false, desc: "Even if receive a signal (like TERM, INT, QUIT), ECS Tasks continue running"
510
513
  def run_cmd(*args)
511
- repo = Wrapbox::ConfigRepository.new.tap { |r| r.load_yaml(options[:config]) }
512
- config = repo.get(options[:config_name])
513
- config.runner = :ecs
514
- runner = config.build_runner
514
+ Wrapbox.load_config(options[:config])
515
+ config = Wrapbox.configs[options[:config_name]]
515
516
  environments = options[:environments].to_s.split(/,\s*/).map { |kv| kv.split("=") }.map do |k, v|
516
517
  {name: k, value: v}
517
518
  end
@@ -519,6 +520,7 @@ module Wrapbox
519
520
  cluster: options[:cluster],
520
521
  task_role_arn: options[:task_role_arn],
521
522
  timeout: options[:timeout],
523
+ launch_type: options[:launch_type],
522
524
  launch_timeout: options[:launch_timeout],
523
525
  launch_retry: options[:launch_retry],
524
526
  execution_retry: options[:execution_retry],
@@ -530,7 +532,7 @@ module Wrapbox
530
532
  else
531
533
  container_definition_overrides = {}
532
534
  end
533
- unless runner.run_cmd(args, environments: environments, container_definition_overrides: container_definition_overrides, **run_options)
535
+ unless config.run_cmd(args, runner: "ecs", environments: environments, container_definition_overrides: container_definition_overrides, **run_options)
534
536
  exit 1
535
537
  end
536
538
  end
@@ -1,3 +1,3 @@
1
1
  module Wrapbox
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wrapbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - joker1007
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-10 00:00:00.000000000 Z
11
+ date: 2018-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-ecs
@@ -203,6 +203,7 @@ files:
203
203
  - lib/wrapbox/configuration.rb
204
204
  - lib/wrapbox/job.rb
205
205
  - lib/wrapbox/log_fetcher.rb
206
+ - lib/wrapbox/log_fetcher/awslogs.rb
206
207
  - lib/wrapbox/log_fetcher/papertrail.rb
207
208
  - lib/wrapbox/runner/docker.rb
208
209
  - lib/wrapbox/runner/ecs.rb