facter 1.6.18 → 1.7.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of facter might be problematic. Click here for more details.
- data/Gemfile +23 -8
- data/bin/facter +4 -1
- data/ext/build_defaults.yaml +1 -1
- data/ext/debian/changelog.erb +4 -22
- data/ext/debian/control +2 -2
- data/ext/project_data.yaml +1 -1
- data/ext/redhat/facter.spec.erb +10 -9
- data/install.rb +27 -53
- data/lib/facter.rb +23 -5
- data/lib/facter/application.rb +21 -0
- data/lib/facter/blockdevices.rb +105 -0
- data/lib/facter/domain.rb +19 -7
- data/lib/facter/filesystems.rb +38 -0
- data/lib/facter/hardwaremodel.rb +3 -2
- data/lib/facter/ipaddress6.rb +1 -2
- data/lib/facter/kernelrelease.rb +10 -2
- data/lib/facter/ldom.rb +47 -0
- data/lib/facter/macaddress.rb +1 -1
- data/lib/facter/manufacturer.rb +7 -1
- data/lib/facter/memory.rb +58 -160
- data/lib/facter/operatingsystem.rb +17 -2
- data/lib/facter/operatingsystemmajrelease.rb +33 -0
- data/lib/facter/operatingsystemrelease.rb +88 -37
- data/lib/facter/osfamily.rb +6 -2
- data/lib/facter/processor.rb +2 -2
- data/lib/facter/ps.rb +5 -0
- data/lib/facter/ssh.rb +50 -12
- data/lib/facter/util/cfpropertylist.rb +6 -0
- data/lib/facter/util/cfpropertylist/LICENSE +19 -0
- data/lib/facter/util/cfpropertylist/README +44 -0
- data/lib/facter/util/cfpropertylist/Rakefile +44 -0
- data/lib/facter/util/cfpropertylist/THANKS +7 -0
- data/lib/facter/util/cfpropertylist/lib/cfpropertylist.rb +6 -0
- data/lib/facter/util/cfpropertylist/lib/rbBinaryCFPropertyList.rb +562 -0
- data/lib/facter/util/cfpropertylist/lib/rbCFPlistError.rb +26 -0
- data/lib/facter/util/cfpropertylist/lib/rbCFPropertyList.rb +402 -0
- data/lib/facter/util/cfpropertylist/lib/rbCFTypes.rb +244 -0
- data/lib/facter/util/cfpropertylist/lib/rbLibXMLParser.rb +135 -0
- data/lib/facter/util/cfpropertylist/lib/rbNokogiriParser.rb +140 -0
- data/lib/facter/util/cfpropertylist/lib/rbREXMLParser.rb +136 -0
- data/lib/facter/util/collection.rb +36 -14
- data/lib/facter/util/composite_loader.rb +12 -0
- data/lib/facter/util/config.rb +36 -0
- data/lib/facter/util/confine.rb +1 -6
- data/lib/facter/util/directory_loader.rb +83 -0
- data/lib/facter/util/fact.rb +49 -42
- data/lib/facter/util/file_read.rb +32 -0
- data/lib/facter/util/ip.rb +2 -9
- data/lib/facter/util/loader.rb +16 -2
- data/lib/facter/util/macosx.rb +15 -2
- data/lib/facter/util/memory.rb +154 -27
- data/lib/facter/util/nothing_loader.rb +15 -0
- data/lib/facter/util/parser.rb +141 -0
- data/lib/facter/util/processor.rb +27 -35
- data/lib/facter/util/resolution.rb +97 -26
- data/lib/facter/util/solaris_zones.rb +153 -0
- data/lib/facter/util/virtual.rb +32 -3
- data/lib/facter/version.rb +72 -2
- data/lib/facter/virtual.rb +56 -3
- data/lib/facter/zfs_version.rb +10 -0
- data/lib/facter/zonename.rb +6 -0
- data/lib/facter/zones.rb +17 -0
- data/lib/facter/zpool_version.rb +10 -0
- data/spec/fixtures/ifconfig/ifconfig_net_tools_1.60.txt +19 -0
- data/spec/fixtures/ifconfig/ifconfig_ubuntu_1204.txt +16 -0
- data/spec/fixtures/ldom/ldom_v1 +6 -0
- data/spec/fixtures/unit/filesystems/linux +28 -0
- data/spec/fixtures/unit/util/manufacturer/intel_linux_dmidecode +549 -0
- data/spec/fixtures/unit/virtual/sysfs_dmi_entries_raw.txt +0 -0
- data/spec/fixtures/unit/zfs_version/freebsd_8.2 +14 -0
- data/spec/fixtures/unit/zfs_version/freebsd_9.0 +13 -0
- data/spec/fixtures/unit/zfs_version/linux-fuse_0.6.9 +14 -0
- data/spec/fixtures/unit/zfs_version/solaris_10 +10 -0
- data/spec/fixtures/unit/zfs_version/solaris_11 +12 -0
- data/spec/fixtures/unit/zpool_version/freebsd_8.2 +26 -0
- data/spec/fixtures/unit/zpool_version/freebsd_9.0 +38 -0
- data/spec/fixtures/unit/zpool_version/linux-fuse_0.6.9 +35 -0
- data/spec/fixtures/unit/zpool_version/solaris_10 +31 -0
- data/spec/fixtures/unit/zpool_version/solaris_11 +43 -0
- data/spec/integration/facter_spec.rb +12 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/unit/architecture_spec.rb +1 -1
- data/spec/unit/blockdevices_spec.rb +109 -0
- data/spec/unit/domain_spec.rb +189 -81
- data/spec/unit/ec2_spec.rb +15 -8
- data/spec/unit/filesystems_spec.rb +50 -0
- data/spec/unit/hardwaremodel_spec.rb +8 -1
- data/spec/unit/id_spec.rb +6 -5
- data/spec/unit/ipaddress6_spec.rb +14 -2
- data/spec/unit/ipaddress_spec.rb +1 -1
- data/spec/unit/kernel_spec.rb +24 -0
- data/spec/unit/kernelmajversion_spec.rb +17 -0
- data/spec/unit/kernelrelease_spec.rb +53 -0
- data/spec/unit/kernelversion_spec.rb +32 -0
- data/spec/unit/ldom_spec.rb +74 -0
- data/spec/unit/macaddress_spec.rb +3 -1
- data/spec/unit/manufacturer_spec.rb +115 -0
- data/spec/unit/memory_spec.rb +442 -75
- data/spec/unit/operatingsystem_spec.rb +16 -2
- data/spec/unit/operatingsystemmajrelease_spec.rb +16 -0
- data/spec/unit/operatingsystemrelease_spec.rb +110 -1
- data/spec/unit/processor_spec.rb +22 -7
- data/spec/unit/ps_spec.rb +42 -0
- data/spec/unit/ssh_spec.rb +76 -0
- data/spec/unit/util/collection_spec.rb +94 -118
- data/spec/unit/util/config_spec.rb +36 -5
- data/spec/unit/util/confine_spec.rb +31 -43
- data/spec/unit/util/directory_loader_spec.rb +87 -0
- data/spec/unit/util/fact_spec.rb +37 -25
- data/spec/unit/util/file_read_spec.rb +29 -0
- data/spec/unit/util/ip_spec.rb +4 -2
- data/spec/unit/util/loader_spec.rb +102 -45
- data/spec/unit/util/macosx_spec.rb +40 -9
- data/spec/unit/util/manufacturer_spec.rb +12 -1
- data/spec/unit/util/parser_spec.rb +135 -0
- data/spec/unit/util/resolution_spec.rb +136 -4
- data/spec/unit/util/solaris_zones_spec.rb +127 -0
- data/spec/unit/util/virtual_spec.rb +54 -0
- data/spec/unit/version_spec.rb +42 -0
- data/spec/unit/virtual_spec.rb +102 -27
- data/spec/unit/zfs_version_spec.rb +76 -0
- data/spec/unit/zonename_spec.rb +14 -0
- data/spec/unit/zones_spec.rb +55 -0
- data/spec/unit/zpool_version_spec.rb +76 -0
- metadata +113 -11
- data/lib/facter/arp.rb +0 -28
@@ -0,0 +1,141 @@
|
|
1
|
+
# This class acts as the factory and parent class for parsed
|
2
|
+
# facts such as scripts, text, json and yaml files.
|
3
|
+
#
|
4
|
+
# Parsers must subclass this class and provide their own #results method.
|
5
|
+
require 'facter'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
module Facter::Util::Parser
|
9
|
+
@parsers = []
|
10
|
+
|
11
|
+
# For support mutliple extensions you can pass an array of extensions as
|
12
|
+
# +ext+.
|
13
|
+
def self.extension_matches?(filename, ext)
|
14
|
+
extension = case ext
|
15
|
+
when String
|
16
|
+
ext.downcase
|
17
|
+
when Enumerable
|
18
|
+
ext.collect {|x| x.downcase }
|
19
|
+
end
|
20
|
+
[extension].flatten.to_a.include?(file_extension(filename).downcase)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.file_extension(filename)
|
24
|
+
File.extname(filename).sub(".", '')
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.register(klass, &suitable)
|
28
|
+
@parsers << [klass, suitable]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parser_for(filename)
|
32
|
+
registration = @parsers.detect { |k| k[1].call(filename) }
|
33
|
+
|
34
|
+
if registration.nil?
|
35
|
+
NothingParser.new
|
36
|
+
else
|
37
|
+
registration[0].new(filename)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Base
|
42
|
+
attr_reader :filename
|
43
|
+
|
44
|
+
def initialize(filename, content = nil)
|
45
|
+
@filename = filename
|
46
|
+
@content = content
|
47
|
+
end
|
48
|
+
|
49
|
+
def content
|
50
|
+
@content ||= File.read(filename)
|
51
|
+
end
|
52
|
+
|
53
|
+
# results on the base class is really meant to be just an exception handler
|
54
|
+
# wrapper.
|
55
|
+
def results
|
56
|
+
parse_results
|
57
|
+
rescue Exception => detail
|
58
|
+
Facter.warn("Failed to handle #{filename} as #{self.class} facts")
|
59
|
+
Facter.warn("detail: #{detail.class}: #{detail.message}")
|
60
|
+
Facter.debug(detail.backtrace.join("\n\t"))
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_results
|
65
|
+
raise ArgumentError, "Subclasses must respond to parse_results"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class YamlParser < Base
|
70
|
+
def parse_results
|
71
|
+
YAML.load(content)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
register(YamlParser) do |filename|
|
76
|
+
extension_matches?(filename, "yaml")
|
77
|
+
end
|
78
|
+
|
79
|
+
class TextParser < Base
|
80
|
+
def parse_results
|
81
|
+
re = /^(.+?)=(.+)$/
|
82
|
+
result = {}
|
83
|
+
content.each_line do |line|
|
84
|
+
if match_data = re.match(line.chomp)
|
85
|
+
result[match_data[1]] = match_data[2]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
result
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
register(TextParser) do |filename|
|
93
|
+
extension_matches?(filename, "txt")
|
94
|
+
end
|
95
|
+
|
96
|
+
class JsonParser < Base
|
97
|
+
def results
|
98
|
+
if Facter.json?
|
99
|
+
JSON.load(content)
|
100
|
+
else
|
101
|
+
Facter.warnonce "Cannot parse JSON data file #{filename} without the json library."
|
102
|
+
Facter.warnonce "Suggested next step is `gem install json` to install the json library."
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
register(JsonParser) do |filename|
|
109
|
+
extension_matches?(filename, "json")
|
110
|
+
end
|
111
|
+
|
112
|
+
class ScriptParser < Base
|
113
|
+
def results
|
114
|
+
output = Facter::Util::Resolution.exec(filename)
|
115
|
+
|
116
|
+
result = {}
|
117
|
+
re = /^(.+)=(.+)$/
|
118
|
+
output.each_line do |line|
|
119
|
+
if match_data = re.match(line.chomp)
|
120
|
+
result[match_data[1]] = match_data[2]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
result
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
register(ScriptParser) do |filename|
|
128
|
+
if not Facter::Util::Config.is_windows?
|
129
|
+
File.executable?(filename) && File.file?(filename)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# A parser that is used when there is no other parser that can handle the file
|
135
|
+
# The return from results indicates to the caller the file was not parsed correctly.
|
136
|
+
class NothingParser
|
137
|
+
def results
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -218,55 +218,47 @@ module Processor
|
|
218
218
|
model = Facter.value(:architecture)
|
219
219
|
case model
|
220
220
|
when "x86_64", "amd64", "i386", "x86", /parisc/, "hppa", "ia64"
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
processor_list[processor_num] = $2 unless processor_num == -1
|
231
|
-
end
|
221
|
+
File.readlines(cpuinfo).each do |l|
|
222
|
+
if l =~ /processor\s+:\s+(\d+)/
|
223
|
+
processor_num = $1.to_i
|
224
|
+
elsif l =~ /model name\s+:\s+(.*)\s*$/
|
225
|
+
processor_list[processor_num] = $1 unless processor_num == -1
|
226
|
+
processor_num = -1
|
227
|
+
elsif l =~ /processor\s+(\d+):\s+(.*)/
|
228
|
+
processor_num = $1.to_i
|
229
|
+
processor_list[processor_num] = $2 unless processor_num == -1
|
232
230
|
end
|
233
231
|
end
|
234
232
|
|
235
233
|
when "ppc64"
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
processor_num = -1
|
243
|
-
end
|
234
|
+
File.readlines(cpuinfo).each do |l|
|
235
|
+
if l =~ /processor\s+:\s+(\d+)/
|
236
|
+
processor_num = $1.to_i
|
237
|
+
elsif l =~ /cpu\s+:\s+(.*)\s*$/
|
238
|
+
processor_list[processor_num] = $1 unless processor_num == -1
|
239
|
+
processor_num = -1
|
244
240
|
end
|
245
241
|
end
|
246
242
|
|
247
243
|
when /arm/
|
248
|
-
|
249
|
-
|
250
|
-
|
244
|
+
File.readlines(cpuinfo).each do |l|
|
245
|
+
if l =~ /Processor\s+:\s+(.+)/
|
246
|
+
processor_num += 1
|
247
|
+
processor_list[processor_num] = $1.chomp
|
248
|
+
elsif l =~ /processor\s+:\s+(\d+)\s*$/
|
249
|
+
proc_num = $1.to_i
|
250
|
+
if proc_num != 0
|
251
251
|
processor_num += 1
|
252
|
-
processor_list[processor_num] =
|
253
|
-
elsif l =~ /processor\s+:\s+(\d+)\s*$/
|
254
|
-
proc_num = $1.to_i
|
255
|
-
if proc_num != 0
|
256
|
-
processor_num += 1
|
257
|
-
processor_list[processor_num] = processor_list[processor_num-1]
|
258
|
-
end
|
252
|
+
processor_list[processor_num] = processor_list[processor_num-1]
|
259
253
|
end
|
260
254
|
end
|
261
255
|
end
|
262
256
|
|
263
257
|
when /sparc/
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
processor_list[processor_num] = $1
|
269
|
-
end
|
258
|
+
File.readlines(cpuinfo).each do |l|
|
259
|
+
if l =~ /cpu\s+:\s+(.*)\s*$/
|
260
|
+
processor_num += 1
|
261
|
+
processor_list[processor_num] = $1
|
270
262
|
end
|
271
263
|
end
|
272
264
|
end
|
@@ -10,6 +10,7 @@ require 'timeout'
|
|
10
10
|
|
11
11
|
class Facter::Util::Resolution
|
12
12
|
attr_accessor :interpreter, :code, :name, :timeout
|
13
|
+
attr_writer :value, :weight
|
13
14
|
|
14
15
|
INTERPRETER = Facter::Util::Config.is_windows? ? "cmd.exe" : "/bin/sh"
|
15
16
|
|
@@ -108,6 +109,39 @@ class Facter::Util::Resolution
|
|
108
109
|
end
|
109
110
|
end
|
110
111
|
|
112
|
+
#
|
113
|
+
# Call this method with a block of code for which you would like to temporarily modify
|
114
|
+
# one or more environment variables; the specified values will be set for the duration
|
115
|
+
# of your block, after which the original values (if any) will be restored.
|
116
|
+
#
|
117
|
+
# [values] a Hash containing the key/value pairs of any environment variables that you
|
118
|
+
# would like to temporarily override
|
119
|
+
def self.with_env(values)
|
120
|
+
old = {}
|
121
|
+
values.each do |var, value|
|
122
|
+
# save the old value if it exists
|
123
|
+
if old_val = ENV[var]
|
124
|
+
old[var] = old_val
|
125
|
+
end
|
126
|
+
# set the new (temporary) value for the environment variable
|
127
|
+
ENV[var] = value
|
128
|
+
end
|
129
|
+
# execute the caller's block, capture the return value
|
130
|
+
rv = yield
|
131
|
+
# use an ensure block to make absolutely sure we restore the variables
|
132
|
+
ensure
|
133
|
+
# restore the old values
|
134
|
+
values.each do |var, value|
|
135
|
+
if old.include?(var)
|
136
|
+
ENV[var] = old[var]
|
137
|
+
else
|
138
|
+
# if there was no old value, delete the key from the current environment variables hash
|
139
|
+
ENV.delete(var)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
# return the captured return value
|
143
|
+
rv
|
144
|
+
end
|
111
145
|
|
112
146
|
# Execute a program and return the output of that program.
|
113
147
|
#
|
@@ -117,33 +151,38 @@ class Facter::Util::Resolution
|
|
117
151
|
def self.exec(code, interpreter = nil)
|
118
152
|
Facter.warnonce "The interpreter parameter to 'exec' is deprecated and will be removed in a future version." if interpreter
|
119
153
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
rescue Errno::ENOENT => detail
|
136
|
-
# command not found on Windows
|
137
|
-
return nil
|
138
|
-
rescue => detail
|
139
|
-
$stderr.puts detail
|
140
|
-
return nil
|
141
|
-
end
|
154
|
+
## Set LANG to force i18n to C for the duration of this exec; this ensures that any code that parses the
|
155
|
+
## output of the command can expect it to be in a consistent / predictable format / locale
|
156
|
+
with_env "LANG" => "C" do
|
157
|
+
|
158
|
+
if expanded_code = expand_command(code)
|
159
|
+
# if we can find the binary, we'll run the command with the expanded path to the binary
|
160
|
+
code = expanded_code
|
161
|
+
else
|
162
|
+
# if we cannot find the binary return nil on posix. On windows we'll still try to run the
|
163
|
+
# command in case it is a shell-builtin. In case it is not, windows will raise Errno::ENOENT
|
164
|
+
return nil unless Facter::Util::Config.is_windows?
|
165
|
+
return nil if absolute_path?(code)
|
166
|
+
end
|
167
|
+
|
168
|
+
out = nil
|
142
169
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
170
|
+
begin
|
171
|
+
out = %x{#{code}}.chomp
|
172
|
+
Facter.warnonce 'Using Facter::Util::Resolution.exec with a shell built-in is deprecated. Most built-ins can be replaced with native ruby commands. If you really have to run a built-in, pass "cmd /c your_builtin" as a command' unless expanded_code
|
173
|
+
rescue Errno::ENOENT => detail
|
174
|
+
# command not found on Windows
|
175
|
+
return nil
|
176
|
+
rescue => detail
|
177
|
+
$stderr.puts detail
|
178
|
+
return nil
|
179
|
+
end
|
180
|
+
|
181
|
+
if out == ""
|
182
|
+
return nil
|
183
|
+
else
|
184
|
+
return out
|
185
|
+
end
|
147
186
|
end
|
148
187
|
end
|
149
188
|
|
@@ -197,6 +236,37 @@ class Facter::Util::Resolution
|
|
197
236
|
end
|
198
237
|
end
|
199
238
|
|
239
|
+
##
|
240
|
+
# on_flush accepts a block and executes the block when the resolution's value
|
241
|
+
# is flushed. This makes it possible to model a single, expensive system
|
242
|
+
# call inside of a Ruby object and then define multiple dynamic facts which
|
243
|
+
# resolve by sending messages to the model instance. If one of the dynamic
|
244
|
+
# facts is flushed then it can, in turn, flush the data stored in the model
|
245
|
+
# instance to keep all of the dynamic facts in sync without making multiple,
|
246
|
+
# expensive, system calls.
|
247
|
+
#
|
248
|
+
# Please see the Solaris zones fact for an example of how this feature may be
|
249
|
+
# used.
|
250
|
+
#
|
251
|
+
# @see Facter::Util::Fact#flush
|
252
|
+
# @see Facter::Util::Resolution#flush
|
253
|
+
#
|
254
|
+
# @api public
|
255
|
+
def on_flush(&block)
|
256
|
+
@on_flush_block = block
|
257
|
+
end
|
258
|
+
|
259
|
+
##
|
260
|
+
# flush executes the block, if any, stored by the {on_flush} method
|
261
|
+
#
|
262
|
+
# @see Facter::Util::Fact#flush
|
263
|
+
# @see Facter::Util::Resolution#on_flush
|
264
|
+
#
|
265
|
+
# @api private
|
266
|
+
def flush
|
267
|
+
@on_flush_block.call if @on_flush_block
|
268
|
+
end
|
269
|
+
|
200
270
|
def interpreter
|
201
271
|
Facter.warnonce "The 'Facter::Util::Resolution.interpreter' method is deprecated and will be removed in a future version."
|
202
272
|
@interpreter
|
@@ -222,6 +292,7 @@ class Facter::Util::Resolution
|
|
222
292
|
|
223
293
|
# How we get a value for our resolution mechanism.
|
224
294
|
def value
|
295
|
+
return @value if @value
|
225
296
|
result = nil
|
226
297
|
return result if @code == nil
|
227
298
|
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'facter/util/resolution'
|
2
|
+
|
3
|
+
module Facter
|
4
|
+
module Util
|
5
|
+
##
|
6
|
+
# Provide a set of utility methods to interact with Solaris zones. This class
|
7
|
+
# is expected to be instantiated once per set of resolutions in order to
|
8
|
+
# cache the output of the zoneadm command, which can be quite expensive.
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
class SolarisZones
|
12
|
+
attr_reader :zone_hash
|
13
|
+
attr_reader :zoneadm_cmd
|
14
|
+
attr_reader :zoneadm_output
|
15
|
+
attr_reader :zoneadm_keys
|
16
|
+
|
17
|
+
##
|
18
|
+
# add_facts defines all of the facts for solaris zones, for example `zones`,
|
19
|
+
# `zone_global_id`, `zone_global_status`, etc... This method defines the
|
20
|
+
# static fact named `zones`. The value of this fact is the numver of zones
|
21
|
+
# reported by the zoneadm system command. The `zones` fact also defines
|
22
|
+
# all of the dynamic facts describing the following seven attribute values
|
23
|
+
# for each zone.
|
24
|
+
#
|
25
|
+
# Zones may be added to the system while Facter is loaded. In order to
|
26
|
+
# define new dynamic facts that reflect this new information, the `virtual`
|
27
|
+
# will define new facts as a side effect of refreshing it's own value.
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
def self.add_facts
|
31
|
+
model = new
|
32
|
+
model.refresh
|
33
|
+
model.add_dynamic_facts
|
34
|
+
Facter.add("zones") do
|
35
|
+
setcode do
|
36
|
+
model.refresh if model.flushed?
|
37
|
+
model.add_dynamic_facts
|
38
|
+
model.count
|
39
|
+
end
|
40
|
+
on_flush do
|
41
|
+
model.flush!
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# @param [Hash] opts the options to create the instance with
|
48
|
+
# @option opts [String] :zoneadm_cmd ('/usr/sbin/zoneadm list -cp') the
|
49
|
+
# system command to inspect zones
|
50
|
+
# @option opts [String] :zoneadm_output (nil) the cached output of the
|
51
|
+
# zoneadm_cmd
|
52
|
+
def initialize(opts = {})
|
53
|
+
@zoneadm_keys = [:id, :name, :status, :path, :uuid, :brand, :iptype]
|
54
|
+
@zoneadm_cmd = opts[:zoneadm_cmd] || '/usr/sbin/zoneadm list -cp'
|
55
|
+
if opts[:zoneadm_output]
|
56
|
+
@zoneadm_output = opts[:zoneadm_output]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# add_dynamic_facts defines all of the dynamic facts derived from parsing
|
62
|
+
# the output of the zoneadm command. The zone facts are dynamic, so this
|
63
|
+
# method has the behavior of figuring out what dynamic zone facts need to
|
64
|
+
# be defined and how they should be resolved.
|
65
|
+
#
|
66
|
+
# @param model [SolarisZones] the model used to store data from the system
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
def add_dynamic_facts
|
70
|
+
model = self
|
71
|
+
zone_hash.each_pair do |zone, attr_hsh|
|
72
|
+
attr_hsh.keys.each do |attr|
|
73
|
+
Facter.add("zone_#{zone}_#{attr}") do
|
74
|
+
setcode do
|
75
|
+
model.refresh if model.flushed?
|
76
|
+
# Don't resolve if the zone has since been deleted
|
77
|
+
if zone_hsh = model.zone_hash[zone]
|
78
|
+
zone_hsh[attr] # the value
|
79
|
+
end
|
80
|
+
end
|
81
|
+
on_flush do
|
82
|
+
model.flush!
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# refresh executes the zoneadm_cmd and stores the output data.
|
91
|
+
#
|
92
|
+
# @api private
|
93
|
+
#
|
94
|
+
# @return [Hash] the parsed output of the zoneadm command
|
95
|
+
def refresh
|
96
|
+
@zoneadm_output = Facter::Util::Resolution.exec(zoneadm_cmd)
|
97
|
+
parse!
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# parse! parses the string stored in {@zoneadm_output} and stores the
|
102
|
+
# resulting Hash data structure in {@zone_hash}
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
def parse!
|
106
|
+
rows = @zoneadm_output.split("\n").collect { |line| line.split(':') }
|
107
|
+
|
108
|
+
@zone_hash = rows.inject({}) do |memo, fields|
|
109
|
+
zone = fields[1].intern
|
110
|
+
# Transform the row into a hash with keys named by the column names
|
111
|
+
memo[zone] = Hash[*@zoneadm_keys.zip(fields).flatten]
|
112
|
+
memo
|
113
|
+
end
|
114
|
+
end
|
115
|
+
private :parse!
|
116
|
+
|
117
|
+
##
|
118
|
+
# count returns the number of running zones, including the global zone.
|
119
|
+
# This method is intended to be used from the setcode block of the `zones`
|
120
|
+
# fact.
|
121
|
+
#
|
122
|
+
# @api private
|
123
|
+
#
|
124
|
+
# @return [Fixnum, nil] the number of running zones or nil if the number
|
125
|
+
# could not be determined.
|
126
|
+
def count
|
127
|
+
if @zone_hash
|
128
|
+
@zone_hash.size
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# flush! purges the saved data from the zoneadm_cmd output
|
134
|
+
#
|
135
|
+
# @api private
|
136
|
+
def flush!
|
137
|
+
@zoneadm_output = nil
|
138
|
+
@zone_hash = nil
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# flushed? returns true if the instance has no parsed data accessible via
|
143
|
+
# the {zone_hash} method.
|
144
|
+
#
|
145
|
+
# @api private
|
146
|
+
#
|
147
|
+
# @return [Boolean] true if there is no parsed data, false otherwise
|
148
|
+
def flushed?
|
149
|
+
!@zone_hash
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|