hako 0.1.0 → 0.2.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 +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
|
+
[](http://badge.fury.io/rb/hako)
|
3
|
+
[](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: []
|