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

(maint) Add FreeBSD disks and partitions facts #553

Merged
merged 1 commit into from
Jun 16, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions lib/facts/freebsd/disks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module Facts
module Freebsd
class Disks
FACT_NAME = 'disks'

def call_the_resolver
disks = Facter::Resolvers::Freebsd::Geom.resolve(:disks)

Facter::ResolvedFact.new(FACT_NAME, disks)
end
end
end
end
15 changes: 15 additions & 0 deletions lib/facts/freebsd/partitions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module Facts
module Freebsd
class Partitions
FACT_NAME = 'partitions'

def call_the_resolver
partitions = Facter::Resolvers::Freebsd::Geom.resolve(:partitions)

Facter::ResolvedFact.new(FACT_NAME, partitions)
end
end
end
end
109 changes: 109 additions & 0 deletions lib/resolvers/freebsd/geom_resolver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# frozen_string_literal: true

module Facter
module Resolvers
module Freebsd
class Geom < BaseResolver
@semaphore = Mutex.new
@fact_list ||= {}

class << self
private

def post_resolve(fact_name)
@fact_list.fetch(fact_name) { read_facts(fact_name) }
end

def read_facts(fact_name)
require_relative 'ffi/ffi_helper'
require 'rexml/document'

read_disks
read_partitions

@fact_list[fact_name]
end

def read_disks
@fact_list[:disks] = {}

each_geom_class_provider('DISK') do |provider|
name = provider.get_text('./name').value

@fact_list[:disks][name] = %i[read_model read_serial_number read_size].map do |x|
send(x, provider)
end.inject(:merge)
end
end

def read_partitions
@fact_list[:partitions] = {}

each_geom_class_provider('PART') do |provider|
name = provider.get_text('./name').value

@fact_list[:partitions][name] = %i[read_partlabel read_partuuid read_size].map do |x|
send(x, provider)
end.inject(:merge)
end
end

def each_geom_class_provider(geom_class_name, &block)
REXML::XPath.each(geom_topology, "/mesh/class[name/text() = '#{geom_class_name}']/geom/provider", &block)
end

def read_size(provider)
res = {}
return res unless (mediasize = provider.get_text('mediasize'))

mediasize = Integer(mediasize.value)

res[:size_bytes] = mediasize
res[:size] = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(mediasize)
res
end

def read_model(provider)
res = {}
return res unless (model = provider.get_text('./config/descr'))

res[:model] = model.value
res
end

def read_partlabel(provider)
res = {}
return res unless (rawuuid = provider.get_text('./config/label'))

res[:partlabel] = rawuuid.value
res
end

def read_partuuid(provider)
res = {}
return res unless (rawuuid = provider.get_text('./config/rawuuid'))

res[:partuuid] = rawuuid.value
res
end

def read_serial_number(provider)
res = {}
return res unless (serial_number = provider.get_text('./config/ident'))

res[:serial_number] = serial_number.value
res
end

def geom_topology
@geom_topology ||= REXML::Document.new(geom_confxml)
end

def geom_confxml
Facter::Freebsd::FfiHelper.sysctl_by_name(:string, 'kern.geom.confxml')
end
end
end
end
end
end
35 changes: 35 additions & 0 deletions spec/facter/facts/freebsd/disks_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

describe Facts::Freebsd::Disks do
subject(:fact) { Facts::Freebsd::Disks.new }

let(:disk) do
{
'disks' => {
'sda' => {
'model' => 'Virtual disk',
'size' => '20.00 GiB',
'size_bytes' => 21_474_836_480,
'vendor' => 'VMware'
}
}
}
end

describe '#call_the_resolver' do
before do
allow(Facter::Resolvers::Freebsd::Geom).to receive(:resolve).with(:disks).and_return(disk)
end

it 'calls Facter::Resolvers::Freebsd::Disk' do
fact.call_the_resolver
expect(Facter::Resolvers::Freebsd::Geom).to have_received(:resolve).with(:disks)
end

it 'returns resolved fact with name disk and value' do
expect(fact.call_the_resolver)
.to be_an_instance_of(Facter::ResolvedFact)
.and have_attributes(name: 'disks', value: disk)
end
end
end
33 changes: 33 additions & 0 deletions spec/facter/facts/freebsd/partitions_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

describe Facts::Freebsd::Partitions do
subject(:fact) { Facts::Freebsd::Partitions.new }

let(:partitions) do
{
'ada0p1' => {
'partlabel' => 'gptboot0',
'partuuid' => '503d3458-c135-11e8-bd11-7d7cd061b26f',
'size' => '512.00 KiB',
'size_bytes' => 524_288
}
}
end

describe '#call_the_resolver' do
before do
allow(Facter::Resolvers::Freebsd::Geom).to receive(:resolve).with(:partitions).and_return(partitions)
end

it 'calls Facter::Resolvers::Freebsd::Partitions' do
fact.call_the_resolver
expect(Facter::Resolvers::Freebsd::Geom).to have_received(:resolve).with(:partitions)
end

it 'returns resolved fact with name partitions and value' do
expect(fact.call_the_resolver)
.to be_an_instance_of(Facter::ResolvedFact)
.and have_attributes(name: 'partitions', value: partitions)
end
end
end
59 changes: 59 additions & 0 deletions spec/facter/resolvers/freebsd/geom_resolver_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

describe Facter::Resolvers::Freebsd::Geom do
describe '#resolve' do
subject(:resolver) { Facter::Resolvers::Freebsd::Geom }

before do
allow(Facter::Freebsd::FfiHelper).to receive(:sysctl_by_name)
.with(:string, 'kern.geom.confxml')
.and_return(load_fixture('kern.geom.confxml').read)
end

describe 'disks resolution' do
let(:expected_output) do
{
'ada0' => {
model: 'Samsung SSD 850 PRO 512GB',
serial_number: 'S250NXAG959927J',
size: '476.94 GiB',
size_bytes: 512_110_190_592
}
}
end

it 'returns disks fact' do
expect(resolver.resolve(:disks)).to eql(expected_output)
end
end

describe 'partitions resolution' do
let(:expected_output) do
{
'ada0p1' => {
partlabel: 'gptboot0',
partuuid: '503d3458-c135-11e8-bd11-7d7cd061b26f',
size: '512.00 KiB',
size_bytes: 524_288
},
'ada0p2' => {
partlabel: 'swap0',
partuuid: '5048d40d-c135-11e8-bd11-7d7cd061b26f',
size: '2.00 GiB',
size_bytes: 2_147_483_648
},
'ada0p3' => {
partlabel: 'zfs0',
partuuid: '504f1547-c135-11e8-bd11-7d7cd061b26f',
size: '474.94 GiB',
size_bytes: 509_961_306_112
}
}
end

it 'returns partitions fact' do
expect(resolver.resolve(:partitions)).to eql(expected_output)
end
end
end
end