mcollective-client 1.3.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mcollective-client might be problematic. Click here for more details.

Files changed (103) hide show
  1. data/bin/mc-call-agent +54 -0
  2. data/bin/mco +27 -0
  3. data/lib/mcollective.rb +70 -0
  4. data/lib/mcollective/agents.rb +160 -0
  5. data/lib/mcollective/application.rb +354 -0
  6. data/lib/mcollective/applications.rb +145 -0
  7. data/lib/mcollective/client.rb +292 -0
  8. data/lib/mcollective/config.rb +202 -0
  9. data/lib/mcollective/connector.rb +18 -0
  10. data/lib/mcollective/connector/base.rb +24 -0
  11. data/lib/mcollective/facts.rb +39 -0
  12. data/lib/mcollective/facts/base.rb +86 -0
  13. data/lib/mcollective/log.rb +103 -0
  14. data/lib/mcollective/logger.rb +5 -0
  15. data/lib/mcollective/logger/base.rb +73 -0
  16. data/lib/mcollective/logger/console_logger.rb +61 -0
  17. data/lib/mcollective/logger/file_logger.rb +46 -0
  18. data/lib/mcollective/logger/syslog_logger.rb +53 -0
  19. data/lib/mcollective/matcher.rb +16 -0
  20. data/lib/mcollective/matcher/parser.rb +93 -0
  21. data/lib/mcollective/matcher/scanner.rb +123 -0
  22. data/lib/mcollective/message.rb +201 -0
  23. data/lib/mcollective/monkey_patches.rb +104 -0
  24. data/lib/mcollective/optionparser.rb +164 -0
  25. data/lib/mcollective/pluginmanager.rb +180 -0
  26. data/lib/mcollective/pluginpackager.rb +26 -0
  27. data/lib/mcollective/pluginpackager/agent_definition.rb +79 -0
  28. data/lib/mcollective/pluginpackager/standard_definition.rb +59 -0
  29. data/lib/mcollective/registration.rb +16 -0
  30. data/lib/mcollective/registration/base.rb +75 -0
  31. data/lib/mcollective/rpc.rb +188 -0
  32. data/lib/mcollective/rpc/actionrunner.rb +142 -0
  33. data/lib/mcollective/rpc/agent.rb +441 -0
  34. data/lib/mcollective/rpc/audit.rb +38 -0
  35. data/lib/mcollective/rpc/client.rb +793 -0
  36. data/lib/mcollective/rpc/ddl.rb +258 -0
  37. data/lib/mcollective/rpc/helpers.rb +339 -0
  38. data/lib/mcollective/rpc/progress.rb +63 -0
  39. data/lib/mcollective/rpc/reply.rb +61 -0
  40. data/lib/mcollective/rpc/request.rb +51 -0
  41. data/lib/mcollective/rpc/result.rb +41 -0
  42. data/lib/mcollective/rpc/stats.rb +185 -0
  43. data/lib/mcollective/runnerstats.rb +90 -0
  44. data/lib/mcollective/security.rb +26 -0
  45. data/lib/mcollective/security/base.rb +237 -0
  46. data/lib/mcollective/shell.rb +87 -0
  47. data/lib/mcollective/ssl.rb +246 -0
  48. data/lib/mcollective/unix_daemon.rb +37 -0
  49. data/lib/mcollective/util.rb +274 -0
  50. data/lib/mcollective/vendor.rb +41 -0
  51. data/lib/mcollective/vendor/require_vendored.rb +2 -0
  52. data/lib/mcollective/windows_daemon.rb +25 -0
  53. data/spec/Rakefile +16 -0
  54. data/spec/fixtures/application/test.rb +7 -0
  55. data/spec/fixtures/test-cert.pem +15 -0
  56. data/spec/fixtures/test-private.pem +15 -0
  57. data/spec/fixtures/test-public.pem +6 -0
  58. data/spec/monkey_patches/instance_variable_defined.rb +7 -0
  59. data/spec/spec.opts +1 -0
  60. data/spec/spec_helper.rb +25 -0
  61. data/spec/unit/agents_spec.rb +280 -0
  62. data/spec/unit/application_spec.rb +636 -0
  63. data/spec/unit/applications_spec.rb +155 -0
  64. data/spec/unit/array.rb +30 -0
  65. data/spec/unit/config_spec.rb +148 -0
  66. data/spec/unit/facts/base_spec.rb +118 -0
  67. data/spec/unit/facts_spec.rb +39 -0
  68. data/spec/unit/log_spec.rb +71 -0
  69. data/spec/unit/logger/base_spec.rb +110 -0
  70. data/spec/unit/logger/syslog_logger_spec.rb +86 -0
  71. data/spec/unit/matcher/parser_spec.rb +106 -0
  72. data/spec/unit/matcher/scanner_spec.rb +71 -0
  73. data/spec/unit/message_spec.rb +401 -0
  74. data/spec/unit/optionparser_spec.rb +113 -0
  75. data/spec/unit/pluginmanager_spec.rb +173 -0
  76. data/spec/unit/pluginpackager/agent_definition_spec.rb +130 -0
  77. data/spec/unit/pluginpackager/standard_definition_spec.rb +75 -0
  78. data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +533 -0
  79. data/spec/unit/plugins/mcollective/connector/stomp/eventlogger_spec.rb +34 -0
  80. data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +417 -0
  81. data/spec/unit/plugins/mcollective/packagers/ospackage_spec.rb +229 -0
  82. data/spec/unit/plugins/mcollective/security/psk_spec.rb +156 -0
  83. data/spec/unit/registration/base_spec.rb +77 -0
  84. data/spec/unit/rpc/actionrunner_spec.rb +213 -0
  85. data/spec/unit/rpc/agent_spec.rb +155 -0
  86. data/spec/unit/rpc/client_spec.rb +523 -0
  87. data/spec/unit/rpc/ddl_spec.rb +388 -0
  88. data/spec/unit/rpc/helpers_spec.rb +55 -0
  89. data/spec/unit/rpc/reply_spec.rb +143 -0
  90. data/spec/unit/rpc/request_spec.rb +115 -0
  91. data/spec/unit/rpc/result_spec.rb +66 -0
  92. data/spec/unit/rpc/stats_spec.rb +288 -0
  93. data/spec/unit/runnerstats_spec.rb +40 -0
  94. data/spec/unit/security/base_spec.rb +279 -0
  95. data/spec/unit/shell_spec.rb +144 -0
  96. data/spec/unit/ssl_spec.rb +244 -0
  97. data/spec/unit/symbol.rb +11 -0
  98. data/spec/unit/unix_daemon.rb +41 -0
  99. data/spec/unit/util_spec.rb +342 -0
  100. data/spec/unit/vendor_spec.rb +34 -0
  101. data/spec/unit/windows_daemon.rb +43 -0
  102. data/spec/windows_spec.opts +1 -0
  103. metadata +242 -0
@@ -0,0 +1,145 @@
1
+ module MCollective
2
+ class Applications
3
+ def self.[](appname)
4
+ load_application(appname)
5
+ PluginManager["#{appname}_application"]
6
+ end
7
+
8
+ def self.run(appname)
9
+ load_config
10
+
11
+ begin
12
+ load_application(appname)
13
+ rescue Exception => e
14
+ e.backtrace.first << RPC::Helpers.colorize(:red, " <----")
15
+ STDERR.puts "Application '#{appname}' failed to load:"
16
+ STDERR.puts
17
+ STDERR.puts RPC::Helpers.colorize(:red, " #{e} (#{e.class})")
18
+ STDERR.puts
19
+ STDERR.puts " %s" % [e.backtrace.join("\n ")]
20
+ exit 1
21
+ end
22
+
23
+ PluginManager["#{appname}_application"].run
24
+ end
25
+
26
+ def self.load_application(appname)
27
+ return if PluginManager.include?("#{appname}_application")
28
+
29
+ load_config
30
+
31
+ PluginManager.loadclass "MCollective::Application::#{appname.capitalize}"
32
+ PluginManager << {:type => "#{appname}_application", :class => "MCollective::Application::#{appname.capitalize}"}
33
+ end
34
+
35
+ # Returns an array of applications found in the lib dirs
36
+ def self.list
37
+ load_config
38
+
39
+ applist = []
40
+
41
+ Config.instance.libdir.each do |libdir|
42
+ applicationdir = "#{libdir}/mcollective/application"
43
+ next unless File.directory?(applicationdir)
44
+
45
+ Dir.entries(applicationdir).grep(/\.rb$/).each do |application|
46
+ applist << File.basename(application, ".rb")
47
+ end
48
+ end
49
+
50
+ applist
51
+ rescue SystemExit
52
+ exit 1
53
+ rescue Exception => e
54
+ STDERR.puts "Failed to generate application list: #{e.class}: #{e}"
55
+ exit 1
56
+ end
57
+
58
+ # Filters a string of opts out using Shellwords
59
+ # keeping only things related to --config and -c
60
+ def self.filter_extra_options(opts)
61
+ res = ""
62
+ words = Shellwords.shellwords(opts)
63
+ words.each_with_index do |word,idx|
64
+ if word == "-c"
65
+ return "--config=#{words[idx + 1]}"
66
+ elsif word == "--config"
67
+ return "--config=#{words[idx + 1]}"
68
+ elsif word =~ /\-c=/
69
+ return word
70
+ elsif word =~ /\-\-config=/
71
+ return word
72
+ end
73
+ end
74
+
75
+ return ""
76
+ end
77
+
78
+ # We need to know the config file in order to know the libdir
79
+ # so that we can find applications.
80
+ #
81
+ # The problem is the CLI might be stuffed with options only the
82
+ # app in the libdir might understand so we have a chicken and
83
+ # egg situation.
84
+ #
85
+ # We're parsing and filtering MCOLLECTIVE_EXTRA_OPTS removing
86
+ # all but config related options and parsing the options looking
87
+ # just for the config file.
88
+ #
89
+ # We're handling failures gracefully and finally restoring the
90
+ # ARG and MCOLLECTIVE_EXTRA_OPTS to the state they were before
91
+ # we started parsing.
92
+ #
93
+ # This is mostly a hack, when we're redoing how config works
94
+ # this stuff should be made less sucky
95
+ def self.load_config
96
+ return if Config.instance.configured
97
+
98
+ original_argv = ARGV.clone
99
+ original_extra_opts = ENV["MCOLLECTIVE_EXTRA_OPTS"].clone rescue nil
100
+ configfile = nil
101
+
102
+ parser = OptionParser.new
103
+ parser.on("--config CONFIG", "-c", "Config file") do |f|
104
+ configfile = f
105
+ end
106
+
107
+ parser.program_name = $0
108
+
109
+ parser.on("--help")
110
+
111
+ # avoid option parsers own internal version handling that sux
112
+ parser.on("-v", "--verbose")
113
+
114
+ if original_extra_opts
115
+ begin
116
+ # optparse will parse the whole ENV in one go and refuse
117
+ # to play along with the retry trick I do below so in
118
+ # order to handle unknown options properly I parse out
119
+ # only -c and --config deleting everything else and
120
+ # then restore the environment variable later when I
121
+ # am done with it
122
+ ENV["MCOLLECTIVE_EXTRA_OPTS"] = filter_extra_options(ENV["MCOLLECTIVE_EXTRA_OPTS"].clone)
123
+ parser.environment("MCOLLECTIVE_EXTRA_OPTS")
124
+ rescue Exception => e
125
+ Log.error("Failed to parse MCOLLECTIVE_EXTRA_OPTS: #{e}")
126
+ end
127
+
128
+ ENV["MCOLLECTIVE_EXTRA_OPTS"] = original_extra_opts.clone
129
+ end
130
+
131
+ begin
132
+ parser.parse!
133
+ rescue OptionParser::InvalidOption => e
134
+ retry
135
+ end
136
+
137
+ ARGV.clear
138
+ original_argv.each {|a| ARGV << a}
139
+
140
+ configfile = Util.config_file_for_user unless configfile
141
+
142
+ Config.instance.loadconfig(configfile)
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,292 @@
1
+ module MCollective
2
+ # Helpers for writing clients that can talk to agents, do discovery and so forth
3
+ class Client
4
+ attr_accessor :options, :stats
5
+
6
+ def initialize(configfile)
7
+ @config = Config.instance
8
+ @config.loadconfig(configfile) unless @config.configured
9
+
10
+ @connection = PluginManager["connector_plugin"]
11
+ @security = PluginManager["security_plugin"]
12
+
13
+ @security.initiated_by = :client
14
+ @options = nil
15
+ @subscriptions = {}
16
+
17
+ @connection.connect
18
+ end
19
+
20
+ # Returns the configured main collective if no
21
+ # specific collective is specified as options
22
+ def collective
23
+ if @options[:collective].nil?
24
+ @config.main_collective
25
+ else
26
+ @options[:collective]
27
+ end
28
+ end
29
+
30
+ # Disconnects cleanly from the middleware
31
+ def disconnect
32
+ Log.debug("Disconnecting from the middleware")
33
+ @connection.disconnect
34
+ end
35
+
36
+ # Sends a request and returns the generated request id, doesn't wait for
37
+ # responses and doesn't execute any passed in code blocks for responses
38
+ def sendreq(msg, agent, filter = {})
39
+ if msg.is_a?(Message)
40
+ request = msg
41
+ agent = request.agent
42
+ else
43
+ ttl = @options[:ttl] || @config.ttl
44
+ request = Message.new(msg, nil, {:agent => agent, :type => :request, :collective => collective, :filter => filter, :ttl => ttl})
45
+ request.reply_to = @options[:reply_to] if @options[:reply_to]
46
+ end
47
+
48
+ request.encode!
49
+
50
+ Log.debug("Sending request #{request.requestid} to the #{request.agent} agent with ttl #{request.ttl} in collective #{request.collective}")
51
+
52
+ subscribe(agent, :reply)
53
+
54
+ request.publish
55
+
56
+ request.requestid
57
+ end
58
+
59
+ def subscribe(agent, type)
60
+ unless @subscriptions.include?(agent)
61
+ subscription = Util.make_subscriptions(agent, type, collective)
62
+ Log.debug("Subscribing to #{type} target for agent #{agent}")
63
+
64
+ Util.subscribe(subscription)
65
+ @subscriptions[agent] = 1
66
+ end
67
+ end
68
+
69
+ def unsubscribe(agent, type)
70
+ if @subscriptions.include?(agent)
71
+ subscription = Util.make_subscriptions(agent, type, collective)
72
+ Log.debug("Unsubscribing #{type} target for #{agent}")
73
+
74
+ Util.unsubscribe(subscription)
75
+ @subscriptions.delete(agent)
76
+ end
77
+ end
78
+ # Blocking call that waits for ever for a message to arrive.
79
+ #
80
+ # If you give it a requestid this means you've previously send a request
81
+ # with that ID and now you just want replies that matches that id, in that
82
+ # case the current connection will just ignore all messages not directed at it
83
+ # and keep waiting for more till it finds a matching message.
84
+ def receive(requestid = nil)
85
+ reply = nil
86
+
87
+ begin
88
+ reply = @connection.receive
89
+ reply.type = :reply
90
+ reply.expected_msgid = requestid
91
+
92
+ reply.decode!
93
+
94
+ reply.payload[:senderid] = Digest::MD5.hexdigest(reply.payload[:senderid]) if ENV.include?("MCOLLECTIVE_ANON")
95
+
96
+ raise(MsgDoesNotMatchRequestID, "Message reqid #{requestid} does not match our reqid #{reply.requestid}") unless reply.requestid == requestid
97
+ rescue SecurityValidationFailed => e
98
+ Log.warn("Ignoring a message that did not pass security validations")
99
+ retry
100
+ rescue MsgDoesNotMatchRequestID => e
101
+ Log.debug("Ignoring a message for some other client")
102
+ retry
103
+ end
104
+
105
+ reply
106
+ end
107
+
108
+ # Performs a discovery of nodes matching the filter passed
109
+ # returns an array of nodes
110
+ #
111
+ # An integer limit can be supplied this will have the effect
112
+ # of the discovery being cancelled soon as it reached the
113
+ # requested limit of hosts
114
+ def discover(filter, timeout, limit=0)
115
+ raise "Limit has to be an integer" unless limit.is_a?(Fixnum)
116
+
117
+ begin
118
+ hosts = []
119
+ Timeout.timeout(timeout) do
120
+ reqid = sendreq("ping", "discovery", filter)
121
+ Log.debug("Waiting #{timeout} seconds for discovery replies to request #{reqid}")
122
+
123
+ loop do
124
+ reply = receive(reqid)
125
+ Log.debug("Got discovery reply from #{reply.payload[:senderid]}")
126
+ hosts << reply.payload[:senderid]
127
+
128
+ return hosts if limit > 0 && hosts.size == limit
129
+ end
130
+ end
131
+ rescue Timeout::Error => e
132
+ rescue Exception => e
133
+ raise
134
+ ensure
135
+ unsubscribe("discovery", :reply)
136
+ end
137
+
138
+ hosts.sort
139
+ end
140
+
141
+ # Send a request, performs the passed block for each response
142
+ #
143
+ # times = req("status", "mcollectived", options, client) {|resp|
144
+ # pp resp
145
+ # }
146
+ #
147
+ # It returns a hash of times and timeouts for discovery and total run is taken from the options
148
+ # hash which in turn is generally built using MCollective::Optionparser
149
+ def req(body, agent=nil, options=false, waitfor=0)
150
+ if body.is_a?(Message)
151
+ agent = body.agent
152
+ options = body.options
153
+ waitfor = body.discovered_hosts.size || 0
154
+ end
155
+
156
+ stat = {:starttime => Time.now.to_f, :discoverytime => 0, :blocktime => 0, :totaltime => 0}
157
+
158
+ options = @options unless options
159
+
160
+ STDOUT.sync = true
161
+
162
+ hosts_responded = 0
163
+
164
+ begin
165
+ Timeout.timeout(options[:timeout]) do
166
+ reqid = sendreq(body, agent, options[:filter])
167
+
168
+ loop do
169
+ resp = receive(reqid)
170
+
171
+ hosts_responded += 1
172
+
173
+ yield(resp.payload)
174
+
175
+ break if (waitfor != 0 && hosts_responded >= waitfor)
176
+ end
177
+ end
178
+ rescue Interrupt => e
179
+ rescue Timeout::Error => e
180
+ ensure
181
+ unsubscribe(agent, :reply)
182
+ end
183
+
184
+ stat[:totaltime] = Time.now.to_f - stat[:starttime]
185
+ stat[:blocktime] = stat[:totaltime] - stat[:discoverytime]
186
+ stat[:responses] = hosts_responded
187
+ stat[:noresponsefrom] = []
188
+
189
+ @stats = stat
190
+ return stat
191
+ end
192
+
193
+ # Performs a discovery and then send a request, performs the passed block for each response
194
+ #
195
+ # times = discovered_req("status", "mcollectived", options, client) {|resp|
196
+ # pp resp
197
+ # }
198
+ #
199
+ # It returns a hash of times and timeouts for discovery and total run is taken from the options
200
+ # hash which in turn is generally built using MCollective::Optionparser
201
+ def discovered_req(body, agent, options=false)
202
+ stat = {:starttime => Time.now.to_f, :discoverytime => 0, :blocktime => 0, :totaltime => 0}
203
+
204
+ options = @options unless options
205
+
206
+ STDOUT.sync = true
207
+
208
+ print("Determining the amount of hosts matching filter for #{options[:disctimeout]} seconds .... ")
209
+
210
+ begin
211
+ discovered_hosts = discover(options[:filter], options[:disctimeout])
212
+ discovered = discovered_hosts.size
213
+ hosts_responded = []
214
+ hosts_not_responded = discovered_hosts
215
+
216
+ stat[:discoverytime] = Time.now.to_f - stat[:starttime]
217
+
218
+ puts("#{discovered}\n\n")
219
+ rescue Interrupt
220
+ puts("Discovery interrupted.")
221
+ exit!
222
+ end
223
+
224
+ raise("No matching clients found") if discovered == 0
225
+
226
+ begin
227
+ Timeout.timeout(options[:timeout]) do
228
+ reqid = sendreq(body, agent, options[:filter])
229
+
230
+ (1..discovered).each do |c|
231
+ resp = receive(reqid)
232
+
233
+ hosts_responded << resp.payload[:senderid]
234
+ hosts_not_responded.delete(resp.payload[:senderid]) if hosts_not_responded.include?(resp.payload[:senderid])
235
+
236
+ yield(resp.payload)
237
+ end
238
+ end
239
+ rescue Interrupt => e
240
+ rescue Timeout::Error => e
241
+ end
242
+
243
+ stat[:totaltime] = Time.now.to_f - stat[:starttime]
244
+ stat[:blocktime] = stat[:totaltime] - stat[:discoverytime]
245
+ stat[:responses] = hosts_responded.size
246
+ stat[:responsesfrom] = hosts_responded
247
+ stat[:noresponsefrom] = hosts_not_responded
248
+ stat[:discovered] = discovered
249
+
250
+ @stats = stat
251
+ return stat
252
+ end
253
+
254
+ # Prints out the stats returns from req and discovered_req in a nice way
255
+ def display_stats(stats, options=false, caption="stomp call summary")
256
+ options = @options unless options
257
+
258
+ if options[:verbose]
259
+ puts("\n---- #{caption} ----")
260
+
261
+ if stats[:discovered]
262
+ puts(" Nodes: #{stats[:discovered]} / #{stats[:responses]}")
263
+ else
264
+ puts(" Nodes: #{stats[:responses]}")
265
+ end
266
+
267
+ printf(" Start Time: %s\n", Time.at(stats[:starttime]))
268
+ printf(" Discovery Time: %.2fms\n", stats[:discoverytime] * 1000)
269
+ printf(" Agent Time: %.2fms\n", stats[:blocktime] * 1000)
270
+ printf(" Total Time: %.2fms\n", stats[:totaltime] * 1000)
271
+
272
+ else
273
+ if stats[:discovered]
274
+ printf("\nFinished processing %d / %d hosts in %.2f ms\n\n", stats[:responses], stats[:discovered], stats[:blocktime] * 1000)
275
+ else
276
+ printf("\nFinished processing %d hosts in %.2f ms\n\n", stats[:responses], stats[:blocktime] * 1000)
277
+ end
278
+ end
279
+
280
+ if stats[:noresponsefrom].size > 0
281
+ puts("\nNo response from:\n")
282
+
283
+ stats[:noresponsefrom].each do |c|
284
+ puts if c % 4 == 1
285
+ printf("%30s", c)
286
+ end
287
+
288
+ puts
289
+ end
290
+ end
291
+ end
292
+ end
@@ -0,0 +1,202 @@
1
+ module MCollective
2
+ # A pretty sucky config class, ripe for refactoring/improving
3
+ class Config
4
+ include Singleton
5
+
6
+ attr_reader :topicprefix, :daemonize, :pluginconf, :libdir, :configured,
7
+ :logfile, :keeplogs, :max_log_size, :loglevel, :logfacility, :identity,
8
+ :daemonize, :connector, :securityprovider, :factsource, :registration,
9
+ :registerinterval, :topicsep, :classesfile, :rpcauditprovider, :rpcaudit,
10
+ :configdir, :rpcauthprovider, :rpcauthorization, :color, :configfile,
11
+ :rpchelptemplate, :rpclimitmethod, :logger_type, :fact_cache_time,
12
+ :collectives, :main_collective, :ssl_cipher, :registration_collective,
13
+ :direct_addressing, :direct_addressing_threshold, :queueprefix, :ttl
14
+
15
+ def initialize
16
+ @configured = false
17
+ end
18
+
19
+ def loadconfig(configfile)
20
+ set_config_defaults(configfile)
21
+
22
+ if File.exists?(configfile)
23
+ File.open(configfile, "r").each do |line|
24
+
25
+ # strip blank spaces, tabs etc off the end of all lines
26
+ line.gsub!(/\s*$/, "")
27
+
28
+ unless line =~ /^#|^$/
29
+ if (line =~ /(.+?)\s*=\s*(.+)/)
30
+ key = $1
31
+ val = $2
32
+
33
+ case key
34
+ when "topicsep"
35
+ @topicsep = val
36
+ when "registration"
37
+ @registration = val.capitalize
38
+ when "registration_collective"
39
+ @registration_collective = val
40
+ when "registerinterval"
41
+ @registerinterval = val.to_i
42
+ when "collectives"
43
+ @collectives = val.split(",").map {|c| c.strip}
44
+ when "main_collective"
45
+ @main_collective = val
46
+ when "topicprefix"
47
+ @topicprefix = val
48
+ when "queueprefix"
49
+ @queueprefix = val
50
+ when "logfile"
51
+ @logfile = val
52
+ when "keeplogs"
53
+ @keeplogs = val.to_i
54
+ when "max_log_size"
55
+ @max_log_size = val.to_i
56
+ when "loglevel"
57
+ @loglevel = val
58
+ when "logfacility"
59
+ @logfacility = val
60
+ when "libdir"
61
+ paths = val.split(File::PATH_SEPARATOR)
62
+ paths.each do |path|
63
+ @libdir << path
64
+ unless $LOAD_PATH.include?(path)
65
+ $LOAD_PATH << path
66
+ end
67
+ end
68
+ when "identity"
69
+ @identity = val
70
+ when "direct_addressing"
71
+ val =~ /^1|y/i ? @direct_addressing = true : @direct_addressing = false
72
+ when "direct_addressing_threshold"
73
+ @direct_addressing_threshold = val.to_i
74
+ when "color"
75
+ val =~ /^1|y/i ? @color = true : @color = false
76
+ when "daemonize"
77
+ val =~ /^1|y/i ? @daemonize = true : @daemonize = false
78
+ when "securityprovider"
79
+ @securityprovider = val.capitalize
80
+ when "factsource"
81
+ @factsource = val.capitalize
82
+ when "connector"
83
+ @connector = val.capitalize
84
+ when "classesfile"
85
+ @classesfile = val
86
+ when /^plugin.(.+)$/
87
+ @pluginconf[$1] = val
88
+ when "rpcaudit"
89
+ val =~ /^1|y/i ? @rpcaudit = true : @rpcaudit = false
90
+ when "rpcauditprovider"
91
+ @rpcauditprovider = val.capitalize
92
+ when "rpcauthorization"
93
+ val =~ /^1|y/i ? @rpcauthorization = true : @rpcauthorization = false
94
+ when "rpcauthprovider"
95
+ @rpcauthprovider = val.capitalize
96
+ when "rpchelptemplate"
97
+ @rpchelptemplate = val
98
+ when "rpclimitmethod"
99
+ @rpclimitmethod = val.to_sym
100
+ when "logger_type"
101
+ @logger_type = val
102
+ when "fact_cache_time"
103
+ @fact_cache_time = val.to_i
104
+ when "ssl_cipher"
105
+ @ssl_cipher = val
106
+ when "ttl"
107
+ @ttl = val.to_i
108
+ else
109
+ raise("Unknown config parameter #{key}")
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ read_plugin_config_dir("#{@configdir}/plugin.d")
116
+
117
+ raise 'Identities can only match /\w\.\-/' unless @identity.match(/^[\w\.\-]+$/)
118
+
119
+ @configured = true
120
+
121
+ @libdir.each {|dir| Log.warn("Cannot find libdir: #{dir}") unless File.directory?(dir)}
122
+
123
+ if @logger_type == "syslog"
124
+ raise "The sylog logger is not usable on the Windows platform" if Util.windows?
125
+ end
126
+
127
+ PluginManager.loadclass("Mcollective::Facts::#{@factsource}_facts")
128
+ PluginManager.loadclass("Mcollective::Connector::#{@connector}")
129
+ PluginManager.loadclass("Mcollective::Security::#{@securityprovider}")
130
+ PluginManager.loadclass("Mcollective::Registration::#{@registration}")
131
+ PluginManager.loadclass("Mcollective::Audit::#{@rpcauditprovider}") if @rpcaudit
132
+ PluginManager << {:type => "global_stats", :class => RunnerStats.new}
133
+ else
134
+ raise("Cannot find config file '#{configfile}'")
135
+ end
136
+ end
137
+
138
+ def set_config_defaults(configfile)
139
+ @stomp = Hash.new
140
+ @subscribe = Array.new
141
+ @pluginconf = Hash.new
142
+ @connector = "Stomp"
143
+ @securityprovider = "Psk"
144
+ @factsource = "Yaml"
145
+ @identity = Socket.gethostname
146
+ @registration = "Agentlist"
147
+ @registerinterval = 0
148
+ @registration_collective = nil
149
+ @topicsep = "."
150
+ @topicprefix = "/topic/"
151
+ @queueprefix = "/queue/"
152
+ @classesfile = "/var/lib/puppet/state/classes.txt"
153
+ @rpcaudit = false
154
+ @rpcauditprovider = ""
155
+ @rpcauthorization = false
156
+ @rpcauthprovider = ""
157
+ @configdir = File.dirname(configfile)
158
+ @color = !Util.windows?
159
+ @configfile = configfile
160
+ @logger_type = "file"
161
+ @keeplogs = 5
162
+ @max_log_size = 2097152
163
+ @rpclimitmethod = :first
164
+ @libdir = Array.new
165
+ @fact_cache_time = 300
166
+ @loglevel = "info"
167
+ @logfacility = "user"
168
+ @collectives = ["mcollective"]
169
+ @main_collective = @collectives.first
170
+ @ssl_cipher = "aes-256-cbc"
171
+ @direct_addressing = false
172
+ @direct_addressing_threshold = 10
173
+ @ttl = 60
174
+
175
+ # look in the config dir for the template so users can provide their own and windows
176
+ # with odd paths will just work more often, but fall back to old behavior if it does
177
+ # not exist
178
+ @rpchelptemplate = File.join(File.dirname(configfile), "rpc-help.erb")
179
+ @rpchelptemplate = "/etc/mcollective/rpc-help.erb" unless File.exists?(@rpchelptemplate)
180
+ end
181
+
182
+ def read_plugin_config_dir(dir)
183
+ return unless File.directory?(dir)
184
+
185
+ Dir.new(dir).each do |pluginconfigfile|
186
+ next unless pluginconfigfile =~ /^([\w]+).cfg$/
187
+
188
+ plugin = $1
189
+ File.open("#{dir}/#{pluginconfigfile}", "r").each do |line|
190
+ # strip blank lines
191
+ line.gsub!(/\s*$/, "")
192
+ next if line =~ /^#|^$/
193
+ if (line =~ /(.+?)\s*=\s*(.+)/)
194
+ key = $1
195
+ val = $2
196
+ @pluginconf["#{plugin}.#{key}"] = val
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end