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.
- checksums.yaml +15 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +18 -0
- data/README.md +42 -0
- data/bin/dtk-node-agent +16 -0
- data/dtk-node-agent.gemspec +38 -0
- data/lib/config/install.config +12 -0
- data/lib/dtk-node-agent/installer.rb +142 -0
- data/lib/dtk-node-agent/version.rb +3 -0
- data/mcollective_additions/plugins/README.md +1 -0
- data/mcollective_additions/plugins/v1.2/agent/discovery.rb +39 -0
- data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.ddl +15 -0
- data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.rb +79 -0
- data/mcollective_additions/plugins/v1.2/agent/git_access.ddl +9 -0
- data/mcollective_additions/plugins/v1.2/agent/git_access.rb +79 -0
- data/mcollective_additions/plugins/v1.2/agent/netstat.ddl +9 -0
- data/mcollective_additions/plugins/v1.2/agent/netstat.rb +34 -0
- data/mcollective_additions/plugins/v1.2/agent/puppet_apply.ddl +9 -0
- data/mcollective_additions/plugins/v1.2/agent/puppet_apply.rb +630 -0
- data/mcollective_additions/plugins/v1.2/agent/rpcutil.ddl +204 -0
- data/mcollective_additions/plugins/v1.2/agent/rpcutil.rb +101 -0
- data/mcollective_additions/plugins/v1.2/facts/pbuilder_facts.rb +35 -0
- data/mcollective_additions/plugins/v2.2/agent/dev_manager.ddl +9 -0
- data/mcollective_additions/plugins/v2.2/agent/dev_manager.rb +69 -0
- data/mcollective_additions/plugins/v2.2/agent/discovery.rb +39 -0
- data/mcollective_additions/plugins/v2.2/agent/dtk_node_agent_git_client.rb +94 -0
- data/mcollective_additions/plugins/v2.2/agent/execute_tests.ddl +9 -0
- data/mcollective_additions/plugins/v2.2/agent/execute_tests.rb +64 -0
- data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.ddl +15 -0
- data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.rb +79 -0
- data/mcollective_additions/plugins/v2.2/agent/git_access.ddl +9 -0
- data/mcollective_additions/plugins/v2.2/agent/git_access.rb +72 -0
- data/mcollective_additions/plugins/v2.2/agent/netstat.ddl +9 -0
- data/mcollective_additions/plugins/v2.2/agent/netstat.rb +34 -0
- data/mcollective_additions/plugins/v2.2/agent/ps.ddl +9 -0
- data/mcollective_additions/plugins/v2.2/agent/ps.rb +37 -0
- data/mcollective_additions/plugins/v2.2/agent/puppet_apply.ddl +9 -0
- data/mcollective_additions/plugins/v2.2/agent/puppet_apply.rb +633 -0
- data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.ddl +10 -0
- data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.rb +78 -0
- data/mcollective_additions/plugins/v2.2/agent/rpcutil.ddl +204 -0
- data/mcollective_additions/plugins/v2.2/agent/rpcutil.rb +101 -0
- data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.ddl +10 -0
- data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.rb +85 -0
- data/mcollective_additions/plugins/v2.2/agent/tail.ddl +11 -0
- data/mcollective_additions/plugins/v2.2/agent/tail.rb +67 -0
- data/mcollective_additions/plugins/v2.2/connector/r8stomp.rb +238 -0
- data/mcollective_additions/plugins/v2.2/connector/stomp.rb +349 -0
- data/mcollective_additions/plugins/v2.2/connector/stomp_em.rb +191 -0
- data/mcollective_additions/plugins/v2.2/facts/pbuilder_facts.rb +35 -0
- data/mcollective_additions/plugins/v2.2/security/sshkey.ddl +9 -0
- data/mcollective_additions/plugins/v2.2/security/sshkey.rb +362 -0
- data/mcollective_additions/server.cfg +22 -0
- data/puppet_additions/modules/r8/lib/puppet/type/r8_export_file.rb +53 -0
- data/puppet_additions/modules/r8/manifests/export_variable.rb +10 -0
- data/puppet_additions/puppet_lib_base/puppet/indirector/catalog/r8_storeconfig_backend.rb +48 -0
- data/puppet_additions/puppet_lib_base/puppet/indirector/r8_storeconfig_backend.rb +4 -0
- data/puppet_additions/puppet_lib_base/puppet/indirector/resource/r8_storeconfig_backend.rb +72 -0
- data/src/etc/init.d/ec2-run-user-data +95 -0
- data/src/etc/logrotate.d/mcollective +10 -0
- data/src/etc/logrotate.d/puppet +7 -0
- metadata +189 -0
@@ -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
|