mcollective-client 2.5.3 → 2.6.0
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.
- data/lib/mcollective.rb +1 -1
- data/lib/mcollective/application.rb +21 -6
- data/lib/mcollective/client.rb +7 -0
- data/lib/mcollective/config.rb +13 -1
- data/lib/mcollective/connector/base.rb +2 -0
- data/lib/mcollective/facts/base.rb +18 -5
- data/lib/mcollective/log.rb +7 -0
- data/lib/mcollective/logger/base.rb +12 -8
- data/lib/mcollective/logger/file_logger.rb +7 -0
- data/lib/mcollective/message.rb +1 -1
- data/lib/mcollective/optionparser.rb +4 -0
- data/lib/mcollective/registration/base.rb +24 -10
- data/lib/mcollective/rpc/agent.rb +7 -1
- data/lib/mcollective/rpc/client.rb +89 -35
- data/lib/mcollective/rpc/helpers.rb +8 -3
- data/lib/mcollective/rpc/result.rb +4 -0
- data/lib/mcollective/rpc/stats.rb +6 -2
- data/lib/mcollective/shell.rb +2 -0
- data/lib/mcollective/ssl.rb +5 -0
- data/lib/mcollective/util.rb +29 -1
- data/lib/mcollective/validator.rb +9 -4
- data/spec/spec_helper.rb +6 -0
- data/spec/unit/config_spec.rb +10 -0
- data/spec/unit/connector/base_spec.rb +28 -0
- data/spec/unit/facts/base_spec.rb +35 -0
- data/spec/unit/log_spec.rb +9 -0
- data/spec/unit/logger/base_spec.rb +12 -2
- data/spec/unit/logger/file_logger_spec.rb +82 -0
- data/spec/unit/plugins/mcollective/application/plugin_spec.rb +1 -0
- data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +44 -17
- data/spec/unit/plugins/mcollective/connector/rabbitmq_spec.rb +20 -19
- data/spec/unit/plugins/mcollective/data/fact_data_spec.rb +92 -0
- data/spec/unit/registration/base_spec.rb +46 -0
- data/spec/unit/rpc/agent_spec.rb +37 -0
- data/spec/unit/rpc/client_spec.rb +68 -15
- data/spec/unit/rpc/result_spec.rb +21 -0
- data/spec/unit/runner_spec.rb +97 -19
- data/spec/unit/shell_spec.rb +5 -0
- data/spec/unit/ssl_spec.rb +5 -0
- data/spec/unit/util_spec.rb +163 -1
- metadata +215 -209
data/lib/mcollective.rb
CHANGED
@@ -314,12 +314,27 @@ module MCollective
|
|
314
314
|
:okcount => 0,
|
315
315
|
:failcount => 0}.merge(stats.to_hash)
|
316
316
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
317
|
+
if (request_stats[:discoverytime] == 0 && request_stats[:responses] == 0)
|
318
|
+
return 4
|
319
|
+
end
|
320
|
+
|
321
|
+
if (request_stats[:discovered] > 0)
|
322
|
+
if (request_stats[:responses] == 0)
|
323
|
+
return 3
|
324
|
+
elsif (request_stats[:failcount] > 0)
|
325
|
+
return 2
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
if (request_stats[:discovered] == 0)
|
330
|
+
if (request_stats[:responses] && request_stats[:responses] > 0)
|
331
|
+
return 0
|
332
|
+
else
|
333
|
+
return 1
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
return 0
|
323
338
|
end
|
324
339
|
|
325
340
|
# A helper that creates a consistent exit code for applications by looking at an
|
data/lib/mcollective/client.rb
CHANGED
@@ -18,6 +18,11 @@ module MCollective
|
|
18
18
|
@connection.connect
|
19
19
|
end
|
20
20
|
|
21
|
+
@@request_sequence = 0
|
22
|
+
def self.request_sequence
|
23
|
+
@@request_sequence
|
24
|
+
end
|
25
|
+
|
21
26
|
# Returns the configured main collective if no
|
22
27
|
# specific collective is specified as options
|
23
28
|
def collective
|
@@ -55,6 +60,8 @@ module MCollective
|
|
55
60
|
request.reply_to = @options[:reply_to] if @options[:reply_to]
|
56
61
|
end
|
57
62
|
|
63
|
+
@@request_sequence += 1
|
64
|
+
|
58
65
|
request.encode!
|
59
66
|
subscribe(agent, :reply) unless request.reply_to
|
60
67
|
request
|
data/lib/mcollective/config.rb
CHANGED
@@ -15,7 +15,8 @@ module MCollective
|
|
15
15
|
attr_reader :main_collective, :ssl_cipher, :registration_collective
|
16
16
|
attr_reader :direct_addressing, :direct_addressing_threshold, :ttl
|
17
17
|
attr_reader :default_discovery_method, :default_discovery_options
|
18
|
-
attr_reader :publish_timeout, :threaded, :soft_shutdown
|
18
|
+
attr_reader :publish_timeout, :threaded, :soft_shutdown, :activate_agents
|
19
|
+
attr_reader :registration_splay, :discovery_timeout, :soft_shutdown_timeout
|
19
20
|
|
20
21
|
def initialize
|
21
22
|
@configured = false
|
@@ -43,6 +44,8 @@ module MCollective
|
|
43
44
|
@registration_collective = val
|
44
45
|
when "registerinterval"
|
45
46
|
@registerinterval = Integer(val)
|
47
|
+
when "registration_splay"
|
48
|
+
@registration_splay = Util.str_to_bool(val)
|
46
49
|
when "collectives"
|
47
50
|
@collectives = val.split(",").map {|c| c.strip}
|
48
51
|
when "main_collective"
|
@@ -87,6 +90,8 @@ module MCollective
|
|
87
90
|
@classesfile = val
|
88
91
|
when /^plugin.(.+)$/
|
89
92
|
@pluginconf[$1] = val
|
93
|
+
when "discovery_timeout"
|
94
|
+
@discovery_timeout = Integer(val)
|
90
95
|
when "publish_timeout"
|
91
96
|
@publish_timeout = Integer(val)
|
92
97
|
when "rpcaudit"
|
@@ -115,6 +120,10 @@ module MCollective
|
|
115
120
|
@default_discovery_method = val
|
116
121
|
when "soft_shutdown"
|
117
122
|
@soft_shutdown = Util.str_to_bool(val)
|
123
|
+
when "soft_shutdown_timeout"
|
124
|
+
@soft_shutdown_timeout = Integer(val)
|
125
|
+
when "activate_agents"
|
126
|
+
@activate_agents = Util.str_to_bool(val)
|
118
127
|
when "topicprefix", "topicsep", "queueprefix", "rpchelptemplate", "helptemplatedir"
|
119
128
|
Log.warn("Use of deprecated '#{key}' option. This option is ignored and should be removed from '#{configfile}'")
|
120
129
|
else
|
@@ -165,6 +174,7 @@ module MCollective
|
|
165
174
|
@registration = "Agentlist"
|
166
175
|
@registerinterval = 0
|
167
176
|
@registration_collective = nil
|
177
|
+
@registration_splay = false
|
168
178
|
@classesfile = "/var/lib/puppet/state/classes.txt"
|
169
179
|
@rpcaudit = false
|
170
180
|
@rpcauditprovider = ""
|
@@ -193,6 +203,8 @@ module MCollective
|
|
193
203
|
@publish_timeout = 2
|
194
204
|
@threaded = false
|
195
205
|
@soft_shutdown = false
|
206
|
+
@soft_shutdown_timeout = nil
|
207
|
+
@activate_agents = true
|
196
208
|
end
|
197
209
|
|
198
210
|
def read_plugin_config_dir(dir)
|
@@ -17,6 +17,8 @@ module MCollective
|
|
17
17
|
module Connector
|
18
18
|
class Base
|
19
19
|
def self.inherited(klass)
|
20
|
+
plugin_name = klass.to_s.split("::").last.downcase
|
21
|
+
ddl = DDL.new(plugin_name, :connector)
|
20
22
|
PluginManager << {:type => "connector_plugin", :class => klass.to_s}
|
21
23
|
end
|
22
24
|
end
|
@@ -34,11 +34,7 @@ module MCollective
|
|
34
34
|
# Force reset to last known good state on empty facts
|
35
35
|
raise "Got empty facts" if tfacts.empty?
|
36
36
|
|
37
|
-
@facts
|
38
|
-
|
39
|
-
tfacts.each_pair do |key,value|
|
40
|
-
@facts[key.to_s] = value.to_s
|
41
|
-
end
|
37
|
+
@facts = normalize_facts(tfacts)
|
42
38
|
|
43
39
|
@last_good_facts = @facts.clone
|
44
40
|
@last_facts_load = Time.now.to_i
|
@@ -81,6 +77,23 @@ module MCollective
|
|
81
77
|
def force_reload?
|
82
78
|
false
|
83
79
|
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def normalize_facts(value)
|
84
|
+
case value
|
85
|
+
when Array
|
86
|
+
return value.map { |v| normalize_facts(v) }
|
87
|
+
when Hash
|
88
|
+
new_hash = {}
|
89
|
+
value.each do |k,v|
|
90
|
+
new_hash[k.to_s] = normalize_facts(v)
|
91
|
+
end
|
92
|
+
return new_hash
|
93
|
+
else
|
94
|
+
return value.to_s
|
95
|
+
end
|
96
|
+
end
|
84
97
|
end
|
85
98
|
end
|
86
99
|
end
|
data/lib/mcollective/log.rb
CHANGED
@@ -44,6 +44,13 @@ module MCollective
|
|
44
44
|
@logger.cycle_level if @configured
|
45
45
|
end
|
46
46
|
|
47
|
+
# reopen log files
|
48
|
+
def reopen
|
49
|
+
if @configured
|
50
|
+
@logger.reopen
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
47
54
|
# logs a message at a certain level
|
48
55
|
def log(level, msg)
|
49
56
|
configure unless @configured
|
@@ -34,6 +34,18 @@ module MCollective
|
|
34
34
|
@active_level = level.to_sym
|
35
35
|
end
|
36
36
|
|
37
|
+
def start
|
38
|
+
raise "The logging class did not supply a start method"
|
39
|
+
end
|
40
|
+
|
41
|
+
def log(level, from, msg)
|
42
|
+
raise "The logging class did not supply a log method"
|
43
|
+
end
|
44
|
+
|
45
|
+
def reopen
|
46
|
+
# reopen may not make sense to all Loggers, but we expect it of the API
|
47
|
+
end
|
48
|
+
|
37
49
|
private
|
38
50
|
def map_level(level)
|
39
51
|
raise "Logger class do not know how to handle #{level} messages" unless valid_levels.include?(level.to_sym)
|
@@ -60,14 +72,6 @@ module MCollective
|
|
60
72
|
def valid_levels
|
61
73
|
raise "The logging class did not supply a valid_levels method"
|
62
74
|
end
|
63
|
-
|
64
|
-
def log(level, from, msg)
|
65
|
-
raise "The logging class did not supply a log method"
|
66
|
-
end
|
67
|
-
|
68
|
-
def start
|
69
|
-
raise "The logging class did not supply a start method"
|
70
|
-
end
|
71
75
|
end
|
72
76
|
end
|
73
77
|
end
|
data/lib/mcollective/message.rb
CHANGED
@@ -200,7 +200,7 @@ module MCollective
|
|
200
200
|
if msg_age > ttl
|
201
201
|
PluginManager["global_stats"].ttlexpired
|
202
202
|
|
203
|
-
raise(MsgTTLExpired, "message #{requestid} from #{cid} created at #{msgtime} is #{msg_age} seconds old, TTL is #{ttl}")
|
203
|
+
raise(MsgTTLExpired, "message #{requestid} from #{cid} created at #{msgtime} is #{msg_age} seconds old, TTL is #{ttl}. Rejecting message.")
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
@@ -177,6 +177,10 @@ module MCollective
|
|
177
177
|
@parser.on("--threaded", "Start publishing requests and receiving responses in threaded mode.") do |v|
|
178
178
|
@options[:threaded] = true
|
179
179
|
end
|
180
|
+
|
181
|
+
@parser.on("--sort", "Sort the output of an RPC call before processing.") do |v|
|
182
|
+
@options[:sort] = true
|
183
|
+
end
|
180
184
|
end
|
181
185
|
|
182
186
|
private
|
@@ -20,16 +20,7 @@ module MCollective
|
|
20
20
|
return false if interval == 0
|
21
21
|
|
22
22
|
Thread.new do
|
23
|
-
|
24
|
-
begin
|
25
|
-
publish(body)
|
26
|
-
|
27
|
-
sleep interval
|
28
|
-
rescue Exception => e
|
29
|
-
Log.error("Sending registration message failed: #{e}")
|
30
|
-
sleep interval
|
31
|
-
end
|
32
|
-
end
|
23
|
+
publish_thread(connection)
|
33
24
|
end
|
34
25
|
end
|
35
26
|
|
@@ -72,6 +63,29 @@ module MCollective
|
|
72
63
|
req.publish
|
73
64
|
end
|
74
65
|
end
|
66
|
+
|
67
|
+
def body
|
68
|
+
raise "Registration Plugins must implement the #body method"
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
def publish_thread(connnection)
|
73
|
+
if config.registration_splay
|
74
|
+
splay_delay = rand(interval)
|
75
|
+
Log.debug("registration_splay enabled. Registration will start in #{splay_delay} seconds")
|
76
|
+
sleep splay_delay
|
77
|
+
end
|
78
|
+
|
79
|
+
loop do
|
80
|
+
begin
|
81
|
+
publish(body)
|
82
|
+
sleep interval
|
83
|
+
rescue Exception => e
|
84
|
+
Log.error("Sending registration message failed: #{e}")
|
85
|
+
sleep interval
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
75
89
|
end
|
76
90
|
end
|
77
91
|
end
|
@@ -138,10 +138,16 @@ module MCollective
|
|
138
138
|
# end
|
139
139
|
def self.activate?
|
140
140
|
agent_name = self.to_s.split("::").last.downcase
|
141
|
+
config = Config.instance
|
141
142
|
|
142
143
|
Log.debug("Starting default activation checks for #{agent_name}")
|
143
144
|
|
144
|
-
|
145
|
+
# Check global state to determine if agent should be loaded
|
146
|
+
should_activate = config.activate_agents
|
147
|
+
|
148
|
+
# Check agent specific state to determine if agent should be loaded
|
149
|
+
should_activate = Util.str_to_bool(config.pluginconf.fetch("#{agent_name}.activate_agent",
|
150
|
+
should_activate))
|
145
151
|
|
146
152
|
unless should_activate
|
147
153
|
Log.debug("Found plugin configuration '#{agent_name}.activate_agent' with value '#{should_activate}'")
|
@@ -25,7 +25,12 @@ module MCollective
|
|
25
25
|
initial_options = Marshal.load(@@initial_options)
|
26
26
|
|
27
27
|
else
|
28
|
-
oparser = MCollective::Optionparser.new({:verbose => false,
|
28
|
+
oparser = MCollective::Optionparser.new({ :verbose => false,
|
29
|
+
:progress_bar => true,
|
30
|
+
:mcollective_limit_targets => false,
|
31
|
+
:batch_size => nil,
|
32
|
+
:batch_sleep_time => 1 },
|
33
|
+
"filter")
|
29
34
|
|
30
35
|
initial_options = oparser.parse do |parser, opts|
|
31
36
|
if block_given?
|
@@ -67,13 +72,13 @@ module MCollective
|
|
67
72
|
@discovery_options = initial_options[:discovery_options] || []
|
68
73
|
@force_display_mode = initial_options[:force_display_mode] || false
|
69
74
|
|
70
|
-
@batch_size =
|
75
|
+
@batch_size = initial_options[:batch_size] || 0
|
71
76
|
@batch_sleep_time = Float(initial_options[:batch_sleep_time] || 1)
|
72
|
-
@batch_mode = @batch_size
|
77
|
+
@batch_mode = determine_batch_mode(@batch_size)
|
73
78
|
|
74
79
|
agent_filter agent
|
75
80
|
|
76
|
-
@discovery_timeout = @initial_options.fetch(:disctimeout, nil)
|
81
|
+
@discovery_timeout = @initial_options.fetch(:disctimeout, nil) || Config.instance.discovery_timeout
|
77
82
|
|
78
83
|
@collective = @client.collective
|
79
84
|
@ttl = initial_options[:ttl] || Config.instance.ttl
|
@@ -239,6 +244,11 @@ module MCollective
|
|
239
244
|
|
240
245
|
validate_request(action, args)
|
241
246
|
|
247
|
+
# TODO(ploubser): The logic here seems poor. It implies that it is valid to
|
248
|
+
# pass arguments where batch_mode is set to false and batch_mode > 0.
|
249
|
+
# If this is the case we completely ignore the supplied value of batch_mode
|
250
|
+
# and do our own thing.
|
251
|
+
|
242
252
|
# if a global batch size is set just use that else set it
|
243
253
|
# in the case that it was passed as an argument
|
244
254
|
batch_mode = args.include?(:batch_size) || @batch_mode
|
@@ -248,7 +258,7 @@ module MCollective
|
|
248
258
|
# if we were given a batch_size argument thats 0 and batch_mode was
|
249
259
|
# determined to be on via global options etc this will allow a batch_size
|
250
260
|
# of 0 to disable or batch_mode for this call only
|
251
|
-
batch_mode = (
|
261
|
+
batch_mode = determine_batch_mode(batch_size)
|
252
262
|
|
253
263
|
# Handle single target requests by doing discovery and picking
|
254
264
|
# a random node. Then do a custom request specifying a filter
|
@@ -580,7 +590,13 @@ module MCollective
|
|
580
590
|
|
581
591
|
# Sets and sanity checks the limit_targets variable
|
582
592
|
# used to restrict how many nodes we'll target
|
593
|
+
# Limit targets can be reset by passing nil or false
|
583
594
|
def limit_targets=(limit)
|
595
|
+
if !limit
|
596
|
+
@limit_targets = nil
|
597
|
+
return
|
598
|
+
end
|
599
|
+
|
584
600
|
if limit.is_a?(String)
|
585
601
|
raise "Invalid limit specified: #{limit} valid limits are /^\d+%*$/" unless limit =~ /^\d+%*$/
|
586
602
|
|
@@ -606,10 +622,14 @@ module MCollective
|
|
606
622
|
|
607
623
|
# Sets the batch size, if the size is set to 0 that will disable batch mode
|
608
624
|
def batch_size=(limit)
|
609
|
-
|
625
|
+
unless Config.instance.direct_addressing
|
626
|
+
raise "Can only set batch size if direct addressing is supported"
|
627
|
+
end
|
628
|
+
|
629
|
+
validate_batch_size(limit)
|
610
630
|
|
611
|
-
@batch_size =
|
612
|
-
@batch_mode = @batch_size
|
631
|
+
@batch_size = limit
|
632
|
+
@batch_mode = determine_batch_mode(@batch_size)
|
613
633
|
end
|
614
634
|
|
615
635
|
def batch_sleep_time=(time)
|
@@ -759,8 +779,8 @@ module MCollective
|
|
759
779
|
def call_agent_batched(action, args, opts, batch_size, sleep_time, &block)
|
760
780
|
raise "Batched requests requires direct addressing" unless Config.instance.direct_addressing
|
761
781
|
raise "Cannot bypass result processing for batched requests" if args[:process_results] == false
|
782
|
+
validate_batch_size(batch_size)
|
762
783
|
|
763
|
-
batch_size = Integer(batch_size)
|
764
784
|
sleep_time = Float(sleep_time)
|
765
785
|
|
766
786
|
Log.debug("Calling #{agent}##{action} in batches of #{batch_size} with sleep time of #{sleep_time}")
|
@@ -782,10 +802,22 @@ module MCollective
|
|
782
802
|
@stdout.print twirl.twirl(respcount, discovered.size)
|
783
803
|
end
|
784
804
|
|
805
|
+
if (batch_size =~ /^(\d+)%$/)
|
806
|
+
# determine batch_size as a percentage of the discovered array's size
|
807
|
+
batch_size = (discovered.size / 100.0 * Integer($1)).ceil
|
808
|
+
else
|
809
|
+
batch_size = Integer(batch_size)
|
810
|
+
end
|
811
|
+
|
785
812
|
@stats.requestid = nil
|
813
|
+
processed_nodes = 0
|
786
814
|
|
787
|
-
discovered.in_groups_of(batch_size) do |hosts
|
788
|
-
message = Message.new(req, nil, {:agent => @agent,
|
815
|
+
discovered.in_groups_of(batch_size) do |hosts|
|
816
|
+
message = Message.new(req, nil, {:agent => @agent,
|
817
|
+
:type => :direct_request,
|
818
|
+
:collective => @collective,
|
819
|
+
:filter => opts[:filter],
|
820
|
+
:options => opts})
|
789
821
|
|
790
822
|
# first time round we let the Message object create a request id
|
791
823
|
# we then re-use it for future requests to keep auditing sane etc
|
@@ -808,13 +840,20 @@ module MCollective
|
|
808
840
|
end
|
809
841
|
end
|
810
842
|
|
843
|
+
if @initial_options[:sort]
|
844
|
+
results.sort!
|
845
|
+
end
|
846
|
+
|
811
847
|
@stats.noresponsefrom.concat @client.stats[:noresponsefrom]
|
812
848
|
@stats.responses += @client.stats[:responses]
|
813
849
|
@stats.blocktime += @client.stats[:blocktime] + sleep_time
|
814
850
|
@stats.totaltime += @client.stats[:totaltime]
|
815
851
|
@stats.discoverytime += @client.stats[:discoverytime]
|
816
852
|
|
817
|
-
|
853
|
+
processed_nodes += hosts.length
|
854
|
+
if (discovered.length > processed_nodes)
|
855
|
+
sleep sleep_time
|
856
|
+
end
|
818
857
|
end
|
819
858
|
|
820
859
|
@stats.aggregate_summary = aggregate.summarize if aggregate
|
@@ -898,6 +937,10 @@ module MCollective
|
|
898
937
|
end
|
899
938
|
end
|
900
939
|
|
940
|
+
if @initial_options[:sort]
|
941
|
+
results.sort!
|
942
|
+
end
|
943
|
+
|
901
944
|
@stats.aggregate_summary = aggregate.summarize if aggregate
|
902
945
|
@stats.aggregate_failures = aggregate.failed if aggregate
|
903
946
|
@stats.client_stats = @client.stats
|
@@ -947,35 +990,46 @@ module MCollective
|
|
947
990
|
result = rpc_result_from_reply(@agent, action, resp)
|
948
991
|
aggregate = aggregate_reply(result, aggregate) if aggregate
|
949
992
|
|
950
|
-
if resp[:body][:statuscode] == 0
|
951
|
-
|
952
|
-
|
953
|
-
@stats.time_block_execution :start
|
993
|
+
@stats.ok if resp[:body][:statuscode] == 0
|
994
|
+
@stats.fail if resp[:body][:statuscode] != 0
|
995
|
+
@stats.time_block_execution :start
|
954
996
|
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
997
|
+
case block.arity
|
998
|
+
when 1
|
999
|
+
block.call(resp)
|
1000
|
+
when 2
|
1001
|
+
block.call(resp, result)
|
1002
|
+
end
|
961
1003
|
|
962
|
-
|
963
|
-
else
|
964
|
-
@stats.fail
|
1004
|
+
@stats.time_block_execution :end
|
965
1005
|
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
1006
|
+
return aggregate
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
private
|
1010
|
+
|
1011
|
+
def determine_batch_mode(batch_size)
|
1012
|
+
if (batch_size != 0 && batch_size != "0")
|
1013
|
+
return true
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
return false
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
# Validate the bach_size based on the following criteria
|
1020
|
+
# batch_size is percentage string and it's more than 0 percent
|
1021
|
+
# batch_size is a string of digits
|
1022
|
+
# batch_size is of type Integer
|
1023
|
+
def validate_batch_size(batch_size)
|
1024
|
+
if (batch_size.is_a?(Integer))
|
1025
|
+
return
|
1026
|
+
elsif (batch_size.is_a?(String))
|
1027
|
+
if ((batch_size =~ /^(\d+)%$/ && Integer($1) != 0) || batch_size =~ /^(\d+)$/)
|
1028
|
+
return
|
975
1029
|
end
|
976
1030
|
end
|
977
1031
|
|
978
|
-
|
1032
|
+
raise("batch_size must be an integer or match a percentage string (e.g. '24%'")
|
979
1033
|
end
|
980
1034
|
end
|
981
1035
|
end
|