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

Add support for processors facts on *BSD #489

Merged
merged 3 commits into from
Jun 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Metrics/MethodLength:
- 'lib/custom_facts/core/execution/windows.rb'
- 'lib/custom_facts/core/execution/base.rb'
- 'lib/framework/detector/os_detector.rb'
- 'lib/resolvers/bsd/ffi/ffi_helper.rb'

Metrics/ModuleLength:
Max: 100
Expand Down Expand Up @@ -56,6 +57,7 @@ Metrics/AbcSize:
- 'lib/custom_facts/core/execution/windows.rb'
- 'lib/custom_facts/core/execution/base.rb'
- 'lib/custom_facts/core/resolvable.rb'
- 'lib/resolvers/bsd/ffi/ffi_helper.rb'

Metrics/PerceivedComplexity:
Exclude:
Expand Down
6 changes: 4 additions & 2 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 81
# Offense count: 82
# Configuration parameters: CustomTransform, IgnoreMethods.
RSpec/FilePath:
Exclude:
Expand Down Expand Up @@ -41,6 +41,7 @@ RSpec/FilePath:
- 'spec/facter/resolvers/dmi_resolver_spec.rb'
- 'spec/facter/resolvers/filesystems_resolver_spec.rb'
- 'spec/facter/resolvers/fips_enabled_resolver_spec.rb'
- 'spec/facter/resolvers/freebsd/ffi_helper_spec.rb'
- 'spec/facter/resolvers/identity_resolver_spec.rb'
- 'spec/facter/resolvers/load_averages_resolver_spec.rb'
- 'spec/facter/resolvers/macosx/dmi_resolver_spec.rb'
Expand Down Expand Up @@ -177,7 +178,7 @@ RSpec/SubjectStub:
- 'spec/custom_facts/util/fact_spec.rb'
- 'spec/custom_facts/util/resolution_spec.rb'

# Offense count: 128
# Offense count: 134
# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
RSpec/VerifiedDoubles:
Exclude:
Expand Down Expand Up @@ -211,6 +212,7 @@ RSpec/VerifiedDoubles:
- 'spec/facter/resolvers/aix/ffi_helper_spec.rb'
- 'spec/facter/resolvers/aix/hardware_resolver_spec.rb'
- 'spec/facter/resolvers/bsd/ffi_helper_spec.rb'
- 'spec/facter/resolvers/freebsd/ffi_helper_spec.rb'
- 'spec/facter/resolvers/macosx/mountpoints_resolver_spec.rb'
- 'spec/facter/resolvers/mountpoints_resolver_spec.rb'
- 'spec/facter/resolvers/utils/windows/network_utils_spec.rb'
Expand Down
17 changes: 17 additions & 0 deletions lib/facts/bsd/processors/count.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module Facts
module Bsd
module Processors
class Count
FACT_NAME = 'processors.count'
ALIASES = 'processorcount'

def call_the_resolver
fact_value = Facter::Resolvers::Bsd::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/bsd/processors/models.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

module Facts
module Bsd
module Processors
class Models
FACT_NAME = 'processors.models'
ALIASES = 'processor.*'

def call_the_resolver
fact_value = Facter::Resolvers::Bsd::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/bsd/processors/speed.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module Facts
module Bsd
module Processors
class Speed
FACT_NAME = 'processors.speed'

def call_the_resolver
fact_value = Facter::Resolvers::Bsd::Processors.resolve(:speed)
speed = Facter::FactsUtils::UnitConverter.hertz_to_human_readable(fact_value)
Facter::ResolvedFact.new(FACT_NAME, speed)
end
end
end
end
end
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
31 changes: 31 additions & 0 deletions lib/resolvers/bsd/ffi/ffi_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module Libc

ffi_lib 'c'
attach_function :getloadavg, %i[pointer int], :int
attach_function :sysctl, %i[pointer uint pointer pointer pointer size_t], :int
end

def self.read_load_averages
Expand All @@ -20,6 +21,36 @@ def self.read_load_averages

raw_loadavg.read_array_of_double(res)
end

def self.sysctl(type, oids)
name = FFI::MemoryPointer.new(:uint, oids.size)
name.write_array_of_uint(oids)
namelen = oids.size

oldp = FFI::Pointer::NULL
oldlenp = FFI::MemoryPointer.new(:size_t)

newp = FFI::Pointer::NULL
newlen = 0

if type == :string
res = Libc.sysctl(name, namelen, oldp, oldlenp, newp, newlen)
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.sysctl(name, namelen, oldp, oldlenp, newp, newlen)
return nil if res.negative?

case type
when :string
oldp.read_string
else
oldp.read(type)
end
end
end
end
end
47 changes: 47 additions & 0 deletions lib/resolvers/bsd/processors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

module Facter
module Resolvers
module Bsd
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)
require "#{ROOT_DIR}/lib/resolvers/bsd/ffi/ffi_helper"

@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

CTL_HW = 6
HW_MODEL = 2
HW_NCPU = 3
HW_CPUSPEED = 12

def model
@model ||= Facter::Bsd::FfiHelper.sysctl(:string, [CTL_HW, HW_MODEL])
end

def logical_count
@logical_count ||= Facter::Bsd::FfiHelper.sysctl(:uint32_t, [CTL_HW, HW_NCPU])
end

def speed
@speed ||= Facter::Bsd::FfiHelper.sysctl(:uint32_t, [CTL_HW, HW_CPUSPEED])
end
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some tests for Freebsd :: FfiHelper

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did it, but it raise a few concerns for me because these tests just mock everything and we are testing the mock framework more than anything else 😢

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
44 changes: 44 additions & 0 deletions lib/resolvers/freebsd/processors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

require 'resolvers/bsd/processors'

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)
require "#{ROOT_DIR}/lib/resolvers/freebsd/ffi/ffi_helper"

@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

def model
@model ||= Facter::Freebsd::FfiHelper.sysctl_by_name(:string, 'hw.model')
end

def logical_count
@logical_count ||= Facter::Freebsd::FfiHelper.sysctl_by_name(:uint32_t, 'hw.ncpu')
end

def speed
@speed ||= Facter::Freebsd::FfiHelper.sysctl_by_name(:uint32_t, 'hw.clockrate')
end
end
end
end
end
end
25 changes: 25 additions & 0 deletions spec/facter/facts/bsd/processors/count_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

describe Facts::Bsd::Processors::Count do
describe '#call_the_resolver' do
subject(:fact) { Facts::Bsd::Processors::Count.new }

let(:processors) { '4' }

before do
allow(Facter::Resolvers::Bsd::Processors).to \
receive(:resolve).with(:logical_count).and_return(processors)
end

it 'calls Facter::Resolvers::Bsd::Processors' do
fact.call_the_resolver
expect(Facter::Resolvers::Bsd::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
Loading