From e5e14bad4595a095c7611ef0be1fc3459ca2ba74 Mon Sep 17 00:00:00 2001 From: Andrei Filipovici Date: Wed, 8 Apr 2020 17:16:12 +0300 Subject: [PATCH 01/13] (FACT-2542) Fix typo --- lib/facts/debian/os/distro/codename.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/facts/debian/os/distro/codename.rb b/lib/facts/debian/os/distro/codename.rb index c0e055070..3fc9a4ac9 100644 --- a/lib/facts/debian/os/distro/codename.rb +++ b/lib/facts/debian/os/distro/codename.rb @@ -14,7 +14,7 @@ def call_the_resolver Facter::ResolvedFact.new(FACT_NAME, fact_value) end - def retreieve_from_version + def retrieve_from_version version = Facter::Resolvers::OsRelease.resolve(:version) return unless version From 200c7991ab5bdf70210a600b2584f9c9aa9af293 Mon Sep 17 00:00:00 2001 From: Andrei Filipovici Date: Sun, 12 Apr 2020 23:15:02 +0300 Subject: [PATCH 02/13] (FACT-2542) Refactored some tests --- spec/facter/facter_spec.rb | 255 ++++++++++++++++--------------------- 1 file changed, 110 insertions(+), 145 deletions(-) diff --git a/spec/facter/facter_spec.rb b/spec/facter/facter_spec.rb index dffea35e7..4e66ce07c 100644 --- a/spec/facter/facter_spec.rb +++ b/spec/facter/facter_spec.rb @@ -24,27 +24,33 @@ Facter.remove_instance_variable(:@logger) end + def mock_fact_manager(method, return_value) + allow(fact_manager_spy).to receive(method).and_return(return_value) + allow(fact_collection_spy) + .to receive(:build_fact_collection!) + .with(return_value) + .and_return(return_value.empty? ? empty_fact_collection : fact_collection_spy) + end + + def mock_collection(method, os = nil, error = nil) + if error + allow(fact_collection_spy).to receive(method).with('os', 'name').and_raise(error) + else + allow(fact_collection_spy).to receive(method).with('os', 'name').and_return(os) + end + end + describe '#to_hash' do it 'returns one resolved fact' do - allow(fact_manager_spy).to receive(:resolve_facts).and_return([os_fact]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([os_fact]) - .and_return(fact_collection_spy) + mock_fact_manager(:resolve_facts, [os_fact]) - resolved_facts_hash = Facter.to_hash - expect(resolved_facts_hash).to eq(fact_collection_spy) + expect(Facter.to_hash).to eq(fact_collection_spy) end it 'return no resolved facts' do - allow(fact_manager_spy).to receive(:resolve_facts).and_return([]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([]) - .and_return(empty_fact_collection) + mock_fact_manager(:resolve_facts, []) - resolved_facts_hash = Facter.to_hash - expect(resolved_facts_hash).to eq(empty_fact_collection) + expect(Facter.to_hash).to eq(empty_fact_collection) end end @@ -121,197 +127,153 @@ end end + + describe '#value' do it 'returns a value' do - user_query = 'os.name' - - allow(fact_manager_spy).to receive(:resolve_facts).and_return([os_fact]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([os_fact]) - .and_return(fact_collection_spy) - allow(fact_collection_spy).to receive(:value).with('os', 'name').and_return('Ubuntu') + mock_fact_manager(:resolve_facts, [os_fact]) + mock_collection(:value,'Ubuntu') - resolved_facts_hash = Facter.value(user_query) - expect(resolved_facts_hash).to eq('Ubuntu') + expect(Facter.value('os.name')).to eq('Ubuntu') end it 'return no value' do - user_query = 'os.name' - - allow(fact_manager_spy).to receive(:resolve_facts).and_return([]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([]) - .and_return(empty_fact_collection) - allow(fact_collection_spy).to receive(:value).with('os', 'name').and_return(nil) + mock_fact_manager(:resolve_facts, []) + mock_collection(:value, nil) - resolved_facts_hash = Facter.value(user_query) - expect(resolved_facts_hash).to be nil + expect(Facter.value('os.name')).to be nil end end describe '#fact' do it 'returns a fact' do - user_query = 'os.name' + mock_fact_manager(:resolve_facts, [os_fact]) + mock_collection(:value,'Ubuntu') - allow(fact_manager_spy).to receive(:resolve_facts).and_return([os_fact]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([os_fact]) - .and_return(fact_collection_spy) - allow(fact_collection_spy).to receive(:value).with('os', 'name').and_return('Ubuntu') - - result = Facter.fact(user_query) - expect(result).to be_instance_of(Facter::ResolvedFact).and(having_attributes(value: 'Ubuntu')) + expect(Facter.fact('os.name')).to be_instance_of(Facter::ResolvedFact).and have_attributes(value: 'Ubuntu') end it 'can be interpolated' do - user_query = 'os.name' + mock_fact_manager(:resolve_facts, [os_fact]) + mock_collection(:value,'Ubuntu') - allow(fact_manager_spy).to receive(:resolve_facts).and_return([os_fact]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([os_fact]) - .and_return(fact_collection_spy) - allow(fact_collection_spy).to receive(:value).with('os', 'name').and_return('Ubuntu') # rubocop:disable Style/UnneededInterpolation - expect("#{Facter.fact(user_query)}").to eq('Ubuntu') + expect("#{Facter.fact('os.name')}").to eq('Ubuntu') # rubocop:enable Style/UnneededInterpolation end it 'return no value' do - user_query = 'os.name' - - allow(fact_manager_spy).to receive(:resolve_facts).and_return([]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([]) - .and_return(fact_collection_spy) - - allow(fact_collection_spy).to receive(:value).with('os', 'name').and_raise(key_error) + mock_fact_manager(:resolve_facts, []) + mock_collection(:value,nil, key_error) - result = Facter.fact(user_query) - expect(result).to be_nil + expect(Facter.fact('os.name')).to be_nil end end + describe '#[]' do it 'returns a fact' do - user_query = 'os.name' - - allow(fact_manager_spy).to receive(:resolve_facts).and_return([os_fact]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([os_fact]) - .and_return(fact_collection_spy) - allow(fact_collection_spy).to receive(:value).with('os', 'name').and_return('Ubuntu') + mock_fact_manager(:resolve_facts, [os_fact]) + mock_collection(:value,'Ubuntu') - result = Facter[user_query] - expect(result).to be_instance_of(Facter::ResolvedFact).and(having_attributes(value: 'Ubuntu')) + expect(Facter['os.name']).to be_instance_of(Facter::ResolvedFact).and(having_attributes(value: 'Ubuntu')) end it 'return no value' do - user_query = 'os.name' - - allow(fact_manager_spy).to receive(:resolve_facts).and_return([]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([]) - .and_return(fact_collection_spy) - allow(fact_collection_spy).to receive(:value).with('os', 'name').and_raise(key_error) + mock_fact_manager(:resolve_facts, []) + mock_collection(:value,nil, key_error) - result = Facter[user_query] - expect(result).to be_nil + expect(Facter['os.name']).to be_nil end end describe '#core_value' do it 'searched in core facts and returns a value' do - user_query = 'os.name' + mock_fact_manager(:resolve_core, [os_fact]) + mock_collection(:dig,'Ubuntu') - allow(fact_manager_spy).to receive(:resolve_core).and_return([os_fact]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([os_fact]) - .and_return(fact_collection_spy) - allow(fact_collection_spy).to receive(:dig).with('os', 'name').and_return('Ubuntu') - - resolved_facts_hash = Facter.core_value(user_query) - expect(resolved_facts_hash).to eq('Ubuntu') + expect(Facter.core_value('os.name')).to eq('Ubuntu') end it 'searches ion core facts and return no value' do - user_query = 'os.name' + mock_fact_manager(:resolve_core, []) + mock_collection(:dig,nil) - allow(fact_manager_spy).to receive(:resolve_core).and_return([]) - allow(fact_collection_spy) - .to receive(:build_fact_collection!) - .with([]) - .and_return(fact_collection_spy) - allow(fact_collection_spy).to receive(:dig).with('os', 'name').and_return(nil) - - resolved_facts_hash = Facter.core_value(user_query) - expect(resolved_facts_hash).to be nil + expect(Facter.core_value('os.name')).to be nil end end - describe '#clear' do - it 'sends call to LegacyFacter' do - expect(LegacyFacter).to receive(:clear).once - Facter.clear + describe 'LegacyFacter methods' do + let(:legacy_facter) { class_spy(LegacyFacter)} + before do + allow(LegacyFacter).to receive(:clear) + allow(LegacyFacter).to receive(:search) + + end + describe '#clear' do + it 'sends call to LegacyFacter' do + Facter.clear + expect(legacy_facter).to have_received(:clear).once + end end - end - describe '#search' do - it 'sends call to LegacyFacter' do - dirs = ['/dir1', '/dir2'] + describe '#search' do + it 'sends call to LegacyFacter' do + dirs = ['/dir1', '/dir2'] - expect(LegacyFacter).to receive(:search).with(dirs) - Facter.search(dirs) + Facter.search(dirs) + expect(LegacyFacter).to have_received(:search).with(dirs) + end end - end - describe '#search_path' do - it 'sends call to LegacyFacter' do - expect(LegacyFacter).to receive(:search_path).once - Facter.search_path + describe '#search_path' do + it 'sends call to LegacyFacter' do + expect(LegacyFacter).to receive(:search_path).once + Facter.search_path + end end - end - describe '#search_external' do - it 'sends call to LegacyFacter' do - dirs = ['/dir1', '/dir2'] + describe '#search_external' do + it 'sends call to LegacyFacter' do + dirs = ['/dir1', '/dir2'] - expect(LegacyFacter).to receive(:search_external).with(dirs) - Facter.search_external(dirs) + expect(LegacyFacter).to receive(:search_external).with(dirs) + Facter.search_external(dirs) + end end - end - describe '#search_external_path' do - it 'sends call to LegacyFacter' do - expect(LegacyFacter).to receive(:search_external_path).once - Facter.search_external_path + describe '#search_external_path' do + it 'sends call to LegacyFacter' do + allow(LegacyFacter).to receive(:search_external_path) + Facter.search_external_path + expect(LegacyFacter).to have_received(:search_external_path).once + end end - end - describe '#reset' do - it 'sends call to LegacyFacter' do - allow(LegacyFacter).to receive(:reset) - Facter.reset - expect(LegacyFacter).to have_received(:reset).once - end + describe '#reset' do + it 'sends call to LegacyFacter' do + allow(LegacyFacter).to receive(:reset) - it 'adds custom facts dirs' do - allow(LegacyFacter).to receive(:search) - Facter.reset - expect(LegacyFacter).to have_received(:search).once - end + Facter.reset + + expect(LegacyFacter).to have_received(:reset).once + end + + it 'adds custom facts dirs' do + allow(LegacyFacter).to receive(:search) + + Facter.reset - it 'add external facts dirs' do - allow(LegacyFacter).to receive(:search_external) - Facter.reset - expect(LegacyFacter).to have_received(:search_external).once + expect(LegacyFacter).to have_received(:search).once + end + + it 'add external facts dirs' do + allow(LegacyFacter).to receive(:search_external) + + Facter.reset + + expect(LegacyFacter).to have_received(:search_external).once + end end end @@ -343,6 +305,7 @@ it 'logs a debug message' do allow(logger).to receive(:debug).with('test') + expect(Facter.debug(message)).to be(nil) end end @@ -394,7 +357,9 @@ it 'format exception to display backtrace' do exception.set_backtrace("prog.rb:2:in `a'") + Facter.log_exception(exception, message) + expect(logger).to have_received(:error).with(expected_message) end end From d54ffb81660c5c4e06651f9f74b0ea62c9cd2f0c Mon Sep 17 00:00:00 2001 From: Andrei Filipovici Date: Mon, 13 Apr 2020 14:07:20 +0300 Subject: [PATCH 03/13] (FACT-2542) Finished example refactoring --- spec/facter/facter_spec.rb | 58 +++++++++++++------------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/spec/facter/facter_spec.rb b/spec/facter/facter_spec.rb index 4e66ce07c..6f67e25b3 100644 --- a/spec/facter/facter_spec.rb +++ b/spec/facter/facter_spec.rb @@ -55,80 +55,62 @@ def mock_collection(method, os = nil, error = nil) end describe '#to_user_output' do - it 'returns one fact and status 0' do - user_query = 'os.name' - expected_json_output = '{"os" : {"name": "ubuntu"}' - - allow(fact_manager_spy).to receive(:resolve_facts).and_return([os_fact]) + before do |example| + resolved_fact = example.metadata[:resolved_fact] ? [os_fact]: [] + expected_json_output = example.metadata[:resolved_fact] ? '{"os" : {"name": "ubuntu"}': '{}' + allow(fact_manager_spy).to receive(:resolve_facts).and_return(resolved_fact) json_fact_formatter = double(Facter::JsonFactFormatter) - allow(json_fact_formatter).to receive(:format).with([os_fact]).and_return(expected_json_output) - + allow(json_fact_formatter).to receive(:format).with(resolved_fact).and_return(expected_json_output) allow(Facter::FormatterFactory).to receive(:build).and_return(json_fact_formatter) + end + + it 'returns one fact and status 0', :resolved_fact => true do + user_query = 'os.name' + expected_json_output = '{"os" : {"name": "ubuntu"}' formated_facts = Facter.to_user_output({}, [user_query]) + expect(formated_facts).to eq([expected_json_output, 0]) end - it 'returns no facts and status 0' do + it 'returns no facts and status 0', :resolved_fact => false do user_query = 'os.name' expected_json_output = '{}' - allow(fact_manager_spy).to receive(:resolve_facts).and_return([]) - - json_fact_formatter = double(Facter::JsonFactFormatter) - allow(json_fact_formatter).to receive(:format).with([]).and_return(expected_json_output) - - allow(Facter::FormatterFactory).to receive(:build).and_return(json_fact_formatter) - formatted_facts = Facter.to_user_output({}, [user_query]) + expect(formatted_facts).to eq([expected_json_output, 0]) end context 'when provided with --strict option' do before do allow(Facter::Options).to receive(:[]).with(:config) + allow(Facter::Options.instance).to receive(:[]).with(:strict).and_return(true) end - it 'returns no fact and status 1' do - allow(logger).to receive(:error).with('fact "os.name" does not exist.', true) - + it 'returns no fact and status 1', :resolved_fact => false do user_query = 'os.name' expected_json_output = '{}' - - allow(fact_manager_spy).to receive(:resolve_facts).and_return([]) - allow(Facter::Options.instance).to receive(:[]).with(:strict).and_return(true) + allow(logger).to receive(:error).with('fact "os.name" does not exist.', true) allow(OsDetector).to receive(:detect).and_return(:solaris) - json_fact_formatter = double(Facter::JsonFactFormatter) - allow(json_fact_formatter).to receive(:format).and_return(expected_json_output) - - allow(Facter::FormatterFactory).to receive(:build).and_return(json_fact_formatter) - formatted_facts = Facter.to_user_output({}, user_query) + expect(formatted_facts).to eq([expected_json_output, 1]) end - it 'returns one fact and status 0' do + it 'returns one fact and status 0', :resolved_fact => true do user_query = 'os.name' expected_json_output = '{"os" : {"name": "ubuntu"}' - allow(Facter::Options.instance).to receive(:[]).with(:strict).and_return(true) - allow(fact_manager_spy).to receive(:resolve_facts).and_return([os_fact]) - - json_fact_formatter = double(Facter::JsonFactFormatter) - allow(json_fact_formatter).to receive(:format).with([os_fact]).and_return(expected_json_output) - - allow(Facter::FormatterFactory).to receive(:build).and_return(json_fact_formatter) - formated_facts = Facter.to_user_output({}, user_query) + expect(formated_facts).to eq([expected_json_output, 0]) end end end - - describe '#value' do it 'returns a value' do mock_fact_manager(:resolve_facts, [os_fact]) @@ -213,7 +195,7 @@ def mock_collection(method, os = nil, error = nil) describe '#clear' do it 'sends call to LegacyFacter' do Facter.clear - expect(legacy_facter).to have_received(:clear).once + expect(LegacyFacter).to have_received(:clear).once end end From 8f092a0d4989a6704258055730911d0b55668075 Mon Sep 17 00:00:00 2001 From: Andrei Filipovici Date: Mon, 13 Apr 2020 16:39:58 +0300 Subject: [PATCH 04/13] (FACT-2542) Fixed rubocop offenses and a failing test --- lib/facts/debian/os/distro/codename.rb | 2 +- spec/facter/facter_spec.rb | 36 ++++++++++++-------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/lib/facts/debian/os/distro/codename.rb b/lib/facts/debian/os/distro/codename.rb index 3fc9a4ac9..2135ad8d2 100644 --- a/lib/facts/debian/os/distro/codename.rb +++ b/lib/facts/debian/os/distro/codename.rb @@ -9,7 +9,7 @@ class Codename def call_the_resolver fact_value = Facter::Resolvers::OsRelease.resolve(:version_codename) - fact_value ||= retreieve_from_version + fact_value ||= retrieve_from_version Facter::ResolvedFact.new(FACT_NAME, fact_value) end diff --git a/spec/facter/facter_spec.rb b/spec/facter/facter_spec.rb index 6f67e25b3..c7c96d099 100644 --- a/spec/facter/facter_spec.rb +++ b/spec/facter/facter_spec.rb @@ -32,11 +32,11 @@ def mock_fact_manager(method, return_value) .and_return(return_value.empty? ? empty_fact_collection : fact_collection_spy) end - def mock_collection(method, os = nil, error = nil) + def mock_collection(method, os_name = nil, error = nil) if error allow(fact_collection_spy).to receive(method).with('os', 'name').and_raise(error) else - allow(fact_collection_spy).to receive(method).with('os', 'name').and_return(os) + allow(fact_collection_spy).to receive(method).with('os', 'name').and_return(os_name) end end @@ -56,8 +56,8 @@ def mock_collection(method, os = nil, error = nil) describe '#to_user_output' do before do |example| - resolved_fact = example.metadata[:resolved_fact] ? [os_fact]: [] - expected_json_output = example.metadata[:resolved_fact] ? '{"os" : {"name": "ubuntu"}': '{}' + resolved_fact = example.metadata[:resolved_fact] ? [os_fact] : [] + expected_json_output = example.metadata[:resolved_fact] ? '{"os" : {"name": "ubuntu"}' : '{}' allow(fact_manager_spy).to receive(:resolve_facts).and_return(resolved_fact) json_fact_formatter = double(Facter::JsonFactFormatter) @@ -65,7 +65,7 @@ def mock_collection(method, os = nil, error = nil) allow(Facter::FormatterFactory).to receive(:build).and_return(json_fact_formatter) end - it 'returns one fact and status 0', :resolved_fact => true do + it 'returns one fact and status 0', resolved_fact: true do user_query = 'os.name' expected_json_output = '{"os" : {"name": "ubuntu"}' @@ -74,7 +74,7 @@ def mock_collection(method, os = nil, error = nil) expect(formated_facts).to eq([expected_json_output, 0]) end - it 'returns no facts and status 0', :resolved_fact => false do + it 'returns no facts and status 0', resolved_fact: false do user_query = 'os.name' expected_json_output = '{}' @@ -89,7 +89,7 @@ def mock_collection(method, os = nil, error = nil) allow(Facter::Options.instance).to receive(:[]).with(:strict).and_return(true) end - it 'returns no fact and status 1', :resolved_fact => false do + it 'returns no fact and status 1', resolved_fact: false do user_query = 'os.name' expected_json_output = '{}' allow(logger).to receive(:error).with('fact "os.name" does not exist.', true) @@ -100,7 +100,7 @@ def mock_collection(method, os = nil, error = nil) expect(formatted_facts).to eq([expected_json_output, 1]) end - it 'returns one fact and status 0', :resolved_fact => true do + it 'returns one fact and status 0', resolved_fact: true do user_query = 'os.name' expected_json_output = '{"os" : {"name": "ubuntu"}' @@ -114,7 +114,7 @@ def mock_collection(method, os = nil, error = nil) describe '#value' do it 'returns a value' do mock_fact_manager(:resolve_facts, [os_fact]) - mock_collection(:value,'Ubuntu') + mock_collection(:value, 'Ubuntu') expect(Facter.value('os.name')).to eq('Ubuntu') end @@ -130,14 +130,14 @@ def mock_collection(method, os = nil, error = nil) describe '#fact' do it 'returns a fact' do mock_fact_manager(:resolve_facts, [os_fact]) - mock_collection(:value,'Ubuntu') + mock_collection(:value, 'Ubuntu') expect(Facter.fact('os.name')).to be_instance_of(Facter::ResolvedFact).and have_attributes(value: 'Ubuntu') end it 'can be interpolated' do mock_fact_manager(:resolve_facts, [os_fact]) - mock_collection(:value,'Ubuntu') + mock_collection(:value, 'Ubuntu') # rubocop:disable Style/UnneededInterpolation expect("#{Facter.fact('os.name')}").to eq('Ubuntu') @@ -146,24 +146,23 @@ def mock_collection(method, os = nil, error = nil) it 'return no value' do mock_fact_manager(:resolve_facts, []) - mock_collection(:value,nil, key_error) + mock_collection(:value, nil, key_error) expect(Facter.fact('os.name')).to be_nil end end - describe '#[]' do it 'returns a fact' do mock_fact_manager(:resolve_facts, [os_fact]) - mock_collection(:value,'Ubuntu') + mock_collection(:value, 'Ubuntu') expect(Facter['os.name']).to be_instance_of(Facter::ResolvedFact).and(having_attributes(value: 'Ubuntu')) end it 'return no value' do mock_fact_manager(:resolve_facts, []) - mock_collection(:value,nil, key_error) + mock_collection(:value, nil, key_error) expect(Facter['os.name']).to be_nil end @@ -172,26 +171,25 @@ def mock_collection(method, os = nil, error = nil) describe '#core_value' do it 'searched in core facts and returns a value' do mock_fact_manager(:resolve_core, [os_fact]) - mock_collection(:dig,'Ubuntu') + mock_collection(:dig, 'Ubuntu') expect(Facter.core_value('os.name')).to eq('Ubuntu') end it 'searches ion core facts and return no value' do mock_fact_manager(:resolve_core, []) - mock_collection(:dig,nil) + mock_collection(:dig, nil) expect(Facter.core_value('os.name')).to be nil end end describe 'LegacyFacter methods' do - let(:legacy_facter) { class_spy(LegacyFacter)} before do allow(LegacyFacter).to receive(:clear) allow(LegacyFacter).to receive(:search) - end + describe '#clear' do it 'sends call to LegacyFacter' do Facter.clear From fb9d4a11b122876a84e13c6a85b1cdf54c72b75d Mon Sep 17 00:00:00 2001 From: Filipovici-Andrei Date: Fri, 24 Apr 2020 12:16:30 +0300 Subject: [PATCH 05/13] (FACT-2559) Fix Facter.debugging? call when Facter not fully loaded (#455) * (FACT-2559) added check if Facter.debugging? is loaded * (FACT-2559) Fixed some tests leakage in logger_spec.rb Added tests for when Facter is not fully loaded * (FACT-2559) Created a context for when debugging is set to false * (FACT-2559) refactored debugging_active? * (FACT-2559) refactored file_helper.rb and file_helper_spec.rb Added in logger_spec.rb removal of multi_logger_double Co-authored-by: Andrei Filipovici Co-authored-by: Bogdan Irimie --- lib/framework/logging/logger.rb | 10 +++- lib/util/file_helper.rb | 17 +++++-- spec/facter/util/file_helper_spec.rb | 37 ++++++++------ spec/framework/logging/logger_spec.rb | 70 +++++++++++++++++++++------ 4 files changed, 97 insertions(+), 37 deletions(-) diff --git a/lib/framework/logging/logger.rb b/lib/framework/logging/logger.rb index f9b6c6edb..a4ed12087 100644 --- a/lib/framework/logging/logger.rb +++ b/lib/framework/logging/logger.rb @@ -65,7 +65,7 @@ def self.set_format_for_legacy_logger end def debug(msg) - return unless Facter.debugging? + return unless debugging_active? if msg.nil? || msg.empty? invoker = caller(1..1).first.slice(/.*:\d+/) @@ -94,5 +94,13 @@ def error(msg, colorize = false) def colorize(msg, color) "\e[#{color}m#{msg}\e[0m" end + + private + + def debugging_active? + return true unless Facter.respond_to?(:debugging?) + + Facter.debugging? + end end end diff --git a/lib/util/file_helper.rb b/lib/util/file_helper.rb index ce0385394..10b201f80 100644 --- a/lib/util/file_helper.rb +++ b/lib/util/file_helper.rb @@ -4,19 +4,28 @@ module Facter module Util class FileHelper @log = Log.new(self) + class << self DEBUG_MESSAGE = 'File at: %s is not accessible.' - def safe_read(path, result_if_not_readable = '') + def safe_read(path, default_return = '') return File.read(path) if File.readable?(path) - result_if_not_readable + log_failed_to_read(path) + default_return end - def safe_readlines(path, result_if_not_readable = []) + def safe_readlines(path, default_return = []) return File.readlines(path) if File.readable?(path) - result_if_not_readable + log_failed_to_read(path) + default_return + end + + private + + def log_failed_to_read(path) + @log.debug(DEBUG_MESSAGE % path) end end end diff --git a/spec/facter/util/file_helper_spec.rb b/spec/facter/util/file_helper_spec.rb index 56ddd2ecb..1508c5733 100644 --- a/spec/facter/util/file_helper_spec.rb +++ b/spec/facter/util/file_helper_spec.rb @@ -3,15 +3,19 @@ describe Facter::Util::FileHelper do subject(:file_helper) { Facter::Util::FileHelper } - let(:logger) { instance_spy(Facter::Log) } let(:path) { '/Users/admin/file.txt' } let(:content) { 'file content' } - let(:error_message) { 'File at: /Users/admin/file.txt is not accessible.' } + let(:error_message) { 'Facter::Util::FileHelper - File at: /Users/admin/file.txt is not accessible.' } let(:array_content) { ['line 1', 'line 2', 'line 3'] } + let(:multi_logger_double) { instance_spy(Facter::MultiLogger, level: :warn) } before do - file_helper.instance_variable_set(:@log, logger) - allow(logger).to receive(:debug).with(error_message) + Facter::Log.class_variable_set(:@@logger, multi_logger_double) + allow(Facter).to receive(:debugging?).and_return(true) + end + + after do + Facter::Log.class_variable_set(:@@logger, Facter::MultiLogger.new([])) end shared_context 'when file is readable' do @@ -53,7 +57,7 @@ it "doesn't log anything" do file_helper.safe_read(path) - expect(logger).not_to have_received(:debug) + expect(multi_logger_double).not_to have_received(:debug) end end @@ -80,11 +84,12 @@ expect(File).not_to have_received(:read) end - # it 'logs a debug message' do - # file_helper.safe_read(path) - # - # expect(logger).to have_received(:debug).with(error_message) - # end + it 'logs a debug message' do + file_helper.safe_read(path) + + expect(multi_logger_double).to have_received(:debug) + .with(error_message) + end end end @@ -115,7 +120,7 @@ it "doesn't log anything" do file_helper.safe_readlines(path) - expect(logger).not_to have_received(:debug) + expect(multi_logger_double).not_to have_received(:debug) end end @@ -142,11 +147,11 @@ expect(File).not_to have_received(:readlines) end - # it 'logs a debug message' do - # file_helper.safe_read(path) - # - # expect(logger).to have_received(:debug).with(error_message) - # end + it 'logs a debug message' do + file_helper.safe_read(path) + + expect(multi_logger_double).to have_received(:debug).with(error_message) + end end end end diff --git a/spec/framework/logging/logger_spec.rb b/spec/framework/logging/logger_spec.rb index 4ca146127..c421f7a11 100644 --- a/spec/framework/logging/logger_spec.rb +++ b/spec/framework/logging/logger_spec.rb @@ -3,14 +3,14 @@ describe Logger do subject(:log) { Facter::Log.new(Class) } - let(:file_logger_double) { instance_spy(Logger) } let(:multi_logger_double) { instance_spy(Facter::MultiLogger, level: :warn) } before do - Facter::Log.class_variable_set(:@@file_logger, file_logger_double) Facter::Log.class_variable_set(:@@logger, multi_logger_double) + end - allow(file_logger_double).to receive(:formatter=) + after do + Facter::Log.class_variable_set(:@@logger, Facter::MultiLogger.new([])) end describe '#debug' do @@ -18,43 +18,74 @@ allow(Facter).to receive(:debugging?).and_return(true) end - let(:handler) { instance_spy(Logger) } + context 'when debugging is set to false' do + it 'no debug messages are sent' do + allow(Facter).to receive(:debugging?).and_return(false) + + log.debug('info_message') - it 'noops of debugging is not set' do - allow(Facter).to receive(:debugging?).and_return(false) - log.debug('info_message') - expect(multi_logger_double).not_to have_received(:debug) + expect(multi_logger_double).not_to have_received(:debug) + end end it 'logs a warn if message is nil' do log.debug(nil) + expect(multi_logger_double).to have_received(:warn).with(/debug invoked with invalid message/) end it 'logs a warn if message is empty' do log.debug('') + expect(multi_logger_double).to have_received(:warn).with(/debug invoked with invalid message/) end - it 'writes debug message' do - log.debug('debug_message') - expect(multi_logger_double).to have_received(:debug).with('Class - debug_message') + shared_examples 'writes debug message' do + it 'calls debug on multi_logger' do + log.debug('debug_message') + + expect(multi_logger_double).to have_received(:debug).with('Class - debug_message') + end end - it 'provides on_message hook' do - Facter.on_message do |level, message| - handler.debug("on_message called with level: #{level}, message: #{message}") + it_behaves_like 'writes debug message' + + context 'when message callback is provided' do + after do + Facter::Log.class_variable_set(:@@message_callback, nil) end - log.debug('test') + it 'provides on_message hook' do + logger_double = instance_spy(Logger) + Facter.on_message do |level, message| + logger_double.debug("on_message called with level: #{level}, message: #{message}") + end + + log.debug('test') - expect(handler).to have_received(:debug).with('on_message called with level: debug, message: test') + expect(logger_double).to have_received(:debug).with('on_message called with level: debug, message: test') + end + end + + context 'when call is made during os detection in os_detector.rb and facter.rb is not fully loaded' do + before do + allow(Facter).to receive(:respond_to?).with(:debugging?).and_return(false) + end + + it_behaves_like 'writes debug message' + + it 'does not call Facter.debugging?' do + log.debug('debug_message') + + expect(Facter).not_to have_received(:debugging?) + end end end describe '#info' do it 'writes info message' do log.info('info_message') + expect(multi_logger_double).to have_received(:info).with('Class - info_message') end end @@ -62,6 +93,7 @@ describe '#warn' do it 'writes warn message' do log.warn('warn_message') + expect(multi_logger_double).to have_received(:warn).with('Class - warn_message') end end @@ -69,18 +101,23 @@ describe '#error' do it 'writes error message with color on macosx' do allow(OsDetector.instance).to receive(:detect).and_return(:macosx) + log.error('error_message', true) + expect(multi_logger_double).to have_received(:error).with("Class - \e[31merror_message\e[0m") end it 'writes error message not colorized on Windows' do allow(OsDetector.instance).to receive(:detect).and_return(:windows) + log.error('error_message', true) + expect(multi_logger_double).to have_received(:error).with('Class - error_message') end it 'writes error message' do log.error('error_message') + expect(multi_logger_double).to have_received(:error).with('Class - error_message') end end @@ -88,6 +125,7 @@ describe '#level=' do it 'sets the log level' do Facter::Log.level = :error + expect(multi_logger_double).to have_received(:level=).with(:error) end end From fa4638b902fff2925e33198da06cccee89ba94fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Romain=20Tarti=C3=A8re?= Date: Thu, 23 Apr 2020 23:31:14 -1000 Subject: [PATCH 06/13] (FACT-2564) Add support for zpool_featureflags and fix zpool_version (#443) * (FACT-2564) Add support for zpool_featureflags and fix zpool_version This allows facter-ng to return the same facts as facter 3.x. This changes took place in facter 3.8.0: https://github.com/puppetlabs/facter/pull/1597 * (FACT-2564) Move zpool feature flags in a let statement Co-authored-by: Bogdan Irimie --- lib/facts/solaris/zpool_featureflags.rb | 14 ++++ lib/resolvers/solaris/zpool_resolver.rb | 4 +- .../facts/solaris/zpool_featureflags_spec.rb | 24 ++++++ .../resolvers/solaris/zpool_resolver_spec.rb | 19 +++++ spec/fixtures/zpool-with-featureflags | 81 +++++++++++++++++++ 5 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 lib/facts/solaris/zpool_featureflags.rb create mode 100644 spec/facter/facts/solaris/zpool_featureflags_spec.rb create mode 100644 spec/fixtures/zpool-with-featureflags diff --git a/lib/facts/solaris/zpool_featureflags.rb b/lib/facts/solaris/zpool_featureflags.rb new file mode 100644 index 000000000..fa16e0142 --- /dev/null +++ b/lib/facts/solaris/zpool_featureflags.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class ZpoolFeatureflags + FACT_NAME = 'zpool_featureflags' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::ZPool.resolve(:zpool_featureflags) + Facter::ResolvedFact.new(FACT_NAME, fact_value) + end + end + end +end diff --git a/lib/resolvers/solaris/zpool_resolver.rb b/lib/resolvers/solaris/zpool_resolver.rb index 9d803ec05..9a2c8c36e 100644 --- a/lib/resolvers/solaris/zpool_resolver.rb +++ b/lib/resolvers/solaris/zpool_resolver.rb @@ -22,11 +22,13 @@ def zpool_fact(fact_name) def build_zpool_facts output, _status = Open3.capture2('zpool upgrade -v') features_list = output.scan(/^\s+(\d+)/).flatten + features_flags = output.scan(/^([a-z0-9_]+)[[:blank:]]*(\(read-only compatible\))?$/).map(&:first) return if features_list.empty? @fact_list[:zpool_featurenumbers] = features_list.join(',') - @fact_list[:zpool_version] = features_list.last + @fact_list[:zpool_featureflags] = features_flags.join(',') + @fact_list[:zpool_version] = features_flags.any? ? '5000' : features_list.last end end end diff --git a/spec/facter/facts/solaris/zpool_featureflags_spec.rb b/spec/facter/facts/solaris/zpool_featureflags_spec.rb new file mode 100644 index 000000000..e98bc68fe --- /dev/null +++ b/spec/facter/facts/solaris/zpool_featureflags_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +describe Facts::Solaris::ZpoolFeatureflags do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::ZpoolFeatureflags.new } + + let(:zpool_feature_flags) { 'async_destroy,empty_bpobj,lz4_compress,multi_vdev_crash_dump,spacemap_histogram' } + + before do + allow(Facter::Resolvers::Solaris::ZPool).to \ + receive(:resolve).with(:zpool_featureflags).and_return(zpool_feature_flags) + end + + it 'calls Facter::Resolvers::Solaris::ZPool' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::ZPool).to have_received(:resolve).with(:zpool_featureflags) + end + + it 'returns the zpool_featureflags fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'zpool_featureflags', value: zpool_feature_flags) + end + end +end diff --git a/spec/facter/resolvers/solaris/zpool_resolver_spec.rb b/spec/facter/resolvers/solaris/zpool_resolver_spec.rb index e9d9adc2f..54377cc18 100644 --- a/spec/facter/resolvers/solaris/zpool_resolver_spec.rb +++ b/spec/facter/resolvers/solaris/zpool_resolver_spec.rb @@ -28,6 +28,25 @@ expect(result).to eq('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,' \ '24,25,26,27,28,29,30,31,32,33,34') end + + context 'when zpool has featureflags' do + let(:output) { load_fixture('zpool-with-featureflags').read } + let(:zpool_featureflags) do + 'async_destroy,empty_bpobj,lz4_compress,multi_vdev_crash_dump,spacemap_histogram,enabled_txg,' \ + 'hole_birth,extensible_dataset,embedded_data,bookmarks,filesystem_limits,large_blocks,large_dnode,' \ + 'sha512,skein,device_removal,obsolete_counts,zpool_checkpoint,spacemap_v2' + end + + it 'returns zpool version fact' do + result = Facter::Resolvers::Solaris::ZPool.resolve(:zpool_version) + expect(result).to eq('5000') + end + + it 'returns zpool featureflags fact' do + result = Facter::Resolvers::Solaris::ZPool.resolve(:zpool_featureflags) + expect(result).to eq(zpool_featureflags) + end + end end context 'when zpool command is not found' do diff --git a/spec/fixtures/zpool-with-featureflags b/spec/fixtures/zpool-with-featureflags new file mode 100644 index 000000000..7e1959e12 --- /dev/null +++ b/spec/fixtures/zpool-with-featureflags @@ -0,0 +1,81 @@ +This system supports ZFS pool feature flags. + +The following features are supported: + +FEAT DESCRIPTION +------------------------------------------------------------- +async_destroy (read-only compatible) + Destroy filesystems asynchronously. +empty_bpobj (read-only compatible) + Snapshots use less space. +lz4_compress + LZ4 compression algorithm support. +multi_vdev_crash_dump + Crash dumps to multiple vdev pools. +spacemap_histogram (read-only compatible) + Spacemaps maintain space histograms. +enabled_txg (read-only compatible) + Record txg at which a feature is enabled +hole_birth + Retain hole birth txg for more precise zfs send +extensible_dataset + Enhanced dataset functionality, used by other features. +embedded_data + Blocks which compress very well use even less space. +bookmarks (read-only compatible) + "zfs bookmark" command +filesystem_limits (read-only compatible) + Filesystem and snapshot limits. +large_blocks + Support for blocks larger than 128KB. +large_dnode + Variable on-disk size of dnodes. +sha512 + SHA-512/256 hash algorithm. +skein + Skein hash algorithm. +device_removal + Top-level vdevs can be removed, reducing logical pool size. +obsolete_counts (read-only compatible) + Reduce memory used by removed devices when their blocks are freed or remapped. +zpool_checkpoint (read-only compatible) + Pool state can be checkpointed, allowing rewind later. +spacemap_v2 (read-only compatible) + Space maps representing large segments are more efficient. + +The following legacy versions are also supported: + +VER DESCRIPTION +--- -------------------------------------------------------- + 1 Initial ZFS version + 2 Ditto blocks (replicated metadata) + 3 Hot spares and double parity RAID-Z + 4 zpool history + 5 Compression using the gzip algorithm + 6 bootfs pool property + 7 Separate intent log devices + 8 Delegated administration + 9 refquota and refreservation properties + 10 Cache devices + 11 Improved scrub performance + 12 Snapshot properties + 13 snapused property + 14 passthrough-x aclinherit + 15 user/group space accounting + 16 stmf property support + 17 Triple-parity RAID-Z + 18 Snapshot user holds + 19 Log device removal + 20 Compression using zle (zero-length encoding) + 21 Deduplication + 22 Received properties + 23 Slim ZIL + 24 System attributes + 25 Improved scrub stats + 26 Improved snapshot deletion performance + 27 Improved snapshot creation performance + 28 Multiple vdev replacements + +For more information on a particular version, including supported releases, +see the ZFS Administration Guide. + From 3dd800c6a424ad694b35c30c7b29f407b8dc229c Mon Sep 17 00:00:00 2001 From: oanatmaria <49147761+oanatmaria@users.noreply.github.com> Date: Fri, 24 Apr 2020 12:38:55 +0300 Subject: [PATCH 07/13] (FACT-2553) remove double backslashes from path (#456) Co-authored-by: Bogdan Irimie --- .rubocop_todo.yml | 6 +- .../formatters/legacy_fact_formatter.rb | 3 +- .../formatters/yaml_fact_formatter.rb | 2 + .../formatters/legacy_fact_formatter_spec.rb | 94 +++++++++---------- .../formatters/yaml_fact_formatter_spec.rb | 85 ++++++++++------- 5 files changed, 100 insertions(+), 90 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 92c4d5334..93aeee91b 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 1000` -# on 2020-04-15 10:09:42 +0300 using RuboCop version 0.74.0. +# on 2020-04-16 12:37:29 +0300 using RuboCop version 0.74.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -190,7 +190,7 @@ RSpec/SubjectStub: - 'spec/custom_facts/util/fact_spec.rb' - 'spec/custom_facts/util/resolution_spec.rb' -# Offense count: 179 +# Offense count: 172 # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: Exclude: @@ -254,6 +254,4 @@ RSpec/VerifiedDoubles: - 'spec/framework/core/session_cache_spec.rb' - 'spec/framework/formatters/hocon_fact_formatter_spec.rb' - 'spec/framework/formatters/json_fact_formatter_spec.rb' - - 'spec/framework/formatters/legacy_fact_formatter_spec.rb' - - 'spec/framework/formatters/yaml_fact_formatter_spec.rb' - 'spec/mocks/util.rb' diff --git a/lib/framework/formatters/legacy_fact_formatter.rb b/lib/framework/formatters/legacy_fact_formatter.rb index 3cbcdd63b..d61f6a62a 100644 --- a/lib/framework/formatters/legacy_fact_formatter.rb +++ b/lib/framework/formatters/legacy_fact_formatter.rb @@ -65,7 +65,8 @@ def hash_to_facter_format(facts_hash) @log.debug('Remove quotes from parent nodes') pretty_json.gsub!(/\"(.*)\"\ =>/, '\1 =>') - pretty_json + @log.debug('Remove double backslashes from paths') + pretty_json.gsub(/\\\\/, '\\') end def remove_enclosing_accolades(pretty_fact_json) diff --git a/lib/framework/formatters/yaml_fact_formatter.rb b/lib/framework/formatters/yaml_fact_formatter.rb index 9be9fb455..ee5687991 100644 --- a/lib/framework/formatters/yaml_fact_formatter.rb +++ b/lib/framework/formatters/yaml_fact_formatter.rb @@ -9,6 +9,8 @@ def initialize def format(fact_hash) yaml_pretty = YAML.dump(JSON.parse(JsonFactFormatter.new.format(fact_hash))) + @log.debug('Replace single backslash with double backslashes') + yaml_pretty.gsub!(/\\/, '\&\&') @log.debug('Replace --- from yaml beginning, to keep it compatible with C facter') yaml_pretty.gsub(/^---[\r\n]+/, '') end diff --git a/spec/framework/formatters/legacy_fact_formatter_spec.rb b/spec/framework/formatters/legacy_fact_formatter_spec.rb index d04e6e5c8..c500adb33 100644 --- a/spec/framework/formatters/legacy_fact_formatter_spec.rb +++ b/spec/framework/formatters/legacy_fact_formatter_spec.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true describe Facter::LegacyFactFormatter do + subject(:legacy_formatter) { Facter::LegacyFactFormatter.new } + let(:resolved_fact1) do Facter::ResolvedFact.new('resolved_fact1', 'resolved_fact1_value') end @@ -37,6 +39,10 @@ Facter::ResolvedFact.new('my.nested.fact2', nil) end + let(:win_path) do + Facter::ResolvedFact.new('path', 'C:\\Program Files\\Puppet Labs\\Puppet\\bin;C:\\cygwin64\\bin') + end + before do resolved_fact1.user_query = 'resolved_fact1' resolved_fact1.filter_tokens = [] @@ -64,6 +70,9 @@ nil_nested_fact2.user_query = 'my.nested.fact2' nil_nested_fact2.filter_tokens = [] + + win_path.user_query = '' + win_path.filter_tokens = [] end context 'when no user query' do @@ -71,9 +80,7 @@ context 'when facts have value' do it 'returns output' do - formatted_output = Facter::LegacyFactFormatter.new.format([resolved_fact1, resolved_fact2]) - - expect(formatted_output).to eq(expected_output) + expect(legacy_formatter.format([resolved_fact1, resolved_fact2])).to eq(expected_output) end end @@ -88,27 +95,23 @@ context 'when is root level fact' do it 'prints no values if all facts are nil' do - formatted_output = Facter::LegacyFactFormatter.new.format([nil_resolved_fact1, nil_resolved_fact2]) - expect(formatted_output).to eq('') + expect(legacy_formatter.format([nil_resolved_fact1, nil_resolved_fact2])).to eq('') end it 'prints only the fact that is not nil' do - formatted_output = Facter::LegacyFactFormatter.new.format([nil_resolved_fact1, resolved_fact2]) - expect(formatted_output).to eq('resolved_fact2 => resolved_fact2_value') + expect(legacy_formatter.format([nil_resolved_fact1, resolved_fact2])).to eq('resolved_fact2 =>'\ + ' resolved_fact2_value') end end context 'when facts are nested' do it 'prints no values if all facts are nil' do - formatted_output = Facter::LegacyFactFormatter.new.format([nil_nested_fact1, nil_nested_fact2]) - expect(formatted_output).to eq('') + expect(legacy_formatter.format([nil_nested_fact1, nil_nested_fact2])).to eq('') end it 'prints only the fact that is not nil' do - formatted_output = - Facter::LegacyFactFormatter.new.format([nil_nested_fact1, nil_nested_fact2, resolved_fact2]) - - expect(formatted_output).to eq('resolved_fact2 => resolved_fact2_value') + expect(legacy_formatter.format([nil_nested_fact1, nil_nested_fact2, resolved_fact2])) + .to eq('resolved_fact2 => resolved_fact2_value') end end end @@ -117,27 +120,29 @@ context 'when one user query' do context 'when facts have values' do it 'returns single value' do - formatted_output = Facter::LegacyFactFormatter.new.format([resolved_fact1]) - - expect(formatted_output).to eq('resolved_fact1_value') + expect(legacy_formatter.format([resolved_fact1])).to eq('resolved_fact1_value') end it 'returns a single value for a nested fact' do - formatted_output = Facter::LegacyFactFormatter.new.format([nested_fact1]) - - expect(formatted_output).to eq('my_nested_fact_value') + expect(legacy_formatter.format([nested_fact1])).to eq('my_nested_fact_value') end context 'when there is a single user query that contains :' do let(:resolved_fact) do - double(Facter::ResolvedFact, name: 'networking.ip6', value: 'fe80::7ca0:ab22:703a:b329', - user_query: 'networking.ip6', filter_tokens: [], type: :core) + instance_spy(Facter::ResolvedFact, name: 'networking.ip6', value: 'fe80::7ca0:ab22:703a:b329', + user_query: 'networking.ip6', filter_tokens: [], type: :core) end it 'returns single value without replacing : with =>' do - formatted_output = Facter::LegacyFactFormatter.new.format([resolved_fact]) + expect(legacy_formatter.format([resolved_fact])).to eq('fe80::7ca0:ab22:703a:b329') + end + end + + context 'when Windows path' do + let(:expected_output) { 'path => C:\\Program Files\\Puppet Labs\\Puppet\\bin;C:\\cygwin64\\bin' } - expect(formatted_output).to eq('fe80::7ca0:ab22:703a:b329') + it 'returns path with one escaped backslash' do + expect(legacy_formatter.format([win_path])).to eq(expected_output) end end end @@ -145,21 +150,19 @@ context 'when fact value is nil' do context 'with root level fact' do it 'prints no values if all facts are nil' do - formatted_output = Facter::LegacyFactFormatter.new.format([nil_resolved_fact1]) - expect(formatted_output).to eq('') + expect(legacy_formatter.format([nil_resolved_fact1])).to eq('') end end context 'with facts that are nested' do it 'returns empty strings for first level query' do - formatted_output = Facter::LegacyFactFormatter.new.format([nil_nested_fact1]) - expect(formatted_output).to eq('') + expect(legacy_formatter.format([nil_nested_fact1])).to eq('') end it 'returns empty strings for leaf level query' do nil_nested_fact1.user_query = 'my.nested.fact1' - formatted_output = Facter::LegacyFactFormatter.new.format([nil_nested_fact1]) - expect(formatted_output).to eq('') + + expect(legacy_formatter.format([nil_nested_fact1])).to eq('') end end end @@ -173,22 +176,16 @@ end it 'returns output' do - formatted_output = Facter::LegacyFactFormatter.new.format([resolved_fact1, resolved_fact2]) - - expect(formatted_output).to eq(expected_output) + expect(legacy_formatter.format([resolved_fact1, resolved_fact2])).to eq(expected_output) end it 'returns output for multiple user queries' do - formatted_output = Facter::LegacyFactFormatter.new.format([nested_fact1, nested_fact2]) - - expect(formatted_output).to eq(nested_expected_output) + expect(legacy_formatter.format([nested_fact1, nested_fact2])).to eq(nested_expected_output) end context 'when value is a hash' do it "returns 'value'" do - formatted_output = Facter::LegacyFactFormatter.new.format([nested_fact3]) - - expect(formatted_output).to eq('value') + expect(legacy_formatter.format([nested_fact3])).to eq('value') end end end @@ -196,26 +193,27 @@ context 'with fact value that is nil' do context 'with a root level fact' do it 'prints no values if all facts are nil' do - formatted_output = Facter::LegacyFactFormatter.new.format([nil_resolved_fact1, nil_resolved_fact2]) - expect(formatted_output).to eq("nil_resolved_fact1 => \nnil_resolved_fact2 => ") + expect(legacy_formatter.format([nil_resolved_fact1, nil_resolved_fact2])) + .to eq("nil_resolved_fact1 => \nnil_resolved_fact2 => ") end it 'prints a value only for the fact that is not nil' do - formatted_output = Facter::LegacyFactFormatter.new.format([nil_resolved_fact1, resolved_fact2]) - expect(formatted_output).to eq("nil_resolved_fact1 => \nresolved_fact2 => resolved_fact2_value") + expect(legacy_formatter.format([nil_resolved_fact1, resolved_fact2])) + .to eq("nil_resolved_fact1 => \nresolved_fact2 => resolved_fact2_value") end end context 'with facts that are nested' do it 'returns empty strings for first and leaf level query' do - formatted_output = Facter::LegacyFactFormatter.new.format([nil_resolved_fact1, nil_nested_fact2]) - expect(formatted_output).to eq("my.nested.fact2 => \nnil_resolved_fact1 => ") + expect(legacy_formatter.format([nil_resolved_fact1, nil_nested_fact2])) + .to eq("my.nested.fact2 => \nnil_resolved_fact1 => ") end it 'returns empty strings for leaf level query' do nil_nested_fact1.user_query = 'my.nested.fact1' - formatted_output = Facter::LegacyFactFormatter.new.format([nil_resolved_fact1, resolved_fact2]) - expect(formatted_output).to eq("nil_resolved_fact1 => \nresolved_fact2 => resolved_fact2_value") + + expect(legacy_formatter.format([nil_resolved_fact1, resolved_fact2])) + .to eq("nil_resolved_fact1 => \nresolved_fact2 => resolved_fact2_value") end end end @@ -223,9 +221,7 @@ context 'when there is an empty resolved fact array' do it 'returns nil' do - formatted_output = Facter::LegacyFactFormatter.new.format([]) - - expect(formatted_output).to eq(nil) + expect(legacy_formatter.format([])).to eq(nil) end end end diff --git a/spec/framework/formatters/yaml_fact_formatter_spec.rb b/spec/framework/formatters/yaml_fact_formatter_spec.rb index 228f6ed58..556a81135 100644 --- a/spec/framework/formatters/yaml_fact_formatter_spec.rb +++ b/spec/framework/formatters/yaml_fact_formatter_spec.rb @@ -1,52 +1,65 @@ # frozen_string_literal: true describe Facter::YamlFactFormatter do - it 'formats to yaml when no user query' do - resolved_fact1 = - double(Facter::ResolvedFact, name: 'os.name', value: 'Darwin', - user_query: '', filter_tokens: [], type: :core) - resolved_fact2 = - double(Facter::ResolvedFact, name: 'os.family', value: 'Darwin', - user_query: '', filter_tokens: [], type: :core) - resolved_fact3 = - double(Facter::ResolvedFact, name: 'os.architecture', value: 'x86_64', - user_query: '', filter_tokens: [], type: :core) - resolved_fact_list = [resolved_fact1, resolved_fact2, resolved_fact3] + subject(:yaml_formatter) { Facter::YamlFactFormatter.new } - double - - formatted_output = Facter::YamlFactFormatter.new.format(resolved_fact_list) + let(:resolved_fact1) do + instance_spy(Facter::ResolvedFact, name: 'os.name', value: 'Darwin', + user_query: user_query1, filter_tokens: [], type: :core) + end + let(:resolved_fact2) do + instance_spy(Facter::ResolvedFact, name: 'os.family', value: 'Darwin', + user_query: user_query2, filter_tokens: [], type: :core) + end + let(:resolved_fact3) do + instance_spy(Facter::ResolvedFact, name: 'os.architecture', value: 'x86_64', + user_query: user_query3, filter_tokens: [], type: :core) + end + let(:user_query1) { '' } + let(:user_query2) { '' } + let(:user_query3) { '' } - expected_output = "os:\n architecture: x86_64\n family: Darwin\n name: Darwin\n" + context 'when no user query' do + let(:resolved_fact_list) { [resolved_fact1, resolved_fact2, resolved_fact3] } + let(:expected_output) { "os:\n architecture: x86_64\n family: Darwin\n name: Darwin\n" } - expect(formatted_output).to eq(expected_output) + it 'formats to yaml' do + expect(yaml_formatter.format(resolved_fact_list)).to eq(expected_output) + end end - it 'formats to yaml for a single user query' do - resolved_fact = - double(Facter::ResolvedFact, name: 'os.name', value: 'Darwin', - user_query: 'os.name', filter_tokens: [], type: :core) - resolved_fact_list = [resolved_fact] - formatted_output = Facter::YamlFactFormatter.new.format(resolved_fact_list) - - expected_output = "os.name: Darwin\n" + context 'when there is a single user query' do + let(:resolved_fact_list) { [resolved_fact1] } + let(:expected_output) { "os.name: Darwin\n" } + let(:user_query1) { 'os.name' } - expect(formatted_output).to eq(expected_output) + it 'formats to yaml' do + expect(yaml_formatter.format(resolved_fact_list)).to eq(expected_output) + end end - it 'formats to yaml for multiple user queries' do - resolved_fact1 = - double(Facter::ResolvedFact, name: 'os.name', value: 'Darwin', - user_query: 'os.name', filter_tokens: [], type: :core) - resolved_fact2 = - double(Facter::ResolvedFact, name: 'os.family', value: 'Darwin', - user_query: 'os.family', filter_tokens: [], type: :core) + context 'when there are multiple user queries' do + let(:resolved_fact_list) { [resolved_fact1, resolved_fact2] } + let(:expected_output) { "os.family: Darwin\nos.name: Darwin\n" } + let(:user_query1) { 'os.name' } + let(:user_query2) { 'os.family' } - resolved_fact_list = [resolved_fact1, resolved_fact2] - formatted_output = Facter::YamlFactFormatter.new.format(resolved_fact_list) + it 'formats to yaml' do + expect(yaml_formatter.format(resolved_fact_list)).to eq(expected_output) + end + end - expected_output = "os.family: Darwin\nos.name: Darwin\n" + context 'when on Windows' do + let(:win_path) do + instance_spy(Facter::ResolvedFact, name: 'path', value: value, + user_query: '', filter_tokens: [], type: :core) + end + let(:value) { 'C:\\Program Files\\Puppet Labs\\Puppet\\bin;C:\\cygwin64\\bin' } + let(:expected_output) { "path: C:\\\\Program Files\\\\Puppet Labs\\\\Puppet\\\\bin;C:\\\\cygwin64\\\\bin\n" } + let(:resolved_fact_list) { [win_path] } - expect(formatted_output).to eq(expected_output) + it 'formats path with double escaped backslashes' do + expect(yaml_formatter.format(resolved_fact_list)).to eq(expected_output) + end end end From 0406682f1320973a170b4efa10c62f96e0a26f67 Mon Sep 17 00:00:00 2001 From: oanatmaria <49147761+oanatmaria@users.noreply.github.com> Date: Fri, 24 Apr 2020 14:06:23 +0300 Subject: [PATCH 08/13] (FACT-2552) Add Solaris processors facts (#451) * (FACT-2552) Add Solaris processors facts * (FACT-2552) Fix rspec failure --- lib/facts/debian/memory/swap/available.rb | 2 +- .../debian/memory/swap/available_bytes.rb | 2 +- lib/facts/debian/memory/swap/total.rb | 2 +- lib/facts/debian/memory/swap/total_bytes.rb | 2 +- lib/facts/debian/memory/swap/used.rb | 2 +- lib/facts/debian/memory/system/available.rb | 2 +- .../debian/memory/system/available_bytes.rb | 2 +- lib/facts/debian/memory/system/total.rb | 2 +- lib/facts/debian/memory/system/total_bytes.rb | 2 +- lib/facts/debian/memory/system/used.rb | 2 +- lib/facts/el/memory/swap/available.rb | 2 +- lib/facts/el/memory/swap/available_bytes.rb | 2 +- lib/facts/el/memory/swap/total.rb | 2 +- lib/facts/el/memory/swap/total_bytes.rb | 2 +- lib/facts/el/memory/swap/used.rb | 2 +- lib/facts/el/memory/system/available.rb | 2 +- lib/facts/el/memory/system/available_bytes.rb | 2 +- lib/facts/el/memory/system/total.rb | 2 +- lib/facts/el/memory/system/total_bytes.rb | 2 +- lib/facts/el/memory/system/used.rb | 2 +- lib/facts/macosx/memory/swap/available.rb | 2 +- .../macosx/memory/swap/available_bytes.rb | 2 +- lib/facts/macosx/memory/swap/total.rb | 2 +- lib/facts/macosx/memory/swap/total_bytes.rb | 2 +- lib/facts/macosx/memory/swap/used.rb | 2 +- lib/facts/macosx/memory/system/available.rb | 2 +- .../macosx/memory/system/available_bytes.rb | 2 +- lib/facts/macosx/memory/system/total.rb | 2 +- lib/facts/macosx/memory/system/total_bytes.rb | 2 +- lib/facts/macosx/memory/system/used.rb | 2 +- lib/facts/macosx/processors/speed.rb | 3 +- lib/facts/sles/memory/swap/available.rb | 2 +- lib/facts/sles/memory/swap/available_bytes.rb | 2 +- lib/facts/sles/memory/swap/total.rb | 2 +- lib/facts/sles/memory/swap/total_bytes.rb | 2 +- lib/facts/sles/memory/swap/used.rb | 2 +- lib/facts/sles/memory/system/available.rb | 2 +- .../sles/memory/system/available_bytes.rb | 2 +- lib/facts/sles/memory/system/total.rb | 2 +- lib/facts/sles/memory/system/total_bytes.rb | 2 +- lib/facts/sles/memory/system/used.rb | 2 +- lib/facts/solaris/processors/count.rb | 17 ++++ lib/facts/solaris/processors/isa.rb | 17 ++++ lib/facts/solaris/processors/models.rb | 21 +++++ lib/facts/solaris/processors/physicalcount.rb | 17 ++++ lib/facts/solaris/processors/speed.rb | 17 ++++ lib/facts/windows/memory/system/available.rb | 2 +- .../windows/memory/system/available_bytes.rb | 2 +- lib/facts/windows/memory/system/total.rb | 2 +- .../windows/memory/system/total_bytes.rb | 2 +- lib/facts/windows/memory/system/used.rb | 2 +- lib/facts_utils/bytes_converter.rb | 15 ---- lib/facts_utils/bytes_to_human_readable.rb | 38 --------- lib/facts_utils/unit_converter.rb | 59 ++++++++++++++ lib/resolvers/aix/mountpoints.rb | 6 +- lib/resolvers/aix/partitions.rb | 2 +- lib/resolvers/disk_resolver.rb | 2 +- lib/resolvers/macosx/mountpoints_resolver.rb | 6 +- lib/resolvers/macosx/processor_resolver.rb | 11 +-- lib/resolvers/mountpoints_resolver.rb | 6 +- lib/resolvers/partitions.rb | 3 +- lib/resolvers/solaris/processors.rb | 40 ++++++++++ .../debian/memory/swap/available_spec.rb | 3 +- .../facts/debian/memory/swap/total_spec.rb | 3 +- .../facts/debian/memory/swap/used_spec.rb | 3 +- .../debian/memory/system/available_spec.rb | 3 +- .../facts/debian/memory/system/total_spec.rb | 3 +- .../facts/debian/memory/system/used_spec.rb | 3 +- .../facts/el/memory/system/used_spec.rb | 3 +- .../facts/macosx/processors/speed_spec.rb | 3 +- .../facts/sles/memory/system/used_spec.rb | 3 +- .../facts/solaris/processors/count_spec.rb | 25 ++++++ .../facts/solaris/processors/isa_spec.rb | 25 ++++++ .../facts/solaris/processors/models_spec.rb | 27 +++++++ .../solaris/processors/physicalcount_spec.rb | 26 +++++++ .../facts/solaris/processors/speed_spec.rb | 25 ++++++ .../facts_utils/bytes_converter_spec.rb | 21 ----- .../bytes_to_human_readable_spec.rb | 35 --------- .../facter/facts_utils/unit_converter_spec.rb | 73 ++++++++++++++++++ .../macosx/processors_resolver_spec.rb | 2 +- .../resolvers/solaris/processors_spec.rb | 73 ++++++++++++++++++ spec/fixtures/kstat_cpu | 77 +++++++++++++++++++ 82 files changed, 611 insertions(+), 195 deletions(-) create mode 100644 lib/facts/solaris/processors/count.rb create mode 100644 lib/facts/solaris/processors/isa.rb create mode 100644 lib/facts/solaris/processors/models.rb create mode 100644 lib/facts/solaris/processors/physicalcount.rb create mode 100644 lib/facts/solaris/processors/speed.rb delete mode 100644 lib/facts_utils/bytes_converter.rb delete mode 100644 lib/facts_utils/bytes_to_human_readable.rb create mode 100644 lib/facts_utils/unit_converter.rb create mode 100644 lib/resolvers/solaris/processors.rb create mode 100644 spec/facter/facts/solaris/processors/count_spec.rb create mode 100644 spec/facter/facts/solaris/processors/isa_spec.rb create mode 100644 spec/facter/facts/solaris/processors/models_spec.rb create mode 100644 spec/facter/facts/solaris/processors/physicalcount_spec.rb create mode 100644 spec/facter/facts/solaris/processors/speed_spec.rb delete mode 100644 spec/facter/facts_utils/bytes_converter_spec.rb delete mode 100644 spec/facter/facts_utils/bytes_to_human_readable_spec.rb create mode 100644 spec/facter/facts_utils/unit_converter_spec.rb create mode 100644 spec/facter/resolvers/solaris/processors_spec.rb create mode 100644 spec/fixtures/kstat_cpu diff --git a/lib/facts/debian/memory/swap/available.rb b/lib/facts/debian/memory/swap/available.rb index 600a33163..ced67903b 100644 --- a/lib/facts/debian/memory/swap/available.rb +++ b/lib/facts/debian/memory/swap/available.rb @@ -10,7 +10,7 @@ class Available def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_free) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/debian/memory/swap/available_bytes.rb b/lib/facts/debian/memory/swap/available_bytes.rb index 94f7306fe..9867ac550 100644 --- a/lib/facts/debian/memory/swap/available_bytes.rb +++ b/lib/facts/debian/memory/swap/available_bytes.rb @@ -12,7 +12,7 @@ def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_free) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/debian/memory/swap/total.rb b/lib/facts/debian/memory/swap/total.rb index 50025466f..c0947d0e4 100644 --- a/lib/facts/debian/memory/swap/total.rb +++ b/lib/facts/debian/memory/swap/total.rb @@ -10,7 +10,7 @@ class Total def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_total) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/debian/memory/swap/total_bytes.rb b/lib/facts/debian/memory/swap/total_bytes.rb index cc039a870..3f33c1e5a 100644 --- a/lib/facts/debian/memory/swap/total_bytes.rb +++ b/lib/facts/debian/memory/swap/total_bytes.rb @@ -11,7 +11,7 @@ class TotalBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_total) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/debian/memory/swap/used.rb b/lib/facts/debian/memory/swap/used.rb index 30b7c60ac..617704188 100644 --- a/lib/facts/debian/memory/swap/used.rb +++ b/lib/facts/debian/memory/swap/used.rb @@ -9,7 +9,7 @@ class Used def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_used_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) Facter::ResolvedFact.new(FACT_NAME, fact_value) end end diff --git a/lib/facts/debian/memory/system/available.rb b/lib/facts/debian/memory/system/available.rb index 17c1dab01..3785b7a26 100644 --- a/lib/facts/debian/memory/system/available.rb +++ b/lib/facts/debian/memory/system/available.rb @@ -10,7 +10,7 @@ class Available def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:memfree) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end diff --git a/lib/facts/debian/memory/system/available_bytes.rb b/lib/facts/debian/memory/system/available_bytes.rb index 1c47ba082..40e593532 100644 --- a/lib/facts/debian/memory/system/available_bytes.rb +++ b/lib/facts/debian/memory/system/available_bytes.rb @@ -12,7 +12,7 @@ def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:memfree) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/debian/memory/system/total.rb b/lib/facts/debian/memory/system/total.rb index 76118d9f9..127896f64 100644 --- a/lib/facts/debian/memory/system/total.rb +++ b/lib/facts/debian/memory/system/total.rb @@ -10,7 +10,7 @@ class Total def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:total) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/debian/memory/system/total_bytes.rb b/lib/facts/debian/memory/system/total_bytes.rb index be4dc9c9d..5c6e0514b 100644 --- a/lib/facts/debian/memory/system/total_bytes.rb +++ b/lib/facts/debian/memory/system/total_bytes.rb @@ -11,7 +11,7 @@ class TotalBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:total) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/debian/memory/system/used.rb b/lib/facts/debian/memory/system/used.rb index d4d825213..d6f771efe 100644 --- a/lib/facts/debian/memory/system/used.rb +++ b/lib/facts/debian/memory/system/used.rb @@ -9,7 +9,7 @@ class Used def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:used_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) Facter::ResolvedFact.new(FACT_NAME, fact_value) end end diff --git a/lib/facts/el/memory/swap/available.rb b/lib/facts/el/memory/swap/available.rb index 3d61958c1..35ef8a363 100644 --- a/lib/facts/el/memory/swap/available.rb +++ b/lib/facts/el/memory/swap/available.rb @@ -10,7 +10,7 @@ class Available def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_free) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/el/memory/swap/available_bytes.rb b/lib/facts/el/memory/swap/available_bytes.rb index 24b616d00..56b06c7df 100644 --- a/lib/facts/el/memory/swap/available_bytes.rb +++ b/lib/facts/el/memory/swap/available_bytes.rb @@ -11,7 +11,7 @@ class AvailableBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_free) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/el/memory/swap/total.rb b/lib/facts/el/memory/swap/total.rb index 086f432a5..cf8f39918 100644 --- a/lib/facts/el/memory/swap/total.rb +++ b/lib/facts/el/memory/swap/total.rb @@ -10,7 +10,7 @@ class Total def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_total) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/el/memory/swap/total_bytes.rb b/lib/facts/el/memory/swap/total_bytes.rb index c2584aaf5..61badfe82 100644 --- a/lib/facts/el/memory/swap/total_bytes.rb +++ b/lib/facts/el/memory/swap/total_bytes.rb @@ -11,7 +11,7 @@ class TotalBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_total) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/el/memory/swap/used.rb b/lib/facts/el/memory/swap/used.rb index 7eb5d41c7..ee879d5d0 100644 --- a/lib/facts/el/memory/swap/used.rb +++ b/lib/facts/el/memory/swap/used.rb @@ -9,7 +9,7 @@ class Used def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_used_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) Facter::ResolvedFact.new(FACT_NAME, fact_value) end end diff --git a/lib/facts/el/memory/system/available.rb b/lib/facts/el/memory/system/available.rb index 55f434932..225dfa59c 100644 --- a/lib/facts/el/memory/system/available.rb +++ b/lib/facts/el/memory/system/available.rb @@ -10,7 +10,7 @@ class Available def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:memfree) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/el/memory/system/available_bytes.rb b/lib/facts/el/memory/system/available_bytes.rb index 8fb7ff78f..7a964c44d 100644 --- a/lib/facts/el/memory/system/available_bytes.rb +++ b/lib/facts/el/memory/system/available_bytes.rb @@ -11,7 +11,7 @@ class AvailableBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:memfree) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/el/memory/system/total.rb b/lib/facts/el/memory/system/total.rb index d713e5450..05e050958 100644 --- a/lib/facts/el/memory/system/total.rb +++ b/lib/facts/el/memory/system/total.rb @@ -10,7 +10,7 @@ class Total def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:total) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/el/memory/system/total_bytes.rb b/lib/facts/el/memory/system/total_bytes.rb index 7d59a3c63..2270d6177 100644 --- a/lib/facts/el/memory/system/total_bytes.rb +++ b/lib/facts/el/memory/system/total_bytes.rb @@ -11,7 +11,7 @@ class TotalBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:total) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/el/memory/system/used.rb b/lib/facts/el/memory/system/used.rb index a7ff85d14..eec72abdf 100644 --- a/lib/facts/el/memory/system/used.rb +++ b/lib/facts/el/memory/system/used.rb @@ -9,7 +9,7 @@ class Used def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:used_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) Facter::ResolvedFact.new(FACT_NAME, fact_value) end end diff --git a/lib/facts/macosx/memory/swap/available.rb b/lib/facts/macosx/memory/swap/available.rb index de8008b64..8c4c0b390 100644 --- a/lib/facts/macosx/memory/swap/available.rb +++ b/lib/facts/macosx/memory/swap/available.rb @@ -10,7 +10,7 @@ class Available def call_the_resolver fact_value = Facter::Resolvers::Macosx::SwapMemory.resolve(:available_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end diff --git a/lib/facts/macosx/memory/swap/available_bytes.rb b/lib/facts/macosx/memory/swap/available_bytes.rb index d0e472a82..043e9dcd3 100644 --- a/lib/facts/macosx/memory/swap/available_bytes.rb +++ b/lib/facts/macosx/memory/swap/available_bytes.rb @@ -11,7 +11,7 @@ class AvailableBytes def call_the_resolver fact_value = Facter::Resolvers::Macosx::SwapMemory.resolve(:available_bytes) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/macosx/memory/swap/total.rb b/lib/facts/macosx/memory/swap/total.rb index 03c614c87..6240d9a0d 100644 --- a/lib/facts/macosx/memory/swap/total.rb +++ b/lib/facts/macosx/memory/swap/total.rb @@ -10,7 +10,7 @@ class Total def call_the_resolver fact_value = Facter::Resolvers::Macosx::SwapMemory.resolve(:total_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end diff --git a/lib/facts/macosx/memory/swap/total_bytes.rb b/lib/facts/macosx/memory/swap/total_bytes.rb index 039c53240..4b2e97f80 100644 --- a/lib/facts/macosx/memory/swap/total_bytes.rb +++ b/lib/facts/macosx/memory/swap/total_bytes.rb @@ -11,7 +11,7 @@ class TotalBytes def call_the_resolver fact_value = Facter::Resolvers::Macosx::SwapMemory.resolve(:total_bytes) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/macosx/memory/swap/used.rb b/lib/facts/macosx/memory/swap/used.rb index 2e37bd712..c3e3781a7 100644 --- a/lib/facts/macosx/memory/swap/used.rb +++ b/lib/facts/macosx/memory/swap/used.rb @@ -9,7 +9,7 @@ class Used def call_the_resolver fact_value = Facter::Resolvers::Macosx::SwapMemory.resolve(:used_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) Facter::ResolvedFact.new(FACT_NAME, fact_value) end diff --git a/lib/facts/macosx/memory/system/available.rb b/lib/facts/macosx/memory/system/available.rb index 5be00c747..a6d2d98db 100644 --- a/lib/facts/macosx/memory/system/available.rb +++ b/lib/facts/macosx/memory/system/available.rb @@ -10,7 +10,7 @@ class Available def call_the_resolver fact_value = Facter::Resolvers::Macosx::SystemMemory.resolve(:available_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end diff --git a/lib/facts/macosx/memory/system/available_bytes.rb b/lib/facts/macosx/memory/system/available_bytes.rb index c764d43cf..36bfdde1e 100644 --- a/lib/facts/macosx/memory/system/available_bytes.rb +++ b/lib/facts/macosx/memory/system/available_bytes.rb @@ -11,7 +11,7 @@ class AvailableBytes def call_the_resolver fact_value = Facter::Resolvers::Macosx::SystemMemory.resolve(:available_bytes) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/macosx/memory/system/total.rb b/lib/facts/macosx/memory/system/total.rb index c1d96c9f3..c1ca63e06 100644 --- a/lib/facts/macosx/memory/system/total.rb +++ b/lib/facts/macosx/memory/system/total.rb @@ -10,7 +10,7 @@ class Total def call_the_resolver fact_value = Facter::Resolvers::Macosx::SystemMemory.resolve(:total_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end diff --git a/lib/facts/macosx/memory/system/total_bytes.rb b/lib/facts/macosx/memory/system/total_bytes.rb index 24f95acb5..684d191bd 100644 --- a/lib/facts/macosx/memory/system/total_bytes.rb +++ b/lib/facts/macosx/memory/system/total_bytes.rb @@ -11,7 +11,7 @@ class TotalBytes def call_the_resolver fact_value = Facter::Resolvers::Macosx::SystemMemory.resolve(:total_bytes) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/macosx/memory/system/used.rb b/lib/facts/macosx/memory/system/used.rb index cbc254da6..376c3b5eb 100644 --- a/lib/facts/macosx/memory/system/used.rb +++ b/lib/facts/macosx/memory/system/used.rb @@ -9,7 +9,7 @@ class Used def call_the_resolver fact_value = Facter::Resolvers::Macosx::SystemMemory.resolve(:used_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) Facter::ResolvedFact.new(FACT_NAME, fact_value) end diff --git a/lib/facts/macosx/processors/speed.rb b/lib/facts/macosx/processors/speed.rb index 274a4f9d7..16f7900d1 100644 --- a/lib/facts/macosx/processors/speed.rb +++ b/lib/facts/macosx/processors/speed.rb @@ -8,7 +8,8 @@ class Speed def call_the_resolver fact_value = Facter::Resolvers::Macosx::Processors.resolve(:speed) - Facter::ResolvedFact.new(FACT_NAME, fact_value) + speed = Facter::FactsUtils::UnitConverter.hertz_to_human_readable(fact_value) + Facter::ResolvedFact.new(FACT_NAME, speed) end end end diff --git a/lib/facts/sles/memory/swap/available.rb b/lib/facts/sles/memory/swap/available.rb index 0c603f50b..3d3654c5c 100644 --- a/lib/facts/sles/memory/swap/available.rb +++ b/lib/facts/sles/memory/swap/available.rb @@ -10,7 +10,7 @@ class Available def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_free) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/sles/memory/swap/available_bytes.rb b/lib/facts/sles/memory/swap/available_bytes.rb index 72013adac..6ca63b917 100644 --- a/lib/facts/sles/memory/swap/available_bytes.rb +++ b/lib/facts/sles/memory/swap/available_bytes.rb @@ -11,7 +11,7 @@ class AvailableBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_free) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/sles/memory/swap/total.rb b/lib/facts/sles/memory/swap/total.rb index d85f72e71..a14bbcaa6 100644 --- a/lib/facts/sles/memory/swap/total.rb +++ b/lib/facts/sles/memory/swap/total.rb @@ -10,7 +10,7 @@ class Total def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_total) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/sles/memory/swap/total_bytes.rb b/lib/facts/sles/memory/swap/total_bytes.rb index ccbfe28d6..3971c0ffd 100644 --- a/lib/facts/sles/memory/swap/total_bytes.rb +++ b/lib/facts/sles/memory/swap/total_bytes.rb @@ -11,7 +11,7 @@ class TotalBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_total) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/sles/memory/swap/used.rb b/lib/facts/sles/memory/swap/used.rb index 918092fbb..d9ed2753a 100644 --- a/lib/facts/sles/memory/swap/used.rb +++ b/lib/facts/sles/memory/swap/used.rb @@ -9,7 +9,7 @@ class Used def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:swap_used_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) Facter::ResolvedFact.new(FACT_NAME, fact_value) end end diff --git a/lib/facts/sles/memory/system/available.rb b/lib/facts/sles/memory/system/available.rb index 66b4156ce..00539fbcd 100644 --- a/lib/facts/sles/memory/system/available.rb +++ b/lib/facts/sles/memory/system/available.rb @@ -10,7 +10,7 @@ class Available def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:memfree) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/sles/memory/system/available_bytes.rb b/lib/facts/sles/memory/system/available_bytes.rb index a8359669b..a8cb08d9c 100644 --- a/lib/facts/sles/memory/system/available_bytes.rb +++ b/lib/facts/sles/memory/system/available_bytes.rb @@ -11,7 +11,7 @@ class AvailableBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:memfree) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/sles/memory/system/total.rb b/lib/facts/sles/memory/system/total.rb index 2ad8a2028..62f25650a 100644 --- a/lib/facts/sles/memory/system/total.rb +++ b/lib/facts/sles/memory/system/total.rb @@ -10,7 +10,7 @@ class Total def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:total) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end end diff --git a/lib/facts/sles/memory/system/total_bytes.rb b/lib/facts/sles/memory/system/total_bytes.rb index 37d9633a8..de3b6546e 100644 --- a/lib/facts/sles/memory/system/total_bytes.rb +++ b/lib/facts/sles/memory/system/total_bytes.rb @@ -11,7 +11,7 @@ class TotalBytes def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:total) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/sles/memory/system/used.rb b/lib/facts/sles/memory/system/used.rb index 73e5cf0cb..bd2e8794e 100644 --- a/lib/facts/sles/memory/system/used.rb +++ b/lib/facts/sles/memory/system/used.rb @@ -9,7 +9,7 @@ class Used def call_the_resolver fact_value = Facter::Resolvers::Linux::Memory.resolve(:used_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) Facter::ResolvedFact.new(FACT_NAME, fact_value) end end diff --git a/lib/facts/solaris/processors/count.rb b/lib/facts/solaris/processors/count.rb new file mode 100644 index 000000000..a38a99a87 --- /dev/null +++ b/lib/facts/solaris/processors/count.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Processors + class Count + FACT_NAME = 'processors.count' + ALIASES = 'processorcount' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Processors.resolve(:logical_count) + [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] + end + end + end + end +end diff --git a/lib/facts/solaris/processors/isa.rb b/lib/facts/solaris/processors/isa.rb new file mode 100644 index 000000000..f8b5a069b --- /dev/null +++ b/lib/facts/solaris/processors/isa.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Processors + class Isa + FACT_NAME = 'processors.isa' + ALIASES = 'hardwareisa' + + def call_the_resolver + fact_value = Facter::Resolvers::Uname.resolve(:processor) + [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] + end + end + end + end +end diff --git a/lib/facts/solaris/processors/models.rb b/lib/facts/solaris/processors/models.rb new file mode 100644 index 000000000..b87cf733c --- /dev/null +++ b/lib/facts/solaris/processors/models.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Processors + class Models + FACT_NAME = 'processors.models' + ALIASES = 'processor.*' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Processors.resolve(:models) + facts = [Facter::ResolvedFact.new(FACT_NAME, fact_value)] + fact_value.each_with_index do |value, index| + facts.push(Facter::ResolvedFact.new("processor#{index}", value, :legacy)) + end + facts + end + end + end + end +end diff --git a/lib/facts/solaris/processors/physicalcount.rb b/lib/facts/solaris/processors/physicalcount.rb new file mode 100644 index 000000000..ecb1955eb --- /dev/null +++ b/lib/facts/solaris/processors/physicalcount.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Processors + class Physicalcount + FACT_NAME = 'processors.physicalcount' + ALIASES = 'physicalprocessorcount' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Processors.resolve(:physical_count) + [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] + end + end + end + end +end diff --git a/lib/facts/solaris/processors/speed.rb b/lib/facts/solaris/processors/speed.rb new file mode 100644 index 000000000..5d1f7a2bc --- /dev/null +++ b/lib/facts/solaris/processors/speed.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Facts + module Solaris + module Processors + class Speed + FACT_NAME = 'processors.speed' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Processors.resolve(:speed) + speed = Facter::FactsUtils::UnitConverter.hertz_to_human_readable(fact_value) + Facter::ResolvedFact.new(FACT_NAME, speed) + end + end + end + end +end diff --git a/lib/facts/windows/memory/system/available.rb b/lib/facts/windows/memory/system/available.rb index e8d1c7a1a..d277f29f0 100644 --- a/lib/facts/windows/memory/system/available.rb +++ b/lib/facts/windows/memory/system/available.rb @@ -10,7 +10,7 @@ class Available def call_the_resolver fact_value = Facter::Resolvers::Memory.resolve(:available_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end diff --git a/lib/facts/windows/memory/system/available_bytes.rb b/lib/facts/windows/memory/system/available_bytes.rb index 1bf7d7af4..54e598cfe 100644 --- a/lib/facts/windows/memory/system/available_bytes.rb +++ b/lib/facts/windows/memory/system/available_bytes.rb @@ -12,7 +12,7 @@ def call_the_resolver fact_value = Facter::Resolvers::Memory.resolve(:available_bytes) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/windows/memory/system/total.rb b/lib/facts/windows/memory/system/total.rb index 083b41a3a..df2c3d99f 100644 --- a/lib/facts/windows/memory/system/total.rb +++ b/lib/facts/windows/memory/system/total.rb @@ -10,7 +10,7 @@ class Total def call_the_resolver fact_value = Facter::Resolvers::Memory.resolve(:total_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) [Facter::ResolvedFact.new(FACT_NAME, fact_value), Facter::ResolvedFact.new(ALIASES, fact_value, :legacy)] end diff --git a/lib/facts/windows/memory/system/total_bytes.rb b/lib/facts/windows/memory/system/total_bytes.rb index 27892ab92..44522bf11 100644 --- a/lib/facts/windows/memory/system/total_bytes.rb +++ b/lib/facts/windows/memory/system/total_bytes.rb @@ -12,7 +12,7 @@ def call_the_resolver fact_value = Facter::Resolvers::Memory.resolve(:total_bytes) [Facter::ResolvedFact.new(FACT_NAME, fact_value), - Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::BytesConverter.to_mb(fact_value), :legacy)] + Facter::ResolvedFact.new(ALIASES, Facter::FactsUtils::UnitConverter.bytes_to_mb(fact_value), :legacy)] end end end diff --git a/lib/facts/windows/memory/system/used.rb b/lib/facts/windows/memory/system/used.rb index c7264c0e5..c6545f07a 100644 --- a/lib/facts/windows/memory/system/used.rb +++ b/lib/facts/windows/memory/system/used.rb @@ -9,7 +9,7 @@ class Used def call_the_resolver fact_value = Facter::Resolvers::Memory.resolve(:used_bytes) - fact_value = Facter::BytesToHumanReadable.convert(fact_value) + fact_value = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(fact_value) Facter::ResolvedFact.new(FACT_NAME, fact_value) end diff --git a/lib/facts_utils/bytes_converter.rb b/lib/facts_utils/bytes_converter.rb deleted file mode 100644 index 3bd9e1b9e..000000000 --- a/lib/facts_utils/bytes_converter.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module Facter - module FactsUtils - class BytesConverter - class << self - def to_mb(value_in_bytes) - (value_in_bytes / (1024.0 * 1024.0)).round(2) - rescue NoMethodError - nil - end - end - end - end -end diff --git a/lib/facts_utils/bytes_to_human_readable.rb b/lib/facts_utils/bytes_to_human_readable.rb deleted file mode 100644 index 290a95ffc..000000000 --- a/lib/facts_utils/bytes_to_human_readable.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -module Facter - class BytesToHumanReadable - class << self - def convert(bytes) - return unless bytes - return bytes.to_s + ' bytes' if bytes < 1024 - - units = %w[K M G T P E] - result = determine_exponent(bytes) - return bytes.to_s + ' bytes' if result[:exp] > units.size - - converted_number = pad_number(result[:converted_number]) - converted_number + " #{units[result[:exp] - 1]}iB" - end - - private - - def pad_number(number) - number = number.to_s - number << '0' if number.split('.').last.length == 1 - number - end - - def determine_exponent(bytes) - exp = (Math.log2(bytes) / 10.0).floor - converted_number = (100.0 * (bytes / 1024.0**exp)).round / 100.0 - - if (converted_number - 1024.0).abs < Float::EPSILON - exp += 1 - converted_number = 1.00 - end - { exp: exp, converted_number: converted_number } - end - end - end -end diff --git a/lib/facts_utils/unit_converter.rb b/lib/facts_utils/unit_converter.rb new file mode 100644 index 000000000..9536cb084 --- /dev/null +++ b/lib/facts_utils/unit_converter.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module Facter + module FactsUtils + class UnitConverter + class << self + def bytes_to_mb(value_in_bytes) + return unless value_in_bytes + + value_in_bytes = value_in_bytes.to_i + + (value_in_bytes / (1024.0 * 1024.0)).round(2) + end + + def hertz_to_human_readable(speed) + speed = speed.to_i + return if !speed || speed.zero? + + prefix = { 3 => 'k', 6 => 'M', 9 => 'G', 12 => 'T' } + power = Math.log10(speed).floor + validated_speed = power.zero? ? speed.to_f : speed.fdiv(10**power) + format('%.2f', displayed_speed: validated_speed).to_s + ' ' + prefix[power] + 'Hz' + end + + def bytes_to_human_readable(bytes) + return unless bytes + return bytes.to_s + ' bytes' if bytes < 1024 + + number, multiple = determine_exponent(bytes) + + "#{pad_number(number)} #{multiple}" + end + + private + + def pad_number(number) + number = number.to_s + number << '0' if number.split('.').last.length == 1 + number + end + + def determine_exponent(bytes) + prefix = %w[KiB MiB GiB TiB PiB EiB] + exp = (Math.log2(bytes) / 10.0).floor + converted_number = (100.0 * (bytes / 1024.0**exp)).round / 100.0 + + if (converted_number - 1024.0).abs < Float::EPSILON + exp += 1 + converted_number = 1.00 + end + multiple = prefix[exp - 1] || 'bytes' + + converted_number = bytes if multiple == 'bytes' + [converted_number, multiple] + end + end + end + end +end diff --git a/lib/resolvers/aix/mountpoints.rb b/lib/resolvers/aix/mountpoints.rb index 1c6f31492..33bb338bd 100644 --- a/lib/resolvers/aix/mountpoints.rb +++ b/lib/resolvers/aix/mountpoints.rb @@ -57,9 +57,9 @@ def compute_sizes(info) available_bytes: available_bytes, used_bytes: used_bytes, size_bytes: size_bytes, - available: BytesToHumanReadable.convert(available_bytes), - used: BytesToHumanReadable.convert(used_bytes), - size: BytesToHumanReadable.convert(size_bytes) + available: FactsUtils::UnitConverter.bytes_to_human_readable(available_bytes), + used: FactsUtils::UnitConverter.bytes_to_human_readable(used_bytes), + size: FactsUtils::UnitConverter.bytes_to_human_readable(size_bytes) ) end end diff --git a/lib/resolvers/aix/partitions.rb b/lib/resolvers/aix/partitions.rb index 3b2d48390..791cf3e41 100644 --- a/lib/resolvers/aix/partitions.rb +++ b/lib/resolvers/aix/partitions.rb @@ -52,7 +52,7 @@ def populate_from_lslv(name) part_info = { filesystem: info_hash['TYPE'], size_bytes: size_bytes, - size: Facter::BytesToHumanReadable.convert(size_bytes) + size: Facter::FactsUtils::UnitConverter.bytes_to_human_readable(size_bytes) } mount = info_hash['MOUNTPOINT'] label = info_hash['LABEL'] diff --git a/lib/resolvers/disk_resolver.rb b/lib/resolvers/disk_resolver.rb index 7efcd00f8..c40da6d6a 100644 --- a/lib/resolvers/disk_resolver.rb +++ b/lib/resolvers/disk_resolver.rb @@ -45,7 +45,7 @@ def build_disks_hash def construct_size(facts, value) value = value.to_i * 512 facts[:size_bytes] = value - facts[:size] = Facter::BytesToHumanReadable.convert(value) + facts[:size] = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(value) end end end diff --git a/lib/resolvers/macosx/mountpoints_resolver.rb b/lib/resolvers/macosx/mountpoints_resolver.rb index eefd761a9..2af41c60b 100644 --- a/lib/resolvers/macosx/mountpoints_resolver.rb +++ b/lib/resolvers/macosx/mountpoints_resolver.rb @@ -50,9 +50,9 @@ def read_stats(path) used_bytes: used_bytes, available_bytes: available_bytes, capacity: FilesystemHelper.compute_capacity(used_bytes, size_bytes), - size: Facter::BytesToHumanReadable.convert(size_bytes), - available: Facter::BytesToHumanReadable.convert(available_bytes), - used: Facter::BytesToHumanReadable.convert(used_bytes) + size: Facter::FactsUtils::UnitConverter.bytes_to_human_readable(size_bytes), + available: Facter::FactsUtils::UnitConverter.bytes_to_human_readable(available_bytes), + used: Facter::FactsUtils::UnitConverter.bytes_to_human_readable(used_bytes) } end end diff --git a/lib/resolvers/macosx/processor_resolver.rb b/lib/resolvers/macosx/processor_resolver.rb index 98aa0c26f..e77471976 100644 --- a/lib/resolvers/macosx/processor_resolver.rb +++ b/lib/resolvers/macosx/processor_resolver.rb @@ -50,16 +50,7 @@ def build_models(model) end def build_speed(value) - @fact_list[:speed] = convert_hz(value.split(': ')[1].to_i) - end - - def convert_hz(speed) - return nil if speed.zero? - - prefix = { 3 => 'k', 6 => 'M', 9 => 'G', 12 => 'T' } - power = Math.log10(speed).floor - validated_speed = power.zero? ? speed.to_f : speed.fdiv(10**power) - format('%.2f', displayed_speed: validated_speed).to_s + ' ' + prefix[power] + 'Hz' + @fact_list[:speed] = value.split(': ')[1].to_i end end end diff --git a/lib/resolvers/mountpoints_resolver.rb b/lib/resolvers/mountpoints_resolver.rb index a89547930..44704a9de 100644 --- a/lib/resolvers/mountpoints_resolver.rb +++ b/lib/resolvers/mountpoints_resolver.rb @@ -46,9 +46,9 @@ def read_mounts # rubocop:disable Metrics/AbcSize total_bytes = used_bytes + available_bytes capacity = FilesystemHelper.compute_capacity(used_bytes, total_bytes) - size = Facter::BytesToHumanReadable.convert(size_bytes) - available = Facter::BytesToHumanReadable.convert(available_bytes) - used = Facter::BytesToHumanReadable.convert(used_bytes) + size = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(size_bytes) + available = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(available_bytes) + used = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(used_bytes) mounts << Hash[FilesystemHelper::MOUNT_KEYS.zip(FilesystemHelper::MOUNT_KEYS .map { |v| binding.local_variable_get(v) })] diff --git a/lib/resolvers/partitions.rb b/lib/resolvers/partitions.rb index 2df317537..735a91b99 100644 --- a/lib/resolvers/partitions.rb +++ b/lib/resolvers/partitions.rb @@ -64,7 +64,8 @@ def populate_partitions(partition_name, block_path, backing_file = nil) size_bytes = Util::FileHelper.safe_read("#{block_path}/size", '0') .chomp.to_i * BLOCK_SIZE info_hash = { size_bytes: size_bytes, - size: Facter::BytesToHumanReadable.convert(size_bytes), backing_file: backing_file } + size: Facter::FactsUtils::UnitConverter.bytes_to_human_readable(size_bytes), + backing_file: backing_file } info_hash.merge!(populate_from_blkid(partition_name)) @fact_list[:partitions][partition_name] = info_hash.reject { |_key, value| value.nil? } end diff --git a/lib/resolvers/solaris/processors.rb b/lib/resolvers/solaris/processors.rb new file mode 100644 index 000000000..152483fdd --- /dev/null +++ b/lib/resolvers/solaris/processors.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Facter + module Resolvers + module Solaris + class Processors < BaseResolver + @log = Facter::Log.new(self) + @semaphore = Mutex.new + @fact_list ||= {} + class << self + private + + def post_resolve(fact_name) + @fact_list.fetch(fact_name) { collect_kstat_info(fact_name) } + end + + def collect_kstat_info(fact_name) + return unless File.executable?('/usr/bin/kstat') + + kstat_output, stderr, status = Open3.capture3('/usr/bin/kstat -m cpu_info') + unless status.to_i.zero? + @log.debug("Command /usr/bin/kstat failed with error message: #{stderr}") + return + end + + parse_output(kstat_output.chomp) + @fact_list[fact_name] + end + + def parse_output(output) + @fact_list[:logical_count] = output.scan(/module/).size + @fact_list[:physical_count] = output.scan(/chip_id .*/).uniq.size + @fact_list[:speed] = output.scan(/current_clock_Hz .*/).first.gsub(/[a-zA-z\s]+/, '').to_i + @fact_list[:models] = output.scan(/brand .*/).map { |elem| elem.gsub(/brand(\s+)/, '') } + end + end + end + end + end +end diff --git a/spec/facter/facts/debian/memory/swap/available_spec.rb b/spec/facter/facts/debian/memory/swap/available_spec.rb index 9a4dc44b5..95acfedfa 100644 --- a/spec/facter/facts/debian/memory/swap/available_spec.rb +++ b/spec/facter/facts/debian/memory/swap/available_spec.rb @@ -5,12 +5,11 @@ subject(:fact) { Facts::Debian::Memory::Swap::Available.new } let(:resolver_value) { 1024 } - let(:value) { '1.0 Kib' } + let(:value) { '1.00 KiB' } before do allow(Facter::Resolvers::Linux::Memory).to \ receive(:resolve).with(:swap_free).and_return(resolver_value) - allow(Facter::BytesToHumanReadable).to receive(:convert).with(resolver_value).and_return(value) end it 'calls Facter::Resolvers::Linux::Memory' do diff --git a/spec/facter/facts/debian/memory/swap/total_spec.rb b/spec/facter/facts/debian/memory/swap/total_spec.rb index de8664573..301900a5f 100644 --- a/spec/facter/facts/debian/memory/swap/total_spec.rb +++ b/spec/facter/facts/debian/memory/swap/total_spec.rb @@ -5,12 +5,11 @@ subject(:fact) { Facts::Debian::Memory::Swap::Total.new } let(:resolver_value) { 1024 } - let(:value) { '1.0 Kib' } + let(:value) { '1.00 KiB' } before do allow(Facter::Resolvers::Linux::Memory).to \ receive(:resolve).with(:swap_total).and_return(resolver_value) - allow(Facter::BytesToHumanReadable).to receive(:convert).with(resolver_value).and_return(value) end it 'calls Facter::Resolvers::Linux::Memory' do diff --git a/spec/facter/facts/debian/memory/swap/used_spec.rb b/spec/facter/facts/debian/memory/swap/used_spec.rb index 63f280983..7ae33427a 100644 --- a/spec/facter/facts/debian/memory/swap/used_spec.rb +++ b/spec/facter/facts/debian/memory/swap/used_spec.rb @@ -5,12 +5,11 @@ subject(:fact) { Facts::Debian::Memory::Swap::Used.new } let(:resolver_value) { 1024 } - let(:value) { '1.0 Kib' } + let(:value) { '1.00 KiB' } before do allow(Facter::Resolvers::Linux::Memory).to \ receive(:resolve).with(:swap_used_bytes).and_return(resolver_value) - allow(Facter::BytesToHumanReadable).to receive(:convert).with(resolver_value).and_return(value) end it 'calls Facter::Resolvers::Linux::Memory' do diff --git a/spec/facter/facts/debian/memory/system/available_spec.rb b/spec/facter/facts/debian/memory/system/available_spec.rb index f6f8f6b64..85a5f6dd1 100644 --- a/spec/facter/facts/debian/memory/system/available_spec.rb +++ b/spec/facter/facts/debian/memory/system/available_spec.rb @@ -5,12 +5,11 @@ subject(:fact) { Facts::Debian::Memory::System::Available.new } let(:resolver_value) { 1024 } - let(:value) { '1.0 Kib' } + let(:value) { '1.00 KiB' } before do allow(Facter::Resolvers::Linux::Memory).to \ receive(:resolve).with(:memfree).and_return(resolver_value) - allow(Facter::BytesToHumanReadable).to receive(:convert).with(resolver_value).and_return(value) end it 'calls Facter::Resolvers::Linux::Memory' do diff --git a/spec/facter/facts/debian/memory/system/total_spec.rb b/spec/facter/facts/debian/memory/system/total_spec.rb index 56b93524f..7a8808e41 100644 --- a/spec/facter/facts/debian/memory/system/total_spec.rb +++ b/spec/facter/facts/debian/memory/system/total_spec.rb @@ -5,12 +5,11 @@ subject(:fact) { Facts::Debian::Memory::System::Total.new } let(:resolver_value) { 1024 } - let(:value) { '1.0 Kib' } + let(:value) { '1.00 KiB' } before do allow(Facter::Resolvers::Linux::Memory).to \ receive(:resolve).with(:total).and_return(resolver_value) - allow(Facter::BytesToHumanReadable).to receive(:convert).with(resolver_value).and_return(value) end it 'calls Facter::Resolvers::Linux::Memory' do diff --git a/spec/facter/facts/debian/memory/system/used_spec.rb b/spec/facter/facts/debian/memory/system/used_spec.rb index bb0bd37ec..081812e1e 100644 --- a/spec/facter/facts/debian/memory/system/used_spec.rb +++ b/spec/facter/facts/debian/memory/system/used_spec.rb @@ -5,12 +5,11 @@ subject(:fact) { Facts::Debian::Memory::System::Used.new } let(:resolver_value) { 1024 } - let(:value) { '1.0 Kib' } + let(:value) { '1.00 KiB' } before do allow(Facter::Resolvers::Linux::Memory).to \ receive(:resolve).with(:used_bytes).and_return(resolver_value) - allow(Facter::BytesToHumanReadable).to receive(:convert).with(resolver_value).and_return(value) end it 'calls Facter::Resolvers::Linux::Memory' do diff --git a/spec/facter/facts/el/memory/system/used_spec.rb b/spec/facter/facts/el/memory/system/used_spec.rb index 4068ed541..58129c389 100644 --- a/spec/facter/facts/el/memory/system/used_spec.rb +++ b/spec/facter/facts/el/memory/system/used_spec.rb @@ -5,12 +5,11 @@ subject(:fact) { Facts::El::Memory::System::Used.new } let(:resolver_value) { 1024 } - let(:value) { '1.0 Kib' } + let(:value) { '1.00 KiB' } before do allow(Facter::Resolvers::Linux::Memory).to \ receive(:resolve).with(:used_bytes).and_return(resolver_value) - allow(Facter::BytesToHumanReadable).to receive(:convert).with(resolver_value).and_return(value) end it 'calls Facter::Resolvers::Linux::Memory' do diff --git a/spec/facter/facts/macosx/processors/speed_spec.rb b/spec/facter/facts/macosx/processors/speed_spec.rb index c7db7e28e..bed8b3937 100644 --- a/spec/facter/facts/macosx/processors/speed_spec.rb +++ b/spec/facter/facts/macosx/processors/speed_spec.rb @@ -5,6 +5,7 @@ subject(:fact) { Facts::Macosx::Processors::Speed.new } let(:speed) { 1_800_000_000 } + let(:converted_speed) { '1.80 GHz' } before do allow(Facter::Resolvers::Macosx::Processors).to \ @@ -18,7 +19,7 @@ it 'returns a resolved fact' do expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ - have_attributes(name: 'processors.speed', value: speed) + have_attributes(name: 'processors.speed', value: converted_speed) end end end diff --git a/spec/facter/facts/sles/memory/system/used_spec.rb b/spec/facter/facts/sles/memory/system/used_spec.rb index 5f43b7ed2..5f2786f0e 100644 --- a/spec/facter/facts/sles/memory/system/used_spec.rb +++ b/spec/facter/facts/sles/memory/system/used_spec.rb @@ -5,12 +5,11 @@ subject(:fact) { Facts::Sles::Memory::System::Used.new } let(:resolver_value) { 1024 } - let(:value) { '1.0 Kib' } + let(:value) { '1.00 KiB' } before do allow(Facter::Resolvers::Linux::Memory).to \ receive(:resolve).with(:used_bytes).and_return(resolver_value) - allow(Facter::BytesToHumanReadable).to receive(:convert).with(resolver_value).and_return(value) end it 'calls Facter::Resolvers::Linux::Memory' do diff --git a/spec/facter/facts/solaris/processors/count_spec.rb b/spec/facter/facts/solaris/processors/count_spec.rb new file mode 100644 index 000000000..44ccdbddd --- /dev/null +++ b/spec/facter/facts/solaris/processors/count_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Processors::Count do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Processors::Count.new } + + let(:processors) { '4' } + + before do + allow(Facter::Resolvers::Solaris::Processors).to \ + receive(:resolve).with(:logical_count).and_return(processors) + end + + it 'calls Facter::Resolvers::Macosx::Processors' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Processors).to have_received(:resolve).with(:logical_count) + end + + it 'returns a resolved fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'processors.count', value: processors), + an_object_having_attributes(name: 'processorcount', value: processors, type: :legacy)) + end + end +end diff --git a/spec/facter/facts/solaris/processors/isa_spec.rb b/spec/facter/facts/solaris/processors/isa_spec.rb new file mode 100644 index 000000000..a098ac04c --- /dev/null +++ b/spec/facter/facts/solaris/processors/isa_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Processors::Isa do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Processors::Isa.new } + + let(:isa) { 'i386' } + + before do + allow(Facter::Resolvers::Uname).to \ + receive(:resolve).with(:processor).and_return(isa) + end + + it 'calls Facter::Resolvers::Uname' do + fact.call_the_resolver + expect(Facter::Resolvers::Uname).to have_received(:resolve).with(:processor) + end + + it 'returns a resolved fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'processors.isa', value: isa), + an_object_having_attributes(name: 'hardwareisa', value: isa, type: :legacy)) + end + end +end diff --git a/spec/facter/facts/solaris/processors/models_spec.rb b/spec/facter/facts/solaris/processors/models_spec.rb new file mode 100644 index 000000000..37b58d6e7 --- /dev/null +++ b/spec/facter/facts/solaris/processors/models_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Processors::Models do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Processors::Models.new } + + let(:value) { 'Intel(R) Core(TM) i7-4980HQ CPU @ 2.80GHz' } + let(:models) { [value, value] } + + before do + allow(Facter::Resolvers::Solaris::Processors).to \ + receive(:resolve).with(:models).and_return(models) + end + + it 'calls Facter::Resolvers::Macosx::Processors' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Processors).to have_received(:resolve).with(:models) + end + + it 'returns a resolved fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'processors.models', value: models), + an_object_having_attributes(name: 'processor0', value: value, type: :legacy), + an_object_having_attributes(name: 'processor1', value: value, type: :legacy)) + end + end +end diff --git a/spec/facter/facts/solaris/processors/physicalcount_spec.rb b/spec/facter/facts/solaris/processors/physicalcount_spec.rb new file mode 100644 index 000000000..d1305ec3b --- /dev/null +++ b/spec/facter/facts/solaris/processors/physicalcount_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Processors::Physicalcount do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Processors::Physicalcount.new } + + let(:physicalcount) { '5' } + + before do + allow(Facter::Resolvers::Solaris::Processors).to \ + receive(:resolve).with(:physical_count).and_return(physicalcount) + end + + it 'calls Facter::Resolvers::Macosx::Processors' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Processors).to have_received(:resolve).with(:physical_count) + end + + it 'returns a resolved fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ + contain_exactly(an_object_having_attributes(name: 'processors.physicalcount', value: physicalcount), + an_object_having_attributes(name: 'physicalprocessorcount', value: physicalcount, + type: :legacy)) + end + end +end diff --git a/spec/facter/facts/solaris/processors/speed_spec.rb b/spec/facter/facts/solaris/processors/speed_spec.rb new file mode 100644 index 000000000..366b13118 --- /dev/null +++ b/spec/facter/facts/solaris/processors/speed_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Processors::Speed do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Processors::Speed.new } + + let(:speed) { 1_800_000_000 } + let(:converted_speed) { '1.80 GHz' } + + before do + allow(Facter::Resolvers::Solaris::Processors).to \ + receive(:resolve).with(:speed).and_return(speed) + end + + it 'calls Facter::Resolvers::Macosx::Processors' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Processors).to have_received(:resolve).with(:speed) + end + + it 'returns a resolved fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'processors.speed', value: converted_speed) + end + end +end diff --git a/spec/facter/facts_utils/bytes_converter_spec.rb b/spec/facter/facts_utils/bytes_converter_spec.rb deleted file mode 100644 index 7b69a09a3..000000000 --- a/spec/facter/facts_utils/bytes_converter_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -describe Facter::FactsUtils::BytesConverter do - describe '#to_mb' do - it 'converts bytes to mega bytes' do - expect(Facter::FactsUtils::BytesConverter.to_mb(256_586_343)).to eq(244.7) - end - - it 'returns nil if value is nil' do - expect(Facter::FactsUtils::BytesConverter.to_mb(nil)).to be(nil) - end - - it 'returns nil if value is string' do - expect(Facter::FactsUtils::BytesConverter.to_mb('2343455')).to be(nil) - end - - it 'returns 0 if value is 0' do - expect(Facter::FactsUtils::BytesConverter.to_mb(0)).to eq(0.0) - end - end -end diff --git a/spec/facter/facts_utils/bytes_to_human_readable_spec.rb b/spec/facter/facts_utils/bytes_to_human_readable_spec.rb deleted file mode 100644 index 81da864a3..000000000 --- a/spec/facter/facts_utils/bytes_to_human_readable_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -describe Facter::BytesToHumanReadable do - describe '.convert' do - it 'returns nil if bytes variable is nil' do - expect(Facter::BytesToHumanReadable.convert(nil)).to be(nil) - end - - it 'returns next unit if result is 1024 after conversion' do - expect(Facter::BytesToHumanReadable.convert(1_048_575.7)).to eql('1.00 MiB') - end - - it 'returns bytes if bytes variable is less than 1024' do - expect(Facter::BytesToHumanReadable.convert(1023)).to eql('1023 bytes') - end - - it 'returns 1 Kib if bytes variable equals 1024' do - expect(Facter::BytesToHumanReadable.convert(1024)).to eql('1.00 KiB') - end - - it 'returns bytes if number exceeds etta bytes' do - expect(Facter::BytesToHumanReadable.convert(3_296_472_651_763_232_323_235)).to eql('3296472651763232323235 bytes') - end - end - - describe '.pad_number' do - it 'appends a 0 when conversion has one decimal digit' do - expect(Facter::BytesToHumanReadable.send(:pad_number, 10.0)).to eql('10.00') - end - - it 'leaves the value unmodified if it has two decimals' do - expect(Facter::BytesToHumanReadable.send(:pad_number, 10.23)).to eql('10.23') - end - end -end diff --git a/spec/facter/facts_utils/unit_converter_spec.rb b/spec/facter/facts_utils/unit_converter_spec.rb new file mode 100644 index 000000000..7cde86344 --- /dev/null +++ b/spec/facter/facts_utils/unit_converter_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +describe Facter::FactsUtils::UnitConverter do + subject(:converter) { Facter::FactsUtils::UnitConverter } + + describe '#bytes_to_mb' do + it 'converts bytes to mega bytes' do + expect(converter.bytes_to_mb(256_586_343)).to eq(244.7) + end + + it 'returns nil if value is nil' do + expect(converter.bytes_to_mb(nil)).to be(nil) + end + + it 'converts bytes if value is string' do + expect(converter.bytes_to_mb('2343455')).to eq(2.23) + end + + it 'returns 0 if value is 0' do + expect(converter.bytes_to_mb(0)).to eq(0.0) + end + end + + describe '#hertz_to_human_readable' do + it 'returns nil if value is 0' do + expect(converter.hertz_to_human_readable(0)).to be_nil + end + + it 'returns nil if value is string' do + expect(converter.hertz_to_human_readable('test')).to be_nil + end + + it 'converts to GHz' do + expect(converter.hertz_to_human_readable(2_300_000_000)).to eql('2.30 GHz') + end + + it 'converts to Hz even if argument is string' do + expect(converter.hertz_to_human_readable('2400')).to eql('2.40 kHz') + end + end + + describe '#bytes_to_human_readable' do + it 'returns nil if bytes variable is nil' do + expect(converter.bytes_to_human_readable(nil)).to be(nil) + end + + it 'returns next unit if result is 1024 after conversion' do + expect(converter.bytes_to_human_readable(1_048_575.7)).to eql('1.00 MiB') + end + + it 'returns bytes if bytes variable is less than 1024' do + expect(converter.bytes_to_human_readable(1023)).to eql('1023 bytes') + end + + it 'returns 1 Kib if bytes variable equals 1024' do + expect(converter.bytes_to_human_readable(1024)).to eql('1.00 KiB') + end + + it 'returns bytes if number exceeds etta bytes' do + expect(converter.bytes_to_human_readable(3_296_472_651_763_232_323_235)).to eql('3296472651763232323235 bytes') + end + end + + describe '#pad_number' do + it 'appends a 0 when conversion has one decimal digit' do + expect(converter.send(:pad_number, 10.0)).to eql('10.00') + end + + it 'leaves the value unmodified if it has two decimals' do + expect(converter.send(:pad_number, 10.23)).to eql('10.23') + end + end +end diff --git a/spec/facter/resolvers/macosx/processors_resolver_spec.rb b/spec/facter/resolvers/macosx/processors_resolver_spec.rb index 48cbc0c7a..09c7f42fb 100644 --- a/spec/facter/resolvers/macosx/processors_resolver_spec.rb +++ b/spec/facter/resolvers/macosx/processors_resolver_spec.rb @@ -7,7 +7,7 @@ 'Intel(R) Xeon(R) CPU E5-2697 v4 @ 2.30GHz', 'Intel(R) Xeon(R) CPU E5-2697 v4 @ 2.30GHz'] end let(:physical_processors) { 1 } - let(:speed_expected) { '2.30 GHz' } + let(:speed_expected) { 2_300_000_000 } output = ['hw.logicalcpu_max: 4', 'hw.physicalcpu_max: 1', diff --git a/spec/facter/resolvers/solaris/processors_spec.rb b/spec/facter/resolvers/solaris/processors_spec.rb new file mode 100644 index 000000000..98997fe7d --- /dev/null +++ b/spec/facter/resolvers/solaris/processors_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +describe Facter::Resolvers::Solaris::Processors do + subject(:resolver) { Facter::Resolvers::Solaris::Processors } + + let(:log_spy) { instance_spy(Facter::Log) } + + before do + allow(File).to receive(:executable?).with('/usr/bin/kstat').and_return(status) + allow(Open3) + .to receive(:capture3) + .with('/usr/bin/kstat -m cpu_info') + .and_return(output) + + resolver.instance_variable_set(:@log, log_spy) + end + + after do + resolver.invalidate_cache + end + + context 'when kstat is present and can retrieve information' do + let(:logicalcount) { 2 } + let(:models) do + ['Intel(r) Xeon(r) Gold 6138 CPU @ 2.00GHz', 'Intel(r) Xeon(r) Gold 6138 CPU @ 2.00GHz'] + end + let(:physical_processors) { 2 } + let(:speed_expected) { 1_995_246_617 } + let(:output) { [load_fixture('kstat_cpu').read, '', 0] } + let(:status) { true } + + it 'returns number of processors' do + expect(resolver.resolve(:logical_count)).to eq(logicalcount) + end + + it 'returns number of physical processors' do + expect(resolver.resolve(:physical_count)).to eq(physical_processors) + end + + it 'returns list of models' do + expect(resolver.resolve(:models)).to eq(models) + end + + it 'returns speed of processors' do + expect(resolver.resolve(:speed)).to eq(speed_expected) + end + end + + context 'when kstat is not present' do + let(:output) {} + let(:status) { false } + + it 'returns nil' do + expect(resolver.resolve(:models)).to be_nil + end + end + + context 'when kstat is present but fails' do + let(:output) { ['', 'kstat failed!', 1] } + let(:status) { true } + + it 'returns nil' do + expect(resolver.resolve(:models)).to be_nil + end + + it 'logs error message' do + resolver.resolve(:models) + + expect(log_spy).to have_received(:debug).with('Command /usr/bin/kstat failed '\ + 'with error message: kstat failed!') + end + end +end diff --git a/spec/fixtures/kstat_cpu b/spec/fixtures/kstat_cpu new file mode 100644 index 000000000..44166d297 --- /dev/null +++ b/spec/fixtures/kstat_cpu @@ -0,0 +1,77 @@ +module: cpu_info instance: 0 +name: cpu_info0 class: misc + brand Intel(r) Xeon(r) Gold 6138 CPU @ 2.00GHz + cache_id 0 + chip_id 0 + clock_MHz 1995 + clog_id 0 + core_id 0 + cpu_type i386 + crtime 37.957590729 + cstates_count 1014040:1014042 + cstates_nsec 7731043379931:134295045809 + current_clock_Hz 1995246617 + current_cstate 1 + current_pstate 0 + family 6 + fpu_type i387 compatible + implementation x86 (chipid 0x0 GenuineIntel 50654 family 6 model 85 step 4 clock 2000 MHz) + lgroup_id 0 + max_ncpu_per_chip 1 + max_ncpu_per_core 1 + max_pwrcap 0 + model 85 + ncore_per_chip 1 + ncpu_per_chip 1 + pg_id 18446744073709551615 + pkg_core_id 0 + pstates_count null + pstates_nsec null + snaptime 7827.384789463 + socket_type Unknown + state on-line + state_begin 1586929325 + stepping 4 + supported_frequencies_Hz 1995246617 + supported_max_cstates 1 + supported_max_pstates 0 + vendor_id GenuineIntel + +module: cpu_info instance: 1 +name: cpu_info1 class: misc + brand Intel(r) Xeon(r) Gold 6138 CPU @ 2.00GHz + cache_id 2 + chip_id 2 + clock_MHz 1995 + clog_id 0 + core_id 2 + cpu_type i386 + crtime 38.360143483 + cstates_count 652423:652424 + cstates_nsec 7734973017129:130932431358 + current_clock_Hz 1995246617 + current_cstate 0 + current_pstate 0 + family 6 + fpu_type i387 compatible + implementation x86 (chipid 0x2 GenuineIntel 50654 family 6 model 85 step 4 clock 2000 MHz) + lgroup_id 0 + max_ncpu_per_chip 1 + max_ncpu_per_core 1 + max_pwrcap 0 + model 85 + ncore_per_chip 1 + ncpu_per_chip 1 + pg_id 18446744073709551615 + pkg_core_id 0 + pstates_count null + pstates_nsec null + snaptime 7827.385273786 + socket_type Unknown + state on-line + state_begin 1586929326 + stepping 4 + supported_frequencies_Hz 1995246617 + supported_max_cstates 1 + supported_max_pstates 0 + vendor_id GenuineIntel From 936fa513853c67ce7c711741773d9c690309855e Mon Sep 17 00:00:00 2001 From: Florin Dragos Date: Fri, 24 Apr 2020 14:52:43 +0300 Subject: [PATCH 09/13] (Fact 2486) Add facts cache (#430) * (FACT-2485) Implement '--list-cache-groups' option * (FACT-2486) Add facts cache --- .rubocop.yml | 1 + .rubocop_todo.yml | 7 +- block_groups.conf | 14 -- fact_groups.conf | 169 ++++++++++++++++++ lib/custom_facts/util/config.rb | 13 ++ lib/facter.rb | 2 +- lib/framework/cli/cli.rb | 8 +- lib/framework/config/block_list.rb | 32 ---- lib/framework/config/fact_groups.rb | 55 ++++++ lib/framework/core/cache_manager.rb | 131 ++++++++++++++ lib/framework/core/fact_manager.rb | 6 + lib/framework/core/file_loader.rb | 2 +- .../core/options/config_file_options.rb | 2 +- lib/framework/core/options/option_store.rb | 2 + lib/models/resolved_fact.rb | 8 +- spec/facter/cache_manager_spec.rb | 138 ++++++++++++++ spec/facter/facter_spec.rb | 4 +- spec/facter/model/resolved_fact_spec.rb | 8 - spec/framework/config/block_list_spec.rb | 63 ------- spec/framework/config/fact_groups_spec.rb | 125 +++++++++++++ spec/framework/core/fact_manager_spec.rb | 19 +- .../core/options/option_store_spec.rb | 3 +- 22 files changed, 676 insertions(+), 136 deletions(-) delete mode 100644 block_groups.conf create mode 100644 fact_groups.conf delete mode 100644 lib/framework/config/block_list.rb create mode 100644 lib/framework/config/fact_groups.rb create mode 100644 lib/framework/core/cache_manager.rb create mode 100644 spec/facter/cache_manager_spec.rb delete mode 100644 spec/framework/config/block_list_spec.rb create mode 100644 spec/framework/config/fact_groups_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index e70d346cc..c4b7ea8cf 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -94,6 +94,7 @@ Metrics/ClassLength: - 'lib/resolvers/windows/networking_resolver.rb' - 'lib/custom_facts/util/collection.rb' - 'lib/framework/core/options/option_store.rb' + - 'lib/framework/cli/cli.rb' Style/DoubleNegation: Exclude: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 93aeee91b..625e4ce37 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 1000` -# on 2020-04-16 12:37:29 +0300 using RuboCop version 0.74.0. +# on 2020-04-24 12:45:39 +0300 using RuboCop version 0.74.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -71,8 +71,8 @@ RSpec/FilePath: - 'spec/facter/resolvers/windows/system32_resolver_spec.rb' - 'spec/facter/resolvers/windows/virtualization_resolver_spec.rb' - 'spec/facter/resolvers/windows/win_os_description_resolver_spec.rb' - - 'spec/framework/config/block_list_spec.rb' - 'spec/framework/config/config_reader_spec.rb' + - 'spec/framework/config/fact_groups_spec.rb' - 'spec/framework/core/fact/external/external_fact_manager_spec.rb' - 'spec/framework/core/fact/internal/internal_fact_manager_spec.rb' - 'spec/framework/core/fact_loaders/class_discoverer_spec.rb' @@ -190,7 +190,7 @@ RSpec/SubjectStub: - 'spec/custom_facts/util/fact_spec.rb' - 'spec/custom_facts/util/resolution_spec.rb' -# Offense count: 172 +# Offense count: 169 # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: Exclude: @@ -247,7 +247,6 @@ RSpec/VerifiedDoubles: - 'spec/facter/resolvers/windows/uptime_resolver_spec.rb' - 'spec/facter/resolvers/windows/virtualization_resolver_spec.rb' - 'spec/facter/resolvers/windows/win_os_description_resolver_spec.rb' - - 'spec/framework/config/block_list_spec.rb' - 'spec/framework/core/fact_loaders/external_fact_loader_spec.rb' - 'spec/framework/core/fact_loaders/fact_loader_spec.rb' - 'spec/framework/core/fact_manager_spec.rb' diff --git a/block_groups.conf b/block_groups.conf deleted file mode 100644 index 96a766c46..000000000 --- a/block_groups.conf +++ /dev/null @@ -1,14 +0,0 @@ -{ - "EC2": [ - "ec2_metadata", - "ec2_userdata" - ], - "file system" : [ - "mountpoints", - "filesystems", - "partitions" - ], - "hypervisors": [ - "hypervisors" - ] -} diff --git a/fact_groups.conf b/fact_groups.conf new file mode 100644 index 000000000..33d006233 --- /dev/null +++ b/fact_groups.conf @@ -0,0 +1,169 @@ +{ + "EC2": [ + "ec2_metadata", + "ec2_userdata" + ], + "GCE": [ + "gce" + ], + "augeas": [ + "augeas", + "augeasversion" + ], + "desktop management interface": [ + "dmi", + "bios_vendor", + "bios_version", + "bios_release_date", + "boardassettag", + "boardmanufacturer", + "boardproductname", + "boardserialnumber", + "chassisassettag", + "manufacturer", + "productname", + "serialnumber", + "uuid", + "chassistype" + ], + "file system": [ + "mountpoints", + "filesystems", + "partitions" + ], + "hypervisors": [ + "hypervisors" + ], + "id": [ + "id", + "gid", + "identity" + ], + "kernel": [ + "kernel", + "kernelversion", + "kernelrelease", + "kernelmajversion" + ], + "load_average": [ + "load_averages" + ], + "memory": [ + "memory", + "memoryfree", + "memoryfree_mb", + "memorysize", + "memorysize_mb", + "swapfree", + "swapfree_mb", + "swapsize", + "swapsize_mb", + "swapencrypted" + ], + "networking": [ + "networking", + "hostname", + "ipaddress", + "ipaddress6", + "netmask", + "netmask6", + "network", + "network6", + "macaddress", + "interfaces", + "domain", + "fqdn", + "dhcp_servers" + ], + "operating system": [ + "os", + "operatingsystem", + "osfamily", + "operatingsystemrelease", + "operatingsystemmajrelease", + "hardwaremodel", + "architecture", + "lsbdistid", + "lsbdistrelease", + "lsbdistcodename", + "lsbdistdescription", + "lsbmajdistrelease", + "lsbminordistrelease", + "lsbrelease", + "macosx_buildversion", + "macosx_productname", + "macosx_productversion", + "macosx_productversion_major", + "macosx_productversion_minor", + "windows_edition_id", + "windows_installation_type", + "windows_product_name", + "windows_release_id", + "system32", + "selinux", + "selinux_enforced", + "selinux_policyversion", + "selinux_current_mode", + "selinux_config_mode", + "selinux_config_policy" + ], + "path": [ + "path" + ], + "processor": [ + "processors", + "processorcount", + "physicalprocessorcount", + "hardwareisa" + ], + "ssh": [ + "ssh", + "sshdsakey", + "sshrsakey", + "sshecdsakey", + "sshed25519key", + "sshfp_dsa", + "sshfp_rsa", + "sshfp_ecdsa", + "sshfp_ed25519" + ], + "system profiler": [ + "system_profiler", + "sp_boot_mode", + "sp_boot_rom_version", + "sp_boot_volume", + "sp_cpu_type", + "sp_current_processor_speed", + "sp_kernel_version", + "sp_l2_cache_core", + "sp_l3_cache", + "sp_local_host_name", + "sp_machine_model", + "sp_machine_name", + "sp_number_processors", + "sp_os_version", + "sp_packages", + "sp_physical_memory", + "sp_platform_uuid", + "sp_secure_vm", + "sp_serial_number", + "sp_smc_version_system", + "sp_uptime", + "sp_user_name" + ], + "timezone": [ + "timezone" + ], + "uptime": [ + "system_uptime", + "uptime", + "uptime_days", + "uptime_hours", + "uptime_seconds" + ], + "virtualization": [ + "virtual", + "is_virtual", + "cloud" + ] +} \ No newline at end of file diff --git a/lib/custom_facts/util/config.rb b/lib/custom_facts/util/config.rb index 340c3abc8..85b72d24b 100644 --- a/lib/custom_facts/util/config.rb +++ b/lib/custom_facts/util/config.rb @@ -36,6 +36,10 @@ def self.external_facts_dirs @external_facts_dirs end + def self.facts_cache_dir + @facts_cache_dir ||= setup_default_cache_dir + end + def self.setup_default_ext_facts_dirs if LegacyFacter::Util::Root.root? windows_dir = windows_data_dir @@ -68,6 +72,15 @@ def self.override_binary_dir @override_binary_dir end + def self.setup_default_cache_dir + windows_dir = windows_data_dir + @facts_cache_dir = if windows_dir + File.join(windows_dir, 'PuppetLabs', 'facter', 'cache', 'cached_facts') + else + '/opt/puppetlabs/facter/cache/cached_facts' + end + end + def self.setup_default_override_binary_dir @override_binary_dir = if LegacyFacter::Util::Config.windows? nil diff --git a/lib/facter.rb b/lib/facter.rb index 066a75c99..7199ccacf 100644 --- a/lib/facter.rb +++ b/lib/facter.rb @@ -327,7 +327,7 @@ def error_check(args, resolved_facts) # # @api private def log_blocked_facts - block_list = Facter::BlockList.new(Facter::Options[:config]).block_list + block_list = Facter::FactGroups.new(Facter::Options[:config]).block_list return unless block_list.any? && Facter::Options[:block] @logger.debug("blocking collection of #{block_list.join("\s")} facts") diff --git a/lib/framework/cli/cli.rb b/lib/framework/cli/cli.rb index 971f7aba5..a57fb99ca 100755 --- a/lib/framework/cli/cli.rb +++ b/lib/framework/cli/cli.rb @@ -122,7 +122,13 @@ def version desc '--list-block-groups', 'List block groups' map ['--list-block-groups'] => :list_block_groups def list_block_groups(*_args) - puts Facter::BlockList.new.block_groups.to_yaml.lines[1..-1].join + puts Facter::FactGroups.new.groups.to_yaml.lines[1..-1].join + end + + desc '--list-cache-groups', 'List cache groups' + map ['--list-cache-groups'] => :list_cache_groups + def list_cache_groups(*_args) + puts Facter::FactGroups.new.groups.to_yaml.lines[1..-1].join end def self.exit_on_failure? diff --git a/lib/framework/config/block_list.rb b/lib/framework/config/block_list.rb deleted file mode 100644 index 6b7ac2997..000000000 --- a/lib/framework/config/block_list.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -module Facter - class BlockList - attr_reader :block_groups, :block_list - - def initialize(block_list_path = nil) - @block_groups_file_path = block_list_path || File.join(ROOT_DIR, 'block_groups.conf') - load_block_groups - end - - # Breakes down blocked groups in blocked facts - def blocked_facts - fact_list = [] - - @block_list.each do |group_name| - facts_for_block = @block_groups[group_name] - - fact_list += facts_for_block || [group_name] - end - - fact_list - end - - private - - def load_block_groups - @block_groups = File.readable?(@block_groups_file_path) ? Hocon.load(@block_groups_file_path) : {} - @block_list = ConfigReader.init(Options[:config]).block_list || {} - end - end -end diff --git a/lib/framework/config/fact_groups.rb b/lib/framework/config/fact_groups.rb new file mode 100644 index 000000000..7932288dd --- /dev/null +++ b/lib/framework/config/fact_groups.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Facter + class FactGroups + attr_reader :groups, :block_list + + @groups_ttls = [] + + STRING_TO_SECONDS = { 'seconds' => 1, 'minutes' => 60, 'hours' => 3600, 'days' => 3600 * 24 }.freeze + + def initialize(group_list_path = nil) + @groups_file_path = group_list_path || File.join(ROOT_DIR, 'fact_groups.conf') + @groups ||= File.readable?(@groups_file_path) ? Hocon.load(@groups_file_path) : {} + load_groups + end + + # Breakes down blocked groups in blocked facts + def blocked_facts + fact_list = [] + + @block_list.each do |group_name| + facts_for_block = @groups[group_name] + + fact_list += facts_for_block || [group_name] + end + + fact_list + end + + # Get the group name a fact is part of + def get_fact_group(fact_name) + @groups.detect { |k, v| break k if Array(v).find { |f| fact_name =~ /^#{f}.*/ } } + end + + # Get config ttls for a given group + def get_group_ttls(group_name) + return unless (ttls = @groups_ttls.find { |g| g[group_name] }) + + ttls_to_seconds(ttls[group_name]) + end + + private + + def load_groups + config = ConfigReader.init(Options[:config]) + @block_list = config.block_list || {} + @groups_ttls = ConfigReader.init(Options[:config]).ttls || {} + end + + def ttls_to_seconds(ttls) + duration, unit = ttls.split(' ', 2) + duration.to_i * STRING_TO_SECONDS[unit] + end + end +end diff --git a/lib/framework/core/cache_manager.rb b/lib/framework/core/cache_manager.rb new file mode 100644 index 000000000..0fd5de747 --- /dev/null +++ b/lib/framework/core/cache_manager.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +module Facter + class CacheManager + def initialize + @groups = {} + @log = Log.new(self) + @fact_groups = Facter::FactGroups.new + end + + def cache_dir + LegacyFacter::Util::Config.facts_cache_dir + end + + def resolve_facts(searched_facts) + return searched_facts, [] if !File.directory?(cache_dir) || !Options[:cache] + + facts = [] + searched_facts.each do |fact| + res = resolve_fact(fact) + facts << res if res + end + facts.each do |fact| + searched_facts.delete_if { |f| f.name == fact.name } + end + [searched_facts, facts] + end + + def cache_facts(resolved_facts) + return unless Options[:cache] + + resolved_facts.each do |fact| + cache_fact(fact) + end + + begin + write_cache unless @groups.empty? + rescue Errno::EACCES => e + @log.warn("Could not write cache: #{e.message}") + end + end + + private + + def resolve_fact(searched_fact) + group_name = @fact_groups.get_fact_group(searched_fact.name) + return unless group_name + + return unless group_cached?(group_name) + + return if check_ttls(group_name).zero? + + data = read_group_json(group_name) + return unless data + + @log.debug("loading cached values for #{group_name} facts") + create_fact(searched_fact, data[searched_fact.name]) + end + + def create_fact(searched_fact, value) + Facter::ResolvedFact.new(searched_fact.name, value, searched_fact.type, + searched_fact.user_query, searched_fact.filter_tokens) + end + + def cache_fact(fact) + group_name = @fact_groups.get_fact_group(fact.name) + return if !group_name || fact.value.nil? + + return unless group_cached?(group_name) + + @groups[group_name] ||= {} + @groups[group_name][fact.name] = fact.value + end + + def write_cache + unless File.directory?(cache_dir) + require 'fileutils' + FileUtils.mkdir_p(cache_dir) + end + + @groups.each do |group_name, data| + next if check_ttls(group_name).zero? + + @log.debug("caching values for #{group_name} facts") + cache_file_name = File.join(cache_dir, group_name) + File.write(cache_file_name, JSON.pretty_generate(data)) + end + end + + def read_group_json(group_name) + return @groups[group_name] if @groups.key?(group_name) + + cache_file_name = File.join(cache_dir, group_name) + data = nil + file = Util::FileHelper.safe_read(cache_file_name) + begin + data = JSON.parse(file) + rescue JSON::ParserError + delete_cache(group_name) + end + @groups[group_name] = data + end + + def group_cached?(group_name) + cached = @fact_groups.get_group_ttls(group_name) ? true : false + delete_cache(group_name) unless cached + cached + end + + def check_ttls(group_name) + ttls = @fact_groups.get_group_ttls(group_name) + return 0 unless ttls + + cache_file_name = File.join(cache_dir, group_name) + return ttls unless File.readable?(cache_file_name) + + file_time = File.mtime(cache_file_name) + expire_date = file_time + ttls + if expire_date < Time.now + File.delete(cache_file_name) + return ttls + end + expire_date.to_i + end + + def delete_cache(group_name) + cache_file_name = File.join(cache_dir, group_name) + File.delete(cache_file_name) if File.readable?(cache_file_name) + end + end +end diff --git a/lib/framework/core/fact_manager.rb b/lib/framework/core/fact_manager.rb index d96022bd5..dfa005a50 100644 --- a/lib/framework/core/fact_manager.rb +++ b/lib/framework/core/fact_manager.rb @@ -20,10 +20,16 @@ def resolve_facts(user_query = []) loaded_facts = @fact_loader.load(Options.get) searched_facts = QueryParser.parse(user_query, loaded_facts) + cache_manager = Facter::CacheManager.new + searched_facts, cached_facts = cache_manager.resolve_facts(searched_facts) internal_facts = @internal_fact_mgr.resolve_facts(searched_facts) external_facts = @external_fact_mgr.resolve_facts(searched_facts) resolved_facts = override_core_facts(internal_facts, external_facts) + + cache_manager.cache_facts(resolved_facts) + resolved_facts = resolved_facts.concat(cached_facts) + FactFilter.new.filter_facts!(resolved_facts) resolved_facts diff --git a/lib/framework/core/file_loader.rb b/lib/framework/core/file_loader.rb index e50534b33..711b5a3e4 100644 --- a/lib/framework/core/file_loader.rb +++ b/lib/framework/core/file_loader.rb @@ -31,7 +31,7 @@ def load_lib_dirs(*dirs) require "#{ROOT_DIR}/lib/framework/detector/os_detector" require "#{ROOT_DIR}/lib/framework/config/config_reader" -require "#{ROOT_DIR}/lib/framework/config/block_list" +require "#{ROOT_DIR}/lib/framework/config/fact_groups" load_dir(['config']) diff --git a/lib/framework/core/options/config_file_options.rb b/lib/framework/core/options/config_file_options.rb index 3ce97453f..05d8073da 100644 --- a/lib/framework/core/options/config_file_options.rb +++ b/lib/framework/core/options/config_file_options.rb @@ -71,7 +71,7 @@ def augment_show_legacy(global_conf) end def augment_facts(ttls) - blocked_facts = Facter::BlockList.new.blocked_facts + blocked_facts = Facter::FactGroups.new.blocked_facts @options[:blocked_facts] = blocked_facts unless blocked_facts.nil? @options[:ttls] = ttls unless ttls.nil? diff --git a/lib/framework/core/options/option_store.rb b/lib/framework/core/options/option_store.rb index 81a81a706..281ec42a1 100644 --- a/lib/framework/core/options/option_store.rb +++ b/lib/framework/core/options/option_store.rb @@ -15,6 +15,7 @@ class OptionStore @external_dir = [] @external_facts = true @ruby = true + @cache = true @blocked_facts = [] @user_query = [] @@ -150,6 +151,7 @@ def reset @blocked_facts = [] @user_query = [] @cli = nil + @cache = true end end end diff --git a/lib/models/resolved_fact.rb b/lib/models/resolved_fact.rb index caa949bb3..535a54ea8 100644 --- a/lib/models/resolved_fact.rb +++ b/lib/models/resolved_fact.rb @@ -5,14 +5,12 @@ class ResolvedFact attr_reader :name, :type attr_accessor :user_query, :filter_tokens, :value - def initialize(name, value = '', type = :core) - unless type =~ /core|legacy|custom/ - raise ArgumentError, 'The type provided for fact is not legacy, core or custom!' - end - + def initialize(name, value = '', type = :core, user_query = nil, filter_tokens = []) @name = name @value = Utils.deep_stringify_keys(value) @type = type + @user_query = user_query + @filter_tokens = filter_tokens end def legacy? diff --git a/spec/facter/cache_manager_spec.rb b/spec/facter/cache_manager_spec.rb new file mode 100644 index 000000000..df1d3386b --- /dev/null +++ b/spec/facter/cache_manager_spec.rb @@ -0,0 +1,138 @@ +# frozen_string_literal: true + +describe Facter::CacheManager do + subject(:cache_manager) { Facter::CacheManager.new } + + let(:cache_dir) { '/etc/facter/cache' } + let(:searched_core_fact) do + instance_spy(Facter::SearchedFact, name: 'os', fact_class: instance_spy(Facts::Debian::Os::Name), + filter_tokens: [], user_query: '', type: :core) + end + let(:searched_custom_fact) do + instance_spy(Facter::SearchedFact, name: 'my_custom_fact', fact_class: nil, filter_tokens: [], + user_query: '', type: :custom) + end + let(:searched_facts) { [searched_core_fact, searched_custom_fact] } + let(:cached_core_fact) { "{\n \"os\": \"Ubuntu\"\n}" } + + let(:resolved_core_fact) { mock_resolved_fact('os', 'Ubuntu', '', []) } + let(:resolved_facts) { [resolved_core_fact] } + let(:group_name) { 'operating system' } + let(:cache_file_name) { File.join(cache_dir, group_name) } + let(:fact_groups) { instance_spy(Facter::FactGroups) } + + before do + allow(LegacyFacter::Util::Config).to receive(:facts_cache_dir).and_return(cache_dir) + allow(Facter::FactGroups).to receive(:new).and_return(fact_groups) + allow(Facter::Options).to receive(:[]).with(:debug).and_return(false) + end + + describe '#resolve_facts' do + context 'with no cache dir' do + before do + allow(File).to receive(:directory?).with(cache_dir).and_return(false) + allow(Facter::Options).to receive(:[]).with(:cache).and_return(true) + end + + it 'returns searched facts' do + sf, _cf = cache_manager.resolve_facts(searched_facts) + expect(sf).to eq(searched_facts) + end + + it 'returns no cached facts' do + _, cf = cache_manager.resolve_facts(searched_facts) + expect(cf).to be_empty + end + end + + context 'with no cache false' do + before do + allow(File).to receive(:directory?).with(cache_dir).and_return(true) + allow(Facter::Options).to receive(:[]).with(:cache).and_return(false) + end + + it 'returns searched facts' do + sf, _cf = cache_manager.resolve_facts(searched_facts) + expect(sf).to eq(searched_facts) + end + + it 'returns no cached facts' do + _, cf = cache_manager.resolve_facts(searched_facts) + expect(cf).to be_empty + end + end + + context 'with cached facts' do + before do + allow(File).to receive(:directory?).with(cache_dir).and_return(true) + allow(fact_groups).to receive(:get_fact_group).with('os').and_return(group_name) + allow(fact_groups).to receive(:get_fact_group).with('my_custom_fact').and_return(nil) + allow(File).to receive(:readable?).with(cache_file_name).and_return(true) + allow(File).to receive(:mtime).with(cache_file_name).and_return(Time.now) + allow(Facter::Util::FileHelper).to receive(:safe_read).with(cache_file_name).and_return(cached_core_fact) + allow(Facter::Options).to receive(:[]).with(:cache).and_return(true) + end + + it 'returns cached fact' do + allow(fact_groups).to receive(:get_group_ttls).with(group_name).and_return(1000) + + _, cached_facts = cache_manager.resolve_facts(searched_facts) + expect(cached_facts).to be_an_instance_of(Array).and contain_exactly( + an_instance_of(Facter::ResolvedFact).and(having_attributes(name: 'os', value: 'Ubuntu', type: :core)) + ) + end + + it 'returns searched fact' do + allow(fact_groups).to receive(:get_group_ttls).with(group_name).and_return(1000) + + sf, _cf = cache_manager.resolve_facts(searched_facts) + expect(sf).to be_an_instance_of(Array).and contain_exactly( + an_object_having_attributes(name: 'my_custom_fact', type: :custom) + ) + end + + it 'deletes cache file' do + allow(fact_groups).to receive(:get_group_ttls).with(group_name).and_return(nil) + allow(File).to receive(:delete).with(cache_file_name) + + cache_manager.resolve_facts(searched_facts) + expect(File).to have_received(:delete).with(cache_file_name) + end + end + end + + describe '#cache_facts' do + context 'with group not cached' do + before do + allow(File).to receive(:directory?).with(cache_dir).and_return(true) + allow(File).to receive(:readable?).with(cache_file_name).and_return(false) + allow(fact_groups).to receive(:get_group_ttls).with(group_name).and_return(nil) + allow(fact_groups).to receive(:get_fact_group).with('os').and_return(group_name) + allow(File).to receive(:write).with(cache_file_name, cached_core_fact) + allow(Facter::Options).to receive(:[]).with(:cache).and_return(true) + end + + it 'returns without caching' do + cache_manager.cache_facts(resolved_facts) + expect(File).not_to have_received(:write).with(cache_file_name, cached_core_fact) + end + end + + context 'with cache group' do + before do + allow(File).to receive(:directory?).with(cache_dir).and_return(true) + allow(fact_groups).to receive(:get_fact_group).with('os').and_return(group_name) + allow(fact_groups).to receive(:get_fact_group).with('my_custom_fact').and_return(nil) + allow(fact_groups).to receive(:get_group_ttls).with(group_name).and_return(1000) + allow(File).to receive(:readable?).with(cache_file_name).and_return(false) + allow(File).to receive(:write).with(cache_file_name, cached_core_fact) + allow(Facter::Options).to receive(:[]).with(:cache).and_return(true) + end + + it 'caches fact' do + cache_manager.cache_facts(resolved_facts) + expect(File).to have_received(:write).with(cache_file_name, cached_core_fact) + end + end + end +end diff --git a/spec/facter/facter_spec.rb b/spec/facter/facter_spec.rb index 02b944a08..87dc4e0e8 100644 --- a/spec/facter/facter_spec.rb +++ b/spec/facter/facter_spec.rb @@ -12,7 +12,7 @@ let(:fact_collection_spy) { instance_spy(Facter::FactCollection) } let(:key_error) { KeyError.new('key error') } let(:config_reader_double) { double(Facter::ConfigReader) } - let(:block_list_double) { double(Facter::BlockList) } + let(:block_list_double) { instance_spy(Facter::FactGroups) } before do allow(Facter::ConfigReader).to receive(:init).and_return(config_reader_double) @@ -21,7 +21,7 @@ allow(config_reader_double).to receive(:ttls).and_return([]) allow(config_reader_double).to receive(:block_list).and_return([]) - allow(Facter::BlockList).to receive(:instance).and_return(block_list_double) + allow(Facter::FactGroups).to receive(:instance).and_return(block_list_double) allow(block_list_double).to receive(:blocked_facts).and_return([]) allow(block_list_double).to receive(:block_list).and_return([]) diff --git a/spec/facter/model/resolved_fact_spec.rb b/spec/facter/model/resolved_fact_spec.rb index 7bcfd1d9e..ab9876ef3 100644 --- a/spec/facter/model/resolved_fact_spec.rb +++ b/spec/facter/model/resolved_fact_spec.rb @@ -35,12 +35,4 @@ end # rubocop:enable Style/UnneededInterpolation end - - context 'when is an invalid type' do - it 'raises an ArgumentError' do - expect do - Facter::ResolvedFact.new('fact_name', 'fact_value', :type) - end.to raise_error(ArgumentError, 'The type provided for fact is not legacy, core or custom!') - end - end end diff --git a/spec/framework/config/block_list_spec.rb b/spec/framework/config/block_list_spec.rb deleted file mode 100644 index e0104235f..000000000 --- a/spec/framework/config/block_list_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -describe Facter::BlockList do - subject(:block_list) { Facter::BlockList } - - let(:config_reader) { double(Facter::ConfigReader) } - - before do - allow(Facter::ConfigReader).to receive(:init).and_return(config_reader) - allow(config_reader).to receive(:block_list).and_return([]) - end - - describe '#initialize' do - it 'sets @block_groups_file_path to parameter value' do - blk_list = block_list.new('path/to/block/groups') - - expect(blk_list.instance_variable_get(:@block_groups_file_path)).to eq('path/to/block/groups') - end - - it 'sets @block_groups_file_path to default path' do - blk_list = block_list.new - - expect(blk_list.instance_variable_get(:@block_groups_file_path)).to eq(File.join(ROOT_DIR, 'block_groups.conf')) - end - end - - describe '#blocked_facts' do - context 'with block_list' do - before do - allow(File).to receive(:readable?).and_return(true) - allow(Hocon).to receive(:load) - .with(File.join(ROOT_DIR, 'block_groups.conf')) - .and_return('blocked_group' => %w[fact1 fact2]) - allow(config_reader).to receive(:block_list).and_return(%w[blocked_group blocked_fact]) - end - - it 'returns a list of blocked facts' do - blk_list = block_list.new - - expect(blk_list.blocked_facts).to eq(%w[fact1 fact2 blocked_fact]) - end - end - - context 'without block_list' do - before do - allow(File).to receive(:readable?).and_return(false) - allow(config_reader).to receive(:block_list).and_return([]) - end - - it 'finds no block group file' do - allow(File).to receive(:readable?).and_return(false) - - config_reader = double(Facter::ConfigReader) - allow(Facter::ConfigReader).to receive(:new).and_return(config_reader) - allow(config_reader).to receive(:block_list).and_return(nil) - - blk_list = block_list.new - - expect(blk_list.blocked_facts).to eq([]) - end - end - end -end diff --git a/spec/framework/config/fact_groups_spec.rb b/spec/framework/config/fact_groups_spec.rb new file mode 100644 index 000000000..ccebccf97 --- /dev/null +++ b/spec/framework/config/fact_groups_spec.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +describe Facter::FactGroups do + subject(:fact_groups) { Facter::FactGroups } + + let(:fg) { fact_groups.new } + let(:config_reader) { class_spy(Facter::ConfigReader) } + + before do + allow(Facter::ConfigReader).to receive(:init).and_return(config_reader) + allow(config_reader).to receive(:block_list).and_return([]) + allow(config_reader).to receive(:ttls).and_return([]) + end + + describe '#initialize' do + it 'sets @groups_file_path to parameter value' do + blk_list = fact_groups.new('path/to/block/groups') + + expect(blk_list.instance_variable_get(:@groups_file_path)).to eq('path/to/block/groups') + end + + it 'sets @groups_file_path to default path' do + blk_list = fact_groups.new + + expect(blk_list.instance_variable_get(:@groups_file_path)).to eq(File.join(ROOT_DIR, 'fact_groups.conf')) + end + end + + describe '#blocked_facts' do + context 'with block_list' do + before do + allow(File).to receive(:readable?).and_return(true) + allow(Hocon).to receive(:load) + .with(File.join(ROOT_DIR, 'fact_groups.conf')) + .and_return('blocked_group' => %w[fact1 fact2]) + allow(config_reader).to receive(:block_list).and_return(%w[blocked_group blocked_fact]) + end + + it 'returns a list of blocked facts' do + blk_list = fact_groups.new + + expect(blk_list.blocked_facts).to eq(%w[fact1 fact2 blocked_fact]) + end + end + + context 'without block_list' do + before do + allow(File).to receive(:readable?).and_return(false) + allow(config_reader).to receive(:block_list).and_return([]) + allow(Facter::ConfigReader).to receive(:new).and_return(config_reader) + allow(config_reader).to receive(:block_list).and_return(nil) + end + + it 'finds no block group file' do + blk_list = fact_groups.new + + expect(blk_list.blocked_facts).to eq([]) + end + end + end + + describe '#get_fact_group' do + context 'when it finds group file' do + before do + allow(File).to receive(:readable?).and_return(true) + allow(Hocon).to receive(:load) + .with(File.join(ROOT_DIR, 'fact_groups.conf')) + .and_return('operating system' => %w[os os.name]) + + allow(config_reader).to receive(:ttls).and_return(['operating system' => '30 minutes']) + end + + it 'returns group' do + expect(fg.get_fact_group('os')).to eq('operating system') + end + + it 'returns nil' do + expect(fg.get_fact_group('memory')).to be_nil + end + end + + context 'when it does not find group file' do + before do + allow(File).to receive(:readable?).and_return(false) + allow(config_reader).to receive(:ttls).and_return(nil) + end + + it 'returns nil' do + expect(fg.get_fact_group('os')).to be_nil + end + end + end + + describe '#get_group_ttls' do + context 'when it finds group file' do + before do + allow(File).to receive(:readable?).and_return(true) + allow(Hocon).to receive(:load) + .with(File.join(ROOT_DIR, 'fact_groups.conf')) + .and_return('operating system' => %w[os os.name]) + + allow(config_reader).to receive(:ttls).and_return(['operating system' => '30 minutes']) + end + + it 'returns group' do + expect(fg.get_group_ttls('operating system')).to eq(1800) + end + + it 'returns nil' do + expect(fg.get_group_ttls('memory')).to be_nil + end + end + + context 'when it does not find group file' do + before do + allow(File).to receive(:readable?).and_return(false) + allow(config_reader).to receive(:ttls).and_return(nil) + end + + it 'returns nil' do + expect(fg.get_group_ttls('os')).to be_nil + end + end + end +end diff --git a/spec/framework/core/fact_manager_spec.rb b/spec/framework/core/fact_manager_spec.rb index 4bd01cdd3..eb9190932 100644 --- a/spec/framework/core/fact_manager_spec.rb +++ b/spec/framework/core/fact_manager_spec.rb @@ -3,11 +3,13 @@ describe Facter::FactManager do let(:internal_manager) { instance_spy(Facter::InternalFactManager) } let(:external_manager) { instance_spy(Facter::ExternalFactManager) } + let(:cache_manager) { instance_spy(Facter::CacheManager) } before do Singleton.__init__(Facter::FactManager) allow(Facter::InternalFactManager).to receive(:new).and_return(internal_manager) allow(Facter::ExternalFactManager).to receive(:new).and_return(external_manager) + allow(Facter::CacheManager).to receive(:new).and_return(cache_manager) end describe '#resolve_facts' do @@ -28,19 +30,30 @@ resolved_fact = mock_resolved_fact('os', 'Ubuntu', '', []) + seached_facts = [searched_fact1, searched_fact2] + allow(Facter::QueryParser) .to receive(:parse) .with(user_query, loaded_facts) - .and_return([searched_fact1, searched_fact2]) + .and_return(seached_facts) allow(internal_manager) .to receive(:resolve_facts) - .with([searched_fact1, searched_fact2]) + .with(seached_facts) .and_return([resolved_fact]) allow(external_manager) .to receive(:resolve_facts) - .with([searched_fact1, searched_fact2]) + .with(seached_facts) + + allow(cache_manager) + .to receive(:resolve_facts) + .with(seached_facts) + .and_return([seached_facts, []]) + + allow(cache_manager) + .to receive(:cache_facts) + .with([resolved_fact]) resolved_facts = Facter::FactManager.instance.resolve_facts(user_query) diff --git a/spec/framework/core/options/option_store_spec.rb b/spec/framework/core/options/option_store_spec.rb index 519c1b0a0..c2c20bdde 100644 --- a/spec/framework/core/options/option_store_spec.rb +++ b/spec/framework/core/options/option_store_spec.rb @@ -24,7 +24,8 @@ trace: false, user_query: [], verbose: false, - config: nil + config: nil, + cache: true ) end end From d3e574d5f04f4e881388e66125c8f9f1cb0239a9 Mon Sep 17 00:00:00 2001 From: Filipovici-Andrei Date: Fri, 24 Apr 2020 15:02:28 +0300 Subject: [PATCH 10/13] (FACT-2565) Debian development versions causes fatal error when resolving os.release (#466) * (FACT-2565) fixed fact for when release does not have minor version refactored unit tests * (FACT-2565) when fact throws exception, it's value is not stored and the failure is logged * (FACT-2565) simplified condition for release minor * (FACT-2565) refactore release hash --- lib/facts/debian/os/distro/release.rb | 6 +- lib/facts/debian/os/release.rb | 9 +- .../fact/internal/internal_fact_manager.rb | 14 ++- .../facts/debian/os/distro/release_spec.rb | 90 ++++++++------- spec/facter/facts/debian/os/release_spec.rb | 107 ++++++++++-------- .../internal/internal_fact_manager_spec.rb | 49 ++++++-- 6 files changed, 173 insertions(+), 102 deletions(-) diff --git a/lib/facts/debian/os/distro/release.rb b/lib/facts/debian/os/distro/release.rb index 7be674c19..cc7e8c6fb 100644 --- a/lib/facts/debian/os/distro/release.rb +++ b/lib/facts/debian/os/distro/release.rb @@ -13,8 +13,10 @@ def call_the_resolver return Facter::ResolvedFact.new(FACT_NAME, nil) unless fact_value versions = fact_value.split('.') - release = { 'full' => fact_value, 'major' => versions[0], 'minor' => versions[1].gsub(/^0([1-9])/, '\1') } - + release = {} + release['full'] = fact_value + release['major'] = versions[0] + release['minor'] = versions[1].gsub(/^0([1-9])/, '\1') if versions[1] Facter::ResolvedFact.new(FACT_NAME, release) end diff --git a/lib/facts/debian/os/release.rb b/lib/facts/debian/os/release.rb index b3a0db92c..3c1aa5e6d 100644 --- a/lib/facts/debian/os/release.rb +++ b/lib/facts/debian/os/release.rb @@ -13,11 +13,10 @@ def call_the_resolver return Facter::ResolvedFact.new(FACT_NAME, nil) unless fact_value versions = fact_value.split('.') - release = { - 'full' => fact_value, - 'major' => versions[0], - 'minor' => versions[1].gsub(/^0([1-9])/, '\1') - } + release = {} + release['full'] = fact_value + release['major'] = versions[0] + release['minor'] = versions[1].gsub(/^0([1-9])/, '\1') if versions[1] [Facter::ResolvedFact.new(FACT_NAME, release), Facter::ResolvedFact.new(ALIASES.first, versions[0], :legacy), diff --git a/lib/framework/core/fact/internal/internal_fact_manager.rb b/lib/framework/core/fact/internal/internal_fact_manager.rb index 95c4ce2d8..55d70ce47 100644 --- a/lib/framework/core/fact/internal/internal_fact_manager.rb +++ b/lib/framework/core/fact/internal/internal_fact_manager.rb @@ -2,6 +2,8 @@ module Facter class InternalFactManager + @@log = Facter::Log.new(self) + def resolve_facts(searched_facts) searched_facts = filter_internal_facts(searched_facts) @@ -18,14 +20,18 @@ def filter_internal_facts(searched_facts) def start_threads(searched_facts) threads = [] - # only resolve a fact once, even if multiple search facts depend on that fact searched_facts .uniq { |searched_fact| searched_fact.fact_class.name } .each do |searched_fact| threads << Thread.new do - fact = CoreFact.new(searched_fact) - fact.create + begin + fact = CoreFact.new(searched_fact) + fact.create + rescue StandardError => e + @@log.error(e.backtrace.join("\n")) + nil + end end end @@ -37,7 +43,7 @@ def join_threads(threads, searched_facts) threads.each do |thread| thread.join - resolved_facts << thread.value + resolved_facts << thread.value unless thread.value.nil? end resolved_facts.flatten! diff --git a/spec/facter/facts/debian/os/distro/release_spec.rb b/spec/facter/facts/debian/os/distro/release_spec.rb index 59a5f43f5..49457dfb5 100644 --- a/spec/facter/facts/debian/os/distro/release_spec.rb +++ b/spec/facter/facts/debian/os/distro/release_spec.rb @@ -4,79 +4,91 @@ describe '#call_the_resolver' do subject(:fact) { Facts::Debian::Os::Distro::Release.new } + shared_examples 'calls Facter::Resolvers::OsRelease with :name' do + it 'calls Facter::Resolvers::OsRelease with :name' do + fact.call_the_resolver + expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:name) + end + end + + shared_examples 'returns distro release fact' do + it 'returns release fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'os.distro.release', value: fact_value) + end + end + context 'when os is Ubuntu' do before do - allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:name).and_return(name) - allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:version_id).and_return(value) + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:name).and_return(os_name) + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:version_id).and_return(os_release_value) end - let(:name) { 'Ubuntu' } + let(:os_name) { 'Ubuntu' } - context 'when version_id is retrieved successful' do - let(:value) { '18.04' } - let(:value_final) { { 'full' => '18.04', 'major' => '18', 'minor' => '4' } } + context 'when version_id is retrieved successfully' do + let(:os_release_value) { '18.04' } + let(:fact_value) { { 'full' => '18.04', 'major' => '18', 'minor' => '4' } } - it 'calls Facter::Resolvers::OsRelease with :name' do - fact.call_the_resolver - expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:name) - end + it_behaves_like 'calls Facter::Resolvers::OsRelease with :name' it 'calls Facter::Resolvers::OsRelease with :version_id' do fact.call_the_resolver expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:version_id) end - it 'returns release fact' do - expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ - have_attributes(name: 'os.distro.release', value: value_final) - end + it_behaves_like 'returns distro release fact' end - context 'when version_id could not be retrieve' do - let(:value) { nil } + context 'when version_id could not be retrieved' do + let(:os_release_value) { nil } + let(:fact_value) { nil } - it 'returns release fact as nil' do - expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ - have_attributes(name: 'os.distro.release', value: value) - end + it_behaves_like 'returns distro release fact' + end + + context 'when version has no minor' do + let(:os_release_value) { 'experimental_release' } + let(:fact_value) { { 'full' => 'experimental_release', 'major' => 'experimental_release' } } + + it_behaves_like 'returns distro release fact' end end context 'when os is Debian' do - let(:name) { 'Debian' } + let(:os_name) { 'Debian' } before do - allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:name).and_return(name) - allow(Facter::Resolvers::DebianVersion).to receive(:resolve).with(:version).and_return(value) + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:name).and_return(os_name) + allow(Facter::Resolvers::DebianVersion).to receive(:resolve).with(:version).and_return(os_release_value) end - context 'when version_id is retrieved successful' do - let(:value) { '10.02' } - let(:value_final) { { 'full' => '10.02', 'major' => '10', 'minor' => '2' } } + context 'when version_id is retrieved successfully' do + let(:os_release_value) { '10.02' } + let(:fact_value) { { 'full' => '10.02', 'major' => '10', 'minor' => '2' } } - it 'calls Facter::Resolvers::OsRelease with :name' do - fact.call_the_resolver - expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:name) - end + it_behaves_like 'calls Facter::Resolvers::OsRelease with :name' it 'calls Facter::Resolvers::DebianVersion' do fact.call_the_resolver expect(Facter::Resolvers::DebianVersion).to have_received(:resolve).with(:version) end - it 'returns release fact' do - expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ - have_attributes(name: 'os.distro.release', value: value_final) - end + it_behaves_like 'returns distro release fact' end context 'when version_id could not be retrieve' do - let(:value) { nil } + let(:os_release_value) { nil } + let(:fact_value) { nil } - it 'returns release fact as nil' do - expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ - have_attributes(name: 'os.distro.release', value: value) - end + it_behaves_like 'returns distro release fact' + end + + context 'when version has no minor' do + let(:os_release_value) { 'bullseye/sid' } + let(:fact_value) { { 'full' => 'bullseye/sid', 'major' => 'bullseye/sid' } } + + it_behaves_like 'returns distro release fact' end end end diff --git a/spec/facter/facts/debian/os/release_spec.rb b/spec/facter/facts/debian/os/release_spec.rb index aec3e93bd..47d8a95df 100644 --- a/spec/facter/facts/debian/os/release_spec.rb +++ b/spec/facter/facts/debian/os/release_spec.rb @@ -4,87 +4,104 @@ describe '#call_the_resolver' do subject(:fact) { Facts::Debian::Os::Release.new } + shared_examples 'calls Facter::Resolvers::OsRelease with :name' do + it 'calls Facter::Resolvers::OsRelease with :name' do + fact.call_the_resolver + expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:name) + end + end + + shared_examples 'returns os release fact' do + it 'returns os release fact' do + expect(fact.call_the_resolver).to match_array \ + [ + having_attributes(name: 'os.release', value: fact_value), + having_attributes(name: 'operatingsystemmajrelease', value: fact_value['major'], + type: :legacy), + having_attributes(name: 'operatingsystemrelease', value: fact_value['full'], + type: :legacy) + ] + end + end + + shared_examples 'returns os release fact as nil' do + it 'returns os release fact as nil' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'os.release', value: fact_value) + end + end + context 'when os is Ubuntu' do before do - allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:name).and_return(name) - allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:version_id).and_return(value) + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:name).and_return(os_name) + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:version_id).and_return(os_release_value) end - let(:name) { 'Ubuntu' } + let(:os_name) { 'Ubuntu' } context 'when version_id is retrieved successful' do - let(:value) { '18.04' } - let(:value_final) { { 'full' => '18.04', 'major' => '18', 'minor' => '4' } } + let(:os_release_value) { '18.04' } + let(:fact_value) { { 'full' => '18.04', 'major' => '18', 'minor' => '4' } } - it 'calls Facter::Resolvers::OsRelease with :name' do - fact.call_the_resolver - expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:name) - end + it_behaves_like 'calls Facter::Resolvers::OsRelease with :name' it 'calls Facter::Resolvers::OsRelease with :version_id' do fact.call_the_resolver expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:version_id) end - it 'returns release fact' do - expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ - contain_exactly(an_object_having_attributes(name: 'os.release', value: value_final), - an_object_having_attributes(name: 'operatingsystemmajrelease', value: value_final['major'], - type: :legacy), - an_object_having_attributes(name: 'operatingsystemrelease', value: value_final['full'], - type: :legacy)) - end + it_behaves_like 'returns os release fact' + end + + context 'when version has no minor' do + let(:os_release_value) { 'bullseye/sid' } + let(:fact_value) { { 'full' => 'bullseye/sid', 'major' => 'bullseye/sid' } } + + it_behaves_like 'returns os release fact' end context 'when version_id could not be retrieve' do - let(:value) { nil } + let(:os_release_value) { nil } + let(:fact_value) { nil } - it 'returns release fact as nil' do - expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ - have_attributes(name: 'os.release', value: value) - end + it_behaves_like 'returns os release fact as nil' end end context 'when os is Debian' do - let(:name) { 'Debian' } + let(:os_name) { 'Debian' } before do - allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:name).and_return(name) - allow(Facter::Resolvers::DebianVersion).to receive(:resolve).with(:version).and_return(value) + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:name).and_return(os_name) + allow(Facter::Resolvers::DebianVersion).to receive(:resolve).with(:version).and_return(os_release_value) end context 'when version_id is retrieved successful' do - let(:value) { '10.02' } - let(:value_final) { { 'full' => '10.02', 'major' => '10', 'minor' => '2' } } + let(:os_release_value) { '10.02' } + let(:fact_value) { { 'full' => '10.02', 'major' => '10', 'minor' => '2' } } - it 'calls Facter::Resolvers::OsRelease with :name' do - fact.call_the_resolver - expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:name) - end + it_behaves_like 'calls Facter::Resolvers::OsRelease with :name' it 'calls Facter::Resolvers::DebianVersion' do fact.call_the_resolver expect(Facter::Resolvers::DebianVersion).to have_received(:resolve).with(:version) end - it 'returns release fact' do - expect(fact.call_the_resolver).to be_an_instance_of(Array).and \ - contain_exactly(an_object_having_attributes(name: 'os.release', value: value_final), - an_object_having_attributes(name: 'operatingsystemmajrelease', value: value_final['major'], - type: :legacy), - an_object_having_attributes(name: 'operatingsystemrelease', value: value_final['full'], - type: :legacy)) - end + it_behaves_like 'returns os release fact' end - context 'when version_id could not be retrieve' do - let(:value) { nil } + context 'when version has no minor' do + let(:os_release_value) { 'testing/release' } + let(:fact_value) { { 'full' => 'testing/release', 'major' => 'testing/release' } } - it 'returns release fact as nil' do - expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ - have_attributes(name: 'os.release', value: value) - end + it_behaves_like 'returns os release fact' + end + + context 'when version_id could not §be retrieve' do + let(:os_release_value) { nil } + let(:fact_value) { nil } + + it_behaves_like 'returns os release fact as nil' end end end diff --git a/spec/framework/core/fact/internal/internal_fact_manager_spec.rb b/spec/framework/core/fact/internal/internal_fact_manager_spec.rb index d1c093cb8..8fd7298f6 100644 --- a/spec/framework/core/fact/internal/internal_fact_manager_spec.rb +++ b/spec/framework/core/fact/internal/internal_fact_manager_spec.rb @@ -7,11 +7,9 @@ describe '#resolve_facts' do it 'resolved one core fact' do - resolved_fact = mock_resolved_fact('os', 'Ubuntu', nil, []) - + resolved_fact = mock_resolved_fact('os', 'Debian', nil, []) allow(os_name_class_spy).to receive(:new).and_return(os_name_instance_spy) allow(os_name_instance_spy).to receive(:call_the_resolver).and_return(resolved_fact) - searched_fact = instance_spy(Facter::SearchedFact, name: 'os', fact_class: os_name_class_spy, filter_tokens: [], user_query: '', type: :core) @@ -23,12 +21,9 @@ it 'resolved one legacy fact' do networking_interface_class_spy = class_spy(Facts::Windows::NetworkInterfaces) windows_networking_interface = instance_spy(Facts::Windows::NetworkInterfaces) - resolved_fact = mock_resolved_fact('network_Ethernet0', '192.168.5.121', nil, [], :legacy) - allow(networking_interface_class_spy).to receive(:new).and_return(windows_networking_interface) allow(windows_networking_interface).to receive(:call_the_resolver).and_return(resolved_fact) - searched_fact = instance_spy(Facter::SearchedFact, name: 'network_.*', fact_class: networking_interface_class_spy, filter_tokens: [], user_query: '', type: :core) @@ -39,7 +34,7 @@ context 'when there are multiple search facts pointing to the same fact' do before do - resolved_fact = mock_resolved_fact('os', 'Ubuntu', nil, []) + resolved_fact = mock_resolved_fact('os', 'Debian', nil, []) allow(os_name_class_spy).to receive(:new).and_return(os_name_instance_spy) allow(os_name_instance_spy).to receive(:call_the_resolver).and_return(resolved_fact) @@ -58,5 +53,45 @@ expect(os_name_instance_spy).to have_received(:call_the_resolver).once end end + + context 'when fact throws exception' do + let(:searched_fact) do + instance_spy(Facter::SearchedFact, + name: 'os', + fact_class: os_name_class_spy, + filter_tokens: [], + user_query: '', + type: :core) + end + + let(:multi_logger_double) { instance_spy(Facter::MultiLogger) } + + before do + allow(os_name_class_spy).to receive(:new).and_return(os_name_instance_spy) + + exception = StandardError.new('error') + exception.set_backtrace(%w[error backtrace]) + allow(os_name_instance_spy).to receive(:call_the_resolver).and_raise(exception) + + allow(multi_logger_double).to receive(:error) + Facter::Log.class_variable_set(:@@logger, multi_logger_double) + end + + after do + Facter::Log.class_variable_set(:@@logger, Facter::MultiLogger.new([])) + end + + it 'does not store the fact value' do + resolved_facts = internal_fact_manager.resolve_facts([searched_fact]) + + expect(resolved_facts).to match_array [] + end + + it 'logs backtrace as error' do + internal_fact_manager.resolve_facts([searched_fact]) + + expect(multi_logger_double).to have_received(:error).with("Facter::InternalFactManager - error\nbacktrace") + end + end end end From 58e1f833fd5dd653c32baed74f0a0b5c42c73423 Mon Sep 17 00:00:00 2001 From: Andrei Filipovici Date: Tue, 28 Apr 2020 16:45:30 +0300 Subject: [PATCH 11/13] (FACT-2542) fixed rubocop offenses --- spec/facter/facter_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/facter/facter_spec.rb b/spec/facter/facter_spec.rb index 87dc4e0e8..824b54a7e 100644 --- a/spec/facter/facter_spec.rb +++ b/spec/facter/facter_spec.rb @@ -154,7 +154,7 @@ def mock_collection(method, os_name = nil, error = nil) # rubocop:enable Style/UnneededInterpolation end - it 'return no value' do + it 'returns no value' do mock_fact_manager(:resolve_facts, []) mock_collection(:value, nil, key_error) From 8d1253f76eca3b0b4b7e02648a8489b3ccd6e76b Mon Sep 17 00:00:00 2001 From: Bogdan Irimie Date: Tue, 28 Apr 2020 17:05:49 +0300 Subject: [PATCH 12/13] (maint) Remove rubycritic from CI (#474) --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3f531d1a7..3dcdce2b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,6 @@ jobs: - rvm: 2.6 script: - bundle exec rubocop - - bundle exec rubycritic --no-browser -f console - bundle exec rake spec - bundle exec rake commits From f32fc2f2b3ec1842d68e129622a7343a96ae6b0d Mon Sep 17 00:00:00 2001 From: Bogdan Irimie Date: Tue, 28 Apr 2020 17:22:42 +0300 Subject: [PATCH 13/13] (FACT-2555)Create OS hierarchy and mechanism for loading it (#470) * (FACT-2555) If no module with the OS name was discovered, log a debug message instead of an error message. * (FACT-2555) Add OsHierarchy Class and json with Os hierarchy definition. * (FACT-2555) Reproduce existing hierarchy in os_hierarchy.json * (FACT-2555) Use OsHierarchy in OsDetector. Rubocop fixes. * (FACT-2555) If the distribution cannot be detected, default to linux * (FACT-2555) Add comments. * (FACT-2555) Add mock for OsHierarchy in OsDetector tests. * (FACT-2555) Add test for fallback to linux in case no distribution is detected. * (FACT-2555) Refactor OsDetector tests. * (FACT-2555) Try to use family to detect os placement in hierarchy. * (FACT-2555) Add mechanism for using os family if no hierarchy can be detected for OS. * (FACT-2555) Add tests for os_hierarchy. * (FACT-2555) Small refactoring of os detector. * (FACT-2555) Add test for family. * (FACT-2555) Force mount-point data to UTF-8 as it might be ASCI in some cases (e.g. when time machine is running on macOS) * (FACT-2555) Move conversion to UTF-8 in helper. * (FACT-2555) Add test for filesusyem_helper. Fix existing tests. * (FACT-2555) Fix os hierarchy for intermediary nodes. Add tests for intermediary and root nodes. * (FACT-2555) Address PR comments. * (FACT-2555) Move the action we are testing in the block. * (FACT-2555) Improve error handling for os_hierarchy. * Revert "(FACT-2555) Add test for filesusyem_helper. Fix existing tests." This reverts commit 0b220cd74fbbd3a32f5684121ce31f5e225b567e. * Revert "(FACT-2555) Move conversion to UTF-8 in helper." This reverts commit a218ac7987fee471253917116cb3e339c90f704d. * Revert "(FACT-2555) Force mount-point data to UTF-8 as it might be ASCI in some cases (e.g. when time machine is running on macOS)" This reverts commit 8cdf10d889e0930a783da3fc624f43561064715b. * (FACT-2555) Add test for cases that throw exceptions. --- .rubocop_todo.yml | 1 + .../core/fact_loaders/class_discoverer.rb | 2 +- lib/framework/core/file_loader.rb | 1 + lib/framework/detector/os_detector.rb | 80 +++---- lib/framework/detector/os_hierarchy.rb | 53 +++++ lib/framework/logging/logger.rb | 2 +- lib/resolvers/redhat_release_resolver.rb | 3 +- lib/resolvers/suse_release_resolver.rb | 4 +- os_hierarchy.json | 33 +++ .../resolvers/redhat_release_resolver_spec.rb | 4 +- .../resolvers/suse_relese_resolver_spec.rb | 4 +- spec/fixtures/broken_os_hierarchy | 32 +++ spec/fixtures/os_hierarchy | 33 +++ spec/framework/detector/os_detector_spec.rb | 204 ++++++++++++++---- spec/framework/detector/os_hierarchy_spec.rb | 93 ++++++++ spec/framework/logging/logger_spec.rb | 2 +- 16 files changed, 454 insertions(+), 97 deletions(-) create mode 100644 lib/framework/detector/os_hierarchy.rb create mode 100644 os_hierarchy.json create mode 100644 spec/fixtures/broken_os_hierarchy create mode 100644 spec/fixtures/os_hierarchy create mode 100644 spec/framework/detector/os_hierarchy_spec.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 625e4ce37..8078b8503 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -90,6 +90,7 @@ RSpec/FilePath: - 'spec/framework/formatters/legacy_fact_formatter_spec.rb' - 'spec/framework/formatters/yaml_fact_formatter_spec.rb' - 'spec/framework/utils/utils_spec.rb' + - 'spec/framework/detector/os_hierarchy_spec.rb' # Offense count: 15 # Configuration parameters: AssignmentOnly. diff --git a/lib/framework/core/fact_loaders/class_discoverer.rb b/lib/framework/core/fact_loaders/class_discoverer.rb index 586ba35a4..ac140f4dc 100644 --- a/lib/framework/core/fact_loaders/class_discoverer.rb +++ b/lib/framework/core/fact_loaders/class_discoverer.rb @@ -15,7 +15,7 @@ def discover_classes(operating_system) find_nested_classes(os_module_name, discovered_classes = []) discovered_classes rescue NameError - @log.error("There is no module named #{operating_system}") + @log.debug("There is no module named #{operating_system}") [] end diff --git a/lib/framework/core/file_loader.rb b/lib/framework/core/file_loader.rb index 711b5a3e4..55818957b 100644 --- a/lib/framework/core/file_loader.rb +++ b/lib/framework/core/file_loader.rb @@ -28,6 +28,7 @@ def load_lib_dirs(*dirs) require "#{ROOT_DIR}/lib/util/file_helper" require "#{ROOT_DIR}/lib/resolvers/base_resolver" +require "#{ROOT_DIR}/lib/framework/detector/os_hierarchy" require "#{ROOT_DIR}/lib/framework/detector/os_detector" require "#{ROOT_DIR}/lib/framework/config/config_reader" diff --git a/lib/framework/detector/os_detector.rb b/lib/framework/detector/os_detector.rb index 03793d40c..1a1ad8fb1 100644 --- a/lib/framework/detector/os_detector.rb +++ b/lib/framework/detector/os_detector.rb @@ -8,31 +8,46 @@ class OsDetector attr_reader :identifier, :version, :hierarchy def initialize(*_args) + @os_hierarchy = Facter::OsHierarchy.new @identifier = detect - @hierarchy = create_hierarchy(@identifier) end + private + def detect host_os = RbConfig::CONFIG['host_os'] - @identifier = case host_os - when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ - :windows - when /darwin|mac os/ - :macosx - when /linux/ - detect_distro - when /bsd/ - :bsd - when /solaris/ - :solaris - when /aix/ - :aix - else - raise "unknown os: #{host_os.inspect}" - end + identifier = case host_os + when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ + :windows + when /darwin|mac os/ + :macosx + when /linux/ + detect_distro + when /bsd/ + :bsd + when /solaris/ + :solaris + when /aix/ + :aix + else + raise "unknown os: #{host_os.inspect}" + end + + @hierarchy = detect_hierarchy(identifier) + @identifier = identifier end - private + def detect_hierarchy(identifier) + hierarchy = @os_hierarchy.construct_hierarchy(identifier) + hierarchy = @os_hierarchy.construct_hierarchy(detect_family) if hierarchy.empty? + hierarchy = @os_hierarchy.construct_hierarchy(:linux) if hierarchy.empty? + + hierarchy + end + + def detect_family + Facter::Resolvers::OsRelease.resolve(:id_like) + end def detect_distro [Facter::Resolvers::OsRelease, @@ -43,33 +58,6 @@ def detect_distro break if @identifier end - @identifier - end - - def create_hierarchy(operating_system) - return [] unless operating_system - - case operating_system.to_sym - when :ubuntu - %w[Debian] - when :elementary - %w[Debian] - when :raspbian - %w[Debian] - when :fedora - %w[El] - when :amzn - %w[El] - when :rhel - %w[El] - when :centos - %w[El] - when :opensuse - %w[Sles] - when :bsd - %w[Solaris Bsd] - else - [operating_system.to_s.capitalize] - end + @identifier&.downcase&.to_sym end end diff --git a/lib/framework/detector/os_hierarchy.rb b/lib/framework/detector/os_hierarchy.rb new file mode 100644 index 000000000..0b227df3e --- /dev/null +++ b/lib/framework/detector/os_hierarchy.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Facter + class OsHierarchy + def initialize + @log = Log.new(self) + json_file = Util::FileHelper.safe_read('os_hierarchy.json') + + begin + @json_os_hierarchy = JSON.parse(json_file) + rescue JSON::ParserError => _e + @log.error('Could not parse os_hierarchy json') + end + end + + def construct_hierarchy(searched_os) + return [] if searched_os.nil? + + searched_os = searched_os.to_s.capitalize + if @json_os_hierarchy.nil? + @log.debug("There is no os_hierarchy, will fall back to: #{searched_os}") + return [searched_os] + end + + @searched_path = [] + search(@json_os_hierarchy, searched_os, []) + + @searched_path.map { |os_name| os_name.to_s.capitalize } + end + + private + + def search(json_data, searched_element, path) + # we hit a dead end, the os was not found on this branch + # and we cannot go deeper + return unless json_data + + json_data.each do |tree_node| + # we found the searched OS, so save the path from the tree + @searched_path = path.dup << tree_node if tree_node == searched_element + + next unless tree_node.is_a?(Hash) + + tree_node.each do |k, v| + return @searched_path = path.dup << k if k == searched_element + + search(v, searched_element, path << k) + path.pop + end + end + end + end +end diff --git a/lib/framework/logging/logger.rb b/lib/framework/logging/logger.rb index a4ed12087..38c6c6d79 100644 --- a/lib/framework/logging/logger.rb +++ b/lib/framework/logging/logger.rb @@ -87,7 +87,7 @@ def warn(msg) def error(msg, colorize = false) @@has_errors = true - msg = colorize(msg, RED) if colorize && !OsDetector.instance.detect.eql?(:windows) + msg = colorize(msg, RED) if colorize && !OsDetector.instance.identifier.eql?(:windows) @@logger.error(@class_name + ' - ' + msg) end diff --git a/lib/resolvers/redhat_release_resolver.rb b/lib/resolvers/redhat_release_resolver.rb index ae4b0be3d..fb89906ae 100644 --- a/lib/resolvers/redhat_release_resolver.rb +++ b/lib/resolvers/redhat_release_resolver.rb @@ -18,7 +18,8 @@ def post_resolve(fact_name) end def read_redhat_release(fact_name) - output, _status = Open3.capture2('cat /etc/redhat-release') + output = Util::FileHelper.safe_read('/etc/redhat-release', nil) + return @fact_list[fact_name] = nil if output.nil? build_fact_list(output) diff --git a/lib/resolvers/suse_release_resolver.rb b/lib/resolvers/suse_release_resolver.rb index 7d3b0cb3f..5bde69b7d 100644 --- a/lib/resolvers/suse_release_resolver.rb +++ b/lib/resolvers/suse_release_resolver.rb @@ -18,7 +18,9 @@ def post_resolve(fact_name) end def read_suse_release(fact_name) - output, _status = Open3.capture2('cat /etc/SuSE-release') + output = Util::FileHelper.safe_read('/etc/SuSE-release', nil) + return @fact_list[fact_name] = nil if output.nil? + output_strings = output.split(' ') @fact_list[:name] = output_strings[0] diff --git a/os_hierarchy.json b/os_hierarchy.json new file mode 100644 index 000000000..f8f523596 --- /dev/null +++ b/os_hierarchy.json @@ -0,0 +1,33 @@ +[ + { + "Linux": [ + { + "Debian": [ + "Elementary", + "Ubuntu", + "Raspbian" + ] + }, + { + "El": [ + "Fedora", + "Amzn", + "Centos" + ] + }, + { + "Sles": [ + "Opensuse" + ] + } + ] + }, + { + "Solaris": [ + "Bsd" + ] + }, + "Macosx", + "Windows", + "Aix" +] diff --git a/spec/facter/resolvers/redhat_release_resolver_spec.rb b/spec/facter/resolvers/redhat_release_resolver_spec.rb index 9704a7e0b..279683c4e 100644 --- a/spec/facter/resolvers/redhat_release_resolver_spec.rb +++ b/spec/facter/resolvers/redhat_release_resolver_spec.rb @@ -2,8 +2,8 @@ describe Facter::Resolvers::RedHatRelease do before do - allow(Open3).to receive(:capture2) - .with('cat /etc/redhat-release') + allow(Facter::Util::FileHelper).to receive(:safe_read) + .with('/etc/redhat-release', nil) .and_return("Red Hat Enterprise Linux Server release 5.10 (Tikanga)\n") end diff --git a/spec/facter/resolvers/suse_relese_resolver_spec.rb b/spec/facter/resolvers/suse_relese_resolver_spec.rb index bd10e3f16..dfe6a3eae 100644 --- a/spec/facter/resolvers/suse_relese_resolver_spec.rb +++ b/spec/facter/resolvers/suse_relese_resolver_spec.rb @@ -2,8 +2,8 @@ describe Facter::Resolvers::SuseRelease do before do - allow(Open3).to receive(:capture2) - .with('cat /etc/SuSE-release') + allow(Facter::Util::FileHelper).to receive(:safe_read) + .with('/etc/SuSE-release', nil) .and_return("openSUSE 11.1 (i586) VERSION = 11.1") end diff --git a/spec/fixtures/broken_os_hierarchy b/spec/fixtures/broken_os_hierarchy new file mode 100644 index 000000000..05db29ddf --- /dev/null +++ b/spec/fixtures/broken_os_hierarchy @@ -0,0 +1,32 @@ +[ + { + "Linux": [ + "Debian": [ + "Elementary", + "Ubuntu", + "Raspbian" + ] + }, + { + "El": [ + "Fedora", + "Amzn", + "Centos" + ] + }, + { + "Sles": [ + "Opensuse" + ] + } + ] + }, + { + "Solaris": [ + "Bsd" + ] + }, + "Macosx", + "Windows", + "Aix" +] diff --git a/spec/fixtures/os_hierarchy b/spec/fixtures/os_hierarchy new file mode 100644 index 000000000..f8f523596 --- /dev/null +++ b/spec/fixtures/os_hierarchy @@ -0,0 +1,33 @@ +[ + { + "Linux": [ + { + "Debian": [ + "Elementary", + "Ubuntu", + "Raspbian" + ] + }, + { + "El": [ + "Fedora", + "Amzn", + "Centos" + ] + }, + { + "Sles": [ + "Opensuse" + ] + } + ] + }, + { + "Solaris": [ + "Bsd" + ] + }, + "Macosx", + "Windows", + "Aix" +] diff --git a/spec/framework/detector/os_detector_spec.rb b/spec/framework/detector/os_detector_spec.rb index 3d6c594d7..190156255 100644 --- a/spec/framework/detector/os_detector_spec.rb +++ b/spec/framework/detector/os_detector_spec.rb @@ -3,68 +3,188 @@ require 'rbconfig' describe OsDetector do + let(:os_hierarchy) { instance_spy(Facter::OsHierarchy) } + before do Singleton.__init__(OsDetector) - end - it 'detects os as macosx' do - RbConfig::CONFIG['host_os'] = 'darwin' - expect(OsDetector.instance.identifier).to eq(:macosx) + allow(Facter::OsHierarchy).to receive(:new).and_return(os_hierarchy) end - it 'detects os as windows' do - RbConfig::CONFIG['host_os'] = 'mingw' - expect(OsDetector.instance.identifier).to eq(:windows) - end + describe 'initialize' do + context 'when os is macosx' do + before do + RbConfig::CONFIG['host_os'] = 'darwin' + allow(os_hierarchy).to receive(:construct_hierarchy).with(:macosx).and_return(['macosx']) + end - it 'detects os as solaris' do - RbConfig::CONFIG['host_os'] = 'solaris' - expect(OsDetector.instance.identifier).to eq(:solaris) - end + it 'detects os as macosx' do + expect(OsDetector.instance.identifier).to eq(:macosx) + end - it 'detects os as aix' do - RbConfig::CONFIG['host_os'] = 'aix' - expect(OsDetector.instance.identifier).to eq(:aix) - end + it 'calls hierarchy construction with macosx identifier' do + OsDetector.instance - it 'raise error if it could not detect os' do - RbConfig::CONFIG['host_os'] = 'os' - expect { OsDetector.instance.identifier }.to raise_error(RuntimeError, 'unknown os: "os"') - end + expect(os_hierarchy).to have_received(:construct_hierarchy).with(:macosx) + end - context 'when host_os is linux' do - before do - RbConfig::CONFIG['host_os'] = 'linux' + it 'construct hierarchy with darwin identifier' do + expect(OsDetector.instance.hierarchy).to eq(['macosx']) + end + end - allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:identifier) - allow(Facter::Resolvers::RedHatRelease).to receive(:resolve).with(:identifier).and_return('RedHat') + context 'when os is windows' do + before do + RbConfig::CONFIG['host_os'] = 'mingw' + allow(os_hierarchy).to receive(:construct_hierarchy).with(:windows).and_return(['windows']) + end - allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:version) - allow(Facter::Resolvers::RedHatRelease).to receive(:resolve).with(:version) - end + it 'detects os as windows' do + expect(OsDetector.instance.identifier).to eq(:windows) + end + + it 'calls hierarchy construction with windows identifier' do + OsDetector.instance + + expect(os_hierarchy).to have_received(:construct_hierarchy).with(:windows) + end - it 'detects linux distro' do - expect(OsDetector.instance.detect).to eql('RedHat') + it 'construct hierarchy with windows identifier' do + expect(OsDetector.instance.hierarchy).to eq(['windows']) + end end - it 'calls Facter::Resolvers::OsRelease with identifier' do - OsDetector.instance - expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:identifier) + context 'when os is solaris' do + before do + RbConfig::CONFIG['host_os'] = 'solaris' + allow(os_hierarchy).to receive(:construct_hierarchy).with(:solaris).and_return(['solaris']) + end + + it 'detects os as solaris' do + expect(OsDetector.instance.identifier).to eq(:solaris) + end + + it 'calls hierarchy construction with solaris identifier' do + OsDetector.instance + + expect(os_hierarchy).to have_received(:construct_hierarchy).with(:solaris) + end + + it 'construct hierarchy with solaris identifier' do + expect(OsDetector.instance.hierarchy).to eq(['solaris']) + end end - it 'calls Facter::Resolvers::RedHatRelease with identifier' do - OsDetector.instance - expect(Facter::Resolvers::RedHatRelease).to have_received(:resolve).with(:identifier) + context 'when os is aix' do + before do + RbConfig::CONFIG['host_os'] = 'aix' + allow(os_hierarchy).to receive(:construct_hierarchy).with(:aix).and_return(['aix']) + end + + it 'detects os as aix' do + expect(OsDetector.instance.identifier).to eq(:aix) + end + + it 'calls hierarchy construction with aix identifier' do + OsDetector.instance + + expect(os_hierarchy).to have_received(:construct_hierarchy).with(:aix) + end + + it 'construct hierarchy with aix identifier' do + expect(OsDetector.instance.hierarchy).to eq(['aix']) + end end - it 'calls Facter::Resolvers::OsRelease with version' do - OsDetector.instance - expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:version) + context 'when os cannot be detected' do + before do + RbConfig::CONFIG['host_os'] = 'my_custom_os' + end + + it 'raises error if it could not detect os' do + expect { OsDetector.instance.identifier }.to raise_error(RuntimeError, 'unknown os: "my_custom_os"') + end end - it 'calls Facter::Resolvers::RedHatRelease with version' do - OsDetector.instance - expect(Facter::Resolvers::RedHatRelease).to have_received(:resolve).with(:version) + context 'when host_os is linux' do + before do + RbConfig::CONFIG['host_os'] = 'linux' + + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:identifier) + allow(Facter::Resolvers::RedHatRelease).to receive(:resolve).with(:identifier).and_return(:redhat) + allow(Facter::Resolvers::SuseRelease).to receive(:resolve).with(:identifier) + + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:version) + allow(Facter::Resolvers::RedHatRelease).to receive(:resolve).with(:version) + allow(Facter::Resolvers::SuseRelease).to receive(:resolve).with(:version) + + allow(os_hierarchy).to receive(:construct_hierarchy).with(:redhat).and_return(%w[linux redhat]) + end + + it 'detects linux distro' do + expect(OsDetector.instance.identifier).to be(:redhat) + end + + it 'calls Facter::OsHierarchy with construct_hierarchy' do + OsDetector.instance + + expect(os_hierarchy).to have_received(:construct_hierarchy).with(:redhat) + end + + it 'calls Facter::Resolvers::OsRelease with identifier' do + OsDetector.instance + + expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:identifier) + end + + it 'calls Facter::Resolvers::RedHatRelease with identifier' do + OsDetector.instance + + expect(Facter::Resolvers::RedHatRelease).to have_received(:resolve).with(:identifier) + end + + it 'calls Facter::Resolvers::OsRelease with version' do + OsDetector.instance + + expect(Facter::Resolvers::OsRelease).to have_received(:resolve).with(:version) + end + + it 'calls Facter::Resolvers::RedHatRelease with version' do + OsDetector.instance + + expect(Facter::Resolvers::RedHatRelease).to have_received(:resolve).with(:version) + end + + context 'when distribution is not known' do + before do + allow(Facter::Resolvers::RedHatRelease).to receive(:resolve).with(:identifier).and_return('my_linux_distro') + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:id_like).and_return(nil) + + allow(os_hierarchy).to receive(:construct_hierarchy).and_return([]) + allow(os_hierarchy).to receive(:construct_hierarchy).with(:linux).and_return(['linux']) + Singleton.__init__(OsDetector) + end + + it 'falls back to linux' do + expect(OsDetector.instance.identifier).to eq(:my_linux_distro) + end + + it 'constructs hierarchy with linux' do + expect(OsDetector.instance.hierarchy).to eq(['linux']) + end + + context 'when family is known' do + before do + allow(Facter::Resolvers::OsRelease).to receive(:resolve).with(:id_like).and_return(:ubuntu) + allow(os_hierarchy).to receive(:construct_hierarchy).with(:ubuntu).and_return(%w[Linux Debian Ubuntu]) + Singleton.__init__(OsDetector) + end + + it 'constructs hierarchy with linux' do + expect(OsDetector.instance.hierarchy).to eq(%w[Linux Debian Ubuntu]) + end + end + end end end end diff --git a/spec/framework/detector/os_hierarchy_spec.rb b/spec/framework/detector/os_hierarchy_spec.rb new file mode 100644 index 000000000..df5daf166 --- /dev/null +++ b/spec/framework/detector/os_hierarchy_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +describe Facter::OsHierarchy do + subject(:os_hierarchy) { Facter::OsHierarchy.new } + + before do + allow(Facter::Util::FileHelper) + .to receive(:safe_read) + .with('os_hierarchy.json') + .and_return(load_fixture('os_hierarchy').read) + allow(Facter::Log).to receive(:new).and_return(log) + end + + let(:log) { instance_spy(Facter::Log) } + + describe '#initialize' do + context 'when os_hierarchy is invalid' do + before do + allow(Facter::Util::FileHelper) + .to receive(:safe_read) + .with('os_hierarchy.json') + .and_return(load_fixture('broken_os_hierarchy').read) + end + + it 'log error message' do + Facter::OsHierarchy.new + expect(log).to have_received(:error).with('Could not parse os_hierarchy json') + end + end + end + + describe '#construct_hierarchy' do + context 'when searched_os is ubuntu' do + it 'constructs hierarchy' do + hierarchy = os_hierarchy.construct_hierarchy(:ubuntu) + + expect(hierarchy).to eq(%w[Linux Debian Ubuntu]) + end + end + + context 'when searched_os is debian' do + it 'constructs hierarchy' do + hierarchy = os_hierarchy.construct_hierarchy(:debian) + + expect(hierarchy).to eq(%w[Linux Debian]) + end + end + + context 'when searched_os is linux' do + it 'constructs hierarchy' do + hierarchy = os_hierarchy.construct_hierarchy(:linux) + + expect(hierarchy).to eq(%w[Linux]) + end + end + + context 'when there is no os hierarchy' do + let(:my_os_name) { 'Myos' } + + before do + allow(JSON).to receive(:parse).and_return(nil) + end + + it 'returns the searched os as the hierarchy' do + hierarchy = os_hierarchy.construct_hierarchy(:myos) + + expect(hierarchy).to eq([my_os_name]) + end + + it 'logs debug message' do + os_hierarchy.construct_hierarchy(:myos) + + expect(log).to have_received(:debug).with("There is no os_hierarchy, will fall back to: #{my_os_name}") + end + end + + context 'when searched_os is nil' do + it 'constructs hierarchy' do + hierarchy = os_hierarchy.construct_hierarchy(nil) + + expect(hierarchy).to eq([]) + end + end + + context 'when searched_os is not in hierarchy' do + it 'constructs hierarchy' do + hierarchy = os_hierarchy.construct_hierarchy(:my_os) + + expect(hierarchy).to eq([]) + end + end + end +end diff --git a/spec/framework/logging/logger_spec.rb b/spec/framework/logging/logger_spec.rb index c421f7a11..20271245c 100644 --- a/spec/framework/logging/logger_spec.rb +++ b/spec/framework/logging/logger_spec.rb @@ -108,7 +108,7 @@ end it 'writes error message not colorized on Windows' do - allow(OsDetector.instance).to receive(:detect).and_return(:windows) + allow(OsDetector.instance).to receive(:identifier).and_return(:windows) log.error('error_message', true)