Class Facter
In: lib/facter.rb
Parent: Object

Methods

<=>   []   add   add   count   debug   debugging   each   each   list   load   new   os   release   reset   suitable?   value   version  

Included Modules

Comparable Enumerable Enumerable

Classes and Modules

Class Facter::Resolution
Class Facter::Tag

Constants

FACTERVERSION = '1.0.2'
GREEN = ""
RESET = ""

Attributes

hardware  [RW] 
name  [RW] 
os  [RW] 
osrel  [RW] 
searching  [RW] 

Public Class methods

[Source]

    # File lib/facter.rb, line 58
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

[Source]

    # File lib/facter.rb, line 68
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

[Source]

    # File lib/facter.rb, line 48
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

[Source]

     # File lib/facter.rb, line 113
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

[Source]

    # File lib/facter.rb, line 90
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

[Source]

     # File lib/facter.rb, line 147
147:     def Facter.list
148:         return @@facts.keys
149:     end

Load all of the default facts

[Source]

     # File lib/facter.rb, line 448
448:     def Facter.load
449:         Facter["OperatingSystem"].add { |obj|
450:             obj.code = 'uname -s'
451:         }
452: 
453:         Facter["OperatingSystemRelease"].add { |obj|
454:             obj.code = 'uname -r'
455:         }
456: 
457:         Facter["HardwareModel"].add { |obj|
458:             obj.code = 'uname -m'
459:             #obj.os = "SunOS"
460:             #obj.tag("operatingsystem","=","SunOS")
461:         }
462: 
463:         Facter["CfKey"].add { |obj|
464:             obj.code = proc {
465:                 value = nil
466:                 ["/usr/local/etc/cfkey.pub",
467:                     "/etc/cfkey.pub",
468:                     "/var/cfng/keys/localhost.pub",
469:                     "/var/cfengine/ppkeys/localhost.pub"
470:                 ].each { |file|
471:                     if FileTest.file?(file)
472:                         File.open(file) { |openfile|
473:                             value = openfile.readlines.reject { |line|
474:                                 line =~ /PUBLIC KEY/
475:                             }.collect { |line|
476:                                 line.chomp
477:                             }.join("")
478:                         }
479:                     end
480:                     if value
481:                         break
482:                     end
483:                 }
484: 
485:                 value
486:             }
487:         }
488: 
489:         Facter["Domain"].add { |obj|
490:             obj.code = proc {
491:                 if defined? $domain and ! $domain.nil?
492:                     $domain
493:                 end
494:             }
495:         }
496:         Facter["Domain"].add { |obj|
497:             obj.code = proc {
498:                 domain = Resolution.exec('domainname') or return nil
499:                 # make sure it's a real domain
500:                 if domain =~ /.+\..+/
501:                     domain
502:                 else
503:                     nil
504:                 end
505:             }
506:         }
507:         Facter["Domain"].add { |obj|
508:             obj.code = proc {
509:                 value = nil
510:                 unless FileTest.exists?("/etc/resolv.conf")
511:                     return nil
512:                 end
513:                 File.open("/etc/resolv.conf") { |file|
514:                     # is the domain set?
515:                     file.each { |line|
516:                         if line =~ /domain\s+(\S+)/
517:                             value = $1
518:                             break
519:                         end
520:                     }
521:                 }
522:                 ! value and File.open("/etc/resolv.conf") { |file|
523:                     # is the search path set?
524:                     file.each { |line|
525:                         if line =~ /search\s+(\S+)/
526:                             value = $1
527:                             break
528:                         end
529:                     }
530:                 }
531:                 value
532:             }
533:         }
534:         Facter["Hostname"].add { |obj|
535:             obj.code = proc {
536:                 hostname = nil
537:                 name = Resolution.exec('hostname') or return nil
538:                 if name =~ /^([\w-]+)\.(.+)$/
539:                     hostname = $1
540:                     # the Domain class uses this
541:                     $domain = $2
542:                 else
543:                     hostname = name
544:                 end
545:                 hostname
546:             }
547:         }
548: 
549:         Facter["IPHostNumber"].add { |obj|
550:             obj.code = proc {
551:                 require 'resolv'
552: 
553:                 begin
554:                     hostname = Facter["hostname"].value or return nil
555:                     ip = Resolv.getaddress(hostname)
556:                     unless ip == "127.0.0.1"
557:                         ip
558:                     end
559:                 rescue Resolv::ResolvError
560:                     nil
561:                 rescue NoMethodError # i think this is a bug in resolv.rb?
562:                     nil
563:                 end
564:             }
565:         }
566:         Facter["IPHostNumber"].add { |obj|
567:             obj.code = proc {
568:                 hostname = Facter["hostname"].value or return nil
569:                 # we need Hostname to exist for this to work
570:                 list = Resolution.exec("host #{hostname}").chomp.split(/\s/) or
571:                     return nil
572: 
573:                 if defined? list[-1] and list[-1] =~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/
574:                     list[-1]
575:                 end
576:             }
577:         }
578: 
579:         ["/etc/ssh","/usr/local/etc/ssh","/etc","/usr/local/etc"].each { |dir|
580:             {"SSHDSAKey" => "ssh_host_dsa_key.pub",
581:                     "SSHRSAKey" => "ssh_host_rsa_key.pub"}.each { |name,file|
582:                 Facter[name].add { |obj|
583:                     obj.code = proc {
584:                         value = nil
585:                         filepath = File.join(dir,file)
586:                         if FileTest.file?(filepath)
587:                             begin
588:                                 value = File.open(filepath).read.chomp
589:                             rescue
590:                                 return nil
591:                             end
592:                         end
593:                         return value
594:                     } # end of proc
595:                 } # end of add
596:             } # end of hash each
597:         } # end of dir each
598: 
599:         Facter["UniqueId"].add { |obj|
600:             obj.code = 'hostid'
601:             obj.interpreter = '/bin/sh'
602:             obj.tag("operatingsystem","=","SunOS")
603:             #obj.os = "SunOS"
604:         }
605:         Facter["HardwareISA"].add { |obj|
606:             obj.code = 'uname -p'
607:             obj.interpreter = '/bin/sh'
608:             #obj.os = "SunOS"
609:             obj.tag("operatingsystem","=","SunOS")
610:         }
611:         Facter["MacAddress"].add { |obj|
612:             #obj.os = "SunOS"
613:             obj.tag("operatingsystem","=","SunOS")
614:             obj.code = proc {
615:                 ether = nil
616:                 output = %x{/sbin/ifconfig -a}
617: 
618:                 output =~ /ether (\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/
619:                 ether = $1
620: 
621:                 ether
622:             }
623:         }
624:         Facter["MacAddress"].add { |obj|
625:             #obj.os = "Darwin"
626:             obj.tag("operatingsystem","=","Darwin")
627:             obj.code = proc {
628:                 ether = nil
629:                 output = %x{/sbin/ifconfig}
630: 
631:                 output.split(/^\S/).each { |str|
632:                     if str =~ /10baseT/ # we're wired
633:                         str =~ /ether (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
634:                         ether = $1
635:                     end
636:                 }
637: 
638:                 ether
639:             }
640:         }
641:         Facter["IPHostnumber"].add { |obj|
642:             #obj.os = "Darwin"
643:             obj.tag("operatingsystem","=","Darwin")
644:             obj.code = proc {
645:                 ip = nil
646:                 output = %x{/sbin/ifconfig}
647: 
648:                 output.split(/^\S/).each { |str|
649:                     if str =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
650:                         tmp = $1
651:                         unless tmp =~ /127\./
652:                             ip = tmp
653:                             break
654:                         end
655:                     end
656:                 }
657: 
658:                 ip
659:             }
660:         }
661:         Facter["Hostname"].add { |obj|
662:             #obj.os = "Darwin"
663:             #obj.release = "R7"
664:             obj.tag("operatingsystem","=","Darwin")
665:             obj.tag("operatingsystemrelease","=","R7")
666:             obj.code = proc {
667:                 hostname = nil
668:                 File.open(
669:                     "/Library/Preferences/SystemConfiguration/preferences.plist"
670:                 ) { |file|
671:                     found = 0
672:                     file.each { |line|
673:                         if line =~ /ComputerName/i
674:                             found = 1
675:                             next
676:                         end
677:                         if found == 1
678:                             if line =~ /<string>([\w|-]+)<\/string>/
679:                                 hostname = $1
680:                                 break
681:                             end
682:                         end
683:                     }
684:                 }
685: 
686:                 if hostname != nil
687:                     hostname
688:                 end
689:             }
690:         }
691:         Facter["IPHostnumber"].add { |obj|
692:             #obj.os = "Darwin"
693:             #obj.release = "R6"
694:             obj.tag("operatingsystem","=","Darwin")
695:             obj.tag("operatingsystemrelease","=","R6")
696:             obj.code = proc {
697:                 hostname = nil
698:                 File.open(
699:                     "/var/db/SystemConfiguration/preferences.xml"
700:                 ) { |file|
701:                     found = 0
702:                     file.each { |line|
703:                         if line =~ /ComputerName/i
704:                             found = 1
705:                             next
706:                         end
707:                         if found == 1
708:                             if line =~ /<string>([\w|-]+)<\/string>/
709:                                 hostname = $1
710:                                 break
711:                             end
712:                         end
713:                     }
714:                 }
715: 
716:                 if hostname != nil
717:                     hostname
718:                 end
719:             }
720:         }
721:         Facter["IPHostnumber"].add { |obj|
722:             #obj.os = "Darwin"
723:             #obj.release = "R6"
724:             obj.tag("operatingsystem","=","Darwin")
725:             obj.tag("operatingsystemrelease","=","R6")
726:             obj.code = proc {
727:                 ether = nil
728:                 output = %x{/sbin/ifconfig}
729: 
730:                 output =~ /HWaddr (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
731:                 ether = $1
732: 
733:                 ether
734:             }
735:         }
736:         Facter["Distro"].add { |obj|
737:             #obj.os = "Linux"
738:             obj.tag("operatingsystem","=","Linux")
739:             obj.code = proc {
740:                 if FileTest.exists?("/etc/debian_version")
741:                     return "Debian"
742:                 elsif FileTest.exists?("/etc/gentoo-release")
743:                     return "Gentoo"
744:                 elsif FileTest.exists?("/etc/fedora-release")
745:                     return "Fedora"
746:                 elsif FileTest.exists?("/etc/redhat-release")
747:                     return "RedHat"
748:                 elsif FileTest.exists?("/etc/SuSE-release")
749:                     return "SuSE"
750:                 end
751:             }
752:         }
753:         Facter["ps"].add { |obj|
754:             obj.code = "echo 'ps -ef'"
755:         }
756:         Facter["ps"].add { |obj|
757:             obj.tag("operatingsystem","=","Darwin")
758:             obj.code = "echo 'ps -auxwww'"
759:         }
760: 
761:         Facter["id"].add { |obj|
762:             obj.tag("operatingsystem","=","Linux")
763:             obj.code = "whoami"
764:         }
765:     end

[Source]

     # File lib/facter.rb, line 171
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

[Source]

     # File lib/facter.rb, line 153
153:     def Facter.os
154:         return @@os
155:     end

[Source]

     # File lib/facter.rb, line 159
159:     def Facter.release
160:         return @@release
161:     end

[Source]

     # File lib/facter.rb, line 104
104:     def Facter.reset
105:         @@facts.each { |name,fact|
106:             @@facts.delete(name)
107:         }
108:     end

[Source]

    # File lib/facter.rb, line 44
44:     def Facter.version
45:         return FACTERVERSION
46:     end

Public Instance methods

[Source]

     # File lib/facter.rb, line 165
165:     def <=>(other)
166:         return self.value <=> other
167:     end

[Source]

     # File lib/facter.rb, line 189
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

[Source]

     # File lib/facter.rb, line 230
230:     def count
231:         return @resolves.length
232:     end

[Source]

     # File lib/facter.rb, line 216
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

[Source]

     # File lib/facter.rb, line 239
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

[Source]

     # File lib/facter.rb, line 257
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

[Validate]