indocker 0.1.5 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
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