facter 4.0.15 → 4.0.16

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.rubocop_todo.yml +5 -7
  4. data/CHANGELOG.md +33 -0
  5. data/VERSION +1 -1
  6. data/lib/custom_facts/util/parser.rb +1 -1
  7. data/lib/custom_facts/version.rb +1 -1
  8. data/lib/facter.rb +13 -17
  9. data/lib/facts/aix/partitions.rb +15 -0
  10. data/lib/facts/windows/ssh.rb +27 -0
  11. data/lib/facts_utils/uptime_parser.rb +3 -3
  12. data/lib/framework/cli/cli.rb +1 -1
  13. data/lib/framework/config/block_list.rb +1 -4
  14. data/lib/framework/config/config_reader.rb +29 -26
  15. data/lib/framework/core/fact_filter.rb +2 -2
  16. data/lib/framework/core/file_loader.rb +3 -3
  17. data/lib/framework/core/options.rb +57 -64
  18. data/lib/framework/core/options/config_file_options.rb +58 -48
  19. data/lib/framework/core/options/option_store.rb +156 -0
  20. data/lib/framework/core/options/options_validator.rb +42 -2
  21. data/lib/framework/logging/logger.rb +2 -0
  22. data/lib/framework/parsers/query_parser.rb +1 -1
  23. data/lib/models/fact_collection.rb +1 -1
  24. data/lib/resolvers/aix/filesystem_resolver.rb +3 -2
  25. data/lib/resolvers/aix/partitions.rb +86 -0
  26. data/lib/resolvers/aix/utils/odm_query.rb +2 -2
  27. data/lib/resolvers/debian_version.rb +2 -5
  28. data/lib/resolvers/disk_resolver.rb +2 -3
  29. data/lib/resolvers/dmi_resolver.rb +3 -3
  30. data/lib/resolvers/filesystems_resolver.rb +3 -3
  31. data/lib/resolvers/fips_enabled_resolver.rb +1 -4
  32. data/lib/resolvers/hostname_resolver.rb +4 -4
  33. data/lib/resolvers/load_averages_resolver.rb +1 -3
  34. data/lib/resolvers/memory_resolver.rb +2 -2
  35. data/lib/resolvers/mountpoints_resolver.rb +1 -3
  36. data/lib/resolvers/os_release_resolver.rb +3 -6
  37. data/lib/resolvers/partitions.rb +11 -6
  38. data/lib/resolvers/processors_resolver.rb +3 -3
  39. data/lib/resolvers/selinux_resolver.rb +9 -9
  40. data/lib/resolvers/solaris/filesystems_resolver.rb +1 -1
  41. data/lib/resolvers/ssh_resolver.rb +4 -43
  42. data/lib/resolvers/utils/ssh_helper.rb +27 -0
  43. data/lib/resolvers/windows/ssh.rb +47 -0
  44. data/lib/util/file_helper.rb +24 -0
  45. metadata +9 -6
  46. data/lib/framework/core/options/default_options.rb +0 -35
  47. data/lib/framework/core/options/helper_options.rb +0 -52
  48. data/lib/framework/core/options/priority_options.rb +0 -12
  49. data/lib/framework/core/options/validate_options.rb +0 -49
@@ -27,9 +27,9 @@ module Facter
27
27
  def execute
28
28
  result = nil
29
29
  REPOS.each do |repo|
30
- break if result
30
+ break if result && !result.empty?
31
31
 
32
- result, _s = Open3.capture2("#{query} #{repo}")
32
+ result, _stderr, _s = Open3.capture3("#{query} #{repo}")
33
33
  end
34
34
  result
35
35
  end
@@ -18,11 +18,8 @@ module Facter
18
18
  end
19
19
 
20
20
  def read_debian_version(fact_name)
21
- return unless File.readable?('/etc/debian_version')
22
-
23
- verion = File.read('/etc/debian_version')
24
-
25
- @fact_list[:version] = verion.strip
21
+ file_content = Util::FileHelper.safe_read('/etc/debian_version')
22
+ @fact_list[:version] = file_content.strip unless file_content.empty?
26
23
 
27
24
  @fact_list[fact_name]
28
25
  end
@@ -23,9 +23,8 @@ module Facter
23
23
  @fact_list[:disks].each do |disk, value|
24
24
  file_path = File.join(DIR, disk, file)
25
25
 
26
- next unless File.readable?(file_path)
27
-
28
- result = File.read(file_path).strip
26
+ result = Util::FileHelper.safe_read(file_path).strip
27
+ next if result.empty?
29
28
 
30
29
  # Linux always considers sectors to be 512 bytes long independently of the devices real block size.
31
30
  value[key] = file =~ /size/ ? construct_size(value, result) : result
@@ -28,15 +28,15 @@ module Facter
28
28
  @fact_list.fetch(fact_name) { read_facts(fact_name) }
29
29
  end
30
30
 
31
- # File.read("/sys/class/dmi/id/#{file}")
32
31
  def read_facts(fact_name)
33
32
  files = %w[bios_date bios_vendor bios_version board_vendor board_name board_serial
34
33
  chassis_asset_tag chassis_type sys_vendor product_name product_serial
35
34
  product_uuid]
36
35
  return unless File.directory?('/sys/class/dmi')
37
36
 
38
- if files.include?(fact_name.to_s) && File.readable?("/sys/class/dmi/id/#{fact_name}")
39
- @fact_list[fact_name] = File.read("/sys/class/dmi/id/#{fact_name}").strip
37
+ file_content = Util::FileHelper.safe_read("/sys/class/dmi/id/#{fact_name}", nil)
38
+ if files.include?(fact_name.to_s) && file_content
39
+ @fact_list[fact_name] = file_content.strip
40
40
  chassis_to_name(@fact_list[fact_name]) if fact_name == :chassis_type
41
41
 
42
42
  end
@@ -16,11 +16,11 @@ module Facter
16
16
  end
17
17
 
18
18
  def read_filesystems(fact_name)
19
- return unless File.readable?('/proc/filesystems')
19
+ output = Util::FileHelper.safe_readlines('/proc/filesystems', nil)
20
+ return unless output
20
21
 
21
- output = File.read('/proc/filesystems')
22
22
  filesystems = []
23
- output.each_line do |line|
23
+ output.each do |line|
24
24
  tokens = line.split(' ')
25
25
  filesystems << tokens if tokens.size == 1
26
26
  end
@@ -16,10 +16,7 @@ module Facter
16
16
  end
17
17
 
18
18
  def read_fips_file(fact_name)
19
- return @fact_list[fact_name] = false unless File.directory?('/proc/sys/crypto') ||
20
- File.readable?('/proc/sys/crypto/fips_enabled')
21
-
22
- file_output = File.read('/proc/sys/crypto/fips_enabled')
19
+ file_output = Util::FileHelper.safe_read('/proc/sys/crypto/fips_enabled')
23
20
  @fact_list[:fips_enabled] = file_output.strip == '1'
24
21
  @fact_list[fact_name]
25
22
  end
@@ -30,11 +30,11 @@ module Facter
30
30
  def read_domain(output)
31
31
  if output =~ /.*?\.(.+$)/
32
32
  domain = Regexp.last_match(1)
33
- elsif File.readable?('/etc/resolv.conf')
34
- file = File.read('/etc/resolv.conf')
35
- if file =~ /^search\s+(\S+)/
33
+ else
34
+ file_content = Util::FileHelper.safe_read('/etc/resolv.conf')
35
+ if file_content =~ /^search\s+(\S+)/
36
36
  domain = Regexp.last_match(1)
37
- elsif file =~ /^domain\s+(\S+)/
37
+ elsif file_content =~ /^domain\s+(\S+)/
38
38
  domain = Regexp.last_match(1)
39
39
  end
40
40
  end
@@ -15,9 +15,7 @@ module Facter
15
15
  end
16
16
 
17
17
  def read_load_averages_file(fact_name)
18
- return unless File.readable?('/proc/loadavg')
19
-
20
- output = File.read('/proc/loadavg')
18
+ output = Util::FileHelper.safe_read('/proc/loadavg')
21
19
  @fact_list[:load_averages] = {}.tap { |h| h['1m'], h['5m'], h['15m'], = output.split.map(&:to_f) }
22
20
 
23
21
  @fact_list[fact_name]
@@ -15,9 +15,9 @@ module Facter
15
15
  end
16
16
 
17
17
  def read_meminfo_file(fact_name)
18
- return unless File.readable?('/proc/meminfo')
18
+ meminfo_output = Util::FileHelper.safe_read('/proc/meminfo', nil)
19
+ return unless meminfo_output
19
20
 
20
- meminfo_output = File.read('/proc/meminfo')
21
21
  read_system(meminfo_output)
22
22
  read_swap(meminfo_output)
23
23
 
@@ -16,9 +16,7 @@ module Facter
16
16
  end
17
17
 
18
18
  def root_device
19
- return unless File.readable?('/proc/cmdline')
20
-
21
- cmdline = File.read('/proc/cmdline')
19
+ cmdline = Util::FileHelper.safe_read('/proc/cmdline')
22
20
  match = cmdline.match(/root=([^\s]+)/)
23
21
  match&.captures&.first
24
22
  end
@@ -25,15 +25,12 @@ module Facter
25
25
  end
26
26
 
27
27
  def read_os_release_file(fact_name)
28
- unless File.readable?('/etc/os-release')
29
- @fact_list[:name] = nil
30
- return
31
- end
28
+ output = Util::FileHelper.safe_readlines('/etc/os-release')
29
+ return @fact_list[:name] = nil if output.empty?
32
30
 
33
- output = File.read('/etc/os-release')
34
31
  pairs = []
35
32
 
36
- output.each_line do |line|
33
+ output.each do |line|
37
34
  pairs << line.strip.delete('"').split('=', 2)
38
35
  end
39
36
 
@@ -6,6 +6,7 @@ module Facter
6
6
  @semaphore = Mutex.new
7
7
  @fact_list ||= {}
8
8
  BLOCK_PATH = '/sys/block'
9
+ BLOCK_SIZE = 512
9
10
 
10
11
  class << self
11
12
  private
@@ -41,23 +42,27 @@ module Facter
41
42
  end
42
43
 
43
44
  def extract_from_dm(block_path)
44
- map_name = File.readable?("#{block_path}/dm/name") ? File.read("#{block_path}/dm/name").chomp : ''
45
+ map_name = Util::FileHelper.safe_read("#{block_path}/dm/name").chomp
45
46
  if map_name.empty?
46
- populate_partitions("/dev/#{block_path}", block_path)
47
+ populate_partitions("/dev#{block_path}", block_path)
47
48
  else
48
49
  populate_partitions("/dev/mapper/#{map_name}", block_path)
49
50
  end
50
51
  end
51
52
 
52
53
  def extract_from_loop(block_path)
53
- populate_partitions("/dev/#{block_path}", block_path) if File.readable?("#{block_path}/loop/backing_file")
54
- backing_file = File.read("#{block_path}/loop/backing_file").chomp
55
- populate_partitions("/dev/#{block_path}", block_path, backing_file)
54
+ backing_file = Util::FileHelper.safe_read("#{block_path}/loop/backing_file").chomp
55
+ if backing_file.empty?
56
+ populate_partitions("/dev#{block_path}", block_path)
57
+ else
58
+ populate_partitions("/dev#{block_path}", block_path, backing_file)
59
+ end
56
60
  end
57
61
 
58
62
  def populate_partitions(partition_name, block_path, backing_file = nil)
59
63
  @fact_list[:partitions][partition_name] = {}
60
- size_bytes = File.readable?("#{block_path}/size") ? File.read("#{block_path}/size").chomp.to_i * 512 : 0
64
+ size_bytes = Util::FileHelper.safe_read("#{block_path}/size", '0')
65
+ .chomp.to_i * BLOCK_SIZE
61
66
  info_hash = { size_bytes: size_bytes,
62
67
  size: Facter::BytesToHumanReadable.convert(size_bytes), backing_file: backing_file }
63
68
  info_hash.merge!(populate_from_blkid(partition_name))
@@ -19,9 +19,9 @@ module Facter
19
19
  end
20
20
 
21
21
  def read_cpuinfo(fact_name)
22
- return unless File.readable?('/proc/cpuinfo')
22
+ cpuinfo_output = Util::FileHelper.safe_readlines('/proc/cpuinfo')
23
+ return if cpuinfo_output.empty?
23
24
 
24
- cpuinfo_output = File.read('/proc/cpuinfo')
25
25
  read_processors(cpuinfo_output) # + model names
26
26
 
27
27
  @fact_list[:physical_count] = @fact_list[:physical_processors].uniq.length
@@ -32,7 +32,7 @@ module Facter
32
32
  @fact_list[:processors] = 0
33
33
  @fact_list[:models] = []
34
34
  @fact_list[:physical_processors] = []
35
- cpuinfo_output.each_line do |line|
35
+ cpuinfo_output.each do |line|
36
36
  tokens = line.split(':')
37
37
  count_processors(tokens)
38
38
  construct_models_list(tokens)
@@ -3,10 +3,6 @@
3
3
  module Facter
4
4
  module Resolvers
5
5
  class SELinux < BaseResolver
6
- # :name
7
- # :version
8
- # :codename
9
-
10
6
  @semaphore = Mutex.new
11
7
  @fact_list ||= {}
12
8
 
@@ -19,7 +15,7 @@ module Facter
19
15
 
20
16
  def retrieve_facts(fact_name)
21
17
  mountpoint = read_mounts_file if @fact_list[:enabled].nil?
22
- read_other_selinux_facts(mountpoint) if @fact_list[:enabled] && File.readable?('/etc/selinux/config')
18
+ read_other_selinux_facts(mountpoint) if @fact_list[:enabled]
23
19
 
24
20
  @fact_list[fact_name]
25
21
  end
@@ -40,14 +36,14 @@ module Facter
40
36
  end
41
37
 
42
38
  def read_other_selinux_facts(mountpoint)
43
- read_selinux_config
39
+ return unless read_selinux_config
44
40
 
45
41
  enforce_file = "#{mountpoint}/enforce"
46
42
  policy_file = "#{mountpoint}/policyvers"
47
43
 
48
- @fact_list[:policy_version] = File.read(policy_file) if File.readable?(policy_file)
44
+ @fact_list[:policy_version] = Util::FileHelper.safe_read(policy_file, nil)
49
45
 
50
- enforce = File.read(enforce_file) if File.readable?(enforce_file)
46
+ enforce = Util::FileHelper.safe_read(enforce_file)
51
47
  if enforce.eql?('1')
52
48
  @fact_list[:enforced] = true
53
49
  @fact_list[:current_mode] = 'enforcing'
@@ -58,10 +54,14 @@ module Facter
58
54
  end
59
55
 
60
56
  def read_selinux_config
61
- File.readlines('/etc/selinux/config').map do |line|
57
+ file_lines = Util::FileHelper.safe_readlines('/etc/selinux/config')
58
+
59
+ file_lines.map do |line|
62
60
  @fact_list[:config_mode] = line.split('=').last.strip if line =~ /^SELINUX=/
63
61
  @fact_list[:config_policy] = line.split('=').last.strip if line =~ /^SELINUXTYPE=/
64
62
  end
63
+
64
+ true unless file_lines.empty?
65
65
  end
66
66
  end
67
67
  end
@@ -15,7 +15,7 @@ module Facter
15
15
  end
16
16
 
17
17
  def read_sysdef_file(fact_name)
18
- return unless File.readable?('/usr/sbin/sysdef')
18
+ return unless File.executable?('/usr/sbin/sysdef')
19
19
 
20
20
  file_content, _status = Open3.capture2('/usr/sbin/sysdef')
21
21
  files = file_content.split("\n").map do |line|
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'base64'
4
- require 'digest/sha1'
5
-
6
3
  module Facter
7
4
  module Resolvers
8
5
  class SshResolver < BaseResolver
@@ -24,52 +21,16 @@ module Facter
24
21
  next unless File.directory?(file_path)
25
22
 
26
23
  @file_names.each do |file_name|
27
- next unless FileTest.file?(File.join(file_path, file_name))
24
+ file_content = Util::FileHelper.safe_read(File.join(file_path, file_name), nil)
25
+ next unless file_content
28
26
 
29
- key_type, key = File.read(File.join(file_path, file_name)).split(' ')
30
- key_name = determine_ssh_key_name(key_type)
31
- ssh_list << create_ssh(key_name, key_type, key)
27
+ key_type, key = file_content.split(' ')
28
+ ssh_list << ::Resolvers::Utils::SshHelper.create_ssh(key_type, key)
32
29
  end
33
30
  end
34
31
  @fact_list[:ssh] = ssh_list
35
32
  @fact_list[fact_name]
36
33
  end
37
-
38
- def create_ssh(key_name, key_type, key)
39
- decoded_key = Base64.decode64(key)
40
- ssh_fa = determine_ssh_fingerprint(key_name)
41
- sha1 = "SSHFP #{ssh_fa} 1 #{Digest::SHA1.new.update(decoded_key)}"
42
- sha256 = "SSHFP #{ssh_fa} 2 #{Digest::SHA2.new.update(decoded_key)}"
43
-
44
- fingerprint = FingerPrint.new(sha1, sha256)
45
- Ssh.new(fingerprint, key_type, key, key_name)
46
- end
47
-
48
- def determine_ssh_key_name(key)
49
- case key
50
- when 'ssh-dss'
51
- 'dsa'
52
- when 'ecdsa-sha2-nistp256'
53
- 'ecdsa'
54
- when 'ssh-ed25519'
55
- 'ed25519'
56
- when 'ssh-rsa'
57
- 'rsa'
58
- end
59
- end
60
-
61
- def determine_ssh_fingerprint(key_name)
62
- case key_name
63
- when 'rsa'
64
- 1
65
- when 'dsa'
66
- 2
67
- when 'ecdsa'
68
- 3
69
- when 'ed25519'
70
- 4
71
- end
72
- end
73
34
  end
74
35
  end
75
36
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'digest/sha1'
5
+
6
+ module Resolvers
7
+ module Utils
8
+ class SshHelper
9
+ class << self
10
+ SSH_NAME = { 'ssh-dss' => 'dsa', 'ecdsa-sha2-nistp256' => 'ecdsa',
11
+ 'ssh-ed25519' => 'ed25519', 'ssh-rsa' => 'rsa' }.freeze
12
+ SSH_FINGERPRINT = { 'rsa' => 1, 'dsa' => 2, 'ecdsa' => 3, 'ed25519' => 4 }.freeze
13
+
14
+ def create_ssh(key_type, key)
15
+ key_name = SSH_NAME[key_type]
16
+ decoded_key = Base64.decode64(key)
17
+ ssh_fp = SSH_FINGERPRINT[key_name]
18
+ sha1 = "SSHFP #{ssh_fp} 1 #{Digest::SHA1.new.update(decoded_key)}"
19
+ sha256 = "SSHFP #{ssh_fp} 2 #{Digest::SHA2.new.update(decoded_key)}"
20
+
21
+ fingerprint = Facter::FingerPrint.new(sha1, sha256)
22
+ Facter::Ssh.new(fingerprint, key_type, key, key_name)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Resolvers
5
+ module Windows
6
+ class Ssh < BaseResolver
7
+ @log = Facter::Log.new(self)
8
+ @semaphore = Mutex.new
9
+ @fact_list ||= {}
10
+ FILE_NAMES = %w[ssh_host_rsa_key.pub ssh_host_dsa_key.pub
11
+ ssh_host_ecdsa_key.pub ssh_host_ed25519_key.pub].freeze
12
+ class << self
13
+ private
14
+
15
+ def post_resolve(fact_name)
16
+ @fact_list.fetch(fact_name) { retrieve_info(fact_name) }
17
+ end
18
+
19
+ def retrieve_info(fact_name)
20
+ ssh_dir = determine_ssh_dir
21
+ return unless ssh_dir && File.directory?(ssh_dir)
22
+
23
+ ssh_list = []
24
+
25
+ FILE_NAMES.each do |file_name|
26
+ output = Util::FileHelper.safe_read(File.join(ssh_dir, file_name))
27
+ next if output.empty?
28
+
29
+ key_type, key = output.split(' ')
30
+ ssh_list << ::Resolvers::Utils::SshHelper.create_ssh(key_type, key)
31
+ end
32
+ @fact_list[:ssh] = ssh_list.empty? ? nil : ssh_list
33
+ @fact_list[fact_name]
34
+ end
35
+
36
+ def determine_ssh_dir
37
+ progdata_dir = ENV['programdata']
38
+
39
+ return if !progdata_dir || progdata_dir.empty?
40
+
41
+ File.join(progdata_dir, 'ssh')
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Util
5
+ class FileHelper
6
+ @log = Log.new(self)
7
+ class << self
8
+ DEBUG_MESSAGE = 'File at: %s is not accessible.'
9
+
10
+ def safe_read(path, result_if_not_readable = '')
11
+ return File.read(path) if File.readable?(path)
12
+
13
+ result_if_not_readable
14
+ end
15
+
16
+ def safe_readlines(path, result_if_not_readable = [])
17
+ return File.readlines(path) if File.readable?(path)
18
+
19
+ result_if_not_readable
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end