choria-mcorpc-support 2.21.0 → 2.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mcollective.rb +1 -1
  3. data/lib/mcollective/agent/bolt_tasks.ddl +235 -0
  4. data/lib/mcollective/agent/bolt_tasks.json +347 -0
  5. data/lib/mcollective/agent/bolt_tasks.rb +176 -0
  6. data/lib/mcollective/agent/choria_util.ddl +152 -0
  7. data/lib/mcollective/agent/choria_util.json +244 -0
  8. data/lib/mcollective/agent/rpcutil.ddl +7 -3
  9. data/lib/mcollective/agent/rpcutil.json +333 -0
  10. data/lib/mcollective/agent/scout.ddl +169 -0
  11. data/lib/mcollective/agent/scout.json +224 -0
  12. data/lib/mcollective/agents.rb +7 -6
  13. data/lib/mcollective/aggregate.rb +4 -4
  14. data/lib/mcollective/aggregate/average.rb +2 -2
  15. data/lib/mcollective/aggregate/base.rb +2 -2
  16. data/lib/mcollective/aggregate/result.rb +3 -3
  17. data/lib/mcollective/aggregate/result/collection_result.rb +2 -2
  18. data/lib/mcollective/aggregate/result/numeric_result.rb +2 -2
  19. data/lib/mcollective/aggregate/sum.rb +2 -2
  20. data/lib/mcollective/aggregate/summary.rb +3 -4
  21. data/lib/mcollective/application.rb +57 -21
  22. data/lib/mcollective/application/choria.rb +249 -0
  23. data/lib/mcollective/application/completion.rb +6 -6
  24. data/lib/mcollective/application/describe_filter.rb +20 -20
  25. data/lib/mcollective/application/facts.rb +19 -11
  26. data/lib/mcollective/application/federation.rb +239 -0
  27. data/lib/mcollective/application/find.rb +4 -4
  28. data/lib/mcollective/application/help.rb +3 -3
  29. data/lib/mcollective/application/inventory.rb +3 -341
  30. data/lib/mcollective/application/ping.rb +3 -77
  31. data/lib/mcollective/application/playbook.rb +207 -0
  32. data/lib/mcollective/application/plugin.rb +106 -106
  33. data/lib/mcollective/application/rpc.rb +3 -108
  34. data/lib/mcollective/application/tasks.rb +416 -0
  35. data/lib/mcollective/applications.rb +11 -10
  36. data/lib/mcollective/audit/choria.rb +33 -0
  37. data/lib/mcollective/cache.rb +2 -4
  38. data/lib/mcollective/client.rb +11 -10
  39. data/lib/mcollective/config.rb +21 -34
  40. data/lib/mcollective/connector/base.rb +2 -1
  41. data/lib/mcollective/connector/nats.ddl +9 -0
  42. data/lib/mcollective/connector/nats.rb +450 -0
  43. data/lib/mcollective/data.rb +8 -3
  44. data/lib/mcollective/data/agent_data.rb +1 -1
  45. data/lib/mcollective/data/base.rb +6 -5
  46. data/lib/mcollective/data/bolt_task_data.ddl +90 -0
  47. data/lib/mcollective/data/bolt_task_data.rb +32 -0
  48. data/lib/mcollective/data/collective_data.rb +1 -1
  49. data/lib/mcollective/data/fact_data.rb +6 -6
  50. data/lib/mcollective/data/fstat_data.rb +2 -4
  51. data/lib/mcollective/data/result.rb +7 -2
  52. data/lib/mcollective/ddl/agentddl.rb +5 -17
  53. data/lib/mcollective/ddl/base.rb +10 -13
  54. data/lib/mcollective/discovery.rb +12 -26
  55. data/lib/mcollective/discovery/choria.ddl +11 -0
  56. data/lib/mcollective/discovery/choria.rb +223 -0
  57. data/lib/mcollective/discovery/flatfile.rb +7 -8
  58. data/lib/mcollective/discovery/mc.rb +2 -2
  59. data/lib/mcollective/discovery/stdin.rb +17 -18
  60. data/lib/mcollective/exceptions.rb +13 -0
  61. data/lib/mcollective/facts/base.rb +9 -9
  62. data/lib/mcollective/facts/yaml_facts.rb +12 -12
  63. data/lib/mcollective/generators.rb +3 -3
  64. data/lib/mcollective/generators/agent_generator.rb +3 -4
  65. data/lib/mcollective/generators/base.rb +14 -15
  66. data/lib/mcollective/generators/data_generator.rb +5 -6
  67. data/lib/mcollective/log.rb +2 -2
  68. data/lib/mcollective/logger/base.rb +3 -2
  69. data/lib/mcollective/logger/console_logger.rb +10 -10
  70. data/lib/mcollective/logger/file_logger.rb +7 -7
  71. data/lib/mcollective/logger/syslog_logger.rb +11 -15
  72. data/lib/mcollective/matcher.rb +14 -14
  73. data/lib/mcollective/matcher/parser.rb +31 -41
  74. data/lib/mcollective/matcher/scanner.rb +69 -74
  75. data/lib/mcollective/message.rb +10 -17
  76. data/lib/mcollective/monkey_patches.rb +2 -4
  77. data/lib/mcollective/optionparser.rb +1 -0
  78. data/lib/mcollective/pluginmanager.rb +3 -5
  79. data/lib/mcollective/pluginpackager.rb +1 -3
  80. data/lib/mcollective/pluginpackager/agent_definition.rb +3 -8
  81. data/lib/mcollective/pluginpackager/forge_packager.rb +7 -9
  82. data/lib/mcollective/pluginpackager/standard_definition.rb +1 -2
  83. data/lib/mcollective/registration/base.rb +18 -16
  84. data/lib/mcollective/rpc.rb +2 -4
  85. data/lib/mcollective/rpc/actionrunner.rb +16 -18
  86. data/lib/mcollective/rpc/agent.rb +26 -43
  87. data/lib/mcollective/rpc/audit.rb +1 -0
  88. data/lib/mcollective/rpc/client.rb +67 -85
  89. data/lib/mcollective/rpc/helpers.rb +55 -62
  90. data/lib/mcollective/rpc/progress.rb +2 -2
  91. data/lib/mcollective/rpc/reply.rb +17 -19
  92. data/lib/mcollective/rpc/request.rb +7 -5
  93. data/lib/mcollective/rpc/result.rb +6 -8
  94. data/lib/mcollective/rpc/stats.rb +49 -58
  95. data/lib/mcollective/security/base.rb +29 -36
  96. data/lib/mcollective/security/choria.rb +765 -0
  97. data/lib/mcollective/shell.rb +9 -4
  98. data/lib/mcollective/signer/base.rb +28 -0
  99. data/lib/mcollective/signer/choria.rb +185 -0
  100. data/lib/mcollective/ssl.rb +8 -6
  101. data/lib/mcollective/util.rb +58 -55
  102. data/lib/mcollective/util/bolt_support.rb +176 -0
  103. data/lib/mcollective/util/bolt_support/plan_runner.rb +167 -0
  104. data/lib/mcollective/util/bolt_support/task_result.rb +94 -0
  105. data/lib/mcollective/util/bolt_support/task_results.rb +128 -0
  106. data/lib/mcollective/util/choria.rb +1103 -0
  107. data/lib/mcollective/util/indifferent_hash.rb +12 -0
  108. data/lib/mcollective/util/natswrapper.rb +242 -0
  109. data/lib/mcollective/util/playbook.rb +435 -0
  110. data/lib/mcollective/util/playbook/data_stores.rb +201 -0
  111. data/lib/mcollective/util/playbook/data_stores/base.rb +99 -0
  112. data/lib/mcollective/util/playbook/data_stores/consul_data_store.rb +88 -0
  113. data/lib/mcollective/util/playbook/data_stores/environment_data_store.rb +33 -0
  114. data/lib/mcollective/util/playbook/data_stores/etcd_data_store.rb +42 -0
  115. data/lib/mcollective/util/playbook/data_stores/file_data_store.rb +106 -0
  116. data/lib/mcollective/util/playbook/data_stores/shell_data_store.rb +103 -0
  117. data/lib/mcollective/util/playbook/inputs.rb +265 -0
  118. data/lib/mcollective/util/playbook/nodes.rb +207 -0
  119. data/lib/mcollective/util/playbook/nodes/mcollective_nodes.rb +86 -0
  120. data/lib/mcollective/util/playbook/nodes/pql_nodes.rb +40 -0
  121. data/lib/mcollective/util/playbook/nodes/shell_nodes.rb +55 -0
  122. data/lib/mcollective/util/playbook/nodes/terraform_nodes.rb +65 -0
  123. data/lib/mcollective/util/playbook/nodes/yaml_nodes.rb +47 -0
  124. data/lib/mcollective/util/playbook/playbook_logger.rb +47 -0
  125. data/lib/mcollective/util/playbook/puppet_logger.rb +51 -0
  126. data/lib/mcollective/util/playbook/report.rb +152 -0
  127. data/lib/mcollective/util/playbook/task_result.rb +55 -0
  128. data/lib/mcollective/util/playbook/tasks.rb +196 -0
  129. data/lib/mcollective/util/playbook/tasks/base.rb +45 -0
  130. data/lib/mcollective/util/playbook/tasks/graphite_event_task.rb +64 -0
  131. data/lib/mcollective/util/playbook/tasks/mcollective_task.rb +356 -0
  132. data/lib/mcollective/util/playbook/tasks/shell_task.rb +93 -0
  133. data/lib/mcollective/util/playbook/tasks/slack_task.rb +105 -0
  134. data/lib/mcollective/util/playbook/tasks/webhook_task.rb +136 -0
  135. data/lib/mcollective/util/playbook/template_util.rb +98 -0
  136. data/lib/mcollective/util/playbook/uses.rb +169 -0
  137. data/lib/mcollective/util/tasks_support.rb +733 -0
  138. data/lib/mcollective/util/tasks_support/cli.rb +260 -0
  139. data/lib/mcollective/util/tasks_support/default_formatter.rb +138 -0
  140. data/lib/mcollective/util/tasks_support/json_formatter.rb +108 -0
  141. data/lib/mcollective/validator.rb +6 -1
  142. data/lib/mcollective/validator/bolt_task_name_validator.ddl +7 -0
  143. data/lib/mcollective/validator/bolt_task_name_validator.rb +11 -0
  144. data/lib/mcollective/validator/length_validator.rb +1 -3
  145. metadata +65 -2
@@ -0,0 +1,176 @@
1
+ require "mcollective"
2
+ require_relative "choria"
3
+ require_relative "playbook"
4
+
5
+ require_relative "bolt_support/task_result"
6
+ require_relative "bolt_support/task_results"
7
+ require_relative "bolt_support/plan_runner"
8
+
9
+ module MCollective
10
+ module Util
11
+ class BoltSupport
12
+ def choria
13
+ @_choria ||= Choria.new
14
+ end
15
+
16
+ # Converts the current Puppet loglevel to one we understand
17
+ #
18
+ # @return ["debug", "info", "warn", "error", "fatal"]
19
+ def self.loglevel
20
+ case Puppet::Util::Log.level
21
+ when :notice, :warning
22
+ "warn"
23
+ when :err
24
+ "error"
25
+ when :alert, :emerg, :crit
26
+ "fatal"
27
+ else
28
+ Puppet::Util::Log.level.to_s
29
+ end
30
+ end
31
+
32
+ # Configures MCollective and initialize the Bolt Support class
33
+ #
34
+ # @return [BoltSupport]
35
+ def self.init_choria
36
+ Config.instance.loadconfig(Util.config_file_for_user) unless Config.instance.configured
37
+
38
+ new
39
+ end
40
+
41
+ # Creates a configured instance of the Playbook
42
+ #
43
+ # @return [Playbook]
44
+ def playbook
45
+ @_playbook ||= begin
46
+ pb = Playbook.new(self.class.loglevel)
47
+ pb.logger = Playbook::Puppet_Logger
48
+ pb.set_logger_level
49
+ pb
50
+ end
51
+ end
52
+
53
+ def nodes
54
+ @_nodes ||= Playbook::Nodes.new(playbook)
55
+ end
56
+
57
+ # Discovers nodes using playbook node sets
58
+ #
59
+ # @param scope [Puppet::Parser::Scope] scope to log against
60
+ # @param type [String] a known node set type like `terraform`
61
+ # @param properties [Hash] properties valid for the node set type
62
+ def discover_nodes(scope, type, properties)
63
+ uses_properties = properties.delete("uses") || {}
64
+ playbook.logger.scope = scope
65
+ assign_playbook_name(scope)
66
+ playbook.uses.from_hash(uses_properties)
67
+
68
+ nodes.from_hash("task_nodes" => properties.merge(
69
+ "type" => type,
70
+ "uses" => uses_properties.keys
71
+ ))
72
+
73
+ nodes.prepare
74
+ nodes["task_nodes"]
75
+ end
76
+
77
+ # Retrieves a data item from a data store
78
+ #
79
+ # @param scope [Puppet::Parser::Scope] scope to log against
80
+ # @param item [String] the item to fetch
81
+ # @param properties [Hash] the data source properties
82
+ def data_read(scope, item, properties)
83
+ playbook.logger.scope = scope
84
+ assign_playbook_name(scope)
85
+ playbook.data_stores.from_hash("plan_store" => properties)
86
+ playbook.data_stores.prepare
87
+ playbook.data_stores.read("plan_store/%s" % item)
88
+ end
89
+
90
+ # Writes a value to a data store
91
+ #
92
+ # @param scope [Puppet::Parser::Scope] scope to log against
93
+ # @param item [String] the item to fetch
94
+ # @param value [String] the item to fetch
95
+ # @param properties [Hash] the data source properties
96
+ # @return [String] the data that was written
97
+ def data_write(scope, item, value, properties)
98
+ config = {"plan_store" => properties}
99
+
100
+ playbook.logger.scope = scope
101
+ assign_playbook_name(scope)
102
+ playbook.data_stores.from_hash(config)
103
+ playbook.data_stores.prepare
104
+ playbook.data_stores.write("plan_store/%s" % item, value)
105
+ end
106
+
107
+ # Performs a block within a lock in a data store
108
+ #
109
+ # @param scope [Puppet::Parser::Scope] scope to log against
110
+ # @param item [String] the lock key
111
+ # @param properties [Hash] the data source properties
112
+ def data_lock(scope, item, properties, &blk)
113
+ locked = false
114
+ lock_path = "plan_store/%s" % item
115
+ config = {"plan_store" => properties}
116
+
117
+ playbook.logger.scope = scope
118
+ assign_playbook_name(scope)
119
+ playbook.data_stores.from_hash(config)
120
+ playbook.data_stores.prepare
121
+
122
+ playbook.data_stores.lock(lock_path)
123
+ locked = true
124
+
125
+ yield
126
+ ensure
127
+ playbook.data_stores.release(lock_path) if locked
128
+ end
129
+
130
+ # Runs a playbook task and return execution results
131
+ #
132
+ # @param scope [Puppet::Parser::Scope] scope to log against
133
+ # @param type [String] the task type
134
+ # @param properties [Hash] properties passed to the task
135
+ # @return [BoltSupport::TaskResults]
136
+ def run_task(scope, type, properties)
137
+ task_properties = properties.reject {|k, _| k.start_with?("_") }
138
+ playbook.logger.scope = scope
139
+ assign_playbook_name(scope)
140
+
141
+ tasks = playbook.tasks.load_tasks([type => task_properties], "tasks")
142
+
143
+ playbook.tasks.run_task(tasks[0], "plan", false)
144
+
145
+ result = tasks[0][:result]
146
+ runner = tasks[0][:runner]
147
+
148
+ execution_result = runner.to_execution_result([result.success, result.msg, result.data])
149
+
150
+ results = execution_result.map do |node, result_properties|
151
+ TaskResult.new(node, JSON.parse(result_properties.to_json))
152
+ end
153
+
154
+ task_results = TaskResults.new(results, nil)
155
+ task_results.message = result.msg
156
+
157
+ return task_results if result.success
158
+ return task_results if properties.fetch("fail_ok", false)
159
+ return task_results if properties["_catch_errors"]
160
+
161
+ raise(result.msg)
162
+ end
163
+
164
+ # Assigns the playbook name based on the fact choria.plan
165
+ #
166
+ # @see PlanRunner#in_environment
167
+ def assign_playbook_name(scope)
168
+ return unless scope
169
+ return unless scope["facts"]["choria"]
170
+ return unless scope["facts"]["choria"]["playbook"]
171
+
172
+ playbook.metadata["name"] = scope["facts"]["choria"]["playbook"]
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,167 @@
1
+ require "puppet"
2
+ require "puppet_pal"
3
+ require "tmpdir"
4
+
5
+ module MCollective
6
+ module Util
7
+ class BoltSupport
8
+ class PlanRunner
9
+ def self.init_puppet
10
+ TaskResults.include_iterable
11
+ Puppet::Util::Log.newdestination(:console)
12
+ end
13
+
14
+ init_puppet
15
+
16
+ attr_reader :modulepath
17
+
18
+ # @param plan [String] the name of the plan to use
19
+ # @param tmpdir [String] the path to an already existing temporary directory
20
+ # @param modulepath [String,nil] a : seperated list of locations to look for modules, uses puppet basemodulepath if nil
21
+ # @param loglevel [debug, info, warn, err]
22
+ def initialize(plan, tmpdir, modulepath, loglevel)
23
+ @plan = plan
24
+ @loglevel = loglevel
25
+ @tmpdir = tmpdir
26
+
27
+ raise("A temporary directory could not be created") unless @tmpdir
28
+ raise("A temporary directory could not be created") unless File.directory?(@tmpdir)
29
+
30
+ @modulepath = modulepath
31
+
32
+ unless @modulepath
33
+ initialize_settings
34
+ @modulepath = Puppet.settings[:basemodulepath]
35
+ end
36
+
37
+ @modulepath = @modulepath.split(":")
38
+
39
+ Puppet[:log_level] = @loglevel
40
+ end
41
+
42
+ # Determines if the requested plan exist
43
+ #
44
+ # @return [Boolean]
45
+ def exist?
46
+ with_script_compiler do |compiler|
47
+ return !!compiler.plan_signature(@plan)
48
+ end
49
+ end
50
+
51
+ # Initialize Puppet to use the configured tmp dir
52
+ def puppet_cli_options
53
+ Puppet::Settings::REQUIRED_APP_SETTINGS.map do |setting|
54
+ "--%s %s" % [setting, @tmpdir]
55
+ end
56
+ end
57
+
58
+ # Retrieves the signature of a plan - its parameters and types
59
+ #
60
+ # NOTE: at present it's not possible to extract description or default values
61
+ #
62
+ # @return [Hash]
63
+ def plan_signature
64
+ with_script_compiler do |compiler|
65
+ sig = compiler.plan_signature(@plan)
66
+
67
+ raise("Cannot find playbook %s in %s" % [@plan, @modulepath.join(":")]) unless sig
68
+
69
+ sig.params_type.elements.map do |elem|
70
+ [elem.name, {
71
+ "type" => elem.value_type.to_s,
72
+ "required" => !elem.key_type.is_a?(Puppet::Pops::Types::POptionalType)
73
+ }]
74
+ end
75
+ end
76
+ end
77
+
78
+ # Yields a PAL script compiler in the temporary environment
79
+ def with_script_compiler(&block)
80
+ in_environment do |env|
81
+ env.with_script_compiler(&block)
82
+ end
83
+ end
84
+
85
+ # Facts to use in the environment
86
+ def facts
87
+ {
88
+ "choria" => {
89
+ "playbook" => @plan
90
+ }
91
+ }
92
+ end
93
+
94
+ def initialize_settings
95
+ Puppet.initialize_settings(puppet_cli_options) unless Puppet.settings.global_defaults_initialized?
96
+ end
97
+
98
+ # Sets up a temporary environment
99
+ def in_environment(&block)
100
+ initialize_settings
101
+
102
+ Puppet::Pal.in_tmp_environment("choria", :modulepath => @modulepath, :facts => facts, &block)
103
+ end
104
+
105
+ # Converts a Puppet type into something mcollective understands
106
+ #
107
+ # This is inevitably hacky by its nature, there is no way for me to
108
+ # parse the types. PAL might get some helpers for this but till then
109
+ # this is going to have to be best efforts.
110
+ #
111
+ # When there is a too complex situation users can always put in --input
112
+ # and some JSON to work around it until something better comes around
113
+ #
114
+ # @param type [String] a puppet type
115
+ # @return [Class, Boolean] The data type, if its an array input or not
116
+ def puppet_type_to_ruby(type)
117
+ array = false
118
+
119
+ type = $1 if type =~ /Optional\[(.+)/
120
+
121
+ if type =~ /Array\[(.+)/
122
+ type = $1
123
+ array = true
124
+ end
125
+
126
+ return [Numeric, array] if type =~ /Integer/
127
+ return [Numeric, array] if type =~ /Float/
128
+ return [Hash, array] if type =~ /Hash/
129
+ return [:boolean, array] if type =~ /Boolean/
130
+
131
+ [String, array]
132
+ end
133
+
134
+ def run!(params)
135
+ with_script_compiler do |compiler|
136
+ compiler.call_function("choria::run_playbook", @plan, params)
137
+ end
138
+ end
139
+
140
+ # Adds the CLI options for an application based on the playbook inputs
141
+ #
142
+ # @param application [MCollective::Application]
143
+ # @param set_required [Boolean]
144
+ def add_cli_options(application, set_required=false)
145
+ sig = plan_signature
146
+
147
+ return if sig.nil? || sig.empty?
148
+
149
+ sig.each do |name, details|
150
+ type, array = puppet_type_to_ruby(details["type"])
151
+
152
+ properties = {
153
+ :description => "Plan input property (%s)" % details["type"],
154
+ :arguments => "--%s %s" % [name.downcase, name.upcase],
155
+ :type => array ? :array : type
156
+ }
157
+
158
+ properties[:required] = true if details["required"] && set_required
159
+ properties[:arguments] = "--[no-]%s" % name.downcase if type == :boolean
160
+
161
+ application.class.option(name, properties)
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,94 @@
1
+ module MCollective
2
+ module Util
3
+ class BoltSupport
4
+ class TaskResult
5
+ attr_reader :host, :result
6
+
7
+ # Method used by Puppet to create the TaskResult from a hash
8
+ #
9
+ # @param hash [Hash] hash as prodused by various execution_result method
10
+ # @return [TaskResult]
11
+ def self.from_asserted_hash(hash)
12
+ new(hash.keys.first, hash.values.first)
13
+ end
14
+
15
+ # @param host [String] node name
16
+ # @param result [Hash] result value as produced by execution_result methods
17
+ def initialize(host, result)
18
+ @host = host
19
+ @result = result
20
+ end
21
+
22
+ def to_hash
23
+ {@host => @result}
24
+ end
25
+
26
+ def to_json(obj={})
27
+ to_hash.to_json(obj)
28
+ end
29
+
30
+ # A error object if this represents an error
31
+ #
32
+ # @return [Puppet::DataTypes::Error, nil]
33
+ def error
34
+ if @result["error"]
35
+ if defined?(Puppet::DataTypes::Error)
36
+ Puppet::DataTypes::Error.from_asserted_hash(@result["error"])
37
+ else
38
+ @result["error"]
39
+ end
40
+ end
41
+ end
42
+
43
+ # The type of task that created this result
44
+ #
45
+ # @return String examples like mcollective, data etc
46
+ def type
47
+ @result["type"]
48
+ end
49
+
50
+ # If this task result represents a succesful task
51
+ #
52
+ # This supposed fail_ok, any task with that set will be considered passed
53
+ #
54
+ # @return Boolean
55
+ def ok
56
+ return true if @result["fail_ok"]
57
+
58
+ !@result.include?("error")
59
+ end
60
+ alias :ok? :ok
61
+
62
+ def fail_ok
63
+ @result["fail_ok"]
64
+ end
65
+ alias :fail_ok? :fail_ok
66
+
67
+ # Access the value data embedded in the result
68
+ #
69
+ # @param key [String] data to access
70
+ # @return [Object] the specifiv item in the value hash or the raw value
71
+ def [](key)
72
+ return @result["value"] unless @result["value"].is_a?(Hash)
73
+
74
+ @result["value"][key]
75
+ end
76
+
77
+ # Access the value data in raw form
78
+ #
79
+ # @return [Object] whatever value the task produced
80
+ def value
81
+ @result["value"]
82
+ end
83
+
84
+ def to_s
85
+ if Object.const_defined?(:Puppet)
86
+ Puppet::Pops::Types::StringConverter.convert(self, "%p")
87
+ else
88
+ super
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,128 @@
1
+ module MCollective
2
+ module Util
3
+ class BoltSupport
4
+ class TaskResults
5
+ attr_reader :results, :exception
6
+ attr_writer :message
7
+
8
+ include Enumerable
9
+
10
+ def self.include_iterable
11
+ include(Puppet::Pops::Types::Iterable)
12
+ include(Puppet::Pops::Types::IteratorProducer)
13
+ end
14
+
15
+ # Method used by Puppet to create the TaskResults from a array
16
+ #
17
+ # @param results [Array<TaskResult>] hash as prodused by various execution_result method
18
+ # @return [TaskResults]
19
+ def self.from_asserted_hash(results, exception=nil)
20
+ new(results, exception)
21
+ end
22
+
23
+ # @param results [Array<TaskResult>]
24
+ def initialize(results, exception=nil)
25
+ @results = results
26
+ @exception = exception
27
+ end
28
+
29
+ def to_json(obj={})
30
+ @results.to_json(obj)
31
+ end
32
+
33
+ # Iterate over all results
34
+ #
35
+ # @yield [TaskResult]
36
+ def each(&block)
37
+ @results.each(&block)
38
+ end
39
+
40
+ # Set of all the results that are errors regardless of fail_ok
41
+ #
42
+ # @return [TaskResults]
43
+ def error_set
44
+ TaskResults.new(@results.select(&:error))
45
+ end
46
+
47
+ # Set of all the results that are ok regardless of fail_ok
48
+ #
49
+ # @return [TaskResults]
50
+ def ok_set
51
+ TaskResults.new(@results.reject(&:error))
52
+ end
53
+
54
+ # Determines if all results are ok, considers fail_ok
55
+ #
56
+ # @return [Boolean]
57
+ def ok
58
+ @results.all?(&:ok)
59
+ end
60
+ alias :ok? :ok
61
+
62
+ def fail_ok
63
+ @results.all?(&:fail_ok)
64
+ end
65
+ alias :fail_ok? :fail_ok
66
+
67
+ def message
68
+ return exception.to_s if exception
69
+
70
+ @message
71
+ end
72
+
73
+ # List of node names for all results
74
+ #
75
+ # @return [Array<String>]
76
+ def hosts
77
+ @results.map(&:host)
78
+ end
79
+
80
+ # First result in the set
81
+ #
82
+ # @return [TaskResult]
83
+ def first
84
+ @results.first
85
+ end
86
+
87
+ # Finds a result by name
88
+ #
89
+ # @param host [String] node hostname
90
+ # @return [TaskResult,nil]
91
+ def find(host)
92
+ @results.find {|r| r.host == host}
93
+ end
94
+
95
+ # Determines if the resultset is empty
96
+ #
97
+ # @return [Boolean]
98
+ def empty
99
+ @results.empty?
100
+ end
101
+ alias :empty? :empty
102
+
103
+ # Determines the count of results in the set
104
+ #
105
+ # @return [Integer]
106
+ def count
107
+ @results.size
108
+ end
109
+
110
+ def to_s
111
+ if Object.const_defined?(:Puppet)
112
+ Puppet::Pops::Types::StringConverter.convert(self, "%p")
113
+ else
114
+ super
115
+ end
116
+ end
117
+
118
+ def iterator
119
+ if Object.const_defined?(:Puppet) && Puppet.const_defined?(:Pops) && self.class.included_modules.include?(Puppet::Pops::Types::Iterable)
120
+ return Puppet::Pops::Types::Iterable.on(@results, TaskResult)
121
+ end
122
+
123
+ raise(NotImplementedError, "iterator requires puppet code to be loaded.")
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end