mcollective-client 2.0.0 → 2.2.0
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.
- data/lib/mcollective.rb +32 -23
- data/lib/mcollective/agent.rb +5 -0
- data/lib/mcollective/agents.rb +5 -16
- data/lib/mcollective/aggregate.rb +61 -0
- data/lib/mcollective/aggregate/base.rb +40 -0
- data/lib/mcollective/aggregate/result.rb +9 -0
- data/lib/mcollective/aggregate/result/base.rb +25 -0
- data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
- data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
- data/lib/mcollective/application.rb +7 -4
- data/lib/mcollective/applications.rb +3 -14
- data/lib/mcollective/cache.rb +145 -0
- data/lib/mcollective/client.rb +10 -87
- data/lib/mcollective/config.rb +22 -8
- data/lib/mcollective/data.rb +87 -0
- data/lib/mcollective/data/base.rb +67 -0
- data/lib/mcollective/data/result.rb +40 -0
- data/lib/mcollective/ddl.rb +113 -0
- data/lib/mcollective/ddl/agentddl.rb +185 -0
- data/lib/mcollective/ddl/base.rb +220 -0
- data/lib/mcollective/ddl/dataddl.rb +56 -0
- data/lib/mcollective/ddl/discoveryddl.rb +52 -0
- data/lib/mcollective/ddl/validatorddl.rb +6 -0
- data/lib/mcollective/discovery.rb +143 -0
- data/lib/mcollective/generators.rb +7 -0
- data/lib/mcollective/generators/agent_generator.rb +51 -0
- data/lib/mcollective/generators/base.rb +46 -0
- data/lib/mcollective/generators/data_generator.rb +51 -0
- data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
- data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
- data/lib/mcollective/generators/templates/ddl.erb +8 -0
- data/lib/mcollective/generators/templates/plugin.erb +7 -0
- data/lib/mcollective/logger/console_logger.rb +15 -15
- data/lib/mcollective/matcher.rb +167 -0
- data/lib/mcollective/matcher/parser.rb +60 -25
- data/lib/mcollective/matcher/scanner.rb +156 -78
- data/lib/mcollective/message.rb +47 -6
- data/lib/mcollective/monkey_patches.rb +17 -0
- data/lib/mcollective/optionparser.rb +18 -1
- data/lib/mcollective/pluginmanager.rb +3 -3
- data/lib/mcollective/pluginpackager.rb +10 -3
- data/lib/mcollective/pluginpackager/agent_definition.rb +28 -20
- data/lib/mcollective/pluginpackager/standard_definition.rb +11 -9
- data/lib/mcollective/registration/base.rb +3 -1
- data/lib/mcollective/rpc.rb +18 -24
- data/lib/mcollective/rpc/agent.rb +37 -113
- data/lib/mcollective/rpc/client.rb +186 -64
- data/lib/mcollective/rpc/helpers.rb +42 -80
- data/lib/mcollective/rpc/progress.rb +3 -3
- data/lib/mcollective/rpc/reply.rb +37 -13
- data/lib/mcollective/rpc/request.rb +17 -6
- data/lib/mcollective/rpc/result.rb +9 -5
- data/lib/mcollective/rpc/stats.rb +71 -24
- data/lib/mcollective/security/base.rb +41 -34
- data/lib/mcollective/shell.rb +1 -1
- data/lib/mcollective/ssl.rb +34 -0
- data/lib/mcollective/util.rb +194 -23
- data/lib/mcollective/validator.rb +80 -0
- data/spec/fixtures/util/1.in +10 -0
- data/spec/fixtures/util/1.out +10 -0
- data/spec/fixtures/util/2.in +1 -0
- data/spec/fixtures/util/2.out +1 -0
- data/spec/fixtures/util/3.in +1 -0
- data/spec/fixtures/util/3.out +2 -0
- data/spec/fixtures/util/4.in +5 -0
- data/spec/fixtures/util/4.out +9 -0
- data/spec/spec.opts +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/agents_spec.rb +34 -19
- data/spec/unit/aggregate/base_spec.rb +57 -0
- data/spec/unit/aggregate/result/base_spec.rb +28 -0
- data/spec/unit/aggregate/result/collection_result_spec.rb +18 -0
- data/spec/unit/aggregate/result/numeric_result_spec.rb +22 -0
- data/spec/unit/aggregate_spec.rb +110 -0
- data/spec/unit/application_spec.rb +8 -3
- data/spec/unit/applications_spec.rb +2 -2
- data/spec/unit/cache_spec.rb +115 -0
- data/spec/unit/client_spec.rb +78 -0
- data/spec/unit/config_spec.rb +32 -34
- data/spec/unit/data/base_spec.rb +90 -0
- data/spec/unit/data/result_spec.rb +64 -0
- data/spec/unit/data_spec.rb +158 -0
- data/spec/unit/ddl/agentddl_spec.rb +217 -0
- data/spec/unit/{rpc/ddl_spec.rb → ddl/base_spec.rb} +238 -224
- data/spec/unit/ddl/dataddl_spec.rb +65 -0
- data/spec/unit/ddl/discoveryddl_spec.rb +58 -0
- data/spec/unit/ddl_spec.rb +84 -0
- data/spec/unit/discovery_spec.rb +196 -0
- data/spec/unit/facts/base_spec.rb +1 -1
- data/spec/unit/generators/agent_generator_spec.rb +72 -0
- data/spec/unit/generators/base_spec.rb +83 -0
- data/spec/unit/generators/data_generator_spec.rb +37 -0
- data/spec/unit/generators/snippets/agent_ddl +19 -0
- data/spec/unit/generators/snippets/data_ddl +20 -0
- data/spec/unit/logger/console_logger_spec.rb +76 -0
- data/spec/unit/logger/syslog_logger_spec.rb +2 -2
- data/spec/unit/matcher/parser_spec.rb +27 -10
- data/spec/unit/matcher/scanner_spec.rb +108 -5
- data/spec/unit/matcher_spec.rb +260 -0
- data/spec/unit/message_spec.rb +35 -13
- data/spec/unit/optionparser_spec.rb +2 -2
- data/spec/unit/pluginpackager/agent_definition_spec.rb +59 -42
- data/spec/unit/pluginpackager/standard_definition_spec.rb +10 -8
- data/spec/unit/pluginpackager_spec.rb +131 -0
- data/spec/unit/plugins/mcollective/aggregate/average_spec.rb +45 -0
- data/spec/unit/plugins/mcollective/aggregate/sum_spec.rb +31 -0
- data/spec/unit/plugins/mcollective/aggregate/summary_spec.rb +45 -0
- data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +1 -1
- data/spec/unit/plugins/mcollective/connector/rabbitmq_spec.rb +478 -0
- data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +2 -0
- data/spec/unit/plugins/mcollective/data/agent_data_spec.rb +43 -0
- data/spec/unit/plugins/mcollective/data/fstat_data_spec.rb +135 -0
- data/spec/unit/plugins/mcollective/discovery/flatfile_spec.rb +48 -0
- data/spec/unit/plugins/mcollective/discovery/mc_spec.rb +40 -0
- data/spec/unit/plugins/mcollective/packagers/debpackage_packager_spec.rb +41 -15
- data/spec/unit/plugins/mcollective/packagers/ospackage_spec.rb +1 -1
- data/spec/unit/plugins/mcollective/packagers/rpmpackage_packager_spec.rb +22 -38
- data/spec/unit/plugins/mcollective/validator/array_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/ipv4address_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/ipv6address_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/length_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/regex_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/shellsafe_validator_spec.rb +21 -0
- data/spec/unit/plugins/mcollective/validator/typecheck_validator_spec.rb +23 -0
- data/spec/unit/registration/base_spec.rb +1 -1
- data/spec/unit/rpc/actionrunner_spec.rb +2 -2
- data/spec/unit/rpc/agent_spec.rb +41 -65
- data/spec/unit/rpc/client_spec.rb +430 -134
- data/spec/unit/rpc/reply_spec.rb +31 -1
- data/spec/unit/rpc/request_spec.rb +33 -12
- data/spec/unit/rpc/result_spec.rb +7 -0
- data/spec/unit/rpc/stats_spec.rb +14 -14
- data/spec/unit/rpc_spec.rb +16 -0
- data/spec/unit/security/base_spec.rb +8 -8
- data/spec/unit/ssl_spec.rb +20 -2
- data/spec/unit/string_spec.rb +15 -0
- data/spec/unit/util_spec.rb +141 -21
- data/spec/unit/validator_spec.rb +67 -0
- metadata +145 -7
- data/lib/mcollective/rpc/ddl.rb +0 -258
@@ -74,26 +74,33 @@ module MCollective
|
|
74
74
|
|
75
75
|
when "compound"
|
76
76
|
filter[key].each do |compound|
|
77
|
-
result =
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
77
|
+
result = false
|
78
|
+
truth_values = []
|
79
|
+
|
80
|
+
begin
|
81
|
+
compound.each do |expression|
|
82
|
+
case expression.keys.first
|
83
|
+
when "statement"
|
84
|
+
truth_values << Matcher.eval_compound_statement(expression).to_s
|
85
|
+
when "fstatement"
|
86
|
+
truth_values << Matcher.eval_compound_fstatement(expression.values.first)
|
87
|
+
when "and"
|
88
|
+
truth_values << "&&"
|
89
|
+
when "or"
|
90
|
+
truth_values << "||"
|
91
|
+
when "("
|
92
|
+
truth_values << "("
|
93
|
+
when ")"
|
94
|
+
truth_values << ")"
|
95
|
+
when "not"
|
96
|
+
truth_values << "!"
|
97
|
+
end
|
93
98
|
end
|
94
|
-
end
|
95
99
|
|
96
|
-
|
100
|
+
result = eval(truth_values.join(" "))
|
101
|
+
rescue DDLValidationError
|
102
|
+
result = false
|
103
|
+
end
|
97
104
|
|
98
105
|
if result
|
99
106
|
Log.debug("Passing based on class and fact composition")
|
@@ -161,24 +168,24 @@ module MCollective
|
|
161
168
|
Log.debug("Encoded a message for request #{reqid}")
|
162
169
|
|
163
170
|
{:senderid => @config.identity,
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
171
|
+
:requestid => reqid,
|
172
|
+
:senderagent => agent,
|
173
|
+
:msgtime => Time.now.utc.to_i,
|
174
|
+
:body => body}
|
168
175
|
end
|
169
176
|
|
170
177
|
def create_request(reqid, filter, msg, initiated_by, target_agent, target_collective, ttl=60)
|
171
178
|
Log.debug("Encoding a request for agent '#{target_agent}' in collective #{target_collective} with request id #{reqid}")
|
172
179
|
|
173
180
|
{:body => msg,
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
181
|
+
:senderid => @config.identity,
|
182
|
+
:requestid => reqid,
|
183
|
+
:filter => filter,
|
184
|
+
:collective => target_collective,
|
185
|
+
:agent => target_agent,
|
186
|
+
:callerid => callerid,
|
187
|
+
:ttl => ttl,
|
188
|
+
:msgtime => Time.now.utc.to_i}
|
182
189
|
end
|
183
190
|
|
184
191
|
# Give a MC::Message instance and a message id this will figure out if you the incoming
|
@@ -215,22 +222,22 @@ module MCollective
|
|
215
222
|
|
216
223
|
# Security providers should provide this, see MCollective::Security::Psk
|
217
224
|
def validrequest?(req)
|
218
|
-
Log.error("validrequest? is not
|
225
|
+
Log.error("validrequest? is not implemented in #{self.class}")
|
219
226
|
end
|
220
227
|
|
221
228
|
# Security providers should provide this, see MCollective::Security::Psk
|
222
229
|
def encoderequest(sender, msg, filter={})
|
223
|
-
Log.error("encoderequest is not
|
230
|
+
Log.error("encoderequest is not implemented in #{self.class}")
|
224
231
|
end
|
225
232
|
|
226
233
|
# Security providers should provide this, see MCollective::Security::Psk
|
227
234
|
def encodereply(sender, msg, requestcallerid=nil)
|
228
|
-
Log.error("encodereply is not
|
235
|
+
Log.error("encodereply is not implemented in #{self.class}")
|
229
236
|
end
|
230
237
|
|
231
238
|
# Security providers should provide this, see MCollective::Security::Psk
|
232
239
|
def decodemsg(msg)
|
233
|
-
Log.error("decodemsg is not
|
240
|
+
Log.error("decodemsg is not implemented in #{self.class}")
|
234
241
|
end
|
235
242
|
end
|
236
243
|
end
|
data/lib/mcollective/shell.rb
CHANGED
data/lib/mcollective/ssl.rb
CHANGED
@@ -204,12 +204,46 @@ module MCollective
|
|
204
204
|
Digest::MD5.hexdigest(string)
|
205
205
|
end
|
206
206
|
|
207
|
+
# Creates a RFC 4122 version 5 UUID. If string is supplied it will produce repeatable
|
208
|
+
# UUIDs for that string else a random 128bit string will be used from OpenSSL::BN
|
209
|
+
#
|
210
|
+
# Code used with permission from:
|
211
|
+
# https://github.com/kwilczynski/puppet-functions/blob/master/lib/puppet/parser/functions/uuid.rb
|
212
|
+
#
|
213
|
+
def self.uuid(string=nil)
|
214
|
+
string ||= OpenSSL::Random.random_bytes(16).unpack('H*').shift
|
215
|
+
|
216
|
+
uuid_name_space_dns = "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
|
217
|
+
|
218
|
+
sha1 = Digest::SHA1.new
|
219
|
+
sha1.update(uuid_name_space_dns)
|
220
|
+
sha1.update(string)
|
221
|
+
|
222
|
+
# first 16 bytes..
|
223
|
+
bytes = sha1.digest[0, 16].bytes.to_a
|
224
|
+
|
225
|
+
# version 5 adjustments
|
226
|
+
bytes[6] &= 0x0f
|
227
|
+
bytes[6] |= 0x50
|
228
|
+
|
229
|
+
# variant is DCE 1.1
|
230
|
+
bytes[8] &= 0x3f
|
231
|
+
bytes[8] |= 0x80
|
232
|
+
|
233
|
+
bytes = [4, 2, 2, 2, 6].collect do |i|
|
234
|
+
bytes.slice!(0, i).pack('C*').unpack('H*')
|
235
|
+
end
|
236
|
+
|
237
|
+
bytes.join('-')
|
238
|
+
end
|
239
|
+
|
207
240
|
# Reads either a :public or :private key from disk, uses an
|
208
241
|
# optional passphrase to read the private key
|
209
242
|
def read_key(type, key=nil, passphrase=nil)
|
210
243
|
return key if key.nil?
|
211
244
|
|
212
245
|
raise "Could not find key #{key}" unless File.exist?(key)
|
246
|
+
raise "#{type} key file '#{key}' is empty" if File.zero?(key)
|
213
247
|
|
214
248
|
if type == :public
|
215
249
|
begin
|
data/lib/mcollective/util.rb
CHANGED
@@ -129,10 +129,10 @@ module MCollective
|
|
129
129
|
# Creates an empty filter
|
130
130
|
def self.empty_filter
|
131
131
|
{"fact" => [],
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
132
|
+
"cf_class" => [],
|
133
|
+
"agent" => [],
|
134
|
+
"identity" => [],
|
135
|
+
"compound" => []}
|
136
136
|
end
|
137
137
|
|
138
138
|
# Picks a config file defaults to ~/.mcollective
|
@@ -156,12 +156,14 @@ module MCollective
|
|
156
156
|
|
157
157
|
# Creates a standard options hash
|
158
158
|
def self.default_options
|
159
|
-
{:verbose
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
159
|
+
{:verbose => false,
|
160
|
+
:disctimeout => nil,
|
161
|
+
:timeout => 5,
|
162
|
+
:config => config_file_for_user,
|
163
|
+
:collective => nil,
|
164
|
+
:discovery_method => nil,
|
165
|
+
:discovery_options => Config.instance.default_discovery_options,
|
166
|
+
:filter => empty_filter}
|
165
167
|
end
|
166
168
|
|
167
169
|
def self.make_subscriptions(agent, type, collective=nil)
|
@@ -247,28 +249,197 @@ module MCollective
|
|
247
249
|
!!(RbConfig::CONFIG['host_os'] =~ /mswin|win32|dos|mingw|cygwin/i)
|
248
250
|
end
|
249
251
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
optype = expression.values.first.match(/>=|<=|=|<|>/)
|
255
|
-
name, value = expression.values.first.split(optype[0])
|
256
|
-
unless value.split("")[0] == "/"
|
257
|
-
optype[0] == "=" ? optype = "==" : optype = optype[0]
|
258
|
-
else
|
259
|
-
optype = "=~"
|
260
|
-
end
|
252
|
+
# Return color codes, if the config color= option is false
|
253
|
+
# just return a empty string
|
254
|
+
def self.color(code)
|
255
|
+
colorize = Config.instance.color
|
261
256
|
|
262
|
-
|
257
|
+
colors = {:red => "[31m",
|
258
|
+
:green => "[32m",
|
259
|
+
:yellow => "[33m",
|
260
|
+
:cyan => "[36m",
|
261
|
+
:bold => "[1m",
|
262
|
+
:reset => "[0m"}
|
263
|
+
|
264
|
+
if colorize
|
265
|
+
return colors[code] || ""
|
263
266
|
else
|
264
|
-
return
|
267
|
+
return ""
|
265
268
|
end
|
266
269
|
end
|
267
270
|
|
271
|
+
# Helper to return a string in specific color
|
272
|
+
def self.colorize(code, msg)
|
273
|
+
"%s%s%s" % [ color(code), msg, color(:reset) ]
|
274
|
+
end
|
275
|
+
|
268
276
|
# Returns the current ruby version as per RUBY_VERSION, mostly
|
269
277
|
# doing this here to aid testing
|
270
278
|
def self.ruby_version
|
271
279
|
RUBY_VERSION
|
272
280
|
end
|
281
|
+
|
282
|
+
def self.mcollective_version
|
283
|
+
MCollective::VERSION
|
284
|
+
end
|
285
|
+
|
286
|
+
# Returns an aligned_string of text relative to the size of the terminal
|
287
|
+
# window. If a line in the string exceeds the width of the terminal window
|
288
|
+
# the line will be chopped off at the whitespace chacter closest to the
|
289
|
+
# end of the line and prepended to the next line, keeping all indentation.
|
290
|
+
#
|
291
|
+
# The terminal size is detected by default, but custom line widths can
|
292
|
+
# passed. All strings will also be left aligned with 5 whitespace characters
|
293
|
+
# by default.
|
294
|
+
def self.align_text(text, console_cols = nil, preamble = 5)
|
295
|
+
unless console_cols
|
296
|
+
console_cols = terminal_dimensions[0]
|
297
|
+
|
298
|
+
# if unknown size we default to the typical unix default
|
299
|
+
console_cols = 80 if console_cols == 0
|
300
|
+
end
|
301
|
+
|
302
|
+
console_cols -= preamble
|
303
|
+
|
304
|
+
# Return unaligned text if console window is too small
|
305
|
+
return text if console_cols <= 0
|
306
|
+
|
307
|
+
# If console is 0 this implies unknown so we assume the common
|
308
|
+
# minimal unix configuration of 80 characters
|
309
|
+
console_cols = 80 if console_cols <= 0
|
310
|
+
|
311
|
+
text = text.split("\n")
|
312
|
+
piece = ''
|
313
|
+
whitespace = 0
|
314
|
+
|
315
|
+
text.each_with_index do |line, i|
|
316
|
+
whitespace = 0
|
317
|
+
|
318
|
+
while whitespace < line.length && line[whitespace].chr == ' '
|
319
|
+
whitespace += 1
|
320
|
+
end
|
321
|
+
|
322
|
+
# If the current line is empty, indent it so that a snippet
|
323
|
+
# from the previous line is aligned correctly.
|
324
|
+
if line == ""
|
325
|
+
line = (" " * whitespace)
|
326
|
+
end
|
327
|
+
|
328
|
+
# If text was snipped from the previous line, prepend it to the
|
329
|
+
# current line after any current indentation.
|
330
|
+
if piece != ''
|
331
|
+
# Reset whitespaces to 0 if there are more whitespaces than there are
|
332
|
+
# console columns
|
333
|
+
whitespace = 0 if whitespace >= console_cols
|
334
|
+
|
335
|
+
# If the current line is empty and being prepended to, create a new
|
336
|
+
# empty line in the text so that formatting is preserved.
|
337
|
+
if text[i + 1] && line == (" " * whitespace)
|
338
|
+
text.insert(i + 1, "")
|
339
|
+
end
|
340
|
+
|
341
|
+
# Add the snipped text to the current line
|
342
|
+
line.insert(whitespace, "#{piece} ")
|
343
|
+
end
|
344
|
+
|
345
|
+
piece = ''
|
346
|
+
|
347
|
+
# Compare the line length to the allowed line length.
|
348
|
+
# If it exceeds it, snip the offending text from the line
|
349
|
+
# and store it so that it can be prepended to the next line.
|
350
|
+
if line.length > (console_cols + preamble)
|
351
|
+
reverse = console_cols
|
352
|
+
|
353
|
+
while line[reverse].chr != ' '
|
354
|
+
reverse -= 1
|
355
|
+
end
|
356
|
+
|
357
|
+
piece = line.slice!(reverse, (line.length - 1)).lstrip
|
358
|
+
end
|
359
|
+
|
360
|
+
# If a snippet exists when all the columns in the text have been
|
361
|
+
# updated, create a new line and append the snippet to it, using
|
362
|
+
# the same left alignment as the last line in the text.
|
363
|
+
if piece != '' && text[i+1].nil?
|
364
|
+
text[i+1] = "#{' ' * (whitespace)}#{piece}"
|
365
|
+
piece = ''
|
366
|
+
end
|
367
|
+
|
368
|
+
# Add the preamble to the line and add it to the text
|
369
|
+
line = ((' ' * preamble) + line)
|
370
|
+
text[i] = line
|
371
|
+
end
|
372
|
+
|
373
|
+
text.join("\n")
|
374
|
+
end
|
375
|
+
|
376
|
+
# Figures out the columns and lines of the current tty
|
377
|
+
#
|
378
|
+
# Returns [0, 0] if it can't figure it out or if you're
|
379
|
+
# not running on a tty
|
380
|
+
def self.terminal_dimensions(stdout = STDOUT, environment = ENV)
|
381
|
+
return [0, 0] unless stdout.tty?
|
382
|
+
|
383
|
+
return [80, 40] if Util.windows?
|
384
|
+
|
385
|
+
if environment["COLUMNS"] && environment["LINES"]
|
386
|
+
return [environment["COLUMNS"].to_i, environment["LINES"].to_i]
|
387
|
+
|
388
|
+
elsif environment["TERM"] && command_in_path?("tput")
|
389
|
+
return [`tput cols`.to_i, `tput lines`.to_i]
|
390
|
+
|
391
|
+
elsif command_in_path?('stty')
|
392
|
+
return `stty size`.scan(/\d+/).map {|s| s.to_i }
|
393
|
+
else
|
394
|
+
return [0, 0]
|
395
|
+
end
|
396
|
+
rescue
|
397
|
+
[0, 0]
|
398
|
+
end
|
399
|
+
|
400
|
+
# Checks in PATH returns true if the command is found
|
401
|
+
def self.command_in_path?(command)
|
402
|
+
found = ENV["PATH"].split(File::PATH_SEPARATOR).map do |p|
|
403
|
+
File.exist?(File.join(p, command))
|
404
|
+
end
|
405
|
+
|
406
|
+
found.include?(true)
|
407
|
+
end
|
408
|
+
|
409
|
+
# compare two software versions as commonly found in
|
410
|
+
# package versions.
|
411
|
+
#
|
412
|
+
# returns 0 if a == b
|
413
|
+
# returns -1 if a < b
|
414
|
+
# returns 1 if a > b
|
415
|
+
#
|
416
|
+
# Code originally from Puppet but refactored to a more
|
417
|
+
# ruby style that fits in better with this code base
|
418
|
+
def self.versioncmp(version_a, version_b)
|
419
|
+
vre = /[-.]|\d+|[^-.\d]+/
|
420
|
+
ax = version_a.scan(vre)
|
421
|
+
bx = version_b.scan(vre)
|
422
|
+
|
423
|
+
until ax.empty? || bx.empty?
|
424
|
+
a = ax.shift
|
425
|
+
b = bx.shift
|
426
|
+
|
427
|
+
next if a == b
|
428
|
+
next if a == '-' && b == '-'
|
429
|
+
return -1 if a == '-'
|
430
|
+
return 1 if b == '-'
|
431
|
+
next if a == '.' && b == '.'
|
432
|
+
return -1 if a == '.'
|
433
|
+
return 1 if b == '.'
|
434
|
+
|
435
|
+
if a =~ /^[^0]\d+$/ && b =~ /^[^0]\d+$/
|
436
|
+
return Integer(a) <=> Integer(b)
|
437
|
+
else
|
438
|
+
return a.upcase <=> b.upcase
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
version_a <=> version_b
|
443
|
+
end
|
273
444
|
end
|
274
445
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module MCollective
|
2
|
+
module Validator
|
3
|
+
@last_load = nil
|
4
|
+
|
5
|
+
# Loads the validator plugins. Validators will only be loaded every 5 minutes
|
6
|
+
def self.load_validators
|
7
|
+
if load_validators?
|
8
|
+
@last_load = Time.now.to_i
|
9
|
+
PluginManager.find_and_load("validator")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns and instance of the Plugin class from which objects can be created.
|
14
|
+
# Valid plugin names are
|
15
|
+
# :valplugin
|
16
|
+
# "valplugin"
|
17
|
+
# "ValpluginValidator"
|
18
|
+
def self.[](klass)
|
19
|
+
if klass.is_a?(Symbol)
|
20
|
+
klass = validator_class(klass)
|
21
|
+
elsif !(klass.match(/.*Validator$/))
|
22
|
+
klass = validator_class(klass)
|
23
|
+
end
|
24
|
+
|
25
|
+
const_get(klass)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Allows validation plugins to be called like module methods : Validator.validate()
|
29
|
+
def self.method_missing(method, *args, &block)
|
30
|
+
if has_validator?(method)
|
31
|
+
validator = Validator[method].validate(*args)
|
32
|
+
else
|
33
|
+
raise ValidatorError, "Unknown validator: '#{method}'."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.has_validator?(validator)
|
38
|
+
const_defined?(validator_class(validator))
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.validator_class(validator)
|
42
|
+
"#{validator.to_s.capitalize}Validator"
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.load_validators?
|
46
|
+
return true if @last_load.nil?
|
47
|
+
|
48
|
+
(@last_load - Time.now.to_i) > 300
|
49
|
+
end
|
50
|
+
|
51
|
+
# Generic validate method that will call the correct validator
|
52
|
+
# plugin based on the type of the validation parameter
|
53
|
+
def self.validate(validator, validation)
|
54
|
+
Validator.load_validators
|
55
|
+
|
56
|
+
begin
|
57
|
+
if [:integer, :boolean, :float, :number, :string].include?(validation)
|
58
|
+
Validator.typecheck(validator, validation)
|
59
|
+
|
60
|
+
else
|
61
|
+
case validation
|
62
|
+
when Regexp,String
|
63
|
+
Validator.regex(validator, validation)
|
64
|
+
|
65
|
+
when Symbol
|
66
|
+
Validator.send(validation, validator)
|
67
|
+
|
68
|
+
when Array
|
69
|
+
Validator.array(validator, validation)
|
70
|
+
|
71
|
+
when Class
|
72
|
+
Validator.typecheck(validator, validation)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
rescue => e
|
76
|
+
raise ValidatorError, e.to_s
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|