Skip to content
This repository has been archived by the owner on Jun 19, 2020. It is now read-only.

Commit

Permalink
(maint) Add support for processors facts on FreeBSD
Browse files Browse the repository at this point in the history
Add a basic sysctl(3) FFI wrapper for getting processors information.
This allows Facter 4 to return the same processors facts as returned by
Facter 3 on FreeBSD.
  • Loading branch information
smortex committed May 1, 2020
1 parent 9933642 commit c75b329
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 0 deletions.
17 changes: 17 additions & 0 deletions lib/facts/freebsd/processors/count.rb
Original file line number Diff line number Diff line change
@@ -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
23 changes: 23 additions & 0 deletions lib/facts/freebsd/processors/models.rb
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions lib/facts/freebsd/processors/speed.rb
Original file line number Diff line number Diff line change
@@ -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
42 changes: 42 additions & 0 deletions lib/resolvers/freebsd/ffi/ffi_helper.rb
Original file line number Diff line number Diff line change
@@ -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
34 changes: 34 additions & 0 deletions lib/resolvers/freebsd/processors.rb
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions spec/facter/facts/freebsd/processors/count_spec.rb
Original file line number Diff line number Diff line change
@@ -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
27 changes: 27 additions & 0 deletions spec/facter/facts/freebsd/processors/models_spec.rb
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions spec/facter/facts/freebsd/processors/speed_spec.rb
Original file line number Diff line number Diff line change
@@ -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
45 changes: 45 additions & 0 deletions spec/facter/resolvers/freebsd/processors_spec.rb
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit c75b329

Please sign in to comment.