algo 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/examples/awesome-cluster.rb +22 -1
- data/lib/algo.rb +3 -0
- data/lib/algo/cli.rb +9 -125
- data/lib/algo/docker/network.rb +4 -0
- data/lib/algo/docker/service.rb +4 -0
- data/lib/algo/dsl.rb +7 -0
- data/lib/algo/dsl/network.rb +27 -0
- data/lib/algo/dsl/service.rb +184 -11
- data/lib/algo/error.rb +9 -0
- data/lib/algo/runner.rb +6 -0
- data/lib/algo/runner/apply.rb +130 -0
- data/lib/algo/runner/rm.rb +46 -0
- data/lib/algo/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86e649323aa163f71b928277a792a0feb51a10d1
|
4
|
+
data.tar.gz: 80a24c0659991faf6098bd2b4044535e5fcf636f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 191b611c8254f37d1883e14053babe39251ed473165adc5b1c77ddb344a71a397b97fcd9def50110de6accf2d67974745fe3330e2f211929ad93850296d49d3c
|
7
|
+
data.tar.gz: f78566709a4b7e3fb9cf1fd4ebc81e51efd2f9ed35c6ead54108c4ec7171618174497a900f43407ca0a82ad755471c36d45b06775f623a712d4a31f57aae41a2
|
data/examples/awesome-cluster.rb
CHANGED
@@ -10,7 +10,13 @@ cluster 'awesomecluster' do
|
|
10
10
|
label 'com.example.sample', 'clusterwidelabel'
|
11
11
|
|
12
12
|
# Define network
|
13
|
-
network 'net1'
|
13
|
+
network 'net1' do
|
14
|
+
ipam do
|
15
|
+
subnet '172.20.0.0/16'
|
16
|
+
ip_range '172.20.10.0/24'
|
17
|
+
gateway '172.20.10.11'
|
18
|
+
end
|
19
|
+
end
|
14
20
|
|
15
21
|
# Define service
|
16
22
|
service 'name' do
|
@@ -23,6 +29,21 @@ cluster 'awesomecluster' do
|
|
23
29
|
|
24
30
|
env 'APP_DOMAIN', 'example.com'
|
25
31
|
|
32
|
+
# Mount host's directory/file
|
33
|
+
volume do
|
34
|
+
type 'bind'
|
35
|
+
source '/tmp/mount'
|
36
|
+
target '/mnt/sample'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Mount host docker volume
|
40
|
+
volume do
|
41
|
+
type 'volume'
|
42
|
+
source 'volume-name'
|
43
|
+
target '/mnt/volume-sample'
|
44
|
+
end
|
45
|
+
|
46
|
+
# join network
|
26
47
|
network 'net1'
|
27
48
|
end
|
28
49
|
|
data/lib/algo.rb
CHANGED
@@ -5,9 +5,12 @@ require 'active_support'
|
|
5
5
|
require 'active_support/core_ext'
|
6
6
|
|
7
7
|
module Algo
|
8
|
+
require 'algo/error'
|
8
9
|
require "algo/version"
|
9
10
|
require "algo/docker"
|
10
11
|
require "algo/dsl"
|
12
|
+
require "algo/runner"
|
11
13
|
require "algo/cli"
|
12
14
|
# Your code goes here...
|
15
|
+
|
13
16
|
end
|
data/lib/algo/cli.rb
CHANGED
@@ -1,70 +1,5 @@
|
|
1
1
|
module Algo
|
2
2
|
class Cli < Thor
|
3
|
-
class ValidationError < StandardError; end
|
4
|
-
|
5
|
-
class ServiceValidator
|
6
|
-
def initialize srv_spec
|
7
|
-
@srv_spec = srv_spec
|
8
|
-
end
|
9
|
-
|
10
|
-
def validate
|
11
|
-
begin
|
12
|
-
@srv = Algo::Docker::Service.find(@srv_spec['Name'])
|
13
|
-
rescue Algo::Docker::Error::NotFoundError
|
14
|
-
@srv = nil
|
15
|
-
end
|
16
|
-
check_networks
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.validate srv_spec
|
20
|
-
new(srv_spec).validate
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def check_networks
|
26
|
-
return true if @srv.blank? or @srv.spec.networks.blank?
|
27
|
-
srv_networks = @srv.spec.networks.map { |n| { 'Target' => n.info['Name'] } }
|
28
|
-
unless srv_networks != @srv_spec['Networks']
|
29
|
-
@srv_spec['Networks'] = @srv.spec.networks.map { |n| { 'Target' => n.info['Id'] } }
|
30
|
-
return true
|
31
|
-
end
|
32
|
-
raise ValidationError, 'changing network in service is not supported'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
class ServiceUpdator
|
37
|
-
|
38
|
-
def initialize srv_spec, options
|
39
|
-
@srv_spec = srv_spec
|
40
|
-
@options = options
|
41
|
-
end
|
42
|
-
|
43
|
-
def update
|
44
|
-
begin
|
45
|
-
srv = Algo::Docker::Service.find(@srv_spec['Name'])
|
46
|
-
if srv.raw_spec == @srv_spec
|
47
|
-
puts "service: #{@srv_spec['Name']}, status: ok"
|
48
|
-
return
|
49
|
-
end
|
50
|
-
srv.update @srv_spec unless dryrun?
|
51
|
-
puts "service: #{@srv_spec['Name']}, status: changed"
|
52
|
-
rescue Algo::Docker::Error::NotFoundError
|
53
|
-
Algo::Docker::Service.create(@srv_spec) unless dryrun?
|
54
|
-
puts "service: #{@srv_spec['Name']}, status: created"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.update srv_spec, dryrun=false
|
59
|
-
new(srv_spec, {dryrun: dryrun}).update
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def dryrun?
|
65
|
-
@options[:dryrun]
|
66
|
-
end
|
67
|
-
end
|
68
3
|
|
69
4
|
desc 'apply [INVENTRY_FILE]', 'Apply configuration to clusters'
|
70
5
|
option :'dry-run', type: :boolean, default: false
|
@@ -76,73 +11,22 @@ module Algo
|
|
76
11
|
def apply inventry
|
77
12
|
Algo::Docker.url = options[:host] if options[:host]
|
78
13
|
Algo::Docker.options = docker_opts if docker_opts.present?
|
79
|
-
puts 'Running with dry-run mode...' if options[:'dry-run']
|
80
14
|
configuration = Algo::Dsl.load({}, inventry)
|
81
|
-
|
82
|
-
puts "Applying to cluster #{cluster['name']}..."
|
83
|
-
|
84
|
-
cluster['networks'].each do |net_spec|
|
85
|
-
begin
|
86
|
-
net = Algo::Docker::Network.find net_spec['Name']
|
87
|
-
puts "network: #{net_spec['Name']}, status: ok"
|
88
|
-
rescue Algo::Docker::Error::NotFoundError
|
89
|
-
Algo::Docker::Network.create net_spec unless options[:'dry-run']
|
90
|
-
puts "network: #{net_spec['Name']}, status: created"
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
cluster['services'].each do |srv_spec|
|
95
|
-
ServiceValidator.validate srv_spec
|
96
|
-
end
|
97
|
-
cluster['services'].each do |srv_spec|
|
98
|
-
ServiceUpdator.update srv_spec, options[:'dry-run']
|
99
|
-
end
|
100
|
-
Algo::Docker::Service.all
|
101
|
-
.select { |srv| srv.spec.name.start_with?("#{cluster['prefix']}-") }
|
102
|
-
.select { |srv| ! srv.spec.name.in? cluster['services'].map { |spec| spec['Name'] } }
|
103
|
-
.map { |srv|
|
104
|
-
srv_name = srv.spec.name
|
105
|
-
srv.remove unless options[:'dry-run']
|
106
|
-
puts "service: #{srv_name}, status: removed"
|
107
|
-
}
|
108
|
-
Algo::Docker::Network.all(skip_default=true)
|
109
|
-
.select { |net| net.info['Name'].start_with?("#{cluster['prefix']}-") }
|
110
|
-
.select { |net| ! net.info['Name'].in? cluster['networks'].map { |net_spec| net_spec['Name'] } }
|
111
|
-
.map { |net|
|
112
|
-
net_name = net.info['Name']
|
113
|
-
net.remove unless options[:'dry-run']
|
114
|
-
puts "network: #{net_name}, status: removed"
|
115
|
-
}
|
116
|
-
puts "Complete applying for cluster #{cluster['name']}!"
|
117
|
-
end
|
118
|
-
rescue ValidationError => e
|
119
|
-
puts 'configuration validation failed because ' + e.message
|
15
|
+
Algo::Runner::Apply.call configuration, options
|
120
16
|
end
|
121
17
|
|
122
18
|
desc 'rm [INVENTRY_FILE]', 'Terminate clusters'
|
123
19
|
option :'dry-run', type: :boolean, default: false
|
20
|
+
option :'url', type: :string, desc: 'docker swarm url like tcp://localhost:2375'
|
21
|
+
option :'client_key', type: :string, desc: 'docker swarm client key path'
|
22
|
+
option :'client_sert', type: :string, desc: 'docker swarm client sert path'
|
23
|
+
option :'ssl_ca_file', type: :string, desc: 'docker swarm ssl ca file path'
|
24
|
+
option :'scheme', type: :string, desc: 'docker swarm connection scheme'
|
124
25
|
def rm inventry
|
125
|
-
|
26
|
+
Algo::Docker.url = options[:host] if options[:host]
|
27
|
+
Algo::Docker.options = docker_opts if docker_opts.present?
|
126
28
|
configuration = Algo::Dsl.load({}, inventry)
|
127
|
-
|
128
|
-
puts "Terminating cluster #{cluster['name']}..."
|
129
|
-
Algo::Docker::Service.all
|
130
|
-
.select { |srv| srv.spec.name.start_with?("#{cluster['prefix']}-") }
|
131
|
-
.map { |srv|
|
132
|
-
srv_name = srv.spec.name
|
133
|
-
srv.remove unless options[:'dry-run']
|
134
|
-
puts "service: #{srv_name}, status: removed"
|
135
|
-
}
|
136
|
-
Algo::Docker::Network.all(skip_default=true)
|
137
|
-
.select { |net| net.info['Name'].start_with?("#{cluster['prefix']}-") }
|
138
|
-
.select { |net| ! net.info['Name'].in? cluster['networks'].map { |net_spec| "#{cluster['prefix']}-#{net_spec['Name']}" } }
|
139
|
-
.map { |net|
|
140
|
-
net_name = net.info['Name']
|
141
|
-
net.remove unless options[:'dry-run']
|
142
|
-
puts "network: #{net_name}, status: removed"
|
143
|
-
}
|
144
|
-
puts "Complete Termination for cluster #{cluster['name']}..."
|
145
|
-
end
|
29
|
+
Algo::Runner::Rm.call configuration, options
|
146
30
|
end
|
147
31
|
|
148
32
|
private
|
data/lib/algo/docker/network.rb
CHANGED
data/lib/algo/docker/service.rb
CHANGED
data/lib/algo/dsl.rb
CHANGED
@@ -21,6 +21,13 @@ module Algo
|
|
21
21
|
dsl.result
|
22
22
|
end
|
23
23
|
|
24
|
+
def self.load_text(options, text)
|
25
|
+
dsl = new(options).tap do |dsl|
|
26
|
+
dsl.instance_eval(text)
|
27
|
+
end
|
28
|
+
dsl.result
|
29
|
+
end
|
30
|
+
|
24
31
|
def initialize(options)
|
25
32
|
@options = CLUSTER_DEFAULT.dup
|
26
33
|
@options.merge!(options)
|
data/lib/algo/dsl/network.rb
CHANGED
@@ -2,6 +2,26 @@ module Algo
|
|
2
2
|
class Dsl
|
3
3
|
module Network
|
4
4
|
|
5
|
+
class IPAMContext
|
6
|
+
attr_reader :context
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@context = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def subnet item
|
13
|
+
@context['Subnet'] = item
|
14
|
+
end
|
15
|
+
|
16
|
+
def ip_range item
|
17
|
+
@context['IPRange'] = item
|
18
|
+
end
|
19
|
+
|
20
|
+
def gateway item
|
21
|
+
@context['Gateway'] = item
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
5
25
|
class Context
|
6
26
|
|
7
27
|
attr_reader :context
|
@@ -36,6 +56,13 @@ module Algo
|
|
36
56
|
@context['EnableIPv6'] = true
|
37
57
|
end
|
38
58
|
|
59
|
+
def ipam &block
|
60
|
+
ctx = Network::IPAMContext.new.tap do |ctx|
|
61
|
+
ctx.instance_eval(&block) if block_given?
|
62
|
+
end
|
63
|
+
@context['IPAM']['Config'] << ctx.context
|
64
|
+
end
|
65
|
+
|
39
66
|
private
|
40
67
|
|
41
68
|
def cluster_prefix
|
data/lib/algo/dsl/service.rb
CHANGED
@@ -2,6 +2,58 @@ module Algo
|
|
2
2
|
class Dsl
|
3
3
|
module Service
|
4
4
|
|
5
|
+
class VolumeContext
|
6
|
+
attr_reader :context
|
7
|
+
|
8
|
+
def initialize clstr_context, srv_context
|
9
|
+
@clstr_context = clstr_context
|
10
|
+
@srv_context = srv_context
|
11
|
+
@context = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def readonly
|
15
|
+
@context['ReadOnly'] = true
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [String] item volume name or host file/directory path
|
19
|
+
def source item
|
20
|
+
raise 'Need to call type at first' unless @context['Type']
|
21
|
+
if @context['Type'] == 'volume'
|
22
|
+
@context['Source'] = "#{cluster_prefix}#{item}"
|
23
|
+
else
|
24
|
+
@context['Source'] = item
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [String] item container mount path
|
29
|
+
def target item
|
30
|
+
@context['Target'] = item
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [String] volume type ex) bind,volume
|
34
|
+
def type item
|
35
|
+
@context['Type'] = item
|
36
|
+
end
|
37
|
+
|
38
|
+
def label key, val
|
39
|
+
@context['VolumeOptions'] ||= {}
|
40
|
+
@context['VolumeOptions']['Labels'] ||= {}
|
41
|
+
@context['VolumeOptions']['Labels'][key] = val
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [String] volume driver type ex) local
|
45
|
+
def driver item
|
46
|
+
@context['VolumeOptions'] ||= {}
|
47
|
+
@context['VolumeOptions'] = { 'DriverConfig' => { 'Name' => item } }
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def cluster_prefix
|
53
|
+
"#{@clstr_context['prefix']}-" if @clstr_context['prefix']
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
5
57
|
class Context
|
6
58
|
attr_reader :context
|
7
59
|
|
@@ -43,20 +95,89 @@ module Algo
|
|
43
95
|
@context['TaskTemplate']['ContainerSpec']['Env'] << "#{key}=#{val}"
|
44
96
|
end
|
45
97
|
|
98
|
+
def workdir name
|
99
|
+
@context['TaskTemplate']['ContainerSpec']['Dir'] = name
|
100
|
+
end
|
101
|
+
|
102
|
+
def user name
|
103
|
+
@context['TaskTemplate']['ContainerSpec']['User'] = name
|
104
|
+
end
|
105
|
+
|
46
106
|
# @param [String] period period string like 30s, 1m, 4h
|
47
107
|
def stop_grace_period period
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
raise
|
108
|
+
@context['TaskTemplate']['ContainerSpec']['StopGracePeriod'] = second_from_string(period) * 1e9
|
109
|
+
end
|
110
|
+
|
111
|
+
def volume &block
|
112
|
+
raise 'should be called in cluster' unless @context
|
113
|
+
ctx = Service::VolumeContext.new(@cluster, @context).tap do |ctx|
|
114
|
+
ctx.instance_eval(&block)
|
56
115
|
end
|
57
|
-
@context['TaskTemplate']['ContainerSpec']['
|
116
|
+
@context['TaskTemplate']['ContainerSpec']['Mounts'] ||= []
|
117
|
+
@context['TaskTemplate']['ContainerSpec']['Mounts'] << ctx.context
|
58
118
|
end
|
59
119
|
|
120
|
+
# Resources
|
121
|
+
|
122
|
+
def limit_cpu decimal
|
123
|
+
@context['TaskTemplate']['Resources'] ||= {}
|
124
|
+
@context['TaskTemplate']['Resources']['Limits'] ||= {}
|
125
|
+
@context['TaskTemplate']['Resources']['Limits']['NanoCPUs'] = decimal * 1e9
|
126
|
+
end
|
127
|
+
|
128
|
+
# @param [String] memory num with unit like 1B 20KB 30MB 1GB
|
129
|
+
def limit_memory memory
|
130
|
+
@context['TaskTemplate']['Resources'] ||= {}
|
131
|
+
@context['TaskTemplate']['Resources']['Limits'] ||= {}
|
132
|
+
@context['TaskTemplate']['Resources']['Limits']['MemoryBytes'] = memory_from_string memory
|
133
|
+
end
|
134
|
+
|
135
|
+
def reserve_cpu decimal
|
136
|
+
@context['TaskTemplate']['Resources'] ||= {}
|
137
|
+
@context['TaskTemplate']['Resources']['Reservation'] ||= {}
|
138
|
+
@context['TaskTemplate']['Resources']['Reservation']['NanoCPUs'] = decimal * 1e9
|
139
|
+
end
|
140
|
+
|
141
|
+
# @param [String] memory num with unit like 1B 20KB 30MB 1GB
|
142
|
+
def reserve_memory memory
|
143
|
+
@context['TaskTemplate']['Resources'] ||= {}
|
144
|
+
@context['TaskTemplate']['Resources']['Reservation'] ||= {}
|
145
|
+
@context['TaskTemplate']['Resources']['Reservation']['MemoryBytes'] = memory_from_string memory
|
146
|
+
end
|
147
|
+
|
148
|
+
# RestartPolicy
|
149
|
+
|
150
|
+
# @param [String] name none, on-failure or any
|
151
|
+
def restart_condition name
|
152
|
+
@context['TaskTemplate']['RestartPolicy'] ||= {}
|
153
|
+
@context['TaskTemplate']['RestartPolicy']['Condition'] = name
|
154
|
+
end
|
155
|
+
|
156
|
+
def restart_delay period
|
157
|
+
@context['TaskTemplate']['RestartPolicy'] ||= {}
|
158
|
+
@context['TaskTemplate']['RestartPolicy']['Delay'] = second_from_string(period) * 10e9
|
159
|
+
end
|
160
|
+
|
161
|
+
# @param [Integer] value
|
162
|
+
def restart_max_attempts value
|
163
|
+
@context['TaskTemplate']['RestartPolicy'] ||= {}
|
164
|
+
@context['TaskTemplate']['RestartPolicy']['Attempts'] = value
|
165
|
+
end
|
166
|
+
|
167
|
+
def restart_window value
|
168
|
+
@context['TaskTemplate']['RestartPolicy'] ||= {}
|
169
|
+
@context['TaskTemplate']['RestartPolicy']['Window'] = second_from_string(period) * 10e9
|
170
|
+
end
|
171
|
+
|
172
|
+
# Placement
|
173
|
+
|
174
|
+
def constraint condition
|
175
|
+
@context['TaskTemplate']['Placement'] ||= {}
|
176
|
+
@context['TaskTemplate']['Placement']['Constraints'] ||= []
|
177
|
+
@context['TaskTemplate']['Placement']['Constraints'] << condition
|
178
|
+
end
|
179
|
+
|
180
|
+
|
60
181
|
# Label
|
61
182
|
|
62
183
|
def label key, val
|
@@ -67,7 +188,31 @@ module Algo
|
|
67
188
|
# Mode
|
68
189
|
|
69
190
|
def replicas replica_size
|
70
|
-
@context['Mode']
|
191
|
+
@context['Mode'] = { 'Replicated' => { 'Replicas' => replica_size } }
|
192
|
+
end
|
193
|
+
|
194
|
+
def global
|
195
|
+
@context['Mode'] = { 'Global' => {} }
|
196
|
+
end
|
197
|
+
|
198
|
+
# EndpointSpec
|
199
|
+
|
200
|
+
# @param [String] mode vip or dnsrr
|
201
|
+
def endpoint_mode mode
|
202
|
+
@context['EndpointSpec'] = { 'Mode' => mode }
|
203
|
+
end
|
204
|
+
|
205
|
+
# @param [String] port like 80 or 80:80 or 80/udp
|
206
|
+
def publish port
|
207
|
+
port, protocol = *port.split('/') if '/'.in? port
|
208
|
+
target, publish = *port.split(':') if ':'.in? port
|
209
|
+
@context['EndpointSpec'] ||= {}
|
210
|
+
@context['EndpointSpec']['Ports'] ||= []
|
211
|
+
@context['EndpointSpec']['Ports'] << {
|
212
|
+
'Protocol' => protocol,
|
213
|
+
'TargetPort' => target,
|
214
|
+
'PublishedPort' => publish
|
215
|
+
}.compact
|
71
216
|
end
|
72
217
|
|
73
218
|
# UpdateConfig
|
@@ -87,7 +232,7 @@ module Algo
|
|
87
232
|
def network name
|
88
233
|
@context['Networks'] ||= []
|
89
234
|
@context['Networks'] << { 'Target' => "#{cluster_prefix}#{name}" }
|
90
|
-
|
235
|
+
end
|
91
236
|
|
92
237
|
private
|
93
238
|
|
@@ -95,6 +240,34 @@ module Algo
|
|
95
240
|
"#{@cluster['prefix']}-" if @cluster['prefix']
|
96
241
|
end
|
97
242
|
|
243
|
+
def second_from_string(period)
|
244
|
+
if period.end_with?('s')
|
245
|
+
period.chomp('s').to_i
|
246
|
+
elsif period.end_with?('m')
|
247
|
+
period.chomp('m').to_i * 60
|
248
|
+
elsif period.end_with?('h')
|
249
|
+
period.chomp('m').to_i * 60 * 60
|
250
|
+
else
|
251
|
+
raise
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def memory_from_string(memory)
|
256
|
+
if memory.end_with?('B')
|
257
|
+
memory.chomp('B').to_i
|
258
|
+
elsif memory.end_with?('KB')
|
259
|
+
memory.chomp('KB').to_i * 1e3
|
260
|
+
elsif memory.end_with?('MB')
|
261
|
+
memory.chomp('MB').to_i * 1e6
|
262
|
+
elsif memory.end_with?('GB')
|
263
|
+
memory.chomp('GB').to_i * 1e9
|
264
|
+
elsif memory.end_with?('TB')
|
265
|
+
memory.chomp('TB').to_i * 1e12
|
266
|
+
else
|
267
|
+
raise
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
98
271
|
end
|
99
272
|
|
100
273
|
def service name, &block
|
data/lib/algo/error.rb
ADDED
data/lib/algo/runner.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
module Algo
|
2
|
+
module Runner
|
3
|
+
class Apply
|
4
|
+
|
5
|
+
class ServiceValidator
|
6
|
+
def initialize srv_spec
|
7
|
+
@srv_spec = srv_spec
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate
|
11
|
+
begin
|
12
|
+
@srv = Algo::Docker::Service.find(@srv_spec['Name'])
|
13
|
+
rescue Algo::Docker::Error::NotFoundError
|
14
|
+
@srv = nil
|
15
|
+
end
|
16
|
+
check_networks
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.validate srv_spec
|
20
|
+
new(srv_spec).validate
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def check_networks
|
26
|
+
return true if @srv.blank? or @srv.spec.networks.blank?
|
27
|
+
srv_networks = @srv.spec.networks.map { |n| { 'Target' => n.name } }
|
28
|
+
unless srv_networks != @srv_spec['Networks']
|
29
|
+
@srv_spec['Networks'] = @srv.spec.networks.map { |n| { 'Target' => n.id } }
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
raise ValidationError, 'changing network in service is not supported'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class ServiceUpdator
|
37
|
+
|
38
|
+
def initialize srv_spec, options
|
39
|
+
@srv_spec = srv_spec
|
40
|
+
@options = options
|
41
|
+
end
|
42
|
+
|
43
|
+
def update
|
44
|
+
begin
|
45
|
+
srv = Algo::Docker::Service.find(@srv_spec['Name'])
|
46
|
+
if srv.raw_spec == @srv_spec
|
47
|
+
puts "service: #{@srv_spec['Name']}, status: ok"
|
48
|
+
return
|
49
|
+
end
|
50
|
+
srv.update @srv_spec unless dryrun?
|
51
|
+
puts "service: #{@srv_spec['Name']}, status: changed"
|
52
|
+
rescue Algo::Docker::Error::NotFoundError
|
53
|
+
Algo::Docker::Service.create(@srv_spec) unless dryrun?
|
54
|
+
puts "service: #{@srv_spec['Name']}, status: created"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.update srv_spec, dryrun=false
|
59
|
+
new(srv_spec, {dryrun: dryrun}).update
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def dryrun?
|
65
|
+
@options[:dryrun]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
attr_reader :configuration, :options
|
70
|
+
|
71
|
+
def initialize configuration, options
|
72
|
+
@configuration = configuration
|
73
|
+
@options = options
|
74
|
+
end
|
75
|
+
|
76
|
+
def call
|
77
|
+
puts 'Running with dry-run mode...' if dryrun?
|
78
|
+
configuration.each do |cluster|
|
79
|
+
puts "Applying to cluster #{cluster['name']}..."
|
80
|
+
|
81
|
+
cluster['networks'].each do |net_spec|
|
82
|
+
begin
|
83
|
+
net = Algo::Docker::Network.find net_spec['Name']
|
84
|
+
puts "network: #{net_spec['Name']}, status: ok"
|
85
|
+
rescue Algo::Docker::Error::NotFoundError
|
86
|
+
Algo::Docker::Network.create net_spec unless dryrun?
|
87
|
+
puts "network: #{net_spec['Name']}, status: created"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
cluster['services'].each do |srv_spec|
|
91
|
+
ServiceValidator.validate srv_spec
|
92
|
+
end
|
93
|
+
cluster['services'].each do |srv_spec|
|
94
|
+
ServiceUpdator.update srv_spec, dryrun?
|
95
|
+
end
|
96
|
+
Algo::Docker::Service.all
|
97
|
+
.select { |srv| srv.spec.name.start_with?("#{cluster['prefix']}-") }
|
98
|
+
.select { |srv| ! srv.spec.name.in? cluster['services'].map { |spec| spec['Name'] } }
|
99
|
+
.map { |srv|
|
100
|
+
srv_name = srv.spec.name
|
101
|
+
srv.remove unless dryrun?
|
102
|
+
puts "service: #{srv_name}, status: removed"
|
103
|
+
}
|
104
|
+
Algo::Docker::Network.all(skip_default=true)
|
105
|
+
.select { |net| net.name.start_with?("#{cluster['prefix']}-") }
|
106
|
+
.select { |net| ! net.name.in? cluster['networks'].map { |net_spec| net_spec['Name'] } }
|
107
|
+
.map { |net|
|
108
|
+
net_name = net.name
|
109
|
+
net.remove unless dryrun?
|
110
|
+
puts "network: #{net_name}, status: removed"
|
111
|
+
}
|
112
|
+
puts "Complete applying for cluster #{cluster['name']}!"
|
113
|
+
end
|
114
|
+
rescue Algo::ValidationError => e
|
115
|
+
puts 'configuration validation failed because ' + e.message
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.call configuration, options
|
119
|
+
new(configuration, options).call
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def dryrun?
|
125
|
+
options[:'dry-run']
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Algo
|
2
|
+
module Runner
|
3
|
+
class Rm
|
4
|
+
attr_reader :configuration, :options
|
5
|
+
|
6
|
+
def initialize configuration, options
|
7
|
+
@configuration = configuration
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
puts 'Running with dry-run mode...' if dryrun?
|
13
|
+
configuration.each do |cluster|
|
14
|
+
puts "Terminating cluster #{cluster['name']}..."
|
15
|
+
Algo::Docker::Service.all
|
16
|
+
.select { |srv| srv.spec.name.start_with?("#{cluster['prefix']}-") }
|
17
|
+
.map { |srv|
|
18
|
+
srv_name = srv.spec.name
|
19
|
+
srv.remove unless dryrun?
|
20
|
+
puts "service: #{srv_name}, status: removed"
|
21
|
+
}
|
22
|
+
Algo::Docker::Network.all(skip_default=true)
|
23
|
+
.select { |net| net.info['Name'].start_with?("#{cluster['prefix']}-") }
|
24
|
+
.select { |net| ! net.info['Name'].in? cluster['networks'].map { |net_spec| "#{cluster['prefix']}-#{net_spec['Name']}" } }
|
25
|
+
.map { |net|
|
26
|
+
net_name = net.info['Name']
|
27
|
+
net.remove unless dryrun?
|
28
|
+
puts "network: #{net_name}, status: removed"
|
29
|
+
}
|
30
|
+
puts "Complete Termination for cluster #{cluster['name']}..."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.call configuration, options
|
35
|
+
new(configuration, options).call
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def dryrun?
|
41
|
+
options[:'dry-run']
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/algo/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: algo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yoshiso
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -140,6 +140,10 @@ files:
|
|
140
140
|
- lib/algo/dsl/cluster.rb
|
141
141
|
- lib/algo/dsl/network.rb
|
142
142
|
- lib/algo/dsl/service.rb
|
143
|
+
- lib/algo/error.rb
|
144
|
+
- lib/algo/runner.rb
|
145
|
+
- lib/algo/runner/apply.rb
|
146
|
+
- lib/algo/runner/rm.rb
|
143
147
|
- lib/algo/version.rb
|
144
148
|
homepage: https://github.com/yoshiso/algo
|
145
149
|
licenses:
|