cm 0.1.6 → 0.1.8
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/.gitignore +3 -0
- data/.gitmodules +3 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +34 -24
- data/VERSION +1 -1
- data/cm.gemspec +18 -10
- data/lib/CM/batch/celluloid.rb +22 -2
- data/lib/CM/resource/AWS.rb +183 -7
- data/lib/CM/resource/BOSH.rb +2 -2
- data/lib/CM/resource/concourse.rb +2 -2
- data/lib/CM/resource/{keypair.rb → plan.rb} +1 -19
- data/lib/CM/resource/variables.rb +3 -11
- data/lib/CM/sequence/default.rb +14 -4
- data/lib/core/plugin/batch.rb +32 -2
- data/lib/core/plugin/cm_action.rb +0 -1
- data/lib/core/plugin/docker_resource.rb +115 -74
- data/lib/core/plugin/plan.rb +13 -15
- data/lib/core/plugin/plan_action.rb +12 -0
- data/lib/core/plugin/resource.rb +85 -8
- data/lib/core/plugin/sequence.rb +29 -1
- data/lib/nucleon/action/resource/run.rb +7 -10
- data/locales/en.yml +40 -1
- data/toolbox/LICENSE.txt +674 -0
- data/toolbox/README.txt +2 -0
- data/toolbox/lib/shell/LICENSE.txt +674 -0
- metadata +49 -19
- data/lib/CM/resource/MicroBOSH.rb +0 -46
data/lib/CM/resource/BOSH.rb
CHANGED
@@ -26,7 +26,7 @@ class BOSH < Nucleon.plugin_class(:CM, :docker_resource)
|
|
26
26
|
|
27
27
|
def operation_deploy
|
28
28
|
super do
|
29
|
-
|
29
|
+
data = {}
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -34,7 +34,7 @@ class BOSH < Nucleon.plugin_class(:CM, :docker_resource)
|
|
34
34
|
|
35
35
|
def operation_destroy
|
36
36
|
super do
|
37
|
-
|
37
|
+
data = {}
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -26,7 +26,7 @@ class Concourse < Nucleon.plugin_class(:CM, :docker_resource)
|
|
26
26
|
|
27
27
|
def operation_deploy
|
28
28
|
super do
|
29
|
-
|
29
|
+
data = {}
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -34,7 +34,7 @@ class Concourse < Nucleon.plugin_class(:CM, :docker_resource)
|
|
34
34
|
|
35
35
|
def operation_destroy
|
36
36
|
super do
|
37
|
-
|
37
|
+
data = {}
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
module CM
|
3
3
|
module Resource
|
4
|
-
class
|
4
|
+
class Plan < Nucleon.plugin_class(:CM, :resource)
|
5
5
|
|
6
6
|
#-----------------------------------------------------------------------------
|
7
7
|
# Plugin interface
|
@@ -14,30 +14,12 @@ class Keypair < Nucleon.plugin_class(:CM, :docker_resource)
|
|
14
14
|
#-----------------------------------------------------------------------------
|
15
15
|
# Checks
|
16
16
|
|
17
|
-
def initialized?(options = {})
|
18
|
-
true
|
19
|
-
end
|
20
|
-
|
21
17
|
#-----------------------------------------------------------------------------
|
22
18
|
# Property accessors / modifiers
|
23
19
|
|
24
20
|
#-----------------------------------------------------------------------------
|
25
21
|
# Operations
|
26
22
|
|
27
|
-
def operation_deploy
|
28
|
-
super do
|
29
|
-
success = true
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
#---
|
34
|
-
|
35
|
-
def operation_destroy
|
36
|
-
super do
|
37
|
-
success = true
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
23
|
#-----------------------------------------------------------------------------
|
42
24
|
# Utilities
|
43
25
|
|
@@ -20,17 +20,9 @@ class Variables < Nucleon.plugin_class(:CM, :resource)
|
|
20
20
|
#-----------------------------------------------------------------------------
|
21
21
|
# Operations
|
22
22
|
|
23
|
-
def
|
24
|
-
super do
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
#---
|
30
|
-
|
31
|
-
def operation_destroy
|
32
|
-
super do
|
33
|
-
success = true
|
23
|
+
def create_resource
|
24
|
+
super do |data|
|
25
|
+
info('create_variables', { :id => id })
|
34
26
|
end
|
35
27
|
end
|
36
28
|
|
data/lib/CM/sequence/default.rb
CHANGED
@@ -23,8 +23,13 @@ class Default < Nucleon.plugin_class(:CM, :sequence)
|
|
23
23
|
def forward(operation)
|
24
24
|
super do |success|
|
25
25
|
resources.each do |resource|
|
26
|
-
|
27
|
-
|
26
|
+
resource.execute(operation)
|
27
|
+
success = false unless resource.status == code.success
|
28
|
+
|
29
|
+
myself.quit = resource.quit ||
|
30
|
+
(((resource.plugin_type == :batch && !Nucleon.parallel?) ||
|
31
|
+
resource.plugin_provider != :variables) && plan.trap && plan.step)
|
32
|
+
break if quit
|
28
33
|
end
|
29
34
|
success
|
30
35
|
end
|
@@ -35,8 +40,13 @@ class Default < Nucleon.plugin_class(:CM, :sequence)
|
|
35
40
|
def reverse(operation)
|
36
41
|
super do |success|
|
37
42
|
resources.reverse.each do |resource|
|
38
|
-
|
39
|
-
|
43
|
+
resource.execute(operation)
|
44
|
+
success = false unless resource.status == code.success
|
45
|
+
|
46
|
+
myself.quit = resource.quit ||
|
47
|
+
(((resource.plugin_type == :batch && !Nucleon.parallel?) ||
|
48
|
+
resource.plugin_provider != :variables) && plan.trap && plan.step)
|
49
|
+
break if quit
|
40
50
|
end
|
41
51
|
success
|
42
52
|
end
|
data/lib/core/plugin/batch.rb
CHANGED
@@ -3,12 +3,18 @@ module CM
|
|
3
3
|
module Plugin
|
4
4
|
class Batch < Nucleon.plugin_class(:nucleon, :base)
|
5
5
|
|
6
|
+
def self.register_ids
|
7
|
+
[ :id ]
|
8
|
+
end
|
9
|
+
|
6
10
|
#-----------------------------------------------------------------------------
|
7
11
|
# Plugin interface
|
8
12
|
|
9
13
|
def normalize(reload)
|
10
14
|
super
|
11
15
|
|
16
|
+
codes :batch_failed
|
17
|
+
|
12
18
|
@plan = delete(:plan, nil) unless reload
|
13
19
|
|
14
20
|
init_resources
|
@@ -54,11 +60,29 @@ class Batch < Nucleon.plugin_class(:nucleon, :base)
|
|
54
60
|
init_resources
|
55
61
|
end
|
56
62
|
|
63
|
+
#---
|
64
|
+
|
65
|
+
def id
|
66
|
+
get(:id).to_sym
|
67
|
+
end
|
68
|
+
|
69
|
+
#---
|
70
|
+
|
71
|
+
def quit
|
72
|
+
@quit
|
73
|
+
end
|
74
|
+
|
75
|
+
def quit=quit
|
76
|
+
@quit = quit
|
77
|
+
end
|
78
|
+
|
57
79
|
#-----------------------------------------------------------------------------
|
58
80
|
# Operations
|
59
81
|
|
60
82
|
def execute(operation)
|
61
83
|
if initialized?
|
84
|
+
myself.status = code.success
|
85
|
+
|
62
86
|
if Nucleon.parallel?
|
63
87
|
success = execute_parallel(operation)
|
64
88
|
else
|
@@ -67,6 +91,7 @@ class Batch < Nucleon.plugin_class(:nucleon, :base)
|
|
67
91
|
else
|
68
92
|
success = false
|
69
93
|
end
|
94
|
+
myself.status = code.batch_failed unless success
|
70
95
|
success
|
71
96
|
end
|
72
97
|
|
@@ -82,8 +107,13 @@ class Batch < Nucleon.plugin_class(:nucleon, :base)
|
|
82
107
|
def execute_sequence(operation)
|
83
108
|
success = true
|
84
109
|
resources.each do |resource|
|
85
|
-
|
86
|
-
|
110
|
+
resource.execute(operation)
|
111
|
+
success = false unless resource.status == code.success
|
112
|
+
|
113
|
+
myself.quit = resource.quit ||
|
114
|
+
((resource.plugin_type != :sequence || resource.plugin_provider != :variables) &&
|
115
|
+
plan.trap && plan.step)
|
116
|
+
break if quit
|
87
117
|
end
|
88
118
|
success
|
89
119
|
end
|
@@ -7,6 +7,13 @@ module CM
|
|
7
7
|
module Plugin
|
8
8
|
class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
9
9
|
|
10
|
+
#-----------------------------------------------------------------------------
|
11
|
+
|
12
|
+
def self.options(action)
|
13
|
+
action.register_bool :docker, true, 'cm.action.docker_resource.options.docker'
|
14
|
+
action.register_bool :keep_alive, false, 'cm.action.docker_resource.options.keep_alive'
|
15
|
+
end
|
16
|
+
|
10
17
|
#-----------------------------------------------------------------------------
|
11
18
|
# Plugin interface
|
12
19
|
|
@@ -28,13 +35,18 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
28
35
|
Docker.url = "#{settings[:docker_protocol]}://#{settings[:docker_host]}:#{settings[:docker_port]}"
|
29
36
|
end
|
30
37
|
|
38
|
+
Docker.options[:write_timeout] = timeout
|
39
|
+
Excon.defaults[:write_timeout] = timeout
|
40
|
+
Docker.options[:read_timeout] = timeout
|
41
|
+
Excon.defaults[:read_timeout] = timeout
|
42
|
+
|
31
43
|
yield if block_given?
|
32
44
|
end
|
33
45
|
|
34
46
|
#---
|
35
47
|
|
36
48
|
def remove_plugin
|
37
|
-
destroy_container
|
49
|
+
destroy_container
|
38
50
|
end
|
39
51
|
|
40
52
|
#-----------------------------------------------------------------------------
|
@@ -50,9 +62,21 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
50
62
|
File.exist?('/.dockerinit')
|
51
63
|
end
|
52
64
|
|
65
|
+
def dockerize?
|
66
|
+
action_settings[:docker] || settings[:docker]
|
67
|
+
end
|
68
|
+
|
69
|
+
def keep_alive?
|
70
|
+
action_settings[:keep_alive] || settings[:keep_alive]
|
71
|
+
end
|
72
|
+
|
53
73
|
#-----------------------------------------------------------------------------
|
54
74
|
# Property accessors / modifiers
|
55
75
|
|
76
|
+
def docker_id
|
77
|
+
@docker_id ||= "#{id}-#{Time.now.strftime('%Y-%m-%dT%H-%M-%S%z')}"
|
78
|
+
end
|
79
|
+
|
56
80
|
def image
|
57
81
|
get(:image, 'awebb/cm').to_s
|
58
82
|
end
|
@@ -82,47 +106,79 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
82
106
|
#---
|
83
107
|
|
84
108
|
def host_input_directory
|
85
|
-
get(:host_input_directory, "/tmp/cm/input/#{
|
109
|
+
get(:host_input_directory, "/tmp/cm-data/input/#{docker_id}")
|
86
110
|
end
|
87
111
|
|
88
112
|
def input_directory
|
89
|
-
get(:input_directory,
|
113
|
+
get(:input_directory, "/opt/cm/volumes/input")
|
90
114
|
end
|
91
115
|
|
92
116
|
#---
|
93
117
|
|
94
118
|
def host_output_directory
|
95
|
-
get(:host_output_directory, "/tmp/cm/output/#{
|
119
|
+
get(:host_output_directory, "/tmp/cm-data/output/#{docker_id}")
|
96
120
|
end
|
97
121
|
|
98
122
|
def output_directory
|
99
|
-
get(:output_directory,
|
123
|
+
get(:output_directory, "/opt/cm/volumes/output")
|
100
124
|
end
|
101
125
|
|
102
126
|
#-----------------------------------------------------------------------------
|
103
127
|
# Operations
|
104
128
|
|
105
129
|
def operation_deploy
|
106
|
-
|
107
|
-
data =
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
130
|
+
operation_run(:deploy) do
|
131
|
+
data = super
|
132
|
+
yield if block_given?
|
133
|
+
data
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def operation_destroy
|
138
|
+
operation_run(:destroy) do
|
139
|
+
data = super
|
140
|
+
yield if block_given?
|
141
|
+
data
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
#---
|
146
|
+
|
147
|
+
def operation_run(operation)
|
148
|
+
data = {}
|
149
|
+
|
150
|
+
# A fork in the road!
|
151
|
+
if !dockerize? || internal?
|
152
|
+
data = yield if block_given?
|
153
|
+
|
154
|
+
if dockerize?
|
155
|
+
FileUtils.mkdir_p(output_directory)
|
156
|
+
|
157
|
+
output_config = CM.configuration(extended_config(:resource_results, {
|
158
|
+
:provider => get(:resource_output_provider, :file),
|
159
|
+
:path => "#{output_directory}/config.json"
|
160
|
+
}))
|
161
|
+
output_config.import(Nucleon::Config.ensure(data).export)
|
162
|
+
output_config.save
|
163
|
+
Nucleon.remove_plugin(output_config)
|
115
164
|
end
|
116
|
-
|
117
|
-
|
165
|
+
|
166
|
+
logger.info("Docker internal data: #{hash(data)}")
|
167
|
+
else
|
168
|
+
info('cm.resource.docker_resource.info.run_dockerized', { :image => Nucleon.yellow(image), :id => Nucleon.green(id), :op => operation, :time => Nucleon.purple(Time.now.to_s) })
|
169
|
+
logger.info("Running #{operation} operation on #{plugin_provider} resource")
|
170
|
+
|
171
|
+
data = action(plugin_provider, operation)
|
172
|
+
logger.info("Docker return data: #{hash(data)}")
|
118
173
|
end
|
174
|
+
data
|
119
175
|
end
|
120
176
|
|
121
177
|
#-----------------------------------------------------------------------------
|
122
178
|
# Docker resource operation execution
|
123
179
|
|
124
180
|
def exec(command)
|
125
|
-
data =
|
181
|
+
data = {}
|
126
182
|
|
127
183
|
create_container
|
128
184
|
|
@@ -135,35 +191,27 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
135
191
|
|
136
192
|
if results[2] == 0
|
137
193
|
if output_config = CM.configuration(extended_config(:resource_results, {
|
138
|
-
:provider => get(:resource_result_provider, :
|
139
|
-
:path => host_output_directory
|
194
|
+
:provider => get(:resource_result_provider, :file),
|
195
|
+
:path => "#{host_output_directory}/config.json"
|
140
196
|
}))
|
141
197
|
data = Nucleon::Util::Data.clone(output_config.export)
|
142
198
|
Nucleon.remove_plugin(output_config)
|
143
199
|
end
|
144
200
|
end
|
145
|
-
|
146
|
-
destroy_container
|
147
201
|
data
|
202
|
+
ensure
|
203
|
+
destroy_container
|
148
204
|
end
|
149
205
|
|
150
206
|
#---
|
151
207
|
|
152
208
|
def command(command, options = {})
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
unless command.is_a?(Nucleon::Plugin::Command)
|
157
|
-
command = Nucleon.command(Nucleon::Config.new({ :command => command }, {}, true, false).import(config), :bash)
|
158
|
-
remove_command = true
|
159
|
-
end
|
209
|
+
command = Nucleon.command(Nucleon::Config.new({ :command => command }, {}, true, false).import(options), :bash)
|
210
|
+
Nucleon.remove_plugin(command)
|
160
211
|
|
161
|
-
|
212
|
+
exec(command.to_s.strip) do |stream, message|
|
162
213
|
yield(stream, message) if block_given?
|
163
214
|
end
|
164
|
-
|
165
|
-
Nucleon.remove_plugin(command) if remove_command
|
166
|
-
data
|
167
215
|
end
|
168
216
|
|
169
217
|
#---
|
@@ -175,24 +223,21 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
175
223
|
action_settings = Nucleon::Util::Data.clean(plan.action_settings)
|
176
224
|
initialize_remote_config(action_settings)
|
177
225
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
data = command('cm', Nucleon::Util::Data.clean({
|
187
|
-
:subcommand => action_config,
|
188
|
-
:quiet => Nucleon::Util::Console.quiet
|
226
|
+
command('cm', Nucleon::Util::Data.clean({
|
227
|
+
:subcommand => extended_config(:action, {
|
228
|
+
:command => 'resource run',
|
229
|
+
:data => { :encoded => Nucleon::Util::CLI.encode(action_settings) },
|
230
|
+
:args => [ provider, operation ]
|
231
|
+
}),
|
232
|
+
:quiet => Nucleon::Util::Console.quiet
|
189
233
|
})) do |stream, message|
|
190
234
|
yield(stream, message) if block_given?
|
191
235
|
end
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
236
|
+
ensure
|
237
|
+
unless keep_alive?
|
238
|
+
FileUtils.rm_rf(host_input_directory)
|
239
|
+
FileUtils.rm_rf(host_output_directory)
|
240
|
+
end
|
196
241
|
end
|
197
242
|
|
198
243
|
#-----------------------------------------------------------------------------
|
@@ -200,15 +245,17 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
200
245
|
|
201
246
|
def create_container
|
202
247
|
container = nil
|
248
|
+
gem_path = "#{ENV['GEM_HOME']}/gems/cm-#{CM.VERSION}"
|
203
249
|
|
204
|
-
destroy_container
|
250
|
+
destroy_container(true)
|
205
251
|
|
206
252
|
container_env = []
|
253
|
+
container_env << "NUCLEON_LOG=#{Nucleon.log_level}" if Nucleon.log_level
|
207
254
|
container_env << "NUCLEON_NO_PARALLEL=1" unless Nucleon.parallel?
|
208
255
|
container_env << "NUCLEON_NO_COLOR=1" unless Nucleon::Util::Console.use_colors
|
209
256
|
|
210
257
|
@container = Docker::Container.create({
|
211
|
-
'name' =>
|
258
|
+
'name' => docker_id,
|
212
259
|
'Image' => image,
|
213
260
|
'Cmd' => array(startup_commands),
|
214
261
|
'Tty' => true,
|
@@ -217,14 +264,16 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
217
264
|
plan_directory => {},
|
218
265
|
key_directory => {},
|
219
266
|
input_directory => {},
|
220
|
-
output_directory => {}
|
267
|
+
output_directory => {},
|
268
|
+
gem_path => {}
|
221
269
|
},
|
222
270
|
'HostConfig' => {
|
223
271
|
'Binds' => [
|
224
272
|
"#{plan.path}:#{plan_directory}:ro",
|
225
273
|
"#{plan.key_directory}:#{key_directory}:rw",
|
226
274
|
"#{host_input_directory}:#{input_directory}:ro", # config.yaml and tokens.json
|
227
|
-
"#{host_output_directory}:#{output_directory}:rw" # ??.yaml and/or ??.json
|
275
|
+
"#{host_output_directory}:#{output_directory}:rw", # ??.yaml and/or ??.json
|
276
|
+
"#{gem_path}:#{gem_path}:ro"
|
228
277
|
]
|
229
278
|
}
|
230
279
|
})
|
@@ -242,24 +291,13 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
242
291
|
#---
|
243
292
|
|
244
293
|
def initialize_remote_config(action_settings)
|
245
|
-
# Generate action settings file
|
246
|
-
settings = CM.configuration(extended_config(:container_input_settings_data, {
|
247
|
-
:provider => get(:container_input_settings_provider, :file),
|
248
|
-
:path => "#{host_input_directory}/action_settings.json"
|
249
|
-
}))
|
250
|
-
settings.import(action_settings)
|
251
|
-
settings.save
|
252
|
-
|
253
|
-
Nucleon.remove_plugin(settings)
|
254
|
-
|
255
294
|
# Generate and store plan configuration in local input directory
|
256
295
|
config = CM.configuration(extended_config(:container_input_config_data, {
|
257
296
|
:provider => get(:container_input_config_provider, :file),
|
258
297
|
:path => "#{host_input_directory}/config.json"
|
259
298
|
}))
|
260
|
-
config.import(plan.manifest_config)
|
299
|
+
config.import({ :config => plan.manifest_config })
|
261
300
|
config.save
|
262
|
-
|
263
301
|
Nucleon.remove_plugin(config)
|
264
302
|
|
265
303
|
# Generate and store plan tokens in local input directory
|
@@ -269,13 +307,12 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
269
307
|
}))
|
270
308
|
tokens.import(plan.tokens)
|
271
309
|
tokens.save
|
272
|
-
|
273
310
|
Nucleon.remove_plugin(tokens)
|
274
311
|
|
275
312
|
# Customize action settings
|
276
313
|
action_settings[:resource_config] = myself.settings
|
277
|
-
action_settings[:settings_path] = "#{input_directory}/action_settings.json"
|
278
314
|
action_settings[:plan_path] = plan_directory
|
315
|
+
action_settings[:manifest] = plan.manifest_file
|
279
316
|
action_settings[:config_provider] = 'file'
|
280
317
|
action_settings[:config_path] = "#{input_directory}/config.json"
|
281
318
|
action_settings[:token_provider] = 'file'
|
@@ -288,16 +325,19 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
288
325
|
|
289
326
|
#---
|
290
327
|
|
291
|
-
def destroy_container
|
292
|
-
|
328
|
+
def destroy_container(override = false)
|
329
|
+
if override || !keep_alive?
|
330
|
+
containers = Docker::Container.all({ :all => 1 })
|
293
331
|
|
294
|
-
|
295
|
-
|
296
|
-
cont.
|
297
|
-
|
332
|
+
# TODO: Fix occasional crashed actor issue when in parallel mode
|
333
|
+
containers.each do |cont|
|
334
|
+
if cont.info.key?('Names') && cont.info['Names'].include?("/#{docker_id}")
|
335
|
+
cont.kill!
|
336
|
+
cont.remove
|
337
|
+
end
|
298
338
|
end
|
339
|
+
@container = nil
|
299
340
|
end
|
300
|
-
@container = nil
|
301
341
|
end
|
302
342
|
protected :destroy_container
|
303
343
|
|
@@ -305,11 +345,12 @@ class DockerResource < Nucleon.plugin_class(:CM, :resource)
|
|
305
345
|
|
306
346
|
def render_docker_message(stream, message)
|
307
347
|
if stream == 'stderr'
|
308
|
-
|
348
|
+
warn("(#{Nucleon.red(image)})>#{message}", { :i18n => false, :prefix => false })
|
309
349
|
else
|
310
|
-
|
350
|
+
info("(#{Nucleon.yellow(image)})>#{message}", { :i18n => false, :prefix => false })
|
311
351
|
end
|
312
352
|
end
|
353
|
+
protected :render_docker_message
|
313
354
|
end
|
314
355
|
end
|
315
356
|
end
|