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.
- checksums.yaml +4 -4
- data/Gemfile +3 -3
- data/Guardfile +5 -0
- data/bin/percheron +8 -4
- data/lib/percheron.rb +3 -0
- data/lib/percheron/actions.rb +15 -0
- data/lib/percheron/actions/base.rb +50 -0
- data/lib/percheron/actions/build.rb +47 -0
- data/lib/percheron/actions/create.rb +109 -0
- data/lib/percheron/actions/exec.rb +51 -0
- data/lib/percheron/actions/purge.rb +38 -0
- data/lib/percheron/actions/recreate.rb +98 -0
- data/lib/percheron/actions/rename.rb +64 -0
- data/lib/percheron/actions/restart.rb +31 -0
- data/lib/percheron/actions/start.rb +46 -0
- data/lib/percheron/actions/stop.rb +27 -0
- data/lib/percheron/cli.rb +1 -0
- data/lib/percheron/cli/abstract_command.rb +7 -0
- data/lib/percheron/cli/create_command.rb +3 -2
- data/lib/percheron/cli/list_command.rb +2 -8
- data/lib/percheron/cli/main_command.rb +1 -0
- data/lib/percheron/cli/purge_command.rb +12 -0
- data/lib/percheron/cli/recreate_command.rb +9 -2
- data/lib/percheron/cli/restart_command.rb +3 -2
- data/lib/percheron/cli/start_command.rb +3 -2
- data/lib/percheron/cli/stop_command.rb +3 -2
- data/lib/percheron/container.rb +120 -5
- data/lib/percheron/errors.rb +0 -1
- data/lib/percheron/formatters/stack/table.rb +1 -1
- data/lib/percheron/null_container.rb +13 -0
- data/lib/percheron/oh_dear.rb +46 -0
- data/lib/percheron/stack.rb +90 -31
- data/lib/percheron/validators/container.rb +9 -1
- data/lib/percheron/version.rb +1 -1
- data/percheron.gemspec +2 -0
- metadata +45 -11
- data/lib/percheron/container/actions.rb +0 -15
- data/lib/percheron/container/actions/base.rb +0 -21
- data/lib/percheron/container/actions/build.rb +0 -58
- data/lib/percheron/container/actions/create.rb +0 -56
- data/lib/percheron/container/actions/recreate.rb +0 -110
- data/lib/percheron/container/actions/start.rb +0 -58
- data/lib/percheron/container/actions/stop.rb +0 -33
- data/lib/percheron/container/main.rb +0 -193
- 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
|
-
|
5
|
+
default_parameters!
|
6
6
|
|
7
7
|
def execute
|
8
|
-
|
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
|
5
|
+
parameter('STACK_NAME', 'stack name', required: false)
|
6
6
|
|
7
7
|
def execute
|
8
|
-
|
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
|
@@ -2,12 +2,19 @@ module Percheron
|
|
2
2
|
module CLI
|
3
3
|
class RecreateCommand < AbstractCommand
|
4
4
|
|
5
|
-
|
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
|
-
|
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
|
-
|
5
|
+
default_parameters!
|
6
6
|
|
7
7
|
def execute
|
8
|
-
|
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
|
-
|
5
|
+
default_parameters!
|
6
6
|
|
7
7
|
def execute
|
8
|
-
|
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
|
-
|
5
|
+
default_parameters!
|
6
6
|
|
7
7
|
def execute
|
8
|
-
|
8
|
+
opts = { container_names: container_names }
|
9
|
+
Percheron::Stack.new(config, stack_name).stop!(opts)
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
data/lib/percheron/container.rb
CHANGED
@@ -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
|
-
|
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
|