diff --git a/lib/facts/linux/virtual.rb b/lib/facts/linux/virtual.rb index e8632dba4..577ed93e2 100644 --- a/lib/facts/linux/virtual.rb +++ b/lib/facts/linux/virtual.rb @@ -7,6 +7,7 @@ class Virtual def call_the_resolver fact_value = check_docker_lxc || check_gce || retrieve_from_virt_what || check_vmware + fact_value ||= check_open_vz || check_vserver Facter::ResolvedFact.new(FACT_NAME, fact_value) end @@ -27,6 +28,14 @@ def check_vmware def retrieve_from_virt_what Facter::Resolvers::VirtWhat.resolve(:vm) end + + def check_open_vz + Facter::Resolvers::OpenVz.resolve(:vm) + end + + def check_vserver + Facter::Resolvers::VirtWhat.resolve(:vserver) + end end end end diff --git a/lib/resolvers/open_vz.rb b/lib/resolvers/open_vz.rb new file mode 100644 index 000000000..aae722997 --- /dev/null +++ b/lib/resolvers/open_vz.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Facter + module Resolvers + class OpenVz < BaseResolver + # build + + @semaphore = Mutex.new + @fact_list ||= {} + + class << self + private + + def post_resolve(fact_name) + @fact_list.fetch(fact_name) { check_proc_vz(fact_name) } + end + + def check_proc_vz(fact_name) + if !Dir.exist?('/proc/vz') || !File.executable?('/proc/lve/list') || Dir.entries('/proc/vz').count.equal?(2) + return + end + + @fact_list[:vm] = read_proc_status + @fact_list[fact_name] + end + + def read_proc_status + proc_status_content = Facter::Util::FileHelper.safe_readlines('/proc/self/status', nil) + return unless proc_status_content + + proc_status_content.each do |line| + parts = line.split("\s") + next unless parts.size.equal?(2) + + next unless /^envID:/.match?(parts[0]) + + return 'openvzhn' if parts[1] == '0' + + return 'openvzve' + end + end + end + end + end +end diff --git a/spec/facter/facts/linux/virtual_spec.rb b/spec/facter/facts/linux/virtual_spec.rb index 1cff2a194..1b37a5672 100644 --- a/spec/facter/facts/linux/virtual_spec.rb +++ b/spec/facter/facts/linux/virtual_spec.rb @@ -64,6 +64,35 @@ end end + context 'when is openVz' do + let(:vm) { nil } + let(:value) { 'openvzve' } + + before do + allow(Facter::Resolvers::OpenVz).to receive(:resolve).with(:vm).and_return(value) + end + + it 'returns virtual fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'virtual', value: value) + end + end + + context 'when is vserver' do + let(:vm) { nil } + let(:value) { 'vserver_host' } + + before do + allow(Facter::Resolvers::VirtWhat).to receive(:resolve).with(:vm).and_return(nil) + allow(Facter::Resolvers::VirtWhat).to receive(:resolve).with(:vserver).and_return(value) + end + + it 'returns virtual fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'virtual', value: value) + end + end + context 'when resolver returns nil' do let(:vm) { nil } diff --git a/spec/facter/resolvers/open_vz_spec.rb b/spec/facter/resolvers/open_vz_spec.rb new file mode 100644 index 000000000..ccdebfde1 --- /dev/null +++ b/spec/facter/resolvers/open_vz_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +describe Facter::Resolvers::OpenVz do + subject(:openvz_resolver) { Facter::Resolvers::OpenVz } + + let(:log_spy) { instance_spy(Facter::Log) } + let(:vz_dir) { true } + let(:list_executable) { true } + + after do + openvz_resolver.invalidate_cache + end + + before do + openvz_resolver.instance_variable_set(:@log, log_spy) + allow(Dir).to receive(:exist?).with('/proc/vz').and_return(vz_dir) + allow(File).to receive(:executable?).with('/proc/lve/list').and_return(list_executable) + allow(Dir).to receive(:entries).with('/proc/vz').and_return(vz_dir_entries) + end + + context 'when /proc/vz dir is empty' do + let(:vz_dir_entries) { ['.', '..'] } + + it 'returns nil' do + expect(openvz_resolver.resolve(:vm)).to be_nil + end + end + + context 'when /proc/vz dir is not empty' do + let(:vz_dir_entries) { ['.', '..', 'some_file.txt'] } + + before do + allow(Facter::Util::FileHelper).to receive(:safe_readlines).with('/proc/self/status', nil).and_return(status_file) + end + + context 'when /proc/self/status is nil' do + let(:status_file) { nil } + + it 'returns nil' do + expect(openvz_resolver.resolve(:vm)).to be_nil + end + end + + context 'when /proc/self/status is readable' do + let(:status_file) { load_fixture('proc_self_status').readlines } + + it 'returns openvzhn' do + expect(openvz_resolver.resolve(:vm)).to eql('openvzhn') + end + end + end +end diff --git a/spec/fixtures/proc_self_status b/spec/fixtures/proc_self_status index 329cbcc9e..a87efa8aa 100644 --- a/spec/fixtures/proc_self_status +++ b/spec/fixtures/proc_self_status @@ -13,5 +13,6 @@ Groups: 4 20 24 25 27 29 30 44 46 108 114 1000 NStgid: 14437 NSpid: 14437 NSpgid: 14437 +envID: 0 NSsid: 14122 VxID: 0 \ No newline at end of file