percheron 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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