choria-mcorpc-support 2.23.0 → 2.24.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 (61) hide show
  1. checksums.yaml +5 -5
  2. data/lib/mcollective.rb +3 -3
  3. data/lib/mcollective/agent/bolt_tasks.ddl +18 -0
  4. data/lib/mcollective/agent/bolt_tasks.json +18 -0
  5. data/lib/mcollective/agent/bolt_tasks.rb +4 -2
  6. data/lib/mcollective/agent/rpcutil.ddl +2 -2
  7. data/lib/mcollective/agent/rpcutil.json +2 -2
  8. data/lib/mcollective/application/choria.rb +3 -63
  9. data/lib/mcollective/application/facts.rb +2 -67
  10. data/lib/mcollective/application/federation.rb +1 -3
  11. data/lib/mcollective/application/find.rb +1 -1
  12. data/lib/mcollective/application/ping.rb +31 -3
  13. data/lib/mcollective/application/plugin.rb +2 -15
  14. data/lib/mcollective/application/tasks.rb +9 -0
  15. data/lib/mcollective/client.rb +1 -1
  16. data/lib/mcollective/config.rb +135 -103
  17. data/lib/mcollective/ddl.rb +0 -1
  18. data/lib/mcollective/discovery.rb +12 -65
  19. data/lib/mcollective/discovery/broadcast.ddl +11 -0
  20. data/lib/mcollective/discovery/choria.ddl +6 -4
  21. data/lib/mcollective/discovery/delegate.ddl +13 -0
  22. data/lib/mcollective/discovery/delegate.rb +73 -0
  23. data/lib/mcollective/discovery/external.ddl +13 -0
  24. data/lib/mcollective/discovery/file.ddl +13 -0
  25. data/lib/mcollective/discovery/flatfile.ddl +7 -5
  26. data/lib/mcollective/discovery/inventory.ddl +13 -0
  27. data/lib/mcollective/discovery/mc.ddl +3 -3
  28. data/lib/mcollective/generators.rb +0 -1
  29. data/lib/mcollective/message.rb +0 -24
  30. data/lib/mcollective/optionparser.rb +2 -2
  31. data/lib/mcollective/pluginpackager/forge_packager.rb +1 -1
  32. data/lib/mcollective/rpc/client.rb +6 -4
  33. data/lib/mcollective/security/base.rb +1 -37
  34. data/lib/mcollective/util.rb +23 -31
  35. data/lib/mcollective/util/choria.rb +0 -157
  36. data/lib/mcollective/util/tasks_support.rb +22 -3
  37. metadata +9 -27
  38. data/lib/mcollective/application/describe_filter.rb +0 -87
  39. data/lib/mcollective/data.rb +0 -96
  40. data/lib/mcollective/data/agent_data.ddl +0 -22
  41. data/lib/mcollective/data/agent_data.rb +0 -17
  42. data/lib/mcollective/data/base.rb +0 -68
  43. data/lib/mcollective/data/bolt_task_data.ddl +0 -90
  44. data/lib/mcollective/data/bolt_task_data.rb +0 -32
  45. data/lib/mcollective/data/collective_data.ddl +0 -20
  46. data/lib/mcollective/data/collective_data.rb +0 -9
  47. data/lib/mcollective/data/fact_data.ddl +0 -28
  48. data/lib/mcollective/data/fact_data.rb +0 -55
  49. data/lib/mcollective/data/fstat_data.ddl +0 -89
  50. data/lib/mcollective/data/fstat_data.rb +0 -54
  51. data/lib/mcollective/data/result.rb +0 -50
  52. data/lib/mcollective/ddl/dataddl.rb +0 -56
  53. data/lib/mcollective/discovery/choria.rb +0 -223
  54. data/lib/mcollective/discovery/flatfile.rb +0 -47
  55. data/lib/mcollective/discovery/stdin.ddl +0 -11
  56. data/lib/mcollective/discovery/stdin.rb +0 -67
  57. data/lib/mcollective/generators/data_generator.rb +0 -50
  58. data/lib/mcollective/generators/templates/data_input_snippet.erb +0 -7
  59. data/lib/mcollective/matcher.rb +0 -220
  60. data/lib/mcollective/matcher/parser.rb +0 -118
  61. data/lib/mcollective/matcher/scanner.rb +0 -236
@@ -1,47 +0,0 @@
1
- # discovers against a flatfile instead of the traditional network discovery
2
- # the flat file must have a node name per line which should match identities
3
- # as configured
4
- module MCollective
5
- class Discovery
6
- class Flatfile
7
- def self.discover(filter, timeout, limit=0, client=nil)
8
- if client.options[:discovery_options].empty?
9
- raise "The flatfile discovery method needs a path to a text file"
10
- else
11
- file = client.options[:discovery_options].first
12
- end
13
-
14
- raise "Cannot read the file %s specified as discovery source" % file unless File.readable?(file)
15
-
16
- discovered = []
17
- hosts = []
18
-
19
- File.readlines(file).each do |host|
20
- host = host.chomp.strip
21
- next if host.empty? || host.match(/^#/)
22
- raise 'Identities can only match /^[\w\.\-]+$/' unless host.match(/^[\w.\-]+$/)
23
-
24
- hosts << host
25
- end
26
-
27
- # this plugin only supports identity filters, do regex matches etc against
28
- # the list found in the flatfile
29
- if !filter["identity"].empty?
30
- filter["identity"].each do |identity|
31
- identity = Regexp.new(identity.gsub("\/", "")) if identity.match("^/")
32
-
33
- if identity.is_a?(Regexp)
34
- discovered = hosts.grep(identity)
35
- elsif hosts.include?(identity)
36
- discovered << identity
37
- end
38
- end
39
- else
40
- discovered = hosts
41
- end
42
-
43
- discovered
44
- end
45
- end
46
- end
47
- end
@@ -1,11 +0,0 @@
1
- metadata :name => "stdin",
2
- :description => "STDIN based discovery for node identities",
3
- :author => "Tomas Doran <bobtfish@bobtfish.net.net>",
4
- :license => "ASL 2.0",
5
- :version => "0.1",
6
- :url => "https://docs.puppetlabs.com/mcollective/",
7
- :timeout => 0
8
-
9
- discovery do
10
- capabilities :identity
11
- end
@@ -1,67 +0,0 @@
1
- # discovers against stdin instead of the traditional network discovery
2
- # the input must be a flat file with a node name per line which should match identities as configured,
3
- # or it should be a json string as output by the -j option of mco rpc
4
- require "mcollective/rpc/helpers"
5
-
6
- module MCollective
7
- class Discovery
8
- class Stdin
9
- def self.discover(filter, timeout, limit=0, client=nil)
10
- if client.options[:discovery_options].empty?
11
- type = "auto"
12
- else
13
- type = client.options[:discovery_options].first.downcase
14
- end
15
-
16
- discovered = []
17
-
18
- file = $stdin.read
19
-
20
- raise("data piped on STDIN contained only whitespace - could not discover hosts from it.") if file =~ /^\s*$/
21
-
22
- if type == "auto"
23
- if file =~ /^\s*\[/
24
- type = "json"
25
- else
26
- type = "text"
27
- end
28
- end
29
-
30
- Log.debug("Parsing STDIN input as type %s" % type)
31
-
32
- case type
33
- when "json"
34
- hosts = RPC::Helpers.extract_hosts_from_json(file)
35
- when "text"
36
- hosts = file.split("\n")
37
- else
38
- raise("stdin discovery plugin only knows the types auto/text/json, not \"#{type}\"")
39
- end
40
-
41
- hosts.map do |host|
42
- raise 'Identities can only match /\w\.\-/' unless host.match(/^[\w.\-]+$/)
43
-
44
- host
45
- end
46
-
47
- # this plugin only supports identity filters, do regex matches etc against
48
- # the list found in the flatfile
49
- if filter["identity"].empty?
50
- discovered = hosts
51
- else
52
- filter["identity"].each do |identity|
53
- identity = Regexp.new(identity.gsub("\/", "")) if identity.match("^/")
54
-
55
- if identity.is_a?(Regexp)
56
- discovered = hosts.grep(identity)
57
- elsif hosts.include?(identity)
58
- discovered << identity
59
- end
60
- end
61
- end
62
-
63
- discovered
64
- end
65
- end
66
- end
67
- end
@@ -1,50 +0,0 @@
1
- module MCollective
2
- module Generators
3
- class DataGenerator < Base
4
- attr_accessor :ddl, :content
5
-
6
- def initialize(plugin_name, outputs=[], name=nil, description=nil, author=nil,
7
- license=nil, version=nil, url=nil, timeout=nil)
8
-
9
- super(name, description, author, license, version, url, timeout)
10
- @mod_name = "Data"
11
- @pclass = "Base"
12
- @plugin_name = plugin_name
13
- @outputs = outputs
14
- @ddl = create_ddl
15
- @content = create_plugin_content
16
- @plugin = create_plugin_string
17
- write_plugins
18
- end
19
-
20
- def create_ddl
21
- query_text = "dataquery :description => \"Query information\" do\n"
22
- query_text += ERB.new(File.read(File.join(File.dirname(__FILE__), "templates", "data_input_snippet.erb"))).result
23
-
24
- @outputs.each_with_index do |output, i|
25
- query_text += "%2s%s" % [" ", "output :#{output},\n"]
26
- query_text += "%9s%s" % [" ", ":description => \"%DESCRIPTION%\",\n"]
27
- query_text += "%9s%s" % [" ", ":display_as => \"%DESCRIPTION%\"\n"]
28
- query_text += "\n" unless @outputs.size == (i + 1)
29
- end
30
-
31
- query_text += "end"
32
-
33
- # Use inherited method to create metadata part of the ddl
34
- create_metadata_string + query_text
35
- end
36
-
37
- def create_plugin_content
38
- content_text = "%6s%s" % [" ", "query do |what|\n"]
39
-
40
- @outputs.each do |output|
41
- content_text += "%8s%s" % [" ", "result[:#{output}] = nil\n"]
42
- end
43
- content_text += "%6s%s" % [" ", "end\n"]
44
-
45
- # Add actions to agent file
46
- content_text
47
- end
48
- end
49
- end
50
- end
@@ -1,7 +0,0 @@
1
- input :query,
2
- :prompt => "%PROMP%",
3
- :description => "%DESCRIPTION%",
4
- :type => %TYPE%,
5
- :validation => %VALIDATION%,
6
- :maxlength => %MAXLENGTH%
7
-
@@ -1,220 +0,0 @@
1
- module MCollective
2
- # A parser and scanner that creates a stack machine for a simple
3
- # fact and class matching language used on the CLI to facilitate
4
- # a rich discovery language
5
- #
6
- # Language EBNF
7
- #
8
- # compound = ["("] expression [")"] {["("] expression [")"]}
9
- # expression = [!|not]statement ["and"|"or"] [!|not] statement
10
- # char = A-Z | a-z | < | > | => | =< | _ | - |* | / { A-Z | a-z | < | > | => | =< | _ | - | * | / | }
11
- # int = 0|1|2|3|4|5|6|7|8|9{|0|1|2|3|4|5|6|7|8|9|0}
12
- module Matcher
13
- require "mcollective/matcher/parser"
14
- require "mcollective/matcher/scanner"
15
-
16
- # Helper creates a hash from a function call string
17
- def self.create_function_hash(function_call)
18
- func_hash = {}
19
- f = ""
20
- func_parts = function_call.split(/(!=|>=|<=|<|>|=)/)
21
- func_hash["r_compare"] = func_parts.pop
22
- func_hash["operator"] = func_parts.pop
23
- func = func_parts.join
24
-
25
- # Deal with dots in function parameters and functions without dot values
26
- if func =~ /^.+\(.*\)$/
27
- f = func
28
- else
29
- func_parts = func.split(".")
30
- func_hash["value"] = func_parts.pop
31
- f = func_parts.join(".")
32
- end
33
-
34
- # Deal with regular expression matches
35
- if func_hash["r_compare"] =~ /^\/.*\/$/
36
- func_hash["operator"] = "=~" if func_hash["operator"] == "="
37
- func_hash["operator"] = "!=~" if func_hash["operator"] == "!="
38
- func_hash["r_compare"] = Regexp.new(func_hash["r_compare"].gsub(/^\/|\/$/, ""))
39
- # Convert = operators to == so they can be propperly evaluated
40
- elsif func_hash["operator"] == "="
41
- func_hash["operator"] = "=="
42
- end
43
-
44
- # Grab function name and parameters from left compare string
45
- func_hash["name"], func_hash["params"] = f.split("(")
46
- if func_hash["params"] == ")"
47
- func_hash["params"] = nil
48
- else
49
-
50
- # Walk the function parameters from the front and from the
51
- # back removing the first and last instances of single of
52
- # double qoutes. We do this to handle the case where params
53
- # contain escaped qoutes.
54
- func_hash["params"] = func_hash["params"].gsub(")", "")
55
- func_quotes = func_hash["params"].split(/('|")/)
56
-
57
- func_quotes.each_with_index do |item, i|
58
- if item =~ /'|"/
59
- func_quotes.delete_at(i)
60
- break
61
- end
62
- end
63
-
64
- func_quotes.reverse.each_with_index do |item, i|
65
- if item =~ /'|"/
66
- func_quotes.delete_at(func_quotes.size - i - 1)
67
- break
68
- end
69
- end
70
-
71
- func_hash["params"] = func_quotes.join
72
- end
73
-
74
- func_hash
75
- end
76
-
77
- # Returns the result of an executed function
78
- def self.execute_function(function_hash)
79
- # In the case where a data plugin isn't present there are two ways we can handle
80
- # the raised exception. The function result can either be false or the entire
81
- # expression can fail.
82
- #
83
- # In the case where we return the result as false it opens us op to unexpected
84
- # negation behavior.
85
- #
86
- # !foo('bar').name = bar
87
- #
88
- # In this case the user would expect discovery to match on all machines where
89
- # the name value of the foo function does not equal bar. If a non existent function
90
- # returns false then it is posible to match machines where the name value of the
91
- # foo function is bar.
92
- #
93
- # Instead we raise a DDLValidationError to prevent this unexpected behavior from
94
- # happening.
95
-
96
- result = Data.send(function_hash["name"], function_hash["params"])
97
-
98
- if function_hash["value"]
99
- begin
100
- eval_result = result.send(function_hash["value"])
101
- rescue
102
- # If data field has not been set we set the comparison result to nil
103
- eval_result = nil
104
- end
105
- eval_result
106
- else
107
- result
108
- end
109
- rescue NoMethodError
110
- Log.debug("cannot execute discovery function '#{function_hash['name']}'. data plugin not found")
111
- raise DDLValidationError
112
- end
113
-
114
- # Evaluates a compound statement
115
- def self.eval_compound_statement(expression)
116
- case expression.values.first
117
- when /^\//
118
- Util.has_cf_class?(expression.values.first)
119
- when />=|<=|=|<|>/
120
- optype = expression.values.first.match(/>=|<=|=|<|>/)
121
- name, value = expression.values.first.split(optype[0])
122
- if value.split("")[0] == "/"
123
- optype = "=~"
124
- else
125
- optype[0] == "=" ? optype = "==" : optype = optype[0]
126
- end
127
-
128
- Util.has_fact?(name, value, optype).to_s
129
- else
130
- Util.has_cf_class?(expression.values.first)
131
- end
132
- end
133
-
134
- # Returns the result of an evaluated compound statement that
135
- # includes a function
136
- def self.eval_compound_fstatement(function_hash) # rubocop:disable Metrics/MethodLength
137
- l_compare = execute_function(function_hash)
138
- r_compare = function_hash["r_compare"]
139
- operator = function_hash["operator"]
140
-
141
- # Break out early and return false if the function returns nil
142
- return false if l_compare.nil?
143
-
144
- # Prevent unwanted discovery by limiting comparison operators
145
- # on Strings and Booleans
146
- if (l_compare.is_a?(String) || l_compare.is_a?(TrueClass) || l_compare.is_a?(FalseClass)) && function_hash["operator"].match(/<|>/)
147
- Log.debug("Cannot do > and < comparison on Booleans and Strings '#{l_compare} #{function_hash['operator']} #{function_hash['r_compare']}'")
148
- return false
149
- end
150
-
151
- # Prevent backticks in function parameters
152
- if function_hash["params"] =~ /`/
153
- Log.debug("Cannot use backticks in function parameters")
154
- return false
155
- end
156
-
157
- # Do a regex comparison if right compare string is a regex
158
- if operator =~ /(=~|!=~)/
159
- # Fail if left compare value isn't a string
160
- if l_compare.is_a?(String)
161
- result = l_compare.match(r_compare)
162
- # Flip return value for != operator
163
- if function_hash["operator"] == "!=~"
164
- !result
165
- else
166
- !!result
167
- end
168
- else
169
- Log.debug("Cannot do a regex check on a non string value.")
170
- false
171
- end
172
- # Otherwise do a normal comparison while taking the type into account
173
- else
174
- if l_compare.is_a? String
175
- r_compare = r_compare.to_s
176
- elsif r_compare.is_a? String
177
- case l_compare
178
- when Numeric
179
- r_compare = r_compare.strip
180
- begin
181
- r_compare = Integer(r_compare)
182
- rescue ArgumentError # rubocop:disable Metrics/BlockNesting
183
- begin
184
- r_compare = Float(r_compare)
185
- rescue ArgumentError # rubocop:disable Metrics/BlockNesting
186
- raise(ArgumentError, "invalid numeric value: #{r_compare}")
187
- end
188
- end
189
- when TrueClass, FalseClass
190
- r_compare = r_compare.strip
191
- if r_compare == true.to_s # rubocop:disable Metrics/BlockNesting
192
- r_compare = true
193
- elsif r_compare == false.to_s # rubocop:disable Metrics/BlockNesting
194
- r_compare = false
195
- else
196
- raise(ArgumentError, "invalid boolean value: #{r_compare}")
197
- end
198
- end
199
- end
200
- operator = operator.strip
201
- if operator =~ /(?:(!=|<=|>=|<|>)|==?)/
202
- operator = $1 ? $1.to_sym : :==
203
- else
204
- raise(ArgumentError, "invalid operator: #{operator}")
205
- end
206
- l_compare.send(operator, r_compare)
207
-
208
- end
209
- end
210
-
211
- # Creates a callstack to be evaluated from a compound evaluation string
212
- def self.create_compound_callstack(call_string)
213
- callstack = Matcher::Parser.new(call_string).execution_stack
214
- callstack.each_with_index do |statement, i|
215
- callstack[i]["fstatement"] = create_function_hash(statement.values.first) if statement.keys.first == "fstatement"
216
- end
217
- callstack
218
- end
219
- end
220
- end
@@ -1,118 +0,0 @@
1
- # rubocop:disable Metrics/BlockNesting
2
- module MCollective
3
- module Matcher
4
- class Parser
5
- attr_reader :scanner, :execution_stack
6
-
7
- def initialize(args)
8
- @scanner = Scanner.new(args)
9
- @execution_stack = []
10
- @parse_errors = []
11
- @token_errors = []
12
- @paren_errors = []
13
- parse
14
- exit_with_token_errors unless @token_errors.empty?
15
- exit_with_parse_errors unless @parse_errors.empty?
16
- exit_with_paren_errors unless @paren_errors.empty?
17
- end
18
-
19
- # Exit and highlight any malformed tokens
20
- def exit_with_token_errors
21
- @token_errors.each do |error_range|
22
- (error_range[0]..error_range[1]).each do |i|
23
- @scanner.arguments[i] = Util.colorize(:red, @scanner.arguments[i])
24
- end
25
- end
26
- raise "Malformed token(s) found while parsing -S input #{@scanner.arguments.join}"
27
- end
28
-
29
- def exit_with_parse_errors
30
- @parse_errors.each do |error_range|
31
- (error_range[0]..error_range[1]).each do |i|
32
- @scanner.arguments[i] = Util.colorize(:red, @scanner.arguments[i])
33
- end
34
- end
35
- raise "Parse errors found while parsing -S input #{@scanner.arguments.join}"
36
- end
37
-
38
- def exit_with_paren_errors
39
- @paren_errors.each do |i|
40
- @scanner.arguments[i] = Util.colorize(:red, @scanner.arguments[i])
41
- end
42
- raise "Missing parenthesis found while parsing -S input #{@scanner.arguments.join}"
43
- end
44
-
45
- # Parse the input string, one token at a time a contruct the call stack
46
- def parse # rubocop:disable Metrics/MethodLength
47
- pre_index = @scanner.token_index
48
- p_token = nil
49
- c_token, c_token_value = @scanner.get_token
50
-
51
- until c_token.nil?
52
- @scanner.token_index += 1
53
- n_token, n_token_value = @scanner.get_token
54
-
55
- unless n_token == " "
56
- case c_token
57
- when "bad_token"
58
- @token_errors << c_token_value
59
-
60
- when "and"
61
- unless (n_token =~ /not|fstatement|statement|\(/) || (scanner.token_index == scanner.arguments.size) && !n_token.nil?
62
- @parse_errors << [pre_index, scanner.token_index]
63
- end
64
-
65
- case p_token
66
- when nil
67
- @parse_errors << [pre_index - c_token.size, scanner.token_index]
68
- when "and", "or"
69
- @parse_errors << [pre_index - 1 - p_token.size, pre_index - 1]
70
- end
71
-
72
- when "or"
73
- unless (n_token =~ /not|fstatement|statement|\(/) || (scanner.token_index == scanner.arguments.size) && !n_token.nil?
74
- @parse_errors << [pre_index, scanner.token_index]
75
- end
76
-
77
- case p_token
78
- when nil
79
- @parse_errors << [pre_index - c_token.size, scanner.token_index]
80
- when "and", "or"
81
- @parse_errors << [pre_index - 1 - p_token.size, pre_index - 1]
82
- end
83
-
84
- when "not"
85
- @parse_errors << [pre_index, scanner.token_index] unless n_token =~ /fstatement|statement|\(|not/ && !n_token.nil?
86
-
87
- when "statement", "fstatement"
88
- @parse_errors << [pre_index, scanner.token_index] if n_token !~ /and|or|\)/ && scanner.token_index != scanner.arguments.size
89
-
90
- when ")"
91
- @parse_errors << [pre_index, scanner.token_index] if n_token !~ /|and|or|not|\(/ && scanner.token_index != scanner.arguments.size
92
- if @paren_errors.empty?
93
- @paren_errors.push(n_token.nil? ? scanner.token_index - 1 : scanner.token_index - n_token_value.size)
94
- else
95
- @paren_errors.pop
96
- end
97
-
98
- when "("
99
- @parse_errors << [pre_index, scanner.token_index] unless n_token =~ /fstatement|statement|not|\(/
100
- @paren_errors.push(n_token.nil? ? scanner.token_index - 1 : scanner.token_index - n_token_value.size)
101
-
102
- else
103
- @parse_errors << [pre_index, scanner.token_index]
104
- end
105
-
106
- @execution_stack << {c_token => c_token_value} unless n_token == " " || c_token == "bad_token"
107
-
108
- p_token = c_token
109
- c_token = n_token
110
- c_token_value = n_token_value
111
- end
112
- pre_index = @scanner.token_index
113
- end
114
- end
115
- end
116
- end
117
- end
118
- # rubocop:enable Metrics/BlockNesting