facter 1.3.8 → 1.5

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 (46) hide show
  1. data/CHANGELOG +68 -0
  2. data/README +1 -1
  3. data/Rakefile +2 -1
  4. data/bin/facter +16 -11
  5. data/lib/facter.rb +55 -1001
  6. data/lib/facter/Cfkey.rb +42 -0
  7. data/lib/facter/architecture.rb +14 -0
  8. data/lib/facter/domain.rb +64 -0
  9. data/lib/facter/facterversion.rb +3 -0
  10. data/lib/facter/fqdn.rb +10 -0
  11. data/lib/facter/hardwareisa.rb +4 -0
  12. data/lib/facter/hardwaremodel.rb +13 -0
  13. data/lib/facter/hostname.rb +25 -0
  14. data/lib/facter/id.rb +4 -0
  15. data/lib/facter/ipaddress.rb +151 -0
  16. data/lib/facter/iphostnumber.rb +18 -0
  17. data/lib/facter/ipmess.rb +64 -74
  18. data/lib/facter/kernel.rb +3 -0
  19. data/lib/facter/kernelrelease.rb +8 -0
  20. data/lib/facter/lsb.rb +37 -0
  21. data/lib/facter/lsbmajdistrelease.rb +15 -0
  22. data/lib/facter/macaddress.rb +65 -0
  23. data/lib/facter/macosx.rb +25 -55
  24. data/lib/facter/manufacturer.rb +7 -45
  25. data/lib/facter/memory.rb +26 -49
  26. data/lib/facter/netmask.rb +17 -0
  27. data/lib/facter/operatingsystem.rb +37 -0
  28. data/lib/facter/operatingsystemrelease.rb +63 -0
  29. data/lib/facter/processor.rb +36 -14
  30. data/lib/facter/ps.rb +8 -0
  31. data/lib/facter/puppetversion.rb +10 -0
  32. data/lib/facter/rubysitedir.rb +8 -0
  33. data/lib/facter/rubyversion.rb +3 -0
  34. data/lib/facter/ssh.rb +33 -0
  35. data/lib/facter/uniqueid.rb +4 -0
  36. data/lib/facter/util/collection.rb +126 -0
  37. data/lib/facter/util/confine.rb +41 -0
  38. data/lib/facter/util/fact.rb +122 -0
  39. data/lib/facter/util/ip.rb +98 -0
  40. data/lib/facter/util/loader.rb +96 -0
  41. data/lib/facter/util/macosx.rb +50 -0
  42. data/lib/facter/util/manufacturer.rb +39 -0
  43. data/lib/facter/util/memory.rb +54 -0
  44. data/lib/facter/util/netmask.rb +36 -0
  45. data/lib/facter/util/resolution.rb +125 -0
  46. metadata +76 -34
data/CHANGELOG CHANGED
@@ -1,3 +1,71 @@
1
+ 1.5:
2
+ Fixed #1400 - OperatingSystemRelease should now work on CentOS
3
+
4
+ Changed 'timeout' option to 'limit' to avoid scope issue
5
+
6
+ Fixes #1376 - Display memory facts for AIX
7
+
8
+ Fixes #1334 - Forced Facter to use LANG=C
9
+
10
+ Fixes #1357 - Change ps syntax for OSX and BSD
11
+
12
+ Set the timeout on the AIX kernelrelease fact to 5 seconds.
13
+
14
+ Refactored so each fact resolution can specify a separate timeout,
15
+ but the default is still 0.5.
16
+
17
+ Refactered ipmess.rb and util/ip.rb to support separate *BSD logic for
18
+ *BSD aliased interfaces.
19
+
20
+ Updated dmidecode facts fixing ticket #60
21
+
22
+ Added AIX support for some facts
23
+
24
+ Add lsbmajdistrelease fact for CentOS and Red Hat
25
+
26
+ Updated Red Hat spec file for new version
27
+ The 'facter' executable now has an option (-p|--puppet) for loading the
28
+ Puppet libraries, which gives it access to Puppet's facts.
29
+
30
+ Added autoloading to Facter with a default of not loading all facts,
31
+ which results in a significant speedup when only one fact is sought.
32
+ Facts are autoloaded in either a single file named after the fact or
33
+ in any file in a directory named after the fact.
34
+
35
+ Significantly refactored Facter's internals, including creating tests
36
+ for all internal classes.
37
+
38
+ A netmask fact has been added closing ticket #46. It only returns the
39
+ netmask of the primary interface (in the same behaviour as the ipaddress
40
+ and macaddress facts).
41
+
42
+ Facts to return multiple interfaces on a host have also been updated.
43
+ If you have multiple interfaces on Linux, *BSD, or Solaris/SunOS you will
44
+ now get facts for each interface's IP address, MAC address and netmask.
45
+ The facts will be structured like:
46
+ ipaddress_int = 10.0.0.x
47
+ macaddress_int = xx:xx:xx:xx
48
+ netmask_int = 255.255.255.0
49
+
50
+ Facter now identifies Ubuntu hosts and their releases using the
51
+ operatingsystem and operatingsystemrelease facts.
52
+
53
+ The Debian operatingsystemrelease fact now correctly returns the current
54
+ Debian release.
55
+
56
+ Fixed ticket #48 - ioperatingsystem and operatingsystemrelease for CentOS
57
+
58
+ Fixed ticket #44 and allowed support for Xen multiple interfaces and aliased
59
+ interfaces. Supports both Linux and *BSD.
60
+
61
+ Added interfaces fact to add as index for ip/MAC address facts
62
+
63
+ Added Mandrake support for operatingsystem fact - closed ticket #47
64
+
65
+ Fixed ticket #45
66
+
67
+ Added netmask.rb closing ticket #46
68
+
1
69
  1.3.8:
2
70
  Fixed Rdoc::usage bug on CentOS 5 - closed Puppet #753 and Facter #40
3
71
 
data/README CHANGED
@@ -6,5 +6,5 @@ processors, etc.
6
6
  It currently cannot collect very much information, but it is architected to be
7
7
  both OS and OS version specific.
8
8
 
9
- See bin/facter or http://reductivelabs.com/project/enhost for an example of the
9
+ See bin/facter or http://reductivelabs.com/trac/enhost for an example of the
10
10
  interface.
data/Rakefile CHANGED
@@ -35,6 +35,8 @@ project.mkgemtask do |gem|
35
35
  gem.bindir = "bin" # Use these for applications.
36
36
  gem.executables = ["facter"]
37
37
  gem.default_executable = "facter"
38
+
39
+ gem.author = "Luke Kanies"
38
40
  end
39
41
 
40
42
  if project.has?(:epm)
@@ -43,4 +45,3 @@ if project.has?(:epm)
43
45
  task.rubylibs = FileList.new('lib/**/*')
44
46
  end
45
47
  end
46
- # $Id$
data/bin/facter CHANGED
@@ -6,7 +6,7 @@
6
6
  #
7
7
  # = Usage
8
8
  #
9
- # facter [-d|--debug] [-h|--help] [-v|--version] [-y|--yaml] [fact] [fact] [...]
9
+ # facter [-d|--debug] [-h|--help] [-p|--puppet] [-v|--version] [-y|--yaml] [fact] [fact] [...]
10
10
  #
11
11
  # = Description
12
12
  #
@@ -24,6 +24,9 @@
24
24
  # help::
25
25
  # Print this help message
26
26
  #
27
+ # puppet::
28
+ # Load the Puppet libraries, thus allowing Facter to load Puppet-specific facts.
29
+ #
27
30
  # version::
28
31
  # Print the version and exit.
29
32
  #
@@ -64,7 +67,8 @@ result = GetoptLong.new(
64
67
  [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
65
68
  [ "--debug", "-d", GetoptLong::NO_ARGUMENT ],
66
69
  [ "--yaml", "-y", GetoptLong::NO_ARGUMENT ],
67
- [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ]
70
+ [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ],
71
+ [ "--puppet", "-p", GetoptLong::NO_ARGUMENT ]
68
72
  )
69
73
 
70
74
  options = {
@@ -74,8 +78,14 @@ options = {
74
78
  result.each { |opt,arg|
75
79
  case opt
76
80
  when "--version"
77
- puts "%s" % Facter.version
78
- exit
81
+ puts "%s" % Facter.version
82
+ exit
83
+ when "--puppet"
84
+ begin
85
+ require 'puppet'
86
+ rescue LoadError => detail
87
+ $stderr.puts "Could not load Puppet: %s" % detail
88
+ end
79
89
  when "--yaml"
80
90
  options[:yaml] = true
81
91
  when "--debug"
@@ -107,13 +117,10 @@ ARGV.each { |item|
107
117
  names.push item
108
118
  }
109
119
 
110
- facts = {}
111
-
112
120
  if names.empty?
113
- Facter.each { |name,fact|
114
- facts[name] = fact
115
- }
121
+ facts = Facter.to_hash
116
122
  else
123
+ facts = {}
117
124
  names.each { |name|
118
125
  begin
119
126
  facts[name] = Facter.value(name)
@@ -139,5 +146,3 @@ facts.sort { |a, b| a[0].to_s <=> b[0].to_s }.each { |name,value|
139
146
  puts "%s => %s" % [name,value]
140
147
  end
141
148
  }
142
-
143
- # $Id: facter,v 1.1.1.1 2004/03/21 21:06:27 luke Exp $
@@ -17,11 +17,17 @@
17
17
  #
18
18
  #--
19
19
 
20
- class Facter
20
+ module Facter
21
+ # This is just so the other classes have the constant.
22
+ module Util; end
23
+
24
+ require 'facter/util/fact'
25
+ require 'facter/util/collection'
26
+
21
27
  include Comparable
22
28
  include Enumerable
23
29
 
24
- FACTERVERSION = '1.3.8'
30
+ FACTERVERSION = '1.5'
25
31
  # = Facter
26
32
  # Functions as a hash of 'facts' you might care about about your
27
33
  # system, such as mac address, IP address, Video card, etc.
@@ -35,23 +41,23 @@ class Facter
35
41
  # puts Facter['operatingsystem']
36
42
  #
37
43
 
44
+ # Set LANG to force i18n to C
45
+ #
46
+ ENV['LANG'] = 'C'
38
47
 
39
- @@facts = Hash.new { |hash, key|
40
- key = key.to_s.downcase.intern
41
- if hash.include?(key)
42
- hash[key]
43
- else
44
- nil
45
- end
46
- }
47
48
  GREEN = ""
48
49
  RESET = ""
49
50
  @@debug = 0
50
51
 
51
- attr_accessor :name, :searching, :ldapname
52
-
53
52
  # module methods
54
53
 
54
+ def self.collection
55
+ unless defined?(@collection) and @collection
56
+ @collection = Facter::Util::Collection.new
57
+ end
58
+ @collection
59
+ end
60
+
55
61
  # Return the version of the library.
56
62
  def self.version
57
63
  return FACTERVERSION
@@ -70,41 +76,41 @@ class Facter
70
76
  # Return a fact object by name. If you use this, you still have to call
71
77
  # 'value' on it to retrieve the actual value.
72
78
  def self.[](name)
73
- @@facts[name]
79
+ collection.fact(name)
74
80
  end
75
81
 
76
- # Add a resolution mechanism for a named fact. This does not distinguish
77
- # between adding a new fact and adding a new way to resolve a fact.
78
- def self.add(name, &block)
79
- fact = nil
80
-
81
- unless fact = @@facts[name]
82
- fact = Facter.new(name)
82
+ class << self
83
+ [:fact, :flush, :list, :value].each do |method|
84
+ define_method(method) do |*args|
85
+ collection.send(method, *args)
86
+ end
83
87
  end
84
88
 
85
- unless block
86
- return fact
89
+ [:list, :to_hash].each do |method|
90
+ define_method(method) do |*args|
91
+ collection.load_all
92
+ collection.send(method, *args)
93
+ end
87
94
  end
95
+ end
88
96
 
89
- fact.add(&block)
90
97
 
91
- return fact
98
+ # Add a resolution mechanism for a named fact. This does not distinguish
99
+ # between adding a new fact and adding a new way to resolve a fact.
100
+ def self.add(name, options = {}, &block)
101
+ collection.add(name, options, &block)
92
102
  end
93
103
 
94
- class << self
95
- include Enumerable
96
- # Iterate across all of the facts.
97
- def each
98
- @@facts.each { |name,fact|
99
- if fact.suitable?
100
- value = fact.value
101
- unless value.nil?
102
- yield name.to_s, fact.value
103
- end
104
- end
105
- }
104
+ def self.each
105
+ # Make sure all facts are loaded.
106
+ collection.load_all
107
+
108
+ collection.each do |*args|
109
+ yield(*args)
106
110
  end
111
+ end
107
112
 
113
+ class << self
108
114
  # Allow users to call fact names directly on the Facter class,
109
115
  # either retrieving the value or comparing it to an existing value.
110
116
  def method_missing(name, *args)
@@ -114,7 +120,7 @@ class Facter
114
120
  name = name.to_s.sub(/\?$/,'')
115
121
  end
116
122
 
117
- if fact = @@facts[name]
123
+ if fact = @collection.fact(name)
118
124
  if question
119
125
  value = fact.value.downcase
120
126
  args.each do |arg|
@@ -130,7 +136,7 @@ class Facter
130
136
  end
131
137
  else
132
138
  # Else, fail like a normal missing method.
133
- return super
139
+ raise NoMethodError, "Could not find fact '%s'" % name
134
140
  end
135
141
  end
136
142
  end
@@ -167,977 +173,25 @@ class Facter
167
173
  end
168
174
  end
169
175
 
170
- # Flush all cached values.
171
- def self.flush
172
- @@facts.each { |name, fact| fact.flush }
173
- end
174
-
175
- # Return a list of all of the facts.
176
- def self.list
177
- return @@facts.keys
178
- end
179
-
180
176
  # Remove them all.
181
177
  def self.reset
182
- @@facts.clear
183
- end
184
-
185
- # Return a hash of all of our facts.
186
- def self.to_hash(*tags)
187
- @@facts.inject({}) do |h, ary|
188
- if ary[1].suitable? and (tags.empty? or ary[1].tagged?(*tags))
189
- value = ary[1].value
190
- if value
191
- # For backwards compatibility, convert the fact name to a string.
192
- h[ary[0].to_s] = value
193
- end
194
- end
195
- h
196
- end
197
- end
198
-
199
- def self.value(name)
200
- if fact = @@facts[name]
201
- fact.value
202
- else
203
- nil
204
- end
205
- end
206
-
207
- # Compare one value to another.
208
- def <=>(other)
209
- return self.value <=> other
210
- end
211
-
212
- # Are we the same? Used for case statements.
213
- def ===(value)
214
- self.value == value
215
- end
216
-
217
- # Create a new fact, with no resolution mechanisms.
218
- def initialize(name)
219
- @name = name.to_s.downcase.intern
220
- if @@facts.include?(@name)
221
- raise ArgumentError, "A fact named %s already exists" % @name
222
- else
223
- @@facts[@name] = self
224
- end
225
-
226
- @resolves = []
227
- @tags = []
228
- @searching = false
229
-
230
- @value = nil
231
-
232
- @ldapname = name.to_s
233
- end
234
-
235
- # Add a new resolution mechanism. This requires a block, which will then
236
- # be evaluated in the context of the new mechanism.
237
- def add(&block)
238
- unless block_given?
239
- raise ArgumentError, "You must pass a block to Fact<instance>.add"
240
- end
241
-
242
- resolve = Resolution.new(@name)
243
-
244
- resolve.fact = self
245
-
246
- resolve.instance_eval(&block)
247
-
248
- # skip resolves that will never be suitable for us
249
- unless resolve.suitable?
250
- return
251
- end
252
-
253
- # insert resolves in order of number of confinements
254
- inserted = false
255
- @resolves.each_with_index { |r,index|
256
- if resolve.length > r.length
257
- @resolves.insert(index,resolve)
258
- inserted = true
259
- break
260
- end
261
- }
262
-
263
- unless inserted
264
- @resolves.push resolve
265
- end
266
- end
267
-
268
- # Return a count of resolution mechanisms available.
269
- def count
270
- return @resolves.length
178
+ @collection = nil
271
179
  end
272
180
 
273
- # Iterate across all of the fact resolution mechanisms and yield each in
274
- # turn. These are inserted in order of most confinements.
275
- def each
276
- @resolves.each { |r| yield r }
277
- end
278
-
279
- # Flush any cached values.
280
- def flush
281
- @value = nil
282
- @suitable = nil
283
- end
284
-
285
- # Is this fact suitable for finding answers on this host? This is used
286
- # to throw away any initially unsuitable mechanisms.
287
- def suitable?
288
- if @resolves.length == 0
289
- return false
290
- end
291
-
292
- unless defined? @suitable or (defined? @suitable and @suitable.nil?)
293
- @suitable = false
294
- @resolves.each { |resolve|
295
- if resolve.suitable?
296
- @suitable = true
297
- break
298
- end
299
- }
300
- end
301
-
302
- return @suitable
303
- end
304
-
305
- # Add one ore more tags
306
- def tag(*tags)
307
- tags.each do |t|
308
- t = t.to_s.downcase.intern
309
- @tags << t unless @tags.include?(t)
310
- end
311
- end
312
-
313
- # Is our fact tagged with all of the specified tags?
314
- def tagged?(*tags)
315
- tags.each do |t|
316
- unless @tags.include? t.to_s.downcase.intern
317
- return false
318
- end
319
- end
320
-
321
- return true
322
- end
323
-
324
- def tags
325
- @tags.dup
326
- end
327
-
328
- # Return the value for a given fact. Searches through all of the mechanisms
329
- # and returns either the first value or nil.
330
- def value
331
- unless @value
332
- # make sure we don't get stuck in recursive dependency loops
333
- if @searching
334
- Facter.debug "Caught recursion on %s" % @name
335
-
336
- # return a cached value if we've got it
337
- if @value
338
- return @value
339
- else
340
- return nil
341
- end
342
- end
343
- @value = nil
344
- foundsuits = false
345
-
346
- if @resolves.length == 0
347
- Facter.debug "No resolves for %s" % @name
348
- return nil
349
- end
350
-
351
- @searching = true
352
- @resolves.each { |resolve|
353
- #Facter.debug "Searching resolves for %s" % @name
354
- if resolve.suitable?
355
- @value = resolve.value
356
- foundsuits = true
357
- end
358
- unless @value.nil? or @value == ""
359
- break
360
- end
361
- }
362
- @searching = false
363
-
364
- unless foundsuits
365
- Facter.debug "Found no suitable resolves of %s for %s" %
366
- [@resolves.length,@name]
367
- end
368
- end
369
-
370
- if @value.nil?
371
- # nothing
372
- Facter.debug("value for %s is still nil" % @name)
373
- return nil
374
- else
375
- return @value
376
- end
181
+ # Load all of the default facts, and then everything from disk.
182
+ def self.loadfacts
183
+ collection.load_all
377
184
  end
378
185
 
379
- # An actual fact resolution mechanism. These are largely just chunks of
380
- # code, with optional confinements restricting the mechanisms to only working on
381
- # specific systems. Note that the confinements are always ANDed, so any
382
- # confinements specified must all be true for the resolution to be
383
- # suitable.
384
- class Resolution
385
- attr_accessor :interpreter, :code, :name, :fact
386
-
387
- def Resolution.have_which
388
- if @have_which.nil?
389
- %x{which which 2>/dev/null}
390
- @have_which = ($? == 0)
391
- end
392
- @have_which
393
- end
394
-
395
- # Execute a chunk of code.
396
- def Resolution.exec(code, interpreter = "/bin/sh")
397
- if interpreter == "/bin/sh"
398
- binary = code.split(/\s+/).shift
399
-
400
- if have_which
401
- path = nil
402
- if binary !~ /^\//
403
- path = %x{which #{binary} 2>/dev/null}.chomp
404
- if path == ""
405
- # we don't have the binary necessary
406
- return nil
407
- end
408
- else
409
- path = binary
410
- end
411
-
412
- unless FileTest.exists?(path)
413
- # our binary does not exist
414
- return nil
415
- end
416
- end
417
-
418
- out = nil
419
- begin
420
- out = %x{#{code}}.chomp
421
- rescue => detail
422
- $stderr.puts detail
423
- return nil
424
- end
425
- if out == ""
426
- return nil
427
- else
428
- return out
429
- end
430
- else
431
- raise ArgumentError,
432
- "non-sh interpreters are not currently supported"
433
- end
434
- end
435
-
436
- # Add a new confine to the resolution mechanism.
437
- def confine(*args)
438
- if args[0].is_a? Hash
439
- args[0].each do |fact, values|
440
- @confines.push Confine.new(fact,*values)
441
- end
442
- else
443
- fact = args.shift
444
- @confines.push Confine.new(fact,*args)
445
- end
446
- end
447
-
448
- # Create a new resolution mechanism.
449
- def initialize(name)
450
- @name = name
451
- @confines = []
452
- @value = nil
453
- end
454
-
455
- # Return the number of confines.
456
- def length
457
- @confines.length
458
- end
459
-
460
- # Set our code for returning a value.
461
- def setcode(string = nil, interp = nil, &block)
462
- if string
463
- @code = string
464
- @interpreter = interp || "/bin/sh"
465
- else
466
- unless block_given?
467
- raise ArgumentError, "You must pass either code or a block"
468
- end
469
- @code = block
470
- end
471
- end
472
-
473
- # Set the name by which this parameter is known in LDAP. The default
474
- # is just the fact name.
475
- def setldapname(name)
476
- @fact.ldapname = name.to_s
477
- end
478
-
479
- # Is this resolution mechanism suitable on the system in question?
480
- def suitable?
481
- unless defined? @suitable
482
- @suitable = true
483
- if @confines.length == 0
484
- return true
485
- end
486
- @confines.each { |confine|
487
- unless confine.true?
488
- @suitable = false
489
- end
490
- }
491
- end
492
-
493
- return @suitable
494
- end
495
-
496
- # Set tags on our parent fact.
497
- def tag(*values)
498
- @fact.tag(*values)
499
- end
500
-
501
- def to_s
502
- return self.value()
503
- end
504
-
505
- # How we get a value for our resolution mechanism.
506
- def value
507
- value = nil
508
-
509
- if @code.is_a?(Proc)
510
- value = @code.call()
511
- else
512
- unless defined? @interpreter
513
- @interpreter = "/bin/sh"
514
- end
515
- if @code.nil?
516
- $stderr.puts "Code for %s is nil" % @name
517
- else
518
- value = Resolution.exec(@code,@interpreter)
519
- end
520
- end
521
-
522
- if value == ""
523
- value = nil
524
- end
525
-
526
- return value
527
- end
186
+ @search_path = []
528
187
 
188
+ # Register a directory to search through.
189
+ def self.search(*dirs)
190
+ @search_path += dirs
529
191
  end
530
192
 
531
- # A restricting tag for fact resolution mechanisms. The tag must be true
532
- # for the resolution mechanism to be suitable.
533
- class Confine
534
- attr_accessor :fact, :op, :value
535
-
536
- # Add the tag. Requires the fact name, an operator, and the value
537
- # we're comparing to.
538
- def initialize(fact, *values)
539
- fact = fact.to_s if fact.is_a? Symbol
540
- @fact = fact
541
- @values = values.collect do |value|
542
- if value.is_a? String
543
- value
544
- else
545
- value.to_s
546
- end
547
- end
548
- end
549
-
550
- def to_s
551
- return "'%s' '%s'" % [@fact, @values.join(",")]
552
- end
553
-
554
- # Evaluate the fact, returning true or false.
555
- def true?
556
- fact = nil
557
- unless fact = Facter[@fact]
558
- Facter.debug "No fact for %s" % @fact
559
- return false
560
- end
561
- value = fact.value
562
-
563
- if value.nil?
564
- return false
565
- end
566
-
567
- retval = @values.find { |v|
568
- if value.downcase == v.downcase
569
- break true
570
- end
571
- }
572
-
573
- if retval
574
- retval = true
575
- else
576
- retval = false
577
- end
578
-
579
- return retval || false
580
- end
193
+ # Return our registered search directories.
194
+ def self.search_path
195
+ @search_path.dup
581
196
  end
582
-
583
- # Load all of the default facts
584
- def self.loadfacts
585
- Facter.add(:facterversion) do
586
- setcode { FACTERVERSION.to_s }
587
- end
588
-
589
- Facter.add(:rubyversion) do
590
- setcode { RUBY_VERSION.to_s }
591
- end
592
-
593
- Facter.add(:puppetversion) do
594
- setcode {
595
- begin
596
- require 'puppet'
597
- Puppet::PUPPETVERSION.to_s
598
- rescue LoadError
599
- nil
600
- end
601
- }
602
- end
603
-
604
- Facter.add :rubysitedir do
605
- setcode do
606
- version = RUBY_VERSION.to_s.sub(/\.\d+$/, '')
607
- $:.find do |dir|
608
- dir =~ /#{File.join("site_ruby", version)}$/
609
- end
610
- end
611
- end
612
-
613
- Facter.add(:kernel) do
614
- setcode 'uname -s'
615
- end
616
-
617
- Facter.add(:kernelrelease) do
618
- setcode 'uname -r'
619
- end
620
-
621
- { "LSBRelease" => %r{^LSB Version:\t(.*)$},
622
- "LSBDistId" => %r{^Distributor ID:\t(.*)$},
623
- "LSBDistRelease" => %r{^Release:\t(.*)$},
624
- "LSBDistDescription" => %r{^Description:\t(.*)$},
625
- "LSBDistCodeName" => %r{^Codename:\t(.*)$}
626
- }.each do |fact, pattern|
627
- Facter.add(fact) do
628
- setcode do
629
- unless defined?(@@lsbdata) and defined?(@@lsbtime) and (Time.now.to_i - @@lsbtime.to_i < 5)
630
- type = nil
631
- @@lsbtime = Time.now
632
- @@lsbdata = Resolution.exec('lsb_release -a 2>/dev/null')
633
- end
634
- if pattern.match(@@lsbdata)
635
- $1
636
- else
637
- nil
638
- end
639
- end
640
- end
641
- end
642
-
643
- Facter.add(:operatingsystem) do
644
- confine :kernel => :sunos
645
- setcode do "Solaris" end
646
- end
647
-
648
- Facter.add(:operatingsystem) do
649
- confine :kernel => :linux
650
- setcode do
651
- if FileTest.exists?("/etc/debian_version")
652
- "Debian"
653
- elsif FileTest.exists?("/etc/gentoo-release")
654
- "Gentoo"
655
- elsif FileTest.exists?("/etc/fedora-release")
656
- "Fedora"
657
- elsif FileTest.exists?("/etc/mandriva-release")
658
- "Mandriva"
659
- elsif FileTest.exists?("/etc/redhat-release")
660
- txt = File.read("/etc/redhat-release")
661
- if txt =~ /centos/i
662
- "CentOS"
663
- else
664
- "RedHat"
665
- end
666
- elsif FileTest.exists?("/etc/SuSE-release")
667
- "SuSE"
668
- end
669
- end
670
- end
671
-
672
- Facter.add(:operatingsystem) do
673
- # Default to just returning the kernel as the operating system
674
- setcode do Facter[:kernel].value end
675
- end
676
-
677
- Facter.add(:operatingsystemrelease) do
678
- confine :operatingsystem => :fedora
679
- setcode do
680
- File::open("/etc/fedora-release", "r") do |f|
681
- line = f.readline.chomp
682
- if line =~ /\(Rawhide\)$/
683
- "Rawhide"
684
- elsif line =~ /release (\d+)/
685
- $1
686
- end
687
- end
688
- end
689
- end
690
-
691
- Facter.add(:operatingsystemrelease) do
692
- confine :operatingsystem => :redhat
693
- setcode do
694
- File::open("/etc/redhat-release", "r") do |f|
695
- line = f.readline.chomp
696
- if line =~ /\(Rawhide\)$/
697
- "Rawhide"
698
- elsif line =~ /release (\d+)/
699
- $1
700
- end
701
- end
702
- end
703
- end
704
-
705
- Facter.add(:operatingsystemrelease) do
706
- setcode do Facter[:kernelrelease].value end
707
- end
708
-
709
- Facter.add(:hardwaremodel) do
710
- setcode 'uname -m'
711
- end
712
-
713
- Facter.add(:architecture) do
714
- confine :kernel => :linux
715
- setcode do
716
- model = Facter.hardwaremodel
717
- case model
718
- # most linuxen use "x86_64"
719
- when 'x86_64':
720
- Facter.operatingsystem == "Debian" ? "amd64" : model;
721
- when /(i[3456]86|pentium)/: "i386"
722
- else
723
- model
724
- end
725
- end
726
- end
727
-
728
- Facter.add(:Cfkey) do
729
- setcode do
730
- value = nil
731
- ["/usr/local/etc/cfkey.pub",
732
- "/etc/cfkey.pub",
733
- "/var/cfng/keys/localhost.pub",
734
- "/var/cfengine/ppkeys/localhost.pub",
735
- "/var/lib/cfengine/ppkeys/localhost.pub",
736
- "/var/lib/cfengine2/ppkeys/localhost.pub"
737
- ].each { |file|
738
- if FileTest.file?(file)
739
- File.open(file) { |openfile|
740
- value = openfile.readlines.reject { |line|
741
- line =~ /PUBLIC KEY/
742
- }.collect { |line|
743
- line.chomp
744
- }.join("")
745
- }
746
- end
747
- if value
748
- break
749
- end
750
- }
751
-
752
- value
753
- end
754
- end
755
-
756
- Facter.add(:domain) do
757
- setcode do
758
- # First force the hostname to be checked
759
- Facter.hostname
760
-
761
- # Now check to see if it set the domain
762
- if defined? $domain and ! $domain.nil?
763
- $domain
764
- else
765
- nil
766
- end
767
- end
768
- end
769
- # Look for the DNS domain name command first.
770
- Facter.add(:domain) do
771
- setcode do
772
- domain = Resolution.exec('dnsdomainname') or nil
773
- # make sure it's a real domain
774
- if domain and domain =~ /.+\..+/
775
- domain
776
- else
777
- nil
778
- end
779
- end
780
- end
781
- Facter.add(:domain) do
782
- setcode do
783
- domain = Resolution.exec('domainname') or nil
784
- # make sure it's a real domain
785
- if domain and domain =~ /.+\..+/
786
- domain
787
- else
788
- nil
789
- end
790
- end
791
- end
792
- Facter.add(:domain) do
793
- setcode do
794
- value = nil
795
- if FileTest.exists?("/etc/resolv.conf")
796
- File.open("/etc/resolv.conf") { |file|
797
- # is the domain set?
798
- file.each { |line|
799
- if line =~ /domain\s+(\S+)/
800
- value = $1
801
- break
802
- end
803
- }
804
- }
805
- ! value and File.open("/etc/resolv.conf") { |file|
806
- # is the search path set?
807
- file.each { |line|
808
- if line =~ /search\s+(\S+)/
809
- value = $1
810
- break
811
- end
812
- }
813
- }
814
- value
815
- else
816
- nil
817
- end
818
- end
819
- end
820
- Facter.add(:hostname) do
821
- setldapname "cn"
822
- setcode do
823
- hostname = nil
824
- name = Resolution.exec('hostname') or nil
825
- if name
826
- if name =~ /^([\w-]+)\.(.+)$/
827
- hostname = $1
828
- # the Domain class uses this
829
- $domain = $2
830
- else
831
- hostname = name
832
- end
833
- hostname
834
- else
835
- nil
836
- end
837
- end
838
- end
839
-
840
- Facter.add(:fqdn) do
841
- setcode do
842
- host = Facter.value(:hostname)
843
- domain = Facter.value(:domain)
844
- if host and domain
845
- [host, domain].join(".")
846
- else
847
- nil
848
- end
849
- end
850
- end
851
-
852
- Facter.add(:ipaddress) do
853
- setldapname "iphostnumber"
854
- setcode do
855
- require 'resolv'
856
-
857
- begin
858
- if hostname = Facter.hostname
859
- ip = Resolv.getaddress(hostname)
860
- unless ip == "127.0.0.1"
861
- ip
862
- end
863
- else
864
- nil
865
- end
866
- rescue Resolv::ResolvError
867
- nil
868
- rescue NoMethodError # i think this is a bug in resolv.rb?
869
- nil
870
- end
871
- end
872
- end
873
- Facter.add(:ipaddress) do
874
- setcode do
875
- if hostname = Facter.hostname
876
- # we need Hostname to exist for this to work
877
- host = nil
878
- if host = Resolution.exec("host #{hostname}")
879
- host = host.chomp.split(/\s/)
880
- if defined? list[-1] and
881
- list[-1] =~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/
882
- list[-1]
883
- end
884
- else
885
- nil
886
- end
887
- else
888
- nil
889
- end
890
- end
891
- end
892
-
893
- ["/etc/ssh","/usr/local/etc/ssh","/etc","/usr/local/etc"].each { |dir|
894
- {"SSHDSAKey" => "ssh_host_dsa_key.pub",
895
- "SSHRSAKey" => "ssh_host_rsa_key.pub"}.each { |name,file|
896
- Facter.add(name) do
897
- setcode do
898
- value = nil
899
- filepath = File.join(dir,file)
900
- if FileTest.file?(filepath)
901
- begin
902
- File.open(filepath) { |f|
903
- value = f.read.chomp.split(/\s+/)[1]
904
- }
905
- rescue
906
- value = nil
907
- end
908
- end
909
- value
910
- end # end of proc
911
- end # end of add
912
- } # end of hash each
913
- } # end of dir each
914
-
915
- Facter.add(:uniqueid) do
916
- setcode 'hostid', '/bin/sh'
917
- confine :operatingsystem => %w{Solaris Linux Fedora RedHat CentOS SuSE Debian Gentoo}
918
- end
919
-
920
- Facter.add(:hardwareisa) do
921
- setcode 'uname -p', '/bin/sh'
922
- confine :operatingsystem => %w{Solaris Linux Fedora RedHat CentOS SuSE Debian Gentoo FreeBSD OpenBSD NetBSD}
923
- end
924
-
925
- Facter.add(:macaddress) do
926
- confine :operatingsystem => %w{Solaris Linux Fedora RedHat CentOS SuSE Debian Gentoo}
927
- setcode do
928
- ether = []
929
- output = %x{/sbin/ifconfig -a}
930
- output.each {|s|
931
- ether.push($1) if s =~ /(?:ether|HWaddr) (\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/
932
- }
933
- ether[0]
934
- end
935
- end
936
-
937
- Facter.add(:macaddress) do
938
- confine :operatingsystem => %w{FreeBSD OpenBSD}
939
- setcode do
940
- ether = []
941
- output = %x{/sbin/ifconfig}
942
- output.each {|s|
943
- if s =~ /(?:ether|lladdr)\s+(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
944
- ether.push($1)
945
- end
946
- }
947
- ether[0]
948
- end
949
- end
950
-
951
- Facter.add(:macaddress) do
952
- confine :kernel => :darwin
953
- setcode do
954
- ether = nil
955
- output = %x{/sbin/ifconfig}
956
-
957
- output.split(/^\S/).each { |str|
958
- if str =~ /10baseT/ # we're wired
959
- str =~ /ether (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
960
- ether = $1
961
- end
962
- }
963
-
964
- ether
965
- end
966
- end
967
-
968
- Facter.add(:ipaddress) do
969
- confine :kernel => :linux
970
- setcode do
971
- ip = nil
972
- output = %x{/sbin/ifconfig}
973
-
974
- output.split(/^\S/).each { |str|
975
- if str =~ /inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
976
- tmp = $1
977
- unless tmp =~ /127\./
978
- ip = tmp
979
- break
980
- end
981
- end
982
- }
983
-
984
- ip
985
- end
986
- end
987
- Facter.add(:ipaddress) do
988
- confine :kernel => %w{FreeBSD OpenBSD solaris}
989
- setcode do
990
- ip = nil
991
- output = %x{/sbin/ifconfig}
992
-
993
- output.split(/^\S/).each { |str|
994
- if str =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
995
- tmp = $1
996
- unless tmp =~ /127\./
997
- ip = tmp
998
- break
999
- end
1000
- end
1001
- }
1002
-
1003
- ip
1004
- end
1005
- end
1006
- Facter.add(:ipaddress) do
1007
- confine :kernel => %w{NetBSD}
1008
- setcode do
1009
- ip = nil
1010
- output = %x{/sbin/ifconfig -a}
1011
-
1012
- output.split(/^\S/).each { |str|
1013
- if str =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
1014
- tmp = $1
1015
- unless tmp =~ /127\./
1016
- ip = tmp
1017
- break
1018
- end
1019
- end
1020
- }
1021
-
1022
- ip
1023
- end
1024
- end
1025
- Facter.add(:ipaddress) do
1026
- confine :kernel => %w{darwin}
1027
- setcode do
1028
- ip = nil
1029
- iface = ""
1030
- output = %x{/usr/sbin/netstat -rn}
1031
- if output =~ /^default\s*\S*\s*\S*\s*\S*\s*\S*\s*(\S*).*/
1032
- iface = $1
1033
- else
1034
- warn "Could not find a default route. Using first non-loopback interface"
1035
- end
1036
- if(iface != "")
1037
- output = %x{/sbin/ifconfig #{iface}}
1038
- else
1039
- output = %x{/sbin/ifconfig}
1040
- end
1041
-
1042
- output.split(/^\S/).each { |str|
1043
- if str =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
1044
- tmp = $1
1045
- unless tmp =~ /127\./
1046
- ip = tmp
1047
- break
1048
- end
1049
- end
1050
- }
1051
-
1052
- ip
1053
- end
1054
- end
1055
- Facter.add(:hostname) do
1056
- confine :kernel => :darwin, :kernelrelease => "R7"
1057
- setcode do
1058
- %x{/usr/sbin/scutil --get LocalHostName}
1059
- end
1060
- end
1061
- Facter.add(:iphostnumber) do
1062
- confine :kernel => :darwin, :kernelrelease => "R6"
1063
- setcode do
1064
- %x{/usr/sbin/scutil --get LocalHostName}
1065
- end
1066
- end
1067
- Facter.add(:iphostnumber) do
1068
- confine :kernel => :darwin, :kernelrelease => "R6"
1069
- setcode do
1070
- ether = nil
1071
- output = %x{/sbin/ifconfig}
1072
-
1073
- output =~ /HWaddr (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
1074
- ether = $1
1075
-
1076
- ether
1077
- end
1078
- end
1079
-
1080
- Facter.add(:ps) do
1081
- setcode do 'ps -ef' end
1082
- end
1083
-
1084
- Facter.add(:ps) do
1085
- confine :operatingsystem => %w{FreeBSD NetBSD OpenBSD Darwin}
1086
- setcode do 'ps -auxwww' end
1087
- end
1088
-
1089
- Facter.add(:id) do
1090
- #confine :kernel => %w{Solaris Linux}
1091
- confine :operatingsystem => %w{Solaris Linux Fedora RedHat CentOS SuSE Debian Gentoo}
1092
- setcode "whoami"
1093
- end
1094
-
1095
- locals = []
1096
-
1097
- # Now find all our loadable facts
1098
- factdirs = [] # All the places to check for facts
1099
-
1100
- # See if we can find any other facts in the regular Ruby lib
1101
- # paths
1102
- $:.each do |dir|
1103
- fdir = File.join(dir, "facter")
1104
- if FileTest.exists?(fdir) and FileTest.directory?(fdir)
1105
- factdirs.push(fdir)
1106
- end
1107
- end
1108
- # Also check anything in 'FACTERLIB'
1109
- if ENV['FACTERLIB']
1110
- ENV['FACTERLIB'].split(":").each do |fdir|
1111
- factdirs.push(fdir)
1112
- end
1113
- end
1114
- factdirs.each do |fdir|
1115
- Dir.glob("#{fdir}/*.rb").each do |file|
1116
- # Load here, rather than require, because otherwise
1117
- # the facts won't get reloaded if someone calls
1118
- # "loadfacts". Really only important in testing, but,
1119
- # well, it's important in testing.
1120
- begin
1121
- load file
1122
- rescue => detail
1123
- warn "Could not load %s: %s" %
1124
- [file, detail]
1125
- end
1126
- end
1127
- end
1128
-
1129
-
1130
- # Now try to get facts from the environment
1131
- ENV.each do |name, value|
1132
- if name =~ /^facter_?(\w+)$/i
1133
- Facter.add($1) do
1134
- setcode { value }
1135
- end
1136
- end
1137
- end
1138
- end
1139
-
1140
- Facter.loadfacts
1141
197
  end
1142
-
1143
- # $Id$