facter 4.0.39 → 4.0.44

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/bin/facter +3 -4
  3. data/lib/facter.rb +107 -28
  4. data/lib/facter/config.rb +354 -0
  5. data/lib/facter/custom_facts/core/aggregate.rb +51 -17
  6. data/lib/facter/custom_facts/core/execution.rb +27 -35
  7. data/lib/facter/custom_facts/core/execution/base.rb +13 -7
  8. data/lib/facter/custom_facts/util/directory_loader.rb +1 -1
  9. data/lib/facter/custom_facts/util/fact.rb +1 -1
  10. data/lib/facter/custom_facts/util/resolution.rb +40 -11
  11. data/lib/facter/facts/aix/disks.rb +1 -1
  12. data/lib/facter/facts/linux/ec2_metadata.rb +5 -29
  13. data/lib/facter/facts/linux/ec2_userdata.rb +5 -27
  14. data/lib/facter/facts/linux/is_virtual.rb +7 -46
  15. data/lib/facter/facts/linux/virtual.rb +3 -58
  16. data/lib/facter/facts/rhel/os/release.rb +1 -1
  17. data/lib/facter/facts/solaris/disks.rb +1 -1
  18. data/lib/facter/facts/solaris/zones.rb +1 -1
  19. data/lib/facter/facts_utils/virtual_detector.rb +78 -0
  20. data/lib/facter/framework/benchmarking/timer.rb +4 -2
  21. data/lib/facter/framework/cli/cli.rb +83 -36
  22. data/lib/facter/framework/cli/cli_launcher.rb +34 -38
  23. data/lib/facter/framework/config/fact_groups.rb +41 -7
  24. data/lib/facter/framework/core/cache_manager.rb +43 -23
  25. data/lib/facter/framework/core/fact_loaders/fact_loader.rb +14 -11
  26. data/lib/facter/framework/core/options/config_file_options.rb +5 -3
  27. data/lib/facter/framework/core/options/option_store.rb +60 -27
  28. data/lib/facter/framework/detector/os_hierarchy.rb +5 -9
  29. data/lib/facter/framework/logging/logger.rb +1 -5
  30. data/lib/facter/resolvers/aix/architecture_resolver.rb +15 -1
  31. data/lib/facter/resolvers/aix/os_level.rb +1 -1
  32. data/lib/facter/resolvers/augeas_resolver.rb +7 -1
  33. data/lib/facter/resolvers/bsd/processors.rb +11 -7
  34. data/lib/facter/resolvers/disk_resolver.rb +11 -3
  35. data/lib/facter/resolvers/dmi_decode.rb +1 -0
  36. data/lib/facter/resolvers/dmi_resolver.rb +2 -2
  37. data/lib/facter/resolvers/freebsd/geom_resolver.rb +12 -20
  38. data/lib/facter/resolvers/freebsd/processors.rb +11 -7
  39. data/lib/facter/resolvers/memory_resolver.rb +12 -14
  40. data/lib/facter/resolvers/mountpoints_resolver.rb +50 -22
  41. data/lib/facter/resolvers/networking_linux_resolver.rb +10 -5
  42. data/lib/facter/resolvers/partitions.rb +60 -57
  43. data/lib/facter/resolvers/processors_resolver.rb +5 -1
  44. data/lib/facter/resolvers/solaris/dmi.rb +2 -0
  45. data/lib/facter/resolvers/solaris/mountpoints.rb +60 -0
  46. data/lib/facter/resolvers/solaris/networking.rb +1 -2
  47. data/lib/facter/resolvers/solaris/os_release.rb +4 -3
  48. data/lib/facter/resolvers/ssh_resolver.rb +4 -4
  49. data/lib/facter/version.rb +1 -1
  50. metadata +5 -4
  51. data/lib/facter/fact_groups.conf +0 -308
  52. data/lib/facter/os_hierarchy.json +0 -36
@@ -1,29 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'facter/config'
4
+
3
5
  module Facter
4
6
  class OsHierarchy
5
7
  def initialize
6
8
  @log = Log.new(self)
7
- json_file_path = File.join(File.dirname(__FILE__), '../../os_hierarchy.json')
8
- json_file = Util::FileHelper.safe_read(json_file_path)
9
- begin
10
- @json_os_hierarchy = JSON.parse(json_file)
11
- rescue JSON::ParserError => _e
12
- @log.error('Could not parse os_hierarchy json')
13
- end
9
+ @os_hierarchy = Facter::Config::OS_HIERARCHY
14
10
  end
15
11
 
16
12
  def construct_hierarchy(searched_os)
17
13
  return [] if searched_os.nil?
18
14
 
19
15
  searched_os = searched_os.to_s.capitalize
20
- if @json_os_hierarchy.nil?
16
+ if @os_hierarchy.nil?
21
17
  @log.debug("There is no os_hierarchy, will fall back to: #{searched_os}")
22
18
  return [searched_os]
23
19
  end
24
20
 
25
21
  @searched_path = []
26
- search(@json_os_hierarchy, searched_os, [])
22
+ search(@os_hierarchy, searched_os, [])
27
23
 
28
24
  @searched_path.map { |os_name| os_name.to_s.capitalize }
29
25
  end
@@ -91,9 +91,7 @@ module Facter
91
91
  def error(msg, colorize = false)
92
92
  @@has_errors = true
93
93
 
94
- if msg.nil? || msg.empty?
95
- empty_message_error(msg)
96
- elsif @@message_callback
94
+ if @@message_callback
97
95
  @@message_callback.call(:error, msg)
98
96
  else
99
97
  msg = colorize(msg, RED) if colorize || Options[:color]
@@ -111,8 +109,6 @@ module Facter
111
109
  private
112
110
 
113
111
  def colorize(msg, color)
114
- return msg if OsDetector.instance.identifier.eql?(:windows)
115
-
116
112
  "#{color}#{msg}#{RESET}"
117
113
  end
118
114
 
@@ -14,9 +14,11 @@ module Facter
14
14
 
15
15
  def read_architecture(fact_name)
16
16
  require_relative 'utils/odm_query'
17
+
18
+ proc_number = read_proc
17
19
  odmquery = ODMQuery.new
18
20
  odmquery
19
- .equals('name', 'proc0')
21
+ .equals('name', proc_number)
20
22
  .equals('attribute', 'type')
21
23
 
22
24
  result = odmquery.execute
@@ -32,6 +34,18 @@ module Facter
32
34
 
33
35
  @fact_list[fact_name]
34
36
  end
37
+
38
+ def read_proc
39
+ odmquery = ODMQuery.new
40
+ odmquery
41
+ .equals('PdDvLn', 'processor/sys/proc_rspc')
42
+ .equals('status', '1')
43
+
44
+ result = odmquery.execute
45
+ result.each_line do |line|
46
+ return line.split('=')[1].strip.delete('\"') if line.include?('name')
47
+ end
48
+ end
35
49
  end
36
50
  end
37
51
  end
@@ -14,7 +14,7 @@ module Facter
14
14
  end
15
15
 
16
16
  def read_oslevel(fact_name)
17
- output = Facter::Core::Execution.execute('/usr/bin/oslevel -s', { limit: 2, logger: log })
17
+ output = Facter::Core::Execution.execute('/usr/bin/oslevel -s', logger: log)
18
18
  @fact_list[:build] = output unless output.empty?
19
19
  @fact_list[:kernel] = 'AIX'
20
20
 
@@ -20,7 +20,13 @@ module Facter
20
20
  end
21
21
 
22
22
  def read_augeas_from_cli
23
- output = Facter::Core::Execution.execute('augparse --version 2>&1', logger: log)
23
+ command = if File.readable?('/opt/puppetlabs/puppet/bin/augparse')
24
+ '/opt/puppetlabs/puppet/bin/augparse'
25
+ else
26
+ 'augparse'
27
+ end
28
+
29
+ output = Facter::Core::Execution.execute("#{command} --version 2>&1", logger: log)
24
30
  Regexp.last_match(1) if output =~ /^augparse (\d+\.\d+\.\d+)/
25
31
  end
26
32
 
@@ -16,8 +16,12 @@ module Facter
16
16
  def collect_processors_info(fact_name)
17
17
  require 'facter/resolvers/bsd/ffi/ffi_helper'
18
18
 
19
- @fact_list[:logical_count] = logical_count
20
- @fact_list[:models] = Array.new(logical_count, model) if logical_count && model
19
+ count = logical_count
20
+ model = processor_model
21
+ speed = processor_speed
22
+
23
+ @fact_list[:logical_count] = count
24
+ @fact_list[:models] = Array.new(count, model) if count && model
21
25
  @fact_list[:speed] = speed * 1000 * 1000 if speed
22
26
 
23
27
  @fact_list[fact_name]
@@ -28,16 +32,16 @@ module Facter
28
32
  HW_NCPU = 3
29
33
  HW_CPUSPEED = 12
30
34
 
31
- def model
32
- @model ||= Facter::Bsd::FfiHelper.sysctl(:string, [CTL_HW, HW_MODEL])
35
+ def processor_model
36
+ Facter::Bsd::FfiHelper.sysctl(:string, [CTL_HW, HW_MODEL])
33
37
  end
34
38
 
35
39
  def logical_count
36
- @logical_count ||= Facter::Bsd::FfiHelper.sysctl(:uint32_t, [CTL_HW, HW_NCPU])
40
+ Facter::Bsd::FfiHelper.sysctl(:uint32_t, [CTL_HW, HW_NCPU])
37
41
  end
38
42
 
39
- def speed
40
- @speed ||= Facter::Bsd::FfiHelper.sysctl(:uint32_t, [CTL_HW, HW_CPUSPEED])
43
+ def processor_speed
44
+ Facter::Bsd::FfiHelper.sysctl(:uint32_t, [CTL_HW, HW_CPUSPEED])
41
45
  end
42
46
  end
43
47
  end
@@ -7,7 +7,7 @@ module Facter
7
7
  @log = Facter::Log.new(self)
8
8
  @fact_list ||= {}
9
9
  DIR = '/sys/block'
10
- FILE_PATHS = { model: 'device/model', size: 'size', vendor: 'device/vendor' }.freeze
10
+ FILE_PATHS = { model: 'device/model', size: 'size', vendor: 'device/vendor', type: 'queue/rotational' }.freeze
11
11
  class << self
12
12
  private
13
13
 
@@ -25,8 +25,16 @@ module Facter
25
25
  result = Util::FileHelper.safe_read(file_path).strip
26
26
  next if result.empty?
27
27
 
28
- # Linux always considers sectors to be 512 bytes long independently of the devices real block size.
29
- value[key] = file =~ /size/ ? construct_size(value, result) : result
28
+ value[key] = case key
29
+ when :size
30
+ # Linux always considers sectors to be 512 bytes long
31
+ # independently of the devices real block size.
32
+ construct_size(value, result)
33
+ when :type
34
+ result == '0' ? 'ssd' : 'hdd'
35
+ else
36
+ result
37
+ end
30
38
  end
31
39
  end
32
40
 
@@ -37,6 +37,7 @@ module Facter
37
37
  @fact_list[:virtualbox_version] = output.match(/vboxVer_(\S+)/)&.captures&.first
38
38
  @fact_list[:virtualbox_revision] = output.match(/vboxRev_(\S+)/)&.captures&.first
39
39
  @fact_list[:vmware_version] = extract_vmware_version(output)
40
+ @fact_list[:vendor] = output.match(/Vendor: (\S+)/)&.captures&.first
40
41
 
41
42
  @fact_list[fact_name]
42
43
  end
@@ -36,9 +36,9 @@ module Facter
36
36
 
37
37
  file_content = Util::FileHelper.safe_read("/sys/class/dmi/id/#{fact_name}", nil)
38
38
  if files.include?(fact_name.to_s) && file_content
39
- @fact_list[fact_name] = file_content.strip
39
+ file_content = file_content.strip
40
+ @fact_list[fact_name] = file_content unless file_content.empty?
40
41
  chassis_to_name(@fact_list[fact_name]) if fact_name == :chassis_type
41
-
42
42
  end
43
43
  @fact_list[fact_name]
44
44
  end
@@ -5,6 +5,8 @@ module Facter
5
5
  module Freebsd
6
6
  class Geom < BaseResolver
7
7
  @fact_list ||= {}
8
+ DISKS_ATTRIBUTES = %i[read_model read_serial_number read_size].freeze
9
+ PARTITIONS_ATTRIBUTES = %i[read_partlabel read_partuuid read_size].freeze
8
10
 
9
11
  class << self
10
12
  private
@@ -17,37 +19,27 @@ module Facter
17
19
  require_relative 'ffi/ffi_helper'
18
20
  require 'rexml/document'
19
21
 
20
- read_disks
21
- read_partitions
22
+ topology = geom_topology
23
+ read_data('DISK', topology, DISKS_ATTRIBUTES)
24
+ read_data('PART', topology, PARTITIONS_ATTRIBUTES)
22
25
 
23
26
  @fact_list[fact_name]
24
27
  end
25
28
 
26
- def read_disks
27
- @fact_list[:disks] = {}
29
+ def read_data(fact_name, geom_topology, data_to_read)
30
+ fact_list_key = fact_name == 'DISK' ? :disks : :partitions
31
+ @fact_list[fact_list_key] = {}
28
32
 
29
- each_geom_class_provider('DISK') do |provider|
33
+ each_geom_class_provider(fact_name, geom_topology) do |provider|
30
34
  name = provider.get_text('./name').value
31
35
 
32
- @fact_list[:disks][name] = %i[read_model read_serial_number read_size].map do |x|
36
+ @fact_list[fact_list_key][name] = data_to_read.map do |x|
33
37
  send(x, provider)
34
38
  end.inject(:merge)
35
39
  end
36
40
  end
37
41
 
38
- def read_partitions
39
- @fact_list[:partitions] = {}
40
-
41
- each_geom_class_provider('PART') do |provider|
42
- name = provider.get_text('./name').value
43
-
44
- @fact_list[:partitions][name] = %i[read_partlabel read_partuuid read_size].map do |x|
45
- send(x, provider)
46
- end.inject(:merge)
47
- end
48
- end
49
-
50
- def each_geom_class_provider(geom_class_name, &block)
42
+ def each_geom_class_provider(geom_class_name, geom_topology, &block)
51
43
  REXML::XPath.each(geom_topology, "/mesh/class[name/text() = '#{geom_class_name}']/geom/provider", &block)
52
44
  end
53
45
 
@@ -95,7 +87,7 @@ module Facter
95
87
  end
96
88
 
97
89
  def geom_topology
98
- @geom_topology ||= REXML::Document.new(geom_confxml)
90
+ REXML::Document.new(geom_confxml)
99
91
  end
100
92
 
101
93
  def geom_confxml
@@ -18,23 +18,27 @@ module Facter
18
18
  def collect_processors_info(fact_name)
19
19
  require 'facter/resolvers/freebsd/ffi/ffi_helper'
20
20
 
21
- @fact_list[:logical_count] = logical_count
22
- @fact_list[:models] = Array.new(logical_count, model) if logical_count && model
21
+ count = logical_count
22
+ model = processors_model
23
+ speed = processors_speed
24
+
25
+ @fact_list[:logical_count] = count
26
+ @fact_list[:models] = Array.new(count, model) if logical_count && model
23
27
  @fact_list[:speed] = speed * 1000 * 1000 if speed
24
28
 
25
29
  @fact_list[fact_name]
26
30
  end
27
31
 
28
- def model
29
- @model ||= Facter::Freebsd::FfiHelper.sysctl_by_name(:string, 'hw.model')
32
+ def processors_model
33
+ Facter::Freebsd::FfiHelper.sysctl_by_name(:string, 'hw.model')
30
34
  end
31
35
 
32
36
  def logical_count
33
- @logical_count ||= Facter::Freebsd::FfiHelper.sysctl_by_name(:uint32_t, 'hw.ncpu')
37
+ Facter::Freebsd::FfiHelper.sysctl_by_name(:uint32_t, 'hw.ncpu')
34
38
  end
35
39
 
36
- def speed
37
- @speed ||= Facter::Freebsd::FfiHelper.sysctl_by_name(:uint32_t, 'hw.clockrate')
40
+ def processors_speed
41
+ Facter::Freebsd::FfiHelper.sysctl_by_name(:uint32_t, 'hw.clockrate')
38
42
  end
39
43
  end
40
44
  end
@@ -25,11 +25,21 @@ module Facter
25
25
 
26
26
  def read_system(output)
27
27
  @fact_list[:total] = kilobytes_to_bytes(output.match(/MemTotal:\s+(\d+)\s/)[1])
28
- @fact_list[:memfree] = kilobytes_to_bytes(output.match(/MemFree:\s+(\d+)\s/)[1])
29
- @fact_list[:used_bytes] = compute_used(@fact_list[:total], reclaimable_memory(output))
28
+ @fact_list[:memfree] = memfree(output)
29
+ @fact_list[:used_bytes] = compute_used(@fact_list[:total], @fact_list[:memfree])
30
30
  @fact_list[:capacity] = compute_capacity(@fact_list[:used_bytes], @fact_list[:total])
31
31
  end
32
32
 
33
+ def memfree(output)
34
+ available = output.match(/MemAvailable:\s+(\d+)\s/)
35
+ return kilobytes_to_bytes(available[1]) if available
36
+
37
+ buffers = kilobytes_to_bytes(output.match(/Buffers:\s+(\d+)\s/)[1])
38
+ cached = kilobytes_to_bytes(output.match(/Cached:\s+(\d+)\s/)[1])
39
+ memfree = kilobytes_to_bytes(output.match(/MemFree:\s+(\d+)\s/)[1])
40
+ memfree + buffers + cached
41
+ end
42
+
33
43
  def read_swap(output)
34
44
  total = output.match(/SwapTotal:\s+(\d+)\s/)[1]
35
45
  return if total.to_i.zero?
@@ -44,18 +54,6 @@ module Facter
44
54
  quantity.to_i * 1024
45
55
  end
46
56
 
47
- def reclaimable_memory(output)
48
- buffers = kilobytes_to_bytes(output.match(/Buffers:\s+(\d+)\s/)[1])
49
- cached = kilobytes_to_bytes(output.match(/Cached:\s+(\d+)\s/)[1])
50
- s_reclaimable = output.match(/SReclaimable:\s+(\d+)\s/)
51
- s_reclaimable = if s_reclaimable
52
- kilobytes_to_bytes(s_reclaimable[1])
53
- else
54
- 0
55
- end
56
- @fact_list[:memfree] + buffers + cached + s_reclaimable
57
- end
58
-
59
57
  def compute_capacity(used, total)
60
58
  format('%<computed_capacity>.2f', computed_capacity: (used / total.to_f * 100)) + '%'
61
59
  end
@@ -10,13 +10,27 @@ module Facter
10
10
  private
11
11
 
12
12
  def post_resolve(fact_name)
13
- @fact_list.fetch(fact_name) { read_mounts }
13
+ @fact_list.fetch(fact_name) { read_mounts(fact_name) }
14
14
  end
15
15
 
16
16
  def root_device
17
17
  cmdline = Util::FileHelper.safe_read('/proc/cmdline')
18
18
  match = cmdline.match(/root=([^\s]+)/)
19
- match&.captures&.first
19
+ root = match&.captures&.first
20
+
21
+ if !root.nil? && root.include?('=')
22
+ # We are dealing with the PARTUUID of the partition. Need to extract partition path.
23
+ root_partition_path = convert_partuuid_to_path(root)
24
+ root = root_partition_path unless root_partition_path.nil?
25
+ end
26
+ root
27
+ end
28
+
29
+ def convert_partuuid_to_path(root)
30
+ blkid_content = Facter::Core::Execution.execute('blkid', logger: log)
31
+ partuuid = root.split('=').last
32
+ match = blkid_content.match(/(.+)#{partuuid}/)
33
+ match&.captures&.first&.split(':')&.first
20
34
  end
21
35
 
22
36
  def compute_device(device)
@@ -26,32 +40,46 @@ module Facter
26
40
  device
27
41
  end
28
42
 
29
- def read_mounts # rubocop:disable Metrics/AbcSize
43
+ def read_mounts(fact_name)
30
44
  mounts = []
31
- FilesystemHelper.read_mountpoints.each do |fs|
32
- device = compute_device(fs.name)
33
- filesystem = fs.mount_type
34
- path = fs.mount_point
35
- options = fs.options.split(',').map(&:strip)
45
+ FilesystemHelper.read_mountpoints.each do |file_system|
46
+ mount = {}
47
+ get_mount_data(file_system, mount)
36
48
 
37
- next if path =~ %r{^/(proc|sys)} && filesystem != 'tmpfs' || filesystem == 'autofs'
49
+ next if mount[:path] =~ %r{^/(proc|sys)} && mount[:filesystem] != 'tmpfs' || mount[:filesystem] == 'autofs'
38
50
 
39
- stats = FilesystemHelper.read_mountpoint_stats(path)
40
- size_bytes = stats.bytes_total.abs
41
- available_bytes = stats.bytes_available.abs
51
+ get_mount_sizes(mount)
52
+ mounts << mount
53
+ end
42
54
 
43
- used_bytes = stats.bytes_used.abs
44
- total_bytes = used_bytes + available_bytes
45
- capacity = FilesystemHelper.compute_capacity(used_bytes, total_bytes)
55
+ @fact_list[:mountpoints] = mounts
56
+ @fact_list[fact_name]
57
+ end
46
58
 
47
- size = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(size_bytes)
48
- available = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(available_bytes)
49
- used = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(used_bytes)
59
+ def get_mount_data(file_system, mount)
60
+ mount[:device] = compute_device(file_system.name)
61
+ mount[:filesystem] = file_system.mount_type
62
+ mount[:path] = file_system.mount_point
63
+ mount[:options] = file_system.options.split(',').map(&:strip)
64
+ end
50
65
 
51
- mounts << Hash[FilesystemHelper::MOUNT_KEYS.zip(FilesystemHelper::MOUNT_KEYS
52
- .map { |v| binding.local_variable_get(v) })]
53
- end
54
- @fact_list[:mountpoints] = mounts
66
+ def get_mount_sizes(mount)
67
+ stats = FilesystemHelper.read_mountpoint_stats(mount[:path])
68
+
69
+ get_bytes_data(mount, stats)
70
+
71
+ total_bytes = mount[:used_bytes] + mount[:available_bytes]
72
+ mount[:capacity] = FilesystemHelper.compute_capacity(mount[:used_bytes], total_bytes)
73
+
74
+ mount[:size] = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(mount[:size_bytes])
75
+ mount[:available] = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(mount[:available_bytes])
76
+ mount[:used] = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(mount[:used_bytes])
77
+ end
78
+
79
+ def get_bytes_data(mount, stats)
80
+ mount[:size_bytes] = stats.bytes_total.abs
81
+ mount[:available_bytes] = stats.bytes_available.abs
82
+ mount[:used_bytes] = stats.bytes_used.abs
55
83
  end
56
84
  end
57
85
  end
@@ -10,7 +10,6 @@ module Facter
10
10
  private
11
11
 
12
12
  def post_resolve(fact_name)
13
- log.debug('in networking_linux_resolver')
14
13
  @fact_list.fetch(fact_name) { retrieve_network_info(fact_name) }
15
14
 
16
15
  @fact_list[fact_name]
@@ -60,9 +59,14 @@ module Facter
60
59
  return if !network_info[interface_name] || network_info[interface_name][:dhcp]
61
60
 
62
61
  index = tokens[0].delete(':')
63
- dhcp = Util::FileHelper.safe_read("/run/systemd/netif/leases/#{index}", nil)
64
- network_info[interface_name][:dhcp] = dhcp.match(/SERVER_ADDRESS=(.*)/)[1] if dhcp
65
- network_info[interface_name][:dhcp] ||= retrieve_from_other_directories(interface_name)
62
+ file_content = Util::FileHelper.safe_read("/run/systemd/netif/leases/#{index}", nil)
63
+ dhcp = file_content.match(/SERVER_ADDRESS=(.*)/) if file_content
64
+ if dhcp
65
+ network_info[interface_name][:dhcp] = dhcp[1]
66
+ else
67
+ alternate_dhcp = retrieve_from_other_directories(interface_name)
68
+ network_info[interface_name][:dhcp] = alternate_dhcp if alternate_dhcp
69
+ end
66
70
  end
67
71
 
68
72
  def retrieve_from_other_directories(interface_name)
@@ -76,7 +80,8 @@ module Facter
76
80
  content = Util::FileHelper.safe_read("#{dir}#{file}", nil)
77
81
  next unless content =~ /interface.*#{interface_name}/
78
82
 
79
- return content.match(/dhcp-server-identifier ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/)[1]
83
+ dhcp = content.match(/dhcp-server-identifier ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/)
84
+ return dhcp[1] if dhcp
80
85
  end
81
86
  end
82
87
  return unless File.readable?('/var/lib/NetworkManager/')