facter 4.0.50 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/lib/docs/generate_cli.rb +7 -0
  3. data/lib/facter.rb +90 -56
  4. data/lib/facter/config.rb +2 -0
  5. data/lib/facter/custom_facts/core/aggregate.rb +9 -0
  6. data/lib/facter/custom_facts/core/execution/base.rb +7 -3
  7. data/lib/facter/custom_facts/core/execution/popen3.rb +13 -1
  8. data/lib/facter/custom_facts/core/execution/posix.rb +2 -2
  9. data/lib/facter/custom_facts/core/execution/windows.rb +1 -1
  10. data/lib/facter/custom_facts/core/resolvable.rb +11 -0
  11. data/lib/facter/custom_facts/util/collection.rb +5 -0
  12. data/lib/facter/custom_facts/util/directory_loader.rb +1 -1
  13. data/lib/facter/custom_facts/util/normalization.rb +7 -2
  14. data/lib/facter/custom_facts/util/resolution.rb +2 -0
  15. data/lib/facter/custom_facts/util/windows_root.rb +2 -1
  16. data/lib/facter/facts/aix/processors/cores.rb +16 -0
  17. data/lib/facter/facts/aix/processors/threads.rb +16 -0
  18. data/lib/facter/facts/amzn/lsbdistcodename.rb +16 -0
  19. data/lib/facter/facts/amzn/lsbdistdescription.rb +16 -0
  20. data/lib/facter/facts/amzn/lsbdistid.rb +16 -0
  21. data/lib/facter/facts/amzn/os/distro/codename.rb +24 -0
  22. data/lib/facter/facts/amzn/os/distro/description.rb +21 -0
  23. data/lib/facter/facts/amzn/os/distro/id.rb +21 -0
  24. data/lib/facter/facts/amzn/os/distro/release.rb +32 -0
  25. data/lib/facter/facts/freebsd/is_virtual.rb +1 -5
  26. data/lib/facter/facts/freebsd/virtual.rb +1 -2
  27. data/lib/facter/facts/linux/az_metadata.rb +23 -0
  28. data/lib/facter/facts/linux/cloud/provider.rb +20 -0
  29. data/lib/facter/facts/linux/dhcp_servers.rb +2 -2
  30. data/lib/facter/facts/linux/ec2_metadata.rb +1 -5
  31. data/lib/facter/facts/linux/ec2_userdata.rb +1 -5
  32. data/lib/facter/facts/linux/hypervisors/xen.rb +1 -4
  33. data/lib/facter/facts/linux/interfaces.rb +1 -1
  34. data/lib/facter/facts/linux/ipaddress6_interfaces.rb +1 -1
  35. data/lib/facter/facts/linux/ipaddress_interfaces.rb +1 -1
  36. data/lib/facter/facts/linux/is_virtual.rb +1 -5
  37. data/lib/facter/facts/linux/macaddress_interfaces.rb +1 -1
  38. data/lib/facter/facts/linux/mtu_interfaces.rb +1 -1
  39. data/lib/facter/facts/linux/netmask6_interfaces.rb +1 -1
  40. data/lib/facter/facts/linux/netmask_interfaces.rb +1 -1
  41. data/lib/facter/facts/linux/network6_interfaces.rb +1 -1
  42. data/lib/facter/facts/linux/network_interfaces.rb +1 -1
  43. data/lib/facter/facts/linux/networking/dhcp.rb +1 -1
  44. data/lib/facter/facts/linux/networking/domain.rb +1 -1
  45. data/lib/facter/facts/linux/networking/fqdn.rb +1 -1
  46. data/lib/facter/facts/linux/networking/hostname.rb +1 -1
  47. data/lib/facter/facts/linux/networking/interfaces.rb +1 -1
  48. data/lib/facter/facts/linux/networking/ip.rb +1 -1
  49. data/lib/facter/facts/linux/networking/ip6.rb +1 -1
  50. data/lib/facter/facts/linux/networking/mac.rb +1 -1
  51. data/lib/facter/facts/linux/networking/mtu.rb +1 -1
  52. data/lib/facter/facts/linux/networking/netmask.rb +1 -1
  53. data/lib/facter/facts/linux/networking/netmask6.rb +1 -1
  54. data/lib/facter/facts/linux/networking/network.rb +1 -1
  55. data/lib/facter/facts/linux/networking/network6.rb +1 -1
  56. data/lib/facter/facts/linux/networking/primary.rb +1 -1
  57. data/lib/facter/facts/linux/networking/scope6.rb +1 -1
  58. data/lib/facter/facts/linux/processors/cores.rb +16 -0
  59. data/lib/facter/facts/linux/processors/threads.rb +16 -0
  60. data/lib/facter/facts/linux/scope6_interfaces.rb +1 -1
  61. data/lib/facter/facts/linux/virtual.rb +1 -2
  62. data/lib/facter/facts/macosx/os/macosx/version.rb +15 -4
  63. data/lib/facter/facts/macosx/processors/cores.rb +16 -0
  64. data/lib/facter/facts/macosx/processors/threads.rb +16 -0
  65. data/lib/facter/facts/rhel/lsbdistcodename.rb +16 -0
  66. data/lib/facter/facts/rhel/lsbdistdescription.rb +16 -0
  67. data/lib/facter/facts/rhel/lsbdistid.rb +16 -0
  68. data/lib/facter/facts/rhel/os/distro/codename.rb +2 -4
  69. data/lib/facter/facts/rhel/os/distro/description.rb +2 -4
  70. data/lib/facter/facts/rhel/os/distro/id.rb +2 -4
  71. data/lib/facter/facts/rhel/os/distro/release.rb +13 -12
  72. data/lib/facter/facts/sles/lsbdistcodename.rb +16 -0
  73. data/lib/facter/facts/sles/lsbdistdescription.rb +16 -0
  74. data/lib/facter/facts/sles/lsbdistid.rb +16 -0
  75. data/lib/facter/facts/sles/os/distro/codename.rb +3 -4
  76. data/lib/facter/facts/sles/os/distro/description.rb +2 -5
  77. data/lib/facter/facts/sles/os/distro/id.rb +6 -5
  78. data/lib/facter/facts/sles/os/distro/release.rb +17 -12
  79. data/lib/facter/facts/solaris/hypervisors/ldom.rb +1 -1
  80. data/lib/facter/facts/solaris/hypervisors/zone.rb +1 -1
  81. data/lib/facter/facts/solaris/mountpoints.rb +1 -1
  82. data/lib/facter/facts/solaris/processors/cores.rb +16 -0
  83. data/lib/facter/facts/solaris/processors/threads.rb +16 -0
  84. data/lib/facter/facts/ubuntu/lsbdistrelease.rb +2 -2
  85. data/lib/facter/facts/windows/az_metadata.rb +23 -0
  86. data/lib/facter/facts/windows/cloud/provider.rb +21 -0
  87. data/lib/facter/facts/windows/ec2_metadata.rb +1 -1
  88. data/lib/facter/facts/windows/ec2_userdata.rb +1 -1
  89. data/lib/facter/facts/windows/gce.rb +1 -1
  90. data/lib/facter/facts/windows/hypervisors/hyperv.rb +1 -1
  91. data/lib/facter/facts/windows/hypervisors/kvm.rb +2 -1
  92. data/lib/facter/facts/windows/hypervisors/virtualbox.rb +2 -2
  93. data/lib/facter/facts/windows/hypervisors/vmware.rb +1 -1
  94. data/lib/facter/facts/windows/hypervisors/xen.rb +3 -1
  95. data/lib/facter/facts/windows/is_virtual.rb +15 -0
  96. data/lib/facter/facts/windows/{virtualization/is_virtual.rb → processors/cores.rb} +4 -4
  97. data/lib/facter/facts/windows/{virtualization/virtual.rb → processors/threads.rb} +4 -4
  98. data/lib/facter/facts/windows/virtual.rb +15 -0
  99. data/lib/facter/framework/cli/cli.rb +6 -8
  100. data/lib/facter/framework/config/config_reader.rb +2 -0
  101. data/lib/facter/framework/config/fact_groups.rb +25 -2
  102. data/lib/facter/framework/core/cache_manager.rb +7 -3
  103. data/lib/facter/framework/core/fact/external/external_fact_manager.rb +0 -1
  104. data/lib/facter/framework/core/fact/internal/internal_fact_manager.rb +41 -39
  105. data/lib/facter/framework/core/fact_filter.rb +5 -15
  106. data/lib/facter/framework/core/fact_loaders/external_fact_loader.rb +9 -6
  107. data/lib/facter/framework/core/fact_loaders/fact_loader.rb +39 -37
  108. data/lib/facter/framework/core/fact_manager.rb +84 -14
  109. data/lib/facter/framework/core/file_loader.rb +1 -1
  110. data/lib/facter/framework/core/options.rb +1 -2
  111. data/lib/facter/framework/core/options/config_file_options.rb +7 -0
  112. data/lib/facter/framework/core/options/option_store.rb +12 -6
  113. data/lib/facter/framework/formatters/formatter_helper.rb +3 -5
  114. data/lib/facter/framework/logging/logger.rb +4 -4
  115. data/lib/facter/framework/parsers/query_parser.rb +5 -12
  116. data/lib/facter/models/fact_collection.rb +48 -5
  117. data/lib/facter/models/resolved_fact.rb +2 -3
  118. data/lib/facter/models/searched_fact.rb +2 -3
  119. data/lib/facter/resolvers/aix/ffi/ffi_helper.rb +1 -1
  120. data/lib/facter/resolvers/aix/processors.rb +4 -0
  121. data/lib/facter/resolvers/az.rb +39 -0
  122. data/lib/facter/resolvers/base_resolver.rb +2 -2
  123. data/lib/facter/resolvers/dmi_decode.rb +0 -1
  124. data/lib/facter/resolvers/linux/hostname.rb +126 -0
  125. data/lib/facter/resolvers/linux/networking.rb +124 -0
  126. data/lib/facter/resolvers/macosx/mountpoints.rb +14 -1
  127. data/lib/facter/resolvers/macosx/processor.rb +16 -1
  128. data/lib/facter/resolvers/mountpoints.rb +16 -8
  129. data/lib/facter/resolvers/networking.rb +3 -2
  130. data/lib/facter/resolvers/partitions.rb +1 -1
  131. data/lib/facter/resolvers/processors_lscpu.rb +44 -0
  132. data/lib/facter/resolvers/redhat_release.rb +28 -12
  133. data/lib/facter/resolvers/ruby.rb +1 -1
  134. data/lib/facter/resolvers/selinux.rb +5 -7
  135. data/lib/facter/resolvers/solaris/ffi/functions.rb +1 -1
  136. data/lib/facter/resolvers/solaris/ffi/structs.rb +12 -0
  137. data/lib/facter/resolvers/solaris/mountpoints.rb +22 -16
  138. data/lib/facter/resolvers/solaris/networking.rb +20 -5
  139. data/lib/facter/resolvers/solaris/processors.rb +7 -0
  140. data/lib/facter/resolvers/solaris/zone.rb +0 -1
  141. data/lib/facter/resolvers/windows/ffi/identity_ffi.rb +5 -0
  142. data/lib/facter/resolvers/windows/identity.rb +1 -6
  143. data/lib/facter/resolvers/windows/processors.rb +41 -4
  144. data/lib/facter/resolvers/windows/uptime.rb +3 -22
  145. data/lib/facter/resolvers/windows/virtualization.rb +46 -44
  146. data/lib/facter/resolvers/xen.rb +6 -1
  147. data/lib/facter/templates/man.erb +13 -5
  148. data/lib/facter/util/facts/posix/virtual_detector.rb +74 -0
  149. data/lib/facter/util/facts/unit_converter.rb +2 -2
  150. data/lib/facter/util/linux/dhcp.rb +86 -0
  151. data/lib/facter/util/linux/if_inet6.rb +73 -0
  152. data/lib/facter/util/linux/routing_table.rb +60 -0
  153. data/lib/facter/util/linux/socket_parser.rb +114 -0
  154. data/lib/facter/util/resolvers/ffi/hostname.rb +70 -0
  155. data/lib/facter/util/resolvers/http.rb +7 -1
  156. data/lib/facter/util/resolvers/networking/primary_interface.rb +11 -5
  157. data/lib/facter/util/utils.rb +18 -1
  158. data/lib/facter/version.rb +1 -1
  159. metadata +63 -13
  160. data/lib/facter/facts/linux/cloud.rb +0 -15
  161. data/lib/facter/framework/core/fact_augmenter.rb +0 -37
  162. data/lib/facter/resolvers/cloud.rb +0 -39
  163. data/lib/facter/resolvers/networking_linux.rb +0 -296
  164. data/lib/facter/util/facts/virtual_detector.rb +0 -90
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Util
5
+ module Facts
6
+ module Posix
7
+ module VirtualDetector
8
+ class << self
9
+ def platform
10
+ @@fact_value ||= check_docker_lxc || check_freebsd || check_gce || retrieve_from_virt_what
11
+ @@fact_value ||= check_vmware || check_open_vz || check_vserver || check_xen || check_other_facts
12
+ @@fact_value ||= check_lspci || 'physical'
13
+
14
+ @@fact_value
15
+ end
16
+
17
+ private
18
+
19
+ def check_docker_lxc
20
+ Facter::Resolvers::Containers.resolve(:vm)
21
+ end
22
+
23
+ def check_gce
24
+ bios_vendor = Facter::Resolvers::Linux::DmiBios.resolve(:bios_vendor)
25
+ 'gce' if bios_vendor&.include?('Google')
26
+ end
27
+
28
+ def check_vmware
29
+ Facter::Resolvers::Vmware.resolve(:vm)
30
+ end
31
+
32
+ def retrieve_from_virt_what
33
+ Facter::Resolvers::VirtWhat.resolve(:vm)
34
+ end
35
+
36
+ def check_open_vz
37
+ Facter::Resolvers::OpenVz.resolve(:vm)
38
+ end
39
+
40
+ def check_vserver
41
+ Facter::Resolvers::VirtWhat.resolve(:vserver)
42
+ end
43
+
44
+ def check_xen
45
+ Facter::Resolvers::Xen.resolve(:vm)
46
+ end
47
+
48
+ def check_freebsd
49
+ return unless Object.const_defined?('Facter::Resolvers::Freebsd::Virtual')
50
+
51
+ Facter::Resolvers::Freebsd::Virtual.resolve(:vm)
52
+ end
53
+
54
+ def check_other_facts
55
+ bios_vendor = Facter::Resolvers::Linux::DmiBios.resolve(:bios_vendor)
56
+ return 'kvm' if bios_vendor&.include?('Amazon EC2')
57
+
58
+ product_name = Facter::Resolvers::Linux::DmiBios.resolve(:product_name)
59
+ return unless product_name
60
+
61
+ Facter::Util::Facts::HYPERVISORS_HASH.each { |key, value| return value if product_name.include?(key) }
62
+
63
+ nil
64
+ end
65
+
66
+ def check_lspci
67
+ Facter::Resolvers::Lspci.resolve(:vm)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -10,7 +10,7 @@ module Facter
10
10
 
11
11
  value_in_bytes = value_in_bytes.to_i
12
12
 
13
- (value_in_bytes / (1024.0 * 1024.0)).round(2)
13
+ (value_in_bytes / (1024.0 * 1024.0))
14
14
  end
15
15
 
16
16
  def hertz_to_human_readable(speed)
@@ -19,7 +19,7 @@ module Facter
19
19
 
20
20
  validated_speed, metric_prefix = determine_metric_prefix(speed)
21
21
 
22
- format('%<displayed_speed>.2f', displayed_speed: validated_speed).to_s + ' ' + metric_prefix + 'Hz'
22
+ format('%<displayed_speed>.2f', displayed_speed: validated_speed.round(2)).to_s + ' ' + metric_prefix + 'Hz'
23
23
  end
24
24
 
25
25
  def bytes_to_human_readable(bytes)
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Util
5
+ module Linux
6
+ class Dhcp
7
+ class << self
8
+ DIRS = %w[/var/lib/dhclient/
9
+ /var/lib/dhcp/
10
+ /var/lib/dhcp3/
11
+ /var/lib/NetworkManager/
12
+ /var/db/].freeze
13
+
14
+ def dhcp(interface_name, interface_index, logger)
15
+ @log = logger
16
+ @log.debug("Get DHCP for interface #{interface_name}")
17
+
18
+ dhcp = search_systemd_netif_leases(interface_index, interface_name)
19
+ dhcp ||= search_dhclient_leases(interface_name)
20
+ dhcp ||= search_internal_leases(interface_name)
21
+ dhcp ||= search_with_dhcpcd_command(interface_name)
22
+ dhcp
23
+ end
24
+
25
+ private
26
+
27
+ def search_systemd_netif_leases(index, interface_name)
28
+ return if index.nil?
29
+
30
+ @log.debug("Attempt to get DHCP for interface #{interface_name}, from systemd/netif/leases")
31
+
32
+ file_content = Facter::Util::FileHelper.safe_read("/run/systemd/netif/leases/#{index}", nil)
33
+ dhcp = file_content.match(/SERVER_ADDRESS=(.*)/) if file_content
34
+ dhcp[1] if dhcp
35
+ end
36
+
37
+ def search_dhclient_leases(interface_name)
38
+ @log.debug("Attempt to get DHCP for interface #{interface_name}, from dhclient leases")
39
+
40
+ DIRS.each do |dir|
41
+ next unless File.readable?(dir)
42
+
43
+ lease_files = Dir.entries(dir).select { |file| file =~ /dhclient.*\.lease/ }
44
+ next if lease_files.empty?
45
+
46
+ lease_files.select do |file|
47
+ content = Facter::Util::FileHelper.safe_read("#{dir}#{file}", nil)
48
+ next unless content =~ /interface.*#{interface_name}/
49
+
50
+ dhcp = content.match(/dhcp-server-identifier ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/)
51
+ return dhcp[1] if dhcp
52
+ end
53
+ end
54
+
55
+ nil
56
+ end
57
+
58
+ def search_internal_leases(interface_name)
59
+ return unless File.readable?('/var/lib/NetworkManager/')
60
+
61
+ @log.debug("Attempt to get DHCP for interface #{interface_name}, from NetworkManager leases")
62
+
63
+ files = Dir.entries('/var/lib/NetworkManager/').reject { |dir| dir =~ /^\.+$/ }
64
+ lease_file = files.find { |file| file =~ /internal.*#{interface_name}\.lease/ }
65
+ return unless lease_file
66
+
67
+ dhcp = Facter::Util::FileHelper.safe_read("/var/lib/NetworkManager/#{lease_file}", nil)
68
+
69
+ return unless dhcp
70
+
71
+ dhcp = dhcp.match(/SERVER_ADDRESS=(.*)/)
72
+ dhcp[1] if dhcp
73
+ end
74
+
75
+ def search_with_dhcpcd_command(interface_name)
76
+ @log.debug("Attempt to get DHCP for interface #{interface_name}, from dhcpcd command")
77
+
78
+ output = Facter::Core::Execution.execute("dhcpcd -U #{interface_name}", logger: @log)
79
+ dhcp = output.match(/dhcp_server_identifier='(.*)'/)
80
+ dhcp[1] if dhcp
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+
5
+ module Facter
6
+ module Util
7
+ module Linux
8
+ class IfInet6
9
+ class << self
10
+ IFA_FLAGS = {
11
+ 'temporary' => 0x01,
12
+ 'noad' => 0x02,
13
+ 'optimistic' => 0x04,
14
+ 'dadfailed' => 0x08,
15
+ 'homeaddress' => 0x10,
16
+ 'deprecated' => 0x20,
17
+ 'tentative' => 0x40,
18
+ 'permanent' => 0x80
19
+ # /proc/net/if_inet6 only supports the old 8bit flags
20
+ # I have been unable to find a simple solution to accesses
21
+ # the full 32bit flags. netlink is all I can could find but
22
+ # that will likely be ugly
23
+ # 'managetempaddr' => 0x100,
24
+ # 'noprefixroute' => 0x200,
25
+ # 'mcautojoin' => 0x400,
26
+ # 'stableprivacy' => 0x800
27
+ }.freeze
28
+
29
+ def read_flags
30
+ return read_flags_from_proc if File.exist?('/proc/net/if_inet6')
31
+
32
+ {}
33
+ end
34
+
35
+ private
36
+
37
+ def read_flags_from_proc
38
+ flags = init_flags
39
+ Facter::Util::FileHelper.safe_read('/proc/net/if_inet6', nil).each_line do |line|
40
+ iface = line.split
41
+ next unless iface.size == 6
42
+
43
+ ip = parse_ip(iface[0])
44
+ flags[iface[5]][ip] = parse_ifa_flags(iface[4])
45
+ end
46
+ flags
47
+ end
48
+
49
+ def init_flags
50
+ Hash.new { |h1, k1| h1[k1] = Hash.new { |h2, k2| h2[k2] = [] } }
51
+ end
52
+
53
+ def parse_ifa_flags(flag)
54
+ flag = flag.hex
55
+ flags = []
56
+ IFA_FLAGS.each_pair do |name, value|
57
+ next if (flag & value).zero?
58
+
59
+ flags << name
60
+ end
61
+ flags
62
+ end
63
+
64
+ def parse_ip(ip)
65
+ # The ip address in if_net6 is a long string wit no colons
66
+ ip = ip.scan(/(\h{4})/).join(':')
67
+ IPAddr.new(ip).to_s
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Util
5
+ module Linux
6
+ class RoutingTable
7
+ class << self
8
+ ROUTE_TYPES = %w[anycast
9
+ unicast
10
+ broadcast
11
+ local
12
+ nat
13
+ unreachable
14
+ prohibit
15
+ blackhole
16
+ throw].freeze
17
+
18
+ def read_routing_table(logger)
19
+ ipv4_output = Facter::Core::Execution.execute('ip route show', logger: logger)
20
+ ipv6_output = Facter::Core::Execution.execute('ip -6 route show', logger: logger)
21
+ routes4 = parse_routes(ipv4_output, true)
22
+ routes6 = parse_routes(ipv6_output, false)
23
+ [routes4, routes6]
24
+ end
25
+
26
+ private
27
+
28
+ def parse_routes(output, ipv4_type)
29
+ routes = []
30
+ output.each_line do |line|
31
+ parts = line.split(' ').compact
32
+ next if parts.include?('linkdown')
33
+
34
+ delete_invalid_route_type(parts)
35
+ next if !ipv4_type && !parts[0].include?(':')
36
+
37
+ route = construct_route(parts)
38
+ routes << route unless route[:ip].nil?
39
+ end
40
+ routes.uniq
41
+ end
42
+
43
+ def delete_invalid_route_type(parts)
44
+ route_type = parts[0]
45
+ parts.delete_at(0) if ROUTE_TYPES.include?(route_type)
46
+ end
47
+
48
+ def construct_route(parts)
49
+ route = {}
50
+ dev_index = parts.find_index { |elem| elem == 'dev' }
51
+ src_index = parts.find_index { |elem| elem == 'src' }
52
+ route[:interface] = parts[dev_index + 1] if dev_index
53
+ route[:ip] = parts[src_index + 1] if src_index
54
+ route
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Util
5
+ module Linux
6
+ class SocketParser
7
+ class << self
8
+ def retrieve_interfaces(logger)
9
+ require 'socket'
10
+ @interfaces = {}
11
+ @log = logger
12
+ Socket.getifaddrs.each do |ifaddr|
13
+ populate_interface_info(ifaddr)
14
+ end
15
+
16
+ @interfaces
17
+ end
18
+
19
+ private
20
+
21
+ def populate_interface_info(ifaddr)
22
+ interface_name = ifaddr.name
23
+ @interfaces[interface_name] = {} if @interfaces[interface_name].nil?
24
+
25
+ mac(ifaddr)
26
+ ip_info_of(ifaddr)
27
+ end
28
+
29
+ def mac(ifaddr)
30
+ return unless @interfaces[ifaddr.name][:mac].nil?
31
+
32
+ mac = search_for_mac(ifaddr)
33
+ @interfaces[ifaddr.name][:mac] = mac if mac
34
+ end
35
+
36
+ def search_for_mac(ifaddr)
37
+ mac = mac_from_bonded_interface(ifaddr.name)
38
+ mac ||= mac_from(ifaddr)
39
+ mac if !mac.nil? && mac != '00:00:00:00:00:00' && mac =~ /^([0-9A-Fa-f]{2}[:-]){5,19}([0-9A-Fa-f]{2})$/
40
+ end
41
+
42
+ def mac_from_bonded_interface(interface_name)
43
+ master = bond_master_of(interface_name)
44
+ return unless master
45
+
46
+ output = Facter::Util::FileHelper.safe_read("/proc/net/bonding/#{master}", nil)
47
+ return unless output
48
+
49
+ found_match = false
50
+ output.each_line do |line|
51
+ if line.strip == "Slave Interface: #{interface_name}"
52
+ found_match = true
53
+ elsif line.include? 'Slave Interface'
54
+ # if we reached the data block of another interface belonging to the bonded interface
55
+ found_match = false
56
+ end
57
+ return Regexp.last_match(1) if found_match && line =~ /Permanent HW addr: (\S*)/
58
+ end
59
+ end
60
+
61
+ def bond_master_of(interface_name)
62
+ content = Facter::Core::Execution.execute("ip link show #{interface_name}", logger: @log)
63
+ content.match(/master (\S*) /)&.captures&.first
64
+ end
65
+
66
+ def mac_from(ifaddr)
67
+ if Socket.const_defined? :PF_LINK
68
+ ifaddr.addr&.getnameinfo&.first # sometimes it returns localhost or ip
69
+ elsif Socket.const_defined? :PF_PACKET
70
+ return if ifaddr.addr.nil?
71
+
72
+ mac_from_sockaddr_of(ifaddr)
73
+ end
74
+ rescue StandardError => e
75
+ @log.debug("Could not read mac for interface #{ifaddr.name}, got #{e}")
76
+ end
77
+
78
+ def mac_from_sockaddr_of(ifaddr)
79
+ result = ifaddr.addr.inspect_sockaddr
80
+ result&.match(/hwaddr=([\h:]+)/)&.captures&.first
81
+ end
82
+
83
+ def ip_info_of(ifaddr)
84
+ return if ifaddr.addr.nil? || ifaddr.netmask.nil?
85
+
86
+ add_binding(ifaddr.name, ifaddr)
87
+ rescue StandardError => e
88
+ @log.debug("Could not read binding data, got #{e}")
89
+ end
90
+
91
+ def add_binding(interface_name, ifaddr)
92
+ ip, netmask, binding_key = binding_data(ifaddr)
93
+ binding = Facter::Util::Resolvers::Networking.build_binding(ip, netmask)
94
+ return if binding.nil?
95
+
96
+ @interfaces[interface_name][binding_key] = [] if @interfaces[interface_name][binding_key].nil?
97
+ @interfaces[interface_name][binding_key] << binding
98
+
99
+ @log.debug("Adding to interface #{interface_name}, binding:\n#{binding}")
100
+ end
101
+
102
+ def binding_data(ifaddr)
103
+ # ipv6 ips are retrieved as <ip>%<interface_name>
104
+ ip = ifaddr.addr.ip_address.split('%').first
105
+ netmask = ifaddr.netmask.ip_address
106
+ binding_key = ifaddr.addr.ipv4? ? :bindings : :bindings6
107
+
108
+ [ip, netmask, binding_key]
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+
5
+ module Facter
6
+ module Util
7
+ module Resolvers
8
+ module Ffi
9
+ class AddrInfo < ::FFI::Struct
10
+ layout :ai_flags, :int,
11
+ :ai_family, :int,
12
+ :ai_socketype, :int,
13
+ :ai_protocol, :int,
14
+ :ai_addrlen, :uint,
15
+ :ai_addr, :pointer,
16
+ :ai_canonname, :string,
17
+ :ai_next, :pointer
18
+ end
19
+
20
+ module Hostname
21
+ HOST_NAME_MAX = 64
22
+
23
+ extend ::FFI::Library
24
+ ffi_lib ::FFI::Library::LIBC
25
+
26
+ attach_function :getaddrinfo, %i[string string pointer pointer], :int
27
+ attach_function :gethostname, %i[pointer int], :int
28
+ attach_function :freeaddrinfo, [:pointer], :void
29
+
30
+ def self.getffihostname
31
+ raw_hostname = ::FFI::MemoryPointer.new(:char, HOST_NAME_MAX)
32
+
33
+ res = Hostname.gethostname(raw_hostname, HOST_NAME_MAX)
34
+ return unless res.zero?
35
+
36
+ raw_hostname.read_string
37
+ end
38
+
39
+ def self.getffiaddrinfo(hostname) # rubocop:disable Metrics/AbcSize
40
+ ret = FFI::MemoryPointer.new(:pointer)
41
+
42
+ hints = Facter::Util::Resolvers::Ffi::AddrInfo.new
43
+ hints[:ai_family] = Socket::AF_UNSPEC
44
+ hints[:ai_socketype] = Socket::SOCK_STREAM
45
+ hints[:ai_flags] = Socket::AI_CANONNAME
46
+
47
+ res = Hostname.getaddrinfo(hostname, '', hints.to_ptr, ret)
48
+ log = Log.new(self)
49
+ log.debug("FFI Getaddrinfo finished with exit status: #{res}")
50
+ log.debug("FFI Getaddrinfo returned an AddrInfo struct at address: #{ret}")
51
+ return unless res.zero?
52
+
53
+ return if ret == FFI::Pointer::NULL || ret.read_pointer == FFI::Pointer::NULL
54
+
55
+ begin
56
+ addr = Facter::Util::Resolvers::Ffi::AddrInfo.new(ret.read_pointer)
57
+ name = addr[:ai_canonname]
58
+ log.debug("FFI AddrInfo struct has the fqdn: #{name}")
59
+ return if !name || hostname == name
60
+
61
+ name
62
+ ensure
63
+ Hostname.freeaddrinfo(ret.read_pointer)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end