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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +4 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +31 -0
  5. data/.travis.yml +4 -1
  6. data/Guardfile +3 -3
  7. data/README.md +19 -3
  8. data/Rakefile +24 -1
  9. data/bin/percheron +2 -20
  10. data/lib/percheron/actions/base.rb +0 -39
  11. data/lib/percheron/actions/build.rb +9 -7
  12. data/lib/percheron/actions/create.rb +64 -38
  13. data/lib/percheron/actions/exec.rb +40 -8
  14. data/lib/percheron/actions/exec_local.rb +4 -4
  15. data/lib/percheron/actions/logs.rb +44 -0
  16. data/lib/percheron/actions/purge.rb +15 -4
  17. data/lib/percheron/actions/recreate.rb +15 -65
  18. data/lib/percheron/actions/restart.rb +2 -1
  19. data/lib/percheron/actions/shell.rb +27 -0
  20. data/lib/percheron/actions/start.rb +10 -7
  21. data/lib/percheron/actions.rb +2 -1
  22. data/lib/percheron/commands/abstract.rb +20 -8
  23. data/lib/percheron/commands/build.rb +13 -0
  24. data/lib/percheron/commands/console.rb +53 -0
  25. data/lib/percheron/commands/create.rb +3 -3
  26. data/lib/percheron/commands/list.rb +7 -3
  27. data/lib/percheron/commands/logs.rb +16 -0
  28. data/lib/percheron/commands/main.rb +5 -2
  29. data/lib/percheron/commands/purge.rb +2 -2
  30. data/lib/percheron/commands/recreate.rb +3 -11
  31. data/lib/percheron/commands/restart.rb +2 -2
  32. data/lib/percheron/commands/shell.rb +16 -0
  33. data/lib/percheron/commands/start.rb +2 -2
  34. data/lib/percheron/commands/stop.rb +2 -2
  35. data/lib/percheron/commands.rb +3 -0
  36. data/lib/percheron/config.rb +64 -3
  37. data/lib/percheron/config_delegator.rb +0 -1
  38. data/lib/percheron/container.rb +95 -38
  39. data/lib/percheron/core_extensions.rb +1 -4
  40. data/lib/percheron/docker_connection.rb +5 -1
  41. data/lib/percheron/formatters/stack/table.rb +24 -12
  42. data/lib/percheron/logger.rb +21 -0
  43. data/lib/percheron/metastore.rb +1 -0
  44. data/lib/percheron/null_stack.rb +5 -0
  45. data/lib/percheron/oh_dear.rb +15 -7
  46. data/lib/percheron/stack.rb +77 -72
  47. data/lib/percheron/validators/config.rb +1 -1
  48. data/lib/percheron/validators/container.rb +31 -11
  49. data/lib/percheron/validators/stack.rb +3 -5
  50. data/lib/percheron/version.rb +1 -1
  51. data/lib/percheron.rb +2 -0
  52. data/percheron.gemspec +4 -1
  53. metadata +54 -4
  54. data/assets/percheron.png +0 -0
  55. data/lib/percheron/actions/rename.rb +0 -65
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61e4d66006bf086c797d921852dae42438f8abca
4
- data.tar.gz: b91b6698c444e51757bee46fa5f290b67211670b
3
+ metadata.gz: cbab3f52787ff0b165f9482186771b07ff673df1
4
+ data.tar.gz: ce6eb63e3621d595f814c8806728bfe9b43fae7b
5
5
  SHA512:
6
- metadata.gz: 9a136f407d6823d6983723a36ea9056f56e440411e56df65e2101348fbb4dcd957027f570a9af29b21f9e5c273698ca9a460a05666fa79353577413c00e8892e
7
- data.tar.gz: b87043f174f595bd1aed913e087089575d7ee602d5a46a5810d01c98aebd38d4816aa1a45145f2b7b685fb443bb1fd4d10c29a3e7ed0dc8396048a0299bbb97c
6
+ metadata.gz: 4b198258dc8f5226a08563b77d1826af3f56eea705c35632d85bbca4d9e49be216c17fc5b776404fe7caac50ac2e84aa1d5c507493faf4edbaf110b276a1c3bc
7
+ data.tar.gz: f790fdeb14e59ce702f5569ea4043fd4747acfd6bc91934ed86646be290bd7e7d98782e049c0da198e9446f9b83d20e7724e7d17e8229502825172bc8d940077
data/.cane ADDED
@@ -0,0 +1,4 @@
1
+ --abc-glob ./lib/**/*.rb
2
+ --style-glob ./lib/**/*.rb
3
+ --style-measure 100
4
+ --no-doc
data/.gitignore CHANGED
@@ -9,3 +9,4 @@
9
9
  /tmp/
10
10
  .ruby-version
11
11
  percheron.sublime-*
12
+ .envrc
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
@@ -5,4 +5,7 @@ branches:
5
5
  only:
6
6
  - master
7
7
  - wip
8
- script: bundle exec rake spec
8
+ script:
9
+ - bundle exec cane
10
+ - bundle exec rubocop
11
+ - bundle exec rake spec:unit
data/Guardfile CHANGED
@@ -1,5 +1,5 @@
1
1
  guard :rspec, cmd: 'bundle exec rspec' do
2
- watch(%r{^spec/.+_spec\.rb$})
3
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
- watch('spec/spec_helper.rb') { "spec" }
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
- WIP, not ready yet :)
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
- RSpec::Core::RakeTask.new('spec')
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
- $metastore = Metastore::Cabinet.new(File.join(ENV['HOME'], '.percheron', 'metastore.yaml'))
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 build_opts
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! unless container.pre_build_scripts.empty?
35
+ execute_pre_build_scripts!
34
36
  $logger.info "Building '#{container.image_name}' image"
35
- Docker::Image.build_from_dir(base_dir, build_opts) do |out|
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, recreate: false)
7
+ def initialize(container, start: false, cmd: false, exec_scripts: true)
8
8
  @container = container
9
- @recreate = recreate
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!(opts={})
15
+ def execute!
13
16
  results = []
14
- if recreate? || !container.exists?
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, :recreate
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.name,
38
+ 'name' => container.full_name,
29
39
  'Image' => container.image_name,
30
- 'Hostname' => container.name,
40
+ 'Hostname' => container.hostname,
31
41
  'Env' => container.env,
32
42
  'ExposedPorts' => container.exposed_ports,
33
- 'HostConfig' => {
34
- 'PortBindings' => port_bindings,
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.inject({}) do |all, p|
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 recreate?
60
- recreate
61
- end
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!(opts.fetch(:create, {}))
67
- execute_post_create_scripts! unless container.post_create_scripts.empty?
68
- set_dockerfile_md5!
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
- def insert_scripts!
76
- insert_files!(container.post_create_scripts)
77
- insert_files!(container.post_start_scripts)
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!(opts)
81
- options = base_options.merge(host_config_options).merge(opts)
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 execute_post_create_scripts!
87
- Exec.new(container, container.dependant_containers.values, container.post_create_scripts, 'POST create').execute!
97
+ def start!
98
+ return nil if !container.startable? || !start?
99
+ Start.new(container).execute!
88
100
  end
89
101
 
90
- def set_dockerfile_md5!
91
- $logger.info "Setting MD5 for '#{container.name}' container to #{container.current_dockerfile_md5}"
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
- results = []
16
- $logger.debug "Executing #{description} scripts '#{scripts.inspect}' on '#{container.name}'"
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/bash -x /tmp/%s 2>&1' % file.basename)
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 |device, out|
46
- $logger.debug '%s: %s' % [ device, out.strip ]
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/bash -x %s 2>&1' % Pathname.new(File.expand_path(script)))
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 |stdin, stdout_stderr, wait_thr|
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! if container.exists?
15
- results << delete_image! if container.image_exists?
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