choria-mcorpc-support 2.23.0 → 2.24.1

Sign up to get free protection for your applications and to get access to all the features.
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