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,79 @@
|
|
1
|
+
module MCollective
|
2
|
+
module Agent
|
3
|
+
class Git_access < RPC::Agent
|
4
|
+
metadata :name => "git access",
|
5
|
+
:description => "Agent to enable git access",
|
6
|
+
:author => "Reactor8",
|
7
|
+
:license => "",
|
8
|
+
:version => "",
|
9
|
+
:url => "",
|
10
|
+
:timeout => 20
|
11
|
+
action "add_rsa_info" do
|
12
|
+
ssh_folder_path = '/root/.ssh'
|
13
|
+
rsa_path = "#{ssh_folder_path}/id_rsa"
|
14
|
+
rsa_pub_path = "#{ssh_folder_path}/id_rsa.pub"
|
15
|
+
known_hosts = "#{ssh_folder_path}/known_hosts"
|
16
|
+
|
17
|
+
begin
|
18
|
+
# validate request
|
19
|
+
validate_request(request)
|
20
|
+
|
21
|
+
#create private rsa file if needed
|
22
|
+
unless donot_create_file?(:private,rsa_path,request[:agent_ssh_key_private])
|
23
|
+
File.open(rsa_path,"w",0600){|f|f.print request[:agent_ssh_key_private]}
|
24
|
+
end
|
25
|
+
|
26
|
+
#create public rsa file if needed
|
27
|
+
unless donot_create_file?(:public,rsa_pub_path,request[:agent_ssh_key_public])
|
28
|
+
File.open(rsa_pub_path,"w"){|f|f.print request[:agent_ssh_key_public]}
|
29
|
+
end
|
30
|
+
|
31
|
+
#create or append if key not there
|
32
|
+
skip = nil
|
33
|
+
fp = request[:server_ssh_rsa_fingerprint]
|
34
|
+
if File.exists?(known_hosts)
|
35
|
+
fp_key = (fp =~ Regexp.new("^[|]1[|]([^=]+)=");$1)
|
36
|
+
if fp_key
|
37
|
+
fp_key_regexp = Regexp.new("^.1.#{fp_key}")
|
38
|
+
skip = !!File.open(known_hosts){|f|f.find{|line|line =~ fp_key_regexp}}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
unless skip
|
42
|
+
File.open(known_hosts,"a"){|f|f.print request[:server_ssh_rsa_fingerprint]}
|
43
|
+
end
|
44
|
+
|
45
|
+
reply.data = { :status => :succeeded}
|
46
|
+
rescue Exception => e
|
47
|
+
reply.data = { :status => :failed, :error => {:message => e.message}}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#TODO: move to using mcollective vallidation on ddl
|
52
|
+
def validate_request(req)
|
53
|
+
required_params = [:agent_ssh_key_public, :agent_ssh_key_private, :server_ssh_rsa_fingerprint]
|
54
|
+
missing_params = []
|
55
|
+
required_params.each do |param|
|
56
|
+
missing_params << param if req[param].nil?
|
57
|
+
end
|
58
|
+
|
59
|
+
unless missing_params.empty?
|
60
|
+
raise "Request is missing required param(s): #{missing_params.join(',')} please review your request."
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def donot_create_file?(type,path,content)
|
65
|
+
# raises exception if these files already exists and content differs
|
66
|
+
if File.exists?(path)
|
67
|
+
existing = File.open(path).read
|
68
|
+
if existing == content
|
69
|
+
true
|
70
|
+
else
|
71
|
+
raise "RSA #{type} key already exists and differs from one in payload"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module MCollective
|
2
|
+
module Agent
|
3
|
+
class Netstat < RPC::Agent
|
4
|
+
metadata :name => "netstat info",
|
5
|
+
:description => "Agent to get netstat info",
|
6
|
+
:author => "Reactor8",
|
7
|
+
:license => "",
|
8
|
+
:version => "",
|
9
|
+
:url => "",
|
10
|
+
:timeout => 2
|
11
|
+
action "get_tcp_udp" do
|
12
|
+
output = `netstat -nltpu`
|
13
|
+
results = output.scan(/(^[a-z0-9]+)\s+(\d)\s+(\d)\s+([0-9:.*]+)\s+([0-9:.*]+)\s+(LISTEN)?\s+([0-9a-zA-Z\/\-: ]+)/m)
|
14
|
+
|
15
|
+
netstat_result = []
|
16
|
+
results.each do |result|
|
17
|
+
netstat_packet = {}
|
18
|
+
netstat_packet.store(:protocol, result[0])
|
19
|
+
netstat_packet.store(:recv_q, result[1])
|
20
|
+
netstat_packet.store(:send_q, result[2])
|
21
|
+
netstat_packet.store(:local, result[3])
|
22
|
+
netstat_packet.store(:foreign, result[4])
|
23
|
+
netstat_packet.store(:state, result[5])
|
24
|
+
netstat_packet.store(:program, result[6].strip)
|
25
|
+
netstat_result << netstat_packet
|
26
|
+
end
|
27
|
+
|
28
|
+
reply[:data] = netstat_result
|
29
|
+
reply[:pbuilderid] = Facts["pbuilderid"]
|
30
|
+
reply[:status] = :ok
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,630 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'puppet'
|
4
|
+
require 'grit'
|
5
|
+
require 'tempfile'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
#dont want to run standard hooks and just want store configs for catalogs/resources, not for facts ..
|
9
|
+
Puppet.settings.set_value(:storeconfigs,true,:memory, :dont_trigger_handles => true)
|
10
|
+
Puppet::Resource::Catalog.indirection.cache_class = :store_configs
|
11
|
+
Puppet::Resource.indirection.terminus_class = :store_configs
|
12
|
+
|
13
|
+
#TODO: move to be shared by agents
|
14
|
+
PuppetApplyLogDir = "/var/log/puppet"
|
15
|
+
ModulePath = "/etc/puppet/modules"
|
16
|
+
|
17
|
+
module MCollective
|
18
|
+
module Agent
|
19
|
+
class Puppet_apply < RPC::Agent
|
20
|
+
metadata :name => "run puppet actions",
|
21
|
+
:description => "Agent to initiate Puppet apply runs",
|
22
|
+
:author => "Reactor8",
|
23
|
+
:license => "",
|
24
|
+
:version => "",
|
25
|
+
:url => "",
|
26
|
+
:timeout => 600
|
27
|
+
def initialize()
|
28
|
+
super()
|
29
|
+
@log = Log.instance
|
30
|
+
@reply_data = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def run_action
|
34
|
+
#validate :components_with_attributes
|
35
|
+
#validate :version_context
|
36
|
+
#validate :node_manifest
|
37
|
+
|
38
|
+
validate :task_id, Fixnum
|
39
|
+
validate :top_task_id, Fixnum
|
40
|
+
log_params()
|
41
|
+
@reply_data = nil
|
42
|
+
@msg_id = request.uniqid
|
43
|
+
@task_info = [:task_id,:top_task_id].inject({}) do |h,k|
|
44
|
+
h.merge(k => request[k])
|
45
|
+
end.merge(:msg_id => @msg_id)
|
46
|
+
|
47
|
+
more_generic_response = Response.new()
|
48
|
+
puppet_run_response = nil
|
49
|
+
begin
|
50
|
+
response = pull_recipes(request[:version_context])
|
51
|
+
return set_reply!(response) if response.failed?()
|
52
|
+
puppet_run_response = run(request)
|
53
|
+
rescue Exception => e
|
54
|
+
more_generic_response.set_status_failed!()
|
55
|
+
error_info = {
|
56
|
+
:error => {
|
57
|
+
:message => e.inspect
|
58
|
+
}
|
59
|
+
}
|
60
|
+
more_generic_response.merge!(error_info)
|
61
|
+
end
|
62
|
+
set_reply?(puppet_run_response || more_generic_response)
|
63
|
+
end
|
64
|
+
private
|
65
|
+
#TODO: this should be common accross Agents after pulling out aagent specfic params
|
66
|
+
def pull_recipes(version_context)
|
67
|
+
ret = Response.new
|
68
|
+
begin
|
69
|
+
version_context.each do |vc|
|
70
|
+
repo = vc[:repo]
|
71
|
+
implementation = vc[:implementation]
|
72
|
+
branch_name = vc[:branch]
|
73
|
+
repo_dir = "#{ModulePath}/#{implementation}"
|
74
|
+
unless File.exists?(repo_dir)
|
75
|
+
begin
|
76
|
+
raise "git server is not set in facts" unless git_server = Facts["git-server"]
|
77
|
+
remote_git = "#{git_server}:#{repo}"
|
78
|
+
ClientRepo.clone(remote_git,repo_dir)
|
79
|
+
rescue Exception => e
|
80
|
+
#to achive idempotent behavior fully remove directory that has not been fully cloned
|
81
|
+
FileUtils.rm_rf repo_dir
|
82
|
+
raise e
|
83
|
+
end
|
84
|
+
end
|
85
|
+
Dir.chdir(repo_dir) do
|
86
|
+
begin
|
87
|
+
repo = ClientRepo.new(".")
|
88
|
+
if repo.branch_exists?(branch_name)
|
89
|
+
current_branch = repo.current_branch
|
90
|
+
repo.git_command__checkout(branch_name) unless current_branch == branch_name
|
91
|
+
repo.git_command__pull(branch_name)
|
92
|
+
else
|
93
|
+
unless repo.remote_branch_exists?("origin/#{branch_name}")
|
94
|
+
repo.git_command__pull()
|
95
|
+
end
|
96
|
+
repo.git_command__checkout_track_branch(branch_name)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
ret.set_status_succeeded!()
|
102
|
+
rescue Exception => e
|
103
|
+
ret.set_status_failed!()
|
104
|
+
error_info = {
|
105
|
+
:error => {
|
106
|
+
:message => e.inspect
|
107
|
+
}
|
108
|
+
}
|
109
|
+
ret.merge!(error_info)
|
110
|
+
ensure
|
111
|
+
#TODO: may mot be needed now switch to grit
|
112
|
+
#git library sets these vars; so resting here
|
113
|
+
%w{GIT_DIR GIT_INDEX_FILE GIT_WORK_TREE}.each{|var|ENV[var]=nil}
|
114
|
+
end
|
115
|
+
ret
|
116
|
+
end
|
117
|
+
|
118
|
+
def run(request)
|
119
|
+
cmps_with_attrs = request[:components_with_attributes]
|
120
|
+
node_manifest = request[:node_manifest]
|
121
|
+
inter_node_stage = request[:inter_node_stage]
|
122
|
+
|
123
|
+
clean_state()
|
124
|
+
ret = nil
|
125
|
+
log_file_path = log_file_path()
|
126
|
+
log_file = nil
|
127
|
+
begin
|
128
|
+
save_stderr = nil
|
129
|
+
log_file = File.open(log_file_path,"a")
|
130
|
+
log_file.close
|
131
|
+
Puppet[:autoflush] = true
|
132
|
+
most_recent_link = most_recent_file_path()
|
133
|
+
File.delete(most_recent_link) if File.exists? most_recent_link
|
134
|
+
File.symlink(log_file_path,most_recent_link)
|
135
|
+
|
136
|
+
execute_lines = node_manifest || ret_execute_lines(cmps_with_attrs)
|
137
|
+
execute_string = execute_lines.join("\n")
|
138
|
+
@log.info("\n----------------execute_string------------\n#{execute_string}\n----------------execute_string------------")
|
139
|
+
File.open("/tmp/site_stage#{inter_node_stage}.pp","w"){|f| f << execute_string}
|
140
|
+
cmd_line =
|
141
|
+
[
|
142
|
+
"apply",
|
143
|
+
"-l", log_file_path,
|
144
|
+
"-d",
|
145
|
+
"--report", true, "--reports", "r8report",
|
146
|
+
"--storeconfigs_backend", "r8_storeconfig_backend",
|
147
|
+
"-e", execute_string
|
148
|
+
]
|
149
|
+
cmd = "/usr/bin/puppet"
|
150
|
+
save_stderr = $stderr
|
151
|
+
stderr_capture = Tempfile.new("stderr")
|
152
|
+
$stderr = stderr_capture
|
153
|
+
Puppet::Util::CommandLine.new(cmd,cmd_line).execute
|
154
|
+
rescue SystemExit => exit
|
155
|
+
report_status = Report::get_status()
|
156
|
+
report_info = Report::get_report_info()
|
157
|
+
exit_status = exit.status
|
158
|
+
@log.info("exit.status = #{exit_status}")
|
159
|
+
@log.info("report_status = #{report_status}")
|
160
|
+
@log.info("report_info = #{report_info.inspect}")
|
161
|
+
return_code = ((report_status == :failed || report_info[:errors]) ? 1 : exit_status)
|
162
|
+
ret ||= Response.new()
|
163
|
+
if return_code == 0
|
164
|
+
if dynamic_attributes = process_dynamic_attributes?(cmps_with_attrs)
|
165
|
+
@log.info("dynamic_attributes = #{dynamic_attributes.inspect}")
|
166
|
+
ret.set_dynamic_attributes!(dynamic_attributes)
|
167
|
+
end
|
168
|
+
ret.set_status_succeeded!()
|
169
|
+
else
|
170
|
+
ret.set_status_failed!()
|
171
|
+
error_info = {
|
172
|
+
:return_code => return_code
|
173
|
+
}
|
174
|
+
error_info.merge!(:errors => report_info[:errors]) if (report_info||{})[:errors]
|
175
|
+
ret.merge!(error_info)
|
176
|
+
end
|
177
|
+
rescue Exception => e
|
178
|
+
pp [e,e.backtrace[0..5]]
|
179
|
+
log_error = ([e.inspect]+[e.backtrace[0..5]]).join("\n")
|
180
|
+
@log.info("\n----------------error-----\n#{log_error}\n----------------error-----")
|
181
|
+
ret ||= Response.new()
|
182
|
+
ret.set_status_failed!()
|
183
|
+
error_info = {
|
184
|
+
:error => {
|
185
|
+
:message => e.inspect
|
186
|
+
}
|
187
|
+
}
|
188
|
+
ret.merge!(error_info)
|
189
|
+
ensure
|
190
|
+
if save_stderr #test if this is nil as to whether did the stderr swap
|
191
|
+
$stderr = save_stderr
|
192
|
+
stderr_capture.rewind
|
193
|
+
stderr_msg = stderr_capture.read
|
194
|
+
stderr_capture.close
|
195
|
+
stderr_capture.unlink
|
196
|
+
if stderr_msg and not stderr_msg.empty?
|
197
|
+
ret[:errors] = (ret[:errors]||[]) + [{:message => stderr_msg}]
|
198
|
+
Puppet::err stderr_msg
|
199
|
+
Puppet::info "(end)"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
Puppet::Util::Log.close_all()
|
203
|
+
end
|
204
|
+
ret
|
205
|
+
end
|
206
|
+
|
207
|
+
#TODO: cleanup fn; need to fix on serevr side; inconsient use of symbol and string keys
|
208
|
+
#execute_lines
|
209
|
+
def ret_execute_lines(cmps_with_attrs)
|
210
|
+
ret = Array.new
|
211
|
+
@import_statement_modules = Array.new
|
212
|
+
cmps_with_attrs.each_with_index do |cmp_with_attrs,i|
|
213
|
+
stage = i+1
|
214
|
+
module_name = cmp_with_attrs["module_name"]
|
215
|
+
ret << "stage{#{quote_form(stage)} :}"
|
216
|
+
attrs = process_and_return_attr_name_val_pairs(cmp_with_attrs)
|
217
|
+
stage_assign = "stage => #{quote_form(stage)}"
|
218
|
+
case cmp_with_attrs["component_type"]
|
219
|
+
when "class"
|
220
|
+
cmp = cmp_with_attrs["name"]
|
221
|
+
raise "No component name" unless cmp
|
222
|
+
if imp_stmt = needs_import_statement?(cmp,module_name)
|
223
|
+
ret << imp_stmt
|
224
|
+
end
|
225
|
+
|
226
|
+
#TODO: see if need \" and quote form
|
227
|
+
attr_str_array = attrs.map{|k,v|"#{k} => #{process_val(v)}"} + [stage_assign]
|
228
|
+
attr_str = attr_str_array.join(", ")
|
229
|
+
ret << "class {\"#{cmp}\": #{attr_str}}"
|
230
|
+
when "definition"
|
231
|
+
defn = cmp_with_attrs["name"]
|
232
|
+
raise "No definition name" unless defn
|
233
|
+
name_attr = nil
|
234
|
+
attr_str_array = attrs.map do |k,v|
|
235
|
+
if k == "name"
|
236
|
+
name_attr = quote_form(v)
|
237
|
+
nil
|
238
|
+
else
|
239
|
+
"#{k} => #{process_val(v)}"
|
240
|
+
end
|
241
|
+
end.compact
|
242
|
+
attr_str = attr_str_array.join(", ")
|
243
|
+
raise "No name attribute for definition" unless name_attr
|
244
|
+
if imp_stmt = needs_import_statement?(defn,module_name)
|
245
|
+
ret << imp_stmt
|
246
|
+
end
|
247
|
+
#putting def in class because defs cannot go in stages
|
248
|
+
class_wrapper = "stage#{stage.to_s}"
|
249
|
+
ret << "class #{class_wrapper} {"
|
250
|
+
ret << "#{defn} {#{name_attr}: #{attr_str}}"
|
251
|
+
ret << "}"
|
252
|
+
ret << "class {\"#{class_wrapper}\": #{stage_assign}}"
|
253
|
+
end
|
254
|
+
end
|
255
|
+
size = cmps_with_attrs.size
|
256
|
+
if size > 1
|
257
|
+
ordering_statement = (1..cmps_with_attrs.size).map{|s|"Stage[#{s.to_s}]"}.join(" -> ")
|
258
|
+
ret << ordering_statement
|
259
|
+
end
|
260
|
+
|
261
|
+
if attr_val_stmts = get_attr_val_statements(cmps_with_attrs)
|
262
|
+
ret += attr_val_stmts
|
263
|
+
end
|
264
|
+
ret
|
265
|
+
end
|
266
|
+
|
267
|
+
#removes imported collections and puts them on global array
|
268
|
+
def process_and_return_attr_name_val_pairs(cmp_with_attrs)
|
269
|
+
ret = Hash.new
|
270
|
+
return ret unless attrs = cmp_with_attrs["attributes"]
|
271
|
+
cmp_name = cmp_with_attrs["name"]
|
272
|
+
attrs.each do |attr_info|
|
273
|
+
attr_name = attr_info["name"]
|
274
|
+
val = attr_info["value"]
|
275
|
+
case attr_info["type"]
|
276
|
+
when "attribute"
|
277
|
+
ret[attr_name] = val
|
278
|
+
when "imported_collection"
|
279
|
+
add_imported_collection(cmp_name,attr_name,val,{"resource_type" => attr_info["resource_type"], "import_coll_query" => attr_info["import_coll_query"]})
|
280
|
+
else raise "unexpected attribute type (#{attr_info["type"]})"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
ret
|
284
|
+
end
|
285
|
+
|
286
|
+
def get_attr_val_statements(cmps_with_attrs)
|
287
|
+
ret = Array.new
|
288
|
+
cmps_with_attrs.each do |cmp_with_attrs|
|
289
|
+
(cmp_with_attrs["dynamic_attributes"]||[]).each do |dyn_attr|
|
290
|
+
if dyn_attr[:type] == "default_variable"
|
291
|
+
qualified_var = "#{cmp_with_attrs["name"]}::#{dyn_attr[:name]}"
|
292
|
+
ret << "r8::export_variable{'#{qualified_var}' :}"
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
ret.empty? ? nil : ret
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
def needs_import_statement?(cmp_or_def,module_name)
|
301
|
+
return nil if cmp_or_def =~ /::/
|
302
|
+
return nil if @import_statement_modules.include?(module_name)
|
303
|
+
@import_statement_modules << module_name
|
304
|
+
"import '#{module_name}'"
|
305
|
+
end
|
306
|
+
|
307
|
+
def process_val(val)
|
308
|
+
#a guarded val
|
309
|
+
if val.kind_of?(Hash) and val.size == 1 and val.keys.first == "__ref"
|
310
|
+
"$#{val.values.join("::")}"
|
311
|
+
else
|
312
|
+
quote_form(val)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def process_dynamic_attributes?(cmps_with_attrs)
|
317
|
+
ret = Array.new
|
318
|
+
cmps_with_attrs.each do |cmp_with_attrs|
|
319
|
+
cmp_name = cmp_with_attrs["name"]
|
320
|
+
dyn_attrs = cmp_with_attrs["dynamic_attributes"]
|
321
|
+
if dyn_attrs and not dyn_attrs.empty?
|
322
|
+
resource_ref = resource_ref(cmp_with_attrs)
|
323
|
+
dyn_attrs.each do |dyn_attr|
|
324
|
+
if el = dynamic_attr_response_el(cmp_name,dyn_attr)
|
325
|
+
ret << el
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
ret.empty? ? nil : ret
|
331
|
+
end
|
332
|
+
def dynamic_attr_response_el(cmp_name,dyn_attr)
|
333
|
+
ret = nil
|
334
|
+
val =
|
335
|
+
if dyn_attr[:type] == "exported_resource"
|
336
|
+
dynamic_attr_response_el__exported_resource(cmp_name,dyn_attr)
|
337
|
+
elsif dyn_attr[:type] == "default_variable"
|
338
|
+
dynamic_attr_response_el__default_attribute(cmp_name,dyn_attr)
|
339
|
+
else #assumption only three types: "exported_resource", "default_attribute, (and other can by "dynamic")
|
340
|
+
dynamic_attr_response_el__default_attribute(cmp_name,dyn_attr)||dynamic_attr_response_el__dynamic(cmp_name,dyn_attr)
|
341
|
+
end
|
342
|
+
if val
|
343
|
+
ret = {
|
344
|
+
:component_name => cmp_name,
|
345
|
+
:attribute_name => dyn_attr[:name],
|
346
|
+
:attribute_id => dyn_attr[:id],
|
347
|
+
:attribute_val => val
|
348
|
+
}
|
349
|
+
end
|
350
|
+
ret
|
351
|
+
end
|
352
|
+
|
353
|
+
def dynamic_attr_response_el__exported_resource(cmp_name,dyn_attr)
|
354
|
+
ret = nil
|
355
|
+
if cmp_exp_rscs = exported_resources(cmp_name)
|
356
|
+
cmp_exp_rscs.each do |title,val|
|
357
|
+
return val if exp_rsc_match(title,dyn_attr[:title_with_vars])
|
358
|
+
end
|
359
|
+
else
|
360
|
+
@log.info("no exported resources set for component #{cmp_name}")
|
361
|
+
end
|
362
|
+
ret
|
363
|
+
end
|
364
|
+
|
365
|
+
#TODO: more sophistiacted would take var bindings
|
366
|
+
def exp_rsc_match(title,title_with_vars)
|
367
|
+
regexp_str = regexp_string(title_with_vars)
|
368
|
+
@log.info("debug: regexp_str = #{regexp_str}")
|
369
|
+
title =~ Regexp.new("^#{regexp_str}$") if regexp_str
|
370
|
+
end
|
371
|
+
|
372
|
+
def regexp_string(title_with_vars)
|
373
|
+
if title_with_vars.kind_of?(Array)
|
374
|
+
case title_with_vars.first
|
375
|
+
when "variable" then ".+"
|
376
|
+
when "fn" then regexp_string__when_op(title_with_vars)
|
377
|
+
else
|
378
|
+
@log.info("unexpected first element in title with vars (#{title_with_vars.first})")
|
379
|
+
nil
|
380
|
+
end
|
381
|
+
else
|
382
|
+
title_with_vars.gsub(".","\\.")
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
def regexp_string__when_op(title_with_vars)
|
387
|
+
unless title_with_vars[1] == "concat"
|
388
|
+
@log.info("not treating operation (#{title_with_vars[1]})")
|
389
|
+
return nil
|
390
|
+
end
|
391
|
+
title_with_vars[2..title_with_vars.size-1].map do |x|
|
392
|
+
return nil unless re = regexp_string(x)
|
393
|
+
re
|
394
|
+
end.join("")
|
395
|
+
end
|
396
|
+
|
397
|
+
def dynamic_attr_response_el__dynamic(cmp_name,dyn_attr)
|
398
|
+
ret = nil
|
399
|
+
attr_name = dyn_attr[:name]
|
400
|
+
filepath = (exported_files(cmp_name)||{})[attr_name]
|
401
|
+
#TODO; legacy; remove when deprecate
|
402
|
+
filepath ||= "/tmp/#{cmp_name.gsub(/::/,".")}.#{attr_name}"
|
403
|
+
begin
|
404
|
+
val = File.open(filepath){|f|f.read}.chomp
|
405
|
+
ret = val unless val.empty?
|
406
|
+
rescue Exception
|
407
|
+
end
|
408
|
+
ret
|
409
|
+
end
|
410
|
+
|
411
|
+
def dynamic_attr_response_el__default_attribute(cmp_name,dyn_attr)
|
412
|
+
ret = nil
|
413
|
+
unless cmp_exp_vars = exported_variables(cmp_name)
|
414
|
+
@log.info("no exported varaibles for component #{cmp_name}")
|
415
|
+
return ret
|
416
|
+
end
|
417
|
+
|
418
|
+
attr_name = dyn_attr[:name]
|
419
|
+
unless cmp_exp_vars.has_key?(attr_name)
|
420
|
+
@log.info("no exported variable entry for component #{cmp_name}, attribute #{dyn_attr[:name]})")
|
421
|
+
return ret
|
422
|
+
end
|
423
|
+
|
424
|
+
cmp_exp_vars[attr_name]
|
425
|
+
end
|
426
|
+
|
427
|
+
def clean_state()
|
428
|
+
[:exported_resources, :exported_variables, :report_status, :imported_collections].each do |k|
|
429
|
+
Thread.current[k] = nil if Thread.current.keys.include?(k)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
def exported_resources(cmp_name)
|
433
|
+
(Thread.current[:exported_resources]||{})[cmp_name]
|
434
|
+
end
|
435
|
+
def exported_variables(cmp_name)
|
436
|
+
(Thread.current[:exported_variables]||{})[cmp_name]
|
437
|
+
end
|
438
|
+
def exported_files(cmp_name)
|
439
|
+
(Thread.current[:exported_files]||{})[cmp_name]
|
440
|
+
end
|
441
|
+
def add_imported_collection(cmp_name,attr_name,val,context={})
|
442
|
+
p = (Thread.current[:imported_collections] ||= Hash.new)[cmp_name] ||= Hash.new
|
443
|
+
p[attr_name] = {"value" => val}.merge(context)
|
444
|
+
end
|
445
|
+
|
446
|
+
def resource_ref(cmp_with_attrs)
|
447
|
+
case cmp_with_attrs["component_type"]
|
448
|
+
when "class"
|
449
|
+
"Class[#{quote_form(cmp_with_attrs["name"])}]"
|
450
|
+
when "definition"
|
451
|
+
defn = cmp_with_attrs["name"]
|
452
|
+
def_name = (cmp_with_attrs["attributes"].find{|k,v|k == "name"}||[]).last
|
453
|
+
raise "Cannot find the name associated with definition #{defn}" unless def_name
|
454
|
+
"#{capitalize_resource_name(defn)}[#{quote_form(def_name)}]"
|
455
|
+
else
|
456
|
+
raise "Reference to type #{cmp_with_attrs["component_type"]} not treated"
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
def self.capitalize_resource_name(name)
|
461
|
+
name.split('::').map{|p|p.capitalize}.join("::")
|
462
|
+
end
|
463
|
+
def capitalize_resource_name(name)
|
464
|
+
self.class.capitalize_resource_name(name)
|
465
|
+
end
|
466
|
+
|
467
|
+
DynamicVarDefName = "r8_dynamic_vars::set_var"
|
468
|
+
DynamicVarDefNameRN = capitalize_resource_name(DynamicVarDefName)
|
469
|
+
|
470
|
+
def quote_form(obj)
|
471
|
+
if obj.kind_of?(Hash)
|
472
|
+
"{#{obj.map{|k,v|"#{quote_form(k)} => #{quote_form(v)}"}.join(",")}}"
|
473
|
+
elsif obj.kind_of?(Array)
|
474
|
+
"[#{obj.map{|el|quote_form(el)}.join(",")}]"
|
475
|
+
elsif obj.kind_of?(String)
|
476
|
+
"\"#{obj}\""
|
477
|
+
elsif obj.nil?
|
478
|
+
"nil"
|
479
|
+
else
|
480
|
+
obj.to_s
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
def set_reply!(response)
|
485
|
+
reply.data = @reply_data = response.to_hash
|
486
|
+
end
|
487
|
+
def set_reply?(response)
|
488
|
+
reply.data = @reply_data ||= response.to_hash
|
489
|
+
end
|
490
|
+
def log_params()
|
491
|
+
@log.info("params: #{request.data.inspect}")
|
492
|
+
end
|
493
|
+
|
494
|
+
def log_file_path()
|
495
|
+
"#{PuppetApplyLogDir}/#{id_info()}.log"
|
496
|
+
end
|
497
|
+
def most_recent_file_path()
|
498
|
+
"#{PuppetApplyLogDir}/last.log"
|
499
|
+
end
|
500
|
+
def id_info()
|
501
|
+
[:msg_id,:task_id,:top_task_id].map do |k|
|
502
|
+
if @task_info.has_key?(k)
|
503
|
+
"#{k}:#{@task_info[k].to_s}"
|
504
|
+
end
|
505
|
+
end.compact.join(":")
|
506
|
+
end
|
507
|
+
|
508
|
+
#TODO: this should be common accross Agents
|
509
|
+
class ClientRepo
|
510
|
+
def self.clone(remote_git,repo_dir)
|
511
|
+
Grit::Git.new("").clone(git_command_opts(),remote_git,repo_dir)
|
512
|
+
end
|
513
|
+
def initialize(path)
|
514
|
+
@path = path
|
515
|
+
@grit_repo = Grit::Repo.new(path)
|
516
|
+
@index = @grit_repo.index #creates new object so use @index, not grit_repo
|
517
|
+
end
|
518
|
+
|
519
|
+
def branch_exists?(branch_name)
|
520
|
+
@grit_repo.heads.find{|h|h.name == branch_name} ? true : nil
|
521
|
+
end
|
522
|
+
|
523
|
+
def remote_branch_exists?(branch_name)
|
524
|
+
@grit_repo.remotes.find{|h|h.name == branch_name} ? true : nil
|
525
|
+
end
|
526
|
+
|
527
|
+
def git_command__checkout_track_branch(branch_name)
|
528
|
+
git_command().checkout(git_command_opts(),"--track","-b", branch_name, "origin/#{branch_name}")
|
529
|
+
end
|
530
|
+
|
531
|
+
def current_branch()
|
532
|
+
@grit_repo.head.name
|
533
|
+
end
|
534
|
+
|
535
|
+
def git_command__checkout(branch_name)
|
536
|
+
git_command().checkout(git_command_opts(),branch_name)
|
537
|
+
end
|
538
|
+
|
539
|
+
def git_command__pull(branch_name=nil)
|
540
|
+
branch_name ? git_command().pull(git_command_opts(),"origin",branch_name) : git_command().pull(git_command_opts(),"origin")
|
541
|
+
end
|
542
|
+
private
|
543
|
+
def self.git_command_opts()
|
544
|
+
{:raise => true, :timeout => 60}
|
545
|
+
end
|
546
|
+
def git_command_opts()
|
547
|
+
self.class.git_command_opts()
|
548
|
+
end
|
549
|
+
def git_command()
|
550
|
+
@grit_repo.git
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
#TODO: this should be common accross Agents
|
555
|
+
class Response < Hash
|
556
|
+
def initialize(hash={})
|
557
|
+
super()
|
558
|
+
self.merge!(hash)
|
559
|
+
self[:status] = :unknown unless hash.has_key?(:status)
|
560
|
+
end
|
561
|
+
|
562
|
+
def to_hash()
|
563
|
+
Hash.new.merge(self)
|
564
|
+
end
|
565
|
+
|
566
|
+
def failed?()
|
567
|
+
self[:status] == :failed
|
568
|
+
end
|
569
|
+
|
570
|
+
def set_status_failed!()
|
571
|
+
self[:status] = :failed
|
572
|
+
end
|
573
|
+
def set_status_succeeded!()
|
574
|
+
self[:status] = :succeeded
|
575
|
+
end
|
576
|
+
def set_dynamic_attributes!(dynamic_attributes)
|
577
|
+
self[:dynamic_attributes] = dynamic_attributes
|
578
|
+
end
|
579
|
+
end
|
580
|
+
class ResponseFailed < Response
|
581
|
+
def initialize(error,info={})
|
582
|
+
super({:status => :failed, :error => error}.merge(info))
|
583
|
+
end
|
584
|
+
end
|
585
|
+
class ResponseSucceeded < Response
|
586
|
+
def initialize(info={})
|
587
|
+
super({:status => :succeeded}.merge(info))
|
588
|
+
end
|
589
|
+
end
|
590
|
+
end
|
591
|
+
end
|
592
|
+
class Report
|
593
|
+
def self.set_status(status)
|
594
|
+
Thread.current[:report_status] = status.to_sym
|
595
|
+
end
|
596
|
+
def self.get_status()
|
597
|
+
Thread.current[:report_status]
|
598
|
+
end
|
599
|
+
def self.set_report_info(report_info)
|
600
|
+
Thread.current[:report_info] = report_info
|
601
|
+
end
|
602
|
+
def self.get_report_info()
|
603
|
+
Thread.current[:report_info]
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
Puppet::Reports.register_report(:r8report) do
|
609
|
+
desc "report for R8 agent"
|
610
|
+
|
611
|
+
def process
|
612
|
+
MCollective::Report.set_status(status)
|
613
|
+
|
614
|
+
#TODO: right now just passing raw info nack on errors; may normalize here
|
615
|
+
report_info = Hash.new
|
616
|
+
errors = logs.select{|log_el|log_el.level == :err}
|
617
|
+
unless errors.empty?
|
618
|
+
report_info[:errors] = errors.map do |err|
|
619
|
+
{
|
620
|
+
"message" => err.message,
|
621
|
+
"source" => err.source,
|
622
|
+
"tags" => err.tags,
|
623
|
+
"time" => err.time
|
624
|
+
}
|
625
|
+
end
|
626
|
+
end
|
627
|
+
MCollective::Report.set_report_info(report_info)
|
628
|
+
self
|
629
|
+
end
|
630
|
+
end
|