Skip to content

Commit

Permalink
(FACT-2721) Added Solaris virtual fact
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastian-miclea committed Aug 20, 2020
1 parent a601821 commit 5d7b20e
Show file tree
Hide file tree
Showing 5 changed files with 418 additions and 0 deletions.
60 changes: 60 additions & 0 deletions lib/facter/facts/solaris/virtual.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

module Facts
module Solaris
class Virtual
FACT_NAME = 'virtual'

def initialize
@log = Facter::Log.new(self)
end

def call_the_resolver
@log.debug('Solaris Virtual Resolver')

fact_value = check_ldom || check_zone || check_xen || check_other_facts || 'physical'

@log.debug("Fact value is: #{fact_value}")

Facter::ResolvedFact.new(FACT_NAME, fact_value)
end

def check_ldom
@log.debug('Checking LDoms')
return unless Facter::Resolvers::Solaris::Ldom.resolve(:role_control) == 'false'

Facter::Resolvers::Solaris::Ldom.resolve(:role_impl)
end

def check_zone
@log.debug('Checking LDoms')
zone_name = Facter::Resolvers::Solaris::ZoneName.resolve(:current_zone_name)

return if zone_name == 'global'

'zone'
end

def check_xen
@log.debug('Checking XEN')
Facter::Resolvers::Xen.resolve(:vm)
end

def check_other_facts
isa = Facter::Resolvers::Uname.resolve(:processor)
klass = isa == 'sparc' ? 'DmiSparc' : 'Dmi'

product_name = Facter::Resolvers::Solaris.const_get(klass).resolve(:product_name)
bios_vendor = Facter::Resolvers::Solaris.const_get(klass).resolve(:bios_vendor)

return 'kvm' if bios_vendor&.include?('Amazon EC2')

return unless product_name

Facter::FactsUtils::HYPERVISORS_HASH.each { |key, value| return value if product_name.include?(key) }

nil
end
end
end
end
70 changes: 70 additions & 0 deletions lib/facter/resolvers/solaris/ldom.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# frozen_string_literal: true

module Facter
module Resolvers
module Solaris
class Ldom < BaseResolver
# :chassis_serial
# :control_domain
# :domain_name
# :domain_uuid
# :role_control
# :role_io
# :role_root
# :role_service
# :role_impl

@semaphore = Mutex.new
@fact_list ||= {}

VIRTINFO_MAPPING = {
chassis_serial: %w[DOMAINCHASSIS serialno],
control_domain: %w[DOMAINCONTROL name],
domain_name: %w[DOMAINNAME name],
domain_uuid: %w[DOMAINUUID uuid],
role_control: %w[DOMAINROLE control],
role_io: %w[DOMAINROLE io],
role_root: %w[DOMAINROLE root],
role_service: %w[DOMAINROLE service],
role_impl: %w[DOMAINROLE impl]
}.freeze

class << self
private

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

def call_virtinfo(fact_name)
# return unless File.executable?('/usr/sbin/virtinfo')

virtinfo_output = Facter::Core::Execution.execute('/usr/sbin/virtinfo -a -p', logger: log)
return if virtinfo_output.empty?

output_hash = parse_output(virtinfo_output)
return if output_hash.empty?

VIRTINFO_MAPPING.each do |key, value|
@fact_list[key] = output_hash.dig(*value)&.strip
end

@fact_list[fact_name]
end

def parse_output(output)
result = {}
output.each_line do |line|
next unless line.include? 'DOMAIN'

x = line.split('|')
result[x.shift] = x.map { |f| f.split('=') }.to_h
end

result
end
end
end
end
end
end
155 changes: 155 additions & 0 deletions spec/facter/facts/solaris/virtual_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# frozen_string_literal: true

describe Facts::Solaris::Virtual do
describe '#call_the_resolver' do
subject(:fact) { Facts::Solaris::Virtual.new }

let(:processor) { 'i386' }

before do
allow(Facter::Resolvers::Uname).to receive(:resolve).with(:processor).and_return(processor)
end

context 'when no hypervisor is found' do
let(:vm) { 'physical' }
let(:current_zone_name) { 'global' }
let(:role_control) { 'false' }

before do
allow(Facter::Resolvers::Solaris::ZoneName)
.to receive(:resolve)
.with(:current_zone_name)
.and_return(current_zone_name)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_impl).and_return(nil)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_control).and_return(nil)
allow(Facter::Resolvers::Solaris::Dmi).to receive(:resolve).with(:product_name).and_return('unkown')
allow(Facter::Resolvers::Solaris::Dmi).to receive(:resolve).with(:bios_vendor).and_return('unkown')
allow(Facter::Resolvers::VirtWhat).to receive(:resolve).with(:vm).and_return(nil)
end

it 'returns virtual fact as physical' do
expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \
have_attributes(name: 'virtual', value: vm)
end
end

context 'when ldom hypervisor is found' do
let(:vm) { 'LDoms' }
let(:current_zone_name) { 'global' }

before do
allow(Facter::Resolvers::Solaris::ZoneName)
.to receive(:resolve)
.with(:current_zone_name)
.and_return(current_zone_name)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_impl).and_return(vm)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_control).and_return(role_control)
end

context 'when role_control is false' do
let(:role_control) { 'false' }

it 'returns virtual fact as physical' do
expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \
have_attributes(name: 'virtual', value: vm)
end
end

context 'when role_control is true' do
let(:role_control) { 'true' }
let(:vm) { 'physical' }

it 'returns virtual fact as physical' do
expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \
have_attributes(name: 'virtual', value: vm)
end
end
end

context 'when zone hypervisor is found' do
let(:vm) { 'zone' }

before do
allow(Facter::Resolvers::Solaris::ZoneName).to receive(:resolve).with(:current_zone_name).and_return(vm)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_impl).and_return(nil)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_control).and_return(nil)
end

it 'returns virtual fact as physical' do
expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \
have_attributes(name: 'virtual', value: vm)
end
end

context 'when xen hypervisor is found' do
let(:current_zone_name) { 'global' }
let(:role_control) { 'false' }
let(:xen_vm) { 'xenhvm' }

before do
allow(Facter::Resolvers::Solaris::ZoneName)
.to receive(:resolve)
.with(:current_zone_name)
.and_return(current_zone_name)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_impl).and_return(nil)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_control).and_return(nil)
allow(Facter::Resolvers::Solaris::Dmi).to receive(:resolve).with(:product_name).and_return('unkown')
allow(Facter::Resolvers::Solaris::Dmi).to receive(:resolve).with(:bios_vendor).and_return('unkown')
allow(Facter::Resolvers::Xen).to receive(:resolve).with(:vm).and_return(xen_vm)
end

it 'returns virtual fact' do
expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \
have_attributes(name: 'virtual', value: xen_vm)
end
end

context 'when other hypervisors' do
let(:vm) { 'global' }

before do
allow(Facter::Resolvers::Solaris::ZoneName).to receive(:resolve).with(:current_zone_name).and_return(vm)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_impl).and_return(nil)
allow(Facter::Resolvers::Solaris::Ldom).to receive(:resolve).with(:role_control).and_return(nil)
end

context 'when processor is i386' do
let(:processor) { 'i386' }
let(:dmi) { class_double(Facter::Resolvers::Solaris::Dmi).as_stubbed_const }

before do
allow(dmi).to receive(:resolve)
end

it 'calls Dmi resolver for product_name' do
fact.call_the_resolver
expect(dmi).to have_received(:resolve).with(:product_name)
end

it 'calls Dmi resolver for bios_vendor' do
fact.call_the_resolver
expect(dmi).to have_received(:resolve).with(:bios_vendor)
end
end

context 'when processor is sparc' do
let(:processor) { 'sparc' }
let(:dmi) { class_double(Facter::Resolvers::Solaris::DmiSparc).as_stubbed_const }

before do
allow(dmi).to receive(:resolve)
end

it 'calls DmiSparc resolver for product_name' do
fact.call_the_resolver
expect(dmi).to have_received(:resolve).with(:product_name)
end

it 'calls DmiSparc resolver for bios_vendor' do
fact.call_the_resolver
expect(dmi).to have_received(:resolve).with(:bios_vendor)
end
end
end
end
end
Loading

0 comments on commit 5d7b20e

Please sign in to comment.