percheron 0.6.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Test Coverage](https://codeclimate.com/github/ashmckenzie/percheron/badges/coverage.svg)](https://codeclimate.com/github/ashmckenzie/percheron)
|
7
7
|
[![Dependency Status](https://gemnasium.com/ashmckenzie/percheron.svg)](https://gemnasium.com/ashmckenzie/percheron)
|
8
8
|
|
9
|
-
![Percheron](https://raw.githubusercontent.com/ashmckenzie/percheron/master/assets/percheron.png)
|
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
|