percheron 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +4 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +31 -0
  5. data/.travis.yml +4 -1
  6. data/Guardfile +3 -3
  7. data/README.md +19 -3
  8. data/Rakefile +24 -1
  9. data/bin/percheron +2 -20
  10. data/lib/percheron/actions/base.rb +0 -39
  11. data/lib/percheron/actions/build.rb +9 -7
  12. data/lib/percheron/actions/create.rb +64 -38
  13. data/lib/percheron/actions/exec.rb +40 -8
  14. data/lib/percheron/actions/exec_local.rb +4 -4
  15. data/lib/percheron/actions/logs.rb +44 -0
  16. data/lib/percheron/actions/purge.rb +15 -4
  17. data/lib/percheron/actions/recreate.rb +15 -65
  18. data/lib/percheron/actions/restart.rb +2 -1
  19. data/lib/percheron/actions/shell.rb +27 -0
  20. data/lib/percheron/actions/start.rb +10 -7
  21. data/lib/percheron/actions.rb +2 -1
  22. data/lib/percheron/commands/abstract.rb +20 -8
  23. data/lib/percheron/commands/build.rb +13 -0
  24. data/lib/percheron/commands/console.rb +53 -0
  25. data/lib/percheron/commands/create.rb +3 -3
  26. data/lib/percheron/commands/list.rb +7 -3
  27. data/lib/percheron/commands/logs.rb +16 -0
  28. data/lib/percheron/commands/main.rb +5 -2
  29. data/lib/percheron/commands/purge.rb +2 -2
  30. data/lib/percheron/commands/recreate.rb +3 -11
  31. data/lib/percheron/commands/restart.rb +2 -2
  32. data/lib/percheron/commands/shell.rb +16 -0
  33. data/lib/percheron/commands/start.rb +2 -2
  34. data/lib/percheron/commands/stop.rb +2 -2
  35. data/lib/percheron/commands.rb +3 -0
  36. data/lib/percheron/config.rb +64 -3
  37. data/lib/percheron/config_delegator.rb +0 -1
  38. data/lib/percheron/container.rb +95 -38
  39. data/lib/percheron/core_extensions.rb +1 -4
  40. data/lib/percheron/docker_connection.rb +5 -1
  41. data/lib/percheron/formatters/stack/table.rb +24 -12
  42. data/lib/percheron/logger.rb +21 -0
  43. data/lib/percheron/metastore.rb +1 -0
  44. data/lib/percheron/null_stack.rb +5 -0
  45. data/lib/percheron/oh_dear.rb +15 -7
  46. data/lib/percheron/stack.rb +77 -72
  47. data/lib/percheron/validators/config.rb +1 -1
  48. data/lib/percheron/validators/container.rb +31 -11
  49. data/lib/percheron/validators/stack.rb +3 -5
  50. data/lib/percheron/version.rb +1 -1
  51. data/lib/percheron.rb +2 -0
  52. data/percheron.gemspec +4 -1
  53. metadata +54 -4
  54. data/assets/percheron.png +0 -0
  55. data/lib/percheron/actions/rename.rb +0 -65
@@ -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
- 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
14
+ attr_reader :config_file_base_path
11
15
 
12
- alias_method :auto_recreate?, :auto_recreate
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
- valid?
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] : 'N/A'
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' % [ name, version.to_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(exists? ? built_image_version : '0.0.0')
92
+ Semantic::Version.new(built_image_version)
42
93
  end
43
94
 
44
95
  def dockerfile
45
- container_config.dockerfile ? Pathname.new(File.expand_path(container_config.dockerfile, config.file_base_path)): nil
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.inject({}) do |all, p|
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
- dependant_container_names.map do |container_name|
57
- '%s:%s' % [ container_name, container_name ]
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(name)
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 dependant_containers
68
- dependant_container_names.inject({}) do |all, container_name|
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 metastore_key
75
- @metastore_key ||= 'stacks.%s.containers.%s' % [ stack.name, name ]
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 current_dockerfile_md5
79
- Digest::MD5.file(dockerfile).hexdigest
126
+ def dockerfile_md5s_match?
127
+ dockerfile_md5 == current_dockerfile_md5
80
128
  end
81
129
 
82
- def dockerfile_md5
83
- $metastore.get("#{metastore_key}.dockerfile_md5")
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
- !!image
143
+ image.nil? ? false : true
96
144
  end
97
145
 
98
- def dependant_containers?
99
- !dependant_container_names.empty?
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 :config, :stack, :container_name
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.Image.split(':')[1]
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 container_config
119
- @container_config ||= stack.container_configs[container_name] || Hashie::Mash.new({})
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
- inject({}) do |all, e|
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
- { connect_timeout: config.docker.timeout }
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 name',
24
+ 'Container',
25
25
  'ID',
26
- 'Version',
27
- 'Running?'
26
+ 'Running?',
27
+ 'Ports',
28
+ 'Volumes',
29
+ 'Version'
28
30
  ]
29
31
  end
30
32
 
31
33
  def rows
32
- stack.filter_containers.map do |container_name, container|
34
+ stack.containers.map do |_, container|
33
35
  [
34
- container_name,
36
+ container.name,
35
37
  container.id,
36
- container.built_version,
37
- container.running?
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'))
@@ -0,0 +1,5 @@
1
+ module Percheron
2
+ NullStack = Naught.build do |config|
3
+ config.mimic Stack
4
+ end
5
+ end
@@ -6,7 +6,16 @@ module Percheron
6
6
  end
7
7
 
8
8
  def generate
9
- <<-EOS
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 - https://github.com/ashmckenzie/percheron/issues/new?labels=bug
37
+ Please copy the detail between the --snip--'s above and raise a ticket please :)
29
38
 
30
- EOS
31
- end
32
-
33
- private
39
+ https://github.com/ashmckenzie/percheron/issues/new?labels=bug
34
40
 
35
- attr_reader :exception
41
+ EOS
42
+ end
43
+ # rubocop:enable Metrics/MethodLength
36
44
 
37
45
  def exception_message
38
46
  exception.inspect
@@ -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, stack_name=nil)
16
- if stack_name
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 ? { stack.name => 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.to_hash_by_key(:name)
25
+ stack_config.containers
31
26
  end
32
27
 
33
- # FIXME: YUCK
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.inject({}) do |all, container_name|
37
- all[container_name] = Container.new(config, self, 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
- container_names = dependant_containers_for(container_names).reverse
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) { |container| Actions::Start.new(container, dependant_containers: container.dependant_containers.values).execute! }
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
- container_names = dependant_containers_for(container_names)
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 create!(container_names: [])
61
+ def build!(container_names: [])
58
62
  container_names = dependant_containers_for(container_names)
59
- exec_on_dependant_containers_for(container_names) { |container| Actions::Create.new(container).execute! }
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 recreate!(container_names: [], force_recreate: false, delete: false)
63
- current = container_names_final = filter_container_names(container_names)
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
- exec_on_dependant_containers_for(container_names_final.uniq) { |container| Actions::Recreate.new(container, force_recreate: force_recreate, delete: delete).execute! }
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
- container_names = filter_container_names(container_names)
77
- exec_on_dependant_containers_for(container_names) { |container| Actions::Purge.new(container).execute! }
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
- def filter_container_names(container_names=[])
93
- stack_config.containers.map do |container_config|
94
- if container_names.empty? || container_names.include?(container_config.name)
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.name)
121
+ container_names.delete(container.full_name)
114
122
  end
115
123
  end
116
124
 
117
- def containers_affected(container_names)
118
- deps = []
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
- wip_list = []
139
- containers_and_their_dependants(container_names).each do |container_name, dependant_container_names|
140
- wip_list += dependant_container_names unless dependant_container_names.empty?
141
- wip_list << container_name
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
- wip_list.uniq
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
- raise Errors::ConfigFileInvalid.new(message)
13
+ fail Errors::ConfigFileInvalid, message
14
14
  else
15
15
  true
16
16
  end
@@ -10,7 +10,7 @@ module Percheron
10
10
  message = rules.return { |rule| send(rule) }
11
11
 
12
12
  if message
13
- raise Errors::ContainerInvalid.new(formatted_message(message))
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: %s" % [ message ]
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
- :validate_version,
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
- 'Name is invalid' if container.name.nil? || !container.name.to_s.match(/[\w\d]{3,}/)
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 validate_version
44
- container.version
45
- nil
46
- rescue ArgumentError
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
- 'Dockerfile is invalid' if container.dockerfile.nil? || !File.exist?(container.dockerfile)
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