diff --git a/lib/facter/facts/solaris/disks.rb b/lib/facter/facts/solaris/disks.rb new file mode 100644 index 0000000000..a4d926d71b --- /dev/null +++ b/lib/facter/facts/solaris/disks.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Facts + module Solaris + class Disks + FACT_NAME = 'disks' + + def call_the_resolver + fact_value = Facter::Resolvers::Solaris::Disks.resolve(:disks) + Facter::ResolvedFact.new(FACT_NAME, fact_value) + end + end + end +end diff --git a/lib/facter/resolvers/load_averages.rb b/lib/facter/resolvers/load_averages.rb index 9e2914a1c3..7224f82cb8 100644 --- a/lib/facter/resolvers/load_averages.rb +++ b/lib/facter/resolvers/load_averages.rb @@ -14,6 +14,8 @@ def post_resolve(fact_name) def read_load_averages(fact_name) require_relative 'utils/ffi/load_averages' + + log.debug('loading cpu load averages') @fact_list[:load_averages] = %w[1m 5m 15m].zip(Utils::Ffi::LoadAverages.read_load_averages).to_h @fact_list[fact_name] diff --git a/lib/facter/resolvers/solaris/disks.rb b/lib/facter/resolvers/solaris/disks.rb new file mode 100644 index 0000000000..8ae202fc9a --- /dev/null +++ b/lib/facter/resolvers/solaris/disks.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module Facter + module Resolvers + module Solaris + class Disks < BaseResolver + @semaphore = Mutex.new + @fact_list ||= {} + + class << self + private + + def post_resolve(fact_name) + @fact_list.fetch(fact_name) { read_disks_info(fact_name) } + end + + def read_disks_info(fact_name) + return unless File.executable?('/usr/bin/kstat') + + log.debug('loading disks info') + + kstat_output = Facter::Core::Execution.execute('/usr/bin/kstat sderr', logger: log) + return if kstat_output.empty? + + @fact_list[fact_name] = parse(kstat_output) + end + + def parse(kstat_output) + disks = {} + + names = kstat_output.scan(/name:\s+(\w+)/).flatten + products = kstat_output.scan(/Product\s+(.+)/).flatten + vendors = kstat_output.scan(/Vendor\s+(\w+)/).flatten + sizes = kstat_output.scan(/Size\s+(\w+)/).flatten + + names.each_with_index do |name, index| + disk_size = sizes[index].to_i + disks[name] = { + product: products[index], + size: Facter::FactsUtils::UnitConverter.bytes_to_human_readable(disk_size), + size_bytes: disk_size, + vendor: vendors[index] + } + end + disks + end + end + end + end + end +end diff --git a/spec/facter/facts/solaris/disks_spec.rb b/spec/facter/facts/solaris/disks_spec.rb new file mode 100644 index 0000000000..afbb8205f1 --- /dev/null +++ b/spec/facter/facts/solaris/disks_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +describe Facts::Solaris::Disks do + describe '#call_the_resolver' do + subject(:fact) { Facts::Solaris::Disks.new } + + let(:value) do + { + 'sd0' => { + 'product' => 'VMware IDE CDR00Revision', + 'size' => '0 bytes', + 'size_bytes' => 0, + 'vendor' => 'NECVMWar' + }, + 'sd1' => { + 'product' => 'Virtual disk Revision', + 'size' => '20.00 GiB', + 'size_bytes' => 21_474_836_480, + 'vendor' => 'VMware' + } + } + end + + before do + allow(Facter::Resolvers::Solaris::Disks).to receive(:resolve).with(:disks).and_return(value) + end + + it 'calls Facter::Resolvers::Solaris::Disks' do + fact.call_the_resolver + expect(Facter::Resolvers::Solaris::Disks).to have_received(:resolve).with(:disks) + end + + it 'returns disks fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'disks', value: value) + end + end +end diff --git a/spec/facter/resolvers/solaris/disks_spec.rb b/spec/facter/resolvers/solaris/disks_spec.rb new file mode 100644 index 0000000000..47526294bc --- /dev/null +++ b/spec/facter/resolvers/solaris/disks_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +describe Facter::Resolvers::Solaris::Disks do + subject(:resolver) { Facter::Resolvers::Solaris::Disks } + + before do + allow(File).to receive(:executable?).with('/usr/bin/kstat').and_return(status) + allow(Facter::Core::Execution) + .to receive(:execute) + .with('/usr/bin/kstat sderr', logger: resolver.log) + .and_return(output) + end + + after do + resolver.invalidate_cache + end + + context 'when kstat is present and can retrieve information' do + let(:value) do + { + 'sd0' => { + product: 'VMware IDE CDR00Revision', + size: '0 bytes', + size_bytes: 0, + vendor: 'NECVMWar' + }, + 'sd1' => { + product: 'Virtual disk Revision', + size: '20.00 GiB', + size_bytes: 21_474_836_480, + vendor: 'VMware' + } + } + end + let(:status) { true } + let(:output) { load_fixture('kstat_sderr').read } + + it 'returns disks info' do + expect(resolver.resolve(:disks)).to eq(value) + end + end + + context 'when kstat is not present' do + let(:output) { '' } + let(:status) { false } + + it 'returns nil' do + expect(resolver.resolve(:disks)).to be_nil + end + end + + context 'when kstat is present but fails' do + let(:output) { '' } + let(:status) { true } + + it 'returns nil' do + expect(resolver.resolve(:disks)).to be_nil + end + end +end diff --git a/spec/fixtures/kstat_sderr b/spec/fixtures/kstat_sderr new file mode 100644 index 0000000000..05beb473c3 --- /dev/null +++ b/spec/fixtures/kstat_sderr @@ -0,0 +1,39 @@ +module: sderr instance: 0 +name: sd0,err class: device_error + Device Not Ready 0 + Hard Errors 0 + Illegal Request 1 + Media Error 0 + No Device 0 + Non-Aligned Writes 0 + Predictive Failure Analysis 0 + Product VMware IDE CDR00Revision + Recoverable 0 + Revision 1.00 + Serial No + Size 0 + Soft Errors 0 + Transport Errors 0 + Vendor NECVMWar + crtime 36.863598884 + snaptime 10853.889452697 + +module: sderr instance: 1 +name: sd1,err class: device_error + Device Not Ready 0 + Hard Errors 0 + Illegal Request 8 + Media Error 0 + No Device 0 + Non-Aligned Writes 0 + Predictive Failure Analysis 0 + Product Virtual disk Revision + Recoverable 0 + Revision 1.0 + Serial No + Size 21474836480 + Soft Errors 0 + Transport Errors 0 + Vendor VMware + crtime 36.668316603 + snaptime 10853.889846855