choria-mcorpc-support 2.21.1 → 2.23.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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mcollective.rb +1 -2
  3. data/lib/mcollective/agent/bolt_tasks.ddl +253 -0
  4. data/lib/mcollective/agent/bolt_tasks.json +365 -0
  5. data/lib/mcollective/agent/bolt_tasks.rb +178 -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 +8 -4
  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 +189 -0
  23. data/lib/mcollective/application/completion.rb +6 -6
  24. data/lib/mcollective/application/facts.rb +11 -11
  25. data/lib/mcollective/application/federation.rb +237 -0
  26. data/lib/mcollective/application/find.rb +4 -4
  27. data/lib/mcollective/application/help.rb +3 -3
  28. data/lib/mcollective/application/inventory.rb +3 -341
  29. data/lib/mcollective/application/ping.rb +5 -51
  30. data/lib/mcollective/application/playbook.rb +207 -0
  31. data/lib/mcollective/application/plugin.rb +106 -106
  32. data/lib/mcollective/application/rpc.rb +3 -108
  33. data/lib/mcollective/application/tasks.rb +425 -0
  34. data/lib/mcollective/applications.rb +11 -10
  35. data/lib/mcollective/audit/choria.rb +33 -0
  36. data/lib/mcollective/cache.rb +2 -4
  37. data/lib/mcollective/client.rb +11 -10
  38. data/lib/mcollective/config.rb +21 -34
  39. data/lib/mcollective/connector/base.rb +2 -1
  40. data/lib/mcollective/connector/nats.ddl +9 -0
  41. data/lib/mcollective/connector/nats.rb +450 -0
  42. data/lib/mcollective/data.rb +8 -3
  43. data/lib/mcollective/data/agent_data.rb +1 -1
  44. data/lib/mcollective/data/base.rb +6 -5
  45. data/lib/mcollective/data/bolt_task_data.ddl +90 -0
  46. data/lib/mcollective/data/bolt_task_data.rb +32 -0
  47. data/lib/mcollective/data/collective_data.rb +1 -1
  48. data/lib/mcollective/data/fact_data.rb +6 -6
  49. data/lib/mcollective/data/fstat_data.rb +2 -4
  50. data/lib/mcollective/data/result.rb +7 -2
  51. data/lib/mcollective/ddl/agentddl.rb +5 -17
  52. data/lib/mcollective/ddl/base.rb +10 -13
  53. data/lib/mcollective/discovery.rb +24 -39
  54. data/lib/mcollective/discovery/choria.ddl +11 -0
  55. data/lib/mcollective/discovery/choria.rb +223 -0
  56. data/lib/mcollective/discovery/flatfile.rb +7 -8
  57. data/lib/mcollective/discovery/mc.rb +2 -2
  58. data/lib/mcollective/discovery/stdin.rb +17 -18
  59. data/lib/mcollective/exceptions.rb +13 -0
  60. data/lib/mcollective/facts/base.rb +9 -9
  61. data/lib/mcollective/facts/yaml_facts.rb +12 -12
  62. data/lib/mcollective/generators.rb +3 -3
  63. data/lib/mcollective/generators/agent_generator.rb +3 -4
  64. data/lib/mcollective/generators/base.rb +14 -15
  65. data/lib/mcollective/generators/data_generator.rb +5 -6
  66. data/lib/mcollective/log.rb +2 -2
  67. data/lib/mcollective/logger/base.rb +3 -2
  68. data/lib/mcollective/logger/console_logger.rb +10 -10
  69. data/lib/mcollective/logger/file_logger.rb +7 -7
  70. data/lib/mcollective/logger/syslog_logger.rb +11 -15
  71. data/lib/mcollective/message.rb +8 -39
  72. data/lib/mcollective/monkey_patches.rb +2 -4
  73. data/lib/mcollective/optionparser.rb +2 -1
  74. data/lib/mcollective/pluginmanager.rb +3 -5
  75. data/lib/mcollective/pluginpackager.rb +1 -3
  76. data/lib/mcollective/pluginpackager/agent_definition.rb +3 -8
  77. data/lib/mcollective/pluginpackager/forge_packager.rb +7 -9
  78. data/lib/mcollective/pluginpackager/standard_definition.rb +1 -2
  79. data/lib/mcollective/registration/base.rb +18 -16
  80. data/lib/mcollective/rpc.rb +2 -4
  81. data/lib/mcollective/rpc/actionrunner.rb +16 -18
  82. data/lib/mcollective/rpc/agent.rb +26 -43
  83. data/lib/mcollective/rpc/audit.rb +1 -0
  84. data/lib/mcollective/rpc/client.rb +67 -85
  85. data/lib/mcollective/rpc/helpers.rb +55 -62
  86. data/lib/mcollective/rpc/progress.rb +2 -2
  87. data/lib/mcollective/rpc/reply.rb +17 -19
  88. data/lib/mcollective/rpc/request.rb +7 -5
  89. data/lib/mcollective/rpc/result.rb +6 -8
  90. data/lib/mcollective/rpc/stats.rb +49 -58
  91. data/lib/mcollective/security/base.rb +13 -56
  92. data/lib/mcollective/security/choria.rb +765 -0
  93. data/lib/mcollective/shell.rb +9 -4
  94. data/lib/mcollective/signer/base.rb +28 -0
  95. data/lib/mcollective/signer/choria.rb +185 -0
  96. data/lib/mcollective/ssl.rb +8 -6
  97. data/lib/mcollective/util.rb +58 -55
  98. data/lib/mcollective/util/bolt_support.rb +176 -0
  99. data/lib/mcollective/util/bolt_support/plan_runner.rb +167 -0
  100. data/lib/mcollective/util/bolt_support/task_result.rb +94 -0
  101. data/lib/mcollective/util/bolt_support/task_results.rb +128 -0
  102. data/lib/mcollective/util/choria.rb +946 -0
  103. data/lib/mcollective/util/indifferent_hash.rb +12 -0
  104. data/lib/mcollective/util/natswrapper.rb +242 -0
  105. data/lib/mcollective/util/playbook.rb +435 -0
  106. data/lib/mcollective/util/playbook/data_stores.rb +201 -0
  107. data/lib/mcollective/util/playbook/data_stores/base.rb +99 -0
  108. data/lib/mcollective/util/playbook/data_stores/consul_data_store.rb +88 -0
  109. data/lib/mcollective/util/playbook/data_stores/environment_data_store.rb +33 -0
  110. data/lib/mcollective/util/playbook/data_stores/etcd_data_store.rb +42 -0
  111. data/lib/mcollective/util/playbook/data_stores/file_data_store.rb +106 -0
  112. data/lib/mcollective/util/playbook/data_stores/shell_data_store.rb +103 -0
  113. data/lib/mcollective/util/playbook/inputs.rb +265 -0
  114. data/lib/mcollective/util/playbook/nodes.rb +207 -0
  115. data/lib/mcollective/util/playbook/nodes/mcollective_nodes.rb +86 -0
  116. data/lib/mcollective/util/playbook/nodes/pql_nodes.rb +40 -0
  117. data/lib/mcollective/util/playbook/nodes/shell_nodes.rb +55 -0
  118. data/lib/mcollective/util/playbook/nodes/terraform_nodes.rb +65 -0
  119. data/lib/mcollective/util/playbook/nodes/yaml_nodes.rb +47 -0
  120. data/lib/mcollective/util/playbook/playbook_logger.rb +47 -0
  121. data/lib/mcollective/util/playbook/puppet_logger.rb +51 -0
  122. data/lib/mcollective/util/playbook/report.rb +152 -0
  123. data/lib/mcollective/util/playbook/task_result.rb +55 -0
  124. data/lib/mcollective/util/playbook/tasks.rb +196 -0
  125. data/lib/mcollective/util/playbook/tasks/base.rb +45 -0
  126. data/lib/mcollective/util/playbook/tasks/graphite_event_task.rb +64 -0
  127. data/lib/mcollective/util/playbook/tasks/mcollective_task.rb +356 -0
  128. data/lib/mcollective/util/playbook/tasks/shell_task.rb +93 -0
  129. data/lib/mcollective/util/playbook/tasks/slack_task.rb +105 -0
  130. data/lib/mcollective/util/playbook/tasks/webhook_task.rb +136 -0
  131. data/lib/mcollective/util/playbook/template_util.rb +98 -0
  132. data/lib/mcollective/util/playbook/uses.rb +169 -0
  133. data/lib/mcollective/util/tasks_support.rb +751 -0
  134. data/lib/mcollective/util/tasks_support/cli.rb +260 -0
  135. data/lib/mcollective/util/tasks_support/default_formatter.rb +138 -0
  136. data/lib/mcollective/util/tasks_support/json_formatter.rb +108 -0
  137. data/lib/mcollective/validator.rb +6 -1
  138. data/lib/mcollective/validator/bolt_task_name_validator.ddl +7 -0
  139. data/lib/mcollective/validator/bolt_task_name_validator.rb +11 -0
  140. data/lib/mcollective/validator/length_validator.rb +1 -3
  141. metadata +65 -6
  142. data/lib/mcollective/application/describe_filter.rb +0 -87
  143. data/lib/mcollective/matcher.rb +0 -220
  144. data/lib/mcollective/matcher/parser.rb +0 -128
  145. data/lib/mcollective/matcher/scanner.rb +0 -241
@@ -0,0 +1,207 @@
1
+ require_relative "nodes/mcollective_nodes"
2
+ require_relative "nodes/pql_nodes"
3
+ require_relative "nodes/yaml_nodes"
4
+ require_relative "nodes/shell_nodes"
5
+ require_relative "nodes/terraform_nodes"
6
+
7
+ module MCollective
8
+ module Util
9
+ class Playbook
10
+ class Nodes
11
+ attr_reader :nodes
12
+
13
+ def initialize(playbook)
14
+ @playbook = playbook
15
+ @nodes = {}
16
+ end
17
+
18
+ # List of known node set names
19
+ #
20
+ # @return [Array<String>]
21
+ def keys
22
+ @nodes.keys
23
+ end
24
+
25
+ # Nodes belonging to a specific node set
26
+ #
27
+ # @param nodeset [String] node set name
28
+ # @return [Array<String>]
29
+ # @raise [StandardError] when node set is unknown
30
+ def [](nodeset)
31
+ if include?(nodeset)
32
+ @nodes[nodeset][:discovered]
33
+ else
34
+ raise("Unknown node set %s" % nodeset)
35
+ end
36
+ end
37
+
38
+ # Properties for a certain node set
39
+ #
40
+ # @param nodes [String] node set name
41
+ # @return [Hash]
42
+ # @raise [StandardError] when node set is unknown
43
+ def properties(nodes)
44
+ if include?(nodes)
45
+ @nodes[nodes][:properties]
46
+ else
47
+ raise("Unknown node set %s" % nodes)
48
+ end
49
+ end
50
+
51
+ # Determines if a node set is known
52
+ #
53
+ # @param nodes [String] node set name
54
+ # @return [Boolean]
55
+ def include?(nodes)
56
+ @nodes.include?(nodes)
57
+ end
58
+
59
+ def prepare
60
+ @nodes.each do |node_set, dets|
61
+ @playbook.in_context(node_set) do
62
+ Log.debug("Preparing nodeset %s" % node_set)
63
+
64
+ resolve_nodes(node_set)
65
+ check_empty(node_set)
66
+ limit_nodes(node_set)
67
+ validate_nodes(node_set)
68
+
69
+ Log.info("Discovered %d node(s) in node set %s" % [dets[:discovered].size, node_set])
70
+ end
71
+ end
72
+
73
+ @playbook.in_context("conn.test") { test_nodes }
74
+ @playbook.in_context("ddl.test") { check_uses }
75
+ end
76
+
77
+ # Resolve the node list using the resolver class
78
+ #
79
+ # @param node_set [String] node set name
80
+ def resolve_nodes(node_set)
81
+ node_props = @nodes[node_set]
82
+ node_props[:resolver].prepare
83
+ node_props[:discovered] = node_props[:resolver].discover.uniq
84
+ end
85
+
86
+ # Checks if the agents on the nodes matches the desired versions
87
+ #
88
+ # @raise [StandardError] on error
89
+ def check_uses
90
+ agent_nodes = {}
91
+
92
+ @nodes.map do |_, dets|
93
+ dets[:properties].fetch("uses", []).each do |agent|
94
+ agent_nodes[agent] ||= []
95
+ agent_nodes[agent].concat(dets[:discovered])
96
+ end
97
+ end
98
+
99
+ @playbook.validate_agents(agent_nodes) unless agent_nodes.empty?
100
+ end
101
+
102
+ # Determines if a nodeset needs connectivity test
103
+ #
104
+ # @param nodes [String] node set name
105
+ # @return [Boolean]
106
+ # @raise [StandardError] for unknown node sets
107
+ def should_test?(nodes)
108
+ !!properties(nodes)["test"]
109
+ end
110
+
111
+ def mcollective_task
112
+ Tasks::McollectiveTask.new(@playbook)
113
+ end
114
+
115
+ # Tests a RPC ping to the discovered nodes
116
+ #
117
+ # @todo is this really needed?
118
+ # @raise [StandardError] on error
119
+ def test_nodes
120
+ nodes_to_test = @nodes.map do |nodes, _|
121
+ self[nodes] if should_test?(nodes)
122
+ end.flatten.compact
123
+
124
+ return if nodes_to_test.empty?
125
+
126
+ Log.info("Checking connectivity for %d nodes" % nodes_to_test.size)
127
+
128
+ rpc = mcollective_task
129
+ rpc.from_hash(
130
+ "nodes" => nodes_to_test,
131
+ "action" => "rpcutil.ping",
132
+ "silent" => true
133
+ )
134
+ success, msg, _ = rpc.run
135
+
136
+ raise("Connectivity test failed for some nodes: %s" % [msg]) unless success
137
+ end
138
+
139
+ # Checks that discovered nodes matches stated expectations
140
+ #
141
+ # @param nodes [String] node set name
142
+ # @raise [StandardError] on error
143
+ def validate_nodes(nodes)
144
+ return if properties(nodes)["empty_ok"]
145
+
146
+ raise("Node set %s needs at least %d nodes, got %d" % [nodes, properties(nodes)["at_least"], self[nodes].size]) unless self[nodes].size >= properties(nodes)["at_least"]
147
+ end
148
+
149
+ # Handles an empty discovered list
150
+ #
151
+ # @param nodes [String] node set name
152
+ # @raise [StandardError] when empty
153
+ def check_empty(nodes)
154
+ raise(properties(nodes)["when_empty"] || "Did not discover any nodes for nodeset %s" % nodes) if self[nodes].empty? && !properties(nodes)["empty_ok"]
155
+ end
156
+
157
+ # Limits the discovered list for a node set based on the playbook limits
158
+ #
159
+ # @todo more intelegent limiting with weighted randoms like mco rpc client
160
+ # @param nodes [String] node set name
161
+ def limit_nodes(nodes)
162
+ return if self[nodes].empty?
163
+
164
+ if limit = properties(nodes)["limit"]
165
+ Log.debug("Limiting node set %s to %d nodes from %d" % [nodes, limit, @nodes[nodes][:discovered].size])
166
+ @nodes[nodes][:discovered] = @nodes[nodes][:discovered][0..(limit - 1)]
167
+ end
168
+ end
169
+
170
+ # Retrieves a new instance of the resolver for a certain type of discovery
171
+ #
172
+ # @param type [String] finds classes called *Nodes::TypeNodes* based on this type
173
+ def resolver_for(type)
174
+ klass_name = "%sNodes" % type.capitalize
175
+
176
+ Nodes.const_get(klass_name).new
177
+ rescue NameError
178
+ raise("Cannot find a handler for Node Set type %s" % type)
179
+ end
180
+
181
+ def from_hash(data)
182
+ data.each do |nodes, props|
183
+ resolver = resolver_for(props["type"])
184
+ resolver.from_hash(props)
185
+ resolver.validate_configuration!
186
+
187
+ node_props = {
188
+ "at_least" => 1,
189
+ "empty_ok" => false,
190
+ "when_empty" => "Did not discover any nodes for nodeset %s" % nodes
191
+ }.merge(props)
192
+
193
+ node_props["at_least"] = 0 if node_props["empty_ok"]
194
+
195
+ @nodes[nodes] = {
196
+ :resolver => resolver,
197
+ :discovered => [],
198
+ :properties => node_props
199
+ }
200
+ end
201
+
202
+ self
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,86 @@
1
+ module MCollective
2
+ module Util
3
+ class Playbook
4
+ class Nodes
5
+ class McollectiveNodes
6
+ def initialize
7
+ @discovery_method = "mc"
8
+ @agents = []
9
+ @facts = []
10
+ @classes = []
11
+ @identity = []
12
+ @compound = nil
13
+ end
14
+
15
+ def prepare; end
16
+
17
+ # @todo
18
+ def validate_configuration!; end
19
+
20
+ # Creates and cache an RPC::Client for the configured agent
21
+ #
22
+ # @param from_cache [Boolean] when false a new instance is always returned
23
+ # @return [RPC::Client]
24
+ def client(from_cache: true)
25
+ if from_cache
26
+ @_rpc_client ||= create_and_configure_client
27
+ else
28
+ create_and_configure_client
29
+ end
30
+ end
31
+
32
+ # Creates a new RPC::Client and configures it with the configured settings
33
+ #
34
+ # @todo discovery
35
+ # @return [RPC::Client]
36
+ def create_and_configure_client
37
+ client = RPC::Client.new(@agents[0], :configfile => Util.config_file_for_user, :options => Util.default_options)
38
+ client.progress = false
39
+ client.discovery_method = @discovery_method
40
+
41
+ @classes.each do |filter|
42
+ client.class_filter(filter)
43
+ end
44
+
45
+ @facts.each do |filter|
46
+ client.fact_filter(filter)
47
+ end
48
+
49
+ @agents.each do |filter|
50
+ client.agent_filter(filter)
51
+ end
52
+
53
+ @identity.each do |filter|
54
+ client.identity_filter(filter)
55
+ end
56
+
57
+ client.compound_filter(@compound) if @compound
58
+
59
+ client
60
+ end
61
+
62
+ # Initialize the nodes source from a hash
63
+ #
64
+ # @param data [Hash] input data matching nodes.json schema
65
+ # @return [McollectiveNodes]
66
+ def from_hash(data)
67
+ @discovery_method = data.fetch("discovery_method", "mc")
68
+ @agents = data.fetch("agents", ["rpcutil"])
69
+ @facts = data.fetch("facts", [])
70
+ @classes = data.fetch("classes", [])
71
+ @identity = data.fetch("identities", [])
72
+ @compound = data["compound"]
73
+
74
+ @_rpc_client = nil
75
+
76
+ self
77
+ end
78
+
79
+ def discover
80
+ client.discover
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,40 @@
1
+ require "mcollective/util/choria"
2
+
3
+ module MCollective
4
+ module Util
5
+ class Playbook
6
+ class Nodes
7
+ class PqlNodes
8
+ def initialize
9
+ @query = nil
10
+ end
11
+
12
+ def prepare; end
13
+
14
+ def validate_configuration!
15
+ raise("No PQL query specified") unless @query
16
+ end
17
+
18
+ def choria
19
+ @_choria ||= Util::Choria.new(false)
20
+ end
21
+
22
+ # Initialize the nodes source from a hash
23
+ #
24
+ # @param data [Hash] input data matching nodes.json schema
25
+ # @return [PqlNodes]
26
+ def from_hash(data)
27
+ @query = data["query"]
28
+
29
+ self
30
+ end
31
+
32
+ # Performs the PQL query and extracts certnames
33
+ def discover
34
+ choria.pql_query(@query, true)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,55 @@
1
+ module MCollective
2
+ module Util
3
+ class Playbook
4
+ class Nodes
5
+ class ShellNodes
6
+ def initialize
7
+ @script = nil
8
+ end
9
+
10
+ def prepare; end
11
+
12
+ def validate_configuration!
13
+ raise("No node source script specified") unless @script
14
+ raise("Node source script is not executable") unless File.executable?(@script)
15
+ raise("Node source script produced no results") if data.empty?
16
+ end
17
+
18
+ def from_hash(data)
19
+ @script = data["script"]
20
+ @_data = nil
21
+
22
+ self
23
+ end
24
+
25
+ def valid_hostname?(host)
26
+ host =~ /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/
27
+ end
28
+
29
+ def data
30
+ return @_data if @_data
31
+
32
+ shell = Shell.new(@script, "timeout" => 10)
33
+ shell.runcommand
34
+
35
+ exitcode = shell.status.exitstatus
36
+
37
+ raise("Could not discover nodes via shell method, command exited with code %d" % [exitcode]) unless exitcode == 0
38
+
39
+ @_data = shell.stdout.lines.map do |line|
40
+ line.chomp!
41
+
42
+ raise("%s is not a valid hostname" % line) unless valid_hostname?(line)
43
+
44
+ line
45
+ end
46
+ end
47
+
48
+ def discover
49
+ data
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,65 @@
1
+ module MCollective
2
+ module Util
3
+ class Playbook
4
+ class Nodes
5
+ class TerraformNodes
6
+ def prepare; end
7
+
8
+ def validate_configuration!
9
+ raise("The supplied terraform path %s is not executable" % @terraform) if @terraform && !File.executable?(@terraform)
10
+ raise("A terraform state file is needed") unless @state
11
+ raise("The terraform statefile %s is not readable" % @state) unless File.readable?(@state)
12
+ raise("An output name is needed") unless @output
13
+
14
+ Validator.validate(@terraform, :shellsafe)
15
+ Validator.validate(@state, :shellsafe)
16
+ Validator.validate(@output, :shellsafe)
17
+ end
18
+
19
+ def from_hash(data)
20
+ @state = data["statefile"]
21
+ @output = data["output"]
22
+ @terraform = data.fetch("terraform", choria.which("terraform"))
23
+
24
+ self
25
+ end
26
+
27
+ def valid_hostname?(host)
28
+ host =~ /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/
29
+ end
30
+
31
+ def tf_output
32
+ shell = Shell.new("%s output -state %s -json %s 2>&1" % [@terraform, @state, @output])
33
+ shell.runcommand
34
+
35
+ raise("Terraform exited with code %d: %s" % [shell.status.exitstatus, shell.stdout]) unless shell.status.exitstatus == 0
36
+
37
+ shell.stdout
38
+ end
39
+
40
+ def output_data
41
+ return @_data if @_data
42
+
43
+ data = JSON.parse(tf_output)
44
+
45
+ raise("Only terraform outputs of type list is supported") unless data["type"] == "list"
46
+
47
+ data["value"].each do |result|
48
+ raise("%s is not a valid hostname" % result) unless valid_hostname?(result)
49
+ end
50
+
51
+ @_data = data["value"]
52
+ end
53
+
54
+ def choria
55
+ @_choria ||= Util::Choria.new(false)
56
+ end
57
+
58
+ def discover
59
+ output_data
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end