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.
@@ -26,7 +26,7 @@ class BOSH < Nucleon.plugin_class(:CM, :docker_resource)
26
26
 
27
27
  def operation_deploy
28
28
  super do
29
- success = true
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
- success = true
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
- success = true
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
- success = true
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 Keypair < Nucleon.plugin_class(:CM, :docker_resource)
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 operation_deploy
24
- super do
25
- success = true
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
 
@@ -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
- success = false unless resource.execute(operation)
27
- break if plan.trap && plan.step
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
- success = false unless resource.execute(operation)
39
- break if plan.trap && plan.step
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
@@ -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
- success = false unless resource.execute(operation)
86
- break if plan.trap && plan.step
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
@@ -3,7 +3,6 @@ module Nucleon
3
3
  module Plugin
4
4
  class CmAction < Nucleon.plugin_class(:nucleon, :action)
5
5
 
6
- include Parallel
7
6
  include Mixin::Action::Config
8
7
 
9
8
  #-----------------------------------------------------------------------------
@@ -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(plugin_instance_name)
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/#{plugin_instance_name}")
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, '/opt/cm/volumes/input')
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/#{plugin_instance_name}")
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, '/opt/cm/volumes/output')
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
- super do
107
- data = nil
108
-
109
- # A fork in the road!
110
- if internal?
111
- data = yield if block_given?
112
- else
113
- data = action(plugin_provider, :deploy)
114
- myself.status = code.docker_exec_failed unless data
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
- myself.data = data
117
- myself.status == code.success
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 = nil
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, :directory),
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
- config = Nucleon::Config.ensure(options)
154
- remove_command = false
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
- data = exec(command.to_s.strip) do |stream, message|
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
- encoded_config = Nucleon::Util::CLI.encode(action_settings)
179
- action_config = extended_config(:action, {
180
- :command => 'resource run',
181
- :data => { :encoded => encoded_config },
182
- :args => [ provider, operation ]
183
- })
184
- action_config[:data][:log_level] = Nucleon.log_level if Nucleon.log_level
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
- FileUtils.rm_rf(host_input_directory)
194
- FileUtils.rm_rf(host_output_directory)
195
- data
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' => plugin_instance_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
- containers = Docker::Container.all({ :all => 1 })
328
+ def destroy_container(override = false)
329
+ if override || !keep_alive?
330
+ containers = Docker::Container.all({ :all => 1 })
293
331
 
294
- containers.each do |cont|
295
- if cont.info.key?('Names') && cont.info['Names'].include?("/#{plugin_instance_name}")
296
- cont.kill!
297
- cont.remove
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
- puts message
348
+ warn("(#{Nucleon.red(image)})>#{message}", { :i18n => false, :prefix => false })
309
349
  else
310
- puts message
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