facter 1.0.1

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.

Files changed (12) hide show
  1. data/CHANGES +9 -0
  2. data/COPYING +339 -0
  3. data/INSTALL +7 -0
  4. data/LICENSE +17 -0
  5. data/README +9 -0
  6. data/Rakefile +277 -0
  7. data/TODO +4 -0
  8. data/bin/facter +72 -0
  9. data/etc/facter.conf +5 -0
  10. data/install.rb +289 -0
  11. data/lib/facter.rb +771 -0
  12. metadata +59 -0
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ More documentation.
2
+
3
+ The ability to specify fact names with strings or symbols; right now, only
4
+ strings are supported
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--------------------
4
+ # duh, it's facter!
5
+ #
6
+ # $Id: facter,v 1.1.1.1 2004/03/21 21:06:27 luke Exp $
7
+
8
+ require 'getoptlong'
9
+ require 'facter'
10
+
11
+ Facter.load
12
+
13
+ $debug = 0
14
+
15
+ config = nil
16
+
17
+ result = GetoptLong.new(
18
+ [ "--version", "-v", GetoptLong::NO_ARGUMENT ],
19
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
20
+ [ "--debug", "-d", GetoptLong::NO_ARGUMENT ],
21
+ [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ]
22
+ )
23
+
24
+ result.each { |opt,arg|
25
+ case opt
26
+ when "--version"
27
+ puts "%s" % Facter.version
28
+ exit
29
+ when "--debug"
30
+ Facter.debugging(1)
31
+ when "--help"
32
+ puts "There is no help yet"
33
+ exit
34
+ else
35
+ raise "Invalid option '#{opt}'"
36
+ end
37
+ }
38
+
39
+ names = []
40
+
41
+ unless config.nil?
42
+ File.open(config) { |file|
43
+ names = file.readlines.collect { |line|
44
+ line.chomp
45
+ }
46
+ }
47
+ end
48
+
49
+ ARGV.each { |item|
50
+ names.push item
51
+ }
52
+
53
+ facts = {}
54
+
55
+ if names.empty?
56
+ Facter.each { |name,fact|
57
+ facts[name] = fact
58
+ }
59
+ else
60
+ names.each { |name|
61
+ begin
62
+ facts[name] = Facter[name].value
63
+ rescue => error
64
+ STDERR.puts "Could not retrieve %s: #{error}" % name
65
+ exit 10
66
+ end
67
+ }
68
+ end
69
+
70
+ facts.each { |name,value|
71
+ puts "%s => %s" % [name,value]
72
+ }
@@ -0,0 +1,5 @@
1
+ Hostname
2
+ OperatingSystem
3
+ OperatingSystemRelease
4
+ SSHDSAKey
5
+ CfKey
@@ -0,0 +1,289 @@
1
+ #! /usr/bin/env ruby
2
+ #--
3
+ # Copyright 2004 Austin Ziegler <ruby-install@halostatue.ca>
4
+ # Install utility. Based on the original installation script for rdoc by the
5
+ # Pragmatic Programmers.
6
+ #
7
+ # This program is free software. It may be redistributed and/or modified under
8
+ # the terms of the GPL version 2 (or later) or the Ruby licence.
9
+ #
10
+ # Usage
11
+ # -----
12
+ # In most cases, if you have a typical project layout, you will need to do
13
+ # absolutely nothing to make this work for you. This layout is:
14
+ #
15
+ # bin/ # executable files -- "commands"
16
+ # lib/ # the source of the library
17
+ # tests/ # unit tests
18
+ #
19
+ # The default behaviour:
20
+ # 1) Run all unit test files (ending in .rb) found in all directories under
21
+ # tests/.
22
+ # 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd),
23
+ # all .rb files in lib/, ./README, ./ChangeLog, and ./Install.
24
+ # 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd),
25
+ # and all .rb files in lib/. This is disabled by default on Win32.
26
+ # 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a
27
+ # if a corresponding batch file (.bat or .cmd) exists in the bin directory,
28
+ # it will be copied over as well. Otherwise, a batch file (always .bat) will
29
+ # be created to run the specified command.
30
+ # 5) Install all library files ending in .rb from lib/ into Ruby's
31
+ # site_lib/version directory.
32
+ #
33
+ # $Id: install.rb,v 1.6 2004/08/08 20:33:09 austin Exp $
34
+ #++
35
+
36
+ require 'rbconfig'
37
+ require 'find'
38
+ require 'fileutils'
39
+ require 'optparse'
40
+ require 'ostruct'
41
+
42
+ InstallOptions = OpenStruct.new
43
+
44
+ $loadedrdoc = false
45
+
46
+ begin
47
+ require 'rdoc/rdoc'
48
+ $loadedrdoc = true
49
+ rescue LoadError => detail
50
+ $stderr.puts "Could not load rdoc/rdoc: %s" % detail
51
+ InstallOptions.rdoc = false
52
+ end
53
+
54
+
55
+ def glob(list)
56
+ g = list.map { |i| Dir.glob(i) }
57
+ g.flatten!
58
+ g.compact!
59
+ g.reject! { |e| e =~ /CVS/ }
60
+ g
61
+ end
62
+
63
+ # Set these values to what you want installed.
64
+ #bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ }
65
+ bins = ["bin/facter"]
66
+ rdoc = glob(%w{bin/**/* lib/**/*.rb README CHANGELOG INSTALL}).reject { |e| e=~ /\.(bat|cmd)$/ }
67
+ ri = glob(%w(bin/**/* lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ }
68
+ libs = glob(%w{lib/**/*.rb})
69
+ tests = glob(%w{tests/**/*.rb})
70
+
71
+ def do_bins(bins, target, strip = 'bin/')
72
+ bins.each do |bf|
73
+ obf = bf.gsub(/#{strip}/, '')
74
+ install_binfile(bf, obf, target)
75
+ end
76
+ end
77
+
78
+ def do_libs(libs, strip = 'lib/')
79
+ libs.each do |lf|
80
+ olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, ''))
81
+ op = File.dirname(olf)
82
+ #if File.respond_to?(:makedirs)
83
+ FileUtils.makedirs(op)
84
+ #else
85
+ # recmkdir(op)
86
+ #end
87
+ File.chmod(0755, op)
88
+ FileUtils.install(lf, olf, :mode => 0755, :verbose => true)
89
+ end
90
+ end
91
+
92
+ ##
93
+ # Prepare the file installation.
94
+ #
95
+ def prepare_installation
96
+ InstallOptions.rdoc = true
97
+ if RUBY_PLATFORM == "i386-mswin32"
98
+ InstallOptions.ri = false
99
+ else
100
+ InstallOptions.ri = true
101
+ end
102
+ InstallOptions.tests = true
103
+
104
+ ARGV.options do |opts|
105
+ opts.banner = "Usage: #{File.basename($0)} [options]"
106
+ opts.separator ""
107
+ opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc|
108
+ InstallOptions.rdoc = onrdoc
109
+ end
110
+ opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri|
111
+ InstallOptions.ri = onri
112
+ end
113
+ opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest|
114
+ InstallOptions.tests = ontest
115
+ end
116
+ opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick|
117
+ InstallOptions.rdoc = false
118
+ InstallOptions.ri = false
119
+ InstallOptions.tests = false
120
+ end
121
+ opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full|
122
+ InstallOptions.rdoc = true
123
+ InstallOptions.ri = true
124
+ InstallOptions.tests = true
125
+ end
126
+ opts.separator("")
127
+ opts.on_tail('--help', "Shows this help text.") do
128
+ $stderr.puts opts
129
+ exit
130
+ end
131
+
132
+ opts.parse!
133
+ end
134
+
135
+ bds = [".", ENV['TMP'], ENV['TEMP'], "/tmp"]
136
+
137
+ version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".")
138
+ ld = File.join(Config::CONFIG["libdir"], "ruby", version)
139
+
140
+ sd = Config::CONFIG["sitelibdir"]
141
+ if sd.nil?
142
+ sd = $:.find { |x| x =~ /site_ruby/ }
143
+ if sd.nil?
144
+ sd = File.join(ld, "site_ruby")
145
+ elsif sd !~ Regexp.quote(version)
146
+ sd = File.join(sd, version)
147
+ end
148
+ end
149
+
150
+ if (destdir = ENV['DESTDIR'])
151
+ bd = "#{destdir}#{Config::CONFIG['bindir']}"
152
+ sd = "#{destdir}#{sd}"
153
+ bds << bd
154
+
155
+ FileUtils.makedirs(bd)
156
+ FileUtils.makedirs(sd)
157
+ else
158
+ bds << Config::CONFIG['bindir']
159
+ end
160
+
161
+ InstallOptions.bin_dirs = bds.compact
162
+ InstallOptions.site_dir = sd
163
+ InstallOptions.bin_dir = bd
164
+ InstallOptions.lib_dir = ld
165
+
166
+ unless $loadedrdoc
167
+ InstallOptions.rdoc = false
168
+ InstallOptions.ri = false
169
+ end
170
+ end
171
+
172
+ ##
173
+ # Build the rdoc documentation. Also, try to build the RI documentation.
174
+ #
175
+ def build_rdoc(files)
176
+ r = RDoc::RDoc.new
177
+ r.document(["--main", "README", "--title", "Facter -- A Fact Collecter",
178
+ "--line-numbers"] + files)
179
+
180
+ rescue RDoc::RDocError => e
181
+ $stderr.puts e.message
182
+ rescue Exception => e
183
+ $stderr.puts "Couldn't build RDoc documentation\n#{e.message}"
184
+ end
185
+
186
+ def build_ri(files)
187
+ ri = RDoc::RDoc.new
188
+ ri.document(["--ri-site", "--merge"] + files)
189
+ rescue RDoc::RDocError => e
190
+ $stderr.puts e.message
191
+ rescue Exception => e
192
+ $stderr.puts e.class
193
+ $stderr.puts "Couldn't build Ri documentation\n#{e.message}"
194
+ end
195
+
196
+ def run_tests(test_list)
197
+ begin
198
+ require 'test/unit/ui/console/testrunner'
199
+ $:.unshift "lib"
200
+ test_list.each do |test|
201
+ next if File.directory?(test)
202
+ require test
203
+ end
204
+
205
+ tests = []
206
+ ObjectSpace.each_object { |o| tests << o if o.kind_of?(Class) }
207
+ tests.delete_if { |o| !o.ancestors.include?(Test::Unit::TestCase) }
208
+ tests.delete_if { |o| o == Test::Unit::TestCase }
209
+
210
+ tests.each { |test| Test::Unit::UI::Console::TestRunner.run(test) }
211
+ $:.shift
212
+ rescue LoadError
213
+ puts "Missing testrunner library; skipping tests"
214
+ end
215
+ end
216
+
217
+ ##
218
+ # Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way
219
+ # to insert a #! line; on a Unix install, the command is named as expected
220
+ # (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under
221
+ # windows, we add an '.rb' extension and let file associations do their stuff.
222
+ def install_binfile(from, op_file, target)
223
+ tmp_dir = nil
224
+ InstallOptions.bin_dirs.each do |t|
225
+ if File.directory?(t) and File.writable_real?(t)
226
+ tmp_dir = t
227
+ break
228
+ end
229
+ end
230
+
231
+ fail "Cannot find a temporary directory" unless tmp_dir
232
+ tmp_file = File.join(tmp_dir, '_tmp')
233
+ ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
234
+
235
+ File.open(from) do |ip|
236
+ File.open(tmp_file, "w") do |op|
237
+ ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
238
+ op.puts "#!#{ruby}"
239
+ op.write ip.read
240
+ end
241
+ end
242
+
243
+ if Config::CONFIG["target_os"] =~ /win/io
244
+ installed_wrapper = false
245
+
246
+ if File.exists?("#{from}.bat")
247
+ FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true)
248
+ installed_wrapper = true
249
+ end
250
+
251
+ if File.exists?("#{from}.cmd")
252
+ FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true)
253
+ installed_wrapper = true
254
+ end
255
+
256
+ if not installed_wrapper
257
+ tmp_file2 = File.join(tmp_dir, '_tmp_wrapper')
258
+ cwn = File.join(Config::CONFIG['bindir'], op_file)
259
+ cwv = CMD_WRAPPER.gsub('<ruby>', ruby.gsub(%r{/}) { "\\" }).gsub!('<command>', cwn.gsub(%r{/}) { "\\" } )
260
+
261
+ File.open(tmp_file2, "wb") { |cw| cw.puts cwv }
262
+ FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true)
263
+
264
+ File.unlink(tmp_file2)
265
+ installed_wrapper = true
266
+ end
267
+ end
268
+ FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true)
269
+ File.unlink(tmp_file)
270
+ end
271
+
272
+ CMD_WRAPPER = <<-EOS
273
+ @echo off
274
+ if "%OS%"=="Windows_NT" goto WinNT
275
+ <ruby> -x "<command>" %1 %2 %3 %4 %5 %6 %7 %8 %9
276
+ goto done
277
+ :WinNT
278
+ <ruby> -x "<command>" %*
279
+ goto done
280
+ :done
281
+ EOS
282
+
283
+ prepare_installation
284
+
285
+ run_tests(tests) if InstallOptions.tests
286
+ build_rdoc(rdoc) if InstallOptions.rdoc
287
+ build_ri(ri) if InstallOptions.ri
288
+ do_bins(bins, Config::CONFIG['bindir'])
289
+ do_libs(libs)
@@ -0,0 +1,771 @@
1
+ # $Id: facter.rb 63 2005-11-22 15:25:08Z luke $
2
+ #--
3
+ # Copyright 2004 Luke Kanies <luke@madstop.com>
4
+ #
5
+ # This program is free software. It may be redistributed and/or modified under
6
+ # the terms of the GPL version 2 (or later), the Perl Artistic licence, or the
7
+ # Ruby licence.
8
+ #
9
+ #--
10
+
11
+ #--------------------------------------------------------------------
12
+ class Facter
13
+ include Comparable
14
+ include Enumerable
15
+
16
+ FACTERVERSION="1.0.0"
17
+ # = Facter 1.0
18
+ # Functions as a hash of 'facts' you might care about about your
19
+ # system, such as mac address, IP address, Video card, etc.
20
+ # returns them dynamically
21
+
22
+ # == Synopsis
23
+ #
24
+ # Generally, treat <tt>Facter</tt> as a hash:
25
+ # == Example
26
+ # require 'facter'
27
+ # puts Facter['operatingsystem']
28
+ #
29
+
30
+
31
+ @@facts = {}
32
+ GREEN = ""
33
+ RESET = ""
34
+ @@debug = 0
35
+ @@os = nil
36
+ @@osrel = nil
37
+
38
+ attr_accessor :name, :os, :osrel, :hardware, :searching
39
+
40
+ #----------------------------------------------------------------
41
+ # module methods
42
+ #----------------------------------------------------------------
43
+
44
+ def Facter.version
45
+ return FACTERVERSION
46
+ end
47
+
48
+ def Facter.debug(string)
49
+ if string.nil?
50
+ return
51
+ end
52
+ if @@debug != 0
53
+ puts GREEN + string + RESET
54
+ end
55
+ end
56
+
57
+ #----------------------------------------------------------------
58
+ def Facter.[](name)
59
+ if @@facts.include?(name.downcase)
60
+ return @@facts[name.downcase]
61
+ else
62
+ return Facter.add(name)
63
+ end
64
+ end
65
+ #----------------------------------------------------------------
66
+
67
+ #----------------------------------------------------------------
68
+ def Facter.add(name)
69
+ fact = nil
70
+ dcname = name.downcase
71
+
72
+ if @@facts.include?(dcname)
73
+ fact = @@facts[dcname]
74
+ else
75
+ Facter.new(dcname)
76
+ fact = @@facts[dcname]
77
+ end
78
+
79
+ if block_given?
80
+ fact.add
81
+ end
82
+
83
+ return fact
84
+ end
85
+ #----------------------------------------------------------------
86
+
87
+ #----------------------------------------------------------------
88
+ class << self
89
+ include Enumerable
90
+ def each
91
+ @@facts.each { |name,fact|
92
+ if fact.suitable?
93
+ value = fact.value
94
+ unless value.nil?
95
+ yield name, fact.value
96
+ end
97
+ end
98
+ }
99
+ end
100
+ end
101
+ #----------------------------------------------------------------
102
+
103
+ #----------------------------------------------------------------
104
+ def Facter.reset
105
+ @@facts.each { |name,fact|
106
+ @@facts.delete(name)
107
+ }
108
+ end
109
+ #----------------------------------------------------------------
110
+
111
+ #----------------------------------------------------------------
112
+ #
113
+ def Facter.debugging(bit)
114
+ if bit
115
+ case bit
116
+ when TrueClass: @@debug = 1
117
+ when FalseClass: @@debug = 0
118
+ when Fixnum:
119
+ if bit > 0
120
+ @@debug = 1
121
+ else
122
+ @@debug = 0
123
+ end
124
+ when String:
125
+ if bit.downcase == 'off'
126
+ @@debug = 0
127
+ else
128
+ @@debug = 1
129
+ end
130
+ else
131
+ @@debug = 0
132
+ end
133
+ else
134
+ @@debug = 0
135
+ end
136
+ end
137
+ #----------------------------------------------------------------
138
+
139
+ #----------------------------------------------------------------
140
+ #def Facter.init
141
+ # @@os = @@facts["operatingsystem"].value
142
+ # @@release = @@facts["operatingsystemrelease"].value
143
+ #end
144
+ #----------------------------------------------------------------
145
+
146
+ #----------------------------------------------------------------
147
+ def Facter.list
148
+ return @@facts.keys
149
+ end
150
+ #----------------------------------------------------------------
151
+
152
+ #----------------------------------------------------------------
153
+ def Facter.os
154
+ return @@os
155
+ end
156
+ #----------------------------------------------------------------
157
+
158
+ #----------------------------------------------------------------
159
+ def Facter.release
160
+ return @@release
161
+ end
162
+ #----------------------------------------------------------------
163
+
164
+ #----------------------------------------------------------------
165
+ def <=>(other)
166
+ return self.value <=> other
167
+ end
168
+ #----------------------------------------------------------------
169
+
170
+ #----------------------------------------------------------------
171
+ def initialize(name)
172
+ @name = name.downcase
173
+ if @@facts.include?(@name)
174
+ raise "A fact named %s already exists" % name
175
+ else
176
+ @@facts[@name] = self
177
+ end
178
+
179
+ @resolves = []
180
+ @searching = false
181
+ end
182
+ #----------------------------------------------------------------
183
+
184
+ #----------------------------------------------------------------
185
+ # as long as this doesn't work over the 'net, it should probably
186
+ # be optimized to throw away any resolutions not valid for the machine
187
+ # it's running on
188
+ # but that's not currently done...
189
+ def add
190
+ resolve = Resolution.new(@name)
191
+ yield(resolve)
192
+
193
+ # skip resolves that will never be suitable for us
194
+ return unless resolve.suitable?
195
+
196
+ # insert resolves in order of number of tags
197
+ inserted = false
198
+ @resolves.each_with_index { |r,index|
199
+ if resolve.length > r.length
200
+ @resolves.insert(index,resolve)
201
+ inserted = true
202
+ break
203
+ end
204
+ }
205
+
206
+ unless inserted
207
+ @resolves.push resolve
208
+ end
209
+ end
210
+ #----------------------------------------------------------------
211
+
212
+ #----------------------------------------------------------------
213
+ # iterate across all of the currently configured resolves
214
+ # sort the resolves in order of most tags first, so we're getting
215
+ # the most specific answers first, hopefully
216
+ def each
217
+ # @resolves.sort { |a,b|
218
+ # puts "for tag %s, alength is %s and blength is %s" %
219
+ # [@name, a.length, b.length]
220
+ # b.length <=> a.length
221
+ # }.each { |resolve|
222
+ # yield resolve
223
+ # }
224
+ @resolves.each { |r| yield r }
225
+ end
226
+ #----------------------------------------------------------------
227
+
228
+ #----------------------------------------------------------------
229
+ # return a count of resolution mechanisms available
230
+ def count
231
+ return @resolves.length
232
+ end
233
+ #----------------------------------------------------------------
234
+
235
+ #----------------------------------------------------------------
236
+ # is this fact suitable for finding answers on this host?
237
+ # again, this should really be optimizing by throwing away everything
238
+ # not suitable, but...
239
+ def suitable?
240
+ return false if @resolves.length == 0
241
+
242
+ unless defined? @suitable
243
+ @suitable = false
244
+ self.each { |resolve|
245
+ if resolve.suitable?
246
+ @suitable = true
247
+ break
248
+ end
249
+ }
250
+ end
251
+
252
+ return @suitable
253
+ end
254
+ #----------------------------------------------------------------
255
+
256
+ #----------------------------------------------------------------
257
+ def value
258
+ # make sure we don't get stuck in recursive dependency loops
259
+ if @searching
260
+ Facter.debug "Caught recursion on %s" % @name
261
+
262
+ # return a cached value if we've got it
263
+ if @value
264
+ return @value
265
+ else
266
+ return nil
267
+ end
268
+ end
269
+ @value = nil
270
+ foundsuits = false
271
+
272
+ if @resolves.length == 0
273
+ Facter.debug "No resolves for %s" % @name
274
+ return nil
275
+ end
276
+
277
+ @searching = true
278
+ @resolves.each { |resolve|
279
+ #Facter.debug "Searching resolves for %s" % @name
280
+ if resolve.suitable?
281
+ @value = resolve.value
282
+ foundsuits = true
283
+ else
284
+ Facter.debug "Unsuitable resolve %s for %s" % [resolve,@name]
285
+ end
286
+ unless @value.nil? or @value == ""
287
+ break
288
+ end
289
+ }
290
+ @searching = false
291
+
292
+ unless foundsuits
293
+ Facter.debug "Found no suitable resolves of %s for %s" %
294
+ [@resolves.length,@name]
295
+ end
296
+
297
+ if @value.nil?
298
+ # nothing
299
+ Facter.debug("value for %s is still nil" % @name)
300
+ return nil
301
+ else
302
+ return @value
303
+ end
304
+ end
305
+ #----------------------------------------------------------------
306
+
307
+ #----------------------------------------------------------------
308
+ class Resolution
309
+ attr_accessor :interpreter, :code, :name
310
+
311
+ def Resolution.exec(code, interpreter = "/bin/sh")
312
+ if interpreter == "/bin/sh"
313
+ binary = code.split(/\s+/).shift
314
+
315
+ path = nil
316
+ if binary !~ /^\//
317
+ path = %x{which #{binary} 2>/dev/null}.chomp
318
+ if path == ""
319
+ # we don't have the binary necessary
320
+ return nil
321
+ end
322
+ else
323
+ path = binary
324
+ end
325
+
326
+ unless FileTest.exists?(path)
327
+ # our binary does not exist
328
+ return nil
329
+ end
330
+ out = nil
331
+ begin
332
+ out = %x{#{code}}.chomp
333
+ rescue => detail
334
+ $stderr.puts detail
335
+ end
336
+ if out == ""
337
+ return nil
338
+ else
339
+ return out
340
+ end
341
+ else
342
+ raise "non-sh interpreters are not currently supported"
343
+ end
344
+ end
345
+
346
+ def initialize(name)
347
+ @name = name
348
+ @tags = []
349
+ end
350
+
351
+ def length
352
+ @tags.length
353
+ end
354
+
355
+ def suitable?
356
+ unless defined? @suitable
357
+ @suitable = true
358
+ if @tags.length == 0
359
+ #Facter.debug "'%s' has no tags" % @name
360
+ return true
361
+ end
362
+ @tags.each { |tag|
363
+ unless tag.true?
364
+ #Facter.debug "'%s' is false" % tag
365
+ @suitable = false
366
+ end
367
+ }
368
+ end
369
+
370
+ return @suitable
371
+ end
372
+
373
+ def tag(fact,op,value)
374
+ @tags.push Tag.new(fact,op,value)
375
+ end
376
+
377
+ def to_s
378
+ return self.value()
379
+ end
380
+
381
+ # how we get a value for our resolution mechanism
382
+ def value
383
+ #puts "called %s value" % @name
384
+ value = nil
385
+ if @code.is_a?(Proc)
386
+ value = @code.call()
387
+ else
388
+ unless defined? @interpreter
389
+ @interpreter = "/bin/sh"
390
+ end
391
+ if @code.nil?
392
+ $stderr.puts "Code for %s is nil" % @name
393
+ else
394
+ value = Resolution.exec(@code,@interpreter)
395
+ end
396
+ end
397
+
398
+ if value == ""
399
+ value = nil
400
+ end
401
+
402
+ return value
403
+ end
404
+ end
405
+ #----------------------------------------------------------------
406
+
407
+ #----------------------------------------------------------------
408
+ class Tag
409
+ attr_accessor :fact, :op, :value
410
+
411
+ def initialize(fact,op,value)
412
+ @fact = fact
413
+ if op == "="
414
+ op = "=="
415
+ end
416
+ @op = op
417
+ @value = value
418
+ end
419
+
420
+ def to_s
421
+ return "'%s' %s '%s'" % [@fact,@op,@value]
422
+ end
423
+
424
+ def true?
425
+ value = Facter[@fact].value
426
+
427
+ if value.nil?
428
+ return false
429
+ end
430
+
431
+ str = "'%s' %s '%s'" % [value,@op,@value]
432
+ begin
433
+ if eval(str)
434
+ return true
435
+ else
436
+ return false
437
+ end
438
+ rescue => detail
439
+ $stderr.puts "Failed to test '%s': %s" % [str,detail]
440
+ return false
441
+ end
442
+ end
443
+ end
444
+ #----------------------------------------------------------------
445
+
446
+ # Load all of the default facts
447
+ def Facter.load
448
+ Facter["OperatingSystem"].add { |obj|
449
+ obj.code = 'uname -s'
450
+ }
451
+
452
+ Facter["OperatingSystemRelease"].add { |obj|
453
+ obj.code = 'uname -r'
454
+ }
455
+
456
+ Facter["HardwareModel"].add { |obj|
457
+ obj.code = 'uname -m'
458
+ #obj.os = "SunOS"
459
+ #obj.tag("operatingsystem","=","SunOS")
460
+ }
461
+
462
+ Facter["CfKey"].add { |obj|
463
+ obj.code = proc {
464
+ value = nil
465
+ ["/usr/local/etc/cfkey.pub",
466
+ "/etc/cfkey.pub",
467
+ "/var/cfng/keys/localhost.pub",
468
+ "/var/cfengine/ppkeys/localhost.pub"
469
+ ].each { |file|
470
+ if FileTest.file?(file)
471
+ File.open(file) { |openfile|
472
+ value = openfile.readlines.reject { |line|
473
+ line =~ /PUBLIC KEY/
474
+ }.collect { |line|
475
+ line.chomp
476
+ }.join("")
477
+ }
478
+ end
479
+ if value
480
+ break
481
+ end
482
+ }
483
+
484
+ value
485
+ }
486
+ }
487
+
488
+ Facter["Domain"].add { |obj|
489
+ obj.code = proc {
490
+ if defined? $domain and ! $domain.nil?
491
+ $domain
492
+ end
493
+ }
494
+ }
495
+ Facter["Domain"].add { |obj|
496
+ obj.code = proc {
497
+ domain = Resolution.exec('domainname')
498
+ # make sure it's a real domain
499
+ if domain =~ /.+\..+/
500
+ domain
501
+ else
502
+ nil
503
+ end
504
+ }
505
+ }
506
+ Facter["Domain"].add { |obj|
507
+ obj.code = proc {
508
+ value = nil
509
+ unless FileTest.exists?("/etc/resolv.conf")
510
+ return nil
511
+ end
512
+ File.open("/etc/resolv.conf") { |file|
513
+ # is the domain set?
514
+ file.each { |line|
515
+ if line =~ /domain\s+(\S+)/
516
+ value = $1
517
+ break
518
+ end
519
+ }
520
+ }
521
+ ! value and File.open("/etc/resolv.conf") { |file|
522
+ # is the search path set?
523
+ file.each { |line|
524
+ if line =~ /search\s+(\S+)/
525
+ value = $1
526
+ break
527
+ end
528
+ }
529
+ }
530
+ value
531
+ }
532
+ }
533
+ Facter["Hostname"].add { |obj|
534
+ obj.code = proc {
535
+ hostname = nil
536
+ name = Resolution.exec('hostname')
537
+ if name =~ /^([\w-]+)\.(.+)$/
538
+ hostname = $1
539
+ # the Domain class uses this
540
+ $domain = $2
541
+ else
542
+ hostname = name
543
+ end
544
+ hostname
545
+ }
546
+ }
547
+
548
+ Facter["IPHostNumber"].add { |obj|
549
+ obj.code = proc {
550
+ require 'resolv'
551
+
552
+ begin
553
+ hostname = Facter["hostname"].value
554
+ ip = Resolv.getaddress(hostname)
555
+ unless ip == "127.0.0.1"
556
+ ip
557
+ end
558
+ rescue Resolv::ResolvError
559
+ nil
560
+ rescue NoMethodError # i think this is a bug in resolv.rb?
561
+ nil
562
+ end
563
+ }
564
+ }
565
+ Facter["IPHostNumber"].add { |obj|
566
+ obj.code = proc {
567
+ hostname = Facter["hostname"].value
568
+ # crap, we need Hostname to exist for this to
569
+ # work
570
+ list = Resolution.exec("host #{hostname}").chomp.split(/\s/)
571
+ if defined? list[-1] and list[-1] =~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/
572
+ list[-1]
573
+ end
574
+ }
575
+ }
576
+
577
+ ["/etc/ssh","/usr/local/etc/ssh","/etc","/usr/local/etc"].each { |dir|
578
+ {"SSHDSAKey" => "ssh_host_dsa_key.pub",
579
+ "SSHRSAKey" => "ssh_host_rsa_key.pub"}.each { |name,file|
580
+ Facter[name].add { |obj|
581
+ obj.code = proc {
582
+ value = nil
583
+ filepath = File.join(dir,file)
584
+ if FileTest.file?(filepath)
585
+ begin
586
+ value = File.open(filepath).read.chomp
587
+ rescue
588
+ return nil
589
+ end
590
+ end
591
+ return value
592
+ } # end of proc
593
+ } # end of add
594
+ } # end of hash each
595
+ } # end of dir each
596
+
597
+ Facter["UniqueId"].add { |obj|
598
+ obj.code = 'hostid'
599
+ obj.interpreter = '/bin/sh'
600
+ obj.tag("operatingsystem","=","SunOS")
601
+ #obj.os = "SunOS"
602
+ }
603
+ Facter["HardwareISA"].add { |obj|
604
+ obj.code = 'uname -p'
605
+ obj.interpreter = '/bin/sh'
606
+ #obj.os = "SunOS"
607
+ obj.tag("operatingsystem","=","SunOS")
608
+ }
609
+ Facter["MacAddress"].add { |obj|
610
+ #obj.os = "SunOS"
611
+ obj.tag("operatingsystem","=","SunOS")
612
+ obj.code = proc {
613
+ ether = nil
614
+ output = %x{/sbin/ifconfig -a}
615
+
616
+ output =~ /ether (\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/
617
+ ether = $1
618
+
619
+ ether
620
+ }
621
+ }
622
+ Facter["MacAddress"].add { |obj|
623
+ #obj.os = "Darwin"
624
+ obj.tag("operatingsystem","=","Darwin")
625
+ obj.code = proc {
626
+ ether = nil
627
+ output = %x{/sbin/ifconfig}
628
+
629
+ output.split(/^\S/).each { |str|
630
+ if str =~ /10baseT/ # we're wired
631
+ str =~ /ether (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
632
+ ether = $1
633
+ end
634
+ }
635
+
636
+ ether
637
+ }
638
+ }
639
+ Facter["IPHostnumber"].add { |obj|
640
+ #obj.os = "Darwin"
641
+ obj.tag("operatingsystem","=","Darwin")
642
+ obj.code = proc {
643
+ ip = nil
644
+ output = %x{/sbin/ifconfig}
645
+
646
+ output.split(/^\S/).each { |str|
647
+ if str =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
648
+ tmp = $1
649
+ unless tmp =~ /127\./
650
+ ip = tmp
651
+ break
652
+ end
653
+ end
654
+ }
655
+
656
+ ip
657
+ }
658
+ }
659
+ Facter["Hostname"].add { |obj|
660
+ #obj.os = "Darwin"
661
+ #obj.release = "R7"
662
+ obj.tag("operatingsystem","=","Darwin")
663
+ obj.tag("operatingsystemrelease","=","R7")
664
+ obj.code = proc {
665
+ hostname = nil
666
+ File.open(
667
+ "/Library/Preferences/SystemConfiguration/preferences.plist"
668
+ ) { |file|
669
+ found = 0
670
+ file.each { |line|
671
+ if line =~ /ComputerName/i
672
+ found = 1
673
+ next
674
+ end
675
+ if found == 1
676
+ if line =~ /<string>([\w|-]+)<\/string>/
677
+ hostname = $1
678
+ break
679
+ end
680
+ end
681
+ }
682
+ }
683
+
684
+ if hostname != nil
685
+ hostname
686
+ end
687
+ }
688
+ }
689
+ Facter["IPHostnumber"].add { |obj|
690
+ #obj.os = "Darwin"
691
+ #obj.release = "R6"
692
+ obj.tag("operatingsystem","=","Darwin")
693
+ obj.tag("operatingsystemrelease","=","R6")
694
+ obj.code = proc {
695
+ hostname = nil
696
+ File.open(
697
+ "/var/db/SystemConfiguration/preferences.xml"
698
+ ) { |file|
699
+ found = 0
700
+ file.each { |line|
701
+ if line =~ /ComputerName/i
702
+ found = 1
703
+ next
704
+ end
705
+ if found == 1
706
+ if line =~ /<string>([\w|-]+)<\/string>/
707
+ hostname = $1
708
+ break
709
+ end
710
+ end
711
+ }
712
+ }
713
+
714
+ if hostname != nil
715
+ hostname
716
+ end
717
+ }
718
+ }
719
+ Facter["IPHostnumber"].add { |obj|
720
+ #obj.os = "Darwin"
721
+ #obj.release = "R6"
722
+ obj.tag("operatingsystem","=","Darwin")
723
+ obj.tag("operatingsystemrelease","=","R6")
724
+ obj.code = proc {
725
+ ether = nil
726
+ output = %x{/sbin/ifconfig}
727
+
728
+ output =~ /HWaddr (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
729
+ ether = $1
730
+
731
+ ether
732
+ }
733
+ }
734
+ Facter["Distro"].add { |obj|
735
+ #obj.os = "Linux"
736
+ obj.tag("operatingsystem","=","Linux")
737
+ obj.code = proc {
738
+ if FileTest.exists?("/etc/debian_version")
739
+ return "Debian"
740
+ elsif FileTest.exists?("/etc/gentoo-release")
741
+ return "Gentoo"
742
+ elsif FileTest.exists?("/etc/fedora-release")
743
+ return "Fedora"
744
+ elsif FileTest.exists?("/etc/redhat-release")
745
+ return "RedHat"
746
+ end
747
+ }
748
+ }
749
+ Facter["ps"].add { |obj|
750
+ obj.code = "echo 'ps -ef'"
751
+ }
752
+ Facter["ps"].add { |obj|
753
+ obj.tag("operatingsystem","=","Darwin")
754
+ obj.code = "echo 'ps -auxwww'"
755
+ }
756
+
757
+ Facter["id"].add { |obj|
758
+ obj.tag("operatingsystem","=","Linux")
759
+ obj.code = "whoami"
760
+ }
761
+ end
762
+
763
+ Facter.load
764
+ end
765
+
766
+ # try to load a local fact library, if there happens to be one
767
+ begin
768
+ require 'facter/local'
769
+ rescue LoadError
770
+ # no worries
771
+ end