hako 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +40 -0
- data/.rubocop_todo.yml +23 -0
- data/.travis.yml +9 -2
- data/README.md +4 -1
- data/Rakefile +5 -3
- data/bin/console +3 -3
- data/examples/hello-lb.yml +6 -0
- data/examples/hello.yml +1 -1
- data/hako.gemspec +14 -13
- data/lib/hako.rb +6 -2
- data/lib/hako/after_scripts.rb +4 -0
- data/lib/hako/application.rb +22 -0
- data/lib/hako/cli.rb +20 -2
- data/lib/hako/commander.rb +44 -17
- data/lib/hako/env_expander.rb +4 -7
- data/lib/hako/env_provider.rb +1 -1
- data/lib/hako/env_providers/file.rb +3 -3
- data/lib/hako/front_config.rb +4 -2
- data/lib/hako/fronts/nginx.rb +41 -1
- data/lib/hako/scheduler.rb +4 -0
- data/lib/hako/schedulers/echo.rb +28 -0
- data/lib/hako/schedulers/ecs.rb +148 -66
- data/lib/hako/schedulers/ecs_definition_comparator.rb +3 -3
- data/lib/hako/schedulers/ecs_elb.rb +64 -0
- data/lib/hako/templates/nginx.conf.erb +8 -8
- data/lib/hako/templates/nginx.location.conf.erb +14 -0
- data/lib/hako/version.rb +1 -1
- metadata +25 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41e144225804bd958a9c8be85ad1f2998cc3a70b
|
4
|
+
data.tar.gz: 746df8720d4697f12ed9b7fd66d73699af39e8c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47a8418855c3fe25132a0033375a00628df9cb07385e6ee1ccb50c6d18c1e14ae0deb1f9284cf32d354568631f7fbfe67d84a1a12b95e6ce1823d43dd48e7d92
|
7
|
+
data.tar.gz: d4274e025153b4cebaac5e6b4d81ef05443afa9a497cccb54b77cf54a8612decf9be2dc5d17980dae692e08cfa112e4f640122f6cf739dded359005657ebfdde
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
DisplayCopNames: true
|
5
|
+
|
6
|
+
Style/GuardClause:
|
7
|
+
Enabled: false
|
8
|
+
|
9
|
+
Style/HashSyntax:
|
10
|
+
Exclude:
|
11
|
+
- 'Rakefile'
|
12
|
+
|
13
|
+
Style/IfUnlessModifier:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Style/Next:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Style/NumericLiterals:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Style/PercentLiteralDelimiters:
|
23
|
+
PreferredDelimiters:
|
24
|
+
'%w': '[]'
|
25
|
+
'%i': '[]'
|
26
|
+
|
27
|
+
Style/RaiseArgs:
|
28
|
+
EnforcedStyle: compact
|
29
|
+
|
30
|
+
Style/SignalException:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Style/TrailingCommaInArguments:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
Style/TrailingCommaInLiteral:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
Performance/RedundantBlockCall:
|
40
|
+
Enabled: false
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Metrics/AbcSize:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
Metrics/ClassLength:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Metrics/CyclomaticComplexity:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Metrics/LineLength:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Metrics/MethodLength:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Metrics/PerceivedComplexity:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Metrics/BlockNesting:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Style/Documentation:
|
23
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
# Hako
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/hako.svg)](http://badge.fury.io/rb/hako)
|
3
|
+
[![Build Status](https://travis-ci.org/eagletmt/hako.svg)](https://travis-ci.org/eagletmt/hako)
|
4
|
+
|
2
5
|
Deploy Docker container.
|
3
6
|
|
4
7
|
## Status
|
@@ -36,7 +39,7 @@ I, [2015-10-02T12:56:12.262760 #8141] INFO -- : Deployment isn't needed
|
|
36
39
|
Load balancer:
|
37
40
|
hako-hello-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com:80 -> front:80
|
38
41
|
Deployments:
|
39
|
-
[PRIMARY] desired_count=2, pending_count=0, running_count=2
|
42
|
+
[PRIMARY] hello:30 desired_count=2, pending_count=0, running_count=2
|
40
43
|
Tasks:
|
41
44
|
[RUNNING]: i-XXXXXXXX (ecs-001)
|
42
45
|
[RUNNING]: i-YYYYYYYY (ecs-002)
|
data/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rubocop/rake_task'
|
3
4
|
|
4
5
|
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
RuboCop::RakeTask.new(:rubocop)
|
5
7
|
|
6
|
-
task :default => :spec
|
8
|
+
task :default => [:spec, :rubocop]
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'hako'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,5 @@ require "hako"
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require 'irb'
|
14
14
|
IRB.start
|
data/examples/hello-lb.yml
CHANGED
@@ -17,6 +17,7 @@ scheduler:
|
|
17
17
|
elb:
|
18
18
|
listeners:
|
19
19
|
- load_balancer_port: 80
|
20
|
+
protocol: HTTP
|
20
21
|
subnets:
|
21
22
|
- subnet-XXXXXXXX
|
22
23
|
- subnet-YYYYYYYY
|
@@ -29,3 +30,8 @@ front:
|
|
29
30
|
region: ap-northeast-1
|
30
31
|
bucket: nanika
|
31
32
|
prefix: hako/front_config
|
33
|
+
extra:
|
34
|
+
locations:
|
35
|
+
/:
|
36
|
+
allow_only_from:
|
37
|
+
- 10.0.0.0/24
|
data/examples/hello.yml
CHANGED
data/hako.gemspec
CHANGED
@@ -4,24 +4,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'hako/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'hako'
|
8
8
|
spec.version = Hako::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['Kohei Suzuki']
|
10
|
+
spec.email = ['eagletmt@gmail.com']
|
11
11
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
14
|
-
spec.homepage =
|
12
|
+
spec.summary = 'Deploy Docker container'
|
13
|
+
spec.description = 'Deploy Docker container'
|
14
|
+
spec.homepage = 'https://github.com/eagletmt/hako'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
-
spec.bindir =
|
17
|
+
spec.bindir = 'exe'
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency
|
22
|
-
spec.add_dependency
|
21
|
+
spec.add_dependency 'aws-sdk', '>= 2.1.0'
|
22
|
+
spec.add_dependency 'thor'
|
23
23
|
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
24
|
+
spec.add_development_dependency 'bundler'
|
25
|
+
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'rspec'
|
27
|
+
spec.add_development_dependency 'rubocop', '>= 0.36.0'
|
27
28
|
end
|
data/lib/hako.rb
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Hako
|
4
|
+
class Application
|
5
|
+
attr_reader :id, :root_path, :yaml
|
6
|
+
|
7
|
+
def initialize(yaml_path)
|
8
|
+
path = Pathname.new(yaml_path)
|
9
|
+
@id = path.basename.sub_ext('').to_s
|
10
|
+
@root_path = path.parent
|
11
|
+
@yaml = YAML.load(load_default_yaml(@root_path) + path.read)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def load_default_yaml(root_path)
|
17
|
+
root_path.join('default.yml').read
|
18
|
+
rescue Errno::ENOENT
|
19
|
+
''
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/hako/cli.rb
CHANGED
@@ -4,15 +4,33 @@ module Hako
|
|
4
4
|
class CLI < Thor
|
5
5
|
desc 'deploy FILE', 'Run deployment'
|
6
6
|
option :force, aliases: %w[-f], type: :boolean, default: false, desc: 'Run deployment even if nothing is changed'
|
7
|
+
option :tag, aliases: %w[-t], type: :string, default: 'latest', desc: 'Specify tag (default: latest)'
|
7
8
|
def deploy(yaml_path)
|
9
|
+
require 'hako/application'
|
8
10
|
require 'hako/commander'
|
9
|
-
Commander.new(yaml_path).deploy(force: options[:force])
|
11
|
+
Commander.new(Application.new(yaml_path)).deploy(force: options[:force], tag: options[:tag])
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'oneshot FILE COMMAND ARG...', 'Run oneshot task'
|
15
|
+
option :tag, aliases: %w[-t], type: :string, default: 'latest', desc: 'Specify tag (default: latest)'
|
16
|
+
def oneshot(yaml_path, command, *args)
|
17
|
+
require 'hako/application'
|
18
|
+
require 'hako/commander'
|
19
|
+
Commander.new(Application.new(yaml_path)).oneshot([command, *args], tag: options[:tag])
|
10
20
|
end
|
11
21
|
|
12
22
|
desc 'status FILE', 'Show deployment status'
|
13
23
|
def status(yaml_path)
|
24
|
+
require 'hako/application'
|
25
|
+
require 'hako/commander'
|
26
|
+
Commander.new(Application.new(yaml_path)).status
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'remove FILE', 'Destroy the application'
|
30
|
+
def remove(yaml_path)
|
31
|
+
require 'hako/application'
|
14
32
|
require 'hako/commander'
|
15
|
-
Commander.new(yaml_path).
|
33
|
+
Commander.new(Application.new(yaml_path)).remove
|
16
34
|
end
|
17
35
|
end
|
18
36
|
end
|
data/lib/hako/commander.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'hako/after_scripts'
|
2
2
|
require 'hako/env_expander'
|
3
3
|
require 'hako/error'
|
4
4
|
require 'hako/front_config'
|
@@ -7,32 +7,53 @@ require 'hako/schedulers'
|
|
7
7
|
|
8
8
|
module Hako
|
9
9
|
class Commander
|
10
|
-
PROVIDERS_KEY = '$providers'
|
10
|
+
PROVIDERS_KEY = '$providers'.freeze
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
@
|
14
|
-
|
12
|
+
def initialize(app)
|
13
|
+
@app = app
|
14
|
+
$LOAD_PATH << @app.root_path.join('lib')
|
15
15
|
end
|
16
16
|
|
17
|
-
def deploy(force: false)
|
18
|
-
env = @yaml['env']
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
def deploy(force: false, tag: 'latest')
|
18
|
+
env = load_environment(@app.yaml['env'])
|
19
|
+
front = load_front(@app.yaml['front'])
|
20
|
+
scheduler = load_scheduler(@app.yaml['scheduler'])
|
21
|
+
app_port = @app.yaml.fetch('port', nil)
|
22
|
+
image = @app.yaml.fetch('image') { raise Error.new('image must be set') }
|
23
|
+
image_tag = "#{image}:#{tag}"
|
24
|
+
after_scripts = @app.yaml.fetch('after_scripts', []).map { |config| load_after_script(config) }
|
23
25
|
|
24
|
-
scheduler = load_scheduler(@yaml['scheduler'])
|
25
|
-
app_port = @yaml.fetch('port', nil)
|
26
|
-
image_tag = @yaml['image'] # TODO: Append revision
|
27
26
|
scheduler.deploy(image_tag, env, app_port, front, force: force)
|
27
|
+
|
28
|
+
after_scripts.each(&:after_deploy)
|
29
|
+
end
|
30
|
+
|
31
|
+
def oneshot(commands, tag: 'latest')
|
32
|
+
env = load_environment(@app.yaml['env'])
|
33
|
+
scheduler = load_scheduler(@app.yaml['scheduler'])
|
34
|
+
image = @app.yaml.fetch('image') { raise Error.new('image must be set') }
|
35
|
+
image_tag = "#{image}:#{tag}"
|
36
|
+
exit scheduler.oneshot(image_tag, env, commands)
|
28
37
|
end
|
29
38
|
|
30
39
|
def status
|
31
|
-
load_scheduler(@yaml['scheduler']).status
|
40
|
+
load_scheduler(@app.yaml['scheduler']).status
|
41
|
+
end
|
42
|
+
|
43
|
+
def remove
|
44
|
+
after_scripts = @app.yaml.fetch('after_scripts', []).map { |config| load_after_script(config) }
|
45
|
+
load_scheduler(@app.yaml['scheduler']).remove
|
46
|
+
after_scripts.each(&:after_remove)
|
32
47
|
end
|
33
48
|
|
34
49
|
private
|
35
50
|
|
51
|
+
def load_environment(env)
|
52
|
+
env = env.dup
|
53
|
+
providers = load_providers(env.delete(PROVIDERS_KEY) || [])
|
54
|
+
EnvExpander.new(providers).expand(env)
|
55
|
+
end
|
56
|
+
|
36
57
|
def load_providers(provider_configs)
|
37
58
|
provider_configs.map do |config|
|
38
59
|
type = config['type']
|
@@ -40,7 +61,7 @@ module Hako
|
|
40
61
|
raise Error.new("type must be set in each #{PROVIDERS_KEY} element")
|
41
62
|
end
|
42
63
|
require "hako/env_providers/#{type}"
|
43
|
-
Hako::EnvProviders.const_get(camelize(type)).new(config)
|
64
|
+
Hako::EnvProviders.const_get(camelize(type)).new(@app.root_path, config)
|
44
65
|
end
|
45
66
|
end
|
46
67
|
|
@@ -50,7 +71,7 @@ module Hako
|
|
50
71
|
raise Error.new('type must be set in scheduler')
|
51
72
|
end
|
52
73
|
require "hako/schedulers/#{type}"
|
53
|
-
Hako::Schedulers.const_get(camelize(type)).new(@
|
74
|
+
Hako::Schedulers.const_get(camelize(type)).new(@app.id, scheduler_config)
|
54
75
|
end
|
55
76
|
|
56
77
|
def load_front(yaml)
|
@@ -59,6 +80,12 @@ module Hako
|
|
59
80
|
Hako::Fronts.const_get(camelize(front_config.type)).new(front_config)
|
60
81
|
end
|
61
82
|
|
83
|
+
def load_after_script(config)
|
84
|
+
type = config.fetch('type')
|
85
|
+
require "hako/after_scripts/#{type}"
|
86
|
+
Hako::AfterScripts.const_get(camelize(type)).new(@app, config)
|
87
|
+
end
|
88
|
+
|
62
89
|
def camelize(name)
|
63
90
|
name.split('_').map(&:capitalize).join('')
|
64
91
|
end
|
data/lib/hako/env_expander.rb
CHANGED
@@ -8,11 +8,8 @@ module Hako
|
|
8
8
|
class ExpansionError < Error
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
class Variable < Struct.new(:name)
|
15
|
-
end
|
11
|
+
Literal = Struct.new(:literal)
|
12
|
+
Variable = Struct.new(:name)
|
16
13
|
|
17
14
|
def initialize(providers)
|
18
15
|
@providers = providers
|
@@ -59,13 +56,13 @@ module Hako
|
|
59
56
|
tokens = []
|
60
57
|
pos = 0
|
61
58
|
while s.scan_until(/#\{(.*?)\}/)
|
62
|
-
pre = s.string.byteslice(pos
|
59
|
+
pre = s.string.byteslice(pos...(s.pos - s.matched.size))
|
63
60
|
var = s[1]
|
64
61
|
unless pre.empty?
|
65
62
|
tokens << Literal.new(pre)
|
66
63
|
end
|
67
64
|
if var.empty?
|
68
|
-
raise ExpansionError.new(
|
65
|
+
raise ExpansionError.new('Empty interpolation is not allowed')
|
69
66
|
else
|
70
67
|
tokens << Variable.new(var)
|
71
68
|
end
|
data/lib/hako/env_provider.rb
CHANGED
@@ -3,11 +3,11 @@ require 'hako/env_provider'
|
|
3
3
|
module Hako
|
4
4
|
module EnvProviders
|
5
5
|
class File < EnvProvider
|
6
|
-
def initialize(options)
|
6
|
+
def initialize(root_path, options)
|
7
7
|
unless options['path']
|
8
|
-
validation_error!(
|
8
|
+
validation_error!('path must be set')
|
9
9
|
end
|
10
|
-
@path = options['path']
|
10
|
+
@path = root_path.join(options['path'])
|
11
11
|
end
|
12
12
|
|
13
13
|
def ask(variables)
|
data/lib/hako/front_config.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'erb'
|
2
2
|
|
3
3
|
module Hako
|
4
|
-
|
5
|
-
|
4
|
+
FrontConfig = Struct.new(:type, :image_tag, :s3, :extra)
|
5
|
+
class FrontConfig
|
6
|
+
S3Config = Struct.new(:region, :bucket, :prefix) do
|
6
7
|
def initialize(options)
|
7
8
|
self.region = options.fetch('region')
|
8
9
|
self.bucket = options.fetch('bucket')
|
@@ -22,6 +23,7 @@ module Hako
|
|
22
23
|
self.type = options.fetch('type')
|
23
24
|
self.image_tag = options.fetch('image_tag')
|
24
25
|
self.s3 = S3Config.new(options.fetch('s3'))
|
26
|
+
self.extra = options.fetch('extra', {})
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
data/lib/hako/fronts/nginx.rb
CHANGED
@@ -11,8 +11,48 @@ module Hako
|
|
11
11
|
|
12
12
|
private
|
13
13
|
|
14
|
+
def templates_directory
|
15
|
+
File.expand_path('../../templates', __FILE__)
|
16
|
+
end
|
17
|
+
|
14
18
|
def nginx_conf_erb
|
15
|
-
File.
|
19
|
+
File.join(templates_directory, 'nginx.conf.erb')
|
20
|
+
end
|
21
|
+
|
22
|
+
def nginx_location_conf_erb
|
23
|
+
File.join(templates_directory, 'nginx.location.conf.erb')
|
24
|
+
end
|
25
|
+
|
26
|
+
def locations
|
27
|
+
locs = @config.extra.fetch('locations', {}).dup
|
28
|
+
locs['/'] ||= {}
|
29
|
+
locs.keys.each do |k|
|
30
|
+
locs[k] = Location.new(locs[k])
|
31
|
+
end
|
32
|
+
locs
|
33
|
+
end
|
34
|
+
|
35
|
+
def client_max_body_size
|
36
|
+
@config.extra.fetch('client_max_body_size', nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
def render_location(listen_spec, location)
|
40
|
+
ERB.new(File.read(nginx_location_conf_erb), nil, '-').result(binding).each_line.map do |line|
|
41
|
+
" #{line}"
|
42
|
+
end.join('')
|
43
|
+
end
|
44
|
+
|
45
|
+
class Location
|
46
|
+
def initialize(config)
|
47
|
+
@config = config
|
48
|
+
end
|
49
|
+
|
50
|
+
def allow_only_from
|
51
|
+
allow = @config.fetch('allow_only_from', nil)
|
52
|
+
if allow
|
53
|
+
allow.flatten
|
54
|
+
end
|
55
|
+
end
|
16
56
|
end
|
17
57
|
end
|
18
58
|
end
|
data/lib/hako/scheduler.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'hako/scheduler'
|
2
|
+
|
3
|
+
module Hako
|
4
|
+
module Schedulers
|
5
|
+
class Echo < Scheduler
|
6
|
+
def initialize(app_id, _options)
|
7
|
+
@app_id = app_id
|
8
|
+
end
|
9
|
+
|
10
|
+
def deploy(image_tag, env, app_port, _front, force: false)
|
11
|
+
puts "Deploy #{image_tag} with app_port=#{app_port}, force=#{force}"
|
12
|
+
puts 'Environment variables:'
|
13
|
+
env.each do |key, val|
|
14
|
+
puts " #{key}=#{val.inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def oneshot(image_tag, env, commands)
|
19
|
+
puts "Run #{image_tag} with oneshot commands=#{commands.inspect}"
|
20
|
+
puts 'Environment variables:'
|
21
|
+
env.each do |key, val|
|
22
|
+
puts " #{key}=#{val.inspect}"
|
23
|
+
end
|
24
|
+
0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/hako/schedulers/ecs.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'aws-sdk'
|
2
2
|
require 'hako'
|
3
|
-
require 'hako/error'
|
4
3
|
require 'hako/scheduler'
|
5
4
|
require 'hako/schedulers/ecs_definition_comparator'
|
5
|
+
require 'hako/schedulers/ecs_elb'
|
6
6
|
|
7
7
|
module Hako
|
8
8
|
module Schedulers
|
9
9
|
class Ecs < Scheduler
|
10
|
-
DEFAULT_CLUSTER = 'default'
|
10
|
+
DEFAULT_CLUSTER = 'default'.freeze
|
11
11
|
DEFAULT_FRONT_PORT = 10000
|
12
12
|
|
13
13
|
def initialize(app_id, options)
|
@@ -19,9 +19,8 @@ module Hako
|
|
19
19
|
region = options.fetch('region') { validation_error!('region must be set') }
|
20
20
|
@role = options.fetch('role', nil)
|
21
21
|
@ecs = Aws::ECS::Client.new(region: region)
|
22
|
-
@elb = Aws::ElasticLoadBalancing::Client.new(region: region)
|
22
|
+
@elb = EcsElb.new(app_id, Aws::ElasticLoadBalancing::Client.new(region: region), options.fetch('elb', nil))
|
23
23
|
@ec2 = Aws::EC2::Client.new(region: region)
|
24
|
-
@elb_config = options.fetch('elb', nil)
|
25
24
|
end
|
26
25
|
|
27
26
|
def deploy(image_tag, env, app_port, front, force: false)
|
@@ -31,7 +30,7 @@ module Hako
|
|
31
30
|
'S3_CONFIG_BUCKET' => front.config.s3.bucket,
|
32
31
|
'S3_CONFIG_KEY' => front.config.s3.key(@app_id),
|
33
32
|
}
|
34
|
-
front_port = determine_front_port
|
33
|
+
front_port = determine_front_port
|
35
34
|
task_definition = register_task_definition(image_tag, env, front.config, front_env, front_port)
|
36
35
|
if task_definition == :noop
|
37
36
|
Hako.logger.info "Task definition isn't changed"
|
@@ -48,11 +47,21 @@ module Hako
|
|
48
47
|
Hako.logger.info "Updated service: #{service.service_arn}"
|
49
48
|
wait_for_ready(service)
|
50
49
|
end
|
51
|
-
Hako.logger.info
|
50
|
+
Hako.logger.info 'Deployment completed'
|
51
|
+
end
|
52
|
+
|
53
|
+
def oneshot(image_tag, env, commands)
|
54
|
+
task_definition = register_task_definition_for_oneshot(image_tag)
|
55
|
+
Hako.logger.info "Registered task definition: #{task_definition.task_definition_arn}"
|
56
|
+
task = run_task(task_definition, env, commands)
|
57
|
+
Hako.logger.info "Started task: #{task.task_arn}"
|
58
|
+
exit_code = wait_for_task(task)
|
59
|
+
Hako.logger.info 'Oneshot task finished'
|
60
|
+
exit_code
|
52
61
|
end
|
53
62
|
|
54
63
|
def status
|
55
|
-
service =
|
64
|
+
service = describe_service
|
56
65
|
unless service
|
57
66
|
puts 'Unavailable'
|
58
67
|
exit 1
|
@@ -60,7 +69,7 @@ module Hako
|
|
60
69
|
|
61
70
|
unless service.load_balancers.empty?
|
62
71
|
lb = service.load_balancers[0]
|
63
|
-
lb_detail = @elb.
|
72
|
+
lb_detail = @elb.describe_load_balancer
|
64
73
|
puts 'Load balancer:'
|
65
74
|
lb_detail.listener_descriptions.each do |ld|
|
66
75
|
l = ld.listener
|
@@ -70,11 +79,12 @@ module Hako
|
|
70
79
|
|
71
80
|
puts 'Deployments:'
|
72
81
|
service.deployments.each do |d|
|
73
|
-
|
82
|
+
abbrev_task_definition = d.task_definition.slice(%r{task-definition/(.+)\z}, 1)
|
83
|
+
puts " [#{d.status}] #{abbrev_task_definition} desired_count=#{d.desired_count}, pending_count=#{d.pending_count}, running_count=#{d.running_count}"
|
74
84
|
end
|
75
85
|
|
76
86
|
puts 'Tasks:'
|
77
|
-
@ecs.list_tasks(cluster: @cluster, service_name:
|
87
|
+
@ecs.list_tasks(cluster: @cluster, service_name: service.service_arn).each do |page|
|
78
88
|
unless page.task_arns.empty?
|
79
89
|
tasks = @ecs.describe_tasks(cluster: @cluster, tasks: page.task_arns).tasks
|
80
90
|
container_instances = {}
|
@@ -108,25 +118,49 @@ module Hako
|
|
108
118
|
end
|
109
119
|
end
|
110
120
|
|
121
|
+
def remove
|
122
|
+
service = describe_service
|
123
|
+
if service
|
124
|
+
@ecs.delete_service(cluster: @cluster, service: @app_id)
|
125
|
+
Hako.logger.info "#{service.service_arn} is deleted"
|
126
|
+
else
|
127
|
+
puts "Service #{@app_id} doesn't exist"
|
128
|
+
end
|
129
|
+
|
130
|
+
@elb.destroy
|
131
|
+
end
|
132
|
+
|
111
133
|
private
|
112
134
|
|
113
|
-
def
|
135
|
+
def describe_service
|
114
136
|
service = @ecs.describe_services(cluster: @cluster, services: [@app_id]).services[0]
|
137
|
+
if service && service.status != 'INACTIVE'
|
138
|
+
service
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def determine_front_port
|
143
|
+
service = describe_service
|
115
144
|
if service
|
116
145
|
find_front_port(service)
|
117
146
|
else
|
118
147
|
max_port = -1
|
119
148
|
@ecs.list_services(cluster: @cluster).each do |page|
|
120
149
|
unless page.service_arns.empty?
|
121
|
-
@ecs.describe_services(cluster: @cluster, services: page.service_arns).services.each do |
|
122
|
-
|
150
|
+
@ecs.describe_services(cluster: @cluster, services: page.service_arns).services.each do |s|
|
151
|
+
if s.status != 'INACTIVE'
|
152
|
+
port = find_front_port(s)
|
153
|
+
if port
|
154
|
+
max_port = [max_port, port].max
|
155
|
+
end
|
156
|
+
end
|
123
157
|
end
|
124
158
|
end
|
125
159
|
end
|
126
160
|
if max_port == -1
|
127
161
|
DEFAULT_FRONT_PORT
|
128
162
|
else
|
129
|
-
max_port+1
|
163
|
+
max_port + 1
|
130
164
|
end
|
131
165
|
end
|
132
166
|
end
|
@@ -137,7 +171,9 @@ module Hako
|
|
137
171
|
task_definition.container_definitions.each do |c|
|
138
172
|
container_definitions[c.name] = c
|
139
173
|
end
|
140
|
-
container_definitions['front']
|
174
|
+
if container_definitions.size == 2 && container_definitions['front'] && container_definitions['app']
|
175
|
+
container_definitions['front'].port_mappings[0].host_port
|
176
|
+
end
|
141
177
|
end
|
142
178
|
|
143
179
|
def task_definition_changed?(front, app)
|
@@ -172,6 +208,23 @@ module Hako
|
|
172
208
|
end
|
173
209
|
end
|
174
210
|
|
211
|
+
def register_task_definition_for_oneshot(image_tag)
|
212
|
+
@ecs.register_task_definition(
|
213
|
+
family: "#{@app_id}-oneshot",
|
214
|
+
container_definitions: [
|
215
|
+
{
|
216
|
+
name: 'oneshot',
|
217
|
+
image: image_tag,
|
218
|
+
cpu: @cpu,
|
219
|
+
memory: @memory,
|
220
|
+
links: [],
|
221
|
+
port_mappings: [],
|
222
|
+
environment: [],
|
223
|
+
},
|
224
|
+
],
|
225
|
+
).task_definition
|
226
|
+
end
|
227
|
+
|
175
228
|
def front_container(front_config, env, front_port)
|
176
229
|
environment = env.map { |k, v| { name: k, value: v } }
|
177
230
|
{
|
@@ -180,7 +233,7 @@ module Hako
|
|
180
233
|
cpu: 100,
|
181
234
|
memory: 100,
|
182
235
|
links: ['app:app'],
|
183
|
-
port_mappings: [{container_port: 80, host_port: front_port, protocol: 'tcp'}],
|
236
|
+
port_mappings: [{ container_port: 80, host_port: front_port, protocol: 'tcp' }],
|
184
237
|
essential: true,
|
185
238
|
environment: environment,
|
186
239
|
}
|
@@ -200,9 +253,69 @@ module Hako
|
|
200
253
|
}
|
201
254
|
end
|
202
255
|
|
256
|
+
def run_task(task_definition, env, commands)
|
257
|
+
environment = env.map { |k, v| { name: k, value: v } }
|
258
|
+
@ecs.run_task(
|
259
|
+
cluster: @cluster,
|
260
|
+
task_definition: task_definition.task_definition_arn,
|
261
|
+
overrides: {
|
262
|
+
container_overrides: [
|
263
|
+
{
|
264
|
+
name: 'oneshot',
|
265
|
+
command: commands,
|
266
|
+
environment: environment,
|
267
|
+
},
|
268
|
+
],
|
269
|
+
},
|
270
|
+
count: 1,
|
271
|
+
started_by: "hako oneshot #{@app_id}",
|
272
|
+
).tasks[0]
|
273
|
+
end
|
274
|
+
|
275
|
+
def wait_for_task(task)
|
276
|
+
task_arn = task.task_arn
|
277
|
+
container_instance_arn = nil
|
278
|
+
started_at = nil
|
279
|
+
loop do
|
280
|
+
task = @ecs.describe_tasks(cluster: @cluster, tasks: [task_arn]).tasks[0]
|
281
|
+
if container_instance_arn != task.container_instance_arn
|
282
|
+
container_instance_arn = task.container_instance_arn
|
283
|
+
report_container_instance(container_instance_arn)
|
284
|
+
end
|
285
|
+
unless started_at
|
286
|
+
started_at = task.started_at
|
287
|
+
if started_at
|
288
|
+
Hako.logger.info "Started at #{started_at}"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
Hako.logger.info " status #{task.last_status}"
|
293
|
+
|
294
|
+
if task.last_status == 'STOPPED'
|
295
|
+
Hako.logger.info "Stopped at #{task.stopped_at}"
|
296
|
+
container = task.containers[0]
|
297
|
+
Hako.logger.info "Exit code is #{container.exit_code}"
|
298
|
+
return container.exit_code
|
299
|
+
end
|
300
|
+
sleep 1
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def report_container_instance(container_instance_arn)
|
305
|
+
container_instance = @ecs.describe_container_instances(cluster: @cluster, container_instances: [container_instance_arn]).container_instances[0]
|
306
|
+
@ec2.describe_tags(filters: [{ name: 'resource-id', values: [container_instance.ec2_instance_id] }]).each do |page|
|
307
|
+
tag = page.tags.find { |t| t.key == 'Name' }
|
308
|
+
if tag
|
309
|
+
Hako.logger.info "Container instance is #{container_instance_arn} (#{tag.value} #{container_instance.ec2_instance_id})"
|
310
|
+
else
|
311
|
+
Hako.logger.info "Container instance is #{container_instance_arn} (#{container_instance.ec2_instance_id})"
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
203
316
|
def create_or_update_service(task_definition_arn, front_port)
|
204
|
-
|
205
|
-
if
|
317
|
+
service = describe_service
|
318
|
+
if service.nil?
|
206
319
|
params = {
|
207
320
|
cluster: @cluster,
|
208
321
|
service_name: @app_id,
|
@@ -210,24 +323,18 @@ module Hako
|
|
210
323
|
desired_count: @desired_count,
|
211
324
|
role: @role,
|
212
325
|
}
|
213
|
-
|
214
|
-
|
215
|
-
params
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
],
|
223
|
-
)
|
326
|
+
name = @elb.find_or_create_load_balancer(front_port)
|
327
|
+
if name
|
328
|
+
params[:load_balancers] = [
|
329
|
+
{
|
330
|
+
load_balancer_name: name,
|
331
|
+
container_name: 'front',
|
332
|
+
container_port: 80,
|
333
|
+
},
|
334
|
+
]
|
224
335
|
end
|
225
336
|
@ecs.create_service(params).service
|
226
337
|
else
|
227
|
-
service = services[0]
|
228
|
-
if service.status != 'ACTIVE'
|
229
|
-
raise Error.new("Service #{service.service_arn} is already exist but the status is #{service.status}")
|
230
|
-
end
|
231
338
|
params = {
|
232
339
|
cluster: @cluster,
|
233
340
|
service: @app_id,
|
@@ -242,7 +349,7 @@ module Hako
|
|
242
349
|
end
|
243
350
|
end
|
244
351
|
|
245
|
-
SERVICE_KEYS = %i[desired_count task_definition]
|
352
|
+
SERVICE_KEYS = %i[desired_count task_definition].freeze
|
246
353
|
|
247
354
|
def service_changed?(service, params)
|
248
355
|
SERVICE_KEYS.each do |key|
|
@@ -254,7 +361,7 @@ module Hako
|
|
254
361
|
end
|
255
362
|
|
256
363
|
def wait_for_ready(service)
|
257
|
-
latest_event_id = service.events
|
364
|
+
latest_event_id = find_latest_event_id(service.events)
|
258
365
|
loop do
|
259
366
|
s = @ecs.describe_services(cluster: service.cluster_arn, services: [service.service_arn]).services[0]
|
260
367
|
s.events.each do |e|
|
@@ -263,7 +370,7 @@ module Hako
|
|
263
370
|
end
|
264
371
|
Hako.logger.info "#{e.created_at}: #{e.message}"
|
265
372
|
end
|
266
|
-
latest_event_id = s.events
|
373
|
+
latest_event_id = find_latest_event_id(s.events)
|
267
374
|
finished = s.deployments.all? { |d| d.status != 'ACTIVE' }
|
268
375
|
if finished
|
269
376
|
return
|
@@ -273,37 +380,12 @@ module Hako
|
|
273
380
|
end
|
274
381
|
end
|
275
382
|
|
276
|
-
def
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
load_balancer_port: l.fetch('load_balancer_port'),
|
282
|
-
instance_port: front_port,
|
283
|
-
ssl_certificate_id: l.fetch('ssl_certificate_id', nil),
|
284
|
-
}
|
285
|
-
end
|
286
|
-
lb = @elb.create_load_balancer(
|
287
|
-
load_balancer_name: elb_name,
|
288
|
-
listeners: listeners,
|
289
|
-
subnets: @elb_config.fetch('subnets'),
|
290
|
-
security_groups: @elb_config.fetch('security_groups'),
|
291
|
-
tags: @elb_config.fetch('tags', {}).map { |k, v| { key: k, value: v.to_s } },
|
292
|
-
)
|
293
|
-
Hako.logger.info "Created ELB #{lb.dns_name} with instance_port=#{front_port}"
|
383
|
+
def find_latest_event_id(events)
|
384
|
+
if events.empty?
|
385
|
+
nil
|
386
|
+
else
|
387
|
+
events[0].id
|
294
388
|
end
|
295
|
-
elb_name
|
296
|
-
end
|
297
|
-
|
298
|
-
def load_balancer_exist?(name)
|
299
|
-
@elb.describe_load_balancers(load_balancer_names: [elb_name])
|
300
|
-
true
|
301
|
-
rescue Aws::ElasticLoadBalancing::Errors::LoadBalancerNotFound
|
302
|
-
false
|
303
|
-
end
|
304
|
-
|
305
|
-
def elb_name
|
306
|
-
"hako-#{@app_id}"
|
307
389
|
end
|
308
390
|
end
|
309
391
|
end
|
@@ -5,9 +5,9 @@ module Hako
|
|
5
5
|
@expected_container = expected_container
|
6
6
|
end
|
7
7
|
|
8
|
-
CONTAINER_KEYS = %i[image cpu memory links]
|
9
|
-
PORT_MAPPING_KEYS = %i[container_port host_port protocol]
|
10
|
-
ENVIRONMENT_KEYS = %i[name value]
|
8
|
+
CONTAINER_KEYS = %i[image cpu memory links].freeze
|
9
|
+
PORT_MAPPING_KEYS = %i[container_port host_port protocol].freeze
|
10
|
+
ENVIRONMENT_KEYS = %i[name value].freeze
|
11
11
|
|
12
12
|
def different?(actual_container)
|
13
13
|
unless actual_container
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'hako'
|
3
|
+
|
4
|
+
module Hako
|
5
|
+
module Schedulers
|
6
|
+
class EcsElb
|
7
|
+
def initialize(app_id, elb, elb_config)
|
8
|
+
@app_id = app_id
|
9
|
+
@elb = elb
|
10
|
+
@elb_config = elb_config
|
11
|
+
end
|
12
|
+
|
13
|
+
def describe_load_balancer
|
14
|
+
@elb.describe_load_balancers(load_balancer_names: [name]).load_balancer_descriptions[0]
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_or_create_load_balancer(front_port)
|
18
|
+
if @elb_config
|
19
|
+
unless exist?
|
20
|
+
listeners = @elb_config.fetch('listeners').map do |l|
|
21
|
+
{
|
22
|
+
protocol: l.fetch('protocol'),
|
23
|
+
load_balancer_port: l.fetch('load_balancer_port'),
|
24
|
+
instance_port: front_port,
|
25
|
+
ssl_certificate_id: l.fetch('ssl_certificate_id', nil),
|
26
|
+
}
|
27
|
+
end
|
28
|
+
lb = @elb.create_load_balancer(
|
29
|
+
load_balancer_name: name,
|
30
|
+
listeners: listeners,
|
31
|
+
subnets: @elb_config.fetch('subnets'),
|
32
|
+
security_groups: @elb_config.fetch('security_groups'),
|
33
|
+
tags: @elb_config.fetch('tags', {}).map { |k, v| { key: k, value: v.to_s } },
|
34
|
+
)
|
35
|
+
Hako.logger.info "Created ELB #{lb.dns_name} with instance_port=#{front_port}"
|
36
|
+
end
|
37
|
+
name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def destroy
|
42
|
+
if exist?
|
43
|
+
@elb.delete_load_balancer(load_balancer_name: name)
|
44
|
+
Hako.logger.info "Deleted ELB #{name}"
|
45
|
+
else
|
46
|
+
Hako.logger.info "ELB #{name} doesn't exist"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def exist?
|
51
|
+
describe_load_balancer
|
52
|
+
true
|
53
|
+
rescue Aws::ElasticLoadBalancing::Errors::LoadBalancerNotFound
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def name
|
60
|
+
"hako-#{@app_id}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
server {
|
2
2
|
listen 80;
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
proxy_read_timeout 20s;
|
4
|
+
<%- if client_max_body_size -%>
|
5
|
+
client_max_body_size <%= client_max_body_size %>;
|
6
|
+
<%- end -%>
|
7
|
+
|
8
|
+
<%- locations.each do |path, location| -%>
|
9
|
+
location <%= path %> {
|
10
|
+
<%= render_location(listen_spec, location) %>
|
12
11
|
}
|
12
|
+
<%- end -%>
|
13
13
|
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<%- if location.allow_only_from -%>
|
2
|
+
<%- location.allow_only_from.each do |ip| -%>
|
3
|
+
allow <%= ip %>;
|
4
|
+
<%- end -%>
|
5
|
+
deny all;
|
6
|
+
<%- end -%>
|
7
|
+
|
8
|
+
proxy_pass http://<%= listen_spec %>;
|
9
|
+
proxy_set_header Host $host;
|
10
|
+
proxy_set_header Connection ""; # for upstream keepalive
|
11
|
+
proxy_http_version 1.1; # for upstream keepalive
|
12
|
+
proxy_connect_timeout 5s;
|
13
|
+
proxy_send_timeout 20s;
|
14
|
+
proxy_read_timeout 20s;
|
data/lib/hako/version.rb
CHANGED
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hako
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kohei Suzuki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 2.1.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.1.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.36.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.36.0
|
83
97
|
description: Deploy Docker container
|
84
98
|
email:
|
85
99
|
- eagletmt@gmail.com
|
@@ -90,6 +104,8 @@ extra_rdoc_files: []
|
|
90
104
|
files:
|
91
105
|
- ".gitignore"
|
92
106
|
- ".rspec"
|
107
|
+
- ".rubocop.yml"
|
108
|
+
- ".rubocop_todo.yml"
|
93
109
|
- ".travis.yml"
|
94
110
|
- Gemfile
|
95
111
|
- README.md
|
@@ -102,6 +118,8 @@ files:
|
|
102
118
|
- exe/hako
|
103
119
|
- hako.gemspec
|
104
120
|
- lib/hako.rb
|
121
|
+
- lib/hako/after_scripts.rb
|
122
|
+
- lib/hako/application.rb
|
105
123
|
- lib/hako/cli.rb
|
106
124
|
- lib/hako/commander.rb
|
107
125
|
- lib/hako/env_expander.rb
|
@@ -115,9 +133,12 @@ files:
|
|
115
133
|
- lib/hako/fronts/nginx.rb
|
116
134
|
- lib/hako/scheduler.rb
|
117
135
|
- lib/hako/schedulers.rb
|
136
|
+
- lib/hako/schedulers/echo.rb
|
118
137
|
- lib/hako/schedulers/ecs.rb
|
119
138
|
- lib/hako/schedulers/ecs_definition_comparator.rb
|
139
|
+
- lib/hako/schedulers/ecs_elb.rb
|
120
140
|
- lib/hako/templates/nginx.conf.erb
|
141
|
+
- lib/hako/templates/nginx.location.conf.erb
|
121
142
|
- lib/hako/version.rb
|
122
143
|
homepage: https://github.com/eagletmt/hako
|
123
144
|
licenses: []
|