indocker 0.1.4 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +5 -0
- data/Gemfile.lock +8 -2
- data/README.md +13 -2
- data/example/indocker/bin/deploy +19 -13
- data/example/indocker/bounded_contexts/shared/container_failing_build/Dockerfile +4 -0
- data/example/indocker/bounded_contexts/shared/container_failing_build/container.rb +5 -0
- data/example/indocker/bounded_contexts/shared/container_failing_build/image.rb +3 -0
- data/example/indocker/configurations/external.rb +12 -0
- data/example/indocker/infrastructure/build_servers.rb +11 -0
- data/example/indocker/infrastructure/servers.rb +11 -0
- data/example/indocker/setup.rb +1 -1
- data/example/spec/indocker_spec.rb +31 -0
- data/example/spec/spec_helper.rb +39 -0
- data/lib/indocker.rb +37 -56
- data/lib/indocker/build_context.rb +15 -13
- data/lib/indocker/build_context_pool.rb +7 -1
- data/lib/indocker/configuration_deployer.rb +137 -107
- data/lib/indocker/container_deployer.rb +4 -1
- data/lib/indocker/context_args.rb +2 -0
- data/lib/indocker/deploy_context.rb +10 -8
- data/lib/indocker/deployment_policy.rb +22 -0
- data/lib/indocker/deployment_progress.rb +7 -2
- data/lib/indocker/logger_factory.rb +37 -0
- data/lib/indocker/server.rb +10 -0
- data/lib/indocker/server_pool.rb +9 -1
- data/lib/indocker/version.rb +1 -1
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0356e417ece7294e5a5185f7cf17313d3b8f47c74895fdf0323989da110d5569
|
4
|
+
data.tar.gz: a2c04c1b66f98aa172b758be94e522901dffb2bef4d472602d70742fd93d80be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38376ede23d5ce780f0234ec01f473d673b4bdfe5a2ef4e893fcf867420ae8a11bbe57df6f010d1f87289f2c970328f8bc86f1b0cde929c73c1129b4bfb0d591
|
7
|
+
data.tar.gz: 93bb3bb739fbc427e8c688e7da395088d6e60fafa68c0741d91706bc2ac50bee9fae80b7ff240be16f4c4b5e7985b9f8fa4b56c9e1e74ccd6aa036f8d9bad021
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
indocker (0.1.
|
4
|
+
indocker (0.1.9)
|
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)
|
14
|
+
pry (0.13.1)
|
15
|
+
coderay (~> 1.1)
|
16
|
+
method_source (~> 1.0)
|
12
17
|
rake (10.5.0)
|
13
18
|
rspec (3.9.0)
|
14
19
|
rspec-core (~> 3.9.0)
|
@@ -30,8 +35,9 @@ PLATFORMS
|
|
30
35
|
DEPENDENCIES
|
31
36
|
bundler (~> 1.17)
|
32
37
|
indocker!
|
38
|
+
pry
|
33
39
|
rake (~> 10.0)
|
34
|
-
rspec
|
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
|
-
|
26
|
+
indocker/bin/deploy -C external -c ruby -d
|
16
27
|
```
|
17
28
|
|
18
29
|
## License
|
data/example/indocker/bin/deploy
CHANGED
@@ -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:
|
12
|
-
|
13
|
-
|
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:
|
110
|
-
tags:
|
111
|
-
skip_containers:
|
112
|
-
skip_dependent:
|
113
|
-
servers:
|
114
|
-
skip_build:
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
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
|
)
|
@@ -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
|
)
|
data/example/indocker/setup.rb
CHANGED
@@ -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
|
data/lib/indocker.rb
CHANGED
@@ -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,
|
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:
|
326
|
-
|
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
|
-
|
391
|
-
|
403
|
+
logger_stdout = if @log_level == Logger::DEBUG
|
404
|
+
STDOUT
|
392
405
|
else
|
393
|
-
|
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
|
-
|
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
|
-
|
13
|
-
|
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
|
-
@
|
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
|
-
@
|
75
|
-
@
|
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,90 +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 =
|
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
|
-
|
21
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
37
|
+
run!(configuration: configuration, deployment_policy: deployment_policy)
|
38
|
+
end
|
56
39
|
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
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
|
+
)
|
70
79
|
|
71
|
-
|
80
|
+
remote_operations = sync_indocker(servers)
|
81
|
+
wait_remote_operations(remote_operations)
|
72
82
|
|
73
|
-
|
74
|
-
|
75
|
-
remote_operations += sync_artifacts(clonner, configuration.artifact_servers)
|
83
|
+
remote_operations = sync_env_files(deploy_servers, configuration.env_files)
|
84
|
+
wait_remote_operations(remote_operations)
|
76
85
|
|
77
|
-
|
86
|
+
remote_operations = pull_repositories(clonner, build_servers, configuration.repositories)
|
87
|
+
wait_remote_operations(remote_operations)
|
78
88
|
|
79
|
-
|
89
|
+
remote_operations = sync_artifacts(clonner, configuration.artifact_servers)
|
90
|
+
wait_remote_operations(remote_operations)
|
80
91
|
|
81
|
-
|
82
|
-
recursively_deploy_container(configuration, deployer, build_context_pool, container, containers, skip_build, force_restart, skip_force_restart)
|
83
|
-
end
|
92
|
+
update_crontab_redeploy_rules(configuration, build_servers.first)
|
84
93
|
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
+
)
|
88
106
|
end
|
89
107
|
|
90
|
-
|
91
|
-
|
108
|
+
Thread
|
109
|
+
.list
|
110
|
+
.each { |t| t.join if t != Thread.current }
|
92
111
|
ensure
|
93
112
|
build_context_pool.close_sessions if build_context_pool
|
94
113
|
deployer.close_sessions if deployer
|
@@ -109,23 +128,18 @@ class Indocker::ConfigurationDeployer
|
|
109
128
|
end
|
110
129
|
end
|
111
130
|
|
112
|
-
def
|
113
|
-
configuration
|
114
|
-
|
115
|
-
require path
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
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
|
+
|
120
134
|
containers = []
|
121
135
|
|
122
|
-
deploy_tags.each do |tag|
|
136
|
+
deployment_policy.deploy_tags.each do |tag|
|
123
137
|
containers += configuration.containers.select do |container|
|
124
138
|
container.tags.include?(tag)
|
125
139
|
end
|
126
140
|
end
|
127
141
|
|
128
|
-
skip_containers.each do |name|
|
142
|
+
deployment_policy.skip_containers.each do |name|
|
129
143
|
container = configuration.containers.detect do |container|
|
130
144
|
container.name == name
|
131
145
|
end
|
@@ -142,7 +156,7 @@ class Indocker::ConfigurationDeployer
|
|
142
156
|
end
|
143
157
|
end
|
144
158
|
|
145
|
-
deploy_containers.each do |name|
|
159
|
+
deployment_policy.deploy_containers.each do |name|
|
146
160
|
container = configuration.containers.detect do |container|
|
147
161
|
container.name == name
|
148
162
|
end
|
@@ -156,17 +170,17 @@ class Indocker::ConfigurationDeployer
|
|
156
170
|
end
|
157
171
|
end
|
158
172
|
|
159
|
-
if deploy_tags.empty? && deploy_containers.empty?
|
173
|
+
if deployment_policy.deploy_tags.empty? && deployment_policy.deploy_containers.empty?
|
160
174
|
containers = configuration.containers.select do |container|
|
161
175
|
configuration.enabled_containers.include?(container.name)
|
162
176
|
end
|
163
177
|
end
|
164
178
|
|
165
|
-
if !skip_dependent
|
179
|
+
if !deployment_policy.skip_dependent
|
166
180
|
containers = collect_dependent_containers(containers)
|
167
181
|
end
|
168
182
|
|
169
|
-
if !skip_dependent
|
183
|
+
if !deployment_policy.skip_dependent
|
170
184
|
containers = collect_soft_dependent_containers(containers, configuration)
|
171
185
|
end
|
172
186
|
|
@@ -179,13 +193,13 @@ class Indocker::ConfigurationDeployer
|
|
179
193
|
|
180
194
|
containers = containers
|
181
195
|
.select { |container| configuration.container_enabled?(container) }
|
182
|
-
.select { |container| !skip_containers.include?(container.name) }
|
196
|
+
.select { |container| !deployment_policy.skip_containers.include?(container.name) }
|
183
197
|
.select { |container|
|
184
|
-
(skip_tags & container.tags).empty?
|
198
|
+
(deployment_policy.skip_tags & container.tags).empty?
|
185
199
|
}
|
186
200
|
|
187
|
-
if !servers.empty?
|
188
|
-
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? }
|
189
203
|
end
|
190
204
|
|
191
205
|
if containers.empty?
|
@@ -194,6 +208,7 @@ class Indocker::ConfigurationDeployer
|
|
194
208
|
else
|
195
209
|
@global_logger.info("Following containers will be deployed:")
|
196
210
|
|
211
|
+
servers = deployment_policy.servers
|
197
212
|
if servers.empty?
|
198
213
|
servers = containers.map(&:servers).flatten.uniq.map(&:name)
|
199
214
|
end
|
@@ -211,7 +226,7 @@ class Indocker::ConfigurationDeployer
|
|
211
226
|
end
|
212
227
|
end
|
213
228
|
|
214
|
-
if (require_confirmation || configuration.confirm_deployment) && !auto_confirm
|
229
|
+
if (deployment_policy.require_confirmation || configuration.confirm_deployment) && !deployment_policy.auto_confirm
|
215
230
|
@global_logger.info("\n")
|
216
231
|
@global_logger.info("Do you want to continue deployment? (y or n)")
|
217
232
|
result = gets.chomp
|
@@ -222,7 +237,14 @@ class Indocker::ConfigurationDeployer
|
|
222
237
|
end
|
223
238
|
end
|
224
239
|
|
225
|
-
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
|
226
248
|
end
|
227
249
|
end
|
228
250
|
|
@@ -283,9 +305,21 @@ class Indocker::ConfigurationDeployer
|
|
283
305
|
build_context.set_compiled(image)
|
284
306
|
end
|
285
307
|
|
286
|
-
def recursively_deploy_container(configuration, deployer, build_context_pool, container,
|
308
|
+
def recursively_deploy_container(configuration, deployer, build_context_pool, container,
|
309
|
+
containers, skip_build, skip_deploy, force_restart, skip_force_restart)
|
310
|
+
|
287
311
|
container.dependent_containers.each do |container|
|
288
|
-
recursively_deploy_container(
|
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
|
+
)
|
289
323
|
end
|
290
324
|
|
291
325
|
return if !containers.include?(container)
|
@@ -302,7 +336,9 @@ class Indocker::ConfigurationDeployer
|
|
302
336
|
|
303
337
|
@progress.finish_building_container(container)
|
304
338
|
|
305
|
-
|
339
|
+
if !skip_deploy
|
340
|
+
deployer.deploy(container, force_restart, skip_force_restart, @progress)
|
341
|
+
end
|
306
342
|
end
|
307
343
|
|
308
344
|
class RemoteOperation
|
@@ -317,7 +353,6 @@ class Indocker::ConfigurationDeployer
|
|
317
353
|
end
|
318
354
|
|
319
355
|
def pull_repositories(clonner, servers, repositories)
|
320
|
-
@logger.info("{timestamp}")
|
321
356
|
@logger.info("Clonning/pulling repositories")
|
322
357
|
|
323
358
|
remote_operations = []
|
@@ -370,7 +405,6 @@ class Indocker::ConfigurationDeployer
|
|
370
405
|
end
|
371
406
|
|
372
407
|
def sync_artifacts(clonner, artifact_servers)
|
373
|
-
@logger.info("{timestamp}")
|
374
408
|
@logger.info("Syncing git artifacts")
|
375
409
|
|
376
410
|
remote_operations = []
|
@@ -380,33 +414,35 @@ class Indocker::ConfigurationDeployer
|
|
380
414
|
@progress.start_syncing_artifact(server, artifact)
|
381
415
|
|
382
416
|
thread = Thread.new do
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
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
|
+
)
|
389
424
|
|
390
|
-
|
391
|
-
|
425
|
+
@logger.info("Pulling git artifact #{artifact.name.to_s.green} for #{server.user}@#{server.host}")
|
426
|
+
result = clonner.clone(session, artifact.repository)
|
392
427
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
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
|
398
433
|
|
399
|
-
|
400
|
-
|
401
|
-
|
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}")
|
402
437
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
438
|
+
if !result.success?
|
439
|
+
@logger.error(result.stdout_data)
|
440
|
+
@logger.error(result.stderr_data)
|
441
|
+
exit 1
|
442
|
+
end
|
408
443
|
|
409
|
-
|
444
|
+
@progress.finish_syncing_artifact(server, artifact)
|
445
|
+
end
|
410
446
|
end
|
411
447
|
|
412
448
|
RemoteOperation.new(thread, server, :artifact_sync)
|
@@ -420,8 +456,6 @@ class Indocker::ConfigurationDeployer
|
|
420
456
|
redeploy_containers = configuration.containers.select {|c| c.redeploy_schedule}.uniq
|
421
457
|
return if redeploy_containers.empty?
|
422
458
|
|
423
|
-
@logger.info("{timestamp}")
|
424
|
-
|
425
459
|
deploy_user = "#{server.user}@#{server.host}"
|
426
460
|
crontab_filepath = Indocker.redeploy_crontab_path
|
427
461
|
|
@@ -446,8 +480,6 @@ class Indocker::ConfigurationDeployer
|
|
446
480
|
end
|
447
481
|
|
448
482
|
def sync_indocker(servers)
|
449
|
-
@logger.info("{timestamp}")
|
450
|
-
|
451
483
|
servers.map do |server|
|
452
484
|
@progress.start_syncing_binaries(server)
|
453
485
|
|
@@ -478,8 +510,6 @@ class Indocker::ConfigurationDeployer
|
|
478
510
|
end
|
479
511
|
|
480
512
|
def sync_env_files(servers, env_files)
|
481
|
-
@logger.info("{timestamp}")
|
482
|
-
|
483
513
|
remote_operations = []
|
484
514
|
|
485
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
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
|
@@ -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
|
data/lib/indocker/server.rb
CHANGED
data/lib/indocker/server_pool.rb
CHANGED
@@ -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)
|
data/lib/indocker/version.rb
CHANGED
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.
|
4
|
+
version: 0.1.9
|
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-
|
12
|
+
date: 2020-08-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: net-ssh
|
@@ -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
|