diff --git a/lib/facts/freebsd/processors/count.rb b/lib/facts/freebsd/processors/count.rb new file mode 100644 index 000000000..5d7e165ae --- /dev/null +++ b/lib/facts/freebsd/processors/count.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Facts + module Freebsd + module Processors + class Count + FACT_NAME = 'processors.count' + ALIASES = 'processorcount' + + def call_the_resolver + fact_value = Facter::Resolvers::Freebsd::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/freebsd/processors/models.rb b/lib/facts/freebsd/processors/models.rb new file mode 100644 index 000000000..5593df70b --- /dev/null +++ b/lib/facts/freebsd/processors/models.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Facts + module Freebsd + module Processors + class Models + FACT_NAME = 'processors.models' + ALIASES = 'processor.*' + + def call_the_resolver + fact_value = Facter::Resolvers::Freebsd::Processors.resolve(:models) + return nil unless fact_value + + 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/freebsd/processors/speed.rb b/lib/facts/freebsd/processors/speed.rb new file mode 100644 index 000000000..078cb5709 --- /dev/null +++ b/lib/facts/freebsd/processors/speed.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Facts + module Freebsd + module Processors + class Speed + FACT_NAME = 'processors.speed' + + def call_the_resolver + fact_value = Facter::Resolvers::Freebsd::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/resolvers/freebsd/ffi/ffi_helper.rb b/lib/resolvers/freebsd/ffi/ffi_helper.rb new file mode 100644 index 000000000..db3cd6403 --- /dev/null +++ b/lib/resolvers/freebsd/ffi/ffi_helper.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'ffi' + +module Facter + module Freebsd + module FfiHelper + module Libc + extend FFI::Library + + ffi_lib 'c' + attach_function :sysctlbyname, %i[string pointer pointer pointer size_t], :int + end + + def self.sysctl_by_name(type, name) + oldp = FFI::Pointer::NULL + oldlenp = FFI::MemoryPointer.new(:size_t) + + newp = FFI::Pointer::NULL + newlenp = 0 + + if type == :string + res = Libc.sysctlbyname(name, oldp, oldlenp, newp, newlenp) + return nil if res.negative? + else + oldlenp.write(:size_t, FFI.type_size(type)) + end + + oldp = FFI::MemoryPointer.new(:uint8_t, oldlenp.read(:size_t)) + res = Libc.sysctlbyname(name, oldp, oldlenp, newp, newlenp) + return nil if res.negative? + + case type + when :string + oldp.read_string + else + oldp.read(type) + end + end + end + end +end diff --git a/lib/resolvers/freebsd/processors.rb b/lib/resolvers/freebsd/processors.rb new file mode 100644 index 000000000..0993f9a1d --- /dev/null +++ b/lib/resolvers/freebsd/processors.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'resolvers/freebsd/ffi/ffi_helper' + +module Facter + module Resolvers + module Freebsd + 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_processors_info(fact_name) } + end + + def collect_processors_info(fact_name) + logical_count = Facter::Freebsd::FfiHelper.sysctl_by_name(:uint32_t, 'hw.ncpu') + model = Facter::Freebsd::FfiHelper.sysctl_by_name(:string, 'hw.model') + speed = Facter::Freebsd::FfiHelper.sysctl_by_name(:uint32_t, 'hw.clockrate') + + @fact_list[:logical_count] = logical_count + @fact_list[:models] = Array.new(logical_count, model) if logical_count && model + @fact_list[:speed] = speed * 1000 * 1000 if speed + + @fact_list[fact_name] + end + end + end + end + end +end diff --git a/spec/facter/facts/freebsd/processors/count_spec.rb b/spec/facter/facts/freebsd/processors/count_spec.rb new file mode 100644 index 000000000..49e14ad42 --- /dev/null +++ b/spec/facter/facts/freebsd/processors/count_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +describe Facts::Freebsd::Processors::Count do + describe '#call_the_resolver' do + subject(:fact) { Facts::Freebsd::Processors::Count.new } + + let(:processors) { '4' } + + before do + allow(Facter::Resolvers::Freebsd::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::Freebsd::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/freebsd/processors/models_spec.rb b/spec/facter/facts/freebsd/processors/models_spec.rb new file mode 100644 index 000000000..bcba2442b --- /dev/null +++ b/spec/facter/facts/freebsd/processors/models_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +describe Facts::Freebsd::Processors::Models do + describe '#call_the_resolver' do + subject(:fact) { Facts::Freebsd::Processors::Models.new } + + let(:value) { 'Intel(R) Core(TM) i7-4980HQ CPU @ 2.80GHz' } + let(:models) { [value, value] } + + before do + allow(Facter::Resolvers::Freebsd::Processors).to \ + receive(:resolve).with(:models).and_return(models) + end + + it 'calls Facter::Resolvers::Freebsd::Processors' do + fact.call_the_resolver + expect(Facter::Resolvers::Freebsd::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/freebsd/processors/speed_spec.rb b/spec/facter/facts/freebsd/processors/speed_spec.rb new file mode 100644 index 000000000..02b713803 --- /dev/null +++ b/spec/facter/facts/freebsd/processors/speed_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +describe Facts::Freebsd::Processors::Speed do + describe '#call_the_resolver' do + subject(:fact) { Facts::Freebsd::Processors::Speed.new } + + let(:speed) { 1_800_000_000 } + let(:converted_speed) { '1.80 GHz' } + + before do + allow(Facter::Resolvers::Freebsd::Processors).to \ + receive(:resolve).with(:speed).and_return(speed) + end + + it 'calls Facter::Resolvers::Macosx::Processors' do + fact.call_the_resolver + expect(Facter::Resolvers::Freebsd::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/resolvers/freebsd/processors_spec.rb b/spec/facter/resolvers/freebsd/processors_spec.rb new file mode 100644 index 000000000..5e9e887e8 --- /dev/null +++ b/spec/facter/resolvers/freebsd/processors_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +describe Facter::Resolvers::Freebsd::Processors do + subject(:resolver) { Facter::Resolvers::Freebsd::Processors } + + let(:log_spy) { instance_spy(Facter::Log) } + 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(:speed_expected) { 2_592_000_000 } + + before do + allow(Facter::Freebsd::FfiHelper) + .to receive(:sysctl_by_name) + .with(:uint32_t, 'hw.ncpu') + .and_return(logicalcount) + allow(Facter::Freebsd::FfiHelper) + .to receive(:sysctl_by_name) + .with(:string, 'hw.model') + .and_return(models[0]) + allow(Facter::Freebsd::FfiHelper) + .to receive(:sysctl_by_name) + .with(:uint32_t, 'hw.clockrate') + .and_return(2592) + + resolver.instance_variable_set(:@log, log_spy) + end + + after do + resolver.invalidate_cache + end + + it 'returns number of processors' do + expect(resolver.resolve(:logical_count)).to eq(logicalcount) + 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