facter 4.0.15 → 4.0.16
Sign up to get free protection for your applications and to get access to all the features.
- 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
|