facter 4.0.51 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. checksums.yaml +4 -4
  2. data/lib/docs/generate_cli.rb +7 -0
  3. data/lib/facter.rb +71 -58
  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 +17 -19
  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 +4 -4
  113. data/lib/facter/framework/formatters/formatter_helper.rb +3 -5
  114. data/lib/facter/framework/parsers/query_parser.rb +5 -12
  115. data/lib/facter/models/fact_collection.rb +48 -5
  116. data/lib/facter/models/resolved_fact.rb +2 -3
  117. data/lib/facter/models/searched_fact.rb +2 -3
  118. data/lib/facter/resolvers/aix/ffi/ffi_helper.rb +1 -1
  119. data/lib/facter/resolvers/aix/processors.rb +4 -0
  120. data/lib/facter/resolvers/az.rb +39 -0
  121. data/lib/facter/resolvers/base_resolver.rb +2 -2
  122. data/lib/facter/resolvers/dmi_decode.rb +0 -1
  123. data/lib/facter/resolvers/ec2.rb +8 -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/ffi/kernel_ffi.rb +1 -1
  143. data/lib/facter/resolvers/windows/identity.rb +1 -6
  144. data/lib/facter/resolvers/windows/processors.rb +41 -4
  145. data/lib/facter/resolvers/windows/uptime.rb +3 -22
  146. data/lib/facter/resolvers/windows/virtualization.rb +46 -44
  147. data/lib/facter/resolvers/xen.rb +6 -1
  148. data/lib/facter/templates/man.erb +13 -5
  149. data/lib/facter/util/facts/posix/virtual_detector.rb +74 -0
  150. data/lib/facter/util/facts/unit_converter.rb +2 -2
  151. data/lib/facter/util/linux/dhcp.rb +86 -0
  152. data/lib/facter/util/linux/if_inet6.rb +73 -0
  153. data/lib/facter/util/linux/routing_table.rb +60 -0
  154. data/lib/facter/util/linux/socket_parser.rb +114 -0
  155. data/lib/facter/util/resolvers/ffi/hostname.rb +70 -0
  156. data/lib/facter/util/resolvers/http.rb +7 -1
  157. data/lib/facter/util/resolvers/networking/primary_interface.rb +11 -5
  158. data/lib/facter/util/utils.rb +18 -1
  159. data/lib/facter/version.rb +1 -1
  160. metadata +77 -13
  161. data/lib/facter/facts/linux/cloud.rb +0 -15
  162. data/lib/facter/framework/core/fact_augmenter.rb +0 -37
  163. data/lib/facter/resolvers/cloud.rb +0 -39
  164. data/lib/facter/resolvers/networking_linux.rb +0 -296
  165. 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