indocker 0.1.6 → 0.1.11

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -0
  3. data/Gemfile.lock +10 -4
  4. data/README.md +13 -2
  5. data/example/indocker/bin/deploy +19 -13
  6. data/example/indocker/bounded_contexts/shared/bad_container_build/Dockerfile +3 -0
  7. data/example/indocker/bounded_contexts/shared/bad_container_build/container.rb +5 -0
  8. data/example/indocker/bounded_contexts/shared/bad_container_build/image.rb +3 -0
  9. data/example/indocker/bounded_contexts/shared/bad_container_start/Dockerfile +8 -0
  10. data/example/indocker/bounded_contexts/shared/bad_container_start/build_context/bin/run +3 -0
  11. data/example/indocker/bounded_contexts/shared/bad_container_start/container.rb +5 -0
  12. data/example/indocker/bounded_contexts/shared/bad_container_start/image.rb +3 -0
  13. data/example/indocker/bounded_contexts/shared/good_container/Dockerfile +4 -0
  14. data/example/indocker/bounded_contexts/shared/good_container/container.rb +5 -0
  15. data/example/indocker/bounded_contexts/shared/good_container/image.rb +3 -0
  16. data/example/indocker/configurations/external.rb +18 -0
  17. data/example/indocker/infrastructure/build_servers.rb +11 -0
  18. data/example/indocker/infrastructure/servers.rb +11 -0
  19. data/example/indocker/setup.rb +1 -1
  20. data/example/spec/indocker_spec.rb +39 -0
  21. data/example/spec/spec_helper.rb +39 -0
  22. data/indocker.gemspec +1 -1
  23. data/lib/indocker.rb +37 -57
  24. data/lib/indocker/build_context.rb +13 -12
  25. data/lib/indocker/build_context_pool.rb +5 -1
  26. data/lib/indocker/configuration_deployer.rb +125 -93
  27. data/lib/indocker/container_deployer.rb +17 -7
  28. data/lib/indocker/context_args.rb +2 -0
  29. data/lib/indocker/deploy_context.rb +10 -8
  30. data/lib/indocker/deployment_policy.rb +22 -0
  31. data/lib/indocker/deployment_progress.rb +7 -2
  32. data/lib/indocker/images_compiler.rb +1 -1
  33. data/lib/indocker/logger_factory.rb +37 -0
  34. data/lib/indocker/server_pool.rb +9 -1
  35. data/lib/indocker/ssh_session.rb +21 -10
  36. data/lib/indocker/version.rb +1 -1
  37. metadata +19 -5
  38. data/lib/indocker/ssh_result_logger.rb +0 -18
@@ -8,17 +8,18 @@ class Indocker::BuildContext
8
8
  @logger = logger
9
9
  @helper = Indocker::BuildContextHelper.new(@configuration, @build_server)
10
10
  @server = build_server
11
+ @compiled_images = Hash.new(false)
12
+ end
11
13
 
12
- if build_server
13
- @session = Indocker::SshSession.new(
14
- host: build_server.host,
15
- user: build_server.user,
16
- port: build_server.port,
17
- logger: @logger
18
- )
19
- end
14
+ def create_session!
15
+ return unless @server
20
16
 
21
- @compiled_images = Hash.new(false)
17
+ @session = Indocker::SshSession.new(
18
+ host: @server.host,
19
+ user: @server.user,
20
+ port: @server.port,
21
+ logger: @logger
22
+ )
22
23
  end
23
24
 
24
25
  def exec!(command)
@@ -69,10 +70,10 @@ class Indocker::BuildContext
69
70
  build_args = args.join(' ')
70
71
 
71
72
  res = Indocker::Docker.build(image.local_registry_url, build_args)
72
-
73
+
73
74
  if res.exit_status != 0
74
- @logger.error("image compilation :#{image.name} failed")
75
- @logger.error(res.stdout)
75
+ puts "image compilation :#{image.name} failed"
76
+ puts res.stdout
76
77
  exit 1
77
78
  end
78
79
 
@@ -7,11 +7,15 @@ class Indocker::BuildContextPool
7
7
  Indocker::BuildContext.new(
8
8
  logger: @logger,
9
9
  configuration: configuration,
10
- build_server: build_server,
10
+ build_server: build_server
11
11
  )
12
12
  end
13
13
  end
14
14
 
15
+ def create_sessions!
16
+ @contexts.each(&:create_session!)
17
+ end
18
+
15
19
  def get
16
20
  context = nil
17
21
 
@@ -5,92 +5,109 @@ require 'tempfile'
5
5
  class Indocker::ConfigurationDeployer
6
6
  REMOTE_OPERATION_TIMEOUT = 60
7
7
 
8
- def initialize(logger)
8
+ def initialize(logger:, global_logger:)
9
9
  Thread.abort_on_exception = true # abort all threads if exception occurs
10
10
 
11
11
  @logger = logger
12
- @global_logger = Logger.new(STDOUT)
13
- @global_logger.formatter = logger.formatter
12
+ @global_logger = global_logger
14
13
 
15
14
  @progress = Indocker::DeploymentProgress.new(
16
15
  Indocker.logger.level == Logger::DEBUG ? nil : Logger.new(STDOUT)
17
16
  )
18
17
  end
19
18
 
20
- def run(configuration:, deploy_containers:, skip_tags:, deploy_tags:, skip_dependent:,
21
- skip_containers:, servers:, skip_build:, force_restart:, skip_force_restart:, auto_confirm:, require_confirmation:)
19
+ # Launch deployment & measure the benchmark
20
+ def run(configuration:, deployment_policy:)
22
21
  build_context_pool = nil
23
22
  deployer = nil
24
23
 
25
24
  time = Benchmark.realtime do
26
- if force_restart
25
+ if deployment_policy.force_restart
27
26
  @logger.warn("WARNING. All containers will be forced to restart.")
28
27
  end
29
28
 
30
- if skip_build
29
+ if deployment_policy.skip_build
31
30
  @logger.warn("WARNING. Images build step will be skipped")
32
31
  end
33
32
 
34
- preload_containers(configuration)
35
-
36
- containers = find_deploy_containers(configuration, deploy_containers, deploy_tags, skip_dependent, skip_containers, servers, skip_tags, auto_confirm, require_confirmation)
37
- containers = containers.uniq {|c| c.name}
38
-
39
- clonner = Indocker::Repositories::Clonner.new(configuration, @logger)
40
-
41
- @global_logger.info("Establishing ssh sessions to all servers...")
42
-
43
- build_context_pool = Indocker::BuildContextPool.new(configuration: configuration, logger: @logger)
44
- deployer = Indocker::ContainerDeployer.new(configuration: configuration, logger: @logger)
45
-
46
- build_servers = configuration
47
- .build_servers
48
- .uniq { |s| s.host }
49
-
50
- deploy_servers = containers
51
- .map(&:servers)
52
- .flatten
53
- .uniq { |s| s.host }
33
+ if deployment_policy.skip_deploy
34
+ @logger.warn("WARNING. Images deploy step will be skipped")
35
+ end
54
36
 
55
- servers = (deploy_servers + build_servers).uniq { |s| s.host }
37
+ run!(configuration: configuration, deployment_policy: deployment_policy)
38
+ end
56
39
 
57
- @progress.setup(
58
- binaries_servers: servers,
59
- build_servers: build_servers,
60
- deploy_servers: deploy_servers,
61
- env_files: configuration.env_files.keys,
62
- repositories: configuration.repositories.keys,
63
- force_restart: force_restart,
64
- skip_build: skip_build,
65
- containers: containers,
66
- artifact_servers: configuration.artifact_servers,
67
- )
40
+ @global_logger.info("Deployment finished".green)
41
+ @global_logger.info("Total time taken: #{time.round}s".green)
42
+ end
68
43
 
69
- remote_operations = sync_indocker(servers)
70
- wait_remote_operations(remote_operations)
44
+ # The main flow of the deployment would happen in this method.
45
+ def run!(configuration:, deployment_policy:)
46
+ containers = find_containers_to_deploy(configuration, deployment_policy)
47
+
48
+ clonner = Indocker::Repositories::Clonner.new(configuration, @logger)
49
+ build_context_pool = Indocker::BuildContextPool.new(configuration: configuration, logger: @logger)
50
+ deployer = Indocker::ContainerDeployer.new(configuration: configuration, logger: @logger)
51
+
52
+ @global_logger.info("Establishing ssh sessions to all servers...")
53
+ build_context_pool.create_sessions!
54
+ deployer.create_sessions!
55
+
56
+ build_servers = configuration
57
+ .build_servers
58
+ .uniq { |s| s.host }
59
+
60
+ deploy_servers = containers
61
+ .map(&:servers)
62
+ .flatten
63
+ .uniq { |s| s.host }
64
+
65
+ servers = (deploy_servers + build_servers).uniq { |s| s.host }
66
+
67
+ @progress.setup(
68
+ binaries_servers: servers,
69
+ build_servers: build_servers,
70
+ deploy_servers: deploy_servers,
71
+ env_files: configuration.env_files.keys,
72
+ repositories: configuration.repositories.keys,
73
+ force_restart: deployment_policy.force_restart,
74
+ skip_build: deployment_policy.skip_build,
75
+ skip_deploy: deployment_policy.skip_deploy,
76
+ containers: containers,
77
+ artifact_servers: configuration.artifact_servers,
78
+ )
71
79
 
72
- remote_operations = sync_env_files(deploy_servers, configuration.env_files)
73
- wait_remote_operations(remote_operations)
80
+ remote_operations = sync_indocker(servers)
81
+ wait_remote_operations(remote_operations)
74
82
 
75
- remote_operations = pull_repositories(clonner, build_servers, configuration.repositories)
76
- wait_remote_operations(remote_operations)
83
+ remote_operations = sync_env_files(deploy_servers, configuration.env_files)
84
+ wait_remote_operations(remote_operations)
77
85
 
78
- remote_operations = sync_artifacts(clonner, configuration.artifact_servers)
79
- wait_remote_operations(remote_operations)
86
+ remote_operations = pull_repositories(clonner, build_servers, configuration.repositories)
87
+ wait_remote_operations(remote_operations)
80
88
 
81
- update_crontab_redeploy_rules(configuration, build_servers.first)
89
+ remote_operations = sync_artifacts(clonner, configuration.artifact_servers)
90
+ wait_remote_operations(remote_operations)
82
91
 
83
- containers.uniq.each do |container|
84
- recursively_deploy_container(configuration, deployer, build_context_pool, container, containers, skip_build, force_restart, skip_force_restart)
85
- end
92
+ update_crontab_redeploy_rules(configuration, build_servers.first)
86
93
 
87
- Thread
88
- .list
89
- .each { |t| t.join if t != Thread.current }
94
+ containers.uniq.each do |container|
95
+ recursively_deploy_container(
96
+ configuration,
97
+ deployer,
98
+ build_context_pool,
99
+ container,
100
+ containers,
101
+ deployment_policy.skip_build,
102
+ deployment_policy.skip_deploy,
103
+ deployment_policy.force_restart,
104
+ deployment_policy.skip_force_restart
105
+ )
90
106
  end
91
107
 
92
- @global_logger.info("Deployment finished".green)
93
- @global_logger.info("Total time taken: #{time.round}s".green)
108
+ Thread
109
+ .list
110
+ .each { |t| t.join if t != Thread.current }
94
111
  ensure
95
112
  build_context_pool.close_sessions if build_context_pool
96
113
  deployer.close_sessions if deployer
@@ -111,23 +128,18 @@ class Indocker::ConfigurationDeployer
111
128
  end
112
129
  end
113
130
 
114
- def preload_containers(configuration)
115
- configuration.enabled_containers.each do |container_name|
116
- path = Indocker.container_files[container_name]
117
- require path
118
- end
119
- end
120
-
121
- def find_deploy_containers(configuration, deploy_containers, deploy_tags, skip_dependent, skip_containers, servers, skip_tags, auto_confirm, require_confirmation)
131
+ def find_containers_to_deploy(configuration, deployment_policy)
132
+ load_enabled_containers(configuration)
133
+
122
134
  containers = []
123
135
 
124
- deploy_tags.each do |tag|
136
+ deployment_policy.deploy_tags.each do |tag|
125
137
  containers += configuration.containers.select do |container|
126
138
  container.tags.include?(tag)
127
139
  end
128
140
  end
129
141
 
130
- skip_containers.each do |name|
142
+ deployment_policy.skip_containers.each do |name|
131
143
  container = configuration.containers.detect do |container|
132
144
  container.name == name
133
145
  end
@@ -144,7 +156,7 @@ class Indocker::ConfigurationDeployer
144
156
  end
145
157
  end
146
158
 
147
- deploy_containers.each do |name|
159
+ deployment_policy.deploy_containers.each do |name|
148
160
  container = configuration.containers.detect do |container|
149
161
  container.name == name
150
162
  end
@@ -158,17 +170,17 @@ class Indocker::ConfigurationDeployer
158
170
  end
159
171
  end
160
172
 
161
- if deploy_tags.empty? && deploy_containers.empty?
173
+ if deployment_policy.deploy_tags.empty? && deployment_policy.deploy_containers.empty?
162
174
  containers = configuration.containers.select do |container|
163
175
  configuration.enabled_containers.include?(container.name)
164
176
  end
165
177
  end
166
178
 
167
- if !skip_dependent
179
+ if !deployment_policy.skip_dependent
168
180
  containers = collect_dependent_containers(containers)
169
181
  end
170
182
 
171
- if !skip_dependent
183
+ if !deployment_policy.skip_dependent
172
184
  containers = collect_soft_dependent_containers(containers, configuration)
173
185
  end
174
186
 
@@ -181,13 +193,13 @@ class Indocker::ConfigurationDeployer
181
193
 
182
194
  containers = containers
183
195
  .select { |container| configuration.container_enabled?(container) }
184
- .select { |container| !skip_containers.include?(container.name) }
196
+ .select { |container| !deployment_policy.skip_containers.include?(container.name) }
185
197
  .select { |container|
186
- (skip_tags & container.tags).empty?
198
+ (deployment_policy.skip_tags & container.tags).empty?
187
199
  }
188
200
 
189
- if !servers.empty?
190
- containers = containers.select {|c| !(c.servers.map(&:name) & servers).empty? }
201
+ if !deployment_policy.servers.empty?
202
+ containers = containers.select {|c| !(c.servers.map(&:name) & deployment_policy.servers).empty? }
191
203
  end
192
204
 
193
205
  if containers.empty?
@@ -196,6 +208,7 @@ class Indocker::ConfigurationDeployer
196
208
  else
197
209
  @global_logger.info("Following containers will be deployed:")
198
210
 
211
+ servers = deployment_policy.servers
199
212
  if servers.empty?
200
213
  servers = containers.map(&:servers).flatten.uniq.map(&:name)
201
214
  end
@@ -213,7 +226,7 @@ class Indocker::ConfigurationDeployer
213
226
  end
214
227
  end
215
228
 
216
- if (require_confirmation || configuration.confirm_deployment) && !auto_confirm
229
+ if (deployment_policy.require_confirmation || configuration.confirm_deployment) && !deployment_policy.auto_confirm
217
230
  @global_logger.info("\n")
218
231
  @global_logger.info("Do you want to continue deployment? (y or n)")
219
232
  result = gets.chomp
@@ -224,7 +237,14 @@ class Indocker::ConfigurationDeployer
224
237
  end
225
238
  end
226
239
 
227
- containers
240
+ containers.uniq {|c| c.name}
241
+ end
242
+ end
243
+
244
+ def load_enabled_containers(configuration)
245
+ configuration.enabled_containers.each do |container_name|
246
+ path = Indocker.container_files[container_name]
247
+ require path
228
248
  end
229
249
  end
230
250
 
@@ -270,24 +290,42 @@ class Indocker::ConfigurationDeployer
270
290
  result = build_context
271
291
  .session
272
292
  .exec!(
273
- "cd #{Indocker::IndockerHelper.indocker_dir} && ./bin/remote/compile -C #{Indocker.configuration_name} -i #{image.name} -s #{@logger.debug? ? '-d' : ''}"
293
+ "cd #{Indocker::IndockerHelper.indocker_dir} && ./bin/remote/compile -C #{Indocker.configuration_name} -i #{image.name} -s #{@logger.debug? ? '-d' : ''}",
294
+ on_stdout: proc { |data|
295
+ @logger.info("[compile] #{data}")
296
+ },
297
+ on_stderr: proc { |data|
298
+ @logger.error("[compile] #{data}")
299
+ }
274
300
  )
275
301
  end
276
302
 
277
- Indocker::SshResultLogger
278
- .new(@logger)
279
- .log(result, "#{image.name.to_s.green} image compilation failed")
280
-
281
- exit 1 if result.exit_code != 0
303
+ if result.exit_code != 0
304
+ @global_logger.error("[compile] #{image.name.to_s.green} image compilation failed")
305
+ puts result.stdout_data
306
+ exit 1
307
+ end
282
308
 
283
309
  @logger.info("Image compilation completed #{image.name.to_s.green}. Time taken: #{time}")
284
310
 
285
311
  build_context.set_compiled(image)
286
312
  end
287
313
 
288
- def recursively_deploy_container(configuration, deployer, build_context_pool, container, containers, skip_build, force_restart, skip_force_restart)
314
+ def recursively_deploy_container(configuration, deployer, build_context_pool, container,
315
+ containers, skip_build, skip_deploy, force_restart, skip_force_restart)
316
+
289
317
  container.dependent_containers.each do |container|
290
- recursively_deploy_container(configuration, deployer, build_context_pool, container, containers, skip_build, force_restart, skip_force_restart)
318
+ recursively_deploy_container(
319
+ configuration,
320
+ deployer,
321
+ build_context_pool,
322
+ container,
323
+ containers,
324
+ skip_build,
325
+ skip_deploy,
326
+ force_restart,
327
+ skip_force_restart
328
+ )
291
329
  end
292
330
 
293
331
  return if !containers.include?(container)
@@ -304,7 +342,9 @@ class Indocker::ConfigurationDeployer
304
342
 
305
343
  @progress.finish_building_container(container)
306
344
 
307
- deployer.deploy(container, force_restart, skip_force_restart, @progress)
345
+ if !skip_deploy
346
+ deployer.deploy(container, force_restart, skip_force_restart, @progress)
347
+ end
308
348
  end
309
349
 
310
350
  class RemoteOperation
@@ -319,7 +359,6 @@ class Indocker::ConfigurationDeployer
319
359
  end
320
360
 
321
361
  def pull_repositories(clonner, servers, repositories)
322
- @logger.info("{timestamp}")
323
362
  @logger.info("Clonning/pulling repositories")
324
363
 
325
364
  remote_operations = []
@@ -372,7 +411,6 @@ class Indocker::ConfigurationDeployer
372
411
  end
373
412
 
374
413
  def sync_artifacts(clonner, artifact_servers)
375
- @logger.info("{timestamp}")
376
414
  @logger.info("Syncing git artifacts")
377
415
 
378
416
  remote_operations = []
@@ -424,8 +462,6 @@ class Indocker::ConfigurationDeployer
424
462
  redeploy_containers = configuration.containers.select {|c| c.redeploy_schedule}.uniq
425
463
  return if redeploy_containers.empty?
426
464
 
427
- @logger.info("{timestamp}")
428
-
429
465
  deploy_user = "#{server.user}@#{server.host}"
430
466
  crontab_filepath = Indocker.redeploy_crontab_path
431
467
 
@@ -450,8 +486,6 @@ class Indocker::ConfigurationDeployer
450
486
  end
451
487
 
452
488
  def sync_indocker(servers)
453
- @logger.info("{timestamp}")
454
-
455
489
  servers.map do |server|
456
490
  @progress.start_syncing_binaries(server)
457
491
 
@@ -482,8 +516,6 @@ class Indocker::ConfigurationDeployer
482
516
  end
483
517
 
484
518
  def sync_env_files(servers, env_files)
485
- @logger.info("{timestamp}")
486
-
487
519
  remote_operations = []
488
520
 
489
521
  servers.map do |server|
@@ -14,6 +14,10 @@ class Indocker::ContainerDeployer
14
14
  @deployed_servers = {}
15
15
  end
16
16
 
17
+ def create_sessions!
18
+ @server_pool.create_sessions!
19
+ end
20
+
17
21
  def deploy(container, force_restart, skip_force_restart, progress)
18
22
  return if @deployed_containers[container]
19
23
 
@@ -34,7 +38,6 @@ class Indocker::ContainerDeployer
34
38
 
35
39
  exec_proc.call do
36
40
  deploy_context = @server_pool.get(server)
37
- @logger.info("{timestamp}")
38
41
  @logger.info("Deploying container: #{container.name.to_s.green} to #{server.user}@#{server.host}")
39
42
 
40
43
  command_output = @logger.debug? ? "" : " > /dev/null"
@@ -47,14 +50,21 @@ class Indocker::ContainerDeployer
47
50
  result = deploy_context
48
51
  .session
49
52
  .exec!(
50
- "cd #{Indocker::IndockerHelper.indocker_dir} && ./bin/remote/run -C #{Indocker.configuration_name} -c #{container.name} #{debug_options} #{command_output} #{force_restart_options}"
53
+ "cd #{Indocker::IndockerHelper.indocker_dir} && ./bin/remote/run -C #{Indocker.configuration_name} -c #{container.name} #{debug_options} #{command_output} #{force_restart_options}",
54
+ on_stdout: proc { |data|
55
+ @logger.info("[deploy] #{data}")
56
+ },
57
+ on_stderr: proc { |data|
58
+ @logger.error("[deploy] #{data}")
59
+ }
51
60
  )
61
+
62
+ if result.exit_code != 0
63
+ @global_logger.error("[deploy] #{container.name.to_s.green} deployment for server #{server.name} failed")
64
+ puts result.stdout_data
65
+ exit 1
66
+ end
52
67
 
53
- Indocker::SshResultLogger
54
- .new(@logger)
55
- .log(result, "#{container.name.to_s.green} deployment for server #{server.name} failed")
56
-
57
- exit 1 if result.exit_code != 0
58
68
  @logger.info("Container deployment to #{server.user}@#{server.host} finished: #{container.name.to_s.green}")
59
69
 
60
70
  deploy_context.close_session