rfacter 0.0.1 → 0.1.0
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 +4 -4
- data/lib/rfacter.rb +1 -0
- data/lib/rfacter/cli.rb +13 -22
- data/lib/rfacter/config.rb +5 -0
- data/lib/rfacter/config/settings.rb +7 -0
- data/lib/rfacter/core/aggregate.rb +8 -14
- data/lib/rfacter/core/directed_graph.rb +6 -0
- data/lib/rfacter/core/resolvable.rb +19 -15
- data/lib/rfacter/core/suitable.rb +6 -11
- data/lib/rfacter/dsl.rb +11 -10
- data/lib/rfacter/facts/os.rb +48 -13
- data/lib/rfacter/factset.rb +116 -0
- data/lib/rfacter/node.rb +59 -1
- data/lib/rfacter/util/collection.rb +33 -25
- data/lib/rfacter/util/confine.rb +3 -0
- data/lib/rfacter/util/fact.rb +10 -37
- data/lib/rfacter/util/loader.rb +1 -4
- data/lib/rfacter/util/logger.rb +1 -0
- data/lib/rfacter/util/non_nullable.rb +1 -0
- data/lib/rfacter/util/normalization.rb +14 -31
- data/lib/rfacter/util/resolution.rb +9 -22
- data/lib/rfacter/util/values.rb +4 -0
- data/lib/rfacter/version.rb +1 -1
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7bc8b832480542b3e326f4f99389ea4d2b9968d
|
4
|
+
data.tar.gz: 37bad144b7ffbef453ad397ea39ed7ca89c1e43a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afef987a44e33cc8c83134de30694a0a3591f64984aac19906cbe35e27f090635c67af8202271af9b1f3ccfeafce07630690de3678eeafda008ec20e5336347e
|
7
|
+
data.tar.gz: fea2ba928eb78d00e736e35b53bd2f1106223aa612a4371bfe36bcb9e9d1b5731bfe05c5bc27aafc3d38769e9a2da79c27c01cb59d38091edb850219630f3127
|
data/lib/rfacter.rb
CHANGED
data/lib/rfacter/cli.rb
CHANGED
@@ -5,8 +5,13 @@ require 'rfacter'
|
|
5
5
|
|
6
6
|
require_relative 'config'
|
7
7
|
require_relative 'node'
|
8
|
+
require_relative 'factset'
|
8
9
|
require_relative 'util/collection'
|
9
10
|
|
11
|
+
# RFacter Command Line Interface module
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
# @since 0.1.0
|
10
15
|
module RFacter::CLI
|
11
16
|
extend SingleForwardable
|
12
17
|
|
@@ -20,31 +25,17 @@ module RFacter::CLI
|
|
20
25
|
@config.nodes['localhost'] = RFacter::Node.new('localhost')
|
21
26
|
end
|
22
27
|
|
23
|
-
logger.info('cli::run') { "Configured nodes: #{@config.nodes.values.map(&:
|
28
|
+
logger.info('cli::run') { "Configured nodes: #{@config.nodes.values.map(&:id)}" }
|
24
29
|
|
25
|
-
|
26
|
-
collection.load_all
|
30
|
+
factset = RFacter::Factset.new(@config.nodes.values)
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
n[name] = collection.value(name, node)
|
34
|
-
n
|
35
|
-
end
|
36
|
-
end
|
32
|
+
node_facts = if names.empty?
|
33
|
+
factset.to_hash
|
34
|
+
else
|
35
|
+
factset.value(names)
|
36
|
+
end
|
37
37
|
|
38
|
-
|
39
|
-
# reset the colleciton on each loop.
|
40
|
-
collection.flush
|
41
|
-
|
42
|
-
h[node.hostname] = node_facts
|
43
|
-
h
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
puts JSON.pretty_generate(facts)
|
38
|
+
puts JSON.pretty_generate(node_facts)
|
48
39
|
|
49
40
|
exit 0
|
50
41
|
end
|
data/lib/rfacter/config.rb
CHANGED
@@ -13,6 +13,7 @@ require_relative 'node'
|
|
13
13
|
# and contains methods for initializing the settings instance from
|
14
14
|
# various sources.
|
15
15
|
#
|
16
|
+
# @api public
|
16
17
|
# @since 0.1.0
|
17
18
|
module RFacter::Config
|
18
19
|
# Return global configuration
|
@@ -75,6 +76,10 @@ module RFacter::Config
|
|
75
76
|
settings.logger.level = Logger::DEBUG
|
76
77
|
end
|
77
78
|
|
79
|
+
parser.on('--profile', 'Profile fact resolution times.') do
|
80
|
+
settings.profile = true
|
81
|
+
end
|
82
|
+
|
78
83
|
parser.on('-n', '--node', '=MANDATORY', URI, 'Add a node by URI.') do |uri|
|
79
84
|
node = RFacter::Node.new(uri)
|
80
85
|
settings.nodes[node.hostname] = node
|
@@ -6,6 +6,7 @@ require_relative '../util/logger'
|
|
6
6
|
# Instances of this class hold top-level configuration values and shared
|
7
7
|
# service objects such as loggers.
|
8
8
|
#
|
9
|
+
# @api public
|
9
10
|
# @since 0.1.0
|
10
11
|
class RFacter::Config::Settings
|
11
12
|
# Access the logger instance
|
@@ -22,10 +23,16 @@ class RFacter::Config::Settings
|
|
22
23
|
# schemes to use when contacting them.
|
23
24
|
attr_reader :nodes
|
24
25
|
|
26
|
+
# A boolean switch for enabling execution profiling
|
27
|
+
#
|
28
|
+
# @return [Boolean] Defaults to false.
|
29
|
+
attr_accessor :profile
|
30
|
+
|
25
31
|
def initialize(**options)
|
26
32
|
@logger = RFacter::Util::Logger.new($stderr)
|
27
33
|
@logger.level = Logger::WARN
|
28
34
|
|
35
|
+
@profile = false
|
29
36
|
@nodes = Hash.new
|
30
37
|
end
|
31
38
|
end
|
@@ -8,12 +8,12 @@ require_relative '../config'
|
|
8
8
|
# Aggregates are evaluated in two parts: generating individual chunks and then
|
9
9
|
# aggregating all chunks together. Each chunk is a block of code that generates
|
10
10
|
# a value, and may depend on other chunks when it runs. After all chunks have
|
11
|
-
# been evaluated they are passed to the aggregate block as Hash<name, result
|
11
|
+
# been evaluated they are passed to the aggregate block as `Hash<name, result>`.
|
12
12
|
# The aggregate block converts the individual chunks into a single value that is
|
13
13
|
# returned as the final value of the aggregate.
|
14
14
|
#
|
15
|
-
# @api
|
16
|
-
# @since
|
15
|
+
# @api private
|
16
|
+
# @since 0.1.0
|
17
17
|
class RFacter::Core::Aggregate
|
18
18
|
require_relative 'directed_graph'
|
19
19
|
require_relative 'resolvable'
|
@@ -32,19 +32,17 @@ class RFacter::Core::Aggregate
|
|
32
32
|
attr_reader :name
|
33
33
|
|
34
34
|
# @!attribute [r] deps
|
35
|
-
# @
|
36
|
-
# @return [Facter::Core::DirectedGraph]
|
35
|
+
# @return [RFacter::Core::DirectedGraph]
|
37
36
|
attr_reader :deps
|
38
37
|
|
39
38
|
# @!attribute [r] confines
|
40
|
-
# @return [Array<
|
39
|
+
# @return [Array<RFacter::Core::Confine>] An array of confines restricting
|
41
40
|
# this to a specific platform
|
42
|
-
# @see
|
41
|
+
# @see RFacter::Core::Suitable
|
43
42
|
attr_reader :confines
|
44
43
|
|
45
44
|
# @!attribute [r] fact
|
46
|
-
# @return [
|
47
|
-
# @api private
|
45
|
+
# @return [RFacter::Util::Fact]
|
48
46
|
attr_reader :fact
|
49
47
|
|
50
48
|
def initialize(name, fact, config: RFacter::Config.config, **options)
|
@@ -83,8 +81,6 @@ class RFacter::Core::Aggregate
|
|
83
81
|
|
84
82
|
# Define a new chunk for the given aggregate
|
85
83
|
#
|
86
|
-
# @api public
|
87
|
-
#
|
88
84
|
# @example Defining a chunk with no dependencies
|
89
85
|
# aggregate.chunk(:mountpoints) do
|
90
86
|
# # generate mountpoint information
|
@@ -120,8 +116,6 @@ class RFacter::Core::Aggregate
|
|
120
116
|
|
121
117
|
# Define how all chunks should be combined
|
122
118
|
#
|
123
|
-
# @api public
|
124
|
-
#
|
125
119
|
# @example Merge all chunks
|
126
120
|
# aggregate.aggregate do |chunks|
|
127
121
|
# final_result = {}
|
@@ -160,7 +154,7 @@ class RFacter::Core::Aggregate
|
|
160
154
|
|
161
155
|
# Evaluate the results of this aggregate.
|
162
156
|
#
|
163
|
-
# @see
|
157
|
+
# @see RFacter::Core::Resolvable#value
|
164
158
|
# @return [Object]
|
165
159
|
def resolve_value
|
166
160
|
chunk_results = run_chunks()
|
@@ -9,6 +9,9 @@ require_relative '../util/normalization'
|
|
9
9
|
# Classes including this mixin should implement at #name method describing
|
10
10
|
# the value being resolved and a #resolve_value that actually executes the code
|
11
11
|
# to resolve the value.
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
# @since 0.1.0
|
12
15
|
module RFacter::Core::Resolvable
|
13
16
|
|
14
17
|
# The timeout, in seconds, for evaluating this resolution.
|
@@ -19,11 +22,11 @@ module RFacter::Core::Resolvable
|
|
19
22
|
# Return the timeout period for resolving a value.
|
20
23
|
# (see #timeout)
|
21
24
|
# @return [Numeric]
|
22
|
-
# @comment requiring 'timeout' stdlib class causes Object#timeout to be
|
23
|
-
# defined which delegates to Timeout.timeout. This method may potentially
|
24
|
-
# overwrite the #timeout attr_reader on this class, so we define #limit to
|
25
|
-
# avoid conflicts.
|
26
25
|
def limit
|
26
|
+
# requiring 'timeout' stdlib class causes Object#timeout to be defined
|
27
|
+
# which delegates to Timeout.timeout. This method may potentially overwrite
|
28
|
+
# the #timeout attr_reader on this class, so we define #limit to avoid
|
29
|
+
# conflicts.
|
27
30
|
@timeout || 0
|
28
31
|
end
|
29
32
|
|
@@ -39,8 +42,7 @@ module RFacter::Core::Resolvable
|
|
39
42
|
# Please see the Solaris zones fact for an example of how this feature may be
|
40
43
|
# used.
|
41
44
|
#
|
42
|
-
# @see
|
43
|
-
# @see Facter::Util::Resolution#flush
|
45
|
+
# @see RFacter::Util::Fact#flush
|
44
46
|
#
|
45
47
|
# @api public
|
46
48
|
def on_flush(&block)
|
@@ -48,10 +50,9 @@ module RFacter::Core::Resolvable
|
|
48
50
|
end
|
49
51
|
|
50
52
|
##
|
51
|
-
# flush executes the block, if any, stored by the {on_flush} method
|
53
|
+
# flush executes the block, if any, stored by the {#on_flush} method
|
52
54
|
#
|
53
|
-
# @see
|
54
|
-
# @see Facter::Util::Resolution#on_flush
|
55
|
+
# @see RFacter::Util::Fact#flush
|
55
56
|
#
|
56
57
|
# @api private
|
57
58
|
def flush
|
@@ -82,13 +83,16 @@ module RFacter::Core::Resolvable
|
|
82
83
|
private
|
83
84
|
|
84
85
|
def with_timing
|
85
|
-
|
86
|
-
|
87
|
-
|
86
|
+
unless @config.profile
|
87
|
+
yield
|
88
|
+
else
|
89
|
+
starttime = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
90
|
+
yield
|
91
|
+
finishtime = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
88
92
|
|
89
|
-
|
90
|
-
|
91
|
-
|
93
|
+
elapsed = (finishtime - starttime)
|
94
|
+
logger.info { "#{qualified_name}: #{"%.2f" % elapsed}ms" }
|
95
|
+
end
|
92
96
|
end
|
93
97
|
|
94
98
|
def qualified_name
|
@@ -4,7 +4,10 @@ require 'rfacter'
|
|
4
4
|
# certain platforms and determining the run precedence of these objects.
|
5
5
|
#
|
6
6
|
# Classes that include the Suitable mixin should define a `#confines` method
|
7
|
-
# that returns an Array of zero or more
|
7
|
+
# that returns an Array of zero or more {RFacter::Util::Confine} objects.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
# @since 0.1.0
|
8
11
|
module RFacter::Core::Suitable
|
9
12
|
require_relative '../util/confine'
|
10
13
|
|
@@ -18,8 +21,6 @@ module RFacter::Core::Suitable
|
|
18
21
|
# @param weight [Integer] the weight of this resolution
|
19
22
|
#
|
20
23
|
# @return [void]
|
21
|
-
#
|
22
|
-
# @api public
|
23
24
|
def has_weight(weight)
|
24
25
|
@weight = weight
|
25
26
|
end
|
@@ -29,8 +30,6 @@ module RFacter::Core::Suitable
|
|
29
30
|
#
|
30
31
|
# @return [void]
|
31
32
|
#
|
32
|
-
# @api public
|
33
|
-
#
|
34
33
|
# @overload confine(confines)
|
35
34
|
# Confine a fact to a specific fact value or values. This form takes a
|
36
35
|
# hash of fact names and values. Every fact must match the values given for
|
@@ -40,7 +39,7 @@ module RFacter::Core::Suitable
|
|
40
39
|
# @param [Hash{String,Symbol=>String,Array<String>}] confines set of facts identified by the hash keys whose
|
41
40
|
# fact value must match the argument value.
|
42
41
|
# @example Confining to Linux
|
43
|
-
#
|
42
|
+
# RFacter.add(:powerstates) do
|
44
43
|
# # This resolution only makes sense on linux systems
|
45
44
|
# confine :kernel => "Linux"
|
46
45
|
# setcode do
|
@@ -56,7 +55,7 @@ module RFacter::Core::Suitable
|
|
56
55
|
# @param [Proc] block determines the suitability of the fact. If the block
|
57
56
|
# evaluates to `false` or `nil` then the confined fact will not be
|
58
57
|
# evaluated.
|
59
|
-
# @yield [value] the value of the fact identified by
|
58
|
+
# @yield [value] the value of the fact identified by `confines`
|
60
59
|
# @example Confine the fact to a host with an ipaddress in a specific
|
61
60
|
# subnet
|
62
61
|
# confine :ipaddress do |addr|
|
@@ -95,8 +94,6 @@ module RFacter::Core::Suitable
|
|
95
94
|
# specific resolution wins over a less specific one).
|
96
95
|
#
|
97
96
|
# @return [Integer] the weight of this resolution
|
98
|
-
#
|
99
|
-
# @api private
|
100
97
|
def weight
|
101
98
|
if @weight
|
102
99
|
@weight
|
@@ -106,8 +103,6 @@ module RFacter::Core::Suitable
|
|
106
103
|
end
|
107
104
|
|
108
105
|
# Is this resolution mechanism suitable on the system in question?
|
109
|
-
#
|
110
|
-
# @api private
|
111
106
|
def suitable?
|
112
107
|
@confines.all? { |confine| confine.true? }
|
113
108
|
end
|
data/lib/rfacter/dsl.rb
CHANGED
@@ -7,9 +7,10 @@ require_relative 'util/non_nullable'
|
|
7
7
|
# Facter compatibility layer
|
8
8
|
#
|
9
9
|
# This module exists to provide compatibility shims for Facter DSL methods as
|
10
|
-
# exposed by the Facter 3
|
11
|
-
#
|
12
|
-
# these shims. The methods in this module should never be
|
10
|
+
# exposed by the Facter 3 Ruby Extension API. Any fact source code that is
|
11
|
+
# loaded into a {RFacter::Util::Collection} instance via `instance_eval`
|
12
|
+
# should pick up on these shims. The methods in this module should never be
|
13
|
+
# called outside of files that define custom facts.
|
13
14
|
#
|
14
15
|
# However, lexical scope is a tricky thing, so "should" is the operative word
|
15
16
|
# here.
|
@@ -60,7 +61,7 @@ EOS
|
|
60
61
|
# of {RFacter::Util::Fact} and {Facter::Util::Resolution} can be
|
61
62
|
# supplied here
|
62
63
|
# @option options [Integer] :timeout set the
|
63
|
-
# {RFacter::
|
64
|
+
# {RFacter::Core::Resolvable#timeout timeout} for this resolution
|
64
65
|
# @param block [Proc] a block defining a fact resolution
|
65
66
|
#
|
66
67
|
# @return [RFacter::Util::Fact] the fact object, which includes any previously
|
@@ -104,7 +105,7 @@ EOS
|
|
104
105
|
#
|
105
106
|
# @return [RFacter::Util::Fact] The fact that was defined
|
106
107
|
#
|
107
|
-
# @see
|
108
|
+
# @see RFacter::Util::Collection#define_fact
|
108
109
|
def self.define_fact(name, options = {}, &block)
|
109
110
|
COLLECTION.value.define_fact(name, options, &block)
|
110
111
|
end
|
@@ -116,7 +117,7 @@ EOS
|
|
116
117
|
#
|
117
118
|
# @return [void]
|
118
119
|
def self.each
|
119
|
-
COLLECTION.value.each
|
120
|
+
COLLECTION.value.each do |*args|
|
120
121
|
yield(*args)
|
121
122
|
end
|
122
123
|
end
|
@@ -185,7 +186,7 @@ EOS
|
|
185
186
|
#
|
186
187
|
# @return [Hash{String => Object}] the hash of fact names and values
|
187
188
|
def self.to_hash
|
188
|
-
COLLECTION.value.to_hash
|
189
|
+
COLLECTION.value.to_hash
|
189
190
|
end
|
190
191
|
|
191
192
|
# Gets the value for a fact.
|
@@ -195,7 +196,7 @@ EOS
|
|
195
196
|
# @return [Object, nil] the value of the fact, or nil if no fact is
|
196
197
|
# found
|
197
198
|
def self.value(name)
|
198
|
-
COLLECTION.value.value(name
|
199
|
+
COLLECTION.value.value(name)
|
199
200
|
end
|
200
201
|
|
201
202
|
# Returns the current RFacter version
|
@@ -304,11 +305,11 @@ EOS
|
|
304
305
|
# Facter::Util DSL methods
|
305
306
|
module Util
|
306
307
|
require_relative 'util/fact'
|
307
|
-
#
|
308
|
+
# @see RFacter::Util::Fact
|
308
309
|
Fact = ::RFacter::Util::Fact
|
309
310
|
|
310
311
|
require_relative 'util/resolution'
|
311
|
-
#
|
312
|
+
# @see RFacter::Util::Resolution
|
312
313
|
Resolution = ::RFacter::Util::Resolution
|
313
314
|
|
314
315
|
# Methods for interacting with remote files.
|
data/lib/rfacter/facts/os.rb
CHANGED
@@ -40,21 +40,56 @@ Facter.add(:os, :type => :aggregate) do
|
|
40
40
|
# stats and reads, so multiple file ops only incur a cost once. However,
|
41
41
|
# these ops are all going over the network, so we should probably
|
42
42
|
# prioritize RedHat and SuSE detection over less common Linuxen in order to
|
43
|
-
# cut down on network chatter that will be useless in most cases.
|
44
|
-
# might be worth adding /etc/os-release detection at the front of the list
|
45
|
-
# since that's the new hotness from systemd standardization.
|
43
|
+
# cut down on network chatter that will be useless in most cases.
|
46
44
|
operatingsystem = nil
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
46
|
+
# Determine OS name from /etc/os-release if it exists.
|
47
|
+
#
|
48
|
+
# see: https://www.freedesktop.org/software/systemd/man/os-release.html
|
49
|
+
if Facter::Util::FileRead.exists?('/etc/os-release')
|
50
|
+
os_release = Facter::Util::FileRead.read('/etc/os-release')
|
51
|
+
# NOTE: The ID field is used instead of NAME as ID was explicitly
|
52
|
+
# designed to be parsed by scripts whereas NAME is for human consumption.
|
53
|
+
os_id = os_release.lines.find {|l| l.start_with?('ID=')}
|
54
|
+
|
55
|
+
unless os_id.nil?
|
56
|
+
operatingsystem = case os_id
|
57
|
+
when /debian/i
|
58
|
+
'Debian'
|
59
|
+
when /ubuntu/i
|
60
|
+
'Ubuntu'
|
61
|
+
when /opensuse/i
|
62
|
+
'OpenSuSE'
|
63
|
+
when /sles/i
|
64
|
+
'SLES'
|
65
|
+
when /fedora/i
|
66
|
+
'Fedora'
|
67
|
+
when /centos/i
|
68
|
+
'CentOS'
|
69
|
+
when /ol/i
|
70
|
+
'OracleLinux'
|
71
|
+
when /rhel/i
|
72
|
+
'RedHat'
|
73
|
+
when /amzn/i
|
74
|
+
'Amazon'
|
75
|
+
else
|
76
|
+
os_id.scan(/^(?:\w+)=[\"']?(.+?)[\"']?$/).flatten.first
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
if operatingsystem.nil?
|
82
|
+
operatingsystem = if Facter.value(:kernel) == "GNU/kFreeBSD"
|
83
|
+
"GNU/kFreeBSD"
|
84
|
+
elsif Facter::Util::FileRead.exists?('/etc/debian_version')
|
85
|
+
case Facter::Core::Execution.exec('lsb_release -i')
|
86
|
+
when /Ubuntu/i
|
87
|
+
'Ubuntu'
|
88
|
+
when /LinuxMint/i
|
89
|
+
'LinuxMint'
|
90
|
+
else
|
91
|
+
'Debian'
|
92
|
+
end
|
58
93
|
end
|
59
94
|
end
|
60
95
|
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
require 'rfacter'
|
4
|
+
|
5
|
+
require_relative 'config'
|
6
|
+
require_relative 'node'
|
7
|
+
require_relative 'util/collection'
|
8
|
+
|
9
|
+
# A class that can retrieve facts from several nodes
|
10
|
+
#
|
11
|
+
# A factset joins instances of {RFacter::Node} to {RFacter::Util::Collection}
|
12
|
+
# and enables parallel and asynchronous resolution of fact values across
|
13
|
+
# several nodes. Supports retrieving single facts asynchronously via {#fetch}
|
14
|
+
# and in a blocking fashion via {#value}. All facts can be retrieved
|
15
|
+
# asynchronously via {#fetch_all} and in a blocking fashion via {#to_hash}.
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
# @since 0.1.0
|
19
|
+
class RFacter::Factset
|
20
|
+
extend Forwardable
|
21
|
+
|
22
|
+
instance_delegate([:logger] => :@config)
|
23
|
+
|
24
|
+
# Returns a new instance of Factset
|
25
|
+
#
|
26
|
+
# @param nodes [Array<RFacter::Node>] An array of node objects to collect
|
27
|
+
# facts from.
|
28
|
+
def initialize(nodes, config: RFacter::Config.config, **opts)
|
29
|
+
@config = config
|
30
|
+
|
31
|
+
@collections = nodes.each_with_object({}) do |node, hash|
|
32
|
+
hash[node.id] = RFacter::Util::Collection.new(node)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Asynchronously fetch the value of a fact from each node
|
37
|
+
#
|
38
|
+
# This method spawns a background thread per node which resolves the value
|
39
|
+
# of a fact specified by `query`.
|
40
|
+
#
|
41
|
+
# @param queries [Array<String>] The names of the facts to fetch.
|
42
|
+
#
|
43
|
+
# @return [Concurrent::Future{String => Hash}]
|
44
|
+
# A future that will return a hash mapping the node id to a hash containing
|
45
|
+
# the resolved facts when `value` is called.
|
46
|
+
def fetch(queries)
|
47
|
+
queries = Array(queries)
|
48
|
+
# Spawn async lookups in the background for each node.
|
49
|
+
futures = @collections.each_with_object({}) do |(name, collection), hash|
|
50
|
+
hash[name] = {}
|
51
|
+
queries.each do |query|
|
52
|
+
hash[name][query] = collection.async.value(query)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return a future with the resolved values.
|
57
|
+
Concurrent::Future.execute do
|
58
|
+
futures.each_with_object({}) do |(name, ivars), hash|
|
59
|
+
hash[name] = ivars.each_with_object({}) do |(query, ivar), results|
|
60
|
+
# TODO: Add exception handling for failed futures.
|
61
|
+
results[query] = ivar.value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Fetch the value of a fact from each node
|
68
|
+
#
|
69
|
+
# This method calls {#fetch} and then blocks until the result is available.
|
70
|
+
#
|
71
|
+
# @return [Hash{String => Hash}]
|
72
|
+
# A hash mapping the node id to a hash containing the resolved facts.
|
73
|
+
def value(queries)
|
74
|
+
fetch(queries).value
|
75
|
+
end
|
76
|
+
|
77
|
+
# Asynchronously fetch all facts from each node
|
78
|
+
#
|
79
|
+
# This method spawns a background thread per node which resolves all
|
80
|
+
# fact values for each node.
|
81
|
+
#
|
82
|
+
# @return [Concurrent::Future{String => Hash}]
|
83
|
+
# A future that will return a hash mapping the node id to a hash containing
|
84
|
+
# the resolved facts when `value` is called.
|
85
|
+
def fetch_all
|
86
|
+
futures = @collections.each_with_object({}) do |(name, collection), hash|
|
87
|
+
collection.async.load_all
|
88
|
+
hash[name] = collection.async.to_hash
|
89
|
+
end
|
90
|
+
|
91
|
+
Concurrent::Future.execute do
|
92
|
+
futures.each_with_object({}) do |(name, future), hash|
|
93
|
+
# TODO: Add exception handling for failed futures.
|
94
|
+
hash[name] = future.value
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Fetch all facts from each node
|
100
|
+
#
|
101
|
+
# This method calls {#fetch_all} and then blocks until the result
|
102
|
+
# is available.
|
103
|
+
#
|
104
|
+
# @return [Hash{String => Hash}]
|
105
|
+
# A hash mapping the node id to a hash containing the resolved facts.
|
106
|
+
def to_hash
|
107
|
+
fetch_all.value
|
108
|
+
end
|
109
|
+
|
110
|
+
# Flush cached fact values
|
111
|
+
#
|
112
|
+
# @return [void]
|
113
|
+
def flush
|
114
|
+
@collections.values.each {|c| c.flush}
|
115
|
+
end
|
116
|
+
end
|
data/lib/rfacter/node.rb
CHANGED
@@ -13,6 +13,7 @@ require 'concurrent'
|
|
13
13
|
# @note This class should be refacter to provide an abstracted interface to
|
14
14
|
# different transport backends like Train, Vagrant, Chloride, etc.
|
15
15
|
#
|
16
|
+
# @api public
|
16
17
|
# @since 0.1.0
|
17
18
|
class RFacter::Node
|
18
19
|
extend Forwardable
|
@@ -34,10 +35,17 @@ class RFacter::Node
|
|
34
35
|
attr_reader :password
|
35
36
|
# @return [Hash]
|
36
37
|
attr_reader :options
|
38
|
+
# @return [String]
|
39
|
+
attr_reader :id
|
37
40
|
|
38
41
|
attr_reader :transport
|
39
42
|
|
40
|
-
|
43
|
+
# Returns a new instance of Node
|
44
|
+
#
|
45
|
+
# @param uri [URI] The URI of the node.
|
46
|
+
# @param id [String, nil] An optional string to use when identifying
|
47
|
+
# this node.
|
48
|
+
def initialize(uri, id: nil, config: RFacter::Config.config, **opts)
|
41
49
|
@config = config
|
42
50
|
|
43
51
|
@uri = unless uri.is_a?(URI)
|
@@ -67,6 +75,20 @@ class RFacter::Node
|
|
67
75
|
@options = @uri.query.nil? ? Hash.new : CGI.parse(@uri.query)
|
68
76
|
@options.update(opts)
|
69
77
|
|
78
|
+
@id = unless id.nil?
|
79
|
+
id
|
80
|
+
else
|
81
|
+
# Create a default from the URI, minus the password and options
|
82
|
+
# components.
|
83
|
+
id_string = "#{@scheme}://"
|
84
|
+
id_string += "#{@user}@" unless @user.nil?
|
85
|
+
id_string += @hostname
|
86
|
+
id_string += ":#{@port}" unless @port.nil?
|
87
|
+
id_string
|
88
|
+
end
|
89
|
+
|
90
|
+
@id.freeze
|
91
|
+
|
70
92
|
# TODO: This should be abstracted.
|
71
93
|
@transport = Train.create(@scheme,
|
72
94
|
host: @hostname,
|
@@ -135,3 +157,39 @@ class RFacter::Node
|
|
135
157
|
connection.file(path)
|
136
158
|
end
|
137
159
|
end
|
160
|
+
|
161
|
+
|
162
|
+
# Hello dear reader. Hiding at the bottom of this file is a consequence of bad
|
163
|
+
# design decisions in Ruby --- specifically the Kernel.autoload feature. Train
|
164
|
+
# uses autload to lazily require its subcomponents. However, autoload plays
|
165
|
+
# filthy tricks with the resolution of Constants that are not thread-safe. So,
|
166
|
+
# this chunk of code is sitting down here out of sight to force these autoloads
|
167
|
+
# to be resolved up front so that we can get on with the business of actually
|
168
|
+
# saving significant time by using parallelism.
|
169
|
+
#
|
170
|
+
# See:
|
171
|
+
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/41149
|
172
|
+
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/20238
|
173
|
+
#
|
174
|
+
# TODO: Remove if this PR lands:
|
175
|
+
# https://github.com/chef/train/pull/178
|
176
|
+
require 'train/plugins/transport'
|
177
|
+
require 'train/plugins/base_connection'
|
178
|
+
|
179
|
+
require 'train/transports/ssh'
|
180
|
+
require 'train/transports/ssh_connection'
|
181
|
+
require 'train/transports/winrm'
|
182
|
+
require 'train/transports/winrm_connection'
|
183
|
+
require 'train/transports/local'
|
184
|
+
require 'train/transports/local_file'
|
185
|
+
require 'train/transports/local_os'
|
186
|
+
|
187
|
+
require 'train/extras'
|
188
|
+
require 'train/extras/command_wrapper'
|
189
|
+
require 'train/extras/file_common'
|
190
|
+
require 'train/extras/file_unix'
|
191
|
+
require 'train/extras/file_aix'
|
192
|
+
require 'train/extras/file_linux'
|
193
|
+
require 'train/extras/file_windows'
|
194
|
+
require 'train/extras/os_common'
|
195
|
+
require 'train/extras/stat'
|
@@ -1,16 +1,22 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
|
+
require 'concurrent'
|
4
|
+
|
3
5
|
require 'rfacter'
|
4
6
|
require_relative '../config'
|
5
7
|
require_relative '../dsl'
|
6
8
|
require_relative 'loader'
|
7
9
|
require_relative 'fact'
|
8
10
|
|
9
|
-
# Manage which facts exist and how we access them.
|
10
|
-
#
|
11
|
+
# Manage which facts exist on a Node and how we access them.
|
12
|
+
#
|
13
|
+
# Largely just a wrapper around a hash of facts that have been retrieved from a
|
14
|
+
# particular node.
|
11
15
|
#
|
12
16
|
# @api private
|
17
|
+
# @since 0.1.0
|
13
18
|
class RFacter::Util::Collection
|
19
|
+
include Concurrent::Async
|
14
20
|
# Ensures unqualified namespaces like `Facter` and `Facter::Util` get
|
15
21
|
# re-directed to RFacter shims when the loader calls `instance_eval`
|
16
22
|
include RFacter::DSL
|
@@ -18,15 +24,21 @@ class RFacter::Util::Collection
|
|
18
24
|
|
19
25
|
instance_delegate([:logger] => :@config)
|
20
26
|
|
21
|
-
|
27
|
+
# Initialize a new Collection object
|
28
|
+
#
|
29
|
+
# @param node [RFacter::Node] The node from which this collection
|
30
|
+
# should retrieve facts.
|
31
|
+
def initialize(node, config: RFacter::Config.config, **opts)
|
32
|
+
@node = node
|
22
33
|
@config = config
|
34
|
+
|
23
35
|
@facts = Hash.new
|
24
36
|
@internal_loader = RFacter::Util::Loader.new
|
25
37
|
end
|
26
38
|
|
27
39
|
# Return a fact object by name.
|
28
|
-
def [](name
|
29
|
-
value(name
|
40
|
+
def [](name)
|
41
|
+
value(name)
|
30
42
|
end
|
31
43
|
|
32
44
|
# Define a new fact or extend an existing fact.
|
@@ -34,7 +46,7 @@ class RFacter::Util::Collection
|
|
34
46
|
# @param name [Symbol] The name of the fact to define
|
35
47
|
# @param options [Hash] A hash of options to set on the fact
|
36
48
|
#
|
37
|
-
# @return [
|
49
|
+
# @return [RFacter::Util::Fact] The fact that was defined
|
38
50
|
def define_fact(name, options = {}, &block)
|
39
51
|
fact = create_or_return_fact(name, options)
|
40
52
|
|
@@ -53,7 +65,7 @@ class RFacter::Util::Collection
|
|
53
65
|
# @param name [Symbol] The name of the fact to define
|
54
66
|
# @param options [Hash] A hash of options to set on the fact and resolution
|
55
67
|
#
|
56
|
-
# @return [
|
68
|
+
# @return [RFacter::Util::Fact] The fact that was defined
|
57
69
|
def add(name, options = {}, &block)
|
58
70
|
fact = create_or_return_fact(name, options)
|
59
71
|
|
@@ -65,11 +77,11 @@ class RFacter::Util::Collection
|
|
65
77
|
include Enumerable
|
66
78
|
|
67
79
|
# Iterate across all of the facts.
|
68
|
-
def each
|
80
|
+
def each
|
69
81
|
load_all
|
70
82
|
|
71
|
-
|
72
|
-
|
83
|
+
COLLECTION.bind(self) do
|
84
|
+
NODE.bind(@node) do
|
73
85
|
@facts.each do |name, fact|
|
74
86
|
value = fact.value
|
75
87
|
unless value.nil?
|
@@ -118,24 +130,22 @@ class RFacter::Util::Collection
|
|
118
130
|
end
|
119
131
|
|
120
132
|
# Return a hash of all of our facts.
|
121
|
-
def to_hash
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
133
|
+
def to_hash
|
134
|
+
COLLECTION.bind(self) do
|
135
|
+
NODE.bind(@node) do
|
136
|
+
@facts.each_with_object({}) do |(name, fact), hash|
|
137
|
+
resolved_value = fact.value
|
138
|
+
|
139
|
+
# For backwards compatibility, convert the fact name to a string.
|
140
|
+
hash[name.to_s] = resolved_value unless resolved_value.nil?
|
126
141
|
end
|
127
142
|
end
|
128
|
-
|
129
|
-
# For backwards compatibility, convert the fact name to a string.
|
130
|
-
h[ary[0].to_s] = resolved_value unless resolved_value.nil?
|
131
|
-
|
132
|
-
h
|
133
143
|
end
|
134
144
|
end
|
135
145
|
|
136
|
-
def value(name
|
137
|
-
|
138
|
-
|
146
|
+
def value(name)
|
147
|
+
COLLECTION.bind(self) do
|
148
|
+
NODE.bind(@node) do
|
139
149
|
if fact = fact(name)
|
140
150
|
fact.value
|
141
151
|
end
|
@@ -153,8 +163,6 @@ class RFacter::Util::Collection
|
|
153
163
|
if fact.nil?
|
154
164
|
fact = RFacter::Util::Fact.new(name, options)
|
155
165
|
@facts[name] = fact
|
156
|
-
else
|
157
|
-
fact.extract_ldapname_option!(options)
|
158
166
|
end
|
159
167
|
|
160
168
|
fact
|
data/lib/rfacter/util/confine.rb
CHANGED
data/lib/rfacter/util/fact.rb
CHANGED
@@ -4,11 +4,12 @@ require 'rfacter'
|
|
4
4
|
require_relative '../config'
|
5
5
|
|
6
6
|
# This class represents a fact. Each fact has a name and multiple
|
7
|
-
# {
|
7
|
+
# {RFacter::Util::Resolution resolutions}.
|
8
8
|
#
|
9
|
-
# Create facts using {Facter.add}
|
9
|
+
# Create facts using {RFacter::DSL::Facter.add Facter.add}
|
10
10
|
#
|
11
|
-
# @api
|
11
|
+
# @api private
|
12
|
+
# @since 0.1.0
|
12
13
|
class RFacter::Util::Fact
|
13
14
|
require_relative '../core/aggregate'
|
14
15
|
require_relative 'resolution'
|
@@ -21,40 +22,27 @@ class RFacter::Util::Fact
|
|
21
22
|
# @return [String]
|
22
23
|
attr_accessor :name
|
23
24
|
|
24
|
-
#
|
25
|
-
# @deprecated
|
26
|
-
attr_accessor :ldapname
|
27
|
-
|
28
|
-
# Creates a new fact, with no resolution mechanisms. See {Facter.add}
|
25
|
+
# Creates a new fact, with no resolution mechanisms. See {RFacter::DSL::Facter.add}
|
29
26
|
# for the public API for creating facts.
|
30
27
|
# @param name [String] the fact name
|
31
28
|
# @param options [Hash] optional parameters
|
32
|
-
# @option options [String] :ldapname set the ldapname property on the fact
|
33
|
-
#
|
34
|
-
# @api private
|
35
29
|
def initialize(name, config: RFacter::Config.config, **options)
|
36
30
|
@name = name.to_s.downcase.intern
|
37
31
|
@config = config
|
38
32
|
|
39
|
-
extract_ldapname_option!(options)
|
40
|
-
|
41
|
-
@ldapname ||= @name.to_s
|
42
|
-
|
43
33
|
@resolves = []
|
44
34
|
@searching = false
|
45
35
|
|
46
36
|
@value = nil
|
47
37
|
end
|
48
38
|
|
49
|
-
# Adds a new {
|
39
|
+
# Adds a new {RFacter::Util::Resolution resolution}. This requires a
|
50
40
|
# block, which will then be evaluated in the context of the new
|
51
41
|
# resolution.
|
52
42
|
#
|
53
43
|
# @param options [Hash] A hash of options to set on the resolution
|
54
44
|
#
|
55
|
-
# @return [
|
56
|
-
#
|
57
|
-
# @api private
|
45
|
+
# @return [RFacter::Util::Resolution]
|
58
46
|
def add(options = {}, &block)
|
59
47
|
define_resolution(nil, options, &block)
|
60
48
|
end
|
@@ -64,9 +52,7 @@ class RFacter::Util::Fact
|
|
64
52
|
#
|
65
53
|
# @param resolution_name [String] The name of the resolve to define or look up
|
66
54
|
# @param options [Hash] A hash of options to set on the resolution
|
67
|
-
# @return [
|
68
|
-
#
|
69
|
-
# @api public
|
55
|
+
# @return [RFacter::Util::Resolution]
|
70
56
|
def define_resolution(resolution_name, options = {}, &block)
|
71
57
|
|
72
58
|
resolution_type = options.delete(:type) || :simple
|
@@ -85,7 +71,7 @@ class RFacter::Util::Fact
|
|
85
71
|
#
|
86
72
|
# @param name [String]
|
87
73
|
#
|
88
|
-
# @return [
|
74
|
+
# @return [RFacter::Util::Resolution, nil] The resolution if exists, nil if
|
89
75
|
# it doesn't exist or name is nil
|
90
76
|
def resolution(name)
|
91
77
|
return nil if name.nil?
|
@@ -96,18 +82,14 @@ class RFacter::Util::Fact
|
|
96
82
|
# Flushes any cached values.
|
97
83
|
#
|
98
84
|
# @return [void]
|
99
|
-
#
|
100
|
-
# @api private
|
101
85
|
def flush
|
102
86
|
@resolves.each { |r| r.flush }
|
103
87
|
@value = nil
|
104
88
|
end
|
105
89
|
|
106
90
|
# Returns the value for this fact. This searches all resolutions by
|
107
|
-
# suitability and weight (see {
|
91
|
+
# suitability and weight (see {RFacter::Util::Resolution}). If no
|
108
92
|
# suitable resolution is found, it returns nil.
|
109
|
-
#
|
110
|
-
# @api public
|
111
93
|
def value
|
112
94
|
return @value if @value
|
113
95
|
|
@@ -128,15 +110,6 @@ class RFacter::Util::Fact
|
|
128
110
|
end
|
129
111
|
end
|
130
112
|
|
131
|
-
# @api private
|
132
|
-
# @deprecated
|
133
|
-
def extract_ldapname_option!(options)
|
134
|
-
if options[:ldapname]
|
135
|
-
logger.warnonce("ldapname is deprecated and will be removed in a future version")
|
136
|
-
self.ldapname = options.delete(:ldapname)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
113
|
private
|
141
114
|
|
142
115
|
# Are we in the midst of a search?
|
data/lib/rfacter/util/loader.rb
CHANGED
@@ -8,6 +8,7 @@ require_relative '../dsl'
|
|
8
8
|
# Load facts on demand.
|
9
9
|
#
|
10
10
|
# @api private
|
11
|
+
# @since 0.1.0
|
11
12
|
class RFacter::Util::Loader
|
12
13
|
extend Forwardable
|
13
14
|
|
@@ -20,7 +21,6 @@ class RFacter::Util::Loader
|
|
20
21
|
|
21
22
|
# Load all resolutions for a single fact.
|
22
23
|
#
|
23
|
-
# @api public
|
24
24
|
# @param fact [Symbol]
|
25
25
|
def load(fact, collection)
|
26
26
|
# Now load from the search path
|
@@ -40,8 +40,6 @@ class RFacter::Util::Loader
|
|
40
40
|
end
|
41
41
|
|
42
42
|
# Load all facts from all directories.
|
43
|
-
#
|
44
|
-
# @api public
|
45
43
|
def load_all(collection)
|
46
44
|
return if defined?(@loaded_all)
|
47
45
|
|
@@ -69,7 +67,6 @@ class RFacter::Util::Loader
|
|
69
67
|
# A warning will be generated for paths that are not
|
70
68
|
# absolute directories.
|
71
69
|
#
|
72
|
-
# @api public
|
73
70
|
# @return [Array<String>]
|
74
71
|
def search_path
|
75
72
|
search_paths = [File.expand_path('../../facts', __FILE__)]
|
data/lib/rfacter/util/logger.rb
CHANGED
@@ -8,6 +8,7 @@ require 'rfacter'
|
|
8
8
|
# if de-referenced to `nil`. This allows the creation of variables
|
9
9
|
# that must always be bound to a specific value before use.
|
10
10
|
#
|
11
|
+
# @api private
|
11
12
|
# @since 0.1.0
|
12
13
|
class RFacter::Util::NonNullable < Concurrent::ThreadLocalVar
|
13
14
|
# @param err_message [String] The error message to raise if
|
@@ -1,5 +1,9 @@
|
|
1
1
|
require 'rfacter'
|
2
2
|
|
3
|
+
# Routines for normalizing fact return values
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
# @since 0.1.0
|
3
7
|
module RFacter
|
4
8
|
module Util
|
5
9
|
module Normalization
|
@@ -11,7 +15,6 @@ module RFacter
|
|
11
15
|
|
12
16
|
# Recursively normalize the given data structure
|
13
17
|
#
|
14
|
-
# @api public
|
15
18
|
# @raise [NormalizationError] If the data structure contained an invalid element.
|
16
19
|
# @return [void]
|
17
20
|
def normalize(value)
|
@@ -33,46 +36,27 @@ module RFacter
|
|
33
36
|
#
|
34
37
|
# Attempt to normalize and validate the given string.
|
35
38
|
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
+
# The string is validate by checking that the string encoding is UTF-8
|
40
|
+
# and that the string content matches the encoding. If the string is not
|
41
|
+
# an expected encoding then it is converted to UTF-8.
|
39
42
|
#
|
40
|
-
# On Ruby 1.9+, the string is validate by checking that the string encoding
|
41
|
-
# is UTF-8 and that the string content matches the encoding. If the string
|
42
|
-
# is not an expected encoding then it is converted to UTF-8.
|
43
|
-
#
|
44
|
-
# @api public
|
45
43
|
# @raise [NormalizationError] If the string used an unsupported encoding or did not match its encoding
|
46
44
|
# @param value [String]
|
47
45
|
# @return [void]
|
46
|
+
def normalize_string(value)
|
47
|
+
value = value.encode(Encoding::UTF_8)
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
def normalize_string(value)
|
53
|
-
converted = Iconv.conv('UTF-8//IGNORE', 'UTF-8', value)
|
54
|
-
if converted != value
|
55
|
-
raise NormalizationError, "String #{value.inspect} is not valid UTF-8"
|
56
|
-
end
|
57
|
-
value
|
49
|
+
unless value.valid_encoding?
|
50
|
+
raise NormalizationError, "String #{value.inspect} doesn't match the reported encoding #{value.encoding}"
|
58
51
|
end
|
59
|
-
else
|
60
|
-
def normalize_string(value)
|
61
|
-
value = value.encode(Encoding::UTF_8)
|
62
52
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
value
|
68
|
-
rescue EncodingError
|
69
|
-
raise NormalizationError, "String encoding #{value.encoding} is not UTF-8 and could not be converted to UTF-8"
|
70
|
-
end
|
53
|
+
value
|
54
|
+
rescue EncodingError
|
55
|
+
raise NormalizationError, "String encoding #{value.encoding} is not UTF-8 and could not be converted to UTF-8"
|
71
56
|
end
|
72
57
|
|
73
58
|
# Validate all elements of the array.
|
74
59
|
#
|
75
|
-
# @api public
|
76
60
|
# @raise [NormalizationError] If one of the elements failed validation
|
77
61
|
# @param value [Array]
|
78
62
|
# @return [void]
|
@@ -84,7 +68,6 @@ module RFacter
|
|
84
68
|
|
85
69
|
# Validate all keys and values of the hash.
|
86
70
|
#
|
87
|
-
# @api public
|
88
71
|
# @raise [NormalizationError] If one of the keys or values failed normalization
|
89
72
|
# @param value [Hash]
|
90
73
|
# @return [void]
|
@@ -6,14 +6,15 @@ require_relative '../config'
|
|
6
6
|
# This represents a fact resolution. A resolution is a concrete
|
7
7
|
# implementation of a fact. A single fact can have many resolutions and
|
8
8
|
# the correct resolution will be chosen at runtime. Each time
|
9
|
-
# {Facter.add} is called, a new resolution is created
|
10
|
-
# set of resolutions for the fact named in the call. Each
|
11
|
-
# has a {#has_weight weight}, which defines its priority over other
|
9
|
+
# {RFacter::DSL::Facter.add Facter.add} is called, a new resolution is created
|
10
|
+
# and added to the set of resolutions for the fact named in the call. Each
|
11
|
+
# resolution has a {#has_weight weight}, which defines its priority over other
|
12
12
|
# resolutions, and a set of {#confine _confinements_}, which defines the
|
13
|
-
# conditions under which it will be chosen. All confinements must be
|
14
|
-
#
|
13
|
+
# conditions under which it will be chosen. All confinements must be satisfied
|
14
|
+
# for a fact to be considered _suitable_.
|
15
15
|
#
|
16
|
-
# @api
|
16
|
+
# @api private
|
17
|
+
# @since 0.1.0
|
17
18
|
class RFacter::Util::Resolution
|
18
19
|
require_relative '../dsl'
|
19
20
|
require_relative '../core/resolvable'
|
@@ -22,7 +23,6 @@ class RFacter::Util::Resolution
|
|
22
23
|
|
23
24
|
instance_delegate([:logger] => :@config)
|
24
25
|
|
25
|
-
# @api private
|
26
26
|
attr_accessor :code
|
27
27
|
attr_writer :value
|
28
28
|
|
@@ -33,12 +33,10 @@ class RFacter::Util::Resolution
|
|
33
33
|
# The name of this resolution. The resolution name should be unique with
|
34
34
|
# respect to the given fact.
|
35
35
|
# @return [String]
|
36
|
-
# @api public
|
37
36
|
attr_accessor :name
|
38
37
|
|
39
38
|
# @!attribute [r] fact
|
40
|
-
# @return [
|
41
|
-
# @api private
|
39
|
+
# @return [RFacter::Util::Fact]
|
42
40
|
attr_reader :fact
|
43
41
|
|
44
42
|
def which(command)
|
@@ -53,8 +51,6 @@ class RFacter::Util::Resolution
|
|
53
51
|
#
|
54
52
|
# @param name [String] The name of the resolution.
|
55
53
|
# @return [void]
|
56
|
-
#
|
57
|
-
# @api private
|
58
54
|
def initialize(name, fact, config: RFacter::Config.config, **options)
|
59
55
|
@name = name
|
60
56
|
@fact = fact
|
@@ -83,14 +79,7 @@ class RFacter::Util::Resolution
|
|
83
79
|
|
84
80
|
instance_eval(&block)
|
85
81
|
|
86
|
-
|
87
|
-
# debugging information if a resolution is being evaluated twice. Since 1.8
|
88
|
-
# doesn't support this we opportunistically provide this information.
|
89
|
-
if block.respond_to? :source_location
|
90
|
-
@last_evaluated = block.source_location.join(':')
|
91
|
-
else
|
92
|
-
@last_evaluated = true
|
93
|
-
end
|
82
|
+
@last_evaluated = block.source_location.join(':')
|
94
83
|
end
|
95
84
|
|
96
85
|
def set_options(options)
|
@@ -130,8 +119,6 @@ class RFacter::Util::Resolution
|
|
130
119
|
# @param [Proc] block The block to determine the resolution's value.
|
131
120
|
# This block is run when the fact is evaluated. Errors raised from
|
132
121
|
# inside the block are rescued and printed to stderr.
|
133
|
-
#
|
134
|
-
# @api public
|
135
122
|
def setcode(string = nil, &block)
|
136
123
|
if string
|
137
124
|
@code = Proc.new do
|
data/lib/rfacter/util/values.rb
CHANGED
data/lib/rfacter/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rfacter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Sharpsteen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-05-
|
12
|
+
date: 2017-05-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: train
|
@@ -40,19 +40,19 @@ dependencies:
|
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '1.0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
43
|
+
name: rake
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '0
|
48
|
+
version: '12.0'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '0
|
55
|
+
version: '12.0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rspec
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,6 +67,20 @@ dependencies:
|
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '3.1'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: yard
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0.9'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0.9'
|
70
84
|
description: |
|
71
85
|
RFacter is a library for collecting facts from remote system(s) by executing
|
72
86
|
commands over transports such as SSH and WinRM.
|
@@ -92,6 +106,7 @@ files:
|
|
92
106
|
- lib/rfacter/facts/kernelversion.rb
|
93
107
|
- lib/rfacter/facts/networking.rb
|
94
108
|
- lib/rfacter/facts/os.rb
|
109
|
+
- lib/rfacter/factset.rb
|
95
110
|
- lib/rfacter/node.rb
|
96
111
|
- lib/rfacter/util/collection.rb
|
97
112
|
- lib/rfacter/util/confine.rb
|