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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +5 -7
- data/CHANGELOG.md +33 -0
- data/VERSION +1 -1
- data/lib/custom_facts/util/parser.rb +1 -1
- data/lib/custom_facts/version.rb +1 -1
- data/lib/facter.rb +13 -17
- data/lib/facts/aix/partitions.rb +15 -0
- data/lib/facts/windows/ssh.rb +27 -0
- data/lib/facts_utils/uptime_parser.rb +3 -3
- data/lib/framework/cli/cli.rb +1 -1
- data/lib/framework/config/block_list.rb +1 -4
- data/lib/framework/config/config_reader.rb +29 -26
- data/lib/framework/core/fact_filter.rb +2 -2
- data/lib/framework/core/file_loader.rb +3 -3
- data/lib/framework/core/options.rb +57 -64
- data/lib/framework/core/options/config_file_options.rb +58 -48
- data/lib/framework/core/options/option_store.rb +156 -0
- data/lib/framework/core/options/options_validator.rb +42 -2
- data/lib/framework/logging/logger.rb +2 -0
- data/lib/framework/parsers/query_parser.rb +1 -1
- data/lib/models/fact_collection.rb +1 -1
- data/lib/resolvers/aix/filesystem_resolver.rb +3 -2
- data/lib/resolvers/aix/partitions.rb +86 -0
- data/lib/resolvers/aix/utils/odm_query.rb +2 -2
- data/lib/resolvers/debian_version.rb +2 -5
- data/lib/resolvers/disk_resolver.rb +2 -3
- data/lib/resolvers/dmi_resolver.rb +3 -3
- data/lib/resolvers/filesystems_resolver.rb +3 -3
- data/lib/resolvers/fips_enabled_resolver.rb +1 -4
- data/lib/resolvers/hostname_resolver.rb +4 -4
- data/lib/resolvers/load_averages_resolver.rb +1 -3
- data/lib/resolvers/memory_resolver.rb +2 -2
- data/lib/resolvers/mountpoints_resolver.rb +1 -3
- data/lib/resolvers/os_release_resolver.rb +3 -6
- data/lib/resolvers/partitions.rb +11 -6
- data/lib/resolvers/processors_resolver.rb +3 -3
- data/lib/resolvers/selinux_resolver.rb +9 -9
- data/lib/resolvers/solaris/filesystems_resolver.rb +1 -1
- data/lib/resolvers/ssh_resolver.rb +4 -43
- data/lib/resolvers/utils/ssh_helper.rb +27 -0
- data/lib/resolvers/windows/ssh.rb +47 -0
- data/lib/util/file_helper.rb +24 -0
- metadata +9 -6
- data/lib/framework/core/options/default_options.rb +0 -35
- data/lib/framework/core/options/helper_options.rb +0 -52
- data/lib/framework/core/options/priority_options.rb +0 -12
- 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.
|
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
|
-
|
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
|
-
|
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
|
-
|
39
|
-
|
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
|
-
|
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.
|
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
|
-
|
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
|
-
|
34
|
-
|
35
|
-
if
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
29
|
-
|
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.
|
33
|
+
output.each do |line|
|
37
34
|
pairs << line.strip.delete('"').split('=', 2)
|
38
35
|
end
|
39
36
|
|
data/lib/resolvers/partitions.rb
CHANGED
@@ -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 =
|
45
|
+
map_name = Util::FileHelper.safe_read("#{block_path}/dm/name").chomp
|
45
46
|
if map_name.empty?
|
46
|
-
populate_partitions("/dev
|
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
|
-
|
54
|
-
|
55
|
-
|
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 =
|
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
|
-
|
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.
|
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]
|
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] =
|
44
|
+
@fact_list[:policy_version] = Util::FileHelper.safe_read(policy_file, nil)
|
49
45
|
|
50
|
-
enforce =
|
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
|
-
|
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.
|
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
|
-
|
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 =
|
30
|
-
|
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
|