facter 1.6.0 → 1.6.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 (63) hide show
  1. data/CHANGELOG +53 -0
  2. data/CONTRIBUTING.md +299 -0
  3. data/Rakefile +3 -3
  4. data/conf/redhat/facter.spec +1 -1
  5. data/install.rb +25 -10
  6. data/lib/facter.rb +16 -1
  7. data/lib/facter/arp.rb +1 -1
  8. data/lib/facter/augeasversion.rb +29 -0
  9. data/lib/facter/domain.rb +9 -10
  10. data/lib/facter/hardwareisa.rb +2 -2
  11. data/lib/facter/hostname.rb +4 -9
  12. data/lib/facter/ipaddress6.rb +9 -0
  13. data/lib/facter/kernel.rb +3 -3
  14. data/lib/facter/kernelrelease.rb +2 -4
  15. data/lib/facter/lsbmajdistrelease.rb +1 -1
  16. data/lib/facter/macaddress.rb +11 -31
  17. data/lib/facter/manufacturer.rb +5 -0
  18. data/lib/facter/memory.rb +32 -4
  19. data/lib/facter/operatingsystem.rb +6 -0
  20. data/lib/facter/operatingsystemrelease.rb +11 -2
  21. data/lib/facter/physicalprocessorcount.rb +8 -0
  22. data/lib/facter/processor.rb +38 -0
  23. data/lib/facter/ps.rb +5 -0
  24. data/lib/facter/selinux.rb +63 -48
  25. data/lib/facter/uniqueid.rb +2 -2
  26. data/lib/facter/util/config.rb +9 -0
  27. data/lib/facter/util/ip.rb +26 -3
  28. data/lib/facter/util/loader.rb +11 -0
  29. data/lib/facter/util/macaddress.rb +20 -0
  30. data/lib/facter/util/manufacturer.rb +10 -5
  31. data/lib/facter/util/resolution.rb +18 -9
  32. data/lib/facter/util/uptime.rb +6 -5
  33. data/lib/facter/util/wmi.rb +16 -0
  34. data/lib/facter/virtual.rb +15 -8
  35. data/spec/fixtures/netsh/windows_netsh_addresses_with_multiple_interfaces +35 -0
  36. data/spec/fixtures/unit/util/loader/nosuchfact.rb +1 -0
  37. data/spec/spec_helper.rb +1 -0
  38. data/spec/unit/data/windows_netsh_all_interfaces +12 -0
  39. data/spec/unit/data/windows_netsh_single_interface +7 -0
  40. data/spec/unit/data/windows_netsh_single_interface6 +18 -0
  41. data/spec/unit/domain_spec.rb +91 -0
  42. data/spec/unit/facter_spec.rb +21 -0
  43. data/spec/unit/hostname_spec.rb +38 -0
  44. data/spec/unit/id_spec.rb +6 -5
  45. data/spec/unit/interfaces_spec.rb +7 -0
  46. data/spec/unit/ipaddress6_spec.rb +19 -0
  47. data/spec/unit/macaddress_spec.rb +38 -0
  48. data/spec/unit/memory_spec.rb +26 -0
  49. data/spec/unit/operatingsystem_spec.rb +28 -0
  50. data/spec/unit/operatingsystemrelease_spec.rb +19 -8
  51. data/spec/unit/physicalprocessorcount_spec.rb +11 -0
  52. data/spec/unit/processor_spec.rb +66 -0
  53. data/spec/unit/selinux_spec.rb +1 -0
  54. data/spec/unit/util/ip_spec.rb +83 -21
  55. data/spec/unit/util/loader_spec.rb +8 -0
  56. data/spec/unit/util/macaddress_spec.rb +28 -1
  57. data/spec/unit/util/manufacturer_spec.rb +21 -0
  58. data/spec/unit/util/resolution_spec.rb +26 -14
  59. data/spec/unit/util/uptime_spec.rb +7 -1
  60. data/spec/unit/util/wmi_spec.rb +20 -0
  61. data/spec/unit/virtual_spec.rb +41 -5
  62. metadata +19 -8
  63. data/spec/spec.opts +0 -5
@@ -104,3 +104,41 @@ if Facter.value(:kernel) == "OpenBSD"
104
104
  end
105
105
  end
106
106
  end
107
+
108
+ if Facter.value(:kernel) == "windows"
109
+ processor_list = []
110
+
111
+ Thread::exclusive do
112
+ require 'facter/util/wmi'
113
+
114
+ # get each physical processor
115
+ Facter::Util::WMI.execquery("select * from Win32_Processor").each do |proc|
116
+ # not supported before 2008
117
+ begin
118
+ processor_num = proc.NumberOfLogicalProcessors
119
+ rescue RuntimeError => e
120
+ processor_num = 1
121
+ end
122
+
123
+ processor_num.times do |i|
124
+ processor_list << proc.Name.squeeze(" ")
125
+ end
126
+ end
127
+ end
128
+
129
+ processor_list.each_with_index do |name, i|
130
+ Facter.add("Processor#{i}") do
131
+ confine :kernel => :windows
132
+ setcode do
133
+ name
134
+ end
135
+ end
136
+ end
137
+
138
+ Facter.add("ProcessorCount") do
139
+ confine :kernel => :windows
140
+ setcode do
141
+ processor_list.length.to_s
142
+ end
143
+ end
144
+ end
@@ -18,3 +18,8 @@ Facter.add(:ps) do
18
18
  confine :operatingsystem => %w{FreeBSD NetBSD OpenBSD Darwin}
19
19
  setcode do 'ps auxwww' end
20
20
  end
21
+
22
+ Facter.add(:ps) do
23
+ confine :operatingsystem => :windows
24
+ setcode do 'tasklist.exe' end
25
+ end
@@ -10,69 +10,84 @@
10
10
  # Fact for SElinux
11
11
  # Written by immerda admin team (admin(at)immerda.ch)
12
12
 
13
- Facter.add("selinux") do
14
- confine :kernel => :linux
13
+ sestatus_cmd = '/usr/sbin/sestatus'
14
+
15
+ # This supports the fact that the selinux mount point is not always in the
16
+ # same location -- the selinux mount point is operating system specific.
17
+ def selinux_mount_point
18
+ if FileTest.exists?('/proc/self/mountinfo')
19
+ File.open('/proc/self/mountinfo') do |f|
20
+ f.grep(/selinuxfs/) do |line|
21
+ line.split[4]
22
+ end
23
+ end
24
+ else
25
+ "/selinux"
26
+ end
27
+ end
15
28
 
16
- setcode do
17
- result = "false"
18
- if FileTest.exists?("/selinux/enforce")
19
- if FileTest.exists?("/proc/self/attr/current")
20
- if (File.read("/proc/self/attr/current") != "kernel\0")
21
- result = "true"
22
- end
23
- end
29
+ Facter.add("selinux") do
30
+ confine :kernel => :linux
31
+ setcode do
32
+ result = "false"
33
+ if FileTest.exists?("#{selinux_mount_point}/enforce")
34
+ if FileTest.exists?("/proc/self/attr/current")
35
+ if (File.read("/proc/self/attr/current") != "kernel\0")
36
+ result = "true"
24
37
  end
25
- result
38
+ end
26
39
  end
40
+ result
41
+ end
27
42
  end
28
43
 
29
44
  Facter.add("selinux_enforced") do
30
- confine :selinux => :true
31
-
32
- setcode do
33
- result = "false"
34
- if FileTest.exists?("/selinux/enforce") and File.read("/selinux/enforce") =~ /1/i
35
- result = "true"
36
- end
37
- result
45
+ confine :selinux => :true
46
+ setcode do
47
+ result = "false"
48
+ if FileTest.exists?("#{selinux_mount_point}/enforce") and
49
+ File.read("#{selinux_mount_point}/enforce") =~ /1/i
50
+ result = "true"
38
51
  end
52
+ result
53
+ end
39
54
  end
40
55
 
41
56
  Facter.add("selinux_policyversion") do
42
- confine :selinux => :true
43
- setcode do
44
- File.read("/selinux/policyvers")
45
- end
57
+ confine :selinux => :true
58
+ setcode do
59
+ File.read("#{selinux_mount_point}/policyvers")
60
+ end
46
61
  end
47
62
 
48
63
  Facter.add("selinux_current_mode") do
49
- confine :selinux => :true
50
- setcode do
51
- result = 'unknown'
52
- mode = Facter::Util::Resolution.exec('/usr/sbin/sestatus')
53
- mode.each_line { |l| result = $1 if l =~ /^Current mode\:\s+(\w+)$/i }
54
- result.chomp
55
- end
64
+ confine :selinux => :true
65
+ setcode do
66
+ result = 'unknown'
67
+ mode = Facter::Util::Resolution.exec(sestatus_cmd)
68
+ mode.each_line { |l| result = $1 if l =~ /^Current mode\:\s+(\w+)$/i }
69
+ result.chomp
70
+ end
56
71
  end
57
72
 
58
73
  Facter.add("selinux_config_mode") do
59
- confine :selinux => :true
60
- setcode do
61
- result = 'unknown'
62
- mode = Facter::Util::Resolution.exec('/usr/sbin/sestatus')
63
- mode.each_line { |l| result = $1 if l =~ /^Mode from config file\:\s+(\w+)$/i }
64
- result.chomp
65
- end
74
+ confine :selinux => :true
75
+ setcode do
76
+ result = 'unknown'
77
+ mode = Facter::Util::Resolution.exec(sestatus_cmd)
78
+ mode.each_line { |l| result = $1 if l =~ /^Mode from config file\:\s+(\w+)$/i }
79
+ result.chomp
80
+ end
66
81
  end
67
82
 
68
83
  Facter.add("selinux_config_policy") do
69
- confine :selinux => :true
70
- setcode do
71
- result = 'unknown'
72
- mode = Facter::Util::Resolution.exec('/usr/sbin/sestatus')
73
- mode.each_line { |l| result = $1 if l =~ /^Policy from config file\:\s+(\w+)$/i }
74
- result.chomp
75
- end
84
+ confine :selinux => :true
85
+ setcode do
86
+ result = 'unknown'
87
+ mode = Facter::Util::Resolution.exec(sestatus_cmd)
88
+ mode.each_line { |l| result = $1 if l =~ /^Policy from config file\:\s+(\w+)$/i }
89
+ result.chomp
90
+ end
76
91
  end
77
92
 
78
93
  # This is a legacy fact which returns the old selinux_mode fact value to prevent
@@ -80,8 +95,8 @@ end
80
95
  # See ticket #6677.
81
96
 
82
97
  Facter.add("selinux_mode") do
83
- confine :selinux => :true
84
- setcode do
85
- Facter.value(:selinux_config_policy)
86
- end
98
+ confine :selinux => :true
99
+ setcode do
100
+ Facter.value(:selinux_config_policy)
101
+ end
87
102
  end
@@ -1,4 +1,4 @@
1
1
  Facter.add(:uniqueid) do
2
- setcode 'hostid', '/bin/sh'
3
- confine :operatingsystem => %w{Solaris Linux Fedora RedHat CentOS SuSE SLES Debian Ubuntu Gentoo AIX OEL OVS GNU/kFreeBSD}
2
+ setcode 'hostid'
3
+ confine :operatingsystem => %w{Solaris Linux Fedora RedHat CentOS Scientific SLC SuSE SLES Debian Ubuntu Gentoo AIX OEL OracleLinux OVS GNU/kFreeBSD}
4
4
  end
@@ -0,0 +1,9 @@
1
+ # A module to return config related data
2
+ #
3
+ module Facter::Util::Config
4
+ require 'rbconfig'
5
+
6
+ def self.is_windows?
7
+ Config::CONFIG['host_os'] =~ /mswin|win32|dos|mingw|cygwin/i
8
+ end
9
+ end
@@ -27,12 +27,17 @@ module Facter::Util::IP
27
27
  :ipaddress => /\s+inet (\S+)\s.*/,
28
28
  :macaddress => /(\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/,
29
29
  :netmask => /.*\s+netmask (\S+)\s.*/
30
+ },
31
+ :windows => {
32
+ :ipaddress => /\s+IP Address:\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/,
33
+ :ipaddress6 => /Address ((?![fe80|::1])(?>[0-9,a-f,A-F]*\:{1,2})+[0-9,a-f,A-F]{0,4})/,
34
+ :netmask => /\s+Subnet Prefix:\s+\S+\s+\(mask ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\)/
30
35
  }
31
36
  }
32
37
 
33
- # Convert an interface name into purely alpha characters.
38
+ # Convert an interface name into purely alphanumeric characters.
34
39
  def self.alphafy(interface)
35
- interface.gsub(/[-:.]/, '_')
40
+ interface.gsub(/[^a-z0-9_]/i, '_')
36
41
  end
37
42
 
38
43
  def self.convert_from_hex?(kernel)
@@ -55,6 +60,10 @@ module Facter::Util::IP
55
60
  def self.get_interfaces
56
61
  return [] unless output = Facter::Util::IP.get_all_interface_output()
57
62
 
63
+ # windows interface names contain spaces and are quoted and can appear multiple
64
+ # times as ipv4 and ipv6
65
+ return output.scan(/\s* connected\s*(\S.*)/).flatten.uniq if Facter.value(:kernel) == 'windows'
66
+
58
67
  # Our regex appears to be stupid, in that it leaves colons sitting
59
68
  # at the end of interfaces. So, we have to trim those trailing
60
69
  # characters. I tried making the regex better but supporting all
@@ -70,6 +79,9 @@ module Facter::Util::IP
70
79
  output = %x{/usr/sbin/ifconfig -a}
71
80
  when 'HP-UX'
72
81
  output = %x{/bin/netstat -in | sed -e 1d}
82
+ when 'windows'
83
+ output = %x|#{ENV['SYSTEMROOT']}/system32/netsh interface ip show interface|
84
+ output += %x|#{ENV['SYSTEMROOT']}/system32/netsh interface ipv6 show interface|
73
85
  end
74
86
  output
75
87
  end
@@ -91,6 +103,17 @@ module Facter::Util::IP
91
103
  output
92
104
  end
93
105
 
106
+ def self.get_output_for_interface_and_label(interface, label)
107
+ return get_single_interface_output(interface) unless Facter.value(:kernel) == 'windows'
108
+
109
+ if label == 'ipaddress6'
110
+ output = %x|#{ENV['SYSTEMROOT']}/system32/netsh interface ipv6 show address \"#{interface}\"|
111
+ else
112
+ output = %x|#{ENV['SYSTEMROOT']}/system32/netsh interface ip show address \"#{interface}\"|
113
+ end
114
+ output
115
+ end
116
+
94
117
  def self.get_bonding_master(interface)
95
118
  if Facter.value(:kernel) != 'Linux'
96
119
  return nil
@@ -139,7 +162,7 @@ module Facter::Util::IP
139
162
  hwaddrre = /^Slave Interface: #{interface}\n[^\n].+?\nPermanent HW addr: (([0-9a-fA-F]{2}:?)*)$/m
140
163
  value = hwaddrre.match(bondinfo.to_s)[1].upcase
141
164
  else
142
- output_int = get_single_interface_output(interface)
165
+ output_int = get_output_for_interface_and_label(interface, label)
143
166
 
144
167
  output_int.each_line do |s|
145
168
  if s =~ regex
@@ -2,6 +2,11 @@ require 'facter'
2
2
 
3
3
  # Load facts on demand.
4
4
  class Facter::Util::Loader
5
+
6
+ def initialize
7
+ @loaded = []
8
+ end
9
+
5
10
  # Load all resolutions for a single fact.
6
11
  def load(fact)
7
12
  # Now load from the search path
@@ -68,10 +73,16 @@ class Facter::Util::Loader
68
73
  end
69
74
 
70
75
  def load_file(file)
76
+ return if @loaded.include? file
71
77
  # We have to specify Kernel.load, because we have a load method.
72
78
  begin
79
+ # Store the file path so we don't try to reload it
80
+ @loaded << file
73
81
  Kernel.load(file)
74
82
  rescue ScriptError => detail
83
+ # Don't store the path if the file can't be loaded
84
+ # in case it's loadable later on.
85
+ @loaded.delete(file)
75
86
  warn "Error loading fact #{file} #{detail}"
76
87
  end
77
88
  end
@@ -2,6 +2,10 @@
2
2
  #
3
3
  module Facter::Util::Macaddress
4
4
 
5
+ def self.standardize(macaddress)
6
+ macaddress.split(":").map{|x| "0#{x}"[-2..-1]}.join(":")
7
+ end
8
+
5
9
  module Darwin
6
10
  def self.macaddress
7
11
  iface = default_interface
@@ -25,4 +29,20 @@ module Facter::Util::Macaddress
25
29
  '/sbin/ifconfig'
26
30
  end
27
31
  end
32
+
33
+ module Windows
34
+ def macaddress
35
+ require 'facter/util/wmi'
36
+
37
+ query = "select MACAddress from Win32_NetworkAdapterConfiguration where IPEnabled = True"
38
+
39
+ ether = nil
40
+ Facter::Util::WMI.execquery(query).each do |nic|
41
+ ether = nic.MacAddress
42
+ break
43
+ end
44
+ ether
45
+ end
46
+ module_function :macaddress
47
+ end
28
48
  end
@@ -53,9 +53,9 @@ module Facter::Manufacturer
53
53
  def self.sysctl_find_system_info(name)
54
54
  name.each do |sysctlkey,facterkey|
55
55
  Facter.add(facterkey) do
56
- confine :kernel => :openbsd
56
+ confine :kernel => [:openbsd, :darwin]
57
57
  setcode do
58
- Facter::Util::Resolution.exec("sysctl -n " + sysctlkey)
58
+ Facter::Util::Resolution.exec("sysctl -n #{sysctlkey} 2>/dev/null")
59
59
  end
60
60
  end
61
61
  end
@@ -79,12 +79,18 @@ module Facter::Manufacturer
79
79
  end
80
80
  end
81
81
  end
82
+
83
+ Facter.add('serialnumber') do
84
+ setcode do
85
+ Facter::Util::Resolution.exec("/usr/sbin/sneep")
86
+ end
87
+ end
82
88
  end
83
89
 
84
90
  def self.win32_find_system_info(name)
85
- require 'win32ole'
91
+ require 'facter/util/wmi'
86
92
  value = ""
87
- wmi = WIN32OLE.connect("winmgmts://")
93
+ wmi = Facter::Util::WMI.connect()
88
94
  name.each do |facterkey, win32key|
89
95
  query = wmi.ExecQuery("select * from Win32_#{win32key.last}")
90
96
  Facter.add(facterkey) do
@@ -96,5 +102,4 @@ module Facter::Manufacturer
96
102
  end
97
103
  end
98
104
  end
99
-
100
105
  end
@@ -4,16 +4,14 @@
4
4
  # confinements specified must all be true for the resolution to be
5
5
  # suitable.
6
6
  require 'facter/util/confine'
7
+ require 'facter/util/config'
7
8
 
8
9
  require 'timeout'
9
- require 'rbconfig'
10
10
 
11
11
  class Facter::Util::Resolution
12
12
  attr_accessor :interpreter, :code, :name, :timeout
13
13
 
14
- WINDOWS = Config::CONFIG['host_os'] =~ /mswin|win32|dos|mingw|cygwin/i
15
-
16
- INTERPRETER = WINDOWS ? 'cmd.exe' : '/bin/sh'
14
+ INTERPRETER = Facter::Util::Config.is_windows? ? "cmd.exe" : "/bin/sh"
17
15
 
18
16
  def self.have_which
19
17
  if ! defined?(@have_which) or @have_which.nil?
@@ -32,8 +30,8 @@ class Facter::Util::Resolution
32
30
  # Returns nil if the program can't be found, or if there is a problem
33
31
  # executing the code.
34
32
  #
35
- def self.exec(code, interpreter = INTERPRETER)
36
- raise ArgumentError, "invalid interpreter" unless interpreter == INTERPRETER
33
+ def self.exec(code, interpreter = nil)
34
+ Facter.warnonce "The interpreter parameter to 'exec' is deprecated and will be removed in a future version." if interpreter
37
35
 
38
36
  # Try to guess whether the specified code can be executed by looking at the
39
37
  # first word. If it cannot be found on the PATH defer on resolving the fact
@@ -45,7 +43,7 @@ class Facter::Util::Resolution
45
43
  # Windows' %x{} throws Errno::ENOENT when the command is not found, so we
46
44
  # can skip the check there. This is good, since builtins cannot be found
47
45
  # elsewhere.
48
- if have_which and !WINDOWS
46
+ if have_which and !Facter::Util::Config.is_windows?
49
47
  path = nil
50
48
  binary = code.split.first
51
49
  if code =~ /^\//
@@ -116,6 +114,7 @@ class Facter::Util::Resolution
116
114
 
117
115
  # Set our code for returning a value.
118
116
  def setcode(string = nil, interp = nil, &block)
117
+ Facter.warnonce "The interpreter parameter to 'setcode' is deprecated and will be removed in a future version." if interp
119
118
  if string
120
119
  @code = string
121
120
  @interpreter = interp || INTERPRETER
@@ -127,6 +126,16 @@ class Facter::Util::Resolution
127
126
  end
128
127
  end
129
128
 
129
+ def interpreter
130
+ Facter.warnonce "The 'Facter::Util::Resolution.interpreter' method is deprecated and will be removed in a future version."
131
+ @interpreter
132
+ end
133
+
134
+ def interpreter=(interp)
135
+ Facter.warnonce "The 'Facter::Util::Resolution.interpreter=' method is deprecated and will be removed in a future version."
136
+ @interpreter = interp
137
+ end
138
+
130
139
  # Is this resolution mechanism suitable on the system in question?
131
140
  def suitable?
132
141
  unless defined? @suitable
@@ -143,7 +152,7 @@ class Facter::Util::Resolution
143
152
  # How we get a value for our resolution mechanism.
144
153
  def value
145
154
  result = nil
146
- return result if @code == nil and @interpreter == nil
155
+ return result if @code == nil
147
156
 
148
157
  starttime = Time.now.to_f
149
158
 
@@ -152,7 +161,7 @@ class Facter::Util::Resolution
152
161
  if @code.is_a?(Proc)
153
162
  result = @code.call()
154
163
  else
155
- result = Facter::Util::Resolution.exec(@code,@interpreter)
164
+ result = Facter::Util::Resolution.exec(@code)
156
165
  end
157
166
  end
158
167
  rescue Timeout::Error => detail