percheron 0.5.0 → 0.6.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -3
  3. data/Guardfile +5 -0
  4. data/bin/percheron +8 -4
  5. data/lib/percheron.rb +3 -0
  6. data/lib/percheron/actions.rb +15 -0
  7. data/lib/percheron/actions/base.rb +50 -0
  8. data/lib/percheron/actions/build.rb +47 -0
  9. data/lib/percheron/actions/create.rb +109 -0
  10. data/lib/percheron/actions/exec.rb +51 -0
  11. data/lib/percheron/actions/purge.rb +38 -0
  12. data/lib/percheron/actions/recreate.rb +98 -0
  13. data/lib/percheron/actions/rename.rb +64 -0
  14. data/lib/percheron/actions/restart.rb +31 -0
  15. data/lib/percheron/actions/start.rb +46 -0
  16. data/lib/percheron/actions/stop.rb +27 -0
  17. data/lib/percheron/cli.rb +1 -0
  18. data/lib/percheron/cli/abstract_command.rb +7 -0
  19. data/lib/percheron/cli/create_command.rb +3 -2
  20. data/lib/percheron/cli/list_command.rb +2 -8
  21. data/lib/percheron/cli/main_command.rb +1 -0
  22. data/lib/percheron/cli/purge_command.rb +12 -0
  23. data/lib/percheron/cli/recreate_command.rb +9 -2
  24. data/lib/percheron/cli/restart_command.rb +3 -2
  25. data/lib/percheron/cli/start_command.rb +3 -2
  26. data/lib/percheron/cli/stop_command.rb +3 -2
  27. data/lib/percheron/container.rb +120 -5
  28. data/lib/percheron/errors.rb +0 -1
  29. data/lib/percheron/formatters/stack/table.rb +1 -1
  30. data/lib/percheron/null_container.rb +13 -0
  31. data/lib/percheron/oh_dear.rb +46 -0
  32. data/lib/percheron/stack.rb +90 -31
  33. data/lib/percheron/validators/container.rb +9 -1
  34. data/lib/percheron/version.rb +1 -1
  35. data/percheron.gemspec +2 -0
  36. metadata +45 -11
  37. data/lib/percheron/container/actions.rb +0 -15
  38. data/lib/percheron/container/actions/base.rb +0 -21
  39. data/lib/percheron/container/actions/build.rb +0 -58
  40. data/lib/percheron/container/actions/create.rb +0 -56
  41. data/lib/percheron/container/actions/recreate.rb +0 -110
  42. data/lib/percheron/container/actions/start.rb +0 -58
  43. data/lib/percheron/container/actions/stop.rb +0 -33
  44. data/lib/percheron/container/main.rb +0 -193
  45. data/lib/percheron/container/null.rb +0 -15
@@ -0,0 +1,64 @@
1
+ module Percheron
2
+ module Actions
3
+ class Rename
4
+
5
+ include Base
6
+
7
+ def initialize(container, temporary_name, new_name)
8
+ @container = container
9
+ @temporary_name = temporary_name
10
+ @new_name = new_name
11
+ end
12
+
13
+ def execute!
14
+ rename!
15
+ container
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :container, :temporary_name, :new_name
21
+
22
+ def rename_current_new_name
23
+ @rename_current_new_name ||= '%s_%s' % [ container.name, now_timestamp ]
24
+ end
25
+
26
+ def old_container
27
+ Docker::Container.get(rename_current_new_name)
28
+ end
29
+
30
+ def temporary_container
31
+ Docker::Container.get(temporary_name)
32
+ end
33
+
34
+ def rename!
35
+ container_running = container.running?
36
+ stop_containers!([ container ]) if container_running
37
+ rename_containers!
38
+ start_containers!([ container ]) if container_running
39
+ remove_old!
40
+ end
41
+
42
+ def rename_containers!
43
+ rename_container_current_to_old! if container.exists?
44
+ rename_container_temporary_to_new!
45
+ end
46
+
47
+ def rename_container_current_to_old!
48
+ $logger.info "Renaming '#{container.name}' container to '#{rename_current_new_name}'"
49
+ container.docker_container.rename(rename_current_new_name)
50
+ end
51
+
52
+ def rename_container_temporary_to_new!
53
+ $logger.info "Renaming '#{temporary_name}' container to '#{new_name}'"
54
+ temporary_container.rename(new_name)
55
+ end
56
+
57
+ def remove_old!
58
+ $logger.info "Removing '#{rename_current_new_name}' container"
59
+ old_container.remove
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,31 @@
1
+ module Percheron
2
+ module Actions
3
+ class Restart
4
+
5
+ include Base
6
+
7
+ def initialize(container)
8
+ @container = container
9
+ end
10
+
11
+ def execute!
12
+ stop!
13
+ start!
14
+ container
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :container
20
+
21
+ def stop!
22
+ Stop.new(container).execute!
23
+ end
24
+
25
+ def start!
26
+ Start.new(container, container.dependant_containers.values).execute!
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,46 @@
1
+ module Percheron
2
+ module Actions
3
+ class Start
4
+
5
+ include Base
6
+
7
+ def initialize(container, dependant_containers=[])
8
+ @container = container
9
+ @dependant_containers = dependant_containers
10
+ end
11
+
12
+ def execute!
13
+ create_or_recreate!
14
+ start! unless container.running?
15
+ execute_post_start_scripts! unless container.post_start_scripts.empty?
16
+ container
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :container, :dependant_containers
22
+
23
+ def create_or_recreate!
24
+ container.exists? ? recreate! : create!
25
+ end
26
+
27
+ def create!
28
+ Create.new(container).execute!
29
+ end
30
+
31
+ def recreate!
32
+ Recreate.new(container).execute!
33
+ end
34
+
35
+ def start!
36
+ $logger.info "Starting '#{container.name}' container"
37
+ container.docker_container.start!
38
+ end
39
+
40
+ def execute_post_start_scripts!
41
+ Exec.new(container, dependant_containers, container.post_start_scripts, 'POST start').execute!
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,27 @@
1
+ module Percheron
2
+ module Actions
3
+ class Stop
4
+
5
+ include Base
6
+
7
+ def initialize(container)
8
+ @container = container
9
+ end
10
+
11
+ def execute!
12
+ stop! if container.running?
13
+ container
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :container
19
+
20
+ def stop!
21
+ $logger.info "Stopping '#{container.name}' container"
22
+ container.docker_container.stop!
23
+ end
24
+
25
+ end
26
+ end
27
+ end
data/lib/percheron/cli.rb CHANGED
@@ -5,6 +5,7 @@ require 'percheron/cli/list_command'
5
5
  require 'percheron/cli/restart_command'
6
6
  require 'percheron/cli/start_command'
7
7
  require 'percheron/cli/stop_command'
8
+ require 'percheron/cli/purge_command'
8
9
  require 'percheron/cli/console_command'
9
10
  require 'percheron/cli/create_command'
10
11
  require 'percheron/cli/recreate_command'
@@ -11,6 +11,13 @@ module Percheron
11
11
  exit(0)
12
12
  end
13
13
 
14
+ def self.default_parameters!
15
+ parameter('STACK_NAME', 'stack name', required: false)
16
+ parameter('CONTAINER_NAMES', 'container names', required: false, default: []) do |container_names|
17
+ container_names.split(/,/)
18
+ end
19
+ end
20
+
14
21
  def default_config_file
15
22
  ENV.fetch('PERCHERON_CONFIG', DEFAULT_CONFIG_FILE)
16
23
  end
@@ -2,10 +2,11 @@ module Percheron
2
2
  module CLI
3
3
  class CreateCommand < AbstractCommand
4
4
 
5
- parameter 'STACK_NAME', 'stack name'
5
+ default_parameters!
6
6
 
7
7
  def execute
8
- Percheron::Stack.new(config, stack_name).create!
8
+ opts = { container_names: container_names }
9
+ Percheron::Stack.new(config, stack_name).create!(opts)
9
10
  end
10
11
  end
11
12
  end
@@ -2,16 +2,10 @@ module Percheron
2
2
  module CLI
3
3
  class ListCommand < AbstractCommand
4
4
 
5
- parameter 'STACK_NAME', 'stack name', required: false
5
+ parameter('STACK_NAME', 'stack name', required: false)
6
6
 
7
7
  def execute
8
- stacks = if stack_name
9
- Stack.get(config, stack_name)
10
- else
11
- Stack.all(config)
12
- end
13
-
14
- stacks.each do |stack_name, stack|
8
+ Stack.get(config, stack_name).each do |stack_name, stack|
15
9
  puts
16
10
  puts Percheron::Formatters::Stack::Table.new(stack).generate
17
11
  end
@@ -8,6 +8,7 @@ module Percheron
8
8
  subcommand 'restart', 'Restart a stack', RestartCommand
9
9
  subcommand 'create', 'Create a stack', CreateCommand
10
10
  subcommand 'recreate', 'Recreate a stack', RecreateCommand
11
+ subcommand 'purge', 'Purge a stack', PurgeCommand
11
12
  end
12
13
  end
13
14
  end
@@ -0,0 +1,12 @@
1
+ module Percheron
2
+ module CLI
3
+ class PurgeCommand < AbstractCommand
4
+
5
+ parameter('STACK_NAME', 'stack name', required: false)
6
+
7
+ def execute
8
+ Percheron::Stack.new(config, stack_name).purge!
9
+ end
10
+ end
11
+ end
12
+ end
@@ -2,12 +2,19 @@ module Percheron
2
2
  module CLI
3
3
  class RecreateCommand < AbstractCommand
4
4
 
5
- parameter 'STACK_NAME', 'stack name'
5
+ default_parameters!
6
6
 
7
7
  option "--force", :flag, 'Force recreation', default: false
8
+ option "--delete", :flag, 'Delete container + image before recreation', default: false
8
9
 
9
10
  def execute
10
- Percheron::Stack.new(config, stack_name).recreate!(force_recreate: force?, force_auto_recreate: true)
11
+ opts = {
12
+ container_names: container_names,
13
+ force_recreate: force?,
14
+ delete: delete?
15
+ }
16
+
17
+ Percheron::Stack.new(config, stack_name).recreate!(opts)
11
18
  end
12
19
  end
13
20
  end
@@ -2,10 +2,11 @@ module Percheron
2
2
  module CLI
3
3
  class RestartCommand < AbstractCommand
4
4
 
5
- parameter 'STACK_NAME', 'stack name'
5
+ default_parameters!
6
6
 
7
7
  def execute
8
- Percheron::Stack.new(config, stack_name).restart!
8
+ opts = { container_names: container_names }
9
+ Percheron::Stack.new(config, stack_name).restart!(opts)
9
10
  end
10
11
  end
11
12
  end
@@ -2,10 +2,11 @@ module Percheron
2
2
  module CLI
3
3
  class StartCommand < AbstractCommand
4
4
 
5
- parameter 'STACK_NAME', 'stack name'
5
+ default_parameters!
6
6
 
7
7
  def execute
8
- Percheron::Stack.new(config, stack_name).start!
8
+ opts = { container_names: container_names }
9
+ Percheron::Stack.new(config, stack_name).start!(opts)
9
10
  end
10
11
  end
11
12
  end
@@ -2,10 +2,11 @@ module Percheron
2
2
  module CLI
3
3
  class StopCommand < AbstractCommand
4
4
 
5
- parameter 'STACK_NAME', 'stack name'
5
+ default_parameters!
6
6
 
7
7
  def execute
8
- Percheron::Stack.new(config, stack_name).stop!
8
+ opts = { container_names: container_names }
9
+ Percheron::Stack.new(config, stack_name).stop!(opts)
9
10
  end
10
11
  end
11
12
  end
@@ -1,8 +1,123 @@
1
- require 'percheron/container/main'
2
- require 'percheron/container/null'
3
- require 'percheron/container/actions'
4
-
5
1
  module Percheron
6
- module Container
2
+ class Container
3
+
4
+ extend Forwardable
5
+ extend ConfigDelegator
6
+
7
+ def_delegators :container_config, :name
8
+
9
+ def_config_item_with_default :container_config, false, :auto_recreate
10
+ def_config_item_with_default :container_config, [], :env, :ports, :volumes, :dependant_container_names, :pre_build_scripts, :post_create_scripts, :post_start_scripts
11
+
12
+ alias_method :auto_recreate?, :auto_recreate
13
+
14
+ def initialize(config, stack, container_name)
15
+ @config = config
16
+ @stack = stack
17
+ @container_name = container_name
18
+ valid?
19
+ self
20
+ end
21
+
22
+ def id
23
+ exists? ? info.id[0...12] : 'N/A'
24
+ end
25
+
26
+ def image_name
27
+ '%s:%s' % [ name, version.to_s ]
28
+ end
29
+
30
+ def image
31
+ Docker::Image.get(image_name)
32
+ rescue Docker::Error::NotFoundError
33
+ nil
34
+ end
35
+
36
+ def version
37
+ Semantic::Version.new(container_config.version)
38
+ end
39
+
40
+ def built_version
41
+ Semantic::Version.new(exists? ? built_image_version : '0.0.0')
42
+ end
43
+
44
+ def dockerfile
45
+ container_config.dockerfile ? Pathname.new(File.expand_path(container_config.dockerfile, config.file_base_path)): nil
46
+ end
47
+
48
+ def exposed_ports
49
+ ports.inject({}) do |all, p|
50
+ all[p.split(':')[1]] = {}
51
+ all
52
+ end
53
+ end
54
+
55
+ def links
56
+ dependant_container_names.map do |container_name|
57
+ '%s:%s' % [ container_name, container_name ]
58
+ end
59
+ end
60
+
61
+ def docker_container
62
+ Docker::Container.get(name)
63
+ rescue Docker::Error::NotFoundError, Excon::Errors::SocketError
64
+ NullContainer.new
65
+ end
66
+
67
+ def dependant_containers
68
+ dependant_container_names.inject({}) do |all, container_name|
69
+ all[container_name] = stack.filter_containers[container_name]
70
+ all
71
+ end
72
+ end
73
+
74
+ def metastore_key
75
+ @metastore_key ||= 'stacks.%s.containers.%s' % [ stack.name, name ]
76
+ end
77
+
78
+ def current_dockerfile_md5
79
+ Digest::MD5.file(dockerfile).hexdigest
80
+ end
81
+
82
+ def dockerfile_md5
83
+ $metastore.get("#{metastore_key}.dockerfile_md5")
84
+ end
85
+
86
+ def running?
87
+ exists? && info.State.Running
88
+ end
89
+
90
+ def exists?
91
+ !info.empty?
92
+ end
93
+
94
+ def image_exists?
95
+ !!image
96
+ end
97
+
98
+ def dependant_containers?
99
+ !dependant_container_names.empty?
100
+ end
101
+
102
+ def valid?
103
+ Validators::Container.new(self).valid?
104
+ end
105
+
106
+ private
107
+
108
+ attr_reader :config, :stack, :container_name
109
+
110
+ def built_image_version
111
+ info.Config.Image.split(':')[1]
112
+ end
113
+
114
+ def info
115
+ Hashie::Mash.new(docker_container.info)
116
+ end
117
+
118
+ def container_config
119
+ @container_config ||= stack.container_configs[container_name] || Hashie::Mash.new({})
120
+ end
121
+
7
122
  end
8
123
  end