choria-mcorpc-support 0.0.1

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.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/bin/mco +64 -0
  3. data/lib/mcollective.rb +63 -0
  4. data/lib/mcollective/agent.rb +5 -0
  5. data/lib/mcollective/agents.rb +149 -0
  6. data/lib/mcollective/aggregate.rb +85 -0
  7. data/lib/mcollective/aggregate/average.ddl +33 -0
  8. data/lib/mcollective/aggregate/average.rb +29 -0
  9. data/lib/mcollective/aggregate/base.rb +40 -0
  10. data/lib/mcollective/aggregate/result.rb +9 -0
  11. data/lib/mcollective/aggregate/result/base.rb +25 -0
  12. data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
  13. data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
  14. data/lib/mcollective/aggregate/sum.ddl +33 -0
  15. data/lib/mcollective/aggregate/sum.rb +18 -0
  16. data/lib/mcollective/aggregate/summary.ddl +33 -0
  17. data/lib/mcollective/aggregate/summary.rb +53 -0
  18. data/lib/mcollective/application.rb +365 -0
  19. data/lib/mcollective/application/completion.rb +104 -0
  20. data/lib/mcollective/application/describe_filter.rb +87 -0
  21. data/lib/mcollective/application/facts.rb +62 -0
  22. data/lib/mcollective/application/find.rb +23 -0
  23. data/lib/mcollective/application/help.rb +28 -0
  24. data/lib/mcollective/application/inventory.rb +344 -0
  25. data/lib/mcollective/application/ping.rb +82 -0
  26. data/lib/mcollective/application/plugin.rb +369 -0
  27. data/lib/mcollective/application/rpc.rb +111 -0
  28. data/lib/mcollective/applications.rb +134 -0
  29. data/lib/mcollective/cache.rb +145 -0
  30. data/lib/mcollective/client.rb +353 -0
  31. data/lib/mcollective/config.rb +245 -0
  32. data/lib/mcollective/connector.rb +18 -0
  33. data/lib/mcollective/connector/base.rb +26 -0
  34. data/lib/mcollective/data.rb +91 -0
  35. data/lib/mcollective/data/agent_data.ddl +22 -0
  36. data/lib/mcollective/data/agent_data.rb +17 -0
  37. data/lib/mcollective/data/base.rb +67 -0
  38. data/lib/mcollective/data/collective_data.ddl +20 -0
  39. data/lib/mcollective/data/collective_data.rb +9 -0
  40. data/lib/mcollective/data/fact_data.ddl +28 -0
  41. data/lib/mcollective/data/fact_data.rb +55 -0
  42. data/lib/mcollective/data/fstat_data.ddl +89 -0
  43. data/lib/mcollective/data/fstat_data.rb +56 -0
  44. data/lib/mcollective/data/result.rb +45 -0
  45. data/lib/mcollective/ddl.rb +113 -0
  46. data/lib/mcollective/ddl/agentddl.rb +253 -0
  47. data/lib/mcollective/ddl/base.rb +217 -0
  48. data/lib/mcollective/ddl/dataddl.rb +56 -0
  49. data/lib/mcollective/ddl/discoveryddl.rb +52 -0
  50. data/lib/mcollective/ddl/validatorddl.rb +6 -0
  51. data/lib/mcollective/discovery.rb +143 -0
  52. data/lib/mcollective/discovery/flatfile.ddl +11 -0
  53. data/lib/mcollective/discovery/flatfile.rb +48 -0
  54. data/lib/mcollective/discovery/mc.ddl +11 -0
  55. data/lib/mcollective/discovery/mc.rb +30 -0
  56. data/lib/mcollective/discovery/stdin.ddl +11 -0
  57. data/lib/mcollective/discovery/stdin.rb +68 -0
  58. data/lib/mcollective/exceptions.rb +28 -0
  59. data/lib/mcollective/facts.rb +39 -0
  60. data/lib/mcollective/facts/base.rb +100 -0
  61. data/lib/mcollective/facts/yaml_facts.rb +65 -0
  62. data/lib/mcollective/generators.rb +7 -0
  63. data/lib/mcollective/generators/agent_generator.rb +51 -0
  64. data/lib/mcollective/generators/base.rb +46 -0
  65. data/lib/mcollective/generators/data_generator.rb +51 -0
  66. data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
  67. data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
  68. data/lib/mcollective/generators/templates/ddl.erb +8 -0
  69. data/lib/mcollective/generators/templates/plugin.erb +7 -0
  70. data/lib/mcollective/log.rb +118 -0
  71. data/lib/mcollective/logger.rb +5 -0
  72. data/lib/mcollective/logger/base.rb +77 -0
  73. data/lib/mcollective/logger/console_logger.rb +61 -0
  74. data/lib/mcollective/logger/file_logger.rb +53 -0
  75. data/lib/mcollective/logger/syslog_logger.rb +53 -0
  76. data/lib/mcollective/matcher.rb +224 -0
  77. data/lib/mcollective/matcher/parser.rb +128 -0
  78. data/lib/mcollective/matcher/scanner.rb +241 -0
  79. data/lib/mcollective/message.rb +248 -0
  80. data/lib/mcollective/monkey_patches.rb +152 -0
  81. data/lib/mcollective/optionparser.rb +197 -0
  82. data/lib/mcollective/pluginmanager.rb +180 -0
  83. data/lib/mcollective/pluginpackager.rb +98 -0
  84. data/lib/mcollective/pluginpackager/agent_definition.rb +94 -0
  85. data/lib/mcollective/pluginpackager/debpackage_packager.rb +237 -0
  86. data/lib/mcollective/pluginpackager/modulepackage_packager.rb +127 -0
  87. data/lib/mcollective/pluginpackager/ospackage_packager.rb +59 -0
  88. data/lib/mcollective/pluginpackager/rpmpackage_packager.rb +180 -0
  89. data/lib/mcollective/pluginpackager/standard_definition.rb +69 -0
  90. data/lib/mcollective/pluginpackager/templates/debian/Makefile.erb +7 -0
  91. data/lib/mcollective/pluginpackager/templates/debian/changelog.erb +5 -0
  92. data/lib/mcollective/pluginpackager/templates/debian/compat.erb +1 -0
  93. data/lib/mcollective/pluginpackager/templates/debian/control.erb +15 -0
  94. data/lib/mcollective/pluginpackager/templates/debian/copyright.erb +8 -0
  95. data/lib/mcollective/pluginpackager/templates/debian/rules.erb +6 -0
  96. data/lib/mcollective/pluginpackager/templates/module/Modulefile.erb +5 -0
  97. data/lib/mcollective/pluginpackager/templates/module/README.md.erb +37 -0
  98. data/lib/mcollective/pluginpackager/templates/module/_manifest.pp.erb +9 -0
  99. data/lib/mcollective/pluginpackager/templates/redhat/rpm_spec.erb +63 -0
  100. data/lib/mcollective/registration/base.rb +91 -0
  101. data/lib/mcollective/rpc.rb +182 -0
  102. data/lib/mcollective/rpc/actionrunner.rb +158 -0
  103. data/lib/mcollective/rpc/agent.rb +374 -0
  104. data/lib/mcollective/rpc/audit.rb +38 -0
  105. data/lib/mcollective/rpc/client.rb +1066 -0
  106. data/lib/mcollective/rpc/helpers.rb +321 -0
  107. data/lib/mcollective/rpc/progress.rb +63 -0
  108. data/lib/mcollective/rpc/reply.rb +87 -0
  109. data/lib/mcollective/rpc/request.rb +86 -0
  110. data/lib/mcollective/rpc/result.rb +90 -0
  111. data/lib/mcollective/rpc/stats.rb +294 -0
  112. data/lib/mcollective/runnerstats.rb +90 -0
  113. data/lib/mcollective/security.rb +26 -0
  114. data/lib/mcollective/security/base.rb +244 -0
  115. data/lib/mcollective/shell.rb +126 -0
  116. data/lib/mcollective/ssl.rb +285 -0
  117. data/lib/mcollective/util.rb +579 -0
  118. data/lib/mcollective/validator.rb +85 -0
  119. data/lib/mcollective/validator/array_validator.ddl +7 -0
  120. data/lib/mcollective/validator/array_validator.rb +9 -0
  121. data/lib/mcollective/validator/ipv4address_validator.ddl +7 -0
  122. data/lib/mcollective/validator/ipv4address_validator.rb +16 -0
  123. data/lib/mcollective/validator/ipv6address_validator.ddl +7 -0
  124. data/lib/mcollective/validator/ipv6address_validator.rb +16 -0
  125. data/lib/mcollective/validator/length_validator.ddl +7 -0
  126. data/lib/mcollective/validator/length_validator.rb +11 -0
  127. data/lib/mcollective/validator/regex_validator.ddl +7 -0
  128. data/lib/mcollective/validator/regex_validator.rb +9 -0
  129. data/lib/mcollective/validator/shellsafe_validator.ddl +7 -0
  130. data/lib/mcollective/validator/shellsafe_validator.rb +13 -0
  131. data/lib/mcollective/validator/typecheck_validator.ddl +7 -0
  132. data/lib/mcollective/validator/typecheck_validator.rb +28 -0
  133. metadata +215 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6ae1643132a522cc95d0ca2aa305795d0339a552
4
+ data.tar.gz: 3bb0890088ba7f874d81df9ea7dc494f2a9ab485
5
+ SHA512:
6
+ metadata.gz: d6b85252e78fe6d90b2c269ca47b06879a963e9108f16170061d05a5da18ac5ccc388a98cfd52a59e1c3360806174dfcbc46bb2409e3814a6c1efc503a9cb788
7
+ data.tar.gz: b09baf095839b1915238661d5bd4ea5430b780318cae53c77bea645a3a23c3b21d3d986da3e25d920d220366961931a23ba59d1fc781c492db2fcead4d2168f5
data/bin/mco ADDED
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # For security reasons, ensure that '.' is not on the load path
4
+ # This is primarily for 1.8.7 since 1.9.2+ doesn't put '.' on the load path
5
+ $LOAD_PATH.delete '.'
6
+
7
+ require 'mcollective'
8
+
9
+ # assume everything will all be fine
10
+ exitcode = 0
11
+
12
+ Version = MCollective.version
13
+ known_applications = MCollective::Applications.list
14
+
15
+ # links from mc-ping to mc will result in ping being run
16
+ if $0 =~ /mc\-([a-zA-Z\-_\.]+)$/
17
+ app_name = $1
18
+ else
19
+ app_name = ARGV.first
20
+ ARGV.delete_at(0)
21
+
22
+ # it may be a config option rather than an application name. In this
23
+ # case pretend we had no application name
24
+ if app_name =~ /^--/
25
+ app_name = nil
26
+ end
27
+ end
28
+
29
+ if known_applications.include?(app_name)
30
+ # make sure the various options classes shows the right help etc
31
+ $0 = app_name
32
+
33
+ MCollective::Applications.run(app_name)
34
+ else
35
+ puts "The Marionette Collective version #{MCollective.version}"
36
+ puts
37
+
38
+ if app_name
39
+ puts "Unknown command '#{app_name}', searched for applications in:"
40
+ puts
41
+ puts MCollective::Config.instance.libdir.map { |path| " #{path}\n" }
42
+ puts
43
+
44
+ # exit with an error as we didn't find a command
45
+ exitcode = 1
46
+ else
47
+ puts "usage: #{$0} command <options>"
48
+ puts
49
+ end
50
+
51
+ puts "Known commands:"
52
+ puts
53
+
54
+ known_applications.sort.uniq.in_groups_of(3) do |apps|
55
+ puts " %-20s %-20s %-20s" % [apps[0], apps[1], apps[2]]
56
+ end
57
+
58
+ puts
59
+ puts "Type '#{$0} help' for a detailed list of commands and '#{$0} help command'"
60
+ puts "to get detailed help for a command"
61
+ puts
62
+ end
63
+
64
+ exit exitcode
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require 'timeout'
4
+ require 'digest/md5'
5
+ require 'optparse'
6
+ require 'singleton'
7
+ require 'socket'
8
+ require 'erb'
9
+ require 'shellwords'
10
+ require 'stringio'
11
+ require 'rbconfig'
12
+ require 'tempfile'
13
+ require 'tmpdir'
14
+ require 'mcollective/monkey_patches'
15
+ require 'mcollective/cache'
16
+ require 'mcollective/exceptions'
17
+ require 'systemu'
18
+
19
+ # == The Marionette Collective
20
+ #
21
+ # Framework to build and run Systems Administration agents running on a
22
+ # publish/subscribe middleware system. The system allows you to treat your
23
+ # network as the only true source of the state of your platform via discovery agents
24
+ # and allow you to run agents matching discovery criteria.
25
+ #
26
+ # For an overview of the idea behind this and what it enables please see:
27
+ # http://www.devco.net/archives/2009/10/18/middleware_for_systems_administration.php
28
+ module MCollective
29
+
30
+ require "mcollective/agent"
31
+ require "mcollective/agents"
32
+ require "mcollective/aggregate"
33
+ require "mcollective/application"
34
+ require "mcollective/applications"
35
+ require "mcollective/client"
36
+ require "mcollective/config"
37
+ require "mcollective/connector"
38
+ require "mcollective/data"
39
+ require "mcollective/ddl"
40
+ require "mcollective/discovery"
41
+ require "mcollective/facts"
42
+ require "mcollective/logger"
43
+ require "mcollective/log"
44
+ require "mcollective/matcher"
45
+ require "mcollective/message"
46
+ require "mcollective/optionparser"
47
+ require "mcollective/generators"
48
+ require "mcollective/pluginmanager"
49
+ require "mcollective/pluginpackager"
50
+ require "mcollective/rpc"
51
+ require "mcollective/runnerstats"
52
+ require "mcollective/security"
53
+ require "mcollective/shell"
54
+ require "mcollective/ssl"
55
+ require "mcollective/util"
56
+ require "mcollective/validator"
57
+
58
+ VERSION="2.20.0"
59
+
60
+ def self.version
61
+ VERSION
62
+ end
63
+ end
@@ -0,0 +1,5 @@
1
+ module MCollective
2
+ module Agent
3
+
4
+ end
5
+ end
@@ -0,0 +1,149 @@
1
+ module MCollective
2
+ # A collection of agents, loads them, reloads them and dispatches messages to them.
3
+ # It uses the PluginManager to store, load and manage instances of plugins.
4
+ class Agents
5
+ def initialize(agents = {})
6
+ @config = Config.instance
7
+ raise ("Configuration has not been loaded, can't load agents") unless @config.configured
8
+
9
+ @@agents = agents
10
+
11
+ loadagents
12
+ end
13
+
14
+ # Deletes all agents
15
+ def clear!
16
+ @@agents.each_key do |agent|
17
+ PluginManager.delete "#{agent}_agent"
18
+ Util.unsubscribe(Util.make_subscriptions(agent, :broadcast))
19
+ end
20
+
21
+ @@agents = {}
22
+ end
23
+
24
+ # Loads all agents from disk
25
+ def loadagents
26
+ Log.debug("Reloading all agents from disk")
27
+
28
+ clear!
29
+
30
+ @config.libdir.each do |libdir|
31
+ agentdir = "#{libdir}/mcollective/agent"
32
+ next unless File.directory?(agentdir)
33
+
34
+ Dir.new(agentdir).grep(/\.rb$/).each do |agent|
35
+ agentname = File.basename(agent, ".rb")
36
+ loadagent(agentname) unless PluginManager.include?("#{agentname}_agent")
37
+ end
38
+ end
39
+ end
40
+
41
+ # Loads a specified agent from disk if available
42
+ def loadagent(agentname)
43
+ agentfile = findagentfile(agentname)
44
+ return false unless agentfile
45
+ classname = class_for_agent(agentname)
46
+
47
+ PluginManager.delete("#{agentname}_agent")
48
+
49
+ begin
50
+ single_instance = ["registration", "discovery"].include?(agentname)
51
+
52
+ PluginManager.loadclass(classname)
53
+
54
+ if activate_agent?(agentname)
55
+ PluginManager << {:type => "#{agentname}_agent", :class => classname, :single_instance => single_instance}
56
+
57
+ # Attempt to instantiate the agent once so any validation and hooks get run
58
+ # this does a basic sanity check on the agent as a whole, if this fails it
59
+ # will be removed from the plugin list
60
+ PluginManager["#{agentname}_agent"]
61
+
62
+ Util.subscribe(Util.make_subscriptions(agentname, :broadcast)) unless @@agents.include?(agentname)
63
+
64
+ @@agents[agentname] = {:file => agentfile}
65
+ return true
66
+ else
67
+ Log.debug("Not activating agent #{agentname} due to agent policy in activate? method")
68
+ return false
69
+ end
70
+ rescue Exception => e
71
+ Log.error("Loading agent #{agentname} failed: #{e}")
72
+ PluginManager.delete("#{agentname}_agent")
73
+ return false
74
+ end
75
+ end
76
+
77
+ # Builds a class name string given a Agent name
78
+ def class_for_agent(agent)
79
+ "MCollective::Agent::#{agent.capitalize}"
80
+ end
81
+
82
+ # Checks if a plugin should be activated by
83
+ # calling #activate? on it if it responds to
84
+ # that method else always activate it
85
+ def activate_agent?(agent)
86
+ klass = Kernel.const_get("MCollective").const_get("Agent").const_get(agent.capitalize)
87
+
88
+ if klass.respond_to?("activate?")
89
+ return klass.activate?
90
+ else
91
+ Log.debug("#{klass} does not have an activate? method, activating as default")
92
+ return true
93
+ end
94
+ rescue Exception => e
95
+ Log.warn("Agent activation check for #{agent} failed: #{e.class}: #{e}")
96
+ return false
97
+ end
98
+
99
+ # searches the libdirs for agents
100
+ def findagentfile(agentname)
101
+ @config.libdir.each do |libdir|
102
+ agentfile = File.join([libdir, "mcollective", "agent", "#{agentname}.rb"])
103
+ if File.exist?(agentfile)
104
+ Log.debug("Found #{agentname} at #{agentfile}")
105
+ return agentfile
106
+ end
107
+ end
108
+ return false
109
+ end
110
+
111
+ # Determines if we have an agent with a certain name
112
+ def include?(agentname)
113
+ PluginManager.include?("#{agentname}_agent")
114
+ end
115
+
116
+ # Dispatches a message to an agent, accepts a block that will get run if there are
117
+ # any replies to process from the agent
118
+ def dispatch(request, connection)
119
+ Log.debug("Dispatching a message to agent #{request.agent}")
120
+
121
+ Thread.new do
122
+ begin
123
+ agent = PluginManager["#{request.agent}_agent"]
124
+
125
+ Timeout::timeout(agent.timeout) do
126
+ replies = agent.handlemsg(request.payload, connection)
127
+
128
+ # Agents can decide if they wish to reply or not,
129
+ # returning nil will mean nothing goes back to the
130
+ # requestor
131
+ unless replies == nil
132
+ yield(replies)
133
+ end
134
+ end
135
+ rescue Timeout::Error => e
136
+ Log.warn("Timeout while handling message for #{request.agent}")
137
+ rescue Exception => e
138
+ Log.error("Execution of #{request.agent} failed: #{e}")
139
+ Log.error(e.backtrace.join("\n\t\t"))
140
+ end
141
+ end
142
+ end
143
+
144
+ # Get a list of agents that we have
145
+ def self.agentlist
146
+ @@agents.keys
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,85 @@
1
+ module MCollective
2
+ class Aggregate
3
+ require 'mcollective/aggregate/result'
4
+ require 'mcollective/aggregate/base'
5
+
6
+ attr_accessor :ddl, :functions, :action, :failed
7
+
8
+ def initialize(ddl)
9
+ @functions = []
10
+ @ddl = ddl
11
+ @action = ddl[:action]
12
+ @failed = []
13
+
14
+ create_functions
15
+ end
16
+
17
+ # Creates instances of the Aggregate functions and stores them in the function array.
18
+ # All aggregate call and summarize method calls operate on these function as a batch.
19
+ def create_functions
20
+ @ddl[:aggregate].each_with_index do |agg, i|
21
+ output = agg[:args][0]
22
+
23
+ if contains_output?(output)
24
+ arguments = agg[:args][1]
25
+ format = (arguments.delete(:format) if arguments) || nil
26
+ begin
27
+ @functions << load_function(agg[:function]).new(output, arguments, format, @action)
28
+ rescue Exception => e
29
+ Log.error("Cannot create aggregate function '#{output}'. #{e.to_s}")
30
+ @failed << {:name => output, :type => :startup}
31
+ end
32
+ else
33
+ Log.error("Cannot create aggregate function '#{output}'. '#{output}' has not been specified as a valid ddl output.")
34
+ @failed << {:name => output, :type => :create}
35
+ end
36
+ end
37
+ end
38
+
39
+ # Check if the function param is defined as an output for the action in the ddl
40
+ def contains_output?(output)
41
+ @ddl[:output].keys.include?(output)
42
+ end
43
+
44
+ # Call all the appropriate functions with the reply data received from RPC::Client
45
+ def call_functions(reply)
46
+ @functions.each do |function|
47
+ Log.debug("Calling aggregate function #{function} for result")
48
+ begin
49
+ function.process_result(reply[:data][function.output_name], reply)
50
+ rescue Exception => e
51
+ Log.error("Could not process aggregate function for '#{function.output_name}'. #{e.to_s}")
52
+ @failed << {:name => function.output_name, :type => :process_result}
53
+ @functions.delete(function)
54
+ end
55
+ end
56
+ end
57
+
58
+ # Finalizes the function returning a result object
59
+ def summarize
60
+ summary = @functions.map do |function|
61
+ begin
62
+ function.summarize
63
+ rescue Exception => e
64
+ Log.error("Could not summarize aggregate result for '#{function.output_name}'. #{e.to_s}")
65
+ @failed << {:name => function.output_name, :type => :summarize}
66
+ nil
67
+ end
68
+ end
69
+
70
+ summary.reject{|x| x.nil?}.sort do |x,y|
71
+ x.result[:output] <=> y.result[:output]
72
+ end
73
+ end
74
+
75
+ # Loads function from disk for use
76
+ def load_function(function_name)
77
+ function_name = function_name.to_s.capitalize
78
+
79
+ PluginManager.loadclass("MCollective::Aggregate::#{function_name}") unless Aggregate.const_defined?(function_name)
80
+ Aggregate.const_get(function_name)
81
+ rescue Exception
82
+ raise "Aggregate function file '#{function_name.downcase}.rb' cannot be loaded"
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,33 @@
1
+ metadata :name => "average",
2
+ :description => "Displays the average of a set of numeric values",
3
+ :author => "Pieter Loubser <pieter.loubser@puppetlabs.com>",
4
+ :license => "ASL 2.0",
5
+ :version => "1.0",
6
+ :url => "https://docs.puppetlabs.com/mcollective/plugin_directory/",
7
+ :timeout => 5
8
+
9
+ usage <<-USAGE
10
+
11
+ This aggregate plugin will determine the average of a set of numeric values.
12
+
13
+ DDL Example:
14
+
15
+ summarize do
16
+ aggregate average(:value)
17
+ end
18
+
19
+ Sample Output:
20
+
21
+ host1.example.com
22
+ Value: 10
23
+
24
+ host2.example.com
25
+ Value: 20
26
+
27
+
28
+ Summary of Value:
29
+
30
+ Average of Value: 15.000000
31
+
32
+ USAGE
33
+
@@ -0,0 +1,29 @@
1
+ module MCollective
2
+ class Aggregate
3
+ class Average<Base
4
+ # Before function is run processing
5
+ def startup_hook
6
+ @result[:value] = 0
7
+ @result[:type] = :numeric
8
+
9
+ @count = 0
10
+
11
+ # Set default aggregate_function if it is undefined
12
+ @aggregate_format = "Average of #{@result[:output]}: %f" unless @aggregate_format
13
+ end
14
+
15
+ # Determines the average of a set of numerical values
16
+ def process_result(value, reply)
17
+ @result[:value] += value
18
+ @count += 1
19
+ end
20
+
21
+ # Stops execution of the function and returns a ResultObject
22
+ def summarize
23
+ @result[:value] /= @count
24
+
25
+ result_class(:numeric).new(@result, @aggregate_format, @action)
26
+ end
27
+ end
28
+ end
29
+ end