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.
- checksums.yaml +5 -5
- data/lib/mcollective.rb +3 -3
- data/lib/mcollective/agent/bolt_tasks.ddl +18 -0
- data/lib/mcollective/agent/bolt_tasks.json +18 -0
- data/lib/mcollective/agent/bolt_tasks.rb +4 -2
- data/lib/mcollective/agent/rpcutil.ddl +2 -2
- data/lib/mcollective/agent/rpcutil.json +2 -2
- data/lib/mcollective/application/choria.rb +3 -63
- data/lib/mcollective/application/facts.rb +2 -67
- data/lib/mcollective/application/federation.rb +1 -3
- data/lib/mcollective/application/find.rb +1 -1
- data/lib/mcollective/application/ping.rb +31 -3
- data/lib/mcollective/application/plugin.rb +2 -15
- data/lib/mcollective/application/tasks.rb +9 -0
- data/lib/mcollective/client.rb +1 -1
- data/lib/mcollective/config.rb +135 -103
- data/lib/mcollective/ddl.rb +0 -1
- data/lib/mcollective/discovery.rb +12 -65
- data/lib/mcollective/discovery/broadcast.ddl +11 -0
- data/lib/mcollective/discovery/choria.ddl +6 -4
- data/lib/mcollective/discovery/delegate.ddl +13 -0
- data/lib/mcollective/discovery/delegate.rb +73 -0
- data/lib/mcollective/discovery/external.ddl +13 -0
- data/lib/mcollective/discovery/file.ddl +13 -0
- data/lib/mcollective/discovery/flatfile.ddl +7 -5
- data/lib/mcollective/discovery/inventory.ddl +13 -0
- data/lib/mcollective/discovery/mc.ddl +3 -3
- data/lib/mcollective/generators.rb +0 -1
- data/lib/mcollective/message.rb +0 -24
- data/lib/mcollective/optionparser.rb +2 -2
- data/lib/mcollective/pluginpackager/forge_packager.rb +1 -1
- data/lib/mcollective/rpc/client.rb +6 -4
- data/lib/mcollective/security/base.rb +1 -37
- data/lib/mcollective/util.rb +23 -31
- data/lib/mcollective/util/choria.rb +0 -157
- data/lib/mcollective/util/tasks_support.rb +22 -3
- metadata +9 -27
- data/lib/mcollective/application/describe_filter.rb +0 -87
- data/lib/mcollective/data.rb +0 -96
- data/lib/mcollective/data/agent_data.ddl +0 -22
- data/lib/mcollective/data/agent_data.rb +0 -17
- data/lib/mcollective/data/base.rb +0 -68
- data/lib/mcollective/data/bolt_task_data.ddl +0 -90
- data/lib/mcollective/data/bolt_task_data.rb +0 -32
- data/lib/mcollective/data/collective_data.ddl +0 -20
- data/lib/mcollective/data/collective_data.rb +0 -9
- data/lib/mcollective/data/fact_data.ddl +0 -28
- data/lib/mcollective/data/fact_data.rb +0 -55
- data/lib/mcollective/data/fstat_data.ddl +0 -89
- data/lib/mcollective/data/fstat_data.rb +0 -54
- data/lib/mcollective/data/result.rb +0 -50
- data/lib/mcollective/ddl/dataddl.rb +0 -56
- data/lib/mcollective/discovery/choria.rb +0 -223
- data/lib/mcollective/discovery/flatfile.rb +0 -47
- data/lib/mcollective/discovery/stdin.ddl +0 -11
- data/lib/mcollective/discovery/stdin.rb +0 -67
- data/lib/mcollective/generators/data_generator.rb +0 -50
- data/lib/mcollective/generators/templates/data_input_snippet.erb +0 -7
- data/lib/mcollective/matcher.rb +0 -220
- data/lib/mcollective/matcher/parser.rb +0 -118
- 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,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
|