facter 4.0.26 → 4.0.28

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/.github/actions/presuite.rb +1 -12
  3. data/.github/workflows/acceptance_tests.yml +4 -4
  4. data/.github/workflows/checks.yaml +9 -3
  5. data/.github/workflows/coverage.yaml +1 -1
  6. data/.github/workflows/unit_tests.yaml +2 -2
  7. data/.rubocop.yml +5 -0
  8. data/.rubocop_todo.yml +6 -4
  9. data/CHANGELOG.md +22 -0
  10. data/Rakefile +2 -1
  11. data/VERSION +1 -1
  12. data/acceptance/.beaker.yml +15 -0
  13. data/acceptance/.gitignore +12 -0
  14. data/acceptance/Gemfile +24 -0
  15. data/acceptance/Rakefile +2 -0
  16. data/acceptance/bin/ci-bootstrap-from-artifacts.sh +55 -0
  17. data/acceptance/config/aio/options.rb +6 -0
  18. data/acceptance/config/git/options.rb +3 -0
  19. data/acceptance/config/nodes/aix-53-power.yaml +7 -0
  20. data/acceptance/config/nodes/aix-61-power.yaml +7 -0
  21. data/acceptance/config/nodes/aix-71-power.yaml +7 -0
  22. data/acceptance/config/nodes/huaweios-6-powerpc.yaml +7 -0
  23. data/acceptance/config/nodes/solaris-10-sparc.yaml +9 -0
  24. data/acceptance/config/nodes/solaris-11-sparc.yaml +9 -0
  25. data/acceptance/lib/facter/acceptance/base_fact_utils.rb +565 -0
  26. data/acceptance/lib/facter/acceptance/user_fact_utils.rb +132 -0
  27. data/acceptance/lib/helper.rb +3 -0
  28. data/acceptance/lib/puppet/acceptance/common_utils.rb +10 -0
  29. data/acceptance/lib/puppet/acceptance/git_utils.rb +19 -0
  30. data/acceptance/lib/puppet/acceptance/install_utils.rb +58 -0
  31. data/acceptance/setup/aio/pre-suite/001_run_with_facter_ng.rb +75 -0
  32. data/acceptance/tests/custom_facts/cached_custom_fact.rb +82 -0
  33. data/acceptance/tests/custom_facts/conflicts_with_builtin_fact.rb +106 -0
  34. data/acceptance/tests/custom_facts/custom_fact_with_10001_weight_overrides_external_fact.rb +30 -0
  35. data/acceptance/tests/custom_facts/expand_command.rb +30 -0
  36. data/acceptance/tests/custom_facts/having_multiple_facts_in_one_file.rb +40 -0
  37. data/acceptance/tests/custom_facts/not_expand_command.rb +30 -0
  38. data/acceptance/tests/custom_facts/using_win32ole_should_not_hang.rb +33 -0
  39. data/acceptance/tests/custom_facts/weighted_cached_custom_facts.rb +94 -0
  40. data/acceptance/tests/custom_facts/windows_not_expand_command.rb +30 -0
  41. data/acceptance/tests/external_facts/env_var_overrides_external_fact.rb +46 -0
  42. data/acceptance/tests/external_facts/external_dir_overrides_default_external_fact.rb +34 -0
  43. data/acceptance/tests/external_facts/external_fact_overrides_custom_fact.rb +29 -0
  44. data/acceptance/tests/external_facts/external_fact_overrides_custom_fact_with_10000_weight_or_less.rb +30 -0
  45. data/acceptance/tests/external_facts/external_fact_overrides_custom_fact_with_confine.rb +35 -0
  46. data/acceptance/tests/external_facts/external_fact_stderr_messages_output_to_stderr.rb +49 -0
  47. data/acceptance/tests/external_facts/external_facts_only_run_once.rb +43 -0
  48. data/acceptance/tests/external_facts/fact_directory_precedence.rb +109 -0
  49. data/acceptance/tests/external_facts/handle_same_filename_in_different_dirs.rb +59 -0
  50. data/acceptance/tests/external_facts/non_root_users_default_external_fact_directory.rb +142 -0
  51. data/acceptance/tests/external_facts/root_uses_default_external_fact_dir.rb +34 -0
  52. data/acceptance/tests/external_facts/structured_executable_facts.rb +139 -0
  53. data/acceptance/tests/facter_returns_success_on_non_existent_fact.rb +9 -0
  54. data/acceptance/tests/facts/dmi.rb +51 -0
  55. data/acceptance/tests/facts/facterversion.rb +11 -0
  56. data/acceptance/tests/facts/identity.rb +52 -0
  57. data/acceptance/tests/facts/mountpoints_fact.rb +12 -0
  58. data/acceptance/tests/facts/networking_facts.rb +93 -0
  59. data/acceptance/tests/facts/nim_type.rb +12 -0
  60. data/acceptance/tests/facts/non_root_users_without_errors.rb +32 -0
  61. data/acceptance/tests/facts/operatingsystem_detection_after_clear_on_ubuntu.rb +26 -0
  62. data/acceptance/tests/facts/os_processors_and_kernel.rb +20 -0
  63. data/acceptance/tests/facts/osx_numeric_hostname.rb +23 -0
  64. data/acceptance/tests/facts/partitions.rb +37 -0
  65. data/acceptance/tests/facts/productname.rb +15 -0
  66. data/acceptance/tests/facts/ruby.rb +59 -0
  67. data/acceptance/tests/facts/ssh_key.rb +59 -0
  68. data/acceptance/tests/facts/validate_file_system_size_bytes.rb +37 -0
  69. data/acceptance/tests/facts/verify_tmpfs_file_system.rb +54 -0
  70. data/acceptance/tests/facts/windows_os.rb +64 -0
  71. data/acceptance/tests/load_libfacter.rb +66 -0
  72. data/acceptance/tests/no_errors_on_stderr.rb +10 -0
  73. data/acceptance/tests/options/color.rb +16 -0
  74. data/acceptance/tests/options/config.rb +27 -0
  75. data/acceptance/tests/options/config_file/blocklist.rb +35 -0
  76. data/acceptance/tests/options/config_file/blocklist_from_puppet_facts.rb +40 -0
  77. data/acceptance/tests/options/config_file/custom_dir_overridden_by_cli_custom_dir.rb +56 -0
  78. data/acceptance/tests/options/config_file/custom_facts.rb +42 -0
  79. data/acceptance/tests/options/config_file/custom_facts_list.rb +56 -0
  80. data/acceptance/tests/options/config_file/debug.rb +34 -0
  81. data/acceptance/tests/options/config_file/debug_override_config_file.rb +34 -0
  82. data/acceptance/tests/options/config_file/default_file_location.rb +37 -0
  83. data/acceptance/tests/options/config_file/external_dir_conflicts_with_cli_no_external_facts.rb +37 -0
  84. data/acceptance/tests/options/config_file/external_dir_overridden_by_cli_external_dir.rb +40 -0
  85. data/acceptance/tests/options/config_file/external_facts.rb +37 -0
  86. data/acceptance/tests/options/config_file/external_facts_list.rb +43 -0
  87. data/acceptance/tests/options/config_file/load_from_ruby.rb +73 -0
  88. data/acceptance/tests/options/config_file/log_level.rb +35 -0
  89. data/acceptance/tests/options/config_file/no_custom_facts_and_custom_dir.rb +43 -0
  90. data/acceptance/tests/options/config_file/no_custom_facts_and_facterlib.rb +43 -0
  91. data/acceptance/tests/options/config_file/no_custom_facts_and_load_path.rb +49 -0
  92. data/acceptance/tests/options/config_file/no_external_facts.rb +38 -0
  93. data/acceptance/tests/options/config_file/no_external_facts_and_external_dir.rb +34 -0
  94. data/acceptance/tests/options/config_file/no_ruby_disables_custom_facts.rb +52 -0
  95. data/acceptance/tests/options/config_file/no_ruby_disables_ruby_facts.rb +34 -0
  96. data/acceptance/tests/options/config_file/trace.rb +48 -0
  97. data/acceptance/tests/options/config_file/ttls_cached_external_execution_resolver_with_json_output.rb +92 -0
  98. data/acceptance/tests/options/config_file/ttls_cached_external_execution_resolver_with_text_output.rb +74 -0
  99. data/acceptance/tests/options/config_file/ttls_cached_external_execution_resolver_with_yaml_output.rb +88 -0
  100. data/acceptance/tests/options/config_file/ttls_cached_external_json_resolver.rb +79 -0
  101. data/acceptance/tests/options/config_file/ttls_cached_external_text_resolver.rb +78 -0
  102. data/acceptance/tests/options/config_file/ttls_cached_external_yaml_resolver.rb +78 -0
  103. data/acceptance/tests/options/config_file/ttls_cached_facts_clear_by_empty_ttls_cache_list.rb +71 -0
  104. data/acceptance/tests/options/config_file/ttls_cached_facts_creates_json_cache_file.rb +48 -0
  105. data/acceptance/tests/options/config_file/ttls_cached_facts_expire_facts_do_not_read_the_old_cached_value.rb +58 -0
  106. data/acceptance/tests/options/config_file/ttls_cached_facts_expire_facts_refresh_the_cached_value.rb +61 -0
  107. data/acceptance/tests/options/config_file/ttls_cached_facts_read_from_the_cached_value.rb +57 -0
  108. data/acceptance/tests/options/config_file/ttls_cached_facts_that_are_corrupt_are_refreshed.rb +53 -0
  109. data/acceptance/tests/options/config_file/ttls_cached_facts_that_are_empty_return_an_empty_value.rb +53 -0
  110. data/acceptance/tests/options/config_file/ttls_puppet_facts_creates_json_for_cached_facts.rb +45 -0
  111. data/acceptance/tests/options/config_file/ttls_puppet_facts_honors_cached_facts.rb +54 -0
  112. data/acceptance/tests/options/config_file/verbose.rb +34 -0
  113. data/acceptance/tests/options/custom_facts.rb +34 -0
  114. data/acceptance/tests/options/custom_facts_facterlib.rb +33 -0
  115. data/acceptance/tests/options/custom_facts_list.rb +48 -0
  116. data/acceptance/tests/options/custom_facts_load_path.rb +42 -0
  117. data/acceptance/tests/options/debug.rb +12 -0
  118. data/acceptance/tests/options/external_facts.rb +28 -0
  119. data/acceptance/tests/options/external_facts_list.rb +35 -0
  120. data/acceptance/tests/options/help.rb +13 -0
  121. data/acceptance/tests/options/json.rb +43 -0
  122. data/acceptance/tests/options/list_block_groups.rb +15 -0
  123. data/acceptance/tests/options/list_block_groups_facter_4.rb +15 -0
  124. data/acceptance/tests/options/list_cache_groups.rb +65 -0
  125. data/acceptance/tests/options/log_level.rb +13 -0
  126. data/acceptance/tests/options/no_block.rb +34 -0
  127. data/acceptance/tests/options/no_cache_should_not_cache_facts.rb +43 -0
  128. data/acceptance/tests/options/no_cache_should_not_load_cached_facts.rb +58 -0
  129. data/acceptance/tests/options/no_cache_should_not_refresh_cached_facts.rb +63 -0
  130. data/acceptance/tests/options/no_color.rb +16 -0
  131. data/acceptance/tests/options/no_custom_facts.rb +34 -0
  132. data/acceptance/tests/options/no_custom_facts_and_custom_dir.rb +19 -0
  133. data/acceptance/tests/options/no_custom_facts_and_facterlib.rb +34 -0
  134. data/acceptance/tests/options/no_custom_facts_and_load_path.rb +43 -0
  135. data/acceptance/tests/options/no_external_facts.rb +28 -0
  136. data/acceptance/tests/options/no_external_facts_and_external_dir.rb +19 -0
  137. data/acceptance/tests/options/no_ruby.rb +44 -0
  138. data/acceptance/tests/options/puppet_facts.rb +37 -0
  139. data/acceptance/tests/options/show_legacy.rb +18 -0
  140. data/acceptance/tests/options/strict.rb +11 -0
  141. data/acceptance/tests/options/trace.rb +36 -0
  142. data/acceptance/tests/options/verbose.rb +12 -0
  143. data/acceptance/tests/options/version.rb +12 -0
  144. data/acceptance/tests/options/yaml.rb +43 -0
  145. data/acceptance/tests/ticket_1123_facter_with_invalid_locale.rb +23 -0
  146. data/acceptance/tests/ticket_1238_hostname_fqdn.rb +57 -0
  147. data/lib/custom_facts/core/execution/base.rb +18 -18
  148. data/lib/custom_facts/util/collection.rb +2 -7
  149. data/lib/custom_facts/util/config.rb +1 -1
  150. data/lib/custom_facts/util/directory_loader.rb +51 -24
  151. data/lib/custom_facts/util/fact.rb +10 -1
  152. data/lib/custom_facts/util/resolution.rb +1 -1
  153. data/lib/facts/aix/aio_agent_version.rb +14 -0
  154. data/lib/facts/bsd/processors/count.rb +17 -0
  155. data/lib/facts/bsd/processors/models.rb +23 -0
  156. data/lib/facts/bsd/processors/speed.rb +17 -0
  157. data/lib/facts/freebsd/disks.rb +15 -0
  158. data/lib/facts/freebsd/partitions.rb +15 -0
  159. data/lib/facts/freebsd/processors/count.rb +17 -0
  160. data/lib/facts/freebsd/processors/models.rb +23 -0
  161. data/lib/facts/freebsd/processors/speed.rb +17 -0
  162. data/lib/facts/linux/aio_agent_version.rb +14 -0
  163. data/lib/facts/linux/ec2_metadata.rb +47 -0
  164. data/lib/facts/linux/ec2_userdata.rb +47 -0
  165. data/lib/facts/linux/is_virtual.rb +2 -5
  166. data/lib/facts/linux/virtual.rb +1 -5
  167. data/lib/facts/macosx/aio_agent_version.rb +14 -0
  168. data/lib/facts/macosx/interfaces.rb +2 -2
  169. data/lib/facts/macosx/networking/dhcp.rb +17 -0
  170. data/lib/facts/macosx/networking/interfaces.rb +21 -0
  171. data/lib/facts/macosx/networking/ip.rb +4 -1
  172. data/lib/facts/macosx/networking/ip6.rb +21 -0
  173. data/lib/facts/macosx/networking/mac.rb +4 -1
  174. data/lib/facts/macosx/networking/mtu.rb +20 -0
  175. data/lib/facts/macosx/networking/netmask.rb +21 -0
  176. data/lib/facts/macosx/networking/netmask6.rb +21 -0
  177. data/lib/facts/macosx/networking/network.rb +21 -0
  178. data/lib/facts/macosx/networking/network6.rb +21 -0
  179. data/lib/facts/macosx/networking/primary.rb +17 -0
  180. data/lib/facts/macosx/networking/scope6.rb +20 -0
  181. data/lib/facts/solaris/aio_agent_version.rb +14 -0
  182. data/lib/facts/windows/aio_agent_version.rb +14 -0
  183. data/lib/facts/windows/ec2_metadata.rb +23 -0
  184. data/lib/facts/windows/ec2_userdata.rb +23 -0
  185. data/lib/facts_utils/hypervisors.rb +10 -0
  186. data/lib/framework/core/cache_manager.rb +42 -18
  187. data/lib/framework/core/fact/external/external_fact_manager.rb +3 -2
  188. data/lib/framework/core/fact_loaders/external_fact_loader.rb +3 -2
  189. data/lib/framework/formatters/legacy_fact_formatter.rb +6 -5
  190. data/lib/framework/parsers/query_parser.rb +14 -2
  191. data/lib/models/loaded_fact.rb +3 -1
  192. data/lib/models/resolved_fact.rb +1 -1
  193. data/lib/models/searched_fact.rb +1 -0
  194. data/lib/resolvers/{agent_resolver.rb → aio_agent_version.rb} +4 -3
  195. data/lib/resolvers/bsd/ffi/ffi_helper.rb +31 -0
  196. data/lib/resolvers/bsd/processors.rb +47 -0
  197. data/lib/resolvers/ec2.rb +77 -0
  198. data/lib/resolvers/freebsd/ffi/ffi_helper.rb +42 -0
  199. data/lib/resolvers/freebsd/geom_resolver.rb +109 -0
  200. data/lib/resolvers/freebsd/processors.rb +44 -0
  201. data/lib/resolvers/macosx/networking.rb +110 -0
  202. data/lib/resolvers/networking_linux_resolver.rb +8 -30
  203. data/lib/resolvers/utils/networking.rb +70 -0
  204. data/lib/resolvers/windows/aio_agent_version.rb +56 -0
  205. metadata +175 -5
  206. data/lib/resolvers/macosx/ipaddress_resolver.rb +0 -52
@@ -0,0 +1,12 @@
1
+ # This test is intended to ensure that the --verbose command-line option
2
+ # works properly. This option provides verbose (INFO) output to stderr.
3
+ test_name "C99986: --verbose command-line option prints verbose information to stderr" do
4
+
5
+ agents.each do |agent|
6
+ step "Agent #{agent}: retrieve verbose info from stderr using --verbose option" do
7
+ on(agent, facter('--verbose')) do
8
+ assert_match(/INFO .* executed with command line: --verbose/, stderr, "Expected stderr to contain verbose (INFO) statements")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # This test is intended to ensure that the --version command-line option works
2
+ # properly. This option outputs the current Facter version.
3
+ test_name "C99983: --version command-line option returns the version string" do
4
+
5
+ agents.each do |agent|
6
+ step "Agent #{agent}: retrieve version info using the --version option" do
7
+ on(agent, facter('--version')) do
8
+ assert_match(/\d+\.\d+\.\d+/, stdout, "Output #{stdout} is not a recognized version string")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,43 @@
1
+ # This test is intended to ensure that the --yaml command-line option works
2
+ # properly. This option causes Facter to output facts in YAML format.
3
+ # A custom fact is used to test for parity between Facter's output and
4
+ # the expected YAML output.
5
+ test_name "C99967: --yaml command-line option results in valid YAML output" do
6
+
7
+ require 'yaml'
8
+ require 'facter/acceptance/user_fact_utils'
9
+ extend Facter::Acceptance::UserFactUtils
10
+
11
+ content = <<EOM
12
+ Facter.add('structured_fact') do
13
+ setcode do
14
+ { "foo" => {"nested" => "value1"}, "bar" => "value2", "baz" => "value3" }
15
+ end
16
+ end
17
+ EOM
18
+
19
+ agents.each do |agent|
20
+ step "Agent #{agent}: create a structured custom fact" do
21
+ custom_dir = get_user_fact_dir(agent['platform'], on(agent, facter('kernelmajversion')).stdout.chomp.to_f)
22
+ custom_fact = File.join(custom_dir, 'custom_fact.rb')
23
+ on(agent, "mkdir -p '#{custom_dir}'")
24
+ create_remote_file(agent, custom_fact, content)
25
+ on(agent, "chmod +x '#{custom_fact}'")
26
+
27
+ teardown do
28
+ on(agent, "rm -f '#{custom_fact}'")
29
+ end
30
+
31
+ step "Agent #{agent}: retrieve output using the --yaml option" do
32
+ on(agent, facter("--custom-dir '#{custom_dir}' --yaml structured_fact")) do
33
+ begin
34
+ expected = {"structured_fact" => {"foo" => {"nested" => "value1"}, "bar" => "value2", "baz" => "value3" }}
35
+ assert_equal(expected, YAML.load(stdout), "YAML output does not match expected output")
36
+ rescue
37
+ fail_test "Couldn't parse output as YAML"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ test_name 'C89524: facter should not crash with invalid locale setting' do
2
+ tag 'risk:high', 'facter_3'
3
+
4
+
5
+ confine :except, :platform => 'windows'
6
+ confine :except, :platform => /^cisco_/ # See CISCO-43
7
+ confine :except, :platform => /^huawei/ # See HUAWEI-24
8
+
9
+ agents.each do |agent|
10
+ step 'facter should run when started with an invalid locale' do
11
+ on(agent, facter('facterversion'), :environment => {'LANG' => 'ABCD'}) do |facter_output|
12
+ assert_match(/^\d+\.\d+\.\d+$/, facter_output.stdout, 'facter did not continue running')
13
+
14
+ if agent['platform'] !~ /solaris|aix|cumulus|osx/
15
+ step 'facter should return an error message when started with an invalid locale' do
16
+ assert_match(/locale environment variables were bad; continuing with LANG=C LC_ALL=C/, facter_output.stderr,
17
+ 'Expected facter to return a locale error message')
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,57 @@
1
+ test_name 'C93827: facter fqdn should return the hostname when its a fully qualified domain name' do
2
+ tag 'risk:high'
3
+ require 'timeout'
4
+
5
+ confine :except, :platform => 'windows'
6
+
7
+ fqdn = 'foo.bar.example.org'
8
+ fqdn_long = 'a23456789.b23456789.c23456789.d23456789.e23456789.f23456789.wxyz'
9
+
10
+ agents.each do |agent|
11
+ orig_hostname = on(agent, 'hostname').stdout.chomp
12
+
13
+ teardown do
14
+ step 'restore original hostname' do
15
+ on(agent, "hostname #{orig_hostname}")
16
+ end
17
+ end
18
+
19
+ step "set hostname as #{fqdn}" do
20
+ on(agent, "hostname #{fqdn}")
21
+ begin
22
+ Timeout.timeout(20) do
23
+ until on(agent, 'hostname').stdout =~ /#{fqdn}/
24
+ sleep(0.25) # on Solaris 11 hostname returns before the hostname is updated
25
+ end
26
+ end
27
+ rescue Timeout::Error
28
+ raise "Failed to reset the hostname of the test machine to #{fqdn}"
29
+ end
30
+ end
31
+
32
+ step 'validate facter uses hostname as the fqdn if its a fully qualified domain name' do
33
+ on(agent, 'facter fqdn') do |facter_output|
34
+ assert_equal(fqdn, facter_output.stdout.chomp, 'facter did not return the hostname set by the test')
35
+ end
36
+ end
37
+ end
38
+
39
+ step "long hostname as #{fqdn_long}" do
40
+ on(agent, "hostname #{fqdn_long}")
41
+ begin
42
+ Timeout.timeout(20) do
43
+ until on(agent, 'hostname').stdout =~ /#{fqdn_long}/
44
+ sleep(0.25) # on Solaris 11 hostname returns before the hostname is updated
45
+ end
46
+ end
47
+ rescue Timeout::Error
48
+ raise "Failed to reset the hostname of the test machine to #{fqdn_long}"
49
+ end
50
+ end
51
+
52
+ step 'validate facter uses hostname as the LONG fqdn if its a fully qualified domain name' do
53
+ on(agent, 'facter fqdn') do |facter_output|
54
+ assert_equal(fqdn_long, facter_output.stdout.chomp, 'facter did not return the hostname set by the test')
55
+ end
56
+ end
57
+ end
@@ -6,6 +6,8 @@ module Facter
6
6
  class Base
7
7
  STDERR_MESSAGE = 'Command %s resulted with the following stderr message: %s'
8
8
 
9
+ # This is part of the public API. No race condition can happen
10
+ # here because custom facts are executed sequentially
9
11
  def with_env(values)
10
12
  old = {}
11
13
  values.each do |var, value|
@@ -38,27 +40,22 @@ module Facter
38
40
  expand = options.fetch(:expand, true)
39
41
  logger = options[:logger]
40
42
 
41
- # Set LC_ALL and LANG to force i18n to C for the duration of this exec;
42
- # this ensures that any code that parses the
43
- # output of the command can expect it to be in a consistent / predictable format / locale
44
- with_env 'LC_ALL' => 'C', 'LANG' => 'C' do
45
- expanded_command = if !expand && builtin_command?(command) || logger
46
- command
47
- else
48
- expand_command(command)
49
- end
43
+ expanded_command = if !expand && builtin_command?(command) || logger
44
+ command
45
+ else
46
+ expand_command(command)
47
+ end
50
48
 
51
- if expanded_command.nil?
52
- if on_fail == :raise
53
- raise Facter::Core::Execution::ExecutionFailure.new,
54
- "Could not execute '#{command}': command not found"
55
- end
56
-
57
- return on_fail
49
+ if expanded_command.nil?
50
+ if on_fail == :raise
51
+ raise Facter::Core::Execution::ExecutionFailure.new,
52
+ "Could not execute '#{command}': command not found"
58
53
  end
59
54
 
60
- execute_command(expanded_command, on_fail, logger)
55
+ return on_fail
61
56
  end
57
+
58
+ execute_command(expanded_command, on_fail, logger)
62
59
  end
63
60
 
64
61
  private
@@ -82,7 +79,10 @@ module Facter
82
79
 
83
80
  def execute_command(command, on_fail, logger = nil)
84
81
  begin
85
- out, stderr, _status_ = Open3.capture3(command.to_s)
82
+ # Set LC_ALL and LANG to force i18n to C for the duration of this exec;
83
+ # this ensures that any code that parses the
84
+ # output of the command can expect it to be in a consistent / predictable format / locale
85
+ out, stderr, _status_ = Open3.capture3({ 'LC_ALL' => 'C', 'LANG' => 'C' }, command.to_s)
86
86
  log_stderr(stderr, command, logger)
87
87
  rescue StandardError => e
88
88
  return '' if logger
@@ -95,8 +95,7 @@ module LegacyFacter
95
95
  return @external_facts unless @external_facts.nil?
96
96
 
97
97
  load_external_facts
98
- external_facts = @facts.select { |_k, v| v.options[:fact_type] == :external }
99
- @external_facts = Facter::Utils.deep_copy(external_facts.keys)
98
+ @external_facts = @facts.select { |_k, v| v.options[:fact_type] == :external }
100
99
  end
101
100
 
102
101
  def invalidate_custom_facts
@@ -148,11 +147,7 @@ module LegacyFacter
148
147
 
149
148
  def value(name)
150
149
  fact = fact(name)
151
- fact_value = fact&.value
152
- return Facter.core_value(name) if fact_value.nil?
153
-
154
- core_value = Facter.core_value(name) if fact.used_resolution_weight <= 0
155
- core_value.nil? ? fact_value : core_value
150
+ fact&.value
156
151
  end
157
152
 
158
153
  private
@@ -8,7 +8,7 @@ module LegacyFacter
8
8
  module Util
9
9
  module Config
10
10
  def self.ext_fact_loader
11
- @ext_fact_loader || LegacyFacter::Util::DirectoryLoader.default_loader
11
+ @ext_fact_loader || LegacyFacter::Util::DirectoryLoader.new
12
12
  end
13
13
 
14
14
  def self.ext_fact_loader=(loader)
@@ -30,55 +30,82 @@ module LegacyFacter
30
30
  EXTERNAL_FACT_WEIGHT = 10_000
31
31
 
32
32
  # Directory for fact loading
33
- attr_reader :directory
33
+ attr_reader :directories
34
34
 
35
- def initialize(dir, weight = nil)
36
- @directory = dir
37
- @weight = weight || EXTERNAL_FACT_WEIGHT
35
+ def initialize(dir = LegacyFacter::Util::Config.external_facts_dirs, weight = EXTERNAL_FACT_WEIGHT)
36
+ @directories = [dir].flatten
37
+ @weight = weight
38
38
  end
39
39
 
40
- def self.loader_for(dir)
41
- raise NoSuchDirectoryError unless File.directory?(dir)
40
+ # Load facts from files in fact directory using the relevant parser classes to
41
+ # parse them.
42
+ def load(collection)
43
+ weight = @weight
44
+
45
+ searched_facts, cached_facts = load_directory_entries(collection)
46
+
47
+ load_cached_facts(collection, cached_facts, weight)
42
48
 
43
- LegacyFacter::Util::DirectoryLoader.new(dir)
49
+ load_searched_facts(collection, searched_facts, weight)
44
50
  end
45
51
 
46
- def self.default_loader
47
- loaders = LegacyFacter::Util::Config.external_facts_dirs.collect do |dir|
48
- LegacyFacter::Util::DirectoryLoader.new(dir)
52
+ private
53
+
54
+ def load_directory_entries(_collection)
55
+ cm = Facter::CacheManager.new
56
+ facts = []
57
+ entries.each do |file|
58
+ basename = File.basename(file)
59
+ if facts.find { |f| f.name == basename } && cm.group_cached?(basename)
60
+ Facter.log_exception(Exception.new("Caching is enabled for group \"#{basename}\" while "\
61
+ 'there are at least two external facts files with the same filename'))
62
+ else
63
+ searched_fact = Facter::SearchedFact.new(basename, nil, [], nil, :file)
64
+ searched_fact.file = file
65
+ facts << searched_fact
66
+ end
49
67
  end
50
- LegacyFacter::Util::CompositeLoader.new(loaders)
68
+
69
+ cm.resolve_facts(facts)
51
70
  end
52
71
 
53
- # Load facts from files in fact directory using the relevant parser classes to
54
- # parse them.
55
- def load(collection)
56
- weight = @weight
57
- entries.each do |file|
58
- parser = LegacyFacter::Util::Parser.parser_for(file)
72
+ def load_cached_facts(collection, cached_facts, weight)
73
+ cached_facts.each do |cached_fact|
74
+ collection.add(cached_fact.name, value: cached_fact.value, fact_type: :external,
75
+ file: cached_fact.file) { has_weight(weight) }
76
+ end
77
+ end
78
+
79
+ def load_searched_facts(collection, searched_facts, weight)
80
+ searched_facts.each do |fact|
81
+ parser = LegacyFacter::Util::Parser.parser_for(fact.file)
59
82
  next if parser.nil?
60
83
 
61
84
  data = parser.results
62
85
  if data == false
63
- LegacyFacter.warn "Could not interpret fact file #{file}"
86
+ LegacyFacter.warn "Could not interpret fact file #{fact.file}"
64
87
  elsif (data == {}) || data.nil?
65
- LegacyFacter.warn "Fact file #{file} was parsed but returned an empty data set"
88
+ LegacyFacter.warn "Fact file #{fact.file} was parsed but returned an empty data set"
66
89
  else
67
- data.each { |p, v| collection.add(p, value: v, fact_type: :external) { has_weight(weight) } }
90
+ data.each do |p, v|
91
+ collection.add(p, value: v, fact_type: :external,
92
+ file: fact.file) { has_weight(weight) }
93
+ end
68
94
  end
69
95
  end
70
96
  end
71
97
 
72
- private
73
-
74
98
  def entries
75
- Dir.entries(directory).find_all { |f| should_parse?(f) }.sort.map { |f| File.join(directory, f) }
99
+ dirs = @directories.select { |directory| File.directory?(directory) }.map do |directory|
100
+ Dir.entries(directory).map { |directory_entry| File.join(directory, directory_entry) }
101
+ end
102
+ dirs.flatten.select { |f| should_parse?(f) }
76
103
  rescue Errno::ENOENT
77
104
  []
78
105
  end
79
106
 
80
107
  def should_parse?(file)
81
- file !~ /^\./
108
+ File.basename(file) !~ /^\./
82
109
  end
83
110
  end
84
111
  end
@@ -123,8 +123,10 @@ module Facter
123
123
  announce_when_no_suitable_resolution(suitable_resolutions)
124
124
  announce_when_no_value_found(@value)
125
125
 
126
- @value
126
+ @value = resolve_value
127
127
  end
128
+
129
+ @value
128
130
  end
129
131
 
130
132
  # @api private
@@ -138,6 +140,13 @@ module Facter
138
140
 
139
141
  private
140
142
 
143
+ def resolve_value
144
+ return Facter.core_value(name) if @value.nil?
145
+
146
+ core_value = Facter.core_value(name) if @used_resolution_weight <= 0
147
+ core_value.nil? ? @value : core_value
148
+ end
149
+
141
150
  # Are we in the midst of a search?
142
151
  def searching?
143
152
  @searching
@@ -86,7 +86,7 @@ module Facter
86
86
  end
87
87
 
88
88
  def options(options)
89
- accepted_options = %i[name value timeout weight fact_type]
89
+ accepted_options = %i[name value timeout weight fact_type file]
90
90
 
91
91
  accepted_options.each do |option_name|
92
92
  instance_variable_set("@#{option_name}", options.delete(option_name)) if options.key?(option_name)
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facts
4
+ module Aix
5
+ class AioAgentVersion
6
+ FACT_NAME = 'aio_agent_version'
7
+
8
+ def call_the_resolver
9
+ fact_value = Facter::Resolvers::AioAgentVersion.resolve(:aio_agent_version)
10
+ Facter::ResolvedFact.new(FACT_NAME, fact_value)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facts
4
+ module Bsd
5
+ module Processors
6
+ class Count
7
+ FACT_NAME = 'processors.count'
8
+ ALIASES = 'processorcount'
9
+
10
+ def call_the_resolver
11
+ fact_value = Facter::Resolvers::Bsd::Processors.resolve(:logical_count)
12
+ [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facts
4
+ module Bsd
5
+ module Processors
6
+ class Models
7
+ FACT_NAME = 'processors.models'
8
+ ALIASES = 'processor.*'
9
+
10
+ def call_the_resolver
11
+ fact_value = Facter::Resolvers::Bsd::Processors.resolve(:models)
12
+ return nil unless fact_value
13
+
14
+ facts = [Facter::ResolvedFact.new(FACT_NAME, fact_value)]
15
+ fact_value.each_with_index do |value, index|
16
+ facts.push(Facter::ResolvedFact.new("processor#{index}", value, :legacy))
17
+ end
18
+ facts
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end