| Class | Facter |
| In: |
lib/facter.rb
|
| Parent: | Object |
| FACTERVERSION | = | '1.0.2' |
| GREEN | = | "[0;32m" |
| RESET | = | "[0m" |
| hardware | [RW] | |
| name | [RW] | |
| os | [RW] | |
| osrel | [RW] | |
| searching | [RW] |
# 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
# 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
# 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
# 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
# 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
Load all of the default facts
# 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
# 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
# File lib/facter.rb, line 104
104: def Facter.reset
105: @@facts.each { |name,fact|
106: @@facts.delete(name)
107: }
108: end
# 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
# 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
# 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
# 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