hako 0.13.3 → 0.14.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/.yardopts +1 -0
- data/Rakefile +2 -0
- data/examples/hello-lb.yml +5 -4
- data/examples/hello.yml +4 -4
- data/hako.gemspec +1 -0
- data/lib/hako/app_container.rb +2 -0
- data/lib/hako/application.rb +6 -0
- data/lib/hako/commander.rb +27 -0
- data/lib/hako/container.rb +13 -0
- data/lib/hako/definition_loader.rb +9 -5
- data/lib/hako/env_expander.rb +5 -0
- data/lib/hako/env_providers/file.rb +7 -0
- data/lib/hako/loader.rb +6 -0
- data/lib/hako/scheduler.rb +10 -1
- data/lib/hako/schedulers/ecs.rb +58 -1
- data/lib/hako/schedulers/ecs_definition_comparator.rb +11 -0
- data/lib/hako/schedulers/ecs_elb.rb +9 -0
- data/lib/hako/script.rb +11 -0
- data/lib/hako/scripts/nginx_front.rb +29 -0
- data/lib/hako/version.rb +1 -1
- data/lib/hako/yaml_loader.rb +2 -0
- metadata +18 -3
- data/lib/hako/schedulers/echo.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcee254b9d6c4c81d6d480835e3c48ea7c73285b
|
4
|
+
data.tar.gz: 2b8626bbf5480ed279e1872c757f7932f230a842
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6325c0e207a2e5f89baa61f7a83a19840d5a439097ed6ecaf35e48b5b540b9d8ade04a063ac04a574328b323dd74d9dd2129791d9861757cfbf2ffc696dbaf74
|
7
|
+
data.tar.gz: 202c812931f149fd9db14f58facf35b82c6fc40f896ad13b92125aa95c0f87d243dbd248d9596027cda15d0038bb4aacb903e34cf42c90cd2647d3620033df44
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--private
|
data/Rakefile
CHANGED
data/examples/hello-lb.yml
CHANGED
@@ -24,10 +24,11 @@ app:
|
|
24
24
|
path: hello.env
|
25
25
|
PORT: 3000
|
26
26
|
MESSAGE: '#{username}-san'
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
additional_containers:
|
28
|
+
front:
|
29
|
+
image_tag: hako-nginx
|
30
|
+
memory: 32
|
31
|
+
cpu: 32
|
31
32
|
scripts:
|
32
33
|
- <<: !include front.yml
|
33
34
|
locations:
|
data/examples/hello.yml
CHANGED
@@ -16,11 +16,11 @@ app:
|
|
16
16
|
path: hello.env
|
17
17
|
PORT: 3000
|
18
18
|
MESSAGE: '#{username}-san'
|
19
|
-
front:
|
20
|
-
image_tag: hako-nginx
|
21
|
-
memory: 32
|
22
|
-
cpu: 32
|
23
19
|
additional_containers:
|
20
|
+
front:
|
21
|
+
image_tag: hako-nginx
|
22
|
+
memory: 32
|
23
|
+
cpu: 32
|
24
24
|
redis:
|
25
25
|
image_tag: redis:3.0
|
26
26
|
cpu: 64
|
data/hako.gemspec
CHANGED
data/lib/hako/app_container.rb
CHANGED
data/lib/hako/application.rb
CHANGED
@@ -3,6 +3,12 @@ require 'hako/yaml_loader'
|
|
3
3
|
|
4
4
|
module Hako
|
5
5
|
class Application
|
6
|
+
# @!attribute [r] id
|
7
|
+
# @return [String]
|
8
|
+
# @!attribute [r] root_path
|
9
|
+
# @return [Pathname]
|
10
|
+
# @!attribute [r] yaml
|
11
|
+
# @return [Hash]
|
6
12
|
attr_reader :id, :root_path, :yaml
|
7
13
|
|
8
14
|
def initialize(yaml_path)
|
data/lib/hako/commander.rb
CHANGED
@@ -8,10 +8,15 @@ require 'hako/scripts'
|
|
8
8
|
|
9
9
|
module Hako
|
10
10
|
class Commander
|
11
|
+
# @param [Application] app
|
11
12
|
def initialize(app)
|
12
13
|
@app = app
|
13
14
|
end
|
14
15
|
|
16
|
+
# @param [Boolean] force
|
17
|
+
# @param [String] tag
|
18
|
+
# @param [Boolean] dry_run
|
19
|
+
# @return [nil]
|
15
20
|
def deploy(force: false, tag: 'latest', dry_run: false)
|
16
21
|
containers = load_containers(tag, dry_run: dry_run)
|
17
22
|
scripts = @app.yaml.fetch('scripts', []).map { |config| load_script(config, dry_run: dry_run) }
|
@@ -21,8 +26,14 @@ module Hako
|
|
21
26
|
scripts.each { |script| script.deploy_starting(containers) }
|
22
27
|
scheduler.deploy(containers)
|
23
28
|
scripts.each { |script| script.deploy_finished(containers) }
|
29
|
+
nil
|
24
30
|
end
|
25
31
|
|
32
|
+
# @param [Array<String>] commands
|
33
|
+
# @param [String] tag
|
34
|
+
# @param [Hash<String, String>] env
|
35
|
+
# @param [Boolean] dry_run
|
36
|
+
# @return [nil]
|
26
37
|
def oneshot(commands, tag:, containers:, env: {}, dry_run: false)
|
27
38
|
containers = load_containers(tag, dry_run: dry_run, with: containers)
|
28
39
|
scripts = @app.yaml.fetch('scripts', []).map { |config| load_script(config, dry_run: dry_run) }
|
@@ -37,10 +48,12 @@ module Hako
|
|
37
48
|
exit exit_code
|
38
49
|
end
|
39
50
|
|
51
|
+
# @return [nil]
|
40
52
|
def status
|
41
53
|
load_scheduler(@app.yaml['scheduler'], []).status
|
42
54
|
end
|
43
55
|
|
56
|
+
# @return [nil]
|
44
57
|
def remove
|
45
58
|
scripts = @app.yaml.fetch('scripts', []).map { |config| load_script(config, dry_run: dry_run) }
|
46
59
|
load_scheduler(@app.yaml['scheduler'], scripts).remove
|
@@ -52,6 +65,8 @@ module Hako
|
|
52
65
|
TRAP_SIGNALS = %i[INT TERM].freeze
|
53
66
|
class SignalTrapped < StandardError; end
|
54
67
|
|
68
|
+
# @param [Scheduler] scheduler
|
69
|
+
# @yieldreturn [Fixnum]
|
55
70
|
def with_oneshot_signal_handlers(scheduler, &block)
|
56
71
|
old_handlers = {}
|
57
72
|
trapped = false
|
@@ -77,14 +92,26 @@ module Hako
|
|
77
92
|
exit_code
|
78
93
|
end
|
79
94
|
|
95
|
+
# @param [String] tag
|
96
|
+
# @param [Boolean] dry_run
|
97
|
+
# @param [Array<String>, nil] with
|
98
|
+
# @return [Hash<String, Container>]
|
80
99
|
def load_containers(tag, dry_run:, with: nil)
|
81
100
|
DefinitionLoader.new(@app, dry_run: dry_run).load(tag, with: with)
|
82
101
|
end
|
83
102
|
|
103
|
+
# @param [Hash] yaml
|
104
|
+
# @param [Hash] volumes
|
105
|
+
# @param [Boolean] force
|
106
|
+
# @param [Boolean] dry_run
|
107
|
+
# @return [Scheduler]
|
84
108
|
def load_scheduler(yaml, scripts, volumes: [], force: false, dry_run: false)
|
85
109
|
Loader.new(Hako::Schedulers, 'hako/schedulers').load(yaml.fetch('type')).new(@app.id, yaml, volumes: volumes, scripts: scripts, force: force, dry_run: dry_run)
|
86
110
|
end
|
87
111
|
|
112
|
+
# @param [Hash] yaml
|
113
|
+
# @param [Boolean] dry_run
|
114
|
+
# @return [Script]
|
88
115
|
def load_script(yaml, dry_run:)
|
89
116
|
Loader.new(Hako::Scripts, 'hako/scripts').load(yaml.fetch('type')).new(@app, yaml, dry_run: dry_run)
|
90
117
|
end
|
data/lib/hako/container.rb
CHANGED
@@ -3,8 +3,13 @@ require 'hako/version'
|
|
3
3
|
|
4
4
|
module Hako
|
5
5
|
class Container
|
6
|
+
# @!attribute [r] definition
|
7
|
+
# @return [Hash]
|
6
8
|
attr_reader :definition
|
7
9
|
|
10
|
+
# @param [Application] app
|
11
|
+
# @param [Hash] definition
|
12
|
+
# @param [Boolean] dry_run
|
8
13
|
def initialize(app, definition, dry_run:)
|
9
14
|
@app = app
|
10
15
|
@definition = default_config.merge(definition)
|
@@ -29,10 +34,12 @@ module Hako
|
|
29
34
|
end
|
30
35
|
end
|
31
36
|
|
37
|
+
# @return [Hash<String, String>]
|
32
38
|
def env
|
33
39
|
@expanded_env ||= expand_env(@definition.fetch('env'))
|
34
40
|
end
|
35
41
|
|
42
|
+
# @return [Array<Hash>]
|
36
43
|
def mount_points
|
37
44
|
@definition['mount_points'].map do |mount_point|
|
38
45
|
{
|
@@ -47,6 +54,8 @@ module Hako
|
|
47
54
|
|
48
55
|
PROVIDERS_KEY = '$providers'
|
49
56
|
|
57
|
+
# @param [Hash<String, String>] env
|
58
|
+
# @return [Hash<String, String>]
|
50
59
|
def expand_env(env)
|
51
60
|
env = env.dup
|
52
61
|
provider_types = env.delete(PROVIDERS_KEY) || []
|
@@ -58,12 +67,15 @@ module Hako
|
|
58
67
|
end
|
59
68
|
end
|
60
69
|
|
70
|
+
# @param [Array<Hash>] provider_configs
|
71
|
+
# @return [Array<EnvProvider>]
|
61
72
|
def load_providers(provider_configs)
|
62
73
|
provider_configs.map do |yaml|
|
63
74
|
Loader.new(Hako::EnvProviders, 'hako/env_providers').load(yaml.fetch('type')).new(@app.root_path, yaml)
|
64
75
|
end
|
65
76
|
end
|
66
77
|
|
78
|
+
# @return [Hash]
|
67
79
|
def default_config
|
68
80
|
{
|
69
81
|
'env' => {},
|
@@ -74,6 +86,7 @@ module Hako
|
|
74
86
|
}
|
75
87
|
end
|
76
88
|
|
89
|
+
# @return [Hash<String, String>]
|
77
90
|
def default_labels
|
78
91
|
{
|
79
92
|
'cc.wanko.hako.version' => VERSION,
|
@@ -6,20 +6,22 @@ require 'hako/loader'
|
|
6
6
|
|
7
7
|
module Hako
|
8
8
|
class DefinitionLoader
|
9
|
+
# @param [Application] app
|
10
|
+
# @param [Boolean] dry_run
|
9
11
|
def initialize(app, dry_run:)
|
10
12
|
@app = app
|
11
13
|
@dry_run = dry_run
|
12
14
|
end
|
13
15
|
|
16
|
+
# @param [String] tag
|
17
|
+
# @param [Array<String>, nil] with
|
18
|
+
# @return [Hash<String, Container>]
|
14
19
|
def load(tag, with: nil)
|
15
20
|
additional_containers = @app.yaml.fetch('additional_containers', {})
|
16
21
|
container_names = ['app']
|
17
22
|
if with
|
18
23
|
container_names.concat(with)
|
19
24
|
else
|
20
|
-
if @app.yaml.key?('front')
|
21
|
-
container_names << 'front'
|
22
|
-
end
|
23
25
|
container_names.concat(additional_containers.keys)
|
24
26
|
end
|
25
27
|
|
@@ -28,6 +30,10 @@ module Hako
|
|
28
30
|
|
29
31
|
private
|
30
32
|
|
33
|
+
# @param [String] tag
|
34
|
+
# @param [Array<String>] container_names
|
35
|
+
# @param [Hash<String, Hash>] additional_containers
|
36
|
+
# @return [Hash<String, Container>]
|
31
37
|
def load_containers_from_name(tag, container_names, additional_containers)
|
32
38
|
names = Set.new(container_names)
|
33
39
|
containers = {}
|
@@ -37,8 +43,6 @@ module Hako
|
|
37
43
|
case name
|
38
44
|
when 'app'
|
39
45
|
AppContainer.new(@app, @app.yaml['app'].merge('tag' => tag), dry_run: @dry_run)
|
40
|
-
when 'front'
|
41
|
-
Container.new(@app, @app.yaml.fetch('front'), dry_run: @dry_run)
|
42
46
|
else
|
43
47
|
Container.new(@app, additional_containers.fetch(name), dry_run: @dry_run)
|
44
48
|
end
|
data/lib/hako/env_expander.rb
CHANGED
@@ -12,10 +12,13 @@ module Hako
|
|
12
12
|
Literal = Struct.new(:literal)
|
13
13
|
Variable = Struct.new(:name)
|
14
14
|
|
15
|
+
# @param [Array<EnvProvider>] providers
|
15
16
|
def initialize(providers)
|
16
17
|
@providers = providers
|
17
18
|
end
|
18
19
|
|
20
|
+
# @param [Hash<String, String>] env
|
21
|
+
# @return [Hash<String, String>]
|
19
22
|
def expand(env)
|
20
23
|
parsed_env = {}
|
21
24
|
variables = Set.new
|
@@ -52,6 +55,8 @@ module Hako
|
|
52
55
|
|
53
56
|
private
|
54
57
|
|
58
|
+
# @param [String] value
|
59
|
+
# @return [Array]
|
55
60
|
def parse(value)
|
56
61
|
s = StringScanner.new(value)
|
57
62
|
tokens = []
|
@@ -4,6 +4,8 @@ require 'hako/env_provider'
|
|
4
4
|
module Hako
|
5
5
|
module EnvProviders
|
6
6
|
class File < EnvProvider
|
7
|
+
# @param [Pathname] root_path
|
8
|
+
# @param [Hash<String, Object>] options
|
7
9
|
def initialize(root_path, options)
|
8
10
|
unless options['path']
|
9
11
|
validation_error!('path must be set')
|
@@ -11,6 +13,8 @@ module Hako
|
|
11
13
|
@path = root_path.join(options['path'])
|
12
14
|
end
|
13
15
|
|
16
|
+
# @param [Array<String>] variables
|
17
|
+
# @return [Hash<String, String>]
|
14
18
|
def ask(variables)
|
15
19
|
env = {}
|
16
20
|
read_from_file do |key, val|
|
@@ -23,6 +27,9 @@ module Hako
|
|
23
27
|
|
24
28
|
private
|
25
29
|
|
30
|
+
# @yieldparam [String] key
|
31
|
+
# @yieldparam [String] val
|
32
|
+
# @return [nil]
|
26
33
|
def read_from_file(&block)
|
27
34
|
::File.open(@path) do |f|
|
28
35
|
f.each_line do |line|
|
data/lib/hako/loader.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Hako
|
3
3
|
class Loader
|
4
|
+
# @param [Module] base_module
|
5
|
+
# @param [String] base_path
|
4
6
|
def initialize(base_module, base_path)
|
5
7
|
@base_module = base_module
|
6
8
|
@base_path = base_path
|
7
9
|
end
|
8
10
|
|
11
|
+
# @param [String] name
|
12
|
+
# @return [Module]
|
9
13
|
def load(name)
|
10
14
|
require "#{@base_path}/#{name}"
|
11
15
|
@base_module.const_get(camelize(name))
|
@@ -13,6 +17,8 @@ module Hako
|
|
13
17
|
|
14
18
|
private
|
15
19
|
|
20
|
+
# @param [String] name
|
21
|
+
# @return [String]
|
16
22
|
def camelize(name)
|
17
23
|
name.split('_').map(&:capitalize).join('')
|
18
24
|
end
|
data/lib/hako/scheduler.rb
CHANGED
@@ -6,6 +6,12 @@ module Hako
|
|
6
6
|
class ValidationError < Error
|
7
7
|
end
|
8
8
|
|
9
|
+
# @param [String] app_id
|
10
|
+
# @param [Hash] options
|
11
|
+
# @param [Hash] volumes
|
12
|
+
# @param [Array<Script>] scripts
|
13
|
+
# @param [Boolean] dry_run
|
14
|
+
# @param [Boolean] force
|
9
15
|
def initialize(app_id, options, volumes:, scripts:, dry_run:, force:)
|
10
16
|
@app_id = app_id
|
11
17
|
@volumes = volumes
|
@@ -15,10 +21,12 @@ module Hako
|
|
15
21
|
configure(options)
|
16
22
|
end
|
17
23
|
|
24
|
+
# @param [Hash] _options
|
18
25
|
def configure(_options)
|
19
26
|
end
|
20
27
|
|
21
|
-
|
28
|
+
# @param [Hash<String, Container>] _containers
|
29
|
+
def deploy(_containers)
|
22
30
|
raise NotImplementedError
|
23
31
|
end
|
24
32
|
|
@@ -32,6 +40,7 @@ module Hako
|
|
32
40
|
|
33
41
|
private
|
34
42
|
|
43
|
+
# @param [String] message
|
35
44
|
def validation_error!(message)
|
36
45
|
raise ValidationError.new(message)
|
37
46
|
end
|
data/lib/hako/schedulers/ecs.rb
CHANGED
@@ -13,9 +13,10 @@ module Hako
|
|
13
13
|
|
14
14
|
attr_reader :task
|
15
15
|
|
16
|
+
# @param [Hash<String, Object>] options
|
16
17
|
def configure(options)
|
17
18
|
@cluster = options.fetch('cluster', DEFAULT_CLUSTER)
|
18
|
-
@desired_count = options.fetch('desired_count'
|
19
|
+
@desired_count = options.fetch('desired_count', nil)
|
19
20
|
region = options.fetch('region') { validation_error!('region must be set') }
|
20
21
|
@role = options.fetch('role', nil)
|
21
22
|
@ecs = Aws::ECS::Client.new(region: region)
|
@@ -25,7 +26,12 @@ module Hako
|
|
25
26
|
@container_instance_arn = nil
|
26
27
|
end
|
27
28
|
|
29
|
+
# @param [Hash<String, Container>] containers
|
30
|
+
# @return [nil]
|
28
31
|
def deploy(containers)
|
32
|
+
unless @desired_count
|
33
|
+
validation_error!('desired_count must be set')
|
34
|
+
end
|
29
35
|
front_port = determine_front_port
|
30
36
|
@scripts.each { |script| script.deploy_started(containers, front_port) }
|
31
37
|
definitions = create_definitions(containers)
|
@@ -53,6 +59,10 @@ module Hako
|
|
53
59
|
end
|
54
60
|
end
|
55
61
|
|
62
|
+
# @param [Hash<String, Container>] containers
|
63
|
+
# @param [Array<String>] commands
|
64
|
+
# @param [Hash<String, String>] env
|
65
|
+
# @return [nil]
|
56
66
|
def oneshot(containers, commands, env)
|
57
67
|
definitions = create_definitions(containers)
|
58
68
|
definitions.each do |definition|
|
@@ -83,6 +93,7 @@ module Hako
|
|
83
93
|
end
|
84
94
|
end
|
85
95
|
|
96
|
+
# @return [nil]
|
86
97
|
def stop_oneshot
|
87
98
|
if @task
|
88
99
|
Hako.logger.warn "Stopping #{@task.task_arn}"
|
@@ -91,6 +102,7 @@ module Hako
|
|
91
102
|
end
|
92
103
|
end
|
93
104
|
|
105
|
+
# @return [nil]
|
94
106
|
def status
|
95
107
|
service = describe_service
|
96
108
|
unless service
|
@@ -149,6 +161,7 @@ module Hako
|
|
149
161
|
end
|
150
162
|
end
|
151
163
|
|
164
|
+
# @return [nil]
|
152
165
|
def remove
|
153
166
|
service = describe_service
|
154
167
|
if service
|
@@ -163,6 +176,7 @@ module Hako
|
|
163
176
|
|
164
177
|
private
|
165
178
|
|
179
|
+
# @return [Aws::ECS::Types::Service, nil]
|
166
180
|
def describe_service
|
167
181
|
service = @ecs.describe_services(cluster: @cluster, services: [@app_id]).services[0]
|
168
182
|
if service && service.status != 'INACTIVE'
|
@@ -170,6 +184,7 @@ module Hako
|
|
170
184
|
end
|
171
185
|
end
|
172
186
|
|
187
|
+
# @return [Fixnum]
|
173
188
|
def determine_front_port
|
174
189
|
if @dry_run
|
175
190
|
return DEFAULT_FRONT_PORT
|
@@ -182,6 +197,7 @@ module Hako
|
|
182
197
|
end
|
183
198
|
end
|
184
199
|
|
200
|
+
# @return [Fixnum]
|
185
201
|
def new_front_port
|
186
202
|
max_port = -1
|
187
203
|
@ecs.list_services(cluster: @cluster).each do |page|
|
@@ -203,6 +219,8 @@ module Hako
|
|
203
219
|
end
|
204
220
|
end
|
205
221
|
|
222
|
+
# @param [Aws::ECS::Types::Service] service
|
223
|
+
# @return [Fixnum, nil]
|
206
224
|
def find_front_port(service)
|
207
225
|
task_definition = @ecs.describe_task_definition(task_definition: service.task_definition).task_definition
|
208
226
|
container_definitions = {}
|
@@ -214,6 +232,9 @@ module Hako
|
|
214
232
|
end
|
215
233
|
end
|
216
234
|
|
235
|
+
# @param [String] family
|
236
|
+
# @param [Array<Hash>] definitions
|
237
|
+
# @return [Boolean]
|
217
238
|
def task_definition_changed?(family, definitions)
|
218
239
|
if @force
|
219
240
|
return true
|
@@ -236,6 +257,8 @@ module Hako
|
|
236
257
|
true
|
237
258
|
end
|
238
259
|
|
260
|
+
# @param [Hash<String, Hash<String, String>>] actual_volumes
|
261
|
+
# @return [Boolean]
|
239
262
|
def different_volumes?(actual_volumes)
|
240
263
|
if @volumes.size != actual_volumes.size
|
241
264
|
return true
|
@@ -253,10 +276,15 @@ module Hako
|
|
253
276
|
false
|
254
277
|
end
|
255
278
|
|
279
|
+
# @param [Hash] expected_container
|
280
|
+
# @param [Aws::ECS::Types::ContainerDefinition] actual_container
|
281
|
+
# @return [Boolean]
|
256
282
|
def different_definition?(expected_container, actual_container)
|
257
283
|
EcsDefinitionComparator.new(expected_container).different?(actual_container)
|
258
284
|
end
|
259
285
|
|
286
|
+
# @param [Array<Hash>] definitions
|
287
|
+
# @return [Aws::ECS::Types::TaskDefinition, Symbol]
|
260
288
|
def register_task_definition(definitions)
|
261
289
|
if task_definition_changed?(@app_id, definitions)
|
262
290
|
@ecs.register_task_definition(
|
@@ -269,12 +297,16 @@ module Hako
|
|
269
297
|
end
|
270
298
|
end
|
271
299
|
|
300
|
+
# @param [Hash<String, Container>] containers
|
301
|
+
# @return [nil]
|
272
302
|
def create_definitions(containers)
|
273
303
|
containers.map do |name, container|
|
274
304
|
create_definition(name, container)
|
275
305
|
end
|
276
306
|
end
|
277
307
|
|
308
|
+
# @param [Array<Hash>] definitions
|
309
|
+
# @return [Aws::ECS::Types::TaskDefinition, Symbol]
|
278
310
|
def register_task_definition_for_oneshot(definitions)
|
279
311
|
family = "#{@app_id}-oneshot"
|
280
312
|
if task_definition_changed?(family, definitions)
|
@@ -288,6 +320,7 @@ module Hako
|
|
288
320
|
end
|
289
321
|
end
|
290
322
|
|
323
|
+
# @return [Hash]
|
291
324
|
def volumes_definition
|
292
325
|
@volumes.map do |name, volume|
|
293
326
|
{
|
@@ -297,6 +330,9 @@ module Hako
|
|
297
330
|
end
|
298
331
|
end
|
299
332
|
|
333
|
+
# @param [String] name
|
334
|
+
# @param [Container] container
|
335
|
+
# @return [Hash]
|
300
336
|
def create_definition(name, container)
|
301
337
|
environment = container.env.map { |k, v| { name: k, value: v } }
|
302
338
|
{
|
@@ -313,6 +349,10 @@ module Hako
|
|
313
349
|
}
|
314
350
|
end
|
315
351
|
|
352
|
+
# @param [Aws::ECS::Types::TaskDefinition] task_definition
|
353
|
+
# @param [Array<String>] commands
|
354
|
+
# @param [Hash<String, String>] env
|
355
|
+
# @return [Aws::ECS::Types::Task]
|
316
356
|
def run_task(task_definition, commands, env)
|
317
357
|
environment = env.map { |k, v| { name: k, value: v } }
|
318
358
|
@ecs.run_task(
|
@@ -332,6 +372,7 @@ module Hako
|
|
332
372
|
).tasks[0]
|
333
373
|
end
|
334
374
|
|
375
|
+
# @return [Fixnum]
|
335
376
|
def wait_for_oneshot_finish
|
336
377
|
containers = wait_for_task(@task)
|
337
378
|
@task = nil
|
@@ -350,6 +391,8 @@ module Hako
|
|
350
391
|
exit_code
|
351
392
|
end
|
352
393
|
|
394
|
+
# @param [Aws::ECS::Types::Task] task
|
395
|
+
# @return [nil]
|
353
396
|
def wait_for_task(task)
|
354
397
|
task_arn = task.task_arn
|
355
398
|
loop do
|
@@ -385,6 +428,8 @@ module Hako
|
|
385
428
|
end
|
386
429
|
end
|
387
430
|
|
431
|
+
# @param [String] container_instance_arn
|
432
|
+
# @return [nil]
|
388
433
|
def report_container_instance(container_instance_arn)
|
389
434
|
container_instance = @ecs.describe_container_instances(cluster: @cluster, container_instances: [container_instance_arn]).container_instances[0]
|
390
435
|
@ec2.describe_tags(filters: [{ name: 'resource-id', values: [container_instance.ec2_instance_id] }]).each do |page|
|
@@ -397,6 +442,9 @@ module Hako
|
|
397
442
|
end
|
398
443
|
end
|
399
444
|
|
445
|
+
# @param [String] task_definition_arn
|
446
|
+
# @param [Fixnum] front_port
|
447
|
+
# @return [Aws::ECS::Types::Service, Symbol]
|
400
448
|
def create_or_update_service(task_definition_arn, front_port)
|
401
449
|
service = describe_service
|
402
450
|
if service.nil?
|
@@ -435,6 +483,9 @@ module Hako
|
|
435
483
|
|
436
484
|
SERVICE_KEYS = %i[desired_count task_definition].freeze
|
437
485
|
|
486
|
+
# @param [Aws::ECS::Types::Service] service
|
487
|
+
# @param [Hash] params
|
488
|
+
# @return [Boolean]
|
438
489
|
def service_changed?(service, params)
|
439
490
|
SERVICE_KEYS.each do |key|
|
440
491
|
if service.public_send(key) != params[key]
|
@@ -444,8 +495,11 @@ module Hako
|
|
444
495
|
false
|
445
496
|
end
|
446
497
|
|
498
|
+
# @param [Aws::ECS::Types::Service] service
|
499
|
+
# @return [nil]
|
447
500
|
def wait_for_ready(service)
|
448
501
|
latest_event_id = find_latest_event_id(service.events)
|
502
|
+
Hako.logger.debug " latest_event_id=#{latest_event_id}"
|
449
503
|
loop do
|
450
504
|
s = @ecs.describe_services(cluster: service.cluster_arn, services: [service.service_arn]).services[0]
|
451
505
|
s.events.each do |e|
|
@@ -456,6 +510,7 @@ module Hako
|
|
456
510
|
end
|
457
511
|
latest_event_id = find_latest_event_id(s.events)
|
458
512
|
finished = s.deployments.all? { |d| d.status != 'ACTIVE' }
|
513
|
+
Hako.logger.debug " latest_event_id=#{latest_event_id}, deployment statuses=#{s.deployments.map(&:status)}"
|
459
514
|
if finished
|
460
515
|
return
|
461
516
|
else
|
@@ -464,6 +519,8 @@ module Hako
|
|
464
519
|
end
|
465
520
|
end
|
466
521
|
|
522
|
+
# @param [Array<Aws::ECS::Types::ServiceEvent>] events
|
523
|
+
# @return [String, nil]
|
467
524
|
def find_latest_event_id(events)
|
468
525
|
if events.empty?
|
469
526
|
nil
|
@@ -2,6 +2,7 @@
|
|
2
2
|
module Hako
|
3
3
|
module Schedulers
|
4
4
|
class EcsDefinitionComparator
|
5
|
+
# @param [Hash] expected_container
|
5
6
|
def initialize(expected_container)
|
6
7
|
@expected_container = expected_container
|
7
8
|
end
|
@@ -11,6 +12,8 @@ module Hako
|
|
11
12
|
ENVIRONMENT_KEYS = %i[name value].freeze
|
12
13
|
MOUNT_POINT_KEYS = %i[source_volume container_path read_only].freeze
|
13
14
|
|
15
|
+
# @param [Aws::ECS::Types::ContainerDefinition] actual_container
|
16
|
+
# @return [Boolean]
|
14
17
|
def different?(actual_container)
|
15
18
|
unless actual_container
|
16
19
|
return true
|
@@ -33,6 +36,10 @@ module Hako
|
|
33
36
|
|
34
37
|
private
|
35
38
|
|
39
|
+
# @param [Hash<String, Object>] expected
|
40
|
+
# @param [Hash<String, Object>] actual
|
41
|
+
# @param [Array<String>] keys
|
42
|
+
# @return [Boolean]
|
36
43
|
def different_members?(expected, actual, keys)
|
37
44
|
keys.each do |key|
|
38
45
|
if actual.public_send(key) != expected[key]
|
@@ -42,6 +49,10 @@ module Hako
|
|
42
49
|
false
|
43
50
|
end
|
44
51
|
|
52
|
+
# @param [Hash<String, Array<Object>>] expected
|
53
|
+
# @param [Hash<String, Array<Object>>] actual
|
54
|
+
# @param [Array<String>] keys
|
55
|
+
# @return [Boolean]
|
45
56
|
def different_array?(expected, actual, key, keys)
|
46
57
|
if expected[key].size != actual.public_send(key).size
|
47
58
|
return true
|
@@ -5,16 +5,22 @@ require 'hako'
|
|
5
5
|
module Hako
|
6
6
|
module Schedulers
|
7
7
|
class EcsElb
|
8
|
+
# @param [String] app_id
|
9
|
+
# @param [Aws::ElasticLoadBalancing::Client] elb
|
10
|
+
# @param [Hash] elb_config
|
8
11
|
def initialize(app_id, elb, elb_config)
|
9
12
|
@app_id = app_id
|
10
13
|
@elb = elb
|
11
14
|
@elb_config = elb_config
|
12
15
|
end
|
13
16
|
|
17
|
+
# @return [Aws::ElasticLoadBalancing::Types::LoadBalancerDescription]
|
14
18
|
def describe_load_balancer
|
15
19
|
@elb.describe_load_balancers(load_balancer_names: [name]).load_balancer_descriptions[0]
|
16
20
|
end
|
17
21
|
|
22
|
+
# @param [Fixnum] front_port
|
23
|
+
# @return [nil]
|
18
24
|
def find_or_create_load_balancer(front_port)
|
19
25
|
if @elb_config
|
20
26
|
unless exist?
|
@@ -40,6 +46,7 @@ module Hako
|
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
49
|
+
# @return [nil]
|
43
50
|
def destroy
|
44
51
|
if exist?
|
45
52
|
@elb.delete_load_balancer(load_balancer_name: name)
|
@@ -49,6 +56,7 @@ module Hako
|
|
49
56
|
end
|
50
57
|
end
|
51
58
|
|
59
|
+
# @return [Boolean]
|
52
60
|
def exist?
|
53
61
|
describe_load_balancer
|
54
62
|
true
|
@@ -56,6 +64,7 @@ module Hako
|
|
56
64
|
false
|
57
65
|
end
|
58
66
|
|
67
|
+
# @return [String]
|
59
68
|
def name
|
60
69
|
"hako-#{@app_id}"
|
61
70
|
end
|
data/lib/hako/script.rb
CHANGED
@@ -3,32 +3,43 @@ require 'hako/scripts'
|
|
3
3
|
|
4
4
|
module Hako
|
5
5
|
class Script
|
6
|
+
# @param [Application] app
|
7
|
+
# @param [Hash] options
|
8
|
+
# @param [Boolean] dry_run
|
6
9
|
def initialize(app, options, dry_run:)
|
7
10
|
@app = app
|
8
11
|
@dry_run = dry_run
|
9
12
|
configure(options)
|
10
13
|
end
|
11
14
|
|
15
|
+
# @param [Hash<String, Container>] _containers
|
12
16
|
def deploy_starting(_containers)
|
13
17
|
end
|
14
18
|
|
19
|
+
# @param [Hash<String, Container>] _containers
|
20
|
+
# @param [Fixnum] _front_port
|
15
21
|
def deploy_started(_containers, _front_port)
|
16
22
|
end
|
17
23
|
|
24
|
+
# @param [Hash<String, Container>] _containers
|
18
25
|
def deploy_finished(_containers)
|
19
26
|
end
|
20
27
|
|
28
|
+
# @param [Hash<String, Container>] _containers
|
21
29
|
def oneshot_starting(_containers)
|
22
30
|
end
|
23
31
|
|
32
|
+
# @param [Scheduler] _scheduler
|
24
33
|
def oneshot_started(_scheduler)
|
25
34
|
end
|
26
35
|
|
36
|
+
# @param [Hash<String, Container>] _containers
|
27
37
|
def oneshot_finished(_containers)
|
28
38
|
end
|
29
39
|
|
30
40
|
private
|
31
41
|
|
42
|
+
# @param [Hash] _options
|
32
43
|
def configure(_options)
|
33
44
|
end
|
34
45
|
end
|
@@ -8,6 +8,7 @@ module Hako
|
|
8
8
|
module Scripts
|
9
9
|
class NginxFront < Script
|
10
10
|
S3Config = Struct.new(:region, :bucket, :prefix) do
|
11
|
+
# @param [Hash] options
|
11
12
|
def initialize(options)
|
12
13
|
self.region = options.fetch('region')
|
13
14
|
self.bucket = options.fetch('bucket')
|
@@ -23,6 +24,8 @@ module Hako
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
27
|
+
# @param [Hash<String, Container>] containers
|
28
|
+
# @return [nil]
|
26
29
|
def deploy_starting(containers)
|
27
30
|
front = containers.fetch('front')
|
28
31
|
front.definition['env'].merge!(
|
@@ -33,6 +36,9 @@ module Hako
|
|
33
36
|
front.links << link_app
|
34
37
|
end
|
35
38
|
|
39
|
+
# @param [Hash<String, Container>] containers
|
40
|
+
# @param [Fixnum] front_port
|
41
|
+
# @return [nil]
|
36
42
|
def deploy_started(containers, front_port)
|
37
43
|
app = containers.fetch('app')
|
38
44
|
front = containers.fetch('front')
|
@@ -43,6 +49,8 @@ module Hako
|
|
43
49
|
|
44
50
|
private
|
45
51
|
|
52
|
+
# @param [Hash] options
|
53
|
+
# @return [nil]
|
46
54
|
def configure(options)
|
47
55
|
super
|
48
56
|
@options = options
|
@@ -50,18 +58,24 @@ module Hako
|
|
50
58
|
@s3 = S3Config.new(@options.fetch('s3'))
|
51
59
|
end
|
52
60
|
|
61
|
+
# @return [String]
|
53
62
|
def link_app
|
54
63
|
'app:app'
|
55
64
|
end
|
56
65
|
|
66
|
+
# @param [Fixnum] front_port
|
67
|
+
# @return [Hash]
|
57
68
|
def port_mapping(front_port)
|
58
69
|
{ container_port: 80, host_port: front_port, protocol: 'tcp' }
|
59
70
|
end
|
60
71
|
|
72
|
+
# @param [Fixnum] app_port
|
73
|
+
# @return [String]
|
61
74
|
def generate_config(app_port)
|
62
75
|
Generator.new(@options, app_port).render
|
63
76
|
end
|
64
77
|
|
78
|
+
# @return [Hash]
|
65
79
|
def upload_config(front_conf)
|
66
80
|
if @dry_run
|
67
81
|
Hako.logger.info "Generated configuration:\n#{front_conf}"
|
@@ -74,38 +88,47 @@ module Hako
|
|
74
88
|
end
|
75
89
|
end
|
76
90
|
|
91
|
+
# @return [Aws::S3::Client]
|
77
92
|
def s3_client
|
78
93
|
@s3_client ||= Aws::S3::Client.new(region: @s3.region)
|
79
94
|
end
|
80
95
|
|
81
96
|
class Generator
|
97
|
+
# @param [Hash] options
|
98
|
+
# @param [Fixnum] app_port
|
82
99
|
def initialize(options, app_port)
|
83
100
|
@options = options
|
84
101
|
@app_port = app_port
|
85
102
|
end
|
86
103
|
|
104
|
+
# @return [String]
|
87
105
|
def render
|
88
106
|
ERB.new(File.read(nginx_conf_erb), nil, '-').result(binding)
|
89
107
|
end
|
90
108
|
|
91
109
|
private
|
92
110
|
|
111
|
+
# @return [String]
|
93
112
|
def listen_spec
|
94
113
|
"app:#{@app_port}"
|
95
114
|
end
|
96
115
|
|
116
|
+
# @return [String]
|
97
117
|
def templates_directory
|
98
118
|
File.expand_path('../../templates', __FILE__)
|
99
119
|
end
|
100
120
|
|
121
|
+
# @return [String]
|
101
122
|
def nginx_conf_erb
|
102
123
|
File.join(templates_directory, 'nginx.conf.erb')
|
103
124
|
end
|
104
125
|
|
126
|
+
# @return [String]
|
105
127
|
def nginx_location_conf_erb
|
106
128
|
File.join(templates_directory, 'nginx.location.conf.erb')
|
107
129
|
end
|
108
130
|
|
131
|
+
# @return [Hash<String, Location>]
|
109
132
|
def locations
|
110
133
|
locs = @options.fetch('locations').dup
|
111
134
|
locs.keys.each do |k|
|
@@ -114,10 +137,14 @@ module Hako
|
|
114
137
|
locs
|
115
138
|
end
|
116
139
|
|
140
|
+
# @return [String, nil]
|
117
141
|
def client_max_body_size
|
118
142
|
@options.fetch('client_max_body_size', nil)
|
119
143
|
end
|
120
144
|
|
145
|
+
# @param [String] listen_spec
|
146
|
+
# @param [Location] location
|
147
|
+
# @return [String]
|
121
148
|
def render_location(listen_spec, location)
|
122
149
|
ERB.new(File.read(nginx_location_conf_erb), nil, '-').result(binding).each_line.map do |line|
|
123
150
|
" #{line}"
|
@@ -125,10 +152,12 @@ module Hako
|
|
125
152
|
end
|
126
153
|
|
127
154
|
class Location
|
155
|
+
# @param [Hash] config
|
128
156
|
def initialize(config)
|
129
157
|
@config = config
|
130
158
|
end
|
131
159
|
|
160
|
+
# @return [Array<String>, nil]
|
132
161
|
def allow_only_from
|
133
162
|
allow = @config.fetch('allow_only_from', nil)
|
134
163
|
if allow
|
data/lib/hako/version.rb
CHANGED
data/lib/hako/yaml_loader.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hako
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.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: 2016-04-
|
11
|
+
date: 2016-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 0.36.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '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'
|
83
97
|
description: Deploy Docker container
|
84
98
|
email:
|
85
99
|
- eagletmt@gmail.com
|
@@ -93,6 +107,7 @@ files:
|
|
93
107
|
- ".rubocop.yml"
|
94
108
|
- ".rubocop_todo.yml"
|
95
109
|
- ".travis.yml"
|
110
|
+
- ".yardopts"
|
96
111
|
- Gemfile
|
97
112
|
- README.md
|
98
113
|
- Rakefile
|
@@ -119,7 +134,6 @@ files:
|
|
119
134
|
- lib/hako/loader.rb
|
120
135
|
- lib/hako/scheduler.rb
|
121
136
|
- lib/hako/schedulers.rb
|
122
|
-
- lib/hako/schedulers/echo.rb
|
123
137
|
- lib/hako/schedulers/ecs.rb
|
124
138
|
- lib/hako/schedulers/ecs_definition_comparator.rb
|
125
139
|
- lib/hako/schedulers/ecs_elb.rb
|
@@ -154,3 +168,4 @@ signing_key:
|
|
154
168
|
specification_version: 4
|
155
169
|
summary: Deploy Docker container
|
156
170
|
test_files: []
|
171
|
+
has_rdoc:
|
data/lib/hako/schedulers/echo.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'hako/scheduler'
|
3
|
-
|
4
|
-
module Hako
|
5
|
-
module Schedulers
|
6
|
-
class Echo < Scheduler
|
7
|
-
def deploy(containers)
|
8
|
-
app = containers.fetch('app')
|
9
|
-
puts "Deploy #{app.image_tag} with app_port=#{app.port}, force=#{@force}, dry_run=#{@dry_run}"
|
10
|
-
puts 'Environment variables:'
|
11
|
-
app.env.each do |key, val|
|
12
|
-
puts " #{key}=#{val.inspect}"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def oneshot(containers, commands, env)
|
17
|
-
app = containers.fetch('app')
|
18
|
-
puts "Run #{app.image_tag} with oneshot commands=#{commands.inspect}"
|
19
|
-
puts 'Environment variables:'
|
20
|
-
env.each do |key, val|
|
21
|
-
puts " #{key}=#{val.inspect}"
|
22
|
-
end
|
23
|
-
0
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|