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,32 +0,0 @@
1
- module MCollective
2
- module Data
3
- class Bolt_task_data < Base
4
- activate_when do
5
- Util::Choria.new.tasks_support.tasks_compatible?
6
- end
7
-
8
- query do |taskid|
9
- tasks = Util::Choria.new.tasks_support
10
-
11
- begin
12
- status = tasks.task_status(taskid)
13
-
14
- result[:known] = true
15
-
16
- if status["task"]
17
- tasks.task_status(taskid).each do |item, value|
18
- value = value.utc.to_i if value.is_a?(Time)
19
- value = value.to_json if value.is_a?(Hash)
20
-
21
- result[item.intern] = value
22
- end
23
-
24
- result[:start_time] = result[:start_time].to_i
25
- end
26
- rescue
27
- Log.debug("Task %s was not found, returning default data. Error was: %s" % [taskid, $!.to_s])
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,20 +0,0 @@
1
- metadata :name => "Collective",
2
- :description => "Collective membership",
3
- :author => "Puppet Labs",
4
- :license => "ASL 2.0",
5
- :version => "1.0",
6
- :url => "https://docs.puppetlabs.com/mcollective/",
7
- :timeout => 1
8
-
9
- dataquery :description => "Collective" do
10
- input :query,
11
- :prompt => 'Collective',
12
- :description => 'Collective name to ask about, eg mcollective',
13
- :type => :string,
14
- :validation => /./,
15
- :maxlength => 256
16
-
17
- output :member,
18
- :description => 'Node is a member of the named collective',
19
- :display_as => 'member'
20
- end
@@ -1,9 +0,0 @@
1
- module MCollective
2
- module Data
3
- class Collective_data < Base
4
- query do |collective|
5
- result[:member] = Config.instance.collectives.include?(collective)
6
- end
7
- end
8
- end
9
- end
@@ -1,28 +0,0 @@
1
- metadata :name => "Fact",
2
- :description => "Structured fact query",
3
- :author => "Puppet Labs",
4
- :license => "ASL 2.0",
5
- :version => "1.0",
6
- :url => "https://docs.puppetlabs.com/mcollective/",
7
- :timeout => 1
8
-
9
- dataquery :description => "Fact" do
10
- input :query,
11
- :prompt => 'Fact Path',
12
- :description => 'Path to a fact, eg network.eth0.address',
13
- :type => :string,
14
- :validation => /./,
15
- :maxlength => 256
16
-
17
- output :exists,
18
- :description => 'Fact is present',
19
- :display_as => 'exists'
20
-
21
- output :value,
22
- :description => 'Fact value',
23
- :display_as => 'value'
24
-
25
- output :value_encoding,
26
- :description => 'Encoding of the fact value (text/plain or application/json)',
27
- :display_as => 'value_encoding'
28
- end
@@ -1,55 +0,0 @@
1
- module MCollective
2
- module Data
3
- class Fact_data < Base
4
- query do |path|
5
- parts = path.split(/\./)
6
- walk_path(parts)
7
- end
8
-
9
- private
10
-
11
- def walk_path(path)
12
- # Set up results as though we didn't find the value
13
- result[:exists] = false
14
- result[:value] = false
15
- result[:value_encoding] = false
16
-
17
- facts = PluginManager["facts_plugin"].get_facts
18
-
19
- path.each do |level|
20
- case facts
21
- when Array
22
- level = Integer(level)
23
- if level >= facts.size
24
- # array index out would be out of bounds, so we don't have the value
25
- return
26
- end
27
- when Hash
28
- unless facts.include?(level)
29
- # we don't have the key for the next level, so give up
30
- return
31
- end
32
- else
33
- # this isn't a container data type, so we can't walk into it
34
- return
35
- end
36
-
37
- facts = facts[level]
38
- end
39
-
40
- result[:exists] = true
41
- case facts
42
- when Array, Hash
43
- # Currently data plugins cannot return structured data, so until
44
- # this is fixed flatten the data with json and flag that we have
45
- # munged the data
46
- result[:value] = facts.to_json
47
- result[:value_encoding] = "application/json"
48
- else
49
- result[:value] = facts
50
- result[:value_encoding] = "text/plain"
51
- end
52
- end
53
- end
54
- end
55
- end
@@ -1,89 +0,0 @@
1
- metadata :name => "File Stat",
2
- :description => "Retrieve file stat data for a given file",
3
- :author => "R.I.Pienaar <rip@devco.net>",
4
- :license => "ASL 2.0",
5
- :version => "1.0",
6
- :url => "https://docs.puppetlabs.com/mcollective/",
7
- :timeout => 1
8
-
9
- dataquery :description => "File stat information" do
10
- input :query,
11
- :prompt => "File Name",
12
- :description => "Valid File Name",
13
- :type => :string,
14
- :validation => /.+/,
15
- :maxlength => 120
16
-
17
- output :name,
18
- :description => "File name",
19
- :display_as => "Name"
20
-
21
- output :output,
22
- :description => "Human readable information about the file",
23
- :display_as => "Status"
24
-
25
- output :present,
26
- :description => "Indicates if the file exist using 0 or 1",
27
- :display_as => "Present"
28
-
29
- output :size,
30
- :description => "File size",
31
- :display_as => "Size"
32
-
33
- output :mode,
34
- :description => "File mode",
35
- :display_as => "Mode"
36
-
37
- output :md5,
38
- :description => "File MD5 digest",
39
- :display_as => "MD5"
40
-
41
- output :mtime,
42
- :description => "File modification time",
43
- :display_as => "Modification time"
44
-
45
- output :ctime,
46
- :description => "File change time",
47
- :display_as => "Change time"
48
-
49
- output :atime,
50
- :description => "File access time",
51
- :display_as => "Access time"
52
-
53
- output :mtime_seconds,
54
- :description => "File modification time in seconds",
55
- :display_as => "Modification time"
56
-
57
- output :ctime_seconds,
58
- :description => "File change time in seconds",
59
- :display_as => "Change time"
60
-
61
- output :atime_seconds,
62
- :description => "File access time in seconds",
63
- :display_as => "Access time"
64
-
65
- output :mtime_age,
66
- :description => "File modification age in seconds",
67
- :display_as => "Modification age"
68
-
69
- output :ctime_age,
70
- :description => "File change age in seconds",
71
- :display_as => "Change age"
72
-
73
- output :atime_age,
74
- :description => "File access age in seconds",
75
- :display_as => "Access age"
76
-
77
- output :uid,
78
- :description => "File owner",
79
- :display_as => "Owner"
80
-
81
- output :gid,
82
- :description => "File group",
83
- :display_as => "Group"
84
-
85
- output :type,
86
- :description => "File type",
87
- :display_as => "Type"
88
- end
89
-
@@ -1,54 +0,0 @@
1
- module MCollective
2
- module Data
3
- class Fstat_data < Base
4
- query do |file|
5
- result[:name] = file
6
- result[:output] = "not present"
7
- result[:type] = "unknown"
8
- result[:mode] = "0000"
9
- result[:present] = 0
10
- result[:size] = 0
11
- result[:mtime] = 0
12
- result[:ctime] = 0
13
- result[:atime] = 0
14
- result[:mtime_seconds] = 0
15
- result[:ctime_seconds] = 0
16
- result[:atime_seconds] = 0
17
- result[:md5] = 0
18
- result[:uid] = 0
19
- result[:gid] = 0
20
-
21
- if File.exist?(file)
22
- result[:output] = "present"
23
- result[:present] = 1
24
-
25
- if File.symlink?(file)
26
- stat = File.lstat(file)
27
- else
28
- stat = File.stat(file)
29
- end
30
-
31
- [:size, :uid, :gid].each do |item|
32
- result[item] = stat.send(item)
33
- end
34
-
35
- [:mtime, :ctime, :atime].each do |item|
36
- result[item] = stat.send(item).strftime("%F %T")
37
- result["#{item}_seconds".to_sym] = stat.send(item).to_i
38
- result["#{item}_age".to_sym] = Time.now.to_i - stat.send(item).to_i
39
- end
40
-
41
- result[:mode] = "%o" % [stat.mode]
42
- result[:md5] = Digest::MD5.hexdigest(File.read(file)) if stat.file?
43
-
44
- result[:type] = "directory" if stat.directory?
45
- result[:type] = "file" if stat.file?
46
- result[:type] = "symlink" if stat.symlink?
47
- result[:type] = "socket" if stat.socket?
48
- result[:type] = "chardev" if stat.chardev?
49
- result[:type] = "blockdev" if stat.blockdev?
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,50 +0,0 @@
1
- module MCollective
2
- module Data
3
- class Result
4
- # remove some methods that might clash with commonly
5
- # used return data to improve the effectiveness of the
6
- # method_missing lookup strategy
7
- undef :type if method_defined?(:type)
8
-
9
- def initialize(outputs)
10
- @data = {}
11
-
12
- outputs.each_key do |output|
13
- @data[output] = Marshal.load(Marshal.dump(outputs[output].fetch(:default, nil)))
14
- end
15
- end
16
-
17
- def include?(key)
18
- @data.include?(key.to_sym)
19
- end
20
-
21
- def [](key)
22
- @data[key.to_sym]
23
- end
24
-
25
- def []=(key, val)
26
- # checks using the string representation of the class name to avoid deprecations on Bignum and Fixnum
27
- raise "Can only store String, Integer, Float or Boolean data but got #{val.class} for key #{key}" unless ["String", "Integer", "Bignum", "Fixnum", "Float", "TrueClass",
28
- "FalseClass"].include?(val.class.to_s)
29
-
30
- @data[key.to_sym] = val
31
- end
32
-
33
- def keys
34
- @data.keys
35
- end
36
-
37
- def respond_to_missing?(method, *)
38
- include?(method)
39
- end
40
-
41
- def method_missing(method, *args)
42
- key = method.to_sym
43
-
44
- raise NoMethodError, "undefined local variable or method `%s'" % key unless include?(key)
45
-
46
- @data[key]
47
- end
48
- end
49
- end
50
- end
@@ -1,56 +0,0 @@
1
- module MCollective
2
- module DDL
3
- # A DDL file for the data query plugins.
4
- #
5
- # Query plugins can today take only one input by convention in the DDL that
6
- # is called :query, otherwise the input is identical to the standard input.
7
- #
8
- # metadata :name => "Agent",
9
- # :description => "Meta data about installed MColletive Agents",
10
- # :author => "R.I.Pienaar <rip@devco.net>",
11
- # :license => "ASL 2.0",
12
- # :version => "1.0",
13
- # :url => "https://docs.puppetlabs.com/mcollective/",
14
- # :timeout => 1
15
- #
16
- # dataquery :description => "Agent Meta Data" do
17
- # input :query,
18
- # :prompt => "Agent Name",
19
- # :description => "Valid agent name",
20
- # :type => :string,
21
- # :validation => /^[\w\_]+$/,
22
- # :maxlength => 20
23
- #
24
- # [:license, :timeout, :description, :url, :version, :author].each do |item|
25
- # output item,
26
- # :description => "Agent #{item}",
27
- # :display_as => item.to_s.capitalize
28
- # end
29
- # end
30
- class DataDDL < Base
31
- def dataquery(input, &block)
32
- raise "Data queries need a :description" unless input.include?(:description)
33
- raise "Data queries can only have one definition" if @entities[:data]
34
-
35
- @entities[:data] = {:description => input[:description],
36
- :input => {},
37
- :output => {}}
38
-
39
- @current_entity = :data
40
- yield if block_given?
41
- @current_entity = nil
42
- end
43
-
44
- def input(argument, properties)
45
- raise "The only valid input name for a data query is 'query'" if argument != :query
46
-
47
- super
48
- end
49
-
50
- # Returns the interface for the data query
51
- def dataquery_interface
52
- @entities[:data] || {}
53
- end
54
- end
55
- end
56
- end
@@ -1,223 +0,0 @@
1
- require "net/http"
2
- require_relative "../util/choria"
3
-
4
- module MCollective
5
- class Discovery
6
- class Choria
7
- def self.discover(filter, timeout, limit=0, client=nil)
8
- Choria.new(filter, timeout, limit, client).discover
9
- end
10
-
11
- attr_reader :timeout, :limit, :client, :config
12
- attr_accessor :filter
13
-
14
- def initialize(filter, timeout, limit, client)
15
- @filter = filter
16
- @timeout = timeout
17
- @limit = limit
18
- @client = client
19
- @config = Config.instance
20
- end
21
-
22
- # Search for nodes
23
- #
24
- # @return [Array<String>] list of certnames found
25
- def discover
26
- queries = []
27
-
28
- if choria.proxied_discovery?
29
- Log.debug("Performing discovery against a PuppetDB Proxy")
30
-
31
- choria.proxy_discovery_query(proxy_request)
32
- else
33
- Log.debug("Performing direct discovery against PuppetDB")
34
- queries << discover_collective(filter["collective"]) if filter["collective"]
35
- queries << discover_nodes(filter["identity"]) unless filter["identity"].empty?
36
- queries << discover_classes(filter["cf_class"]) unless filter["cf_class"].empty?
37
- queries << discover_facts(filter["fact"]) unless filter["fact"].empty?
38
- queries << discover_agents(filter["agent"]) unless filter["agent"].empty?
39
-
40
- choria.pql_query(node_search_string(queries.compact), true)
41
- end
42
- end
43
-
44
- # Creates a request hash for the discovery proxy
45
- #
46
- # @return [Hash]
47
- def proxy_request
48
- request = {}
49
-
50
- request["collective"] = filter["collective"] if filter["collective"]
51
- request["identities"] = filter["identity"] unless filter["identity"].empty?
52
- request["classes"] = filter["cf_class"] unless filter["cf_class"].empty?
53
- request["facts"] = filter["fact"] unless filter["fact"].empty?
54
- request["agents"] = filter["agent"] unless filter["agent"].empty?
55
-
56
- request
57
- end
58
-
59
- # Discovers nodes in a specific collective
60
- #
61
- # @param filter [String] a collective name
62
- # @return [String] a query string
63
- def discover_collective(filter)
64
- 'certname in inventory[certname] { facts.mcollective.server.collectives.match("\d+") = "%s" }' % filter
65
- end
66
-
67
- # Searches for facts
68
- #
69
- # Nodes are searched using an `and` operator via the discover_classes method
70
- #
71
- # When the `rpcutil` or `scout` agent is required it will look for `Mcollective` class
72
- # otherwise `Mcollective_avent_agentname` thus it will only find plugins
73
- # installed using the `choria/mcollective` AIO plugin packager
74
- #
75
- # @param filter [Array<String>] agent names
76
- # @return [Array<String>] list of nodes found
77
- def discover_agents(filter)
78
- pql = filter.map do |agent|
79
- if ["rpcutil", "scout"].include?(agent)
80
- "(%s or %s)" % [discover_classes(["mcollective::service"]), discover_classes(["choria::service"])]
81
- elsif agent =~ /^\/(.+)\/$/
82
- 'resources {type = "File" and tag ~ "mcollective_agent_.*?%s.*?_server"}' % [string_regexi($1)]
83
- else
84
- 'resources {type = "File" and tag = "mcollective_agent_%s_server"}' % [agent]
85
- end
86
- end
87
-
88
- pql.join(" and ") unless pql.empty?
89
- end
90
-
91
- # Turns a string into a case insensitive regex string
92
- #
93
- # @param value [String]
94
- # @return [String]
95
- def string_regexi(value)
96
- value =~ /^\/(.+)\/$/ ? derived_value = $1 : derived_value = value.dup
97
-
98
- derived_value.each_char.map do |char|
99
- if char =~ /[[:alpha:]]/
100
- "[%s%s]" % [char.downcase, char.upcase]
101
- else
102
- char
103
- end
104
- end.join
105
- end
106
-
107
- # Capitalize a Puppet Resource
108
- #
109
- # foo::bar => Foo::Bar
110
- #
111
- # @param resource [String] a resource title
112
- # @return [String]
113
- def capitalize_resource(resource)
114
- resource.split("::").map(&:capitalize).join("::")
115
- end
116
-
117
- # Searches for facts
118
- #
119
- # Nodes are searched using an `and` operator
120
- #
121
- # @param filter [Array<Hash>] hashes with :fact, :operator and :value
122
- # @return [Array<String>] list of nodes found
123
- def discover_facts(filter)
124
- pql = filter.map do |q|
125
- fact = q[:fact]
126
- operator = q[:operator]
127
- value = q[:value]
128
-
129
- case operator
130
- when "=~"
131
- regex = string_regexi(value)
132
-
133
- 'inventory {facts.%s ~ "%s"}' % [fact, regex]
134
- when "=="
135
- if ["true", "false"].include?(value) || numeric?(value)
136
- 'inventory {facts.%s = %s or facts.%s = "%s"}' % [fact, value, fact, value]
137
- else
138
- 'inventory {facts.%s = "%s"}' % [fact, value]
139
- end
140
- when "!="
141
- if ["true", "false"].include?(value) || numeric?(value)
142
- 'inventory {!(facts.%s = %s or facts.%s = "%s")}' % [fact, value, fact, value]
143
- else
144
- 'inventory {!(facts.%s = "%s")}' % [fact, value]
145
- end
146
- when ">=", ">", "<=", "<"
147
- raise("Do not know how to do string fact comparisons using the '%s' operator with PuppetDB" % operator) unless numeric?(value)
148
-
149
- "inventory {facts.%s %s %s}" % [fact, operator, value]
150
- else
151
- raise("Do not know how to do fact comparisons using the '%s' operator with PuppetDB" % operator)
152
- end
153
- end
154
-
155
- pql.join(" and ") unless pql.empty?
156
- end
157
-
158
- # Searches for classes
159
- #
160
- # Nodes are searched using an `and` operator
161
- #
162
- # @return [Array<String>] list of nodes found
163
- def discover_classes(filter)
164
- pql = filter.map do |klass|
165
- if klass =~ /^\/(.+)\/$/
166
- 'resources {type = "Class" and title ~ "%s"}' % [string_regexi($1)]
167
- else
168
- 'resources {type = "Class" and title = "%s"}' % [capitalize_resource(klass)]
169
- end
170
- end
171
-
172
- pql.join(" and ") unless pql.empty?
173
- end
174
-
175
- # Searches for nodes
176
- #
177
- # Nodes are searched using an `or` operator
178
- #
179
- # @return [Array<String>] list of nodes found
180
- def discover_nodes(filter)
181
- if filter.empty?
182
- Log.debug("Empty node filter found, discovering all nodes")
183
- nil
184
- else
185
- pql = filter.map do |ident|
186
- case ident
187
- when /^pql:\s*(.+)$/
188
- "certname in %s" % $1
189
- when /^\/(.+)\/$/
190
- 'certname ~ "%s"' % string_regexi($1)
191
- else
192
- 'certname = "%s"' % ident
193
- end
194
- end
195
-
196
- pql.join(" or ") unless pql.empty?
197
- end
198
- end
199
-
200
- # Produce a nodes query with the supplied sub query included
201
- #
202
- # @param queries [Array<String>] PQL queries to be used as a sub query
203
- # @return [String] nodes search string
204
- def node_search_string(queries)
205
- filter_queries = queries.map {|q| "(%s)" % q}.join(" and ")
206
-
207
- "nodes[certname, deactivated] { %s }" % [filter_queries]
208
- end
209
-
210
- # Determines if a string is a number, either float or integer
211
- #
212
- # @param string [String]
213
- # @return [boolean]
214
- def numeric?(string)
215
- true if Float(string) rescue false
216
- end
217
-
218
- def choria
219
- @_choria ||= Util::Choria.new(false)
220
- end
221
- end
222
- end
223
- end