dtk-node-agent 0.7.7 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +5 -13
  2. data/README.md +21 -4
  3. data/bin/dtk-node-agent +17 -0
  4. data/lib/config/install.config +2 -2
  5. data/lib/dtk-node-agent/installer.rb +30 -25
  6. data/lib/dtk-node-agent/version.rb +18 -1
  7. metadata +23 -110
  8. data/mcollective_additions/debian.mcollective.init +0 -92
  9. data/mcollective_additions/plugins/README.md +0 -1
  10. data/mcollective_additions/plugins/v1.2/agent/discovery.rb +0 -39
  11. data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.ddl +0 -15
  12. data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.rb +0 -79
  13. data/mcollective_additions/plugins/v1.2/agent/git_access.ddl +0 -9
  14. data/mcollective_additions/plugins/v1.2/agent/git_access.rb +0 -79
  15. data/mcollective_additions/plugins/v1.2/agent/netstat.ddl +0 -9
  16. data/mcollective_additions/plugins/v1.2/agent/netstat.rb +0 -34
  17. data/mcollective_additions/plugins/v1.2/agent/puppet_apply.ddl +0 -9
  18. data/mcollective_additions/plugins/v1.2/agent/puppet_apply.rb +0 -630
  19. data/mcollective_additions/plugins/v1.2/agent/rpcutil.ddl +0 -204
  20. data/mcollective_additions/plugins/v1.2/agent/rpcutil.rb +0 -101
  21. data/mcollective_additions/plugins/v1.2/facts/pbuilder_facts.rb +0 -35
  22. data/mcollective_additions/plugins/v2.2/agent/action_agent.ddl +0 -9
  23. data/mcollective_additions/plugins/v2.2/agent/action_agent.rb +0 -47
  24. data/mcollective_additions/plugins/v2.2/agent/dev_manager.ddl +0 -9
  25. data/mcollective_additions/plugins/v2.2/agent/dev_manager.rb +0 -111
  26. data/mcollective_additions/plugins/v2.2/agent/discovery.rb +0 -39
  27. data/mcollective_additions/plugins/v2.2/agent/dtk_node_agent_git_client.rb +0 -94
  28. data/mcollective_additions/plugins/v2.2/agent/execute_tests.ddl +0 -9
  29. data/mcollective_additions/plugins/v2.2/agent/execute_tests.rb +0 -111
  30. data/mcollective_additions/plugins/v2.2/agent/execute_tests_v2.ddl +0 -9
  31. data/mcollective_additions/plugins/v2.2/agent/execute_tests_v2.rb +0 -131
  32. data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.ddl +0 -15
  33. data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.rb +0 -79
  34. data/mcollective_additions/plugins/v2.2/agent/git_access.ddl +0 -9
  35. data/mcollective_additions/plugins/v2.2/agent/git_access.rb +0 -61
  36. data/mcollective_additions/plugins/v2.2/agent/netstat.ddl +0 -9
  37. data/mcollective_additions/plugins/v2.2/agent/netstat.rb +0 -34
  38. data/mcollective_additions/plugins/v2.2/agent/ps.ddl +0 -9
  39. data/mcollective_additions/plugins/v2.2/agent/ps.rb +0 -37
  40. data/mcollective_additions/plugins/v2.2/agent/puppet_apply.ddl +0 -9
  41. data/mcollective_additions/plugins/v2.2/agent/puppet_apply.rb +0 -818
  42. data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.ddl +0 -10
  43. data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.rb +0 -78
  44. data/mcollective_additions/plugins/v2.2/agent/rpcutil.ddl +0 -204
  45. data/mcollective_additions/plugins/v2.2/agent/rpcutil.rb +0 -101
  46. data/mcollective_additions/plugins/v2.2/agent/ssh_agent.ddl +0 -13
  47. data/mcollective_additions/plugins/v2.2/agent/ssh_agent.rb +0 -97
  48. data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.ddl +0 -10
  49. data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.rb +0 -85
  50. data/mcollective_additions/plugins/v2.2/agent/tail.ddl +0 -11
  51. data/mcollective_additions/plugins/v2.2/agent/tail.rb +0 -67
  52. data/mcollective_additions/plugins/v2.2/audit/logfile.rb +0 -26
  53. data/mcollective_additions/plugins/v2.2/connector/r8stomp.rb +0 -238
  54. data/mcollective_additions/plugins/v2.2/connector/stomp.rb +0 -349
  55. data/mcollective_additions/plugins/v2.2/connector/stomp_em.rb +0 -191
  56. data/mcollective_additions/plugins/v2.2/data/agent_data.ddl +0 -22
  57. data/mcollective_additions/plugins/v2.2/data/agent_data.rb +0 -17
  58. data/mcollective_additions/plugins/v2.2/data/collective_data.ddl +0 -20
  59. data/mcollective_additions/plugins/v2.2/data/collective_data.rb +0 -9
  60. data/mcollective_additions/plugins/v2.2/data/fact_data.ddl +0 -28
  61. data/mcollective_additions/plugins/v2.2/data/fact_data.rb +0 -55
  62. data/mcollective_additions/plugins/v2.2/data/fstat_data.ddl +0 -89
  63. data/mcollective_additions/plugins/v2.2/data/fstat_data.rb +0 -56
  64. data/mcollective_additions/plugins/v2.2/discovery/flatfile.ddl +0 -11
  65. data/mcollective_additions/plugins/v2.2/discovery/flatfile.rb +0 -48
  66. data/mcollective_additions/plugins/v2.2/discovery/mc.ddl +0 -11
  67. data/mcollective_additions/plugins/v2.2/discovery/mc.rb +0 -30
  68. data/mcollective_additions/plugins/v2.2/discovery/stdin.ddl +0 -11
  69. data/mcollective_additions/plugins/v2.2/discovery/stdin.rb +0 -66
  70. data/mcollective_additions/plugins/v2.2/facts/pbuilder_facts.rb +0 -37
  71. data/mcollective_additions/plugins/v2.2/facts/yaml_facts.rb +0 -61
  72. data/mcollective_additions/plugins/v2.2/registration/agentlist.rb +0 -10
  73. data/mcollective_additions/plugins/v2.2/security/sshkey.ddl +0 -9
  74. data/mcollective_additions/plugins/v2.2/security/sshkey.rb +0 -362
  75. data/mcollective_additions/plugins/v2.2/util/puppetrunner.rb +0 -36
  76. data/mcollective_additions/plugins/v2.2/validator/array_validator.ddl +0 -7
  77. data/mcollective_additions/plugins/v2.2/validator/array_validator.rb +0 -9
  78. data/mcollective_additions/plugins/v2.2/validator/ipv4address_validator.ddl +0 -7
  79. data/mcollective_additions/plugins/v2.2/validator/ipv4address_validator.rb +0 -16
  80. data/mcollective_additions/plugins/v2.2/validator/ipv6address_validator.ddl +0 -7
  81. data/mcollective_additions/plugins/v2.2/validator/ipv6address_validator.rb +0 -16
  82. data/mcollective_additions/plugins/v2.2/validator/length_validator.ddl +0 -7
  83. data/mcollective_additions/plugins/v2.2/validator/length_validator.rb +0 -11
  84. data/mcollective_additions/plugins/v2.2/validator/regex_validator.ddl +0 -7
  85. data/mcollective_additions/plugins/v2.2/validator/regex_validator.rb +0 -9
  86. data/mcollective_additions/plugins/v2.2/validator/shellsafe_validator.ddl +0 -7
  87. data/mcollective_additions/plugins/v2.2/validator/shellsafe_validator.rb +0 -13
  88. data/mcollective_additions/plugins/v2.2/validator/typecheck_validator.ddl +0 -7
  89. data/mcollective_additions/plugins/v2.2/validator/typecheck_validator.rb +0 -28
  90. data/mcollective_additions/redhat.mcollective.init +0 -139
  91. data/mcollective_additions/redhat.mcollective.service +0 -14
  92. data/mcollective_additions/server.cfg +0 -22
  93. data/src/etc/logrotate.d/mcollective +0 -10
  94. data/src/etc/mcollective.default +0 -6
@@ -1,9 +0,0 @@
1
- metadata :name => "git access",
2
- :description => "Agent to enable git access",
3
- :author => "Reactor8",
4
- :license => "",
5
- :version => "",
6
- :url => "",
7
- :timeout => 20
8
- action "add_rsa_info", :description => "add ssh rsa info" do
9
- end
@@ -1,61 +0,0 @@
1
- module MCollective
2
- module Agent
3
- class Git_access < RPC::Agent
4
- action "add_rsa_info" do
5
- ssh_folder_path = '/root/.ssh'
6
- rsa_path = "#{ssh_folder_path}/id_rsa"
7
- rsa_pub_path = "#{ssh_folder_path}/id_rsa.pub"
8
- known_hosts = "#{ssh_folder_path}/known_hosts"
9
-
10
- begin
11
- # validate request
12
- validate_request(request)
13
-
14
- #create private rsa file if needed
15
- unless donot_create_file?(:private,rsa_path,request[:agent_ssh_key_private])
16
- File.open(rsa_path,"w",0600){|f|f.print request[:agent_ssh_key_private]}
17
- end
18
-
19
- #create public rsa file if needed
20
- unless donot_create_file?(:public,rsa_pub_path,request[:agent_ssh_key_public])
21
- File.open(rsa_pub_path,"w"){|f|f.print request[:agent_ssh_key_public]}
22
- end
23
-
24
- # add rsa_fingerprint to known hsots; server logic makes sure that is not requested twice so no duplicates
25
- File.open(known_hosts,"a"){|f|f.print request[:server_ssh_rsa_fingerprint]}
26
-
27
- reply.data = { :status => :succeeded}
28
- rescue Exception => e
29
- reply.data = { :status => :failed, :error => {:message => e.message}}
30
- end
31
- end
32
-
33
- #TODO: move to using mcollective vallidation on ddl
34
- def validate_request(req)
35
- required_params = [:agent_ssh_key_public, :agent_ssh_key_private, :server_ssh_rsa_fingerprint]
36
- missing_params = []
37
- required_params.each do |param|
38
- missing_params << param if req[param].nil?
39
- end
40
-
41
- unless missing_params.empty?
42
- raise "Request is missing required param(s): #{missing_params.join(',')} please review your request."
43
- end
44
- end
45
-
46
- def donot_create_file?(type,path,content)
47
- # raises exception if these files already exists and content differs
48
- if File.exists?(path)
49
- existing = File.open(path).read
50
- if existing == content
51
- true
52
- else
53
- raise "RSA #{type} key already exists and differs from one in payload"
54
- end
55
- end
56
- end
57
- end
58
- end
59
- end
60
-
61
-
@@ -1,9 +0,0 @@
1
- metadata :name => "netstat info",
2
- :description => "Agent to get netstat info",
3
- :author => "Reactor8",
4
- :license => "",
5
- :version => "",
6
- :url => "",
7
- :timeout => 2
8
- action "get_tcp_udp", :description => "get tcp and udp info" do
9
- end
@@ -1,34 +0,0 @@
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+([a-z0-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
@@ -1,9 +0,0 @@
1
- metadata :name => "ps info",
2
- :description => "Agent to get ps info (running processes)",
3
- :author => "Reactor8",
4
- :license => "",
5
- :version => "",
6
- :url => "",
7
- :timeout => 2
8
- action "get_ps", :description => "get running processes via ps" do
9
- end
@@ -1,37 +0,0 @@
1
- module MCollective
2
- module Agent
3
- class Ps < RPC::Agent
4
- metadata :name => "ps info",
5
- :description => "Agent to get ps info (running processes)",
6
- :author => "Reactor8",
7
- :license => "",
8
- :version => "",
9
- :url => "",
10
- :timeout => 2
11
- action "get_ps" do
12
- output=`ps -ef`
13
- output.gsub!(/^.+\]$/,'')
14
- results = output.scan(/(\S+)[\s].*?(\S+)[\s].*?(\S+)[\s].*?(\S+)[\s].*?(\S+)[\s].*?(\S+)[\s].*?(\S+)[\s].*?(.+)/)
15
- results.shift
16
- ps_result = []
17
- results.each do |result|
18
- ps_packet = {}
19
- ps_packet.store(:uid, result[0])
20
- ps_packet.store(:pid, result[1])
21
- ps_packet.store(:ppid, result[2])
22
- ps_packet.store(:cpu, result[3])
23
- ps_packet.store(:start_time, result[4])
24
- ps_packet.store(:tty, result[5])
25
- ps_packet.store(:time, result[6])
26
- result[7] = (result[7][0...60].strip + '...') if result[7].strip.length > 60
27
- ps_packet.store(:command, result[7])
28
- ps_result << ps_packet
29
- end
30
-
31
- reply[:data] = ps_result
32
- reply[:pbuilderid] = Facts["pbuilderid"]
33
- reply[:status] = :ok
34
- end
35
- end
36
- end
37
- end
@@ -1,9 +0,0 @@
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
@@ -1,818 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'rubygems'
3
- require 'puppet'
4
- require 'grit'
5
- require 'tempfile'
6
- require 'fileutils'
7
- require 'etc'
8
- require File.expand_path('dtk_node_agent_git_client',File.dirname(__FILE__))
9
-
10
- #TODO: move to be shared by agents
11
- PuppetApplyLogDir = "/var/log/puppet"
12
- ModulePath = "/etc/puppet/modules"
13
- DTKPuppetCacheBaseDir = "/usr/share/dtk/tasks"
14
- DTKPuppetModulePath = "/usr/share/dtk/puppet-modules"
15
- # make sure HOME variable is set correctly
16
- ENV['HOME'] = Etc.getpwuid.dir
17
-
18
- module MCollective
19
- module Agent
20
- class Puppet_apply < RPC::Agent
21
-
22
- NUMBER_OF_RETRIES = 5
23
-
24
- def initialize()
25
- super()
26
- @log = Log.instance
27
- @reply_data = nil
28
- end
29
-
30
- def run_action
31
- #validate :components_with_attributes
32
- #validate :version_context
33
- #validate :node_manifest
34
- #validate :task_id, Fixnum
35
- #validate :top_task_id, Fixnum
36
-
37
- log_params()
38
- @reply_data = nil
39
- @msg_id = request.uniqid
40
- @service_name = request[:service_name] || "UNKNOWN"
41
- @task_info = [:task_id,:top_task_id].inject({}) do |h,k|
42
- h.merge(k => request[k])
43
- end.merge(:msg_id => @msg_id)
44
-
45
- more_generic_response = Response.new()
46
- puppet_run_response = nil
47
- begin
48
- unless git_server = Facts["git-server"]
49
- raise "git-server is not set in facts"
50
- end
51
- response = pull_modules(request[:version_context],git_server)
52
- return set_reply!(response) if response.failed?()
53
- puppet_run_response = run(request)
54
- rescue Exception => e
55
- more_generic_response.set_status_failed!()
56
- more_generic_response.merge!(error_info(e))
57
- end
58
- set_reply?(puppet_run_response || more_generic_response)
59
- end
60
- private
61
- def pull_modules(version_context,git_server)
62
- ret = Response.new
63
- ENV['GIT_SHELL'] = nil #This is put in because if vcsrepo Puppet module used it sets this
64
- error_backtrace = nil
65
- begin
66
- version_context.each do |vc|
67
- [:repo,:implementation,:branch].each do |field|
68
- unless vc[field]
69
- raise "version context does not have :#{field} field"
70
- end
71
- end
72
-
73
- FileUtils.mkdir_p(DTKPuppetModulePath) unless File.directory?(DTKPuppetModulePath)
74
-
75
- module_name = vc[:implementation]
76
- puppet_repo_dir = "#{DTKPuppetModulePath}/#{module_name}"
77
- repo_dir = "#{ModulePath}/#{module_name}"
78
- remote_repo = git_repo_full_url(git_server, vc[:repo])
79
-
80
- opts = Hash.new
81
- opts.merge!(:sha => vc[:sha]) if vc[:sha]
82
-
83
- clean_and_clone = true
84
- if File.exists?("#{puppet_repo_dir}/.git")
85
- pull_err = trap_and_return_error do
86
- pull_module(puppet_repo_dir, vc[:branch], opts)
87
- end
88
- # clean_and_clone set so if pull error then try again, this time cleaning dir and freshly cleaning
89
- clean_and_clone = !pull_err.nil?
90
- end
91
-
92
- if clean_and_clone
93
- begin
94
- tries ||= NUMBER_OF_RETRIES
95
- clean_and_clone_module(puppet_repo_dir, remote_repo,vc[:branch], opts)
96
- rescue Exception => e
97
- # to achieve idempotent behavior; fully remove directory if any problems
98
- FileUtils.rm_rf puppet_repo_dir
99
- unless (tries -= 1).zero?
100
- @log.info("Re-trying last command becuase of error: #{e.message}, retries left: #{tries}")
101
- sleep(1)
102
- retry
103
- end
104
- # TODO: not used now
105
- error_backtrace = backtrace_subset(e)
106
- raise e
107
- end
108
- end
109
-
110
- # remove symlink if exist already
111
- if File.symlink?(repo_dir)
112
- FileUtils.rm(repo_dir)
113
- elsif File.directory?(repo_dir)
114
- FileUtils.rm_r(repo_dir)
115
- end
116
-
117
- puppet_dir = "#{DTKPuppetModulePath}/#{module_name}/puppet"
118
-
119
- if File.directory?(puppet_dir)
120
- FileUtils.ln_sf(puppet_dir, repo_dir)
121
- else
122
- FileUtils.ln_sf("#{DTKPuppetModulePath}/#{module_name}", repo_dir)
123
- end
124
- end
125
- ret.set_status_succeeded!()
126
- rescue Exception => e
127
- log_error(e)
128
- ret.set_status_failed!()
129
- ret.merge!(error_info(e))
130
- ensure
131
- #TODO: may mot be needed now switch to grit
132
- #git library sets these vars; so reseting here
133
- %w{GIT_DIR GIT_INDEX_FILE GIT_WORK_TREE}.each{|var|ENV[var]=nil}
134
- end
135
- ret
136
- end
137
-
138
- #
139
- # Keep in mind that if we are using default format of git url the name of repo is added after ':' symbol.
140
- # When using ssh style URL repo name is added after '/'
141
- def git_repo_full_url(git_url, repo_name)
142
- "#{git_url}/#{repo_name}"
143
- end
144
-
145
- # returns a trapped error
146
- def trap_and_return_error(&body)
147
- error = nil
148
- begin
149
- yield
150
- rescue => e
151
- error = e
152
- end
153
- error
154
- end
155
-
156
- def pull_module(repo_dir,branch,opts={})
157
- git_repo = ::DTK::NodeAgent::GitClient.new(repo_dir)
158
- git_repo.pull_and_checkout_branch?(branch,opts)
159
- end
160
-
161
- def clean_and_clone_module(repo_dir,remote_repo,branch,opts={})
162
- FileUtils.rm_rf repo_dir if File.exists?(repo_dir)
163
- git_repo = ::DTK::NodeAgent::GitClient.new(repo_dir,:create=>true)
164
- git_repo.clone_branch(remote_repo,branch,opts)
165
- end
166
-
167
- def run(request)
168
- cmps_with_attrs = request[:components_with_attributes]
169
- node_manifest = request[:node_manifest]
170
- inter_node_stage = request[:inter_node_stage]
171
- puppet_version = request[:puppet_version]
172
-
173
- if puppet_version
174
- @log.info("Setting user provided puppet version '#{puppet_version}'")
175
- puppet_version = "_#{puppet_version}_"
176
- end
177
-
178
- # Amar: Added task ID to current thread, so puppet apply can be canceled from puppet_cancel.rb when user requests cancel
179
- task_id = request[:top_task_id]
180
- Thread.current[:task_id] = task_id
181
- clean_state()
182
- ret = nil
183
- runtime_errors = nil # in contast to compile errors
184
- # TODO: harmonize request[:top_task_id] and top_task_id()
185
- dtk_puppet_cache = DTKPuppetCache.new(@service_name,top_task_id())
186
- log_file_path = dtk_puppet_cache.log_file_path(inter_node_stage)
187
- log_file = nil
188
- begin
189
- save_stderr = nil
190
- stderr_capture = nil
191
- log_file = File.open(log_file_path,"a")
192
- log_file.close
193
- Puppet[:autoflush] = true
194
- most_recent_link = puppet_last_log_link()
195
- ln_s(log_file_path,most_recent_link)
196
-
197
- # Amar: Node manifest contains list of generated puppet manifests
198
- # This is done to support multiple puppet calls inside one puppet_apply agent call
199
- node_manifest.each_with_index do |puppet_manifest, i|
200
- execute_lines = puppet_manifest || ret_execute_lines(cmps_with_attrs)
201
- execute_string = execute_lines.join("\n")
202
- @log.info("\n----------------execute_string------------\n#{execute_string}\n----------------execute_string------------")
203
- task_dir = dtk_puppet_cache.task_dir()
204
- # set the link to last_task
205
- ln_s(task_dir, dtk_puppet_cache.last_task_link())
206
-
207
- manifest_path = dtk_puppet_cache.node_manifest_path(inter_node_stage,i+1)
208
- File.open(manifest_path,"w"){|f| f << execute_string}
209
-
210
- cmd_line =
211
- [
212
- "apply",
213
- "-l", log_file_path,
214
- "-d",
215
- "--report", "true", "--reports", "r8report",
216
- #"--storeconfigs_backend", "r8_storeconfig_backend",
217
- "-e", execute_string
218
- ]
219
- cmd = "/usr/bin/puppet"
220
- save_stderr = $stderr
221
- stderr_capture = Tempfile.new("stderr")
222
- $stderr = stderr_capture
223
- begin
224
- Puppet::Node::Environment.clear()
225
- 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
226
- Puppet::Util::CommandLine.new(cmd,cmd_line).execute
227
- rescue SystemExit => exit
228
- report_status = Report::get_status()
229
- report_info = Report::get_report_info()
230
- # For multiple puppet calls, if one fails, rest will not get executed
231
- raise exit if report_status == :failed || report_info[:errors] || (i == node_manifest.size - 1)
232
- end
233
- end
234
- rescue SystemExit => exit
235
- report_status = Report::get_status()
236
- report_info = Report::get_report_info()
237
- exit_status = exit.status
238
- @log.info("exit.status = #{exit_status}")
239
- @log.info("report_status = #{report_status}")
240
- @log.info("report_info = #{report_info.inspect}")
241
- return_code = ((report_status == :failed || report_info[:errors]) ? 1 : exit_status)
242
- ret ||= Response.new()
243
- if return_code == 0
244
- if dynamic_attr_info = has_dynamic_attributes?(cmps_with_attrs)
245
- @log.info("dynamic_attributes = #{dynamic_attr_info.inspect}")
246
- process_dynamic_attributes!(ret,dynamic_attr_info)
247
- else
248
- ret.set_status_succeeded!()
249
- end
250
- else
251
- ret.set_status_failed!()
252
- error_info = {
253
- :return_code => return_code
254
- }
255
- if runtime_errors = (report_info||{})[:errors]
256
- error_info[:errors] = runtime_errors.map{|e|e.merge(:type => "user_error")}
257
- end
258
- ret.merge!(error_info)
259
- end
260
- rescue Exception => e
261
- log_error(e)
262
- ret ||= Response.new()
263
- ret.set_status_failed!()
264
- ret.merge!(error_info(e))
265
- ensure
266
- # Amar: If puppet_apply thread was killed from puppet_cancel, ':is_canceled' flag is set on the thread,
267
- # so puppet_apply can send status canceled in the response
268
- ret ||= Response.new()
269
- if Thread.current[:is_canceled]
270
- @log.info("Setting cancel status...")
271
- ret.set_status_canceled!()
272
- return set_reply!(ret)
273
- end
274
- if save_stderr #test if this is nil as to whether did the stderr swap
275
- $stderr = save_stderr
276
- stderr_capture.rewind
277
- stderr_msg = stderr_capture.read
278
- stderr_capture.close
279
- stderr_capture.unlink
280
- # dont look for compile errors if runtime errors
281
- unless runtime_errors
282
- if err_message = compile_error_message?(return_code,stderr_msg,log_file_path)
283
- ret[:errors] = [{:message => err_message, :type => "user_error" }]
284
- ret.set_status_failed!()
285
- Puppet::err stderr_msg
286
- Puppet::info "(end)"
287
- end
288
- end
289
- end
290
- Puppet::Util::Log.close_all()
291
- end
292
- @log.info("Debuging response from mcollective (RESPONSE):")
293
- @log.info(ret)
294
- ret
295
- end
296
-
297
- def compile_error_message?(return_code,stderr_msg,log_file_path)
298
- if stderr_msg and not stderr_msg.empty?
299
- stderr_msg
300
- elsif return_code != 0
301
- rest_reverse = Array.new
302
- error = nil
303
- begin
304
- File.open(log_file_path).read.split("\n").reverse_each do |line|
305
- if line =~ /^.+Puppet \(err\):\s*(.+$)/
306
- error = $1
307
- break
308
- else
309
- rest_reverse << line
310
- end
311
- end
312
- rescue
313
- end
314
- ([error || 'Puppet catalog compile error'] + rest_reverse.reverse).join("\n")
315
- end
316
- end
317
-
318
- def backtrace_subset(e)
319
- e.backtrace[0..10]
320
- end
321
-
322
- def log_error(e)
323
- log_error = ([e.inspect]+backtrace_subset(e)).join("\n")
324
- @log.info("\n----------------error-----\n#{log_error}\n----------------error-----")
325
- end
326
-
327
- def error_info(e,backtrace=nil)
328
- {
329
- :error => {
330
- :message => e.inspect,
331
- :backtrace => backtrace||backtrace_subset(e)
332
- }
333
- }
334
- end
335
-
336
- #TODO: cleanup fn; need to fix on serevr side; inconsient use of symbol and string keys
337
- #execute_lines
338
- def ret_execute_lines(cmps_with_attrs)
339
- ret = Array.new
340
- @import_statement_modules = Array.new
341
- cmps_with_attrs.each_with_index do |cmp_with_attrs,i|
342
- stage = i+1
343
- module_name = cmp_with_attrs["module_name"]
344
- ret << "stage{#{quote_form(stage)} :}"
345
- attrs = process_and_return_attr_name_val_pairs(cmp_with_attrs)
346
- stage_assign = "stage => #{quote_form(stage)}"
347
- case cmp_with_attrs["component_type"]
348
- when "class"
349
- cmp = cmp_with_attrs["name"]
350
- raise "No component name" unless cmp
351
- if imp_stmt = needs_import_statement?(cmp,module_name)
352
- ret << imp_stmt
353
- end
354
-
355
- #TODO: see if need \" and quote form
356
- attr_str_array = attrs.map{|k,v|"#{k} => #{process_val(v)}"} + [stage_assign]
357
- attr_str = attr_str_array.join(", ")
358
- ret << "class {\"#{cmp}\": #{attr_str}}"
359
- when "definition"
360
- defn = cmp_with_attrs["name"]
361
- raise "No definition name" unless defn
362
- name_attr = nil
363
- attr_str_array = attrs.map do |k,v|
364
- if k == "name"
365
- name_attr = quote_form(v)
366
- nil
367
- else
368
- "#{k} => #{process_val(v)}"
369
- end
370
- end.compact
371
- attr_str = attr_str_array.join(", ")
372
- raise "No name attribute for definition" unless name_attr
373
- if imp_stmt = needs_import_statement?(defn,module_name)
374
- ret << imp_stmt
375
- end
376
- #putting def in class because defs cannot go in stages
377
- class_wrapper = "stage#{stage.to_s}"
378
- ret << "class #{class_wrapper} {"
379
- ret << "#{defn} {#{name_attr}: #{attr_str}}"
380
- ret << "}"
381
- ret << "class {\"#{class_wrapper}\": #{stage_assign}}"
382
- end
383
- end
384
- size = cmps_with_attrs.size
385
- if size > 1
386
- ordering_statement = (1..cmps_with_attrs.size).map{|s|"Stage[#{s.to_s}]"}.join(" -> ")
387
- ret << ordering_statement
388
- end
389
-
390
- if attr_val_stmts = get_attr_val_statements(cmps_with_attrs)
391
- ret += attr_val_stmts
392
- end
393
- ret
394
- end
395
-
396
- #removes imported collections and puts them on global array
397
- def process_and_return_attr_name_val_pairs(cmp_with_attrs)
398
- ret = Hash.new
399
- return ret unless attrs = cmp_with_attrs["attributes"]
400
- cmp_name = cmp_with_attrs["name"]
401
- attrs.each do |attr_info|
402
- attr_name = attr_info["name"]
403
- val = attr_info["value"]
404
- case attr_info["type"]
405
- when "attribute"
406
- ret[attr_name] = val
407
- when "imported_collection"
408
- add_imported_collection(cmp_name,attr_name,val,{"resource_type" => attr_info["resource_type"], "import_coll_query" => attr_info["import_coll_query"]})
409
- else raise "unexpected attribute type (#{attr_info["type"]})"
410
- end
411
- end
412
- ret
413
- end
414
-
415
- def get_attr_val_statements(cmps_with_attrs)
416
- ret = Array.new
417
- cmps_with_attrs.each do |cmp_with_attrs|
418
- (cmp_with_attrs["dynamic_attributes"]||[]).each do |dyn_attr|
419
- if dyn_attr[:type] == "default_variable"
420
- qualified_var = "#{cmp_with_attrs["name"]}::#{dyn_attr[:name]}"
421
- ret << "r8::export_variable{'#{qualified_var}' :}"
422
- end
423
- end
424
- end
425
- ret.empty? ? nil : ret
426
- end
427
-
428
-
429
- def needs_import_statement?(cmp_or_def,module_name)
430
- return nil if cmp_or_def =~ /::/
431
- return nil if @import_statement_modules.include?(module_name)
432
- @import_statement_modules << module_name
433
- "import '#{module_name}'"
434
- end
435
-
436
- def process_val(val)
437
- #a guarded val
438
- if val.kind_of?(Hash) and val.size == 1 and val.keys.first == "__ref"
439
- "$#{val.values.join("::")}"
440
- else
441
- quote_form(val)
442
- end
443
- end
444
-
445
- def has_dynamic_attributes?(cmps_with_attrs)
446
- ret = cmps_with_attrs.map do |cmp_with_attrs|
447
- dyn_attrs = cmp_with_attrs["dynamic_attributes"]||[]
448
- if !dyn_attrs.empty?
449
- {
450
- :cmp_ref => component_ref(cmp_with_attrs),
451
- :dynamic_attrs => dyn_attrs
452
- }
453
- end
454
- end.compact
455
- !ret.empty? && ret
456
- end
457
-
458
- def process_dynamic_attributes!(ret,dynamic_attr_info)
459
- dyn_attr_assigns = Array.new
460
- missing_dyn_attrs = Array.new
461
- dynamic_attr_info.each do |info|
462
- cmp_ref = info[:cmp_ref]
463
- info[:dynamic_attrs].each do |dyn_attr|
464
- if dyn_attr_assign = dynamic_attr_response_el(cmp_ref,dyn_attr)
465
- dyn_attr_assigns << dyn_attr_assign
466
- else
467
- missing_attr = {
468
- :cmp_ref => cmp_ref,
469
- :attr => dyn_attr[:name]
470
- }
471
- missing_dyn_attrs << missing_attr
472
- end
473
- end
474
- end
475
- if missing_dyn_attrs.empty?
476
- ret.set_dynamic_attributes!(dyn_attr_assigns)
477
- ret.set_status_succeeded!()
478
- else
479
- set_error_missing_dynamic_attrs!(ret,missing_dyn_attrs)
480
- ret.set_status_failed!()
481
- end
482
- end
483
-
484
- def set_error_missing_dynamic_attrs!(ret,missing_dyn_attrs)
485
- errors = missing_dyn_attrs.map do |info|
486
- err_message = "Dynamic Attribute (#{info[:attr]}) is not set by component (#{info[:cmp_ref]})"
487
- {
488
- :message => err_message,
489
- :type => "user_error"
490
- }
491
- end
492
- error_info = {
493
- :return_code => 1,
494
- :errors => errors
495
- }
496
- ret.merge!(error_info)
497
- end
498
-
499
- def dynamic_attr_response_el(cmp_name,dyn_attr)
500
- ret = nil
501
- val =
502
- if dyn_attr[:type] == "exported_resource"
503
- dynamic_attr_response_el__exported_resource(cmp_name,dyn_attr)
504
- elsif dyn_attr[:type] == "default_variable"
505
- dynamic_attr_response_el__default_attribute(cmp_name,dyn_attr)
506
- else #assumption only three types: "exported_resource", "default_attribute, (and other can by "dynamic")
507
- dynamic_attr_response_el__default_attribute(cmp_name,dyn_attr)||dynamic_attr_response_el__dynamic(cmp_name,dyn_attr)
508
- end
509
- if val
510
- ret = {
511
- :component_name => cmp_name,
512
- :attribute_name => dyn_attr[:name],
513
- :attribute_id => dyn_attr[:id],
514
- :attribute_val => val
515
- }
516
- end
517
- ret
518
- end
519
-
520
- def dynamic_attr_response_el__exported_resource(cmp_name,dyn_attr)
521
- ret = nil
522
- if cmp_exp_rscs = exported_resources(cmp_name)
523
- cmp_exp_rscs.each do |title,val|
524
- return val if exp_rsc_match(title,dyn_attr[:title_with_vars])
525
- end
526
- else
527
- @log.info("no exported resources set for component #{cmp_name}")
528
- end
529
- ret
530
- end
531
-
532
- #TODO: more sophistiacted would take var bindings
533
- def exp_rsc_match(title,title_with_vars)
534
- regexp_str = regexp_string(title_with_vars)
535
- @log.info("debug: regexp_str = #{regexp_str}")
536
- title =~ Regexp.new("^#{regexp_str}$") if regexp_str
537
- end
538
-
539
- def regexp_string(title_with_vars)
540
- if title_with_vars.kind_of?(Array)
541
- case title_with_vars.first
542
- when "variable" then ".+"
543
- when "fn" then regexp_string__when_op(title_with_vars)
544
- else
545
- @log.info("unexpected first element in title with vars (#{title_with_vars.first})")
546
- nil
547
- end
548
- else
549
- title_with_vars.gsub(".","\\.")
550
- end
551
- end
552
-
553
- def regexp_string__when_op(title_with_vars)
554
- unless title_with_vars[1] == "concat"
555
- @log.info("not treating operation (#{title_with_vars[1]})")
556
- return nil
557
- end
558
- title_with_vars[2..title_with_vars.size-1].map do |x|
559
- return nil unless re = regexp_string(x)
560
- re
561
- end.join("")
562
- end
563
-
564
- def dynamic_attr_response_el__dynamic(cmp_name,dyn_attr)
565
- ret = nil
566
- attr_name = dyn_attr[:name]
567
- filepath = (exported_files(cmp_name)||{})[attr_name]
568
- #TODO; legacy; remove when deprecate
569
- filepath ||= "/tmp/#{cmp_name.gsub(/::/,".")}.#{attr_name}"
570
- begin
571
- val = File.open(filepath){|f|f.read}.chomp
572
- ret = val unless val.empty?
573
- rescue Exception
574
- end
575
- ret
576
- end
577
-
578
- def dynamic_attr_response_el__default_attribute(cmp_name,dyn_attr)
579
- ret = nil
580
- unless cmp_exp_vars = exported_variables(cmp_name)
581
- @log.info("no exported varaibles for component #{cmp_name}")
582
- return ret
583
- end
584
-
585
- attr_name = dyn_attr[:name]
586
- unless cmp_exp_vars.has_key?(attr_name)
587
- @log.info("no exported variable entry for component #{cmp_name}, attribute #{dyn_attr[:name]})")
588
- return ret
589
- end
590
-
591
- cmp_exp_vars[attr_name]
592
- end
593
-
594
- def clean_state()
595
- [:exported_resources, :exported_variables, :report_status, :imported_collections].each do |k|
596
- Thread.current[k] = nil if Thread.current.keys.include?(k)
597
- end
598
- end
599
- def exported_resources(cmp_name)
600
- (Thread.current[:exported_resources]||{})[cmp_name]
601
- end
602
- def exported_variables(cmp_name)
603
- (Thread.current[:exported_variables]||{})[cmp_name]
604
- end
605
- def exported_files(cmp_name)
606
- (Thread.current[:exported_files]||{})[cmp_name]
607
- end
608
- def add_imported_collection(cmp_name,attr_name,val,context={})
609
- p = (Thread.current[:imported_collections] ||= Hash.new)[cmp_name] ||= Hash.new
610
- p[attr_name] = {"value" => val}.merge(context)
611
- end
612
-
613
- def component_ref(cmp_with_attrs)
614
- case cmp_with_attrs["component_type"]
615
- when "class"
616
- cmp_with_attrs["name"]
617
- when "definition"
618
- defn = cmp_with_attrs["name"]
619
- unless name_attr = cmp_with_attrs["attributes"].find{|attr|attr["name"] == "name"}
620
- raise "Cannot find the name associated with definition #{defn}"
621
- end
622
- "#{cmp_with_attrs["name"]}[#{name_attr["value"]}]"
623
- else
624
- raise "Reference to type #{cmp_with_attrs["component_type"]} not treated"
625
- end
626
- end
627
-
628
- def self.capitalize_resource_name(name)
629
- name.split('::').map{|p|p.capitalize}.join("::")
630
- end
631
- def capitalize_resource_name(name)
632
- self.class.capitalize_resource_name(name)
633
- end
634
-
635
- DynamicVarDefName = "r8_dynamic_vars::set_var"
636
- DynamicVarDefNameRN = capitalize_resource_name(DynamicVarDefName)
637
-
638
- def quote_form(obj)
639
- if obj.kind_of?(Hash)
640
- "{#{obj.map{|k,v|"#{quote_form(k)} => #{quote_form(v)}"}.join(",")}}"
641
- elsif obj.kind_of?(Array)
642
- "[#{obj.map{|el|quote_form(el)}.join(",")}]"
643
- elsif obj.kind_of?(String)
644
- "\"#{obj}\""
645
- elsif obj.nil?
646
- "nil"
647
- else
648
- obj.to_s
649
- end
650
- end
651
-
652
- def set_reply!(response)
653
- reply.data = @reply_data = response.to_hash
654
- end
655
- def set_reply?(response)
656
- reply.data = @reply_data ||= response.to_hash
657
- end
658
- def log_params()
659
- @log.info("params: #{request.data.inspect}")
660
- end
661
-
662
- def puppet_last_log_link()
663
- "#{PuppetApplyLogDir}/last.log"
664
- end
665
- def id_info()
666
- [:msg_id,:task_id,:top_task_id].map do |k|
667
- if @task_info.has_key?(k)
668
- "#{k}:#{@task_info[k].to_s}"
669
- end
670
- end.compact.join(":")
671
- end
672
- def top_task_id()
673
- "task_id_#{@task_info[:top_task_id] || @task_info[:task_id] || 'task' }"
674
- end
675
-
676
- def ln_s(target,link)
677
- File.delete(link) if File.exists? link
678
- FileUtils.ln_s(target,link,:force => true)
679
- end
680
-
681
- class DTKPuppetCache
682
- BaseDir = DTKPuppetCacheBaseDir
683
- def initialize(service_name,top_task_id)
684
- @service_name = service_name
685
- @top_task_id = top_task_id
686
- end
687
-
688
- def task_dir()
689
- @task_dir ||= mkdir_p("#{base_dir()}/#{@service_name}/#{@top_task_id}")
690
- end
691
-
692
- def log_file_path(stage)
693
- "#{task_dir()}/stage-#{stage}-puppet.log"
694
- end
695
- def node_manifest_path(stage,invocation)
696
- "#{task_dir()}/site-stage-#{stage}-invocation-#{invocation}.pp"
697
- end
698
-
699
- def last_task_link()
700
- "#{base_dir()}/last-task"
701
- end
702
-
703
- private
704
- def base_dir()
705
- @base_dir ||= mkdir_p(BaseDir)
706
- end
707
-
708
- def mkdir_p(dir_path)
709
- FileUtils.mkdir_p(dir_path)
710
- dir_path
711
- end
712
- end
713
-
714
- #TODO: this should be common accross Agents
715
- class Response < Hash
716
- def initialize(hash={})
717
- super()
718
- self.merge!(hash)
719
- self[:status] = :unknown unless hash.has_key?(:status)
720
- end
721
-
722
- def to_hash()
723
- Hash.new.merge(self)
724
- end
725
-
726
- def failed?()
727
- self[:status] == :failed
728
- end
729
-
730
- def set_status_failed!()
731
- self[:status] = :failed
732
- end
733
- def set_status_succeeded!()
734
- self[:status] = :succeeded
735
- end
736
- def set_status_canceled!()
737
- self[:status] = :canceled
738
- end
739
- def set_dynamic_attributes!(dynamic_attributes)
740
- self[:dynamic_attributes] = dynamic_attributes
741
- end
742
- end
743
- class ResponseFailed < Response
744
- def initialize(error,info={})
745
- super({:status => :failed, :error => error}.merge(info))
746
- end
747
- end
748
- class ResponseSucceeded < Response
749
- def initialize(info={})
750
- super({:status => :succeeded}.merge(info))
751
- end
752
- end
753
- end
754
- end
755
-
756
- class Report
757
- def self.set_status(status)
758
- Thread.current[:report_status] = status.to_sym
759
- end
760
- def self.get_status()
761
- Thread.current[:report_status] || :failed
762
- end
763
- def self.set_report_info(report_info)
764
- Thread.current[:report_info] = report_info
765
- end
766
- def self.get_report_info()
767
- Thread.current[:report_info]||{}
768
- end
769
- end
770
- end
771
-
772
- #below is more complicated to allow reloading
773
- if Puppet::Reports.constants.include?('R8report')
774
- Puppet::Reports.send(:remove_const,:R8report)
775
- end
776
- #TODO: needed to pass {:overwrite => true} to Puppet::Reports.genmodule so expanded def Puppet::Reports.register_report(:r8report)
777
- def register_report(name,&block)
778
- name = name.intern
779
- mod = Puppet::Reports.genmodule(name, :overwrite=> true,:extend => Puppet::Util::Docs, :hash => Puppet::Reports.instance_hash(:report), :block => block)
780
- mod.send(:define_method, :report_name) do
781
- name
782
- end
783
- end
784
- register_report(:r8report) do
785
- desc "report for R8 agent"
786
-
787
- def process
788
- MCollective::Report.set_status(status)
789
- report_info = Hash.new
790
- errors = logs.select{|log_el|log_el.level == :err}
791
- unless errors.empty?
792
- report_info[:errors] = errors.map do |err|
793
- {
794
- "message" => err.message,
795
- "source" => err.source,
796
- "tags" => err.tags,
797
- "time" => err.time
798
- }
799
- end
800
- end
801
- MCollective::Report.set_report_info(report_info)
802
- self
803
- end
804
- end
805
-
806
- class Puppet::Settings
807
- def initialize_global_settings(args = [])
808
- #raise Puppet::DevError, "Attempting to initialize global default settings more than once!" if global_defaults_initialized?
809
- return if global_defaults_initialized?
810
- # The first two phases of the lifecycle of a puppet application are:
811
- # 1) Parse the command line options and handle any of them that are
812
- # registered, defined "global" puppet settings (mostly from defaults.rb).
813
- # 2) Parse the puppet config file(s).
814
- parse_global_options(args)
815
- parse_config_files
816
- @global_defaults_initialized = true
817
- end
818
- end