dtk-node-agent 0.5.10

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.
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