Skip to content

Commit

Permalink
(FACT-2809) Fixed output differences on solaris
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastian-miclea committed Oct 5, 2020
1 parent 2bcf4a3 commit 1ea61d5
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 7 deletions.
2 changes: 1 addition & 1 deletion lib/facter/facts/solaris/zones.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def call_the_resolver
end

resolved_facts << Facter::ResolvedFact.new('solaris_zones.zones', zones)
resolved_facts << Facter::ResolvedFact.new('zones', results.count.to_s, :legacy)
resolved_facts << Facter::ResolvedFact.new('zones', results.count, :legacy)

resolved_facts.flatten
end
Expand Down
7 changes: 5 additions & 2 deletions lib/facter/resolvers/mountpoints_resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class << self
private

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

def root_device
Expand All @@ -26,7 +26,8 @@ def compute_device(device)
device
end

def read_mounts # rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
def read_mounts(fact_name)
mounts = []
FilesystemHelper.read_mountpoints.each do |fs|
device = compute_device(fs.name)
Expand All @@ -52,7 +53,9 @@ def read_mounts # rubocop:disable Metrics/AbcSize
.map { |v| binding.local_variable_get(v) })]
end
@fact_list[:mountpoints] = mounts
@fact_list[fact_name]
end
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
end
end
end
Expand Down
60 changes: 60 additions & 0 deletions lib/facter/resolvers/solaris/mountpoints.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

module Facter
module Resolvers
module Solaris
class Mountpoints < BaseResolver
include Facter::FilesystemHelper
@fact_list ||= {}
@log = Facter::Log.new(self)
class << self
private

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

def root_device
cmdline = Util::FileHelper.safe_read('/proc/cmdline')
match = cmdline.match(/root=([^\s]+)/)
match&.captures&.first
end

def compute_device(device)
# If the "root" device, lookup the actual device from the kernel options
# This is done because not all systems symlink /dev/root
device = root_device if device == '/dev/root'
device
end

def read_mounts(fact_name) # rubocop:disable Metrics/AbcSize
mounts = []
FilesystemHelper.read_mountpoints.each do |fs|
device = compute_device(fs.name)
filesystem = fs.mount_type
path = fs.mount_point
options = fs.options.split(',').map(&:strip)

stats = FilesystemHelper.read_mountpoint_stats(path)
size_bytes = stats.bytes_total.abs
available_bytes = stats.bytes_available.abs

used_bytes = stats.bytes_used.abs
total_bytes = used_bytes + available_bytes
capacity = FilesystemHelper.compute_capacity(used_bytes, total_bytes)

size = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(size_bytes)
available = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(available_bytes)
used = Facter::FactsUtils::UnitConverter.bytes_to_human_readable(used_bytes)

mounts << Hash[FilesystemHelper::MOUNT_KEYS.zip(FilesystemHelper::MOUNT_KEYS
.map { |v| binding.local_variable_get(v) })]
end
@fact_list[:mountpoints] = mounts
@fact_list[fact_name]
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/facter/resolvers/solaris/networking.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def add_mtu(lifreq)

@log.debug("Error! #{::FFI::LastError.error}") if ioctl == -1

@interfaces[lifreq.name][:mtu] = lifreq[:lifr_lifru][:lifru_metric]
@interfaces[lifreq.name][:mtu] ||= lifreq[:lifr_lifru][:lifru_metric]
end

def load_netmask(lifreq)
Expand Down
2 changes: 1 addition & 1 deletion spec/facter/facts/solaris/zones_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
an_object_having_attributes(name: 'zone_global_status', value: result[:status], type: :legacy),
an_object_having_attributes(name: 'zone_global_brand', value: result[:brand], type: :legacy),
an_object_having_attributes(name: 'zone_global_iptype', value: result[:iptype], type: :legacy),
an_object_having_attributes(name: 'zones', value: '1', type: :legacy)
an_object_having_attributes(name: 'zones', value: 1, type: :legacy)
)
end
end
Expand Down
6 changes: 6 additions & 0 deletions spec/facter/resolvers/mountpoints_resolver_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,10 @@
end
end
end

describe 'resolver key not found' do
it 'returns nil when resolver cannot find key' do
expect(Facter::Resolvers::Mountpoints.resolve(:inexistent_key)).to be_nil
end
end
end
115 changes: 115 additions & 0 deletions spec/facter/resolvers/solaris/mountpoints_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# frozen_string_literal: true

describe Facter::Resolvers::Solaris::Mountpoints do
let(:resolver) { Facter::Resolvers::Solaris::Mountpoints }
let(:mount) do
class_double(Sys::Filesystem::Mount,
mount_point: '/', mount_time: nil,
mount_type: 'ext4', options: 'rw,noatime', name:
'/dev/nvme0n1p2', dump_frequency: 0, pass_number: 0)
end

let(:stat) do
class_double(Sys::Filesystem::Stat,
path: '/', base_type: nil, fragment_size: 4096, block_size: 4096, blocks: 113_879_332,
blocks_available: -16_596_603, blocks_free: 22_398_776)
end

let(:fact) do
[{ available: '63.31 GiB',
available_bytes: 67_979_685_888,
capacity: '84.64%',
device: '/dev/nvme0n1p2',
filesystem: 'ext4',
options: %w[rw noatime],
path: '/',
size: '434.42 GiB',
size_bytes: 466_449_743_872,
used: '348.97 GiB',
used_bytes: 374_704_357_376 }]
end

let(:ignored_mount1) do
[
class_double(
Sys::Filesystem::Mount, mount_type: 'zfs', mount_point: '/system/', name: '/dev/ignore', options: 'rw'
)
]
end

let(:ignored_mount2) do
[
class_double(
Sys::Filesystem::Mount, mount_type: 'autofs', mount_point: '/mnt/auto', name: '/dev/ignore', options: 'rw'
)
]
end

before do
allow(Facter::Util::FileHelper).to receive(:safe_read)
.with('/proc/cmdline')
.and_return(load_fixture('cmdline_root_device').read)

allow(Facter::FilesystemHelper).to receive(:read_mountpoints).and_return([mount])
allow(Facter::FilesystemHelper).to receive(:read_mountpoint_stats).and_return(stat)

# mock sys/filesystem methods
allow(stat).to receive(:bytes_total).and_return(stat.blocks * stat.fragment_size)
allow(stat).to receive(:bytes_available).and_return(stat.blocks_available * stat.fragment_size)
allow(stat).to receive(:bytes_free).and_return(stat.blocks_free * stat.fragment_size)
allow(stat).to receive(:bytes_used).and_return(stat.bytes_total - stat.bytes_free)
resolver.invalidate_cache
end

it 'correctly builds the mountpoints fact' do
result = resolver.resolve(:mountpoints)

expect(result).to eq(fact)
end

it 'does not drop non-tmpfs mounts under /proc or /sys' do
allow(Facter::FilesystemHelper).to receive(:read_mountpoints).and_return(ignored_mount1)

resolver.resolve(:mountpoints)
expect(Facter::FilesystemHelper).to have_received(:read_mountpoint_stats).with('/system/')
end

it 'does not drop automounts mounts under /proc or /sys' do
allow(Facter::FilesystemHelper).to receive(:read_mountpoints).and_return(ignored_mount2)

resolver.resolve(:mountpoints)
expect(Facter::FilesystemHelper).to have_received(:read_mountpoint_stats).with('/mnt/auto')
end

describe '.root_device' do
let(:mount) do
class_double(
Sys::Filesystem::Mount, mount_point: '/', mount_type: 'ext4', options: 'rw,noatime', name: '/dev/root'
)
end

it 'looks up the actual device if /dev/root' do
result = resolver.resolve(:mountpoints)
expect(result.first[:device]).to eq('/dev/mmcblk0p2')
end

context 'when /proc/cmdline is not accessible' do
before do
allow(Facter::Util::FileHelper).to receive(:safe_read)
.with('/proc/cmdline')
.and_return('')
end

it 'returns device as nil' do
result = resolver.resolve(:mountpoints)
expect(result.first[:device]).to be(nil)
end
end
end

describe 'resolver key not found' do
it 'returns nil when resolver cannot find key' do
expect(resolver.resolve(:inexistent_key)).to be_nil
end
end
end
41 changes: 39 additions & 2 deletions spec/mocks/sys_filesystem_mock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,44 @@ module Sys
class Filesystem
def self.mounts; end

class Mount; end
class Stat; end
class Mount
def self.mount_point; end

def self.mount_type; end

def self.options; end

def self.mount_time; end

def self.name; end

def self.dump_frequency; end

def self.pass_number; end
end

class Stat
def self.path; end

def self.base_type; end

def self.fragment_size; end

def self.block_size; end

def self.blocks; end

def self.blocks_available; end

def self.blocks_free; end

def self.bytes_total; end

def self.bytes_available; end

def self.bytes_free; end

def self.bytes_used; end
end
end
end

0 comments on commit 1ea61d5

Please sign in to comment.