dtk-node-agent 0.5.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +18 -0
  4. data/README.md +42 -0
  5. data/bin/dtk-node-agent +16 -0
  6. data/dtk-node-agent.gemspec +38 -0
  7. data/lib/config/install.config +12 -0
  8. data/lib/dtk-node-agent/installer.rb +142 -0
  9. data/lib/dtk-node-agent/version.rb +3 -0
  10. data/mcollective_additions/plugins/README.md +1 -0
  11. data/mcollective_additions/plugins/v1.2/agent/discovery.rb +39 -0
  12. data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.ddl +15 -0
  13. data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.rb +79 -0
  14. data/mcollective_additions/plugins/v1.2/agent/git_access.ddl +9 -0
  15. data/mcollective_additions/plugins/v1.2/agent/git_access.rb +79 -0
  16. data/mcollective_additions/plugins/v1.2/agent/netstat.ddl +9 -0
  17. data/mcollective_additions/plugins/v1.2/agent/netstat.rb +34 -0
  18. data/mcollective_additions/plugins/v1.2/agent/puppet_apply.ddl +9 -0
  19. data/mcollective_additions/plugins/v1.2/agent/puppet_apply.rb +630 -0
  20. data/mcollective_additions/plugins/v1.2/agent/rpcutil.ddl +204 -0
  21. data/mcollective_additions/plugins/v1.2/agent/rpcutil.rb +101 -0
  22. data/mcollective_additions/plugins/v1.2/facts/pbuilder_facts.rb +35 -0
  23. data/mcollective_additions/plugins/v2.2/agent/dev_manager.ddl +9 -0
  24. data/mcollective_additions/plugins/v2.2/agent/dev_manager.rb +69 -0
  25. data/mcollective_additions/plugins/v2.2/agent/discovery.rb +39 -0
  26. data/mcollective_additions/plugins/v2.2/agent/dtk_node_agent_git_client.rb +94 -0
  27. data/mcollective_additions/plugins/v2.2/agent/execute_tests.ddl +9 -0
  28. data/mcollective_additions/plugins/v2.2/agent/execute_tests.rb +64 -0
  29. data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.ddl +15 -0
  30. data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.rb +79 -0
  31. data/mcollective_additions/plugins/v2.2/agent/git_access.ddl +9 -0
  32. data/mcollective_additions/plugins/v2.2/agent/git_access.rb +72 -0
  33. data/mcollective_additions/plugins/v2.2/agent/netstat.ddl +9 -0
  34. data/mcollective_additions/plugins/v2.2/agent/netstat.rb +34 -0
  35. data/mcollective_additions/plugins/v2.2/agent/ps.ddl +9 -0
  36. data/mcollective_additions/plugins/v2.2/agent/ps.rb +37 -0
  37. data/mcollective_additions/plugins/v2.2/agent/puppet_apply.ddl +9 -0
  38. data/mcollective_additions/plugins/v2.2/agent/puppet_apply.rb +633 -0
  39. data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.ddl +10 -0
  40. data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.rb +78 -0
  41. data/mcollective_additions/plugins/v2.2/agent/rpcutil.ddl +204 -0
  42. data/mcollective_additions/plugins/v2.2/agent/rpcutil.rb +101 -0
  43. data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.ddl +10 -0
  44. data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.rb +85 -0
  45. data/mcollective_additions/plugins/v2.2/agent/tail.ddl +11 -0
  46. data/mcollective_additions/plugins/v2.2/agent/tail.rb +67 -0
  47. data/mcollective_additions/plugins/v2.2/connector/r8stomp.rb +238 -0
  48. data/mcollective_additions/plugins/v2.2/connector/stomp.rb +349 -0
  49. data/mcollective_additions/plugins/v2.2/connector/stomp_em.rb +191 -0
  50. data/mcollective_additions/plugins/v2.2/facts/pbuilder_facts.rb +35 -0
  51. data/mcollective_additions/plugins/v2.2/security/sshkey.ddl +9 -0
  52. data/mcollective_additions/plugins/v2.2/security/sshkey.rb +362 -0
  53. data/mcollective_additions/server.cfg +22 -0
  54. data/puppet_additions/modules/r8/lib/puppet/type/r8_export_file.rb +53 -0
  55. data/puppet_additions/modules/r8/manifests/export_variable.rb +10 -0
  56. data/puppet_additions/puppet_lib_base/puppet/indirector/catalog/r8_storeconfig_backend.rb +48 -0
  57. data/puppet_additions/puppet_lib_base/puppet/indirector/r8_storeconfig_backend.rb +4 -0
  58. data/puppet_additions/puppet_lib_base/puppet/indirector/resource/r8_storeconfig_backend.rb +72 -0
  59. data/src/etc/init.d/ec2-run-user-data +95 -0
  60. data/src/etc/logrotate.d/mcollective +10 -0
  61. data/src/etc/logrotate.d/puppet +7 -0
  62. metadata +189 -0
@@ -0,0 +1,9 @@
1
+ metadata :name => "run puppet actions",
2
+ :description => "Agent to initiate Puppet apply runs",
3
+ :author => "Reactor8",
4
+ :license => "",
5
+ :version => "",
6
+ :url => "",
7
+ :timeout => 1800
8
+ action "run", :description => "puppet apply" do
9
+ end
@@ -0,0 +1,633 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'puppet'
4
+ require 'grit'
5
+ require 'tempfile'
6
+ require 'fileutils'
7
+ require File.expand_path('dtk_node_agent_git_client',File.dirname(__FILE__))
8
+
9
+ #TODO: move to be shared by agents
10
+ PuppetApplyLogDir = "/var/log/puppet"
11
+ ModulePath = "/etc/puppet/modules"
12
+
13
+ module MCollective
14
+ module Agent
15
+ class Puppet_apply < RPC::Agent
16
+ def initialize()
17
+ super()
18
+ @log = Log.instance
19
+ @reply_data = nil
20
+ end
21
+
22
+ def run_action
23
+ #validate :components_with_attributes
24
+ #validate :version_context
25
+ #validate :node_manifest
26
+ #validate :task_id, Fixnum
27
+ #validate :top_task_id, Fixnum
28
+
29
+ log_params()
30
+ @reply_data = nil
31
+ @msg_id = request.uniqid
32
+ @task_info = [:task_id,:top_task_id].inject({}) do |h,k|
33
+ h.merge(k => request[k])
34
+ end.merge(:msg_id => @msg_id)
35
+
36
+ more_generic_response = Response.new()
37
+ puppet_run_response = nil
38
+ begin
39
+ unless git_server = Facts["git-server"]
40
+ raise "git-server is not set in facts"
41
+ end
42
+ response = pull_modules(request[:version_context],git_server)
43
+ return set_reply!(response) if response.failed?()
44
+ puppet_run_response = run(request)
45
+ rescue Exception => e
46
+ more_generic_response.set_status_failed!()
47
+ more_generic_response.merge!(error_info(e))
48
+ end
49
+ set_reply?(puppet_run_response || more_generic_response)
50
+ end
51
+ private
52
+ def pull_modules(version_context,git_server)
53
+ ret = Response.new
54
+ ENV['GIT_SHELL'] = nil #This is put in because if vcsrepo Puppet module used it sets this
55
+ error_backtrace = nil
56
+ begin
57
+ version_context.each do |vc|
58
+ [:repo,:implementation,:branch].each do |field|
59
+ unless vc[field]
60
+ raise "version context does not have :#{field} field"
61
+ end
62
+ end
63
+ repo_dir = "#{ModulePath}/#{vc[:implementation]}"
64
+ remote_repo = "#{git_server}:#{vc[:repo]}"
65
+ opts = Hash.new
66
+ opts.merge!(:sha => vc[:sha]) if vc[:sha]
67
+ begin
68
+ if File.exists?(repo_dir)
69
+ git_repo = ::DTK::NodeAgent::GitClient.new(repo_dir)
70
+ git_repo.pull_and_checkout_branch?(vc[:branch],opts)
71
+ else
72
+ git_repo = ::DTK::NodeAgent::GitClient.new(repo_dir,:create=>true)
73
+ git_repo.clone_branch(remote_repo,vc[:branch],opts)
74
+ end
75
+ rescue Exception => e
76
+ error_backtrace = backtrace_subset(e)
77
+ #to achieve idempotent behavior; fully remove directory if any problems
78
+ FileUtils.rm_rf repo_dir
79
+ raise e
80
+ end
81
+ end
82
+ ret.set_status_succeeded!()
83
+ rescue Exception => e
84
+ log_error(e)
85
+ ret.set_status_failed!()
86
+ ret.merge!(error_info(e))
87
+ ensure
88
+ #TODO: may mot be needed now switch to grit
89
+ #git library sets these vars; so reseting here
90
+ %w{GIT_DIR GIT_INDEX_FILE GIT_WORK_TREE}.each{|var|ENV[var]=nil}
91
+ end
92
+ ret
93
+ end
94
+
95
+ def run(request)
96
+ cmps_with_attrs = request[:components_with_attributes]
97
+ node_manifest = request[:node_manifest]
98
+ inter_node_stage = request[:inter_node_stage]
99
+ puppet_version = request[:puppet_version]
100
+
101
+ if puppet_version
102
+ @log.info("Setting user provided puppet version '#{puppet_version}'")
103
+ puppet_version = "_#{puppet_version}_"
104
+ end
105
+
106
+ # Amar: Added task ID to current thread, so puppet apply can be canceled from puppet_cancel.rb when user requests cancel
107
+ task_id = request[:top_task_id]
108
+ Thread.current[:task_id] = task_id
109
+
110
+ clean_state()
111
+ ret = nil
112
+ log_file_path = log_file_path()
113
+ log_file = nil
114
+ begin
115
+ save_stderr = nil
116
+ stderr_capture = nil
117
+ log_file = File.open(log_file_path,"a")
118
+ log_file.close
119
+ Puppet[:autoflush] = true
120
+ most_recent_link = most_recent_file_path()
121
+ File.delete(most_recent_link) if File.exists? most_recent_link
122
+ File.symlink(log_file_path,most_recent_link)
123
+
124
+ # Amar: Node manifest contains list of generated puppet manifests
125
+ # This is done to support multiple puppet calls inside one puppet_apply agent call
126
+ node_manifest.each_with_index do |puppet_manifest, i|
127
+ execute_lines = puppet_manifest || ret_execute_lines(cmps_with_attrs)
128
+ execute_string = execute_lines.join("\n")
129
+ @log.info("\n----------------execute_string------------\n#{execute_string}\n----------------execute_string------------")
130
+ File.open("/tmp/site_stage#{inter_node_stage}_puppet_invocation_#{i+1}.pp","w"){|f| f << execute_string}
131
+ cmd_line =
132
+ [
133
+ "apply",
134
+ "-l", log_file_path,
135
+ "-d",
136
+ "--report", "true", "--reports", "r8report",
137
+ #"--storeconfigs_backend", "r8_storeconfig_backend",
138
+ "-e", execute_string
139
+ ]
140
+ cmd = "/usr/bin/puppet"
141
+ save_stderr = $stderr
142
+ stderr_capture = Tempfile.new("stderr")
143
+ $stderr = stderr_capture
144
+ begin
145
+ Puppet::Node::Environment.clear()
146
+ Thread.current[:known_resource_types] = nil #TODO: when move up to later versions of puupet think can remove because Puppet::Node::Environment.clear() does this
147
+ Puppet::Util::CommandLine.new(cmd,cmd_line).execute
148
+ rescue SystemExit => exit
149
+ report_status = Report::get_status()
150
+ report_info = Report::get_report_info()
151
+ # For multiple puppet calls, if one fails, rest will not get executed
152
+ raise exit if report_status == :failed || report_info[:errors] || (i == node_manifest.size - 1)
153
+ end
154
+ end
155
+ rescue SystemExit => exit
156
+ report_status = Report::get_status()
157
+ report_info = Report::get_report_info()
158
+ exit_status = exit.status
159
+ @log.info("exit.status = #{exit_status}")
160
+ @log.info("report_status = #{report_status}")
161
+ @log.info("report_info = #{report_info.inspect}")
162
+ return_code = ((report_status == :failed || report_info[:errors]) ? 1 : exit_status)
163
+ ret ||= Response.new()
164
+ if return_code == 0
165
+ if dynamic_attributes = process_dynamic_attributes?(cmps_with_attrs)
166
+ @log.info("dynamic_attributes = #{dynamic_attributes.inspect}")
167
+ ret.set_dynamic_attributes!(dynamic_attributes)
168
+ end
169
+ ret.set_status_succeeded!()
170
+ else
171
+ ret.set_status_failed!()
172
+ error_info = {
173
+ :return_code => return_code
174
+ }
175
+ error_info.merge!(:errors => report_info[:errors]) if (report_info||{})[:errors]
176
+ error_info[:errors].each { |error| error["type"] = "user_error" } if error_info[:errors]
177
+ ret.merge!(error_info)
178
+ end
179
+ rescue Exception => e
180
+ log_error(e)
181
+ ret ||= Response.new()
182
+ ret.set_status_failed!()
183
+ ret.merge!(error_info(e))
184
+ ensure
185
+ # Amar: If puppet_apply thread was killed from puppet_cancel, ':is_canceled' flag is set on the thread,
186
+ # so puppet_apply can send status canceled in the response
187
+ ret ||= Response.new()
188
+ if Thread.current[:is_canceled]
189
+ @log.info("Setting cancel status...")
190
+ ret.set_status_canceled!()
191
+ return set_reply!(ret)
192
+ end
193
+ if save_stderr #test if this is nil as to whether did the stderr swap
194
+ $stderr = save_stderr
195
+ stderr_capture.rewind
196
+ stderr_msg = stderr_capture.read
197
+ stderr_capture.close
198
+ stderr_capture.unlink
199
+ if stderr_msg and not stderr_msg.empty?
200
+ ret[:errors] = (ret[:errors]||[]) + [{:message => stderr_msg, :type => "user_error" }]
201
+ ret.set_status_failed!()
202
+ Puppet::err stderr_msg
203
+ Puppet::info "(end)"
204
+ end
205
+ end
206
+ Puppet::Util::Log.close_all()
207
+ end
208
+ ret
209
+ end
210
+
211
+ def backtrace_subset(e)
212
+ e.backtrace[0..10]
213
+ end
214
+
215
+ def log_error(e)
216
+ log_error = ([e.inspect]+backtrace_subset(e)).join("\n")
217
+ @log.info("\n----------------error-----\n#{log_error}\n----------------error-----")
218
+ end
219
+
220
+ def error_info(e,backtrace=nil)
221
+ {
222
+ :error => {
223
+ :message => e.inspect,
224
+ :backtrace => backtrace||backtrace_subset(e)
225
+ }
226
+ }
227
+ end
228
+
229
+ #TODO: cleanup fn; need to fix on serevr side; inconsient use of symbol and string keys
230
+ #execute_lines
231
+ def ret_execute_lines(cmps_with_attrs)
232
+ ret = Array.new
233
+ @import_statement_modules = Array.new
234
+ cmps_with_attrs.each_with_index do |cmp_with_attrs,i|
235
+ stage = i+1
236
+ module_name = cmp_with_attrs["module_name"]
237
+ ret << "stage{#{quote_form(stage)} :}"
238
+ attrs = process_and_return_attr_name_val_pairs(cmp_with_attrs)
239
+ stage_assign = "stage => #{quote_form(stage)}"
240
+ case cmp_with_attrs["component_type"]
241
+ when "class"
242
+ cmp = cmp_with_attrs["name"]
243
+ raise "No component name" unless cmp
244
+ if imp_stmt = needs_import_statement?(cmp,module_name)
245
+ ret << imp_stmt
246
+ end
247
+
248
+ #TODO: see if need \" and quote form
249
+ attr_str_array = attrs.map{|k,v|"#{k} => #{process_val(v)}"} + [stage_assign]
250
+ attr_str = attr_str_array.join(", ")
251
+ ret << "class {\"#{cmp}\": #{attr_str}}"
252
+ when "definition"
253
+ defn = cmp_with_attrs["name"]
254
+ raise "No definition name" unless defn
255
+ name_attr = nil
256
+ attr_str_array = attrs.map do |k,v|
257
+ if k == "name"
258
+ name_attr = quote_form(v)
259
+ nil
260
+ else
261
+ "#{k} => #{process_val(v)}"
262
+ end
263
+ end.compact
264
+ attr_str = attr_str_array.join(", ")
265
+ raise "No name attribute for definition" unless name_attr
266
+ if imp_stmt = needs_import_statement?(defn,module_name)
267
+ ret << imp_stmt
268
+ end
269
+ #putting def in class because defs cannot go in stages
270
+ class_wrapper = "stage#{stage.to_s}"
271
+ ret << "class #{class_wrapper} {"
272
+ ret << "#{defn} {#{name_attr}: #{attr_str}}"
273
+ ret << "}"
274
+ ret << "class {\"#{class_wrapper}\": #{stage_assign}}"
275
+ end
276
+ end
277
+ size = cmps_with_attrs.size
278
+ if size > 1
279
+ ordering_statement = (1..cmps_with_attrs.size).map{|s|"Stage[#{s.to_s}]"}.join(" -> ")
280
+ ret << ordering_statement
281
+ end
282
+
283
+ if attr_val_stmts = get_attr_val_statements(cmps_with_attrs)
284
+ ret += attr_val_stmts
285
+ end
286
+ ret
287
+ end
288
+
289
+ #removes imported collections and puts them on global array
290
+ def process_and_return_attr_name_val_pairs(cmp_with_attrs)
291
+ ret = Hash.new
292
+ return ret unless attrs = cmp_with_attrs["attributes"]
293
+ cmp_name = cmp_with_attrs["name"]
294
+ attrs.each do |attr_info|
295
+ attr_name = attr_info["name"]
296
+ val = attr_info["value"]
297
+ case attr_info["type"]
298
+ when "attribute"
299
+ ret[attr_name] = val
300
+ when "imported_collection"
301
+ add_imported_collection(cmp_name,attr_name,val,{"resource_type" => attr_info["resource_type"], "import_coll_query" => attr_info["import_coll_query"]})
302
+ else raise "unexpected attribute type (#{attr_info["type"]})"
303
+ end
304
+ end
305
+ ret
306
+ end
307
+
308
+ def get_attr_val_statements(cmps_with_attrs)
309
+ ret = Array.new
310
+ cmps_with_attrs.each do |cmp_with_attrs|
311
+ (cmp_with_attrs["dynamic_attributes"]||[]).each do |dyn_attr|
312
+ if dyn_attr[:type] == "default_variable"
313
+ qualified_var = "#{cmp_with_attrs["name"]}::#{dyn_attr[:name]}"
314
+ ret << "r8::export_variable{'#{qualified_var}' :}"
315
+ end
316
+ end
317
+ end
318
+ ret.empty? ? nil : ret
319
+ end
320
+
321
+
322
+ def needs_import_statement?(cmp_or_def,module_name)
323
+ return nil if cmp_or_def =~ /::/
324
+ return nil if @import_statement_modules.include?(module_name)
325
+ @import_statement_modules << module_name
326
+ "import '#{module_name}'"
327
+ end
328
+
329
+ def process_val(val)
330
+ #a guarded val
331
+ if val.kind_of?(Hash) and val.size == 1 and val.keys.first == "__ref"
332
+ "$#{val.values.join("::")}"
333
+ else
334
+ quote_form(val)
335
+ end
336
+ end
337
+
338
+ def process_dynamic_attributes?(cmps_with_attrs)
339
+ ret = Array.new
340
+ cmps_with_attrs.each do |cmp_with_attrs|
341
+ dyn_attrs = cmp_with_attrs["dynamic_attributes"]
342
+ if dyn_attrs and not dyn_attrs.empty?
343
+ cmp_ref = component_ref(cmp_with_attrs)
344
+ dyn_attrs.each do |dyn_attr|
345
+ if el = dynamic_attr_response_el(cmp_ref,dyn_attr)
346
+ ret << el
347
+ end
348
+ end
349
+ end
350
+ end
351
+ ret.empty? ? nil : ret
352
+ end
353
+ def dynamic_attr_response_el(cmp_name,dyn_attr)
354
+ ret = nil
355
+ val =
356
+ if dyn_attr[:type] == "exported_resource"
357
+ dynamic_attr_response_el__exported_resource(cmp_name,dyn_attr)
358
+ elsif dyn_attr[:type] == "default_variable"
359
+ dynamic_attr_response_el__default_attribute(cmp_name,dyn_attr)
360
+ else #assumption only three types: "exported_resource", "default_attribute, (and other can by "dynamic")
361
+ dynamic_attr_response_el__default_attribute(cmp_name,dyn_attr)||dynamic_attr_response_el__dynamic(cmp_name,dyn_attr)
362
+ end
363
+ if val
364
+ ret = {
365
+ :component_name => cmp_name,
366
+ :attribute_name => dyn_attr[:name],
367
+ :attribute_id => dyn_attr[:id],
368
+ :attribute_val => val
369
+ }
370
+ end
371
+ ret
372
+ end
373
+
374
+ def dynamic_attr_response_el__exported_resource(cmp_name,dyn_attr)
375
+ ret = nil
376
+ if cmp_exp_rscs = exported_resources(cmp_name)
377
+ cmp_exp_rscs.each do |title,val|
378
+ return val if exp_rsc_match(title,dyn_attr[:title_with_vars])
379
+ end
380
+ else
381
+ @log.info("no exported resources set for component #{cmp_name}")
382
+ end
383
+ ret
384
+ end
385
+
386
+ #TODO: more sophistiacted would take var bindings
387
+ def exp_rsc_match(title,title_with_vars)
388
+ regexp_str = regexp_string(title_with_vars)
389
+ @log.info("debug: regexp_str = #{regexp_str}")
390
+ title =~ Regexp.new("^#{regexp_str}$") if regexp_str
391
+ end
392
+
393
+ def regexp_string(title_with_vars)
394
+ if title_with_vars.kind_of?(Array)
395
+ case title_with_vars.first
396
+ when "variable" then ".+"
397
+ when "fn" then regexp_string__when_op(title_with_vars)
398
+ else
399
+ @log.info("unexpected first element in title with vars (#{title_with_vars.first})")
400
+ nil
401
+ end
402
+ else
403
+ title_with_vars.gsub(".","\\.")
404
+ end
405
+ end
406
+
407
+ def regexp_string__when_op(title_with_vars)
408
+ unless title_with_vars[1] == "concat"
409
+ @log.info("not treating operation (#{title_with_vars[1]})")
410
+ return nil
411
+ end
412
+ title_with_vars[2..title_with_vars.size-1].map do |x|
413
+ return nil unless re = regexp_string(x)
414
+ re
415
+ end.join("")
416
+ end
417
+
418
+ def dynamic_attr_response_el__dynamic(cmp_name,dyn_attr)
419
+ ret = nil
420
+ attr_name = dyn_attr[:name]
421
+ filepath = (exported_files(cmp_name)||{})[attr_name]
422
+ #TODO; legacy; remove when deprecate
423
+ filepath ||= "/tmp/#{cmp_name.gsub(/::/,".")}.#{attr_name}"
424
+ begin
425
+ val = File.open(filepath){|f|f.read}.chomp
426
+ ret = val unless val.empty?
427
+ rescue Exception
428
+ end
429
+ ret
430
+ end
431
+
432
+ def dynamic_attr_response_el__default_attribute(cmp_name,dyn_attr)
433
+ ret = nil
434
+ unless cmp_exp_vars = exported_variables(cmp_name)
435
+ @log.info("no exported varaibles for component #{cmp_name}")
436
+ return ret
437
+ end
438
+
439
+ attr_name = dyn_attr[:name]
440
+ unless cmp_exp_vars.has_key?(attr_name)
441
+ @log.info("no exported variable entry for component #{cmp_name}, attribute #{dyn_attr[:name]})")
442
+ return ret
443
+ end
444
+
445
+ cmp_exp_vars[attr_name]
446
+ end
447
+
448
+ def clean_state()
449
+ [:exported_resources, :exported_variables, :report_status, :imported_collections].each do |k|
450
+ Thread.current[k] = nil if Thread.current.keys.include?(k)
451
+ end
452
+ end
453
+ def exported_resources(cmp_name)
454
+ (Thread.current[:exported_resources]||{})[cmp_name]
455
+ end
456
+ def exported_variables(cmp_name)
457
+ (Thread.current[:exported_variables]||{})[cmp_name]
458
+ end
459
+ def exported_files(cmp_name)
460
+ (Thread.current[:exported_files]||{})[cmp_name]
461
+ end
462
+ def add_imported_collection(cmp_name,attr_name,val,context={})
463
+ p = (Thread.current[:imported_collections] ||= Hash.new)[cmp_name] ||= Hash.new
464
+ p[attr_name] = {"value" => val}.merge(context)
465
+ end
466
+
467
+ def component_ref(cmp_with_attrs)
468
+ case cmp_with_attrs["component_type"]
469
+ when "class"
470
+ cmp_with_attrs["name"]
471
+ when "definition"
472
+ defn = cmp_with_attrs["name"]
473
+ name_attr_val = (cmp_with_attrs["attributes"].find{|attr|attr["name"]}||{})["value"]
474
+ raise "Cannot find the name associated with definition #{defn}" unless name_attr_val
475
+ "#{cmp_with_attrs["name"]}[#{name_attr_val}]"
476
+ else
477
+ raise "Reference to type #{cmp_with_attrs["component_type"]} not treated"
478
+ end
479
+ end
480
+
481
+ def self.capitalize_resource_name(name)
482
+ name.split('::').map{|p|p.capitalize}.join("::")
483
+ end
484
+ def capitalize_resource_name(name)
485
+ self.class.capitalize_resource_name(name)
486
+ end
487
+
488
+ DynamicVarDefName = "r8_dynamic_vars::set_var"
489
+ DynamicVarDefNameRN = capitalize_resource_name(DynamicVarDefName)
490
+
491
+ def quote_form(obj)
492
+ if obj.kind_of?(Hash)
493
+ "{#{obj.map{|k,v|"#{quote_form(k)} => #{quote_form(v)}"}.join(",")}}"
494
+ elsif obj.kind_of?(Array)
495
+ "[#{obj.map{|el|quote_form(el)}.join(",")}]"
496
+ elsif obj.kind_of?(String)
497
+ "\"#{obj}\""
498
+ elsif obj.nil?
499
+ "nil"
500
+ else
501
+ obj.to_s
502
+ end
503
+ end
504
+
505
+ def set_reply!(response)
506
+ reply.data = @reply_data = response.to_hash
507
+ end
508
+ def set_reply?(response)
509
+ reply.data = @reply_data ||= response.to_hash
510
+ end
511
+ def log_params()
512
+ @log.info("params: #{request.data.inspect}")
513
+ end
514
+
515
+ def log_file_path()
516
+ "#{PuppetApplyLogDir}/#{id_info()}.log"
517
+ end
518
+ def most_recent_file_path()
519
+ "#{PuppetApplyLogDir}/last.log"
520
+ end
521
+ def id_info()
522
+ [:msg_id,:task_id,:top_task_id].map do |k|
523
+ if @task_info.has_key?(k)
524
+ "#{k}:#{@task_info[k].to_s}"
525
+ end
526
+ end.compact.join(":")
527
+ end
528
+
529
+ #TODO: this should be common accross Agents
530
+ class Response < Hash
531
+ def initialize(hash={})
532
+ super()
533
+ self.merge!(hash)
534
+ self[:status] = :unknown unless hash.has_key?(:status)
535
+ end
536
+
537
+ def to_hash()
538
+ Hash.new.merge(self)
539
+ end
540
+
541
+ def failed?()
542
+ self[:status] == :failed
543
+ end
544
+
545
+ def set_status_failed!()
546
+ self[:status] = :failed
547
+ end
548
+ def set_status_succeeded!()
549
+ self[:status] = :succeeded
550
+ end
551
+ def set_status_canceled!()
552
+ self[:status] = :canceled
553
+ end
554
+ def set_dynamic_attributes!(dynamic_attributes)
555
+ self[:dynamic_attributes] = dynamic_attributes
556
+ end
557
+ end
558
+ class ResponseFailed < Response
559
+ def initialize(error,info={})
560
+ super({:status => :failed, :error => error}.merge(info))
561
+ end
562
+ end
563
+ class ResponseSucceeded < Response
564
+ def initialize(info={})
565
+ super({:status => :succeeded}.merge(info))
566
+ end
567
+ end
568
+ end
569
+ end
570
+
571
+ class Report
572
+ def self.set_status(status)
573
+ Thread.current[:report_status] = status.to_sym
574
+ end
575
+ def self.get_status()
576
+ Thread.current[:report_status]
577
+ end
578
+ def self.set_report_info(report_info)
579
+ Thread.current[:report_info] = report_info
580
+ end
581
+ def self.get_report_info()
582
+ Thread.current[:report_info]||{}
583
+ end
584
+ end
585
+ end
586
+
587
+ #below is more complicated to allow reloading
588
+ if Puppet::Reports.constants.include?('R8report')
589
+ Puppet::Reports.send(:remove_const,:R8report)
590
+ end
591
+ #TODO: needed to pass {:overwrite => true} to Puppet::Reports.genmodule so expanded def Puppet::Reports.register_report(:r8report)
592
+ def register_report(name,&block)
593
+ name = name.intern
594
+ mod = Puppet::Reports.genmodule(name, :overwrite=> true,:extend => Puppet::Util::Docs, :hash => Puppet::Reports.instance_hash(:report), :block => block)
595
+ mod.send(:define_method, :report_name) do
596
+ name
597
+ end
598
+ end
599
+ register_report(:r8report) do
600
+ desc "report for R8 agent"
601
+
602
+ def process
603
+ MCollective::Report.set_status(status)
604
+ report_info = Hash.new
605
+ errors = logs.select{|log_el|log_el.level == :err}
606
+ unless errors.empty?
607
+ report_info[:errors] = errors.map do |err|
608
+ {
609
+ "message" => err.message,
610
+ "source" => err.source,
611
+ "tags" => err.tags,
612
+ "time" => err.time
613
+ }
614
+ end
615
+ end
616
+ MCollective::Report.set_report_info(report_info)
617
+ self
618
+ end
619
+ end
620
+
621
+ class Puppet::Settings
622
+ def initialize_global_settings(args = [])
623
+ #raise Puppet::DevError, "Attempting to initialize global default settings more than once!" if global_defaults_initialized?
624
+ return if global_defaults_initialized?
625
+ # The first two phases of the lifecycle of a puppet application are:
626
+ # 1) Parse the command line options and handle any of them that are
627
+ # registered, defined "global" puppet settings (mostly from defaults.rb).
628
+ # 2) Parse the puppet config file(s).
629
+ parse_global_options(args)
630
+ parse_config_files
631
+ @global_defaults_initialized = true
632
+ end
633
+ end