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

Commit

Permalink
(FACT-2602) Add docker/Lxc resolver for Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
Oana Tanasoiu committed May 18, 2020
1 parent af08f87 commit 2625f6f
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 0 deletions.
18 changes: 18 additions & 0 deletions lib/facts/linux/hypervisors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module Facts
module Linux
class Hypervisors
FACT_NAME = 'hypervisors'

def call_the_resolver
fact_value = check_docker_lxc
Facter::ResolvedFact.new(FACT_NAME, fact_value)
end

def check_docker_lxc
Facter::Resolvers::DockerLxc.resolve(:hypervisor)
end
end
end
end
14 changes: 14 additions & 0 deletions lib/facts/linux/virtual.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

module Facts
module Linux
class Virtual
FACT_NAME = 'virtual'

def call_the_resolver
fact_value = Facter::Resolvers::DockerLxc.resolve(:vm)
Facter::ResolvedFact.new(FACT_NAME, fact_value)
end
end
end
end
49 changes: 49 additions & 0 deletions lib/resolvers/docker_lxc.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

module Facter
module Resolvers
class DockerLxc < BaseResolver
# :virtual
# :hypervisor

@semaphore = Mutex.new
@fact_list ||= {}
INFO = { 'docker' => 'id', 'lxc' => 'name' }.freeze

class << self
private

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

def read_cgroup(fact_name)
output_cgroup = Util::FileHelper.safe_read('/proc/1/cgroup', nil)
output_environ = Util::FileHelper.safe_read('/proc/1/environ', nil)
return if output_cgroup.nil? || output_environ.nil?

output_docker = %r{docker/(.+)}.match(output_cgroup)
output_lxc = %r{^/lxc/([^/]+)}.match(output_cgroup)
lxc_from_environ = /container=lxc/ =~ output_environ

info, vm = extract_vm_and_info(output_docker, output_lxc, lxc_from_environ)
@fact_list[:vm] = vm
@fact_list[:hypervisor] = { vm.to_sym => info } if vm
@fact_list[fact_name]
end

def extract_vm_and_info(output_docker, output_lxc, lxc_from_environ)
vm = nil
if output_docker
vm = 'docker'
info = output_docker[1]
end
vm = 'lxc' if output_lxc || lxc_from_environ
info = output_lxc[1] if output_lxc

[info ? { INFO[vm] => info } : {}, vm]
end
end
end
end
end
49 changes: 49 additions & 0 deletions spec/facter/facts/linux/hypervisors_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

describe Facts::Linux::Hypervisors do
describe '#call_the_resolver' do
subject(:fact) { Facts::Linux::Hypervisors.new }

before do
allow(Facter::Resolvers::DockerLxc).to \
receive(:resolve).with(:hypervisor).and_return(hv)
end

context 'when resolver returns docker' do
let(:hv) { { 'docker' => { 'id' => 'testid' } } }

it 'calls Facter::Resolvers::DockerLxc' do
fact.call_the_resolver
expect(Facter::Resolvers::DockerLxc).to have_received(:resolve).with(:hypervisor)
end

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

context 'when resolver returns lxc' do
let(:hv) { { 'lxc' => { 'name' => 'test_name' } } }

it 'calls Facter::Resolvers::DockerLxc' do
fact.call_the_resolver
expect(Facter::Resolvers::DockerLxc).to have_received(:resolve).with(:hypervisor)
end

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

context 'when resolver returns nil' do
let(:hv) { nil }

it 'returns virtual fact as nil' do
expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \
have_attributes(name: 'hypervisors', value: hv)
end
end
end
end
33 changes: 33 additions & 0 deletions spec/facter/facts/linux/virtual_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

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

let(:vm) { 'docker' }

before do
allow(Facter::Resolvers::DockerLxc).to \
receive(:resolve).with(:vm).and_return(vm)
end

it 'calls Facter::Resolvers::DockerLxc' do
fact.call_the_resolver
expect(Facter::Resolvers::DockerLxc).to have_received(:resolve).with(: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: vm)
end

context 'when resolver returns nil' do
let(:vm) { nil }

it 'returns virtual fact as nil' do
expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \
have_attributes(name: 'virtual', value: vm)
end
end
end
end
74 changes: 74 additions & 0 deletions spec/facter/resolvers/docker_lxc_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# frozen_string_literal: true

describe Facter::Resolvers::DockerLxc do
subject(:docker_lxc_resolver) { Facter::Resolvers::DockerLxc }

before do
allow(Facter::Util::FileHelper).to receive(:safe_read)
.with('/proc/1/cgroup', nil)
.and_return(cgroup_output)
allow(Facter::Util::FileHelper).to receive(:safe_read)
.with('/proc/1/environ', nil)
.and_return(environ_output)
end

after do
docker_lxc_resolver.invalidate_cache
end

context 'when hypervisor is docker' do
let(:cgroup_output) { load_fixture('docker_cgroup').read }
let(:environ_output) { 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' }
let(:result) { { docker: { 'id' => 'ee6e3c05422f1273c9b41a26f2b4ec64bdb4480d63a1ad9741e05cafc1651b90' } } }

it 'return docker for vm' do
expect(docker_lxc_resolver.resolve(:vm)).to eq('docker')
end

it 'return docker info for hypervisor' do
expect(docker_lxc_resolver.resolve(:hypervisor)).to eq(result)
end
end

context 'when hypervisor is lxc and it is discovered by cgroup' do
let(:cgroup_output) { load_fixture('lxc_cgroup').read }
let(:environ_output) { 'PATH=/usr/local/sbin:/sbin:/bin' }
let(:result) { { lxc: { 'name' => 'lxc_container' } } }

it 'return lxc for vm' do
expect(docker_lxc_resolver.resolve(:vm)).to eq('lxc')
end

it 'return lxc info for hypervisor' do
expect(docker_lxc_resolver.resolve(:hypervisor)).to eq(result)
end
end

context 'when hypervisor is lxc and it is discovered by environ' do
let(:cgroup_output) { load_fixture('cgroup_file').read }
let(:environ_output) { 'container=lxcroot' }
let(:result) { { lxc: {} } }

it 'return lxc for vm' do
expect(docker_lxc_resolver.resolve(:vm)).to eq('lxc')
end

it 'return lxc info for hypervisor' do
expect(docker_lxc_resolver.resolve(:hypervisor)).to eq(result)
end
end

context 'when hypervisor is neighter lxc nor docker' do
let(:cgroup_output) { load_fixture('cgroup_file').read }
let(:environ_output) { 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin' }
let(:result) { nil }

it 'return lxc for vm' do
expect(docker_lxc_resolver.resolve(:vm)).to eq(nil)
end

it 'return lxc info for hypervisor' do
expect(docker_lxc_resolver.resolve(:hypervisor)).to eq(result)
end
end
end
3 changes: 3 additions & 0 deletions spec/fixtures/cgroup_file
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
12:pids:/init.scope
11:cpu,cpuacct:/init.scope
10:rdma:/
3 changes: 3 additions & 0 deletions spec/fixtures/docker_cgroup
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
13:name=systemd:/docker/ee6e3c05422f1273c9b41a26f2b4ec64bdb4480d63a1ad9741e05cafc1651b90
12:pids:/docker/ee6e3c05422f1273c9b41a26f2b4ec64bdb4480d63a1ad9741e05cafc1651b90
11:hugetlb:/docker/ee6e3c05422f1273c9b41a26f2b4ec64bdb4480d63a1ad9741e05cafc1651b90
4 changes: 4 additions & 0 deletions spec/fixtures/lxc_cgroup
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
12:pids:/init.scope
11:cpu,cpuacct:/init.scope
10:rdma:/
/lxc/lxc_container/

0 comments on commit 2625f6f

Please sign in to comment.