choria-mcorpc-support 0.0.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 +7 -0
- data/bin/mco +64 -0
- data/lib/mcollective.rb +63 -0
- data/lib/mcollective/agent.rb +5 -0
- data/lib/mcollective/agents.rb +149 -0
- data/lib/mcollective/aggregate.rb +85 -0
- data/lib/mcollective/aggregate/average.ddl +33 -0
- data/lib/mcollective/aggregate/average.rb +29 -0
- data/lib/mcollective/aggregate/base.rb +40 -0
- data/lib/mcollective/aggregate/result.rb +9 -0
- data/lib/mcollective/aggregate/result/base.rb +25 -0
- data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
- data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
- data/lib/mcollective/aggregate/sum.ddl +33 -0
- data/lib/mcollective/aggregate/sum.rb +18 -0
- data/lib/mcollective/aggregate/summary.ddl +33 -0
- data/lib/mcollective/aggregate/summary.rb +53 -0
- data/lib/mcollective/application.rb +365 -0
- data/lib/mcollective/application/completion.rb +104 -0
- data/lib/mcollective/application/describe_filter.rb +87 -0
- data/lib/mcollective/application/facts.rb +62 -0
- data/lib/mcollective/application/find.rb +23 -0
- data/lib/mcollective/application/help.rb +28 -0
- data/lib/mcollective/application/inventory.rb +344 -0
- data/lib/mcollective/application/ping.rb +82 -0
- data/lib/mcollective/application/plugin.rb +369 -0
- data/lib/mcollective/application/rpc.rb +111 -0
- data/lib/mcollective/applications.rb +134 -0
- data/lib/mcollective/cache.rb +145 -0
- data/lib/mcollective/client.rb +353 -0
- data/lib/mcollective/config.rb +245 -0
- data/lib/mcollective/connector.rb +18 -0
- data/lib/mcollective/connector/base.rb +26 -0
- data/lib/mcollective/data.rb +91 -0
- data/lib/mcollective/data/agent_data.ddl +22 -0
- data/lib/mcollective/data/agent_data.rb +17 -0
- data/lib/mcollective/data/base.rb +67 -0
- data/lib/mcollective/data/collective_data.ddl +20 -0
- data/lib/mcollective/data/collective_data.rb +9 -0
- data/lib/mcollective/data/fact_data.ddl +28 -0
- data/lib/mcollective/data/fact_data.rb +55 -0
- data/lib/mcollective/data/fstat_data.ddl +89 -0
- data/lib/mcollective/data/fstat_data.rb +56 -0
- data/lib/mcollective/data/result.rb +45 -0
- data/lib/mcollective/ddl.rb +113 -0
- data/lib/mcollective/ddl/agentddl.rb +253 -0
- data/lib/mcollective/ddl/base.rb +217 -0
- data/lib/mcollective/ddl/dataddl.rb +56 -0
- data/lib/mcollective/ddl/discoveryddl.rb +52 -0
- data/lib/mcollective/ddl/validatorddl.rb +6 -0
- data/lib/mcollective/discovery.rb +143 -0
- data/lib/mcollective/discovery/flatfile.ddl +11 -0
- data/lib/mcollective/discovery/flatfile.rb +48 -0
- data/lib/mcollective/discovery/mc.ddl +11 -0
- data/lib/mcollective/discovery/mc.rb +30 -0
- data/lib/mcollective/discovery/stdin.ddl +11 -0
- data/lib/mcollective/discovery/stdin.rb +68 -0
- data/lib/mcollective/exceptions.rb +28 -0
- data/lib/mcollective/facts.rb +39 -0
- data/lib/mcollective/facts/base.rb +100 -0
- data/lib/mcollective/facts/yaml_facts.rb +65 -0
- data/lib/mcollective/generators.rb +7 -0
- data/lib/mcollective/generators/agent_generator.rb +51 -0
- data/lib/mcollective/generators/base.rb +46 -0
- data/lib/mcollective/generators/data_generator.rb +51 -0
- data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
- data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
- data/lib/mcollective/generators/templates/ddl.erb +8 -0
- data/lib/mcollective/generators/templates/plugin.erb +7 -0
- data/lib/mcollective/log.rb +118 -0
- data/lib/mcollective/logger.rb +5 -0
- data/lib/mcollective/logger/base.rb +77 -0
- data/lib/mcollective/logger/console_logger.rb +61 -0
- data/lib/mcollective/logger/file_logger.rb +53 -0
- data/lib/mcollective/logger/syslog_logger.rb +53 -0
- data/lib/mcollective/matcher.rb +224 -0
- data/lib/mcollective/matcher/parser.rb +128 -0
- data/lib/mcollective/matcher/scanner.rb +241 -0
- data/lib/mcollective/message.rb +248 -0
- data/lib/mcollective/monkey_patches.rb +152 -0
- data/lib/mcollective/optionparser.rb +197 -0
- data/lib/mcollective/pluginmanager.rb +180 -0
- data/lib/mcollective/pluginpackager.rb +98 -0
- data/lib/mcollective/pluginpackager/agent_definition.rb +94 -0
- data/lib/mcollective/pluginpackager/debpackage_packager.rb +237 -0
- data/lib/mcollective/pluginpackager/modulepackage_packager.rb +127 -0
- data/lib/mcollective/pluginpackager/ospackage_packager.rb +59 -0
- data/lib/mcollective/pluginpackager/rpmpackage_packager.rb +180 -0
- data/lib/mcollective/pluginpackager/standard_definition.rb +69 -0
- data/lib/mcollective/pluginpackager/templates/debian/Makefile.erb +7 -0
- data/lib/mcollective/pluginpackager/templates/debian/changelog.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/debian/compat.erb +1 -0
- data/lib/mcollective/pluginpackager/templates/debian/control.erb +15 -0
- data/lib/mcollective/pluginpackager/templates/debian/copyright.erb +8 -0
- data/lib/mcollective/pluginpackager/templates/debian/rules.erb +6 -0
- data/lib/mcollective/pluginpackager/templates/module/Modulefile.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/module/README.md.erb +37 -0
- data/lib/mcollective/pluginpackager/templates/module/_manifest.pp.erb +9 -0
- data/lib/mcollective/pluginpackager/templates/redhat/rpm_spec.erb +63 -0
- data/lib/mcollective/registration/base.rb +91 -0
- data/lib/mcollective/rpc.rb +182 -0
- data/lib/mcollective/rpc/actionrunner.rb +158 -0
- data/lib/mcollective/rpc/agent.rb +374 -0
- data/lib/mcollective/rpc/audit.rb +38 -0
- data/lib/mcollective/rpc/client.rb +1066 -0
- data/lib/mcollective/rpc/helpers.rb +321 -0
- data/lib/mcollective/rpc/progress.rb +63 -0
- data/lib/mcollective/rpc/reply.rb +87 -0
- data/lib/mcollective/rpc/request.rb +86 -0
- data/lib/mcollective/rpc/result.rb +90 -0
- data/lib/mcollective/rpc/stats.rb +294 -0
- data/lib/mcollective/runnerstats.rb +90 -0
- data/lib/mcollective/security.rb +26 -0
- data/lib/mcollective/security/base.rb +244 -0
- data/lib/mcollective/shell.rb +126 -0
- data/lib/mcollective/ssl.rb +285 -0
- data/lib/mcollective/util.rb +579 -0
- data/lib/mcollective/validator.rb +85 -0
- data/lib/mcollective/validator/array_validator.ddl +7 -0
- data/lib/mcollective/validator/array_validator.rb +9 -0
- data/lib/mcollective/validator/ipv4address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv4address_validator.rb +16 -0
- data/lib/mcollective/validator/ipv6address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv6address_validator.rb +16 -0
- data/lib/mcollective/validator/length_validator.ddl +7 -0
- data/lib/mcollective/validator/length_validator.rb +11 -0
- data/lib/mcollective/validator/regex_validator.ddl +7 -0
- data/lib/mcollective/validator/regex_validator.rb +9 -0
- data/lib/mcollective/validator/shellsafe_validator.ddl +7 -0
- data/lib/mcollective/validator/shellsafe_validator.rb +13 -0
- data/lib/mcollective/validator/typecheck_validator.ddl +7 -0
- data/lib/mcollective/validator/typecheck_validator.rb +28 -0
- metadata +215 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
metadata :name => "flatfile",
|
|
2
|
+
:description => "Flatfile based discovery for node identities",
|
|
3
|
+
:author => "R.I.Pienaar <rip@devco.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
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
unless client.options[:discovery_options].empty?
|
|
9
|
+
file = client.options[:discovery_options].first
|
|
10
|
+
else
|
|
11
|
+
raise "The flatfile discovery method needs a path to a text file"
|
|
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
|
+
if host.empty? || host.match(/^#/)
|
|
22
|
+
next
|
|
23
|
+
end
|
|
24
|
+
raise 'Identities can only match /^[\w\.\-]+$/' unless host.match(/^[\w\.\-]+$/)
|
|
25
|
+
hosts << host
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# this plugin only supports identity filters, do regex matches etc against
|
|
29
|
+
# the list found in the flatfile
|
|
30
|
+
if !(filter["identity"].empty?)
|
|
31
|
+
filter["identity"].each do |identity|
|
|
32
|
+
identity = Regexp.new(identity.gsub("\/", "")) if identity.match("^/")
|
|
33
|
+
|
|
34
|
+
if identity.is_a?(Regexp)
|
|
35
|
+
discovered = hosts.grep(identity)
|
|
36
|
+
elsif hosts.include?(identity)
|
|
37
|
+
discovered << identity
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
discovered = hosts
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
discovered
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
metadata :name => "mc",
|
|
2
|
+
:description => "MCollective Broadcast based discovery",
|
|
3
|
+
:author => "R.I.Pienaar <rip@devco.net>",
|
|
4
|
+
:license => "ASL 2.0",
|
|
5
|
+
:version => "0.1",
|
|
6
|
+
:url => "https://docs.puppetlabs.com/mcollective/",
|
|
7
|
+
:timeout => 2
|
|
8
|
+
|
|
9
|
+
discovery do
|
|
10
|
+
capabilities [:classes, :facts, :identity, :agents, :compound]
|
|
11
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
class Discovery
|
|
3
|
+
class Mc
|
|
4
|
+
def self.discover(filter, timeout, limit, client)
|
|
5
|
+
begin
|
|
6
|
+
hosts = []
|
|
7
|
+
Timeout.timeout(timeout) do
|
|
8
|
+
reqid = client.sendreq("ping", "discovery", filter)
|
|
9
|
+
Log.debug("Waiting #{timeout} seconds for discovery replies to request #{reqid}")
|
|
10
|
+
|
|
11
|
+
loop do
|
|
12
|
+
reply = client.receive(reqid)
|
|
13
|
+
Log.debug("Got discovery reply from #{reply.payload[:senderid]}")
|
|
14
|
+
hosts << reply.payload[:senderid]
|
|
15
|
+
|
|
16
|
+
return hosts if limit > 0 && hosts.size == limit
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
rescue Timeout::Error => e
|
|
20
|
+
rescue Exception => e
|
|
21
|
+
raise
|
|
22
|
+
ensure
|
|
23
|
+
client.unsubscribe("discovery", :reply)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
hosts
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
|
@@ -0,0 +1,68 @@
|
|
|
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
|
+
unless client.options[:discovery_options].empty?
|
|
11
|
+
type = client.options[:discovery_options].first.downcase
|
|
12
|
+
else
|
|
13
|
+
type = 'auto'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
discovered = []
|
|
17
|
+
|
|
18
|
+
file = STDIN.read
|
|
19
|
+
|
|
20
|
+
if file =~ /^\s*$/
|
|
21
|
+
raise("data piped on STDIN contained only whitespace - could not discover hosts from it.")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if type == 'auto'
|
|
25
|
+
if file =~ /^\s*\[/
|
|
26
|
+
type = 'json'
|
|
27
|
+
else
|
|
28
|
+
type = 'text'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
Log.debug("Parsing STDIN input as type %s" % type)
|
|
33
|
+
|
|
34
|
+
if type == 'json'
|
|
35
|
+
hosts = RPC::Helpers.extract_hosts_from_json(file)
|
|
36
|
+
elsif type == 'text'
|
|
37
|
+
hosts = file.split("\n")
|
|
38
|
+
else
|
|
39
|
+
raise("stdin discovery plugin only knows the types auto/text/json, not \"#{type}\"")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
hosts.map do |host|
|
|
43
|
+
raise 'Identities can only match /\w\.\-/' unless host.match(/^[\w\.\-]+$/)
|
|
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
|
+
unless filter["identity"].empty?
|
|
50
|
+
filter["identity"].each do |identity|
|
|
51
|
+
identity = Regexp.new(identity.gsub("\/", "")) if identity.match("^/")
|
|
52
|
+
|
|
53
|
+
if identity.is_a?(Regexp)
|
|
54
|
+
discovered = hosts.grep(identity)
|
|
55
|
+
elsif hosts.include?(identity)
|
|
56
|
+
discovered << identity
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
else
|
|
60
|
+
discovered = hosts
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
discovered
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
# Exceptions for the RPC system
|
|
3
|
+
class DDLValidationError<RuntimeError;end
|
|
4
|
+
class ValidatorError<RuntimeError; end
|
|
5
|
+
class ClientTimeoutError<RuntimeError; end
|
|
6
|
+
class MsgDoesNotMatchRequestID < RuntimeError; end
|
|
7
|
+
class MsgTTLExpired<RuntimeError;end
|
|
8
|
+
class NotTargettedAtUs<RuntimeError;end
|
|
9
|
+
class RPCError<StandardError;end
|
|
10
|
+
class SecurityValidationFailed<RuntimeError;end
|
|
11
|
+
|
|
12
|
+
class BackoffSuggestion<StandardError
|
|
13
|
+
attr_reader :backoff
|
|
14
|
+
|
|
15
|
+
def initialize(backoff = nil)
|
|
16
|
+
@backoff = backoff
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class MessageNotReceived<BackoffSuggestion; end
|
|
21
|
+
class UnexpectedMessageType<BackoffSuggestion; end
|
|
22
|
+
|
|
23
|
+
class InvalidRPCData<RPCError;end
|
|
24
|
+
class MissingRPCData<RPCError;end
|
|
25
|
+
class RPCAborted<RPCError;end
|
|
26
|
+
class UnknownRPCAction<RPCError;end
|
|
27
|
+
class UnknownRPCError<RPCError;end
|
|
28
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
# This is a class that gives access to the configured fact provider
|
|
3
|
+
# such as MCollectives::Facts::Facter that uses Reductive Labs facter
|
|
4
|
+
#
|
|
5
|
+
# The actual provider is pluggable and configurable using the 'factsource'
|
|
6
|
+
# configuration option.
|
|
7
|
+
#
|
|
8
|
+
# To develop a new factsource simply create a class under MCollective::Facts::
|
|
9
|
+
# and provide the following classes:
|
|
10
|
+
#
|
|
11
|
+
# self.get_fact(fact)
|
|
12
|
+
# self.has_fact?(fact)
|
|
13
|
+
#
|
|
14
|
+
# You can also just inherit from MCollective::Facts::Base and provide just the
|
|
15
|
+
#
|
|
16
|
+
# self.get_facts
|
|
17
|
+
#
|
|
18
|
+
# method that should return a hash of facts.
|
|
19
|
+
module Facts
|
|
20
|
+
require "mcollective/facts/base"
|
|
21
|
+
|
|
22
|
+
@@config = nil
|
|
23
|
+
|
|
24
|
+
# True if we know of a specific fact else false
|
|
25
|
+
def self.has_fact?(fact, value)
|
|
26
|
+
PluginManager["facts_plugin"].get_fact(fact) == value ? true : false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Get the value of a fact
|
|
30
|
+
def self.get_fact(fact)
|
|
31
|
+
PluginManager["facts_plugin"].get_fact(fact)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Get the value of a fact
|
|
35
|
+
def self.[](fact)
|
|
36
|
+
PluginManager["facts_plugin"].get_fact(fact)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Facts
|
|
3
|
+
# A base class for fact providers, to make a new fully functional fact provider
|
|
4
|
+
# inherit from this and simply provide a self.get_facts method that returns a
|
|
5
|
+
# hash like:
|
|
6
|
+
#
|
|
7
|
+
# {"foo" => "bar",
|
|
8
|
+
# "bar" => "baz"}
|
|
9
|
+
class Base
|
|
10
|
+
def initialize
|
|
11
|
+
@mutex = Mutex.new
|
|
12
|
+
@facts = {}
|
|
13
|
+
@last_good_facts = {}
|
|
14
|
+
@last_facts_load = 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Registers new fact sources into the plugin manager
|
|
18
|
+
def self.inherited(klass)
|
|
19
|
+
PluginManager << {:type => "facts_plugin", :class => klass.to_s}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns the value of a single fact
|
|
23
|
+
def get_fact(fact=nil)
|
|
24
|
+
config = Config.instance
|
|
25
|
+
|
|
26
|
+
cache_time = config.fact_cache_time || 300
|
|
27
|
+
|
|
28
|
+
@mutex.synchronize do
|
|
29
|
+
begin
|
|
30
|
+
if (Time.now.to_i - @last_facts_load > cache_time.to_i ) || force_reload?
|
|
31
|
+
Log.debug("Resetting facter cache, now: #{Time.now.to_i} last-known-good: #{@last_facts_load}")
|
|
32
|
+
|
|
33
|
+
tfacts = load_facts_from_source
|
|
34
|
+
|
|
35
|
+
# Force reset to last known good state on empty facts
|
|
36
|
+
raise "Got empty facts" if tfacts.empty?
|
|
37
|
+
|
|
38
|
+
@facts = normalize_facts(tfacts)
|
|
39
|
+
|
|
40
|
+
@last_good_facts = @facts.clone
|
|
41
|
+
@last_facts_load = Time.now.to_i
|
|
42
|
+
else
|
|
43
|
+
Log.debug("Using cached facts now: #{Time.now.to_i} last-known-good: #{@last_facts_load}")
|
|
44
|
+
end
|
|
45
|
+
rescue Exception => e
|
|
46
|
+
Log.error("Failed to load facts: #{e.class}: #{e}")
|
|
47
|
+
|
|
48
|
+
# Avoid loops where failing fact loads cause huge CPU
|
|
49
|
+
# loops, this way it only retries once every cache_time
|
|
50
|
+
# seconds
|
|
51
|
+
@last_facts_load = Time.now.to_i
|
|
52
|
+
|
|
53
|
+
# Revert to last known good state
|
|
54
|
+
@facts = @last_good_facts.clone
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# If you do not supply a specific fact all facts will be returned
|
|
60
|
+
if fact.nil?
|
|
61
|
+
return @facts
|
|
62
|
+
else
|
|
63
|
+
@facts.include?(fact) ? @facts[fact] : nil
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Returns all facts
|
|
68
|
+
def get_facts
|
|
69
|
+
get_fact(nil)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Returns true if we know about a specific fact, false otherwise
|
|
73
|
+
def has_fact?(fact)
|
|
74
|
+
get_fact(nil).include?(fact)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Plugins can override this to provide forced fact invalidation
|
|
78
|
+
def force_reload?
|
|
79
|
+
false
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def normalize_facts(value)
|
|
85
|
+
case value
|
|
86
|
+
when Array
|
|
87
|
+
return value.map { |v| normalize_facts(v) }
|
|
88
|
+
when Hash
|
|
89
|
+
new_hash = {}
|
|
90
|
+
value.each do |k,v|
|
|
91
|
+
new_hash[k.to_s] = normalize_facts(v)
|
|
92
|
+
end
|
|
93
|
+
return new_hash
|
|
94
|
+
else
|
|
95
|
+
return value.to_s
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Facts
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
# A factsource that reads a hash of facts from a YAML file
|
|
6
|
+
#
|
|
7
|
+
# Multiple files can be specified seperated with a : in the
|
|
8
|
+
# config file, they will be merged with later files overriding
|
|
9
|
+
# earlier ones in the list.
|
|
10
|
+
class Yaml_facts<Base
|
|
11
|
+
def initialize
|
|
12
|
+
@yaml_file_mtimes = {}
|
|
13
|
+
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def load_facts_from_source
|
|
18
|
+
config = Config.instance
|
|
19
|
+
|
|
20
|
+
fact_files = config.pluginconf["yaml"].split(File::PATH_SEPARATOR)
|
|
21
|
+
facts = {}
|
|
22
|
+
|
|
23
|
+
fact_files.each do |file|
|
|
24
|
+
begin
|
|
25
|
+
if File.exist?(file)
|
|
26
|
+
if YAML.respond_to? :safe_load
|
|
27
|
+
facts.merge!(YAML.safe_load(File.read(file)))
|
|
28
|
+
else
|
|
29
|
+
facts.merge!(YAML.load(File.read(file))) # rubocop:disable Security/YAMLLoad
|
|
30
|
+
end
|
|
31
|
+
else
|
|
32
|
+
raise("Can't find YAML file to load: #{file}")
|
|
33
|
+
end
|
|
34
|
+
rescue Exception => e
|
|
35
|
+
Log.error("Failed to load yaml facts from #{file}: #{e.class}: #{e}")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
facts
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# force fact reloads when the mtime on the yaml file change
|
|
43
|
+
def force_reload?
|
|
44
|
+
config = Config.instance
|
|
45
|
+
|
|
46
|
+
fact_files = config.pluginconf["yaml"].split(File::PATH_SEPARATOR)
|
|
47
|
+
|
|
48
|
+
fact_files.each do |file|
|
|
49
|
+
@yaml_file_mtimes[file] ||= File.stat(file).mtime
|
|
50
|
+
mtime = File.stat(file).mtime
|
|
51
|
+
|
|
52
|
+
if mtime > @yaml_file_mtimes[file]
|
|
53
|
+
@yaml_file_mtimes[file] = mtime
|
|
54
|
+
|
|
55
|
+
Log.debug("Forcing fact reload due to age of #{file}")
|
|
56
|
+
|
|
57
|
+
return true
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
false
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
module Generators
|
|
3
|
+
class AgentGenerator<Base
|
|
4
|
+
|
|
5
|
+
attr_accessor :ddl, :content
|
|
6
|
+
|
|
7
|
+
def initialize(plugin_name, actions = [], name = nil, description = nil, author = nil ,
|
|
8
|
+
license = nil, version = nil, url = nil, timeout = nil)
|
|
9
|
+
|
|
10
|
+
super(name, description, author, license, version, url, timeout)
|
|
11
|
+
@plugin_name = plugin_name
|
|
12
|
+
@actions = actions || []
|
|
13
|
+
@ddl = create_ddl
|
|
14
|
+
@mod_name = "Agent"
|
|
15
|
+
@pclass = "RPC::Agent"
|
|
16
|
+
@content = create_plugin_content
|
|
17
|
+
@plugin = create_plugin_string
|
|
18
|
+
write_plugins
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_ddl
|
|
22
|
+
action_text = ""
|
|
23
|
+
@actions.each_with_index do |action, i|
|
|
24
|
+
action_text += "action \"#{action}\", :description => \"%ACTIONDESCRIPTION%\" do\n"
|
|
25
|
+
action_text += action_help if i == 0
|
|
26
|
+
action_text += "end\n"
|
|
27
|
+
action_text += "\n" unless @actions.size == (i + 1)
|
|
28
|
+
end
|
|
29
|
+
# Use inherited method to create metadata part of the ddl
|
|
30
|
+
create_metadata_string + action_text
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def create_plugin_content
|
|
34
|
+
content_text = ""
|
|
35
|
+
|
|
36
|
+
# Add actions to agent file
|
|
37
|
+
@actions.each_with_index do |action, i|
|
|
38
|
+
content_text += "%6s%s" % [" ", "action \"#{action}\" do\n"]
|
|
39
|
+
content_text += "%6s%s" % [" ", "end\n"]
|
|
40
|
+
content_text += "\n" unless @actions.size == (i + 1)
|
|
41
|
+
end
|
|
42
|
+
content_text
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def action_help
|
|
46
|
+
action_snippet = File.read(File.join(File.dirname(__FILE__), "templates", "action_snippet.erb"))
|
|
47
|
+
ERB.new(action_snippet).result
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|