indocker 0.1.5 → 0.1.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 969dd78ffb984ee7bbf45cca5d1c6fca115e38429975b08c07f4698a5bfd05a7
4
- data.tar.gz: dfeeaceb39626a7974c95648fca8de8391e46f24756f0112634c750ecf6ad17c
3
+ metadata.gz: 5cc8ce4873ccea152495206a220d2bd9cd382c4046fea21490787ebd10b87f84
4
+ data.tar.gz: 83453296afe65dae6146b35b50317f5b720eadc0a19d941d9dad2c8617087dfb
5
5
  SHA512:
6
- metadata.gz: 4e8a80818b4e69361ed8f51fec6a45cfe08fe63fa53d8449dd00e00877c776984b1b8c8c886a9b619857868bc0f55ad7f1f0e613cc2f282593e08a45652b225f
7
- data.tar.gz: 6cf020eb3455d8230a8e2bf5392df10e63f6d2b9ff2f181b22a87ef747b6460d28eb5dcd7c3f2d094ca5fafc94fe9628cf86260aa2b7a64cfcf59f0dd28a17a0
6
+ metadata.gz: 2322d367c0d236ccc4e6abab8b5d4c73a2a0ea40a9c29936d986ccd2c0d1249676c11100071ab385f676abf56310c934b0dca99cfa0c8f90619e46c9a29a6726
7
+ data.tar.gz: 6183205fcf0cf0dbfc05194e9d81a4e4f768a9a8b7ae631c0ced837190de55c7eac93844b5830fa6c1009966991a1dde9af4c5df92a1027d3f21de0440ce6672
data/Gemfile CHANGED
@@ -4,3 +4,8 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in indocker.gemspec
6
6
  gemspec
7
+
8
+ group :test do
9
+ gem 'rspec'
10
+ gem 'pry'
11
+ end
@@ -1,15 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- indocker (0.1.5)
4
+ indocker (0.1.10)
5
5
  net-ssh
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
+ coderay (1.1.3)
10
11
  diff-lcs (1.3)
12
+ method_source (1.0.0)
11
13
  net-ssh (6.1.0)
12
- rake (10.5.0)
14
+ pry (0.13.1)
15
+ coderay (~> 1.1)
16
+ method_source (~> 1.0)
17
+ rake (12.3.3)
13
18
  rspec (3.9.0)
14
19
  rspec-core (~> 3.9.0)
15
20
  rspec-expectations (~> 3.9.0)
@@ -30,8 +35,9 @@ PLATFORMS
30
35
  DEPENDENCIES
31
36
  bundler (~> 1.17)
32
37
  indocker!
33
- rake (~> 10.0)
34
- rspec (~> 3.0)
38
+ pry
39
+ rake (~> 12.3.3)
40
+ rspec
35
41
 
36
42
  BUNDLED WITH
37
43
  1.17.3
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # InDocker
2
2
 
3
+ [![Codeship Status for ArtStation/indocker](https://app.codeship.com/projects/bf8888c0-b7e4-0138-fc1f-7e2faa53772a/status?branch=master)](https://app.codeship.com/projects/404716)
4
+
3
5
  Docker Containers Deployment
4
6
 
5
7
  ## Installation
@@ -8,11 +10,20 @@ Docker Containers Deployment
8
10
  $ gem install indocker
9
11
  ```
10
12
 
11
- ## Development: Launch example app
13
+ ## Development: Launch example app locally
14
+
15
+ ```ruby
16
+ cd example
17
+ indocker/bin/deploy -C dev -c ruby -d
18
+ ```
19
+
20
+ ## Development: Launch example with external host
21
+
22
+ NOTE: Default external host requires extra permissions.
12
23
 
13
24
  ```ruby
14
25
  cd example
15
- bundle exec indocker/bin/deploy -C dev -c ruby -d
26
+ indocker/bin/deploy -C external -c ruby -d
16
27
  ```
17
28
 
18
29
  ## License
@@ -8,9 +8,10 @@ configurations = list_configurations(File.expand_path(File.join(__dir__, '../con
8
8
  ARGV << '-h' if ARGV.empty?
9
9
 
10
10
  options = {
11
- skip_build: false,
12
- force_restart: false,
13
- skip_tags: [],
11
+ skip_build: false,
12
+ skip_deploy: false,
13
+ force_restart: false,
14
+ skip_tags: [],
14
15
  skip_force_restart: [],
15
16
  }
16
17
 
@@ -61,6 +62,10 @@ OptionParser.new do |opts|
61
62
  options[:skip_build] = true
62
63
  end
63
64
 
65
+ opts.on("-b", "--skip-deploy", "Skip image deploy") do |val|
66
+ options[:skip_deploy] = true
67
+ end
68
+
64
69
  opts.on("-y", "--auto-confirm", "Automatically confirm deployment") do |val|
65
70
  options[:auto_confirm] = true
66
71
  end
@@ -106,15 +111,16 @@ Indocker.set_configuration_name(options[:configuration])
106
111
  require_relative '../setup'
107
112
 
108
113
  Indocker.deploy(
109
- containers: options[:containers] || [],
110
- tags: options[:tags] || [],
111
- skip_containers: options[:skip_containers] || [],
112
- skip_dependent: !!options[:skip_dependent],
113
- servers: options[:servers] || [],
114
- skip_build: options[:skip_build],
115
- force_restart: options[:force_restart],
116
- skip_tags: options[:skip_tags] || [],
117
- skip_force_restart: options[:skip_force_restart] || [],
118
- auto_confirm: !!options[:auto_confirm],
114
+ containers: options[:containers] || [],
115
+ tags: options[:tags] || [],
116
+ skip_containers: options[:skip_containers] || [],
117
+ skip_dependent: !!options[:skip_dependent],
118
+ servers: options[:servers] || [],
119
+ skip_build: options[:skip_build],
120
+ skip_deploy: options[:skip_deploy],
121
+ force_restart: options[:force_restart],
122
+ skip_tags: options[:skip_tags] || [],
123
+ skip_force_restart: options[:skip_force_restart] || [],
124
+ auto_confirm: !!options[:auto_confirm],
119
125
  require_confirmation: !!options[:require_confirmation],
120
126
  )
@@ -0,0 +1,4 @@
1
+ FROM ruby:2.5.0
2
+
3
+ RUN some-unexisting-command
4
+ WORKDIR /app
@@ -0,0 +1,5 @@
1
+ Indocker
2
+ .define_container(:container_failing_build)
3
+ .tags('container_failing_build', 'console=true')
4
+ .image(:container_failing_build)
5
+ .networks(:app_net)
@@ -0,0 +1,3 @@
1
+ Indocker
2
+ .define_image(:container_failing_build)
3
+ .registry(:default)
@@ -0,0 +1,12 @@
1
+ Indocker
2
+ .build_configuration(:external)
3
+ .use_registry(:dev, as: :default)
4
+ .use_build_server(:external_bs)
5
+ .enabled_containers(
6
+ ruby: {
7
+ servers: [:external],
8
+ },
9
+ container_failing_build: {
10
+ servers: [:external],
11
+ }
12
+ )
@@ -5,4 +5,15 @@ Indocker.add_build_server(
5
5
  user: `whoami`.strip,
6
6
  port: 22
7
7
  )
8
+ )
9
+
10
+ external_host = ENV['INDOCKER_EXTERNAL_HOST'] || 'indocker.artstn.ninja'
11
+ external_user = ENV['INDOCKER_EXTERNAL_USER'] || 'indocker'
12
+ Indocker.add_build_server(
13
+ Indocker::BuildServer.new(
14
+ name: :external_bs,
15
+ host: external_host,
16
+ user: external_user,
17
+ port: 22
18
+ )
8
19
  )
@@ -5,4 +5,15 @@ Indocker.add_server(
5
5
  user: `whoami`.strip,
6
6
  port: 22
7
7
  )
8
+ )
9
+
10
+ external_host = ENV['INDOCKER_EXTERNAL_HOST'] || 'indocker.artstn.ninja'
11
+ external_user = ENV['INDOCKER_EXTERNAL_USER'] || 'indocker'
12
+ Indocker.add_server(
13
+ Indocker::Server.new(
14
+ name: :external,
15
+ host: external_host,
16
+ user: external_user,
17
+ port: 22
18
+ )
8
19
  )
@@ -3,7 +3,7 @@ require 'indocker'
3
3
  root_dir = File.join(__dir__, '..', '..')
4
4
 
5
5
  Indocker.set_root_dir(__dir__)
6
- Indocker.set_deploy_dir(File.join(root_dir, 'tmp', 'deployment'))
6
+ Indocker.set_deploy_dir('~/deployment')
7
7
 
8
8
  Indocker.set_dockerignore [
9
9
  'Dockerfile',
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Indocker do
4
+ it "has a version number" do
5
+ expect(Indocker::VERSION).not_to be nil
6
+ end
7
+
8
+ describe "successful deployment" do
9
+ it "doesn't raise any error" do
10
+ expect{
11
+ launch_deployment(containers: [:ruby])
12
+ }.to_not raise_error
13
+ end
14
+
15
+ it "shows a message about successful deploy" do
16
+ allow(Indocker.global_logger).to receive(:info).at_least(:once)
17
+
18
+ launch_deployment(containers: [:ruby])
19
+
20
+ expect(Indocker.global_logger).to have_received(:info).at_least(:once).with(/Deployment finished/)
21
+ end
22
+ end
23
+
24
+ describe "failed build" do
25
+ it "exits with an error" do
26
+ expect{
27
+ launch_deployment(containers: [:container_failing_build])
28
+ }.to raise_error(SystemExit)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ require "bundler/setup"
2
+ require "indocker"
3
+ require "pry"
4
+
5
+ RSpec.configure do |config|
6
+ # Enable flags like --only-failures and --next-failure
7
+ config.example_status_persistence_file_path = ".rspec_status"
8
+
9
+ # Disable RSpec exposing methods globally on `Module` and `main`
10
+ config.disable_monkey_patching!
11
+
12
+ config.expect_with :rspec do |c|
13
+ c.syntax = :expect
14
+ end
15
+ end
16
+
17
+ def launch_deployment(options = {})
18
+ require_relative '../indocker/bin/utils/configurations'
19
+
20
+ Indocker.set_configuration_name(options[:configuration] || "external")
21
+ require_relative '../indocker/setup'
22
+
23
+ Indocker.set_log_level(options[:debug] ? Logger::DEBUG : Logger::INFO)
24
+
25
+ Indocker.deploy(
26
+ containers: options[:containers] || [],
27
+ tags: options[:tags] || [],
28
+ skip_containers: options[:skip_containers] || [],
29
+ skip_dependent: !!options[:skip_dependent],
30
+ servers: options[:servers] || [],
31
+ skip_build: options[:skip_build],
32
+ skip_deploy: options[:skip_deploy],
33
+ force_restart: options[:force_restart],
34
+ skip_tags: options[:skip_tags] || [],
35
+ skip_force_restart: options[:skip_force_restart] || [],
36
+ auto_confirm: !!options[:auto_confirm],
37
+ require_confirmation: !!options[:require_confirmation],
38
+ )
39
+ end
@@ -25,6 +25,6 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_dependency "net-ssh"
27
27
  spec.add_development_dependency "bundler", "~> 1.17"
28
- spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rake", "~> 12.3.3"
29
29
  spec.add_development_dependency "rspec", "~> 3.0"
30
30
  end
@@ -88,7 +88,9 @@ module Indocker
88
88
  autoload :SshResultLogger, 'ssh_result_logger'
89
89
  autoload :DeploymentProgress, 'deployment_progress'
90
90
  autoload :DeploymentChecker, 'deployment_checker'
91
+ autoload :DeploymentPolicy, 'deployment_policy'
91
92
  autoload :CrontabRedeployRulesBuilder, 'crontab_redeploy_rules_builder'
93
+ autoload :LoggerFactory, 'logger_factory'
92
94
 
93
95
  class << self
94
96
  def set_export_command(command)
@@ -318,22 +320,31 @@ module Indocker
318
320
  builder
319
321
  end
320
322
 
321
- def deploy(containers: [], skip_tags: [], tags: [], skip_dependent: false, skip_containers: [], servers: [], skip_build: false, force_restart: false, skip_force_restart: [], auto_confirm: false, require_confirmation: false)
323
+ def deploy(containers: [], skip_tags: [], tags: [], skip_dependent: false,
324
+ skip_containers: [], servers: [], skip_build: false, skip_deploy: false,
325
+ force_restart: false, skip_force_restart: [], auto_confirm: false,
326
+ require_confirmation: false)
327
+
328
+ deployment_policy = Indocker::DeploymentPolicy.new(
329
+ deploy_containers: containers,
330
+ deploy_tags: tags,
331
+ servers: servers,
332
+ skip_dependent: skip_dependent,
333
+ skip_containers: skip_containers,
334
+ skip_build: skip_build,
335
+ skip_deploy: skip_deploy,
336
+ skip_tags: skip_tags,
337
+ force_restart: force_restart,
338
+ skip_force_restart: skip_force_restart,
339
+ auto_confirm: auto_confirm,
340
+ require_confirmation: require_confirmation,
341
+ )
342
+
322
343
  Indocker::ConfigurationDeployer
323
- .new(Indocker.logger)
344
+ .new(logger: Indocker.logger, global_logger: Indocker.global_logger)
324
345
  .run(
325
- configuration: configuration,
326
- deploy_containers: containers,
327
- deploy_tags: tags,
328
- skip_dependent: skip_dependent,
329
- skip_containers: skip_containers,
330
- servers: servers,
331
- skip_build: skip_build,
332
- force_restart: force_restart,
333
- skip_tags: skip_tags,
334
- skip_force_restart: skip_force_restart,
335
- auto_confirm: auto_confirm,
336
- require_confirmation: require_confirmation,
346
+ configuration: configuration,
347
+ deployment_policy: deployment_policy
337
348
  )
338
349
  end
339
350
 
@@ -385,56 +396,26 @@ module Indocker
385
396
  Indocker::BuildContextHelper.new(Indocker.configuration, nil)
386
397
  end
387
398
 
399
+ # This logger outputs progress of the deployment
400
+ # It will not output anything for deployment without debug option
388
401
  def logger
389
402
  @logger ||= begin
390
- logger = if @log_level == Logger::DEBUG
391
- Logger.new(STDOUT)
403
+ logger_stdout = if @log_level == Logger::DEBUG
404
+ STDOUT
392
405
  else
393
- Logger.new(File.open(File::NULL, "w"))
394
- end
395
-
396
- logger.level = @log_level || Logger::INFO
397
-
398
- logger.formatter = proc do |severity, datetime, progname, msg|
399
- level = Logger::SEV_LABEL.index(severity)
400
-
401
- severity = case level
402
- when Logger::INFO
403
- severity.green
404
- when Logger::WARN
405
- severity.purple
406
- when Logger::DEBUG
407
- severity.yellow
408
- when Logger::ERROR
409
- severity.red
410
- when Logger::FATAL
411
- severity.red
412
- else
413
- severity
414
- end
415
-
416
- severity = severity.downcase
417
-
418
- if logger.debug?
419
- if msg == "{timestamp}"
420
- ""
421
- else
422
- "#{datetime.strftime("%Y/%m/%d %H:%M:%S")} #{severity}: #{msg}\n"
423
- end
424
- else
425
- # Use a nicer logging for not debug
426
- if msg == "{timestamp}"
427
- datetime.strftime("%Y/%m/%d %H:%M:%S\n").grey
428
- else
429
- " #{severity}: #{msg}\n"
430
- end
431
- end
406
+ File.open(File::NULL, "w")
432
407
  end
433
408
 
434
- logger
409
+ Indocker::LoggerFactory.create(logger_stdout, @log_level)
435
410
  end
436
411
  end
437
412
 
413
+ # Global logger would output data without dependency on how we deploy the progress
414
+ # Currently it will always output data to stdout
415
+ def global_logger
416
+ @global_logger ||= Indocker::LoggerFactory.create(STDOUT, @log_level)
417
+ end
418
+
438
419
  def set_log_level(level)
439
420
  @log_level = level
440
421
  end
@@ -3,22 +3,24 @@ require 'fileutils'
3
3
  class Indocker::BuildContext
4
4
  attr_reader :session, :server, :configuration, :helper, :logger
5
5
 
6
- def initialize(configuration:, build_server:, logger:)
6
+ def initialize(configuration:, build_server:, logger:, global_logger:)
7
7
  @configuration = configuration
8
8
  @logger = logger
9
9
  @helper = Indocker::BuildContextHelper.new(@configuration, @build_server)
10
10
  @server = build_server
11
+ @global_logger = global_logger
12
+ @compiled_images = Hash.new(false)
13
+ end
11
14
 
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
15
+ def create_session!
16
+ return unless @server
20
17
 
21
- @compiled_images = Hash.new(false)
18
+ @session = Indocker::SshSession.new(
19
+ host: @server.host,
20
+ user: @server.user,
21
+ port: @server.port,
22
+ logger: @logger
23
+ )
22
24
  end
23
25
 
24
26
  def exec!(command)
@@ -69,10 +71,10 @@ class Indocker::BuildContext
69
71
  build_args = args.join(' ')
70
72
 
71
73
  res = Indocker::Docker.build(image.local_registry_url, build_args)
72
-
74
+
73
75
  if res.exit_status != 0
74
- @logger.error("image compilation :#{image.name} failed")
75
- @logger.error(res.stdout)
76
+ @global_logger.error("image compilation :#{image.name} failed")
77
+ @global_logger.error(res.stdout)
76
78
  exit 1
77
79
  end
78
80
 
@@ -1,17 +1,23 @@
1
1
  class Indocker::BuildContextPool
2
- def initialize(configuration:, logger:)
2
+ def initialize(configuration:, logger:, global_logger:)
3
3
  @logger = logger
4
4
  @configuration = configuration
5
+ @global_logger = global_logger
5
6
 
6
7
  @contexts = configuration.build_servers.map do |build_server|
7
8
  Indocker::BuildContext.new(
8
9
  logger: @logger,
9
10
  configuration: configuration,
10
11
  build_server: build_server,
12
+ global_logger: @global_logger,
11
13
  )
12
14
  end
13
15
  end
14
16
 
17
+ def create_sessions!
18
+ @contexts.each(&:create_session!)
19
+ end
20
+
15
21
  def get
16
22
  context = nil
17
23
 
@@ -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, global_logger: @global_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
 
@@ -285,9 +305,21 @@ class Indocker::ConfigurationDeployer
285
305
  build_context.set_compiled(image)
286
306
  end
287
307
 
288
- def recursively_deploy_container(configuration, deployer, build_context_pool, container, containers, skip_build, force_restart, skip_force_restart)
308
+ def recursively_deploy_container(configuration, deployer, build_context_pool, container,
309
+ containers, skip_build, skip_deploy, force_restart, skip_force_restart)
310
+
289
311
  container.dependent_containers.each do |container|
290
- recursively_deploy_container(configuration, deployer, build_context_pool, container, containers, skip_build, force_restart, skip_force_restart)
312
+ recursively_deploy_container(
313
+ configuration,
314
+ deployer,
315
+ build_context_pool,
316
+ container,
317
+ containers,
318
+ skip_build,
319
+ skip_deploy,
320
+ force_restart,
321
+ skip_force_restart
322
+ )
291
323
  end
292
324
 
293
325
  return if !containers.include?(container)
@@ -304,7 +336,9 @@ class Indocker::ConfigurationDeployer
304
336
 
305
337
  @progress.finish_building_container(container)
306
338
 
307
- deployer.deploy(container, force_restart, skip_force_restart, @progress)
339
+ if !skip_deploy
340
+ deployer.deploy(container, force_restart, skip_force_restart, @progress)
341
+ end
308
342
  end
309
343
 
310
344
  class RemoteOperation
@@ -319,7 +353,6 @@ class Indocker::ConfigurationDeployer
319
353
  end
320
354
 
321
355
  def pull_repositories(clonner, servers, repositories)
322
- @logger.info("{timestamp}")
323
356
  @logger.info("Clonning/pulling repositories")
324
357
 
325
358
  remote_operations = []
@@ -372,7 +405,6 @@ class Indocker::ConfigurationDeployer
372
405
  end
373
406
 
374
407
  def sync_artifacts(clonner, artifact_servers)
375
- @logger.info("{timestamp}")
376
408
  @logger.info("Syncing git artifacts")
377
409
 
378
410
  remote_operations = []
@@ -382,33 +414,35 @@ class Indocker::ConfigurationDeployer
382
414
  @progress.start_syncing_artifact(server, artifact)
383
415
 
384
416
  thread = Thread.new do
385
- session = Indocker::SshSession.new(
386
- host: server.host,
387
- user: server.user,
388
- port: server.port,
389
- logger: @logger
390
- )
417
+ server.synchronize do
418
+ session = Indocker::SshSession.new(
419
+ host: server.host,
420
+ user: server.user,
421
+ port: server.port,
422
+ logger: @logger
423
+ )
391
424
 
392
- @logger.info("Pulling git artifact #{artifact.name.to_s.green} for #{server.user}@#{server.host}")
393
- result = clonner.clone(session, artifact.repository)
425
+ @logger.info("Pulling git artifact #{artifact.name.to_s.green} for #{server.user}@#{server.host}")
426
+ result = clonner.clone(session, artifact.repository)
394
427
 
395
- if result.exit_code != 0
396
- @logger.error("Artifact repository :#{artifact.repository.name} was not clonned")
397
- @logger.error(result.stderr_data)
398
- exit 1
399
- end
428
+ if result.exit_code != 0
429
+ @logger.error("Artifact repository :#{artifact.repository.name} was not clonned")
430
+ @logger.error(result.stderr_data)
431
+ exit 1
432
+ end
400
433
 
401
- source_path = File.join(artifact.repository.clone_path, artifact.source_path)
402
- result = session.exec!("mkdir -p #{artifact.target_path}")
403
- result = session.exec!("cp -r #{source_path} #{artifact.target_path}")
434
+ source_path = File.join(artifact.repository.clone_path, artifact.source_path)
435
+ result = session.exec!("mkdir -p #{artifact.target_path}")
436
+ result = session.exec!("cp -r #{source_path} #{artifact.target_path}")
404
437
 
405
- if !result.success?
406
- @logger.error(result.stdout_data)
407
- @logger.error(result.stderr_data)
408
- exit 1
409
- end
438
+ if !result.success?
439
+ @logger.error(result.stdout_data)
440
+ @logger.error(result.stderr_data)
441
+ exit 1
442
+ end
410
443
 
411
- @progress.finish_syncing_artifact(server, artifact)
444
+ @progress.finish_syncing_artifact(server, artifact)
445
+ end
412
446
  end
413
447
 
414
448
  RemoteOperation.new(thread, server, :artifact_sync)
@@ -422,8 +456,6 @@ class Indocker::ConfigurationDeployer
422
456
  redeploy_containers = configuration.containers.select {|c| c.redeploy_schedule}.uniq
423
457
  return if redeploy_containers.empty?
424
458
 
425
- @logger.info("{timestamp}")
426
-
427
459
  deploy_user = "#{server.user}@#{server.host}"
428
460
  crontab_filepath = Indocker.redeploy_crontab_path
429
461
 
@@ -448,8 +480,6 @@ class Indocker::ConfigurationDeployer
448
480
  end
449
481
 
450
482
  def sync_indocker(servers)
451
- @logger.info("{timestamp}")
452
-
453
483
  servers.map do |server|
454
484
  @progress.start_syncing_binaries(server)
455
485
 
@@ -480,8 +510,6 @@ class Indocker::ConfigurationDeployer
480
510
  end
481
511
 
482
512
  def sync_env_files(servers, env_files)
483
- @logger.info("{timestamp}")
484
-
485
513
  remote_operations = []
486
514
 
487
515
  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"
@@ -16,6 +16,8 @@ class Indocker::ContextArgs
16
16
  value = @context_args.fetch(name) do
17
17
  Indocker.logger.warn("build arg '#{format_arg(name)}' is not defined#{@container ? " for container :#{@container.name}" : ""}")
18
18
  Indocker.logger.warn("available args: #{@context_args.inspect}")
19
+
20
+ nil
19
21
  end
20
22
 
21
23
  if value.is_a?(Hash)
@@ -9,15 +9,17 @@ class Indocker::DeployContext
9
9
  @configuration = configuration
10
10
  @server = server
11
11
  @restart_policy = Indocker::Containers::RestartPolicy.new(configuration, logger)
12
+ end
12
13
 
13
- if server
14
- @session = Indocker::SshSession.new(
15
- host: server.host,
16
- user: server.user,
17
- port: server.port,
18
- logger: @logger
19
- )
20
- end
14
+ def create_session!
15
+ return unless @server
16
+
17
+ @session = Indocker::SshSession.new(
18
+ host: @server.host,
19
+ user: @server.user,
20
+ port: @server.port,
21
+ logger: @logger
22
+ )
21
23
  end
22
24
 
23
25
  def exec!(command)
@@ -0,0 +1,22 @@
1
+ class Indocker::DeploymentPolicy
2
+ attr_reader :deploy_containers, :deploy_tags, :servers,
3
+ :skip_dependent, :skip_tags, :skip_containers, :skip_build, :skip_deploy,
4
+ :force_restart, :skip_force_restart, :auto_confirm, :require_confirmation
5
+
6
+ def initialize(deploy_containers:, deploy_tags:, servers:,
7
+ skip_dependent:, skip_tags:, skip_containers:, skip_build:, skip_deploy:,
8
+ force_restart:, skip_force_restart:, auto_confirm:, require_confirmation:)
9
+ @deploy_containers = deploy_containers
10
+ @deploy_tags = deploy_tags
11
+ @servers = servers
12
+ @skip_dependent = skip_dependent
13
+ @skip_tags = skip_tags
14
+ @skip_containers = skip_containers
15
+ @skip_build = skip_build
16
+ @skip_deploy = skip_deploy
17
+ @force_restart = force_restart
18
+ @skip_force_restart = skip_force_restart
19
+ @auto_confirm = auto_confirm
20
+ @require_confirmation = require_confirmation
21
+ end
22
+ end
@@ -70,9 +70,10 @@ class Indocker::DeploymentProgress
70
70
  end
71
71
 
72
72
  def setup(binaries_servers:, build_servers:, deploy_servers:, env_files:, artifact_servers:,
73
- repositories:, force_restart:, skip_build:, containers:)
73
+ repositories:, force_restart:, skip_build:, skip_deploy:, containers:)
74
74
  @force_restart = force_restart
75
- @skip_build = skip_build
75
+ @skip_build = skip_build
76
+ @skip_deploy = skip_deploy
76
77
 
77
78
  binaries_servers.each do |server|
78
79
  @synced_binaries[server] = {
@@ -250,6 +251,10 @@ class Indocker::DeploymentProgress
250
251
  @logger.info("Warning: Image build is skipped for all containers".purple)
251
252
  end
252
253
 
254
+ if @skip_deploy
255
+ @logger.info("Warning: All container deployment is skipped".purple)
256
+ end
257
+
253
258
  if @force_restart
254
259
  @logger.info("Warning: All containers will be force restarted".purple)
255
260
  end
@@ -9,7 +9,8 @@ class Indocker::ImagesCompiler
9
9
  build_context = Indocker::BuildContext.new(
10
10
  configuration: configuration,
11
11
  build_server: nil,
12
- logger: Indocker.logger
12
+ logger: @logger,
13
+ global_logger: Indocker.global_logger
13
14
  )
14
15
 
15
16
  image_compiler = Indocker::Images::ImageCompiler.new
@@ -0,0 +1,37 @@
1
+ class Indocker::LoggerFactory
2
+ class << self
3
+ def create(stdout, level = nil)
4
+ logger = Logger.new(stdout)
5
+
6
+ logger.level = level || Logger::INFO
7
+
8
+ logger.formatter = proc do |severity, datetime, progname, msg|
9
+ level = Logger::SEV_LABEL.index(severity)
10
+
11
+ severity = case level
12
+ when Logger::INFO
13
+ severity.green
14
+ when Logger::WARN
15
+ severity.purple
16
+ when Logger::DEBUG
17
+ severity.yellow
18
+ when Logger::ERROR
19
+ severity.red
20
+ when Logger::FATAL
21
+ severity.red
22
+ else
23
+ severity
24
+ end
25
+
26
+ severity = severity.downcase
27
+ if logger.debug?
28
+ "#{datetime.strftime("%Y/%m/%d %H:%M:%S")} #{severity}: #{msg}\n"
29
+ else
30
+ " #{severity}: #{msg}\n"
31
+ end
32
+ end
33
+
34
+ logger
35
+ end
36
+ end
37
+ end
@@ -17,4 +17,14 @@ class Indocker::Server
17
17
  super
18
18
  end
19
19
  end
20
+
21
+ def synchronize(&block)
22
+ semaphore.synchronize do
23
+ block.call if block_given?
24
+ end
25
+ end
26
+
27
+ def semaphore
28
+ @semaphore ||= Mutex.new
29
+ end
20
30
  end
@@ -12,12 +12,20 @@ class Indocker::ServerPool
12
12
  end
13
13
  end
14
14
 
15
+ def create_sessions!
16
+ @contexts.each(&:create_session!)
17
+ end
18
+
19
+ # NOTE: get is a bad name here, because we create a new connection.
20
+ # TODO: why we create a new connection here?
15
21
  def get(server)
16
- Indocker::DeployContext.new(
22
+ context = Indocker::DeployContext.new(
17
23
  logger: @logger,
18
24
  configuration: @configuration,
19
25
  server: server,
20
26
  )
27
+ context.create_session!
28
+ context
21
29
  end
22
30
 
23
31
  def each(&proc)
@@ -1,3 +1,3 @@
1
1
  module Indocker
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.10"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: indocker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-06-30 00:00:00.000000000 Z
12
+ date: 2020-08-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net-ssh
@@ -45,14 +45,14 @@ dependencies:
45
45
  requirements:
46
46
  - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: '10.0'
48
+ version: 12.3.3
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: '10.0'
55
+ version: 12.3.3
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: rspec
58
58
  requirement: !ruby/object:Gem::Requirement
@@ -88,15 +88,21 @@ files:
88
88
  - example/indocker/bin/remote/compile
89
89
  - example/indocker/bin/remote/run
90
90
  - example/indocker/bin/utils/configurations.rb
91
+ - example/indocker/bounded_contexts/shared/container_failing_build/Dockerfile
92
+ - example/indocker/bounded_contexts/shared/container_failing_build/container.rb
93
+ - example/indocker/bounded_contexts/shared/container_failing_build/image.rb
91
94
  - example/indocker/bounded_contexts/shared/ruby/Dockerfile
92
95
  - example/indocker/bounded_contexts/shared/ruby/container.rb
93
96
  - example/indocker/bounded_contexts/shared/ruby/image.rb
94
97
  - example/indocker/configurations/dev.rb
98
+ - example/indocker/configurations/external.rb
95
99
  - example/indocker/infrastructure/build_servers.rb
96
100
  - example/indocker/infrastructure/networks.rb
97
101
  - example/indocker/infrastructure/registries.rb
98
102
  - example/indocker/infrastructure/servers.rb
99
103
  - example/indocker/setup.rb
104
+ - example/spec/indocker_spec.rb
105
+ - example/spec/spec_helper.rb
100
106
  - indocker.gemspec
101
107
  - lib/indocker.rb
102
108
  - lib/indocker/artifacts/git.rb
@@ -120,6 +126,7 @@ files:
120
126
  - lib/indocker/crontab_redeploy_rules_builder.rb
121
127
  - lib/indocker/deploy_context.rb
122
128
  - lib/indocker/deployment_checker.rb
129
+ - lib/indocker/deployment_policy.rb
123
130
  - lib/indocker/deployment_progress.rb
124
131
  - lib/indocker/docker.rb
125
132
  - lib/indocker/docker_run_args.rb
@@ -134,6 +141,7 @@ files:
134
141
  - lib/indocker/images/templates_compiler.rb
135
142
  - lib/indocker/images_compiler.rb
136
143
  - lib/indocker/indocker_helper.rb
144
+ - lib/indocker/logger_factory.rb
137
145
  - lib/indocker/network.rb
138
146
  - lib/indocker/network_helper.rb
139
147
  - lib/indocker/registries/abstract.rb