percheron 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cane +4 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +31 -0
- data/.travis.yml +4 -1
- data/Guardfile +3 -3
- data/README.md +19 -3
- data/Rakefile +24 -1
- data/bin/percheron +2 -20
- data/lib/percheron/actions/base.rb +0 -39
- data/lib/percheron/actions/build.rb +9 -7
- data/lib/percheron/actions/create.rb +64 -38
- data/lib/percheron/actions/exec.rb +40 -8
- data/lib/percheron/actions/exec_local.rb +4 -4
- data/lib/percheron/actions/logs.rb +44 -0
- data/lib/percheron/actions/purge.rb +15 -4
- data/lib/percheron/actions/recreate.rb +15 -65
- data/lib/percheron/actions/restart.rb +2 -1
- data/lib/percheron/actions/shell.rb +27 -0
- data/lib/percheron/actions/start.rb +10 -7
- data/lib/percheron/actions.rb +2 -1
- data/lib/percheron/commands/abstract.rb +20 -8
- data/lib/percheron/commands/build.rb +13 -0
- data/lib/percheron/commands/console.rb +53 -0
- data/lib/percheron/commands/create.rb +3 -3
- data/lib/percheron/commands/list.rb +7 -3
- data/lib/percheron/commands/logs.rb +16 -0
- data/lib/percheron/commands/main.rb +5 -2
- data/lib/percheron/commands/purge.rb +2 -2
- data/lib/percheron/commands/recreate.rb +3 -11
- data/lib/percheron/commands/restart.rb +2 -2
- data/lib/percheron/commands/shell.rb +16 -0
- data/lib/percheron/commands/start.rb +2 -2
- data/lib/percheron/commands/stop.rb +2 -2
- data/lib/percheron/commands.rb +3 -0
- data/lib/percheron/config.rb +64 -3
- data/lib/percheron/config_delegator.rb +0 -1
- data/lib/percheron/container.rb +95 -38
- data/lib/percheron/core_extensions.rb +1 -4
- data/lib/percheron/docker_connection.rb +5 -1
- data/lib/percheron/formatters/stack/table.rb +24 -12
- data/lib/percheron/logger.rb +21 -0
- data/lib/percheron/metastore.rb +1 -0
- data/lib/percheron/null_stack.rb +5 -0
- data/lib/percheron/oh_dear.rb +15 -7
- data/lib/percheron/stack.rb +77 -72
- data/lib/percheron/validators/config.rb +1 -1
- data/lib/percheron/validators/container.rb +31 -11
- data/lib/percheron/validators/stack.rb +3 -5
- data/lib/percheron/version.rb +1 -1
- data/lib/percheron.rb +2 -0
- data/percheron.gemspec +4 -1
- metadata +54 -4
- data/assets/percheron.png +0 -0
- data/lib/percheron/actions/rename.rb +0 -65
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cbab3f52787ff0b165f9482186771b07ff673df1
|
4
|
+
data.tar.gz: ce6eb63e3621d595f814c8806728bfe9b43fae7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b198258dc8f5226a08563b77d1826af3f56eea705c35632d85bbca4d9e49be216c17fc5b776404fe7caac50ac2e84aa1d5c507493faf4edbaf110b276a1c3bc
|
7
|
+
data.tar.gz: f790fdeb14e59ce702f5569ea4043fd4747acfd6bc91934ed86646be290bd7e7d98782e049c0da198e9446f9b83d20e7724e7d17e8229502825172bc8d940077
|
data/.cane
ADDED
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Style/SpaceInsideBrackets:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
Style/EmptyLinesAroundClassBody:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Style/Documentation:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Style/IndentationConsistency:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Style/FormatString:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Metrics/LineLength:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Style/GlobalVars:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Style/RegexpLiteral:
|
23
|
+
EnforcedStyle: mixed
|
24
|
+
AllowInnerSlashes: false
|
25
|
+
|
26
|
+
Metrics/ClassLength:
|
27
|
+
CountComments: false
|
28
|
+
Max: 150
|
29
|
+
|
30
|
+
Style/SpaceAroundEqualsInParameterDefault:
|
31
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/Guardfile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
guard :rspec, cmd: 'bundle exec rspec' do
|
2
|
-
watch(%r{^spec
|
3
|
-
watch(%r{^lib
|
4
|
-
watch('spec/spec_helper.rb') {
|
2
|
+
watch(%r{^spec\/.+_spec\.rb$})
|
3
|
+
watch(%r{^lib\/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
|
4
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
5
5
|
end
|
data/README.md
CHANGED
@@ -6,8 +6,6 @@
|
|
6
6
|
[](https://codeclimate.com/github/ashmckenzie/percheron)
|
7
7
|
[](https://gemnasium.com/ashmckenzie/percheron)
|
8
8
|
|
9
|
-

|
10
|
-
|
11
9
|
Organise your Docker containers with muscle and intelligence.
|
12
10
|
|
13
11
|
## Installation
|
@@ -30,9 +28,27 @@ Or install it yourself as:
|
|
30
28
|
$ gem install percheron
|
31
29
|
```
|
32
30
|
|
31
|
+
## Requirements
|
32
|
+
|
33
|
+
* Ruby 2.x
|
34
|
+
* Docker 1.6.x
|
35
|
+
|
33
36
|
## Usage
|
34
37
|
|
35
|
-
|
38
|
+
TODO
|
39
|
+
|
40
|
+
## Examples
|
41
|
+
|
42
|
+
* Rails - https://github.com/ashmckenzie/percheron-rails#quickstart
|
43
|
+
* Torrent - https://github.com/ashmckenzie/percheron-torrent#quickstart
|
44
|
+
|
45
|
+
## Testing
|
46
|
+
|
47
|
+
All (cane, RuboCop, unit and integration):
|
48
|
+
|
49
|
+
```shell
|
50
|
+
bundle exec test
|
51
|
+
```
|
36
52
|
|
37
53
|
## Contributing
|
38
54
|
|
data/Rakefile
CHANGED
@@ -1,4 +1,27 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
2
|
require 'rspec/core/rake_task'
|
3
|
+
require 'cane/rake_task'
|
4
|
+
require 'rubocop/rake_task'
|
3
5
|
|
4
|
-
|
6
|
+
desc 'Run cane, rubocop, unit and integration tests'
|
7
|
+
task test: %w(test:cane test:rubocop spec:unit spec:integration)
|
8
|
+
|
9
|
+
namespace :test do
|
10
|
+
desc 'Run cane'
|
11
|
+
Cane::RakeTask.new(:cane)
|
12
|
+
|
13
|
+
desc 'Run RuboCop'
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new('spec') do |config|
|
18
|
+
config.pattern = './spec/**{,/*/**}/*_spec.rb'
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec::Core::RakeTask.new('spec:unit') do |config|
|
22
|
+
config.pattern = './spec/unit/**{,/*/**}/*_spec.rb'
|
23
|
+
end
|
24
|
+
|
25
|
+
RSpec::Core::RakeTask.new('spec:integration') do |config|
|
26
|
+
config.pattern = './spec/integration/**{,/*/**}/*_spec.rb'
|
27
|
+
end
|
data/bin/percheron
CHANGED
@@ -3,28 +3,10 @@
|
|
3
3
|
lib = File.expand_path('../../lib', __FILE__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
|
6
|
-
require 'logger'
|
7
6
|
require 'percheron'
|
8
7
|
require 'percheron/commands'
|
9
|
-
|
10
|
-
|
11
|
-
$logger = Logger.new(STDOUT)
|
12
|
-
|
13
|
-
logger_level = Logger::INFO
|
14
|
-
|
15
|
-
if ENV['QUIET'] == 'true'
|
16
|
-
logger_level = Logger::WARN
|
17
|
-
end
|
18
|
-
|
19
|
-
if ENV['DEBUG'] == 'true' || ENV['DOCKER_DEBUG'] == 'true'
|
20
|
-
require 'pry-byebug'
|
21
|
-
require 'awesome_print'
|
22
|
-
logger_level = Logger::DEBUG
|
23
|
-
|
24
|
-
Docker.logger = $logger if ENV['DOCKER_DEBUG'] == 'true'
|
25
|
-
end
|
26
|
-
|
27
|
-
$logger.level = logger_level
|
8
|
+
require 'percheron/logger'
|
9
|
+
require 'percheron/metastore'
|
28
10
|
|
29
11
|
begin
|
30
12
|
Percheron::Commands::Main.run
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Percheron
|
2
2
|
module Actions
|
3
3
|
module Base
|
4
|
-
|
5
4
|
def base_dir
|
6
5
|
container.dockerfile.dirname.to_s
|
7
6
|
end
|
@@ -13,44 +12,6 @@ module Percheron
|
|
13
12
|
ensure
|
14
13
|
Dir.chdir(old_dir)
|
15
14
|
end
|
16
|
-
|
17
|
-
def now_timestamp
|
18
|
-
Time.now.strftime('%Y%m%d%H%M%S')
|
19
|
-
end
|
20
|
-
|
21
|
-
def insert_files!(files)
|
22
|
-
files.each do |file|
|
23
|
-
file = Pathname.new(File.expand_path(file, base_dir))
|
24
|
-
container.image.insert_local('localPath' => file.to_s, 'outputPath' => "/tmp/#{file.basename}").tap do |new_image|
|
25
|
-
new_image.tag(repo: container.name, tag: container.version.to_s, force: true)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def stop_containers!(containers)
|
31
|
-
exec_on_containers!(containers) do |container|
|
32
|
-
if container.running?
|
33
|
-
$logger.debug "Stopping '#{container.name}' container"
|
34
|
-
Stop.new(container).execute!
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def start_containers!(containers, exec_scripts: true)
|
40
|
-
exec_on_containers!(containers) do |container|
|
41
|
-
unless container.running?
|
42
|
-
$logger.debug "Starting '#{container.name}' container"
|
43
|
-
Start.new(container, dependant_containers: container.dependant_containers.values, exec_scripts: exec_scripts).execute!
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def exec_on_containers!(containers)
|
49
|
-
containers.inject([]) do |all, container|
|
50
|
-
all << container if yield(container)
|
51
|
-
all
|
52
|
-
end.compact
|
53
|
-
end
|
54
15
|
end
|
55
16
|
end
|
56
17
|
end
|
@@ -4,22 +4,24 @@ module Percheron
|
|
4
4
|
|
5
5
|
include Base
|
6
6
|
|
7
|
-
def initialize(container, nocache: false)
|
7
|
+
def initialize(container, nocache: false, exec_scripts: true)
|
8
8
|
@container = container
|
9
9
|
@nocache = nocache
|
10
|
+
@exec_scripts = exec_scripts
|
10
11
|
end
|
11
12
|
|
12
13
|
def execute!
|
13
14
|
results = []
|
14
|
-
results << build!
|
15
|
+
results << build! if container.buildable?
|
15
16
|
results.compact.empty? ? nil : container
|
16
17
|
end
|
17
18
|
|
18
19
|
private
|
19
20
|
|
20
|
-
attr_reader :container, :nocache
|
21
|
+
attr_reader :container, :nocache, :exec_scripts
|
22
|
+
alias_method :exec_scripts?, :exec_scripts
|
21
23
|
|
22
|
-
def
|
24
|
+
def options
|
23
25
|
{
|
24
26
|
'dockerfile' => container.dockerfile.basename.to_s,
|
25
27
|
't' => container.image_name,
|
@@ -30,18 +32,18 @@ module Percheron
|
|
30
32
|
|
31
33
|
def build!
|
32
34
|
in_working_directory(base_dir) do
|
33
|
-
execute_pre_build_scripts!
|
35
|
+
execute_pre_build_scripts!
|
34
36
|
$logger.info "Building '#{container.image_name}' image"
|
35
|
-
Docker::Image.build_from_dir(base_dir,
|
37
|
+
Docker::Image.build_from_dir(base_dir, options) do |out|
|
36
38
|
$logger.debug '%s' % [ out.strip ]
|
37
39
|
end
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
43
|
def execute_pre_build_scripts!
|
44
|
+
return nil if !exec_scripts? && container.pre_build_scripts.empty?
|
42
45
|
ExecLocal.new(container, container.pre_build_scripts, 'PRE build').execute!
|
43
46
|
end
|
44
|
-
|
45
47
|
end
|
46
48
|
end
|
47
49
|
end
|
@@ -4,37 +4,44 @@ module Percheron
|
|
4
4
|
|
5
5
|
include Base
|
6
6
|
|
7
|
-
def initialize(container,
|
7
|
+
def initialize(container, start: false, cmd: false, exec_scripts: true)
|
8
8
|
@container = container
|
9
|
-
@
|
9
|
+
@start = start
|
10
|
+
@exec_scripts = exec_scripts
|
11
|
+
@cmd = cmd
|
12
|
+
@container_image_existed = container.image_exists?
|
10
13
|
end
|
11
14
|
|
12
|
-
def execute!
|
15
|
+
def execute!
|
13
16
|
results = []
|
14
|
-
if
|
15
|
-
results << create!(opts)
|
16
|
-
else
|
17
|
+
if container.exists?
|
17
18
|
$logger.debug "Container '#{container.name}' already exists"
|
19
|
+
else
|
20
|
+
results << create!
|
18
21
|
end
|
19
22
|
results.compact.empty? ? nil : container
|
20
23
|
end
|
21
24
|
|
22
25
|
private
|
23
26
|
|
24
|
-
attr_reader :container, :
|
27
|
+
attr_reader :container, :start, :exec_scripts, :container_image_existed
|
28
|
+
alias_method :start?, :start
|
29
|
+
alias_method :exec_scripts?, :exec_scripts
|
30
|
+
alias_method :container_image_existed?, :container_image_existed
|
31
|
+
|
32
|
+
def cmd
|
33
|
+
@cmd ||= (@cmd || container.start_args)
|
34
|
+
end
|
25
35
|
|
26
36
|
def base_options
|
27
37
|
{
|
28
|
-
'name' => container.
|
38
|
+
'name' => container.full_name,
|
29
39
|
'Image' => container.image_name,
|
30
|
-
'Hostname' => container.
|
40
|
+
'Hostname' => container.hostname,
|
31
41
|
'Env' => container.env,
|
32
42
|
'ExposedPorts' => container.exposed_ports,
|
33
|
-
'
|
34
|
-
|
35
|
-
'Links' => container.links,
|
36
|
-
'Binds' => container.volumes
|
37
|
-
}
|
43
|
+
'Cmd' => cmd,
|
44
|
+
'Labels' => container.labels
|
38
45
|
}
|
39
46
|
end
|
40
47
|
|
@@ -43,55 +50,74 @@ module Percheron
|
|
43
50
|
'HostConfig' => {
|
44
51
|
'PortBindings' => port_bindings,
|
45
52
|
'Links' => container.links,
|
46
|
-
'Binds' => container.volumes
|
53
|
+
'Binds' => container.volumes,
|
54
|
+
'Dns' => container.dns
|
47
55
|
}
|
48
56
|
}
|
49
57
|
end
|
50
58
|
|
59
|
+
def options
|
60
|
+
@options ||= base_options.merge(host_config_options)
|
61
|
+
end
|
62
|
+
|
51
63
|
def port_bindings
|
52
|
-
container.ports.
|
64
|
+
container.ports.each_with_object({}) do |p, all|
|
53
65
|
destination, source = p.split(':')
|
54
66
|
all[source] = [ { 'HostPort' => destination } ]
|
55
|
-
all
|
56
67
|
end
|
57
68
|
end
|
58
69
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def create!(opts)
|
64
|
-
build_image! unless container.image_exists?
|
70
|
+
def create!
|
71
|
+
container.buildable? ? build_image! : pull_image!
|
72
|
+
return unless container.startable?
|
65
73
|
insert_scripts!
|
66
|
-
create_container!
|
67
|
-
|
68
|
-
|
74
|
+
create_container!
|
75
|
+
update_dockerfile_md5!
|
76
|
+
start!
|
69
77
|
end
|
70
78
|
|
71
79
|
def build_image!
|
72
|
-
Build.new(container).execute!
|
80
|
+
Build.new(container).execute! unless container.image_exists?
|
73
81
|
end
|
74
82
|
|
75
|
-
|
76
|
-
|
77
|
-
|
83
|
+
# FIXME: move this
|
84
|
+
def pull_image!
|
85
|
+
return nil if container.image_exists?
|
86
|
+
$logger.info "Pulling '#{container.image_name}' image"
|
87
|
+
Docker::Image.create(fromImage: container.image_name) do |out|
|
88
|
+
$logger.debug JSON.parse(out)
|
89
|
+
end
|
78
90
|
end
|
79
91
|
|
80
|
-
def create_container!
|
81
|
-
|
82
|
-
$logger.info "Creating '%s' container" % options['name']
|
92
|
+
def create_container!
|
93
|
+
$logger.info "Creating '#{container.name}' container"
|
83
94
|
Docker::Container.create(options)
|
84
95
|
end
|
85
96
|
|
86
|
-
def
|
87
|
-
|
97
|
+
def start!
|
98
|
+
return nil if !container.startable? || !start?
|
99
|
+
Start.new(container).execute!
|
88
100
|
end
|
89
101
|
|
90
|
-
def
|
91
|
-
|
92
|
-
$metastore.set("#{container.metastore_key}.dockerfile_md5", container.current_dockerfile_md5)
|
102
|
+
def update_dockerfile_md5!
|
103
|
+
container.update_dockerfile_md5!
|
93
104
|
end
|
94
105
|
|
106
|
+
def insert_scripts!
|
107
|
+
return nil if container_image_existed?
|
108
|
+
insert_files!(container.post_start_scripts)
|
109
|
+
end
|
110
|
+
|
111
|
+
def insert_files!(files)
|
112
|
+
files.each { |file| insert_file!(file) }
|
113
|
+
end
|
114
|
+
|
115
|
+
def insert_file!(file)
|
116
|
+
file = Pathname.new(File.expand_path(file, base_dir))
|
117
|
+
opts = { 'localPath' => file.to_s, 'outputPath' => "/tmp/#{file.basename}" }
|
118
|
+
new_image = container.image.insert_local(opts)
|
119
|
+
new_image.tag(repo: container.image_repo, tag: container.version.to_s, force: true)
|
120
|
+
end
|
95
121
|
end
|
96
122
|
end
|
97
123
|
end
|
@@ -12,11 +12,8 @@ module Percheron
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def execute!
|
15
|
-
|
16
|
-
|
17
|
-
started_dependant_containers = start_containers!(dependant_containers)
|
18
|
-
results << execute_scripts_on_running_container!
|
19
|
-
results << stop_containers!(started_dependant_containers)
|
15
|
+
$logger.debug "Executing #{description} #{scripts.inspect} on '#{container.name}' container"
|
16
|
+
results = exec!
|
20
17
|
results.compact.empty? ? nil : container
|
21
18
|
end
|
22
19
|
|
@@ -24,29 +21,64 @@ module Percheron
|
|
24
21
|
|
25
22
|
attr_reader :container, :dependant_containers, :scripts, :description
|
26
23
|
|
24
|
+
def exec!
|
25
|
+
results = []
|
26
|
+
started_dependant_containers = start_containers!(dependant_containers)
|
27
|
+
results << execute_scripts_on_running_container!
|
28
|
+
results << stop_containers!(started_dependant_containers)
|
29
|
+
results
|
30
|
+
end
|
31
|
+
|
27
32
|
def execute_scripts_on_running_container!
|
28
33
|
container_running = container.running?
|
29
34
|
Start.new(container, exec_scripts: false).execute! unless container_running
|
30
35
|
execute_scripts!
|
36
|
+
commit_and_tag_new_image!
|
31
37
|
Stop.new(container).execute! unless container_running
|
32
38
|
end
|
33
39
|
|
40
|
+
# FIXME
|
41
|
+
def commit_and_tag_new_image!
|
42
|
+
new_image = container.docker_container.commit
|
43
|
+
new_image.tag(repo: container.image_repo, tag: container.version.to_s, force: true)
|
44
|
+
end
|
45
|
+
|
34
46
|
def execute_scripts!
|
35
47
|
scripts.each do |script|
|
36
48
|
in_working_directory(base_dir) do
|
37
49
|
file = Pathname.new(File.expand_path(script, base_dir))
|
38
|
-
execute_command!('/bin/
|
50
|
+
execute_command!('/bin/sh /tmp/%s 2>&1' % file.basename)
|
39
51
|
end
|
40
52
|
end
|
41
53
|
end
|
42
54
|
|
43
55
|
def execute_command!(command)
|
44
56
|
$logger.info "Executing #{description} '#{command}' for '#{container.name}' container"
|
45
|
-
container.docker_container.exec(command.split(' ')) do |
|
46
|
-
$logger.debug '%s: %s' % [
|
57
|
+
container.docker_container.exec(command.split(' ')) do |stream, out|
|
58
|
+
$logger.debug '%s: %s' % [ stream, out.strip ]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def stop_containers!(containers)
|
63
|
+
exec_on_containers!(containers) do |container|
|
64
|
+
Stop.new(container).execute! if container.running?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def start_containers!(containers, scripts: true)
|
69
|
+
exec_on_containers!(containers) do |container|
|
70
|
+
next if container.running?
|
71
|
+
containers = container.startable_dependant_containers.values
|
72
|
+
Start.new(container, dependant_containers: containers, exec_scripts: scripts).execute!
|
47
73
|
end
|
48
74
|
end
|
49
75
|
|
76
|
+
def exec_on_containers!(containers)
|
77
|
+
containers.each_with_object([]) do |container, all|
|
78
|
+
all << container if yield(container)
|
79
|
+
end.compact
|
80
|
+
end
|
81
|
+
|
50
82
|
end
|
51
83
|
end
|
52
84
|
end
|
@@ -26,15 +26,15 @@ module Percheron
|
|
26
26
|
$logger.debug "Executing #{description} scripts '#{scripts.inspect}' locally"
|
27
27
|
scripts.each do |script|
|
28
28
|
in_working_directory(base_dir) do
|
29
|
-
execute_command!('/bin/
|
29
|
+
execute_command!('/bin/sh %s 2>&1' % Pathname.new(File.expand_path(script)))
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
def execute_command!(command)
|
35
|
-
$logger.info "Executing #{description} '#{command}' locally"
|
36
|
-
Open3.popen2e(command) do |
|
37
|
-
while line = stdout_stderr.gets
|
35
|
+
$logger.info "Executing #{description} script '#{command}' locally"
|
36
|
+
Open3.popen2e(command) do |_, stdout_stderr, _|
|
37
|
+
while (line = stdout_stderr.gets)
|
38
38
|
$logger.debug line.strip
|
39
39
|
end
|
40
40
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Percheron
|
2
|
+
module Actions
|
3
|
+
class Logs
|
4
|
+
include Base
|
5
|
+
|
6
|
+
def initialize(container, follow: false)
|
7
|
+
@container = container
|
8
|
+
@follow = follow
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute!
|
12
|
+
$logger.debug "Showing logs on '#{container.name}' container"
|
13
|
+
display_logs!
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :container, :follow
|
19
|
+
alias_method :follow?, :follow
|
20
|
+
|
21
|
+
def options
|
22
|
+
{
|
23
|
+
stdout: true,
|
24
|
+
stderr: true,
|
25
|
+
timestamps: true,
|
26
|
+
tail: 100
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def display_logs!
|
31
|
+
if follow?
|
32
|
+
opts = options.merge(follow: true)
|
33
|
+
container.docker_container.streaming_logs(opts) do |stream, chunk|
|
34
|
+
puts "#{stream}: #{chunk}"
|
35
|
+
end
|
36
|
+
else
|
37
|
+
puts container.docker_container.logs(options)
|
38
|
+
end
|
39
|
+
rescue Interrupt
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -4,34 +4,45 @@ module Percheron
|
|
4
4
|
|
5
5
|
include Base
|
6
6
|
|
7
|
-
def initialize(container)
|
7
|
+
def initialize(container, delete_image: true)
|
8
8
|
@container = container
|
9
|
+
@delete_image = delete_image
|
9
10
|
end
|
10
11
|
|
11
12
|
def execute!
|
12
13
|
results = []
|
13
14
|
results << stop!
|
14
|
-
results << delete_container!
|
15
|
-
results << delete_image!
|
15
|
+
results << delete_container!
|
16
|
+
results << delete_image!
|
16
17
|
results.compact.empty? ? nil : container
|
17
18
|
end
|
18
19
|
|
19
20
|
private
|
20
21
|
|
21
|
-
attr_reader :container
|
22
|
+
attr_reader :container, :delete_image
|
22
23
|
|
23
24
|
def stop!
|
24
25
|
Stop.new(container).execute!
|
25
26
|
end
|
26
27
|
|
28
|
+
def delete_image?
|
29
|
+
delete_image && container.image_exists? && container.buildable?
|
30
|
+
end
|
31
|
+
|
27
32
|
def delete_container!
|
33
|
+
return nil unless container.exists?
|
28
34
|
$logger.info "Deleting '#{container.name}' container"
|
29
35
|
container.docker_container.remove
|
36
|
+
rescue Docker::Error::ConflictError => e
|
37
|
+
$logger.error "Unable to delete '%s' container - %s" % [ container.name, e.inspect ]
|
30
38
|
end
|
31
39
|
|
32
40
|
def delete_image!
|
41
|
+
return nil unless delete_image?
|
33
42
|
$logger.info "Deleting '#{container.image_name}' image"
|
34
43
|
container.image.remove
|
44
|
+
rescue Docker::Error::ConflictError => e
|
45
|
+
$logger.error "Unable to delete '%s' image - %s" % [ container.image_name, e.inspect ]
|
35
46
|
end
|
36
47
|
|
37
48
|
end
|