bako 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +25 -0
- data/.rubocop.yml +1159 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +5 -0
- data/README.md +14 -4
- data/bako.gemspec +1 -0
- data/example/hello/hello.rb +4 -2
- data/lib/bako.rb +5 -0
- data/lib/bako/cli.rb +5 -1
- data/lib/bako/cli/run.rb +9 -5
- data/lib/bako/common_helper.rb +12 -9
- data/lib/bako/dsl.rb +2 -0
- data/lib/bako/dsl/context.rb +24 -17
- data/lib/bako/dsl/context/job.rb +29 -17
- data/lib/bako/dsl/context/job_definition.rb +17 -22
- data/lib/bako/error.rb +3 -1
- data/lib/bako/models/job.rb +41 -27
- data/lib/bako/models/job_definition.rb +27 -19
- data/lib/bako/version.rb +3 -1
- metadata +19 -2
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.1
|
data/.travis.yml
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
|
+
cache: bundler
|
3
4
|
rvm:
|
4
5
|
- 2.3.3
|
5
6
|
before_install: gem install bundler -v 1.14.6
|
7
|
+
addons:
|
8
|
+
code_climate:
|
9
|
+
repo_token:
|
10
|
+
secure: "rzEVWgZoxVjhiqC3YwS3h2+aYLlA8FWnEuHfrvFS7kRbiOmA0h8STR7ajMS8K4nglen1UCo5uoH194UeGNeaVKUgADS/5Db4nadA9fQ8bOwpIyq9FpAA9IHqMkmQ7cHPJ6cYf4m0z25mVq4Wy7xJQQgBSSLJPGe9ZAHrE6sHd0LggsGM4St6IYqUXyf3Nshs36Mx70Kxi0YIh743frUAWDEXWv7VPtKjhLEBHN6ZB3F9W3HvwlRrpFKx5nJT6aeEdQxy+Day3cWel6a4j/VH2pm3LDGrkF9/WByu1ULCL5aUY46vKhAfVdWIucUc9ABi09+6xhI/mf8rcMUeK96qa/gCtE1f9Tn7bX8qolvJlOprJanYTiy2eOMjP0PCuWlOazW7oKoODIn74LHIZqz9Nk3zS9GmLsfc87M1BUM4ri9txoN8RlLu6mzR4Tf6D4uceDa8VlTJLCkxRyi/CDJDwIsmyWSeBHtoRn8AfeIhrZsmCCKq3giYUJawbprZB57aQ377f5r1ZasRrdUfpMXMw/6+YVqfnLzIaFfGsS2Jz5uddSIHww9fHYPEAy/0OIPG9AgmxrKFmi4DQe5O4I1wr3yuKRpMQtqJOBNS2vvryvoNmoMLLW2ThC5D1k2ig3/+FMMYNh8hsv6nYCz1o/EDnDxJ4bQAf9ulPAc/6feyqrk="
|
6
11
|
deploy:
|
7
12
|
provider: rubygems
|
8
13
|
api_key:
|
@@ -11,3 +16,5 @@ deploy:
|
|
11
16
|
on:
|
12
17
|
tags: true
|
13
18
|
repo: ayemos/bako
|
19
|
+
after_success:
|
20
|
+
- bundle exec codeclimate-test-reporter
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# Bako
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/bako.svg)](https://badge.fury.io/rb/bako)
|
3
|
+
[![Code Climate](https://codeclimate.com/github/ayemos/bako/badges/gpa.svg)](https://codeclimate.com/github/ayemos/bako)
|
4
|
+
[![Test Coverage](https://codeclimate.com/github/ayemos/bako/badges/coverage.svg)](https://codeclimate.com/github/ayemos/bako/coverage)
|
5
|
+
[![Issue Count](https://codeclimate.com/github/ayemos/bako/badges/issue_count.svg)](https://codeclimate.com/github/ayemos/bako)
|
2
6
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
7
|
+
Bako is a CLI tool to manage your [AWS Batch](https://aws.amazon.com/batch/) jobs. It also has its own DSL for AWS Batch.
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
@@ -22,7 +24,15 @@ Or install it yourself as:
|
|
22
24
|
|
23
25
|
## Usage
|
24
26
|
|
25
|
-
|
27
|
+
### Prepare environment
|
28
|
+
|
29
|
+
Before start using Bako, you need to prepare basic environment on AWS Batch.
|
30
|
+
We need at least
|
31
|
+
- one Job Queue
|
32
|
+
- one Compute Environment
|
33
|
+
- and one [Amazon EC2 Container Registory](https://aws.amazon.com/jp/ecr/) (only if you use container image for batch implementation)
|
34
|
+
|
35
|
+
## Examples
|
26
36
|
|
27
37
|
## Development
|
28
38
|
|
data/bako.gemspec
CHANGED
data/example/hello/hello.rb
CHANGED
@@ -9,6 +9,7 @@ preproc_jobs = []
|
|
9
9
|
[*1..2].each do |i|
|
10
10
|
preproc_job = job "preproc-inception-#{i}" do
|
11
11
|
job_definition preproc_jd
|
12
|
+
job_queue 'bako-test-queue-001'
|
12
13
|
|
13
14
|
param({
|
14
15
|
foo: 'bar'
|
@@ -22,11 +23,12 @@ train_jd = job_definition 'train-inception' do
|
|
22
23
|
command ['python', '/tensorflow/tensorflow/examples/learn/mnist.py']
|
23
24
|
type 'container'
|
24
25
|
memory 1024
|
25
|
-
vcpus
|
26
|
+
vcpus 4
|
26
27
|
image 'tensorflow/tensorflow:latest-devel'
|
27
28
|
end
|
28
29
|
|
29
30
|
job 'train-inception' do
|
30
31
|
job_definition train_jd
|
31
|
-
|
32
|
+
job_queue 'bako-test-queue-001'
|
33
|
+
depends_on preproc_jobs
|
32
34
|
end
|
data/lib/bako.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "bako/version"
|
2
4
|
require 'bako/common_helper'
|
5
|
+
require 'logger'
|
3
6
|
|
4
7
|
module Bako
|
5
8
|
def Bako.logger
|
@@ -7,6 +10,8 @@ module Bako
|
|
7
10
|
end
|
8
11
|
end
|
9
12
|
|
13
|
+
require 'bako/error'
|
14
|
+
|
10
15
|
require 'bako/dsl'
|
11
16
|
require 'bako/dsl/context'
|
12
17
|
require 'bako/dsl/context/job'
|
data/lib/bako/cli.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'thor'
|
2
4
|
|
3
5
|
module Bako
|
@@ -5,7 +7,9 @@ module Bako
|
|
5
7
|
class_option :verbose, aliases: '-v', type: :boolean
|
6
8
|
map '--version' => :print_version
|
7
9
|
|
8
|
-
desc 'run', '
|
10
|
+
desc 'run JOB_FILE', 'Run batch job'
|
11
|
+
method_option :dry_run, aliases: '-n', type: :boolean,
|
12
|
+
desc: 'Run job locally without call any actual APIs'
|
9
13
|
def runjob(path)
|
10
14
|
require 'bako/cli/run'
|
11
15
|
Bako::CLI::Run.new(path, options, self).run
|
data/lib/bako/cli/run.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Bako
|
2
4
|
class CLI::Run
|
3
5
|
include Bako::CommonHelper
|
@@ -9,10 +11,12 @@ module Bako
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def run
|
12
|
-
|
13
|
-
|
14
|
+
dry_run = @options['dry_run']
|
15
|
+
|
16
|
+
dsl.result[:job_definitions].each do |_, jd_context|
|
17
|
+
jd = Bako::Models::JobDefinition.from_context(jd_context, dry_run: dry_run)
|
14
18
|
|
15
|
-
if jd.remote_exists?
|
19
|
+
if !dry_run && jd.remote_exists?
|
16
20
|
y_or_n = @thor.ask("JobDefinition #{jd.name} seems to exist on remote. would you like to update it? (y/n)")
|
17
21
|
next unless y_or_n =~ /y/i
|
18
22
|
end
|
@@ -21,14 +25,14 @@ module Bako
|
|
21
25
|
end
|
22
26
|
|
23
27
|
jobs_to_be_run.each do |job|
|
24
|
-
Bako::Models::Job.from_context(job).start
|
28
|
+
Bako::Models::Job.from_context(job, dry_run: dry_run).start
|
25
29
|
end
|
26
30
|
end
|
27
31
|
|
28
32
|
private
|
29
33
|
|
30
34
|
def jobs_to_be_run
|
31
|
-
dsl.jobs.values - dsl.jobs.values.map{|j| j.
|
35
|
+
dsl.result[:jobs].values - dsl.result[:jobs].values.map{|j| j.result[:depends_on]}.flatten
|
32
36
|
end
|
33
37
|
|
34
38
|
def dsl
|
data/lib/bako/common_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'aws-sdk'
|
2
4
|
|
3
5
|
module Bako
|
@@ -5,12 +7,11 @@ module Bako
|
|
5
7
|
DEFAULTS = {
|
6
8
|
vcpus: 1,
|
7
9
|
memory: 128
|
8
|
-
}
|
10
|
+
}.freeze
|
11
|
+
|
9
12
|
def batch_client
|
10
13
|
@batch_client ||= Aws::Batch::Client.new
|
11
14
|
end
|
12
|
-
def remote_resource(arn)
|
13
|
-
end
|
14
15
|
|
15
16
|
def remote_job_definition(name_or_arn, status=nil)
|
16
17
|
remote_job_definitions(status).find{|jd|
|
@@ -24,12 +25,14 @@ module Bako
|
|
24
25
|
}).job_definitions.map do |jd|
|
25
26
|
Bako::Models::JobDefinition.new(
|
26
27
|
jd.job_definition_name,
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
{
|
29
|
+
command: jd.container_properties&.command,
|
30
|
+
image: jd.container_properties&.image,
|
31
|
+
role_arn: jd.container_properties&.job_role_arn,
|
32
|
+
type: jd.type,
|
33
|
+
memory: jd.container_properties&.memory,
|
34
|
+
vcpus: jd.container_properties&.vcpus,
|
35
|
+
}
|
33
36
|
)
|
34
37
|
end
|
35
38
|
end
|
data/lib/bako/dsl.rb
CHANGED
data/lib/bako/dsl/context.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
4
|
+
|
1
5
|
class Bako::DSL::Context
|
2
|
-
attr_reader :
|
6
|
+
attr_reader :result
|
3
7
|
|
4
8
|
def self.eval(dsl)
|
5
9
|
new do
|
@@ -8,31 +12,34 @@ class Bako::DSL::Context
|
|
8
12
|
end
|
9
13
|
|
10
14
|
def initialize(&block)
|
11
|
-
|
12
|
-
@
|
15
|
+
|
16
|
+
@result = {
|
17
|
+
jobs: {},
|
18
|
+
job_definitions: {},
|
19
|
+
}
|
13
20
|
|
14
21
|
instance_eval(&block)
|
15
22
|
end
|
16
23
|
|
17
24
|
private
|
18
25
|
|
19
|
-
|
20
|
-
|
26
|
+
%i[
|
27
|
+
job
|
28
|
+
job_definition
|
29
|
+
].each do |context|
|
30
|
+
define_method(context) do |name, &block|
|
31
|
+
name = name.to_s
|
32
|
+
result_key = context.to_s.pluralize.to_sym
|
21
33
|
|
22
|
-
|
23
|
-
|
24
|
-
|
34
|
+
if result[result_key][name]
|
35
|
+
raise "#{context.to_s.capitalize} `#{name}` is already defined"
|
36
|
+
end
|
25
37
|
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
def job_definition(name, &block)
|
30
|
-
name = name.to_s
|
31
|
-
|
32
|
-
if @job_definitions[name]
|
33
|
-
raise "JobDefinition `#{name}` is already defined"
|
38
|
+
@result[result_key][name] = load_context(context).new(name, &block)
|
34
39
|
end
|
40
|
+
end
|
35
41
|
|
36
|
-
|
42
|
+
def load_context(context)
|
43
|
+
Object.const_get("Bako::DSL::Context::#{context.to_s.camelize}")
|
37
44
|
end
|
38
45
|
end
|
data/lib/bako/dsl/context/job.rb
CHANGED
@@ -1,21 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Bako
|
2
4
|
class DSL::Context::Job
|
3
|
-
attr_reader :name, :
|
5
|
+
attr_reader :name, :result
|
4
6
|
|
5
7
|
def initialize(name, &block)
|
6
8
|
@name = name
|
9
|
+
@result = {}
|
7
10
|
|
8
11
|
instance_eval(&block)
|
12
|
+
validate!
|
9
13
|
end
|
10
14
|
|
11
15
|
private
|
12
16
|
|
17
|
+
%i[
|
18
|
+
param
|
19
|
+
memory
|
20
|
+
vcpus
|
21
|
+
job_queue
|
22
|
+
].each do |attr|
|
23
|
+
define_method(attr) do |v|
|
24
|
+
result[attr] = v
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate!
|
29
|
+
raise InvalidArgumentError.new('job_queue must be set') unless result[:job_queue]
|
30
|
+
raise InvalidArgumentError.new('job_definition must be set') unless result[:job_definition]
|
31
|
+
end
|
32
|
+
|
13
33
|
def job_definition(jd)
|
14
34
|
if jd.nil?
|
15
35
|
raise InvalidArgumentError.new('JobDefinition must be set')
|
16
36
|
end
|
17
37
|
|
18
|
-
|
38
|
+
result[:job_definition] =
|
19
39
|
if jd.is_a?(Bako::DSL::Context::JobDefinition)
|
20
40
|
jd
|
21
41
|
elsif jd.is_a?(String)
|
@@ -26,7 +46,7 @@ module Bako
|
|
26
46
|
end
|
27
47
|
|
28
48
|
def depends_on(jobs)
|
29
|
-
|
49
|
+
result[:depends_on] = jobs&.map do |job|
|
30
50
|
if job.is_a?(Bako::DSL::Context::Job)
|
31
51
|
job
|
32
52
|
elsif job.is_a?(String)
|
@@ -37,20 +57,12 @@ module Bako
|
|
37
57
|
end
|
38
58
|
end
|
39
59
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
def vcpus(vcpus_b)
|
49
|
-
@vcpus_b = vcpus_b
|
50
|
-
end
|
51
|
-
|
52
|
-
def job_queue(job_queue_b)
|
53
|
-
@job_queue_b = job_queue_b
|
60
|
+
def command(v)
|
61
|
+
result[:command] = if v.is_a?(Array)
|
62
|
+
v.map(&:to_s)
|
63
|
+
else
|
64
|
+
v.split.map(&:to_s)
|
65
|
+
end
|
54
66
|
end
|
55
67
|
end
|
56
68
|
end
|
@@ -1,39 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Bako
|
3
4
|
class DSL::Context::JobDefinition
|
4
|
-
attr_reader :name, :
|
5
|
+
attr_reader :name, :result
|
5
6
|
|
6
7
|
def initialize(name, &block)
|
7
8
|
@name = name
|
8
|
-
@
|
9
|
+
@result = {}
|
9
10
|
|
10
11
|
instance_eval(&block)
|
12
|
+
validate!
|
11
13
|
end
|
12
14
|
|
13
15
|
private
|
14
16
|
|
15
|
-
def
|
16
|
-
|
17
|
+
def validate!
|
18
|
+
raise InvalidArgumentError.new('type must be set') unless result[:type]
|
17
19
|
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
def memory(memory_b)
|
32
|
-
@memory_b = memory_b
|
33
|
-
end
|
34
|
-
|
35
|
-
def vcpus(vcpus_b)
|
36
|
-
@vcpus_b = vcpus_b
|
21
|
+
%i[
|
22
|
+
type
|
23
|
+
image
|
24
|
+
command
|
25
|
+
role_arn
|
26
|
+
memory
|
27
|
+
vcpus
|
28
|
+
].each do |attr|
|
29
|
+
define_method(attr) do |v|
|
30
|
+
result[attr] = v
|
31
|
+
end
|
37
32
|
end
|
38
33
|
end
|
39
34
|
end
|
data/lib/bako/error.rb
CHANGED
data/lib/bako/models/job.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'yaml'
|
2
4
|
require 'pathname'
|
3
5
|
|
@@ -6,50 +8,62 @@ module Bako
|
|
6
8
|
class Job
|
7
9
|
include Bako::CommonHelper
|
8
10
|
|
9
|
-
attr_reader :name, :job_definition, :depends_on, :param, :id, :memory, :vcpus, :job_queue
|
11
|
+
attr_reader :name, :job_definition, :depends_on, :param, :id, :memory, :vcpus, :job_queue, :command
|
10
12
|
|
11
|
-
def self.from_context(context)
|
13
|
+
def self.from_context(context, dry_run: false)
|
12
14
|
new(
|
13
15
|
context.name,
|
14
|
-
context.
|
15
|
-
|
16
|
-
Bako::Models::Job.from_context(job_context)
|
17
|
-
},
|
18
|
-
context.param_b,
|
19
|
-
context.memory_b,
|
20
|
-
context.vcpus_b,
|
21
|
-
context.job_queue_b
|
16
|
+
context.result,
|
17
|
+
dry_run: dry_run
|
22
18
|
)
|
23
19
|
end
|
24
20
|
|
25
|
-
def initialize(name,
|
21
|
+
def initialize(name, result, dry_run: false)
|
26
22
|
@name = name
|
27
|
-
@job_definition = job_definition
|
28
|
-
@depends_on = depends_on
|
29
|
-
|
30
|
-
|
31
|
-
@
|
32
|
-
@
|
23
|
+
@job_definition = result[:job_definition]
|
24
|
+
@depends_on = result[:depends_on]&.map{|job_context|
|
25
|
+
Bako::Models::Job.from_context(job_context)
|
26
|
+
}
|
27
|
+
@param = result[:param]
|
28
|
+
@memory = result[:memory]
|
29
|
+
@vcpus = result[:vcpus]
|
30
|
+
@job_queue = result[:job_queue]
|
31
|
+
@command = result[:command]
|
32
|
+
@dry_run = dry_run
|
33
33
|
end
|
34
34
|
|
35
35
|
def start
|
36
|
-
|
37
|
-
|
36
|
+
_start(dry_run: @dry_run)
|
37
|
+
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
def _start(dry_run: false)
|
40
|
+
# start 'depends_on' jobs first
|
41
|
+
@depends_on&.each{|j| j._start(dry_run: dry_run)}
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
Bako.logger.info("Submitting job #{@name}:")
|
44
|
+
job_arg = {
|
45
45
|
job_definition: @job_definition.name,
|
46
46
|
job_name: @name,
|
47
47
|
job_queue: @job_queue,
|
48
48
|
depends_on: @depends_on&.map{|j| [[:job_id, j.id]].to_h},
|
49
|
-
parameters: @param
|
50
|
-
|
49
|
+
parameters: @param,
|
50
|
+
container_overrides: {
|
51
|
+
command: @command,
|
52
|
+
vcpus: @vcpus,
|
53
|
+
memory: @memory
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
Bako.logger.info("\n#{job_arg.to_yaml}\n")
|
58
|
+
|
59
|
+
# start job
|
60
|
+
if dry_run
|
61
|
+
@id = '(dry_run)'
|
62
|
+
else
|
63
|
+
resp = batch_client.submit_job(job_arg)
|
64
|
+
@id = resp.job_id
|
65
|
+
end
|
51
66
|
|
52
|
-
@id = resp.job_id
|
53
67
|
Bako.logger.info("Submitted job #{@name} (id: #{@id})")
|
54
68
|
|
55
69
|
resp
|