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