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.
- checksums.yaml +4 -4
- data/.cane +4 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +31 -0
- data/.travis.yml +4 -1
- data/Guardfile +3 -3
- data/README.md +19 -3
- data/Rakefile +24 -1
- data/bin/percheron +2 -20
- data/lib/percheron/actions/base.rb +0 -39
- data/lib/percheron/actions/build.rb +9 -7
- data/lib/percheron/actions/create.rb +64 -38
- data/lib/percheron/actions/exec.rb +40 -8
- data/lib/percheron/actions/exec_local.rb +4 -4
- data/lib/percheron/actions/logs.rb +44 -0
- data/lib/percheron/actions/purge.rb +15 -4
- data/lib/percheron/actions/recreate.rb +15 -65
- data/lib/percheron/actions/restart.rb +2 -1
- data/lib/percheron/actions/shell.rb +27 -0
- data/lib/percheron/actions/start.rb +10 -7
- data/lib/percheron/actions.rb +2 -1
- data/lib/percheron/commands/abstract.rb +20 -8
- data/lib/percheron/commands/build.rb +13 -0
- data/lib/percheron/commands/console.rb +53 -0
- data/lib/percheron/commands/create.rb +3 -3
- data/lib/percheron/commands/list.rb +7 -3
- data/lib/percheron/commands/logs.rb +16 -0
- data/lib/percheron/commands/main.rb +5 -2
- data/lib/percheron/commands/purge.rb +2 -2
- data/lib/percheron/commands/recreate.rb +3 -11
- data/lib/percheron/commands/restart.rb +2 -2
- data/lib/percheron/commands/shell.rb +16 -0
- data/lib/percheron/commands/start.rb +2 -2
- data/lib/percheron/commands/stop.rb +2 -2
- data/lib/percheron/commands.rb +3 -0
- data/lib/percheron/config.rb +64 -3
- data/lib/percheron/config_delegator.rb +0 -1
- data/lib/percheron/container.rb +95 -38
- data/lib/percheron/core_extensions.rb +1 -4
- data/lib/percheron/docker_connection.rb +5 -1
- data/lib/percheron/formatters/stack/table.rb +24 -12
- data/lib/percheron/logger.rb +21 -0
- data/lib/percheron/metastore.rb +1 -0
- data/lib/percheron/null_stack.rb +5 -0
- data/lib/percheron/oh_dear.rb +15 -7
- data/lib/percheron/stack.rb +77 -72
- data/lib/percheron/validators/config.rb +1 -1
- data/lib/percheron/validators/container.rb +31 -11
- data/lib/percheron/validators/stack.rb +3 -5
- data/lib/percheron/version.rb +1 -1
- data/lib/percheron.rb +2 -0
- data/percheron.gemspec +4 -1
- metadata +54 -4
- data/assets/percheron.png +0 -0
- data/lib/percheron/actions/rename.rb +0 -65
data/lib/percheron/container.rb
CHANGED
@@ -4,27 +4,78 @@ module Percheron
|
|
4
4
|
extend Forwardable
|
5
5
|
extend ConfigDelegator
|
6
6
|
|
7
|
-
def_delegators :container_config, :name
|
7
|
+
def_delegators :container_config, :name, :pseudo_name, :docker_image
|
8
|
+
def_config_item_with_default :container_config, [], :env, :ports, :volumes,
|
9
|
+
:dependant_container_names, :pre_build_scripts,
|
10
|
+
:post_start_scripts, :start_args
|
11
|
+
def_config_item_with_default :container_config, %w(127.0.0.1 8.8.8.8), :dns
|
12
|
+
def_config_item_with_default :container_config, true, :startable
|
8
13
|
|
9
|
-
|
10
|
-
def_config_item_with_default :container_config, [], :env, :ports, :volumes, :dependant_container_names, :pre_build_scripts, :post_create_scripts, :post_start_scripts
|
14
|
+
attr_reader :config_file_base_path
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
def initialize(config, stack, container_name)
|
15
|
-
@config = config
|
16
|
+
def initialize(stack, container_name, config_file_base_path)
|
16
17
|
@stack = stack
|
17
18
|
@container_name = container_name
|
18
|
-
|
19
|
+
@config_file_base_path = config_file_base_path
|
19
20
|
self
|
20
21
|
end
|
21
22
|
|
23
|
+
def dependant_containers
|
24
|
+
dependant_container_names.each_with_object({}) do |container_name, all|
|
25
|
+
all[container_name] = stack.containers[container_name]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def startable_dependant_containers
|
30
|
+
dependant_containers.select { |_, container| container.startable? }
|
31
|
+
end
|
32
|
+
|
33
|
+
def metastore_key
|
34
|
+
@metastore_key ||= 'stacks.%s.containers.%s' % [ stack.name, name ]
|
35
|
+
end
|
36
|
+
|
37
|
+
def container_config
|
38
|
+
@container_config ||= stack.container_configs[container_name] || Hashie::Mash.new({})
|
39
|
+
end
|
40
|
+
|
22
41
|
def id
|
23
|
-
exists? ? info.id[0...12] :
|
42
|
+
exists? ? info.id[0...12] : nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def hostname
|
46
|
+
container_config.fetch('hostname', name)
|
24
47
|
end
|
25
48
|
|
26
49
|
def image_name
|
27
|
-
'%s:%s' % [
|
50
|
+
'%s:%s' % [ image_repo, image_version.to_s ] if image_repo && image_version
|
51
|
+
end
|
52
|
+
|
53
|
+
def image_repo # FIXME
|
54
|
+
if pseudo?
|
55
|
+
pseudo_full_name
|
56
|
+
elsif !buildable?
|
57
|
+
container_config.docker_image.split(':')[0]
|
58
|
+
else
|
59
|
+
full_name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def image_version
|
64
|
+
if buildable?
|
65
|
+
version
|
66
|
+
elsif !container_config.docker_image.nil?
|
67
|
+
container_config.docker_image.split(':')[1]
|
68
|
+
else
|
69
|
+
fail Errors::ContainerInvalid, 'Cannot determine image version'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def full_name
|
74
|
+
'%s_%s' % [ stack.name, name ]
|
75
|
+
end
|
76
|
+
|
77
|
+
def pseudo_full_name
|
78
|
+
'%s_%s' % [ stack.name, pseudo_name ]
|
28
79
|
end
|
29
80
|
|
30
81
|
def image
|
@@ -38,49 +89,46 @@ module Percheron
|
|
38
89
|
end
|
39
90
|
|
40
91
|
def built_version
|
41
|
-
Semantic::Version.new(
|
92
|
+
Semantic::Version.new(built_image_version)
|
42
93
|
end
|
43
94
|
|
44
95
|
def dockerfile
|
45
|
-
|
96
|
+
return nil unless container_config.dockerfile
|
97
|
+
Pathname.new(File.expand_path(container_config.dockerfile, config_file_base_path))
|
46
98
|
end
|
47
99
|
|
48
100
|
def exposed_ports
|
49
|
-
ports.
|
50
|
-
all[p.split(':')[1]] = {}
|
51
|
-
all
|
52
|
-
end
|
101
|
+
ports.each_with_object({}) { |p, all| all[p.split(':')[1]] = {} }
|
53
102
|
end
|
54
103
|
|
55
104
|
def links
|
56
|
-
|
57
|
-
'%s:%s' % [
|
105
|
+
startable_dependant_containers.map do |_, container|
|
106
|
+
'%s:%s' % [ container.full_name, container.name ]
|
58
107
|
end
|
59
108
|
end
|
60
109
|
|
61
110
|
def docker_container
|
62
|
-
Docker::Container.get(
|
111
|
+
Docker::Container.get(full_name)
|
63
112
|
rescue Docker::Error::NotFoundError, Excon::Errors::SocketError
|
64
113
|
NullContainer.new
|
65
114
|
end
|
66
115
|
|
67
|
-
def
|
68
|
-
|
69
|
-
all[container_name] = stack.filter_containers[container_name]
|
70
|
-
all
|
71
|
-
end
|
116
|
+
def labels
|
117
|
+
{ version: version.to_s, created_by: "Percheron #{Percheron::VERSION}" }
|
72
118
|
end
|
73
119
|
|
74
|
-
def
|
75
|
-
|
120
|
+
def update_dockerfile_md5!
|
121
|
+
md5 = current_dockerfile_md5
|
122
|
+
$logger.info "Setting MD5 for '#{name}' container to #{md5}"
|
123
|
+
$metastore.set("#{metastore_key}.dockerfile_md5", md5)
|
76
124
|
end
|
77
125
|
|
78
|
-
def
|
79
|
-
|
126
|
+
def dockerfile_md5s_match?
|
127
|
+
dockerfile_md5 == current_dockerfile_md5
|
80
128
|
end
|
81
129
|
|
82
|
-
def
|
83
|
-
|
130
|
+
def versions_match?
|
131
|
+
version == built_version
|
84
132
|
end
|
85
133
|
|
86
134
|
def running?
|
@@ -92,32 +140,41 @@ module Percheron
|
|
92
140
|
end
|
93
141
|
|
94
142
|
def image_exists?
|
95
|
-
|
143
|
+
image.nil? ? false : true
|
96
144
|
end
|
97
145
|
|
98
|
-
def
|
99
|
-
!
|
146
|
+
def buildable?
|
147
|
+
!dockerfile.nil? && container_config.docker_image.nil?
|
100
148
|
end
|
101
149
|
|
102
150
|
def valid?
|
103
151
|
Validators::Container.new(self).valid?
|
104
152
|
end
|
105
153
|
|
154
|
+
alias_method :startable?, :startable
|
155
|
+
|
106
156
|
private
|
107
157
|
|
108
|
-
attr_reader :
|
158
|
+
attr_reader :stack, :container_name
|
159
|
+
|
160
|
+
def current_dockerfile_md5
|
161
|
+
dockerfile ? Digest::MD5.file(dockerfile).hexdigest : Digest::MD5.hexdigest(image_name)
|
162
|
+
end
|
163
|
+
|
164
|
+
def dockerfile_md5
|
165
|
+
$metastore.get("#{metastore_key}.dockerfile_md5") || current_dockerfile_md5
|
166
|
+
end
|
109
167
|
|
110
168
|
def built_image_version
|
111
|
-
info.Config.
|
169
|
+
(exists? && info.Config.Labels) ? info.Config.Labels.version : '0.0.0'
|
112
170
|
end
|
113
171
|
|
114
172
|
def info
|
115
173
|
Hashie::Mash.new(docker_container.info)
|
116
174
|
end
|
117
175
|
|
118
|
-
def
|
119
|
-
|
176
|
+
def pseudo?
|
177
|
+
!pseudo_name.nil?
|
120
178
|
end
|
121
|
-
|
122
179
|
end
|
123
180
|
end
|
@@ -2,7 +2,6 @@ module Percheron
|
|
2
2
|
module CoreExtensions
|
3
3
|
module Array
|
4
4
|
module Extras
|
5
|
-
|
6
5
|
def return
|
7
6
|
result = nil
|
8
7
|
each do |x|
|
@@ -16,12 +15,10 @@ module Percheron
|
|
16
15
|
end
|
17
16
|
|
18
17
|
def to_hash_by_key(key_attr)
|
19
|
-
|
18
|
+
each_with_object({}) do |e, all|
|
20
19
|
all[e.send(key_attr)] = e unless all[e.send(key_attr)]
|
21
|
-
all
|
22
20
|
end
|
23
21
|
end
|
24
|
-
|
25
22
|
end
|
26
23
|
end
|
27
24
|
end
|
@@ -23,6 +23,7 @@ module Percheron
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def set_options!
|
26
|
+
Excon.defaults[:ssl_verify_peer] = config.docker.fetch('ssl_verify_peer', true)
|
26
27
|
Docker.options = docker_options
|
27
28
|
end
|
28
29
|
|
@@ -31,7 +32,10 @@ module Percheron
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def base_docker_options
|
34
|
-
{
|
35
|
+
{
|
36
|
+
connect_timeout: config.docker.connect_timeout || 5,
|
37
|
+
read_timeout: config.docker.read_timeout || 300
|
38
|
+
}
|
35
39
|
end
|
36
40
|
|
37
41
|
def extra_docker_opts
|
@@ -8,36 +8,48 @@ module Percheron
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def generate
|
11
|
-
Terminal::Table.new(
|
12
|
-
title: stack.name,
|
13
|
-
headings: headings,
|
14
|
-
rows: rows
|
15
|
-
)
|
11
|
+
Terminal::Table.new(title: title, headings: headings, rows: rows)
|
16
12
|
end
|
17
13
|
|
18
14
|
private
|
19
15
|
|
20
16
|
attr_reader :stack
|
21
17
|
|
18
|
+
def title
|
19
|
+
stack.name
|
20
|
+
end
|
21
|
+
|
22
22
|
def headings
|
23
23
|
[
|
24
|
-
'Container
|
24
|
+
'Container',
|
25
25
|
'ID',
|
26
|
-
'
|
27
|
-
'
|
26
|
+
'Running?',
|
27
|
+
'Ports',
|
28
|
+
'Volumes',
|
29
|
+
'Version'
|
28
30
|
]
|
29
31
|
end
|
30
32
|
|
31
33
|
def rows
|
32
|
-
stack.
|
34
|
+
stack.containers.map do |_, container|
|
33
35
|
[
|
34
|
-
|
36
|
+
container.name,
|
35
37
|
container.id,
|
36
|
-
container
|
37
|
-
container.
|
38
|
+
startable(container),
|
39
|
+
container.ports.join(', '),
|
40
|
+
container.volumes.join(', '),
|
41
|
+
(container.built_version == '0.0.0') ? '' : container.built_version
|
38
42
|
]
|
39
43
|
end
|
40
44
|
end
|
45
|
+
|
46
|
+
def startable(container)
|
47
|
+
if container.startable?
|
48
|
+
container.running? ? 'yes' : '-'
|
49
|
+
else
|
50
|
+
'n/a'
|
51
|
+
end
|
52
|
+
end
|
41
53
|
end
|
42
54
|
end
|
43
55
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
$logger = Logger.new(STDOUT)
|
4
|
+
|
5
|
+
logger_level = Logger::INFO
|
6
|
+
logger_level = Logger::WARN if ENV['QUIET'] == 'true'
|
7
|
+
|
8
|
+
if ENV['DEBUG'] == 'true' || ENV['DOCKER_DEBUG'] == 'true'
|
9
|
+
begin
|
10
|
+
require 'pry-byebug'
|
11
|
+
require 'awesome_print'
|
12
|
+
rescue LoadError
|
13
|
+
$logger.warn 'Debugging gems are not installed'
|
14
|
+
end
|
15
|
+
|
16
|
+
logger_level = Logger::DEBUG
|
17
|
+
|
18
|
+
Docker.logger = $logger if ENV['DOCKER_DEBUG'] == 'true'
|
19
|
+
end
|
20
|
+
|
21
|
+
$logger.level = logger_level
|
@@ -0,0 +1 @@
|
|
1
|
+
$metastore = Metastore::Cabinet.new(File.join(ENV['HOME'], '.percheron', 'metastore.yaml'))
|
data/lib/percheron/oh_dear.rb
CHANGED
@@ -6,7 +6,16 @@ module Percheron
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def generate
|
9
|
-
|
9
|
+
template
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
attr_reader :exception
|
15
|
+
|
16
|
+
# rubocop:disable Metrics/MethodLength
|
17
|
+
def template
|
18
|
+
<<-EOS
|
10
19
|
|
11
20
|
OH DEAR, we are terribly sorry.. something unexpected occurred :(
|
12
21
|
|
@@ -25,14 +34,13 @@ Trace
|
|
25
34
|
|
26
35
|
--snip--
|
27
36
|
|
28
|
-
Please copy the detail between the --snip--'s above and raise a ticket
|
37
|
+
Please copy the detail between the --snip--'s above and raise a ticket please :)
|
29
38
|
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
39
|
+
https://github.com/ashmckenzie/percheron/issues/new?labels=bug
|
34
40
|
|
35
|
-
|
41
|
+
EOS
|
42
|
+
end
|
43
|
+
# rubocop:enable Metrics/MethodLength
|
36
44
|
|
37
45
|
def exception_message
|
38
46
|
exception.inspect
|
data/lib/percheron/stack.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
require 'highline/import'
|
2
|
+
|
1
3
|
module Percheron
|
2
4
|
class Stack
|
3
|
-
|
4
5
|
extend Forwardable
|
5
6
|
|
6
7
|
def_delegators :stack_config, :name, :description
|
@@ -8,73 +9,84 @@ module Percheron
|
|
8
9
|
def initialize(config, stack_name)
|
9
10
|
@config = config
|
10
11
|
@stack_name = stack_name
|
11
|
-
valid?
|
12
12
|
self
|
13
13
|
end
|
14
14
|
|
15
|
-
def self.get(config,
|
16
|
-
|
15
|
+
def self.get(config, name = nil)
|
16
|
+
stacks = name.nil? ? config.stacks : { name => config.stacks[name] }
|
17
|
+
stacks.each_with_object({}) do |stack_config, all|
|
18
|
+
stack_name, _ = stack_config
|
17
19
|
stack = new(config, stack_name)
|
18
|
-
stack
|
19
|
-
else
|
20
|
-
all = {}
|
21
|
-
config.stacks.each do |stack_name, _|
|
22
|
-
stack = new(config, stack_name)
|
23
|
-
all[stack.name] = stack
|
24
|
-
end
|
25
|
-
all
|
20
|
+
all[stack.name] = stack
|
26
21
|
end
|
27
22
|
end
|
28
23
|
|
29
24
|
def container_configs
|
30
|
-
stack_config.containers
|
25
|
+
stack_config.containers
|
31
26
|
end
|
32
27
|
|
33
|
-
|
34
|
-
def filter_containers(container_names=[])
|
28
|
+
def containers(container_names = [])
|
35
29
|
container_names = !container_names.empty? ? container_names : filter_container_names
|
36
|
-
container_names.
|
37
|
-
all[container_name] =
|
38
|
-
all
|
30
|
+
container_names.each_with_object({}) do |container_name, all|
|
31
|
+
all[container_name] = container_from_name(container_name)
|
39
32
|
end
|
40
33
|
end
|
41
34
|
|
35
|
+
def shell!(container_name, shell: Percheron::Actions::Shell::DEFAULT_SHELL)
|
36
|
+
Actions::Shell.new(container_from_name(container_name), shell: shell).execute!
|
37
|
+
end
|
38
|
+
|
39
|
+
def logs!(container_name, follow: false)
|
40
|
+
Actions::Logs.new(container_from_name(container_name), follow: follow).execute!
|
41
|
+
end
|
42
|
+
|
42
43
|
def stop!(container_names: [])
|
43
|
-
|
44
|
-
exec_on_dependant_containers_for(container_names) { |container| Actions::Stop.new(container).execute! }
|
44
|
+
execute!(Actions::Stop, filter_container_names(container_names).reverse)
|
45
45
|
end
|
46
46
|
|
47
|
+
# FIXME: bug when non-startable container specified, all containers started
|
47
48
|
def start!(container_names: [])
|
48
49
|
container_names = dependant_containers_for(container_names)
|
49
|
-
exec_on_dependant_containers_for(container_names)
|
50
|
+
exec_on_dependant_containers_for(container_names) do |container|
|
51
|
+
dependant_containers = container.startable_dependant_containers.values
|
52
|
+
Actions::Start.new(container, dependant_containers: dependant_containers).execute!
|
53
|
+
end
|
54
|
+
nil
|
50
55
|
end
|
51
56
|
|
52
57
|
def restart!(container_names: [])
|
53
|
-
|
54
|
-
exec_on_dependant_containers_for(container_names) { |container| Actions::Restart.new(container).execute! }
|
58
|
+
execute!(Actions::Restart, filter_container_names(container_names))
|
55
59
|
end
|
56
60
|
|
57
|
-
def
|
61
|
+
def build!(container_names: [])
|
58
62
|
container_names = dependant_containers_for(container_names)
|
59
|
-
exec_on_dependant_containers_for(container_names)
|
63
|
+
exec_on_dependant_containers_for(container_names) do |container|
|
64
|
+
Actions::Build.new(container).execute!
|
65
|
+
end
|
66
|
+
nil
|
60
67
|
end
|
61
68
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
# FIXME: make this suck less
|
66
|
-
while true
|
67
|
-
current = deps = containers_affected(current).uniq
|
68
|
-
break if deps.empty?
|
69
|
-
container_names_final += deps
|
70
|
-
end
|
69
|
+
def create!(container_names: [], start: false)
|
70
|
+
execute!(Actions::Create, dependant_containers_for(container_names), start: start)
|
71
|
+
end
|
71
72
|
|
72
|
-
|
73
|
+
def recreate!(container_names: [], start: false)
|
74
|
+
execute!(Actions::Recreate, filter_container_names(container_names), start: start)
|
73
75
|
end
|
74
76
|
|
75
77
|
def purge!(container_names: [])
|
76
|
-
|
77
|
-
|
78
|
+
execute!(Actions::Purge, filter_container_names(container_names).reverse)
|
79
|
+
end
|
80
|
+
|
81
|
+
def execute!(klass, container_names, args=nil)
|
82
|
+
exec_on_dependant_containers_for(container_names) do |container|
|
83
|
+
if args
|
84
|
+
klass.new(container, args).execute!
|
85
|
+
else
|
86
|
+
klass.new(container).execute!
|
87
|
+
end
|
88
|
+
end
|
89
|
+
nil
|
78
90
|
end
|
79
91
|
|
80
92
|
def valid?
|
@@ -89,59 +101,52 @@ module Percheron
|
|
89
101
|
@stack_config ||= (config.stacks[stack_name] || Hashie::Mash.new({}))
|
90
102
|
end
|
91
103
|
|
92
|
-
|
93
|
-
|
94
|
-
|
104
|
+
# FIXME: yuck
|
105
|
+
# rubocop:disable Style/Next
|
106
|
+
def filter_container_names(container_names = [])
|
107
|
+
stack_config.fetch('containers', {}).map do |container_name, container_config|
|
108
|
+
if container_names.empty? || container_names.include?(container_name) ||
|
109
|
+
(container_config.pseudo_name &&
|
110
|
+
container_names.include?(container_config.pseudo_name))
|
95
111
|
container_config.name
|
96
112
|
end
|
97
113
|
end.compact
|
98
114
|
end
|
99
|
-
|
100
|
-
def exec_on_containers(container_names)
|
101
|
-
filter_containers(container_names).each { |_, container| yield(container) }
|
102
|
-
end
|
115
|
+
# rubocop:enable Style/Next
|
103
116
|
|
104
117
|
def exec_on_dependant_containers_for(container_names)
|
105
|
-
serial_processor(container_names) do |container|
|
106
|
-
$logger.info '' if yield(container)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def serial_processor(container_names)
|
111
118
|
exec_on_containers(container_names) do |container|
|
119
|
+
$logger.debug "Processing '#{container.name}' container"
|
112
120
|
yield(container)
|
113
|
-
container_names.delete(container.
|
121
|
+
container_names.delete(container.full_name)
|
114
122
|
end
|
115
123
|
end
|
116
124
|
|
117
|
-
def
|
118
|
-
|
119
|
-
container_names.each do |container_name|
|
120
|
-
filter_containers.each do |_, container|
|
121
|
-
deps << container.name if container.dependant_container_names.include?(container_name)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
deps
|
125
|
-
end
|
126
|
-
|
127
|
-
def containers_and_their_dependants(container_names)
|
128
|
-
all_containers = filter_containers
|
129
|
-
container_names.inject({}) do |all, container_name|
|
130
|
-
all[container_name] = all_containers[container_name].dependant_container_names
|
131
|
-
all
|
132
|
-
end
|
125
|
+
def exec_on_containers(container_names)
|
126
|
+
containers(container_names).each { |_, container| yield(container) }
|
133
127
|
end
|
134
128
|
|
135
129
|
def dependant_containers_for(container_names)
|
130
|
+
list = []
|
136
131
|
container_names = filter_container_names(container_names)
|
132
|
+
containers = all_containers_and_dependants(container_names)
|
133
|
+
containers.each do |container_name, dependant_container_names|
|
134
|
+
list += dependant_container_names unless dependant_container_names.empty?
|
135
|
+
list << container_name
|
136
|
+
end
|
137
|
+
list.uniq
|
138
|
+
end
|
137
139
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
140
|
+
def all_containers_and_dependants(container_names)
|
141
|
+
all_containers = containers
|
142
|
+
containers = container_names.each_with_object({}) do |container_name, all|
|
143
|
+
all[container_name] = all_containers[container_name].dependant_container_names
|
142
144
|
end
|
143
|
-
|
145
|
+
containers.sort { |x, y| x[1].length <=> y[1].length } # FIXME
|
144
146
|
end
|
145
147
|
|
148
|
+
def container_from_name(container_name)
|
149
|
+
Container.new(self, container_name, config.file_base_path)
|
150
|
+
end
|
146
151
|
end
|
147
152
|
end
|
@@ -10,7 +10,7 @@ module Percheron
|
|
10
10
|
message = rules.return { |rule| send(rule) }
|
11
11
|
|
12
12
|
if message
|
13
|
-
|
13
|
+
fail Errors::ContainerInvalid, formatted_message(message)
|
14
14
|
else
|
15
15
|
true
|
16
16
|
end
|
@@ -24,32 +24,52 @@ module Percheron
|
|
24
24
|
if container.name
|
25
25
|
"Container config for '%s' is invalid: %s" % [ container.name, message ]
|
26
26
|
else
|
27
|
-
"Container config is invalid:
|
27
|
+
"Container config is invalid: #{message}"
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
def rules
|
32
32
|
[
|
33
33
|
:validate_name,
|
34
|
-
:
|
35
|
-
:validate_dockerfile
|
34
|
+
:validate_dockerfile_and_image_name,
|
35
|
+
:validate_dockerfile,
|
36
|
+
:validate_image,
|
37
|
+
:validate_version
|
36
38
|
]
|
37
39
|
end
|
38
40
|
|
41
|
+
# rubocop:disable Style/GuardClause
|
39
42
|
def validate_name
|
40
|
-
|
43
|
+
if container.name.nil? || !container.name.to_s.match(/[\w]{3,}/)
|
44
|
+
'Container name is invalid'
|
45
|
+
end
|
41
46
|
end
|
42
47
|
|
43
|
-
def
|
44
|
-
container.
|
45
|
-
|
46
|
-
|
47
|
-
'Version is invalid'
|
48
|
+
def validate_dockerfile_and_image_name
|
49
|
+
if container.dockerfile.nil? && container.docker_image.nil?
|
50
|
+
'Container Dockerfile OR image name not provided'
|
51
|
+
end
|
48
52
|
end
|
49
53
|
|
50
54
|
def validate_dockerfile
|
51
|
-
|
55
|
+
if !container.dockerfile.nil? && !File.exist?(container.dockerfile)
|
56
|
+
'Container Dockerfile is invalid'
|
57
|
+
end
|
52
58
|
end
|
59
|
+
|
60
|
+
def validate_image
|
61
|
+
if !container.docker_image.nil? && !container.docker_image.match(/^.+:.+$/)
|
62
|
+
'Container Docker image is invalid'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
# rubocop:enable Style/GuardClause
|
66
|
+
|
67
|
+
def validate_version
|
68
|
+
container.version ? nil : fail(ArgumentError)
|
69
|
+
rescue ArgumentError
|
70
|
+
'Container version is invalid'
|
71
|
+
end
|
72
|
+
|
53
73
|
end
|
54
74
|
end
|
55
75
|
end
|