facter 4.0.35 → 4.0.36

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/lib/facter/custom_facts/util/directory_loader.rb +3 -1
  3. data/lib/facter/fact_groups.conf +140 -1
  4. data/lib/facter/facts/aix/disks.rb +17 -2
  5. data/lib/facter/facts/aix/networking/scope6.rb +3 -1
  6. data/lib/facter/facts/aix/scope6_interfaces.rb +0 -2
  7. data/lib/facter/facts/aix/serialnumber.rb +20 -0
  8. data/lib/facter/facts/aix/sshalgorithmkey.rb +17 -0
  9. data/lib/facter/facts/aix/sshfp_algorithm.rb +20 -0
  10. data/lib/facter/facts/debian/os/distro/release.rb +6 -1
  11. data/lib/facter/facts/freebsd/sshalgorithmkey.rb +17 -0
  12. data/lib/facter/facts/freebsd/sshfp_algorithm.rb +20 -0
  13. data/lib/facter/facts/linux/disks.rb +20 -1
  14. data/lib/facter/facts/linux/dmi/board/asset_tag.rb +19 -0
  15. data/lib/facter/facts/linux/ec2_metadata.rb +5 -3
  16. data/lib/facter/facts/linux/ec2_userdata.rb +5 -3
  17. data/lib/facter/facts/linux/gce.rb +16 -0
  18. data/lib/facter/facts/linux/is_virtual.rb +1 -3
  19. data/lib/facter/facts/linux/networking/scope6.rb +3 -1
  20. data/lib/facter/facts/linux/processors/speed.rb +17 -0
  21. data/lib/facter/facts/linux/scope6_interfaces.rb +1 -2
  22. data/lib/facter/facts/linux/sshfp_algorithm.rb +1 -1
  23. data/lib/facter/facts/linux/xen.rb +28 -0
  24. data/lib/facter/facts/macosx/networking/scope6.rb +3 -1
  25. data/lib/facter/facts/macosx/scope6_interfaces.rb +0 -2
  26. data/lib/facter/facts/macosx/sshfp_algorithm.rb +1 -1
  27. data/lib/facter/facts/solaris/disks.rb +21 -2
  28. data/lib/facter/facts/solaris/hypervisors/ldom.rb +24 -0
  29. data/lib/facter/facts/solaris/hypervisors/zone.rb +39 -0
  30. data/lib/facter/facts/solaris/is_virtual.rb +64 -0
  31. data/lib/facter/facts/solaris/kernelmajversion.rb +1 -1
  32. data/lib/facter/facts/solaris/ldom.rb +35 -0
  33. data/lib/facter/facts/solaris/sshalgorithmkey.rb +17 -0
  34. data/lib/facter/facts/solaris/sshfp_algorithm.rb +20 -0
  35. data/lib/facter/facts/solaris/virtual.rb +60 -0
  36. data/lib/facter/facts/solaris/zones.rb +1 -1
  37. data/lib/facter/facts/windows/ec2_metadata.rb +5 -3
  38. data/lib/facter/facts/windows/ec2_userdata.rb +5 -3
  39. data/lib/facter/facts/windows/gce.rb +16 -0
  40. data/lib/facter/facts/windows/networking/scope6.rb +3 -1
  41. data/lib/facter/facts/windows/sshalgorithmkey.rb +22 -0
  42. data/lib/facter/facts/windows/sshfp_algorithm.rb +25 -0
  43. data/lib/facter/facts_utils/facts_utils.rb +2 -0
  44. data/lib/facter/framework/core/fact/internal/core_fact.rb +2 -0
  45. data/lib/facter/framework/core/fact/internal/internal_fact_manager.rb +10 -25
  46. data/lib/facter/framework/core/fact_filter.rb +13 -0
  47. data/lib/facter/framework/core/fact_loaders/fact_loader.rb +24 -1
  48. data/lib/facter/framework/formatters/legacy_fact_formatter.rb +8 -1
  49. data/lib/facter/framework/formatters/yaml_fact_formatter.rb +1 -1
  50. data/lib/facter/resolvers/aix/serialnumber.rb +37 -0
  51. data/lib/facter/resolvers/dmi_resolver.rb +4 -3
  52. data/lib/facter/resolvers/ec2.rb +4 -18
  53. data/lib/facter/resolvers/gce.rb +54 -0
  54. data/lib/facter/resolvers/memory_resolver.rb +8 -1
  55. data/lib/facter/resolvers/processors_resolver.rb +24 -2
  56. data/lib/facter/resolvers/solaris/ldom.rb +70 -0
  57. data/lib/facter/resolvers/utils/http.rb +68 -0
  58. data/lib/facter/resolvers/xen.rb +28 -0
  59. data/lib/facter/version.rb +1 -1
  60. metadata +25 -2
@@ -28,7 +28,7 @@ module Facts
28
28
  end
29
29
 
30
30
  resolved_facts << Facter::ResolvedFact.new('solaris_zones.zones', zones)
31
- resolved_facts << Facter::ResolvedFact.new('zones', results.count, :legacy)
31
+ resolved_facts << Facter::ResolvedFact.new('zones', results.count.to_s, :legacy)
32
32
 
33
33
  resolved_facts.flatten
34
34
  end
@@ -6,14 +6,16 @@ module Facts
6
6
  FACT_NAME = 'ec2_metadata'
7
7
 
8
8
  def call_the_resolver
9
- return Facter::ResolvedFact.new(FACT_NAME, nil) unless aws?
9
+ return Facter::ResolvedFact.new(FACT_NAME, nil) unless aws_hypervisors?
10
10
 
11
11
  fact_value = Facter::Resolvers::Ec2.resolve(:metadata)
12
12
 
13
- Facter::ResolvedFact.new(FACT_NAME, fact_value.empty? ? nil : fact_value)
13
+ Facter::ResolvedFact.new(FACT_NAME, fact_value&.empty? ? nil : fact_value)
14
14
  end
15
15
 
16
- def aws?
16
+ private
17
+
18
+ def aws_hypervisors?
17
19
  virtual = Facter::Resolvers::Virtualization.resolve(:virtual)
18
20
 
19
21
  virtual == 'kvm' || virtual =~ /xen/
@@ -6,14 +6,16 @@ module Facts
6
6
  FACT_NAME = 'ec2_userdata'
7
7
 
8
8
  def call_the_resolver
9
- return Facter::ResolvedFact.new(FACT_NAME, nil) unless aws?
9
+ return Facter::ResolvedFact.new(FACT_NAME, nil) unless aws_hypervisors?
10
10
 
11
11
  fact_value = Facter::Resolvers::Ec2.resolve(:userdata)
12
12
 
13
- Facter::ResolvedFact.new(FACT_NAME, fact_value.empty? ? nil : fact_value)
13
+ Facter::ResolvedFact.new(FACT_NAME, fact_value&.empty? ? nil : fact_value)
14
14
  end
15
15
 
16
- def aws?
16
+ private
17
+
18
+ def aws_hypervisors?
17
19
  virtual = Facter::Resolvers::Virtualization.resolve(:virtual)
18
20
 
19
21
  virtual == 'kvm' || virtual =~ /xen/
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facts
4
+ module Windows
5
+ class Gce
6
+ FACT_NAME = 'gce'
7
+
8
+ def call_the_resolver
9
+ virtualization = Facter::Resolvers::Virtualization.resolve(:virtual)
10
+
11
+ fact_value = virtualization&.include?('gce') ? Facter::Resolvers::Gce.resolve(:metadata) : nil
12
+ Facter::ResolvedFact.new(FACT_NAME, fact_value)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -5,11 +5,13 @@ module Facts
5
5
  module Networking
6
6
  class Scope6
7
7
  FACT_NAME = 'networking.scope6'
8
+ ALIASES = 'scope6'
8
9
 
9
10
  def call_the_resolver
10
11
  fact_value = Facter::Resolvers::Windows::Networking.resolve(:scope6)
11
12
 
12
- Facter::ResolvedFact.new(FACT_NAME, fact_value)
13
+ [Facter::ResolvedFact.new(FACT_NAME, fact_value),
14
+ Facter::ResolvedFact.new('scope6', fact_value, :legacy)]
13
15
  end
14
16
  end
15
17
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facts
4
+ module Windows
5
+ class Sshalgorithmkey
6
+ FACT_NAME = 'ssh.*key'
7
+ TYPE = :legacy
8
+
9
+ def call_the_resolver
10
+ facts = []
11
+ privileged = Facter::Resolvers::Identity.resolve(:privileged)
12
+
13
+ return facts unless privileged
14
+
15
+ result = Facter::Resolvers::Windows::Ssh.resolve(:ssh)
16
+
17
+ result&.each { |ssh| facts << Facter::ResolvedFact.new("ssh#{ssh.name.to_sym}key", ssh.key, :legacy) }
18
+ facts
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facts
4
+ module Windows
5
+ class SshfpAlgorithm
6
+ FACT_NAME = 'sshfp_.*'
7
+ TYPE = :legacy
8
+
9
+ def call_the_resolver
10
+ facts = []
11
+ privileged = Facter::Resolvers::Identity.resolve(:privileged)
12
+
13
+ return facts unless privileged
14
+
15
+ result = Facter::Resolvers::Windows::Ssh.resolve(:ssh)
16
+
17
+ result&.each do |ssh|
18
+ facts << Facter::ResolvedFact.new("sshfp_#{ssh.name.to_sym}",
19
+ "#{ssh.fingerprint.sha1}\n#{ssh.fingerprint.sha256}", :legacy)
20
+ end
21
+ facts
22
+ end
23
+ end
24
+ end
25
+ end
@@ -6,5 +6,7 @@ module Facter
6
6
  'KVM' => 'kvm', 'Virtual Machine' => 'hyperv', 'RHEV Hypervisor' => 'rhev',
7
7
  'oVirt Node' => 'ovirt', 'HVM domU' => 'xenhvm', 'Bochs' => 'bochs', 'OpenBSD' => 'vmm',
8
8
  'BHYVE' => 'bhyve' }.freeze
9
+
10
+ PHYSICAL_HYPERVISORS = %w[physical xen0 vmware_server vmware_workstation openvzhn vserver_host].freeze
9
11
  end
10
12
  end
@@ -9,6 +9,8 @@ module Facter
9
9
  def create
10
10
  fact_class = @searched_fact.fact_class
11
11
 
12
+ return unless fact_class
13
+
12
14
  fact_class.new.call_the_resolver
13
15
  end
14
16
  end
@@ -6,9 +6,8 @@ module Facter
6
6
 
7
7
  def resolve_facts(searched_facts)
8
8
  internal_searched_facts = filter_internal_facts(searched_facts)
9
- threads = start_threads(internal_searched_facts)
10
- resolved_facts = join_threads(threads, internal_searched_facts)
11
9
 
10
+ resolved_facts = resolve(internal_searched_facts)
12
11
  nil_resolved_facts = resolve_nil_facts(searched_facts)
13
12
 
14
13
  resolved_facts.concat(nil_resolved_facts)
@@ -29,36 +28,22 @@ module Facter
29
28
  resolved_facts
30
29
  end
31
30
 
32
- def start_threads(searched_facts)
33
- threads = []
34
- # only resolve a fact once, even if multiple search facts depend on that fact
31
+ def resolve(searched_facts)
32
+ resolved_facts = []
33
+
35
34
  searched_facts
36
35
  .uniq { |searched_fact| searched_fact.fact_class.name }
37
36
  .each do |searched_fact|
38
- threads << Thread.new do
39
- begin
40
- fact = CoreFact.new(searched_fact)
41
- fact.create
42
- rescue StandardError => e
43
- @@log.log_exception(e)
44
- nil
45
- end
37
+ begin
38
+ fact = CoreFact.new(searched_fact)
39
+ fact_value = fact.create
40
+ resolved_facts << fact_value unless fact_value.nil?
41
+ rescue StandardError => e
42
+ @@log.log_exception(e)
46
43
  end
47
44
  end
48
45
 
49
- threads
50
- end
51
-
52
- def join_threads(threads, searched_facts)
53
- resolved_facts = []
54
-
55
- threads.each do |thread|
56
- thread.join
57
- resolved_facts << thread.value unless thread.value.nil?
58
- end
59
-
60
46
  resolved_facts.flatten!
61
-
62
47
  FactAugmenter.augment_resolved_facts(searched_facts, resolved_facts)
63
48
  end
64
49
  end
@@ -7,6 +7,8 @@ module Facter
7
7
  class FactFilter
8
8
  def filter_facts!(searched_facts)
9
9
  filter_legacy_facts!(searched_facts)
10
+ filter_blocked_legacy_facts!(searched_facts)
11
+
10
12
  searched_facts.each do |fact|
11
13
  fact.value = if fact.filter_tokens.any? && fact.value.respond_to?(:dig)
12
14
  fact.value.dig(*fact.filter_tokens)
@@ -18,6 +20,17 @@ module Facter
18
20
 
19
21
  private
20
22
 
23
+ # This will filter out the legacy facts that should be blocked. Because some legacy facts are just aliases
24
+ # to the core ones, even if they are blocked, facter will resolved them but they won't be displayed.
25
+
26
+ def filter_blocked_legacy_facts!(facts)
27
+ blocked_facts = Options[:blocked_facts] || []
28
+
29
+ facts.reject! do |fact|
30
+ blocked_facts.select { |blocked_fact| fact.name.match(/^#{blocked_fact}/) && fact.type == :legacy }.any?
31
+ end
32
+ end
33
+
21
34
  def filter_legacy_facts!(resolved_facts)
22
35
  return unless !Options[:show_legacy] && Options[:user_query].empty?
23
36
 
@@ -64,11 +64,34 @@ module Facter
64
64
  def block_facts(facts, options)
65
65
  blocked_facts = options[:blocked_facts] || []
66
66
 
67
+ reject_list_core, reject_list_legacy = construct_reject_lists(blocked_facts, facts)
68
+
67
69
  facts = facts.reject do |fact|
68
- blocked_facts.select { |blocked_fact| fact.name.match(/^#{blocked_fact}/) }.any?
70
+ reject_list_core.include?(fact) || reject_list_core.find do |fact_to_block|
71
+ fact_to_block.klass == fact.klass
72
+ end || reject_list_legacy.include?(fact)
69
73
  end
70
74
 
71
75
  facts
72
76
  end
77
+
78
+ def construct_reject_lists(blocked_facts, facts)
79
+ reject_list_core = []
80
+ reject_list_legacy = []
81
+
82
+ blocked_facts.each do |blocked|
83
+ facts.each do |fact|
84
+ next unless fact.name =~ /^#{blocked}/
85
+
86
+ if fact.type == :core
87
+ reject_list_core << fact
88
+ else
89
+ reject_list_legacy << fact
90
+ end
91
+ end
92
+ end
93
+
94
+ [reject_list_core, reject_list_legacy]
95
+ end
73
96
  end
74
97
  end
@@ -26,7 +26,8 @@ module Facter
26
26
  pretty_json = hash_to_facter_format(fact_collection)
27
27
 
28
28
  pretty_json = remove_enclosing_accolades(pretty_json)
29
- remove_comma_and_quotation(pretty_json)
29
+ pretty_json = remove_comma_and_quotation(pretty_json)
30
+ handle_newlines(pretty_json)
30
31
  end
31
32
 
32
33
  def format_for_multiple_user_queries(user_queries, resolved_facts)
@@ -38,6 +39,7 @@ module Facter
38
39
  pretty_json = hash_to_facter_format(facts_to_display)
39
40
  pretty_json = remove_enclosing_accolades(pretty_json)
40
41
  pretty_json = remove_comma_and_quotation(pretty_json)
42
+ pretty_json = handle_newlines(pretty_json)
41
43
 
42
44
  @log.debug('Remove quotes from value if value is a string')
43
45
  pretty_json.gsub(/^(\S*) => \"(.*)\"/, '\1 => \2')
@@ -84,6 +86,11 @@ module Facter
84
86
  pretty_fact_json.gsub(/^},/, '}')
85
87
  end
86
88
 
89
+ def handle_newlines(pretty_fact_json)
90
+ @log.debug('Convert newline characters to actual newlines')
91
+ pretty_fact_json.gsub('\n', "\n")
92
+ end
93
+
87
94
  def remove_comma_and_quotation(output)
88
95
  # quotation marks that come after \ are not removed
89
96
  @log.debug('Remove unnecessary comma and quotation marks on root facts')
@@ -56,7 +56,7 @@ module Facter
56
56
  return false if value[/^[0-9]+$/]
57
57
  return true if value =~ /y|Y|yes|Yes|YES|n|N|no|No|NO|True|TRUE|False|FALSE|on|On|ON|off|Off|OFF|:/
58
58
  return false if value[/[a-zA-Z]/]
59
- return false if value[/[0-9]+\.[0-9]+\./]
59
+ return false if value[/[0-9]+\.[0-9]+/]
60
60
 
61
61
  true
62
62
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Resolvers
5
+ module Aix
6
+ class Serialnumber < BaseResolver
7
+ @semaphore = Mutex.new
8
+ @fact_list ||= {}
9
+
10
+ class << self
11
+ private
12
+
13
+ def post_resolve(fact_name)
14
+ @fact_list.fetch(fact_name) { read_serialnumber(fact_name) }
15
+ end
16
+
17
+ def read_serialnumber(fact_name)
18
+ odmquery = Facter::ODMQuery.new
19
+ odmquery
20
+ .equals('name', 'sys0')
21
+ .equals('attribute', 'systemid')
22
+ result = odmquery.execute
23
+
24
+ result.each_line do |line|
25
+ if line.include?('value')
26
+ @fact_list[:serialnumber] = line.split('=')[1].strip.delete('\"')[6..-1]
27
+ break
28
+ end
29
+ end
30
+
31
+ @fact_list[fact_name]
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -12,6 +12,7 @@ module Facter
12
12
  # :bios_vendor
13
13
  # :bios_date
14
14
  # :bios_version
15
+ # :board_asset_tag
15
16
  # :board_vendor
16
17
  # :board_serial
17
18
  # :board_name
@@ -29,9 +30,9 @@ module Facter
29
30
  end
30
31
 
31
32
  def read_facts(fact_name)
32
- files = %w[bios_date bios_vendor bios_version board_vendor board_name board_serial
33
- chassis_asset_tag chassis_type sys_vendor product_name product_serial
34
- product_uuid]
33
+ files = %w[bios_date bios_vendor bios_version board_asset_tag board_vendor board_name
34
+ board_serial chassis_asset_tag chassis_type sys_vendor product_name
35
+ product_serial product_uuid]
35
36
  return unless File.directory?('/sys/class/dmi')
36
37
 
37
38
  file_content = Util::FileHelper.safe_read("/sys/class/dmi/id/#{fact_name}", nil)
@@ -7,13 +7,13 @@ module Facter
7
7
  @fact_list ||= {}
8
8
  EC2_METADATA_ROOT_URL = 'http://169.254.169.254/latest/meta-data/'
9
9
  EC2_USERDATA_ROOT_URL = 'http://169.254.169.254/latest/user-data/'
10
- EC2_CONNECTION_TIMEOUT = 0.6
11
10
  EC2_SESSION_TIMEOUT = 5
12
11
 
13
12
  class << self
14
13
  private
15
14
 
16
15
  def post_resolve(fact_name)
16
+ log.debug('Querying Ec2 metadata')
17
17
  @fact_list.fetch(fact_name) { read_facts(fact_name) }
18
18
  end
19
19
 
@@ -29,7 +29,7 @@ module Facter
29
29
  metadata.each_line do |line|
30
30
  next if line.empty?
31
31
 
32
- http_path_component = build_path_compoent(line)
32
+ http_path_component = build_path_component(line)
33
33
  next if http_path_component == 'security-credentials/'
34
34
 
35
35
  if http_path_component.end_with?('/')
@@ -44,27 +44,13 @@ module Facter
44
44
  end
45
45
  end
46
46
 
47
- def build_path_compoent(line)
47
+ def build_path_component(line)
48
48
  array_match = /^(\d+)=.*$/.match(line)
49
49
  array_match ? "#{array_match[1]}/" : line.strip
50
50
  end
51
51
 
52
52
  def get_data_from(url)
53
- require 'net/http'
54
-
55
- parsed_url = URI.parse(url)
56
- http = Net::HTTP.new(parsed_url.host)
57
- http.read_timeout = determine_session_timeout
58
- http.open_timeout = EC2_CONNECTION_TIMEOUT
59
- resp = http.get(parsed_url.path)
60
- response_code_valid?(resp.code) ? resp.body : ''
61
- rescue StandardError => e
62
- log.debug("Trying to connect to #{url} but got: #{e.message}")
63
- ''
64
- end
65
-
66
- def response_code_valid?(http_code)
67
- http_code.to_i.equal?(200)
53
+ Utils::Http.get_request(url, {}, { session: determine_session_timeout })
68
54
  end
69
55
 
70
56
  def determine_session_timeout
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Resolvers
5
+ class Gce < BaseResolver
6
+ @semaphore = Mutex.new
7
+ @fact_list ||= {}
8
+ METADATA_URL = 'http://metadata.google.internal/computeMetadata/v1/?recursive=true&alt=json'
9
+ HEADERS = { "Metadata-Flavor": 'Google', "Accept": 'application/json' }.freeze
10
+
11
+ class << self
12
+ private
13
+
14
+ def post_resolve(fact_name)
15
+ log.debug('reading Gce metadata')
16
+ @fact_list.fetch(fact_name) { read_facts(fact_name) }
17
+ end
18
+
19
+ def read_facts(fact_name)
20
+ @fact_list[:metadata] = query_for_metadata
21
+ @fact_list[fact_name]
22
+ end
23
+
24
+ def query_for_metadata
25
+ gce_data = extract_to_hash(Utils::Http.get_request(METADATA_URL, HEADERS))
26
+ parse_instance(gce_data)
27
+
28
+ gce_data.empty? ? nil : gce_data
29
+ end
30
+
31
+ def extract_to_hash(metadata)
32
+ JSON.parse(metadata)
33
+ rescue JSON::ParserError => e
34
+ log.debug("Trying to parse result but got: #{e.message}")
35
+ {}
36
+ end
37
+
38
+ def parse_instance(gce_data)
39
+ instance_data = gce_data['instance']
40
+ return if instance_data.nil? || instance_data.empty?
41
+
42
+ %w[image machineType zone].each do |key|
43
+ instance_data[key] = instance_data[key].split('/').last if instance_data[key]
44
+ end
45
+
46
+ network = instance_data.dig('networkInterfaces', 0, 'network')
47
+ instance_data['networkInterfaces'][0]['network'] = network.split('/').last unless network.nil?
48
+
49
+ gce_data['instance'] = instance_data
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end